2022-04-16 02:19:11

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 00/45] Allwinner A31/A83T MIPI CSI-2 and A31 ISP / CSI Rework

This new version is an offspring from the big "Allwinner A31/A83T
MIPI CSI-2 Support and A31 ISP Support" series, which was split into
individual series for better clarity and handling.

This part only concerns the rework of the CSI driver to support the MIPI CSI-2
and ISP workflows.

Changes since v3:
- Updated Kconfig to follow the latest media-wide changes;
- Rebased on latest changes to the driver (JPEG/sRGB colorspaces);
- Added helper to get a single enabled link for an entity's pad, to replace
source selection at link_validate time and select the remote source at
stream on time instead;
- Kept clock-managed regmap mmio;
- Added collected review tags;
- Various cosmetic cleanups;

Changes since all-in-one v2:
- Reworked capture video device registration, which stays in the main path.
- Reworked async subdev handling with a dedicated structure holding the
corresponding source to avoid matching in the driver;
- Added mutex for mbus format serialization;
- Remove useless else in link_validate;
- Reworked commit logs to include missing information;
- Cleaned up Kconfig, added PM dependency;
- Moved platform-specific clock rate to of match data;
- Added collected Reviewed-by tags;
- Updated copyright years;

Paul Kocialkowski (45):
media: sun6i-csi: Define and use driver name and (reworked)
description
media: sun6i-csi: Refactor main driver data structures
media: sun6i-csi: Tidy up platform code
media: sun6i-csi: Always set exclusive module clock rate
media: sun6i-csi: Define and use variant to get module clock rate
media: sun6i-csi: Use runtime pm for clocks and reset
media: sun6i-csi: Tidy up Kconfig
media: sun6i-csi: Tidy up v4l2 code
media: sun6i-csi: Tidy up video code
media: sun6i-csi: Pass and store csi device directly in video code
media: sun6i-csi: Register the media device after creation
media: sun6i-csi: Add media ops with link notify callback
media: sun6i-csi: Introduce and use video helper functions
media: sun6i-csi: Move csi buffer definition to main header file
media: media-entity: Add helper to get a single enabled link
media: sun6i-csi: Add bridge v4l2 subdev with port management
media: sun6i-csi: Rename sun6i_video to sun6i_csi_capture
media: sun6i-csi: Add capture state using vsync for page flip
media: sun6i-csi: Rework register definitions, invert misleading
fields
media: sun6i-csi: Add dimensions and format helpers to capture
media: sun6i-csi: Implement address configuration without indirection
media: sun6i-csi: Split stream sequences and irq code in capture
media: sun6i-csi: Move power management to runtime pm in capture
media: sun6i-csi: Move register configuration to capture
media: sun6i-csi: Rework capture format management with helper
media: sun6i-csi: Remove custom format helper and rework configure
media: sun6i-csi: Add bridge dimensions and format helpers
media: sun6i-csi: Get mbus code from bridge instead of storing it
media: sun6i-csi: Tidy capture configure code
media: sun6i-csi: Introduce bridge format structure, list and helper
media: sun6i-csi: Introduce capture format structure, list and helper
media: sun6i-csi: Configure registers from format tables
media: sun6i-csi: Introduce format match structure, list and helper
media: sun6i-csi: Implement capture link validation with logic
media: sun6i-csi: Get bridge subdev directly in capture stream ops
media: sun6i-csi: Move hardware control to the bridge
media: sun6i-csi: Rename the capture video device to sun6i-csi-capture
media: sun6i-csi: Cleanup headers and includes, update copyright lines
media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code
media: sun6i-csi: Only configure capture when streaming
media: sun6i-csi: Add extra checks to the interrupt routine
media: sun6i-csi: Request a shared interrupt
media: sun6i-csi: Detect the availability of the ISP
media: sun6i-csi: Add support for hooking to the isp devices
MAINTAINERS: Add myself as sun6i-csi maintainer and rename/move entry

MAINTAINERS | 17 +-
drivers/media/mc/mc-entity.c | 26 +
.../media/platform/sunxi/sun6i-csi/Kconfig | 12 +-
.../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 1077 +++++-----------
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 153 +--
.../sunxi/sun6i-csi/sun6i_csi_bridge.c | 869 +++++++++++++
.../sunxi/sun6i-csi/sun6i_csi_bridge.h | 69 +
.../sunxi/sun6i-csi/sun6i_csi_capture.c | 1109 +++++++++++++++++
.../sunxi/sun6i-csi/sun6i_csi_capture.h | 89 ++
.../platform/sunxi/sun6i-csi/sun6i_csi_reg.h | 362 +++---
.../platform/sunxi/sun6i-csi/sun6i_video.c | 685 ----------
.../platform/sunxi/sun6i-csi/sun6i_video.h | 38 -
include/media/media-entity.h | 13 +
14 files changed, 2707 insertions(+), 1814 deletions(-)
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
delete mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
delete mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h

--
2.35.2


2022-04-16 02:19:28

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 45/45] MAINTAINERS: Add myself as sun6i-csi maintainer and rename/move entry

Given the substantial rework of the driver that I carried out and the
knowledge acquired about the hardware along the way, make myself a
maintainer of the sun6i-csi driver.

Also rename and move the entry while at it since the driver is not
specific to the V3s.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
MAINTAINERS | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0c7a3c792837..43f456982ecc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -761,6 +761,15 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
F: drivers/media/platform/sunxi/sun4i-csi/

+ALLWINNER A31 CSI DRIVER
+M: Yong Deng <[email protected]>
+M: Paul Kocialkowski <[email protected]>
+L: [email protected]
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
+F: drivers/media/platform/sunxi/sun6i-csi/
+
ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER
M: Paul Kocialkowski <[email protected]>
L: [email protected]
@@ -5232,14 +5241,6 @@ M: Jaya Kumar <[email protected]>
S: Maintained
F: sound/pci/cs5535audio/

-CSI DRIVERS FOR ALLWINNER V3s
-M: Yong Deng <[email protected]>
-L: [email protected]
-S: Maintained
-T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
-F: drivers/media/platform/sunxi/sun6i-csi/
-
CW1200 WLAN driver
M: Solomon Peachy <[email protected]>
S: Maintained
--
2.35.2

2022-04-16 02:19:57

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 08/45] media: sun6i-csi: Tidy up v4l2 code

Various cosmetic improvements to the v4l2 registration code, with
renames, lowerings, etc. The cleanup function is moved down after
setup. No functional change intended.

Signed-off-by: Paul Kocialkowski <[email protected]>
Reviewed-by: Maxime Ripard <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 118 ++++++++++--------
1 file changed, 68 insertions(+), 50 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index dcc9e7a125e2..902a69cc27fe 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -27,6 +27,8 @@
#include "sun6i_csi.h"
#include "sun6i_csi_reg.h"

+/* Helpers */
+
/* TODO add 10&12 bit YUV, RGB support */
bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev,
u32 pixformat, u32 mbus_code)
@@ -572,9 +574,8 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
CSI_CAP_CH0_VCAP_ON);
}

-/* -----------------------------------------------------------------------------
- * Media Controller and V4L2
- */
+/* V4L2 */
+
static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev,
struct media_entity *entity,
struct fwnode_handle *fwnode)
@@ -666,86 +667,103 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
}
}

-static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
+static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev)
{
struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
+ struct media_device *media_dev = &v4l2->media_dev;
+ struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
+ struct v4l2_async_notifier *notifier = &v4l2->notifier;
+ struct device *dev = csi_dev->dev;
+ int ret;

- media_device_unregister(&v4l2->media_dev);
- v4l2_async_nf_unregister(&v4l2->notifier);
- v4l2_async_nf_cleanup(&v4l2->notifier);
- sun6i_video_cleanup(&csi_dev->video);
- v4l2_device_unregister(&v4l2->v4l2_dev);
- v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
- media_device_cleanup(&v4l2->media_dev);
-}
+ /* Media Device */

-static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev)
-{
- struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
- int ret;
+ strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION,
+ sizeof(media_dev->model));
+ snprintf(media_dev->bus_info, sizeof(media_dev->bus_info),
+ "platform:%s", dev_name(dev));
+ media_dev->hw_revision = 0;
+ media_dev->dev = dev;

- v4l2->media_dev.dev = csi_dev->dev;
- strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION,
- sizeof(v4l2->media_dev.model));
- v4l2->media_dev.hw_revision = 0;
- snprintf(v4l2->media_dev.bus_info,
- sizeof(v4l2->media_dev.bus_info), "platform:%s",
- dev_name(csi_dev->dev));
+ media_device_init(media_dev);

- media_device_init(&v4l2->media_dev);
- v4l2_async_nf_init(&v4l2->notifier);
+ /* V4L2 Control Handler */

ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0);
if (ret) {
- dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n",
- ret);
- goto clean_media;
+ dev_err(dev, "failed to init v4l2 control handler: %d\n", ret);
+ goto error_media;
}

- v4l2->v4l2_dev.mdev = &v4l2->media_dev;
- v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler;
- ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev);
+ /* V4L2 Device */
+
+ v4l2_dev->mdev = media_dev;
+ v4l2_dev->ctrl_handler = &v4l2->ctrl_handler;
+
+ ret = v4l2_device_register(dev, v4l2_dev);
if (ret) {
- dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n",
- ret);
- goto free_ctrl;
+ dev_err(dev, "failed to register v4l2 device: %d\n", ret);
+ goto error_v4l2_ctrl;
}

+ /* Video */
+
ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME);
if (ret)
- goto unreg_v4l2;
+ goto error_v4l2_device;

- ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev,
- &v4l2->notifier,
+ /* V4L2 Async */
+
+ v4l2_async_nf_init(notifier);
+ notifier->ops = &sun6i_csi_async_ops;
+
+ ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier,
sizeof(struct
v4l2_async_subdev),
sun6i_csi_fwnode_parse);
if (ret)
- goto clean_video;
-
- v4l2->notifier.ops = &sun6i_csi_async_ops;
+ goto error_video;

- ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier);
+ ret = v4l2_async_nf_register(v4l2_dev, notifier);
if (ret) {
- dev_err(csi_dev->dev, "notifier registration failed\n");
- goto clean_video;
+ dev_err(dev, "failed to register v4l2 async notifier: %d\n",
+ ret);
+ goto error_v4l2_async_notifier;
}

return 0;

-clean_video:
+error_v4l2_async_notifier:
+ v4l2_async_nf_cleanup(notifier);
+
+error_video:
sun6i_video_cleanup(&csi_dev->video);
-unreg_v4l2:
+
+error_v4l2_device:
v4l2_device_unregister(&v4l2->v4l2_dev);
-free_ctrl:
+
+error_v4l2_ctrl:
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
-clean_media:
- v4l2_async_nf_cleanup(&v4l2->notifier);
- media_device_cleanup(&v4l2->media_dev);
+
+error_media:
+ media_device_cleanup(media_dev);

return ret;
}

+static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
+{
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
+
+ media_device_unregister(&v4l2->media_dev);
+ v4l2_async_nf_unregister(&v4l2->notifier);
+ v4l2_async_nf_cleanup(&v4l2->notifier);
+ sun6i_video_cleanup(&csi_dev->video);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ media_device_cleanup(&v4l2->media_dev);
+}
+
/* Platform */

static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
@@ -942,7 +960,7 @@ static int sun6i_csi_probe(struct platform_device *platform_dev)
if (ret)
return ret;

- ret = sun6i_csi_v4l2_init(csi_dev);
+ ret = sun6i_csi_v4l2_setup(csi_dev);
if (ret)
goto error_resources;

--
2.35.2

2022-04-16 02:20:11

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 06/45] media: sun6i-csi: Use runtime pm for clocks and reset

Wrap the clock and reset preparation into runtime pm functions
for better organization of the code. Also fix the clock and
reset enable order to first deassert reset, as recommended in
Allwinner litterature.

Make the driver depend on PM while at it since runtime pm is
mandatory for the driver to work.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../media/platform/sunxi/sun6i-csi/Kconfig | 2 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++------
2 files changed, 60 insertions(+), 26 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig
index 0345901617d4..965fbd937841 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig
+++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig
@@ -2,7 +2,7 @@
config VIDEO_SUN6I_CSI
tristate "Allwinner V3s Camera Sensor Interface driver"
depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && COMMON_CLK && HAS_DMA
+ depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM
depends on ARCH_SUNXI || COMPILE_TEST
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 46d92b925cc8..dcc9e7a125e2 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable)

if (!enable) {
regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
+ pm_runtime_put(dev);

- clk_disable_unprepare(csi_dev->clock_ram);
- clk_disable_unprepare(csi_dev->clock_mod);
- reset_control_assert(csi_dev->reset);
return 0;
}

- ret = clk_prepare_enable(csi_dev->clock_mod);
- if (ret) {
- dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
-
- ret = clk_prepare_enable(csi_dev->clock_ram);
- if (ret) {
- dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret);
- goto clk_mod_disable;
- }
-
- ret = reset_control_deassert(csi_dev->reset);
- if (ret) {
- dev_err(csi_dev->dev, "reset err %d\n", ret);
- goto clk_ram_disable;
- }

regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);

return 0;
-
-clk_ram_disable:
- clk_disable_unprepare(csi_dev->clock_ram);
-clk_mod_disable:
- clk_disable_unprepare(csi_dev->clock_mod);
- return ret;
}

static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev,
@@ -800,6 +778,56 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
return IRQ_HANDLED;
}

+static int sun6i_csi_suspend(struct device *dev)
+{
+ struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
+
+ reset_control_assert(csi_dev->reset);
+ clk_disable_unprepare(csi_dev->clock_ram);
+ clk_disable_unprepare(csi_dev->clock_mod);
+
+ return 0;
+}
+
+static int sun6i_csi_resume(struct device *dev)
+{
+ struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(csi_dev->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(csi_dev->clock_mod);
+ if (ret) {
+ dev_err(dev, "failed to enable module clock\n");
+ goto error_reset;
+ }
+
+ ret = clk_prepare_enable(csi_dev->clock_ram);
+ if (ret) {
+ dev_err(dev, "failed to enable ram clock\n");
+ goto error_clock_mod;
+ }
+
+ return 0;
+
+error_clock_mod:
+ clk_disable_unprepare(csi_dev->clock_mod);
+
+error_reset:
+ reset_control_assert(csi_dev->reset);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sun6i_csi_pm_ops = {
+ .runtime_suspend = sun6i_csi_suspend,
+ .runtime_resume = sun6i_csi_resume,
+};
+
static const struct regmap_config sun6i_csi_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -879,6 +907,10 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,
goto error_clock_rate_exclusive;
}

+ /* Runtime PM */
+
+ pm_runtime_enable(dev);
+
return 0;

error_clock_rate_exclusive:
@@ -889,6 +921,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,

static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev)
{
+ pm_runtime_disable(csi_dev->dev);
clk_rate_exclusive_put(csi_dev->clock_mod);
}

@@ -971,6 +1004,7 @@ static struct platform_driver sun6i_csi_platform_driver = {
.driver = {
.name = SUN6I_CSI_NAME,
.of_match_table = of_match_ptr(sun6i_csi_of_match),
+ .pm = &sun6i_csi_pm_ops,
},
};

--
2.35.2

2022-04-16 02:29:35

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 02/45] media: sun6i-csi: Refactor main driver data structures

Merge contents of structs sun6i_csi and sun6i_csi_dev into a main
sun6i_csi_device structure holding a sun6i_csi_v4l2 struct for things
related to v4l2, as well as the already-existing sun6i_csi_video and
sun6i_csi_config which are left unchanged.

This mostly simplifies accessing stuff by having a single main
structure accessible to every part of the code instead of a private
definition.

No functional change is intended in this commit, variables are just
moved around (cosmetics).

Signed-off-by: Paul Kocialkowski <[email protected]>
Reviewed-by: Maxime Ripard <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 351 +++++++++---------
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 34 +-
.../platform/sunxi/sun6i-csi/sun6i_video.c | 52 +--
.../platform/sunxi/sun6i-csi/sun6i_video.h | 8 +-
4 files changed, 221 insertions(+), 224 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 43dcd8117d3f..5fbaa1e99412 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -27,37 +27,20 @@
#include "sun6i_csi.h"
#include "sun6i_csi_reg.h"

-struct sun6i_csi_dev {
- struct sun6i_csi csi;
- struct device *dev;
-
- struct regmap *regmap;
- struct clk *clk_mod;
- struct clk *clk_ram;
- struct reset_control *rstc_bus;
-
- int planar_offset[3];
-};
-
-static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
-{
- return container_of(csi, struct sun6i_csi_dev, csi);
-}
-
/* TODO add 10&12 bit YUV, RGB support */
-bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
+bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev,
u32 pixformat, u32 mbus_code)
{
- struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;

/*
* Some video receivers have the ability to be compatible with
* 8bit and 16bit bus width.
* Identify the media bus format from device tree.
*/
- if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
- || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656)
- && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) {
+ if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
+ || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656)
+ && v4l2->v4l2_ep.bus.parallel.bus_width == 16) {
switch (pixformat) {
case V4L2_PIX_FMT_NV12_16L16:
case V4L2_PIX_FMT_NV12:
@@ -74,13 +57,14 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
case MEDIA_BUS_FMT_YVYU8_1X16:
return true;
default:
- dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
+ dev_dbg(csi_dev->dev,
+ "Unsupported mbus code: 0x%x\n",
mbus_code);
break;
}
break;
default:
- dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n",
+ dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n",
pixformat);
break;
}
@@ -137,7 +121,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
case MEDIA_BUS_FMT_YVYU8_2X8:
return true;
default:
- dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
+ dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
mbus_code);
break;
}
@@ -152,50 +136,50 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8);

default:
- dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
+ dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n",
+ pixformat);
break;
}

return false;
}

-int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
+int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable)
{
- struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
- struct device *dev = sdev->dev;
- struct regmap *regmap = sdev->regmap;
+ struct device *dev = csi_dev->dev;
+ struct regmap *regmap = csi_dev->regmap;
int ret;

if (!enable) {
regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);

- clk_disable_unprepare(sdev->clk_ram);
+ clk_disable_unprepare(csi_dev->clk_ram);
if (of_device_is_compatible(dev->of_node,
"allwinner,sun50i-a64-csi"))
- clk_rate_exclusive_put(sdev->clk_mod);
- clk_disable_unprepare(sdev->clk_mod);
- reset_control_assert(sdev->rstc_bus);
+ clk_rate_exclusive_put(csi_dev->clk_mod);
+ clk_disable_unprepare(csi_dev->clk_mod);
+ reset_control_assert(csi_dev->reset);
return 0;
}

- ret = clk_prepare_enable(sdev->clk_mod);
+ ret = clk_prepare_enable(csi_dev->clk_mod);
if (ret) {
- dev_err(sdev->dev, "Enable csi clk err %d\n", ret);
+ dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret);
return ret;
}

if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi"))
- clk_set_rate_exclusive(sdev->clk_mod, 300000000);
+ clk_set_rate_exclusive(csi_dev->clk_mod, 300000000);

- ret = clk_prepare_enable(sdev->clk_ram);
+ ret = clk_prepare_enable(csi_dev->clk_ram);
if (ret) {
- dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret);
+ dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret);
goto clk_mod_disable;
}

- ret = reset_control_deassert(sdev->rstc_bus);
+ ret = reset_control_deassert(csi_dev->reset);
if (ret) {
- dev_err(sdev->dev, "reset err %d\n", ret);
+ dev_err(csi_dev->dev, "reset err %d\n", ret);
goto clk_ram_disable;
}

@@ -204,15 +188,15 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
return 0;

clk_ram_disable:
- clk_disable_unprepare(sdev->clk_ram);
+ clk_disable_unprepare(csi_dev->clk_ram);
clk_mod_disable:
if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi"))
- clk_rate_exclusive_put(sdev->clk_mod);
- clk_disable_unprepare(sdev->clk_mod);
+ clk_rate_exclusive_put(csi_dev->clk_mod);
+ clk_disable_unprepare(csi_dev->clk_mod);
return ret;
}

-static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev,
+static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev,
u32 mbus_code, u32 pixformat)
{
/* non-YUV */
@@ -230,12 +214,13 @@ static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev,
}

/* not support YUV420 input format yet */
- dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n");
+ dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n");
return CSI_INPUT_FORMAT_YUV422;
}

-static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev,
- u32 pixformat, u32 field)
+static enum csi_output_fmt
+get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat,
+ u32 field)
{
bool buf_interlaced = false;

@@ -294,14 +279,14 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev,
return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;

default:
- dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
+ dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
break;
}

return CSI_FIELD_RAW_8;
}

-static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
+static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev,
u32 mbus_code, u32 pixformat)
{
/* Input sequence does not apply to non-YUV formats */
@@ -328,7 +313,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
case MEDIA_BUS_FMT_YVYU8_2X8:
return CSI_INPUT_SEQ_YVYU;
default:
- dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
+ dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
mbus_code);
break;
}
@@ -350,7 +335,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
case MEDIA_BUS_FMT_YVYU8_2X8:
return CSI_INPUT_SEQ_YUYV;
default:
- dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
+ dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n",
mbus_code);
break;
}
@@ -360,7 +345,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
return CSI_INPUT_SEQ_YUYV;

default:
- dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
+ dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
pixformat);
break;
}
@@ -368,23 +353,23 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
return CSI_INPUT_SEQ_YUYV;
}

-static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
+static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)
{
- struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep;
- struct sun6i_csi *csi = &sdev->csi;
+ struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep;
+ struct sun6i_csi_config *config = &csi_dev->config;
unsigned char bus_width;
u32 flags;
u32 cfg;
bool input_interlaced = false;

- if (csi->config.field == V4L2_FIELD_INTERLACED
- || csi->config.field == V4L2_FIELD_INTERLACED_TB
- || csi->config.field == V4L2_FIELD_INTERLACED_BT)
+ if (config->field == V4L2_FIELD_INTERLACED
+ || config->field == V4L2_FIELD_INTERLACED_TB
+ || config->field == V4L2_FIELD_INTERLACED_BT)
input_interlaced = true;

bus_width = endpoint->bus.parallel.bus_width;

- regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg);
+ regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg);

cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
CSI_IF_CFG_IF_DATA_WIDTH_MASK |
@@ -432,7 +417,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
break;
default:
- dev_warn(sdev->dev, "Unsupported bus type: %d\n",
+ dev_warn(csi_dev->dev, "Unsupported bus type: %d\n",
endpoint->bus_type);
break;
}
@@ -450,54 +435,54 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
case 16: /* No need to configure DATA_WIDTH for 16bit */
break;
default:
- dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
+ dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width);
break;
}

- regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
+ regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg);
}

-static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev)
+static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_csi *csi = &sdev->csi;
+ struct sun6i_csi_config *config = &csi_dev->config;
u32 cfg;
u32 val;

- regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg);
+ regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg);

cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
CSI_CH_CFG_INPUT_SEQ_MASK);

- val = get_csi_input_format(sdev, csi->config.code,
- csi->config.pixelformat);
+ val = get_csi_input_format(csi_dev, config->code,
+ config->pixelformat);
cfg |= CSI_CH_CFG_INPUT_FMT(val);

- val = get_csi_output_format(sdev, csi->config.pixelformat,
- csi->config.field);
+ val = get_csi_output_format(csi_dev, config->pixelformat,
+ config->field);
cfg |= CSI_CH_CFG_OUTPUT_FMT(val);

- val = get_csi_input_seq(sdev, csi->config.code,
- csi->config.pixelformat);
+ val = get_csi_input_seq(csi_dev, config->code,
+ config->pixelformat);
cfg |= CSI_CH_CFG_INPUT_SEQ(val);

- if (csi->config.field == V4L2_FIELD_TOP)
+ if (config->field == V4L2_FIELD_TOP)
cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
- else if (csi->config.field == V4L2_FIELD_BOTTOM)
+ else if (config->field == V4L2_FIELD_BOTTOM)
cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
else
cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;

- regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg);
+ regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg);
}

-static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
+static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_csi_config *config = &sdev->csi.config;
+ struct sun6i_csi_config *config = &csi_dev->config;
u32 bytesperline_y;
u32 bytesperline_c;
- int *planar_offset = sdev->planar_offset;
+ int *planar_offset = csi_dev->planar_offset;
u32 width = config->width;
u32 height = config->height;
u32 hor_len = width;
@@ -507,7 +492,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
- dev_dbg(sdev->dev,
+ dev_dbg(csi_dev->dev,
"Horizontal length should be 2 times of width for packed YUV formats!\n");
hor_len = width * 2;
break;
@@ -515,10 +500,10 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
break;
}

- regmap_write(sdev->regmap, CSI_CH_HSIZE_REG,
+ regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG,
CSI_CH_HSIZE_HOR_LEN(hor_len) |
CSI_CH_HSIZE_HOR_START(0));
- regmap_write(sdev->regmap, CSI_CH_VSIZE_REG,
+ regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG,
CSI_CH_VSIZE_VER_LEN(height) |
CSI_CH_VSIZE_VER_START(0));

@@ -550,7 +535,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
bytesperline_c * height;
break;
default: /* raw */
- dev_dbg(sdev->dev,
+ dev_dbg(csi_dev->dev,
"Calculating pixelformat(0x%x)'s bytesperline as a packed format\n",
config->pixelformat);
bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
@@ -561,46 +546,42 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
break;
}

- regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG,
+ regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG,
CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
}

-int sun6i_csi_update_config(struct sun6i_csi *csi,
+int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
struct sun6i_csi_config *config)
{
- struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
-
if (!config)
return -EINVAL;

- memcpy(&csi->config, config, sizeof(csi->config));
+ memcpy(&csi_dev->config, config, sizeof(csi_dev->config));

- sun6i_csi_setup_bus(sdev);
- sun6i_csi_set_format(sdev);
- sun6i_csi_set_window(sdev);
+ sun6i_csi_setup_bus(csi_dev);
+ sun6i_csi_set_format(csi_dev);
+ sun6i_csi_set_window(csi_dev);

return 0;
}

-void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr)
+void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
+ dma_addr_t addr)
{
- struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
-
- regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG,
- (addr + sdev->planar_offset[0]) >> 2);
- if (sdev->planar_offset[1] != -1)
- regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG,
- (addr + sdev->planar_offset[1]) >> 2);
- if (sdev->planar_offset[2] != -1)
- regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG,
- (addr + sdev->planar_offset[2]) >> 2);
+ regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG,
+ (addr + csi_dev->planar_offset[0]) >> 2);
+ if (csi_dev->planar_offset[1] != -1)
+ regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG,
+ (addr + csi_dev->planar_offset[1]) >> 2);
+ if (csi_dev->planar_offset[2] != -1)
+ regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG,
+ (addr + csi_dev->planar_offset[2]) >> 2);
}

-void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
+void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
{
- struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
- struct regmap *regmap = sdev->regmap;
+ struct regmap *regmap = csi_dev->regmap;

if (!enable) {
regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
@@ -624,7 +605,7 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
/* -----------------------------------------------------------------------------
* Media Controller and V4L2
*/
-static int sun6i_csi_link_entity(struct sun6i_csi *csi,
+static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev,
struct media_entity *entity,
struct fwnode_handle *fwnode)
{
@@ -635,24 +616,25 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi,

ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE);
if (ret < 0) {
- dev_err(csi->dev, "%s: no source pad in external entity %s\n",
- __func__, entity->name);
+ dev_err(csi_dev->dev,
+ "%s: no source pad in external entity %s\n", __func__,
+ entity->name);
return -EINVAL;
}

src_pad_index = ret;

- sink = &csi->video.vdev.entity;
- sink_pad = &csi->video.pad;
+ sink = &csi_dev->video.vdev.entity;
+ sink_pad = &csi_dev->video.pad;

- dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n",
+ dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n",
entity->name, src_pad_index, sink->name, sink_pad->index);
ret = media_create_pad_link(entity, src_pad_index, sink,
sink_pad->index,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (ret < 0) {
- dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n",
+ dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n",
entity->name, src_pad_index,
sink->name, sink_pad->index);
return ret;
@@ -663,27 +645,29 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi,

static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier)
{
- struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi,
- notifier);
- struct v4l2_device *v4l2_dev = &csi->v4l2_dev;
+ struct sun6i_csi_device *csi_dev =
+ container_of(notifier, struct sun6i_csi_device,
+ v4l2.notifier);
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
+ struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
struct v4l2_subdev *sd;
int ret;

- dev_dbg(csi->dev, "notify complete, all subdevs registered\n");
+ dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n");

sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list);
if (!sd)
return -EINVAL;

- ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode);
+ ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode);
if (ret < 0)
return ret;

- ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
+ ret = v4l2_device_register_subdev_nodes(v4l2_dev);
if (ret < 0)
return ret;

- return media_device_register(&csi->media_dev);
+ return media_device_register(&v4l2->media_dev);
}

static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = {
@@ -694,7 +678,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd)
{
- struct sun6i_csi *csi = dev_get_drvdata(dev);
+ struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);

if (vep->base.port || vep->base.id) {
dev_warn(dev, "Only support a single port with one endpoint\n");
@@ -704,7 +688,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
switch (vep->bus_type) {
case V4L2_MBUS_PARALLEL:
case V4L2_MBUS_BT656:
- csi->v4l2_ep = *vep;
+ csi_dev->v4l2.v4l2_ep = *vep;
return 0;
default:
dev_err(dev, "Unsupported media bus type\n");
@@ -712,78 +696,82 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
}
}

-static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi)
+static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
{
- media_device_unregister(&csi->media_dev);
- v4l2_async_nf_unregister(&csi->notifier);
- v4l2_async_nf_cleanup(&csi->notifier);
- sun6i_video_cleanup(&csi->video);
- v4l2_device_unregister(&csi->v4l2_dev);
- v4l2_ctrl_handler_free(&csi->ctrl_handler);
- media_device_cleanup(&csi->media_dev);
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
+
+ media_device_unregister(&v4l2->media_dev);
+ v4l2_async_nf_unregister(&v4l2->notifier);
+ v4l2_async_nf_cleanup(&v4l2->notifier);
+ sun6i_video_cleanup(&csi_dev->video);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ media_device_cleanup(&v4l2->media_dev);
}

-static int sun6i_csi_v4l2_init(struct sun6i_csi *csi)
+static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev)
{
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
int ret;

- csi->media_dev.dev = csi->dev;
- strscpy(csi->media_dev.model, SUN6I_CSI_DESCRIPTION,
- sizeof(csi->media_dev.model));
- csi->media_dev.hw_revision = 0;
- snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info),
- "platform:%s", dev_name(csi->dev));
+ v4l2->media_dev.dev = csi_dev->dev;
+ strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION,
+ sizeof(v4l2->media_dev.model));
+ v4l2->media_dev.hw_revision = 0;
+ snprintf(v4l2->media_dev.bus_info,
+ sizeof(v4l2->media_dev.bus_info), "platform:%s",
+ dev_name(csi_dev->dev));

- media_device_init(&csi->media_dev);
- v4l2_async_nf_init(&csi->notifier);
+ media_device_init(&v4l2->media_dev);
+ v4l2_async_nf_init(&v4l2->notifier);

- ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0);
+ ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0);
if (ret) {
- dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n",
+ dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n",
ret);
goto clean_media;
}

- csi->v4l2_dev.mdev = &csi->media_dev;
- csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler;
- ret = v4l2_device_register(csi->dev, &csi->v4l2_dev);
+ v4l2->v4l2_dev.mdev = &v4l2->media_dev;
+ v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler;
+ ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev);
if (ret) {
- dev_err(csi->dev, "V4L2 device registration failed (%d)\n",
+ dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n",
ret);
goto free_ctrl;
}

- ret = sun6i_video_init(&csi->video, csi, SUN6I_CSI_NAME);
+ ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME);
if (ret)
goto unreg_v4l2;

- ret = v4l2_async_nf_parse_fwnode_endpoints(csi->dev,
- &csi->notifier,
+ ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev,
+ &v4l2->notifier,
sizeof(struct
v4l2_async_subdev),
sun6i_csi_fwnode_parse);
if (ret)
goto clean_video;

- csi->notifier.ops = &sun6i_csi_async_ops;
+ v4l2->notifier.ops = &sun6i_csi_async_ops;

- ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier);
+ ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier);
if (ret) {
- dev_err(csi->dev, "notifier registration failed\n");
+ dev_err(csi_dev->dev, "notifier registration failed\n");
goto clean_video;
}

return 0;

clean_video:
- sun6i_video_cleanup(&csi->video);
+ sun6i_video_cleanup(&csi_dev->video);
unreg_v4l2:
- v4l2_device_unregister(&csi->v4l2_dev);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
free_ctrl:
- v4l2_ctrl_handler_free(&csi->ctrl_handler);
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
clean_media:
- v4l2_async_nf_cleanup(&csi->notifier);
- media_device_cleanup(&csi->media_dev);
+ v4l2_async_nf_cleanup(&v4l2->notifier);
+ media_device_cleanup(&v4l2->media_dev);

return ret;
}
@@ -793,8 +781,8 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi)
*/
static irqreturn_t sun6i_csi_isr(int irq, void *dev_id)
{
- struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id;
- struct regmap *regmap = sdev->regmap;
+ struct sun6i_csi_device *csi_dev = (struct sun6i_csi_device *)dev_id;
+ struct regmap *regmap = csi_dev->regmap;
u32 status;

regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
@@ -814,7 +802,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id)
}

if (status & CSI_CH_INT_STA_FD_PD)
- sun6i_video_frame_done(&sdev->csi.video);
+ sun6i_video_frame_done(&csi_dev->video);

regmap_write(regmap, CSI_CH_INT_STA_REG, status);

@@ -828,7 +816,7 @@ static const struct regmap_config sun6i_csi_regmap_config = {
.max_register = 0x9c,
};

-static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
+static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev,
struct platform_device *pdev)
{
void __iomem *io_base;
@@ -839,29 +827,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
if (IS_ERR(io_base))
return PTR_ERR(io_base);

- sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base,
- &sun6i_csi_regmap_config);
- if (IS_ERR(sdev->regmap)) {
+ csi_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base,
+ &sun6i_csi_regmap_config);
+ if (IS_ERR(csi_dev->regmap)) {
dev_err(&pdev->dev, "Failed to init register map\n");
- return PTR_ERR(sdev->regmap);
+ return PTR_ERR(csi_dev->regmap);
}

- sdev->clk_mod = devm_clk_get(&pdev->dev, "mod");
- if (IS_ERR(sdev->clk_mod)) {
+ csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(csi_dev->clk_mod)) {
dev_err(&pdev->dev, "Unable to acquire csi clock\n");
- return PTR_ERR(sdev->clk_mod);
+ return PTR_ERR(csi_dev->clk_mod);
}

- sdev->clk_ram = devm_clk_get(&pdev->dev, "ram");
- if (IS_ERR(sdev->clk_ram)) {
+ csi_dev->clk_ram = devm_clk_get(&pdev->dev, "ram");
+ if (IS_ERR(csi_dev->clk_ram)) {
dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n");
- return PTR_ERR(sdev->clk_ram);
+ return PTR_ERR(csi_dev->clk_ram);
}

- sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
- if (IS_ERR(sdev->rstc_bus)) {
+ csi_dev->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
+ if (IS_ERR(csi_dev->reset)) {
dev_err(&pdev->dev, "Cannot get reset controller\n");
- return PTR_ERR(sdev->rstc_bus);
+ return PTR_ERR(csi_dev->reset);
}

irq = platform_get_irq(pdev, 0);
@@ -869,7 +857,7 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
return -ENXIO;

ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0,
- SUN6I_CSI_NAME, sdev);
+ SUN6I_CSI_NAME, csi_dev);
if (ret) {
dev_err(&pdev->dev, "Cannot request csi IRQ\n");
return ret;
@@ -880,30 +868,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,

static int sun6i_csi_probe(struct platform_device *pdev)
{
- struct sun6i_csi_dev *sdev;
+ struct sun6i_csi_device *csi_dev;
int ret;

- sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
- if (!sdev)
+ csi_dev = devm_kzalloc(&pdev->dev, sizeof(*csi_dev), GFP_KERNEL);
+ if (!csi_dev)
return -ENOMEM;

- sdev->dev = &pdev->dev;
+ csi_dev->dev = &pdev->dev;

- ret = sun6i_csi_resource_request(sdev, pdev);
+ ret = sun6i_csi_resource_request(csi_dev, pdev);
if (ret)
return ret;

- platform_set_drvdata(pdev, sdev);
+ platform_set_drvdata(pdev, csi_dev);

- sdev->csi.dev = &pdev->dev;
- return sun6i_csi_v4l2_init(&sdev->csi);
+ return sun6i_csi_v4l2_init(csi_dev);
}

static int sun6i_csi_remove(struct platform_device *pdev)
{
- struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev);
+ struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev);

- sun6i_csi_v4l2_cleanup(&sdev->csi);
+ sun6i_csi_v4l2_cleanup(csi_dev);

return 0;
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index e04f3c3fa27b..e4e7ac6c869f 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -17,8 +17,6 @@
#define SUN6I_CSI_NAME "sun6i-csi"
#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device"

-struct sun6i_csi;
-
/**
* struct sun6i_csi_config - configs for sun6i csi
* @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*)
@@ -35,20 +33,29 @@ struct sun6i_csi_config {
u32 height;
};

-struct sun6i_csi {
- struct device *dev;
- struct v4l2_ctrl_handler ctrl_handler;
+struct sun6i_csi_v4l2 {
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
struct media_device media_dev;

struct v4l2_async_notifier notifier;
-
/* video port settings */
struct v4l2_fwnode_endpoint v4l2_ep;
+};

- struct sun6i_csi_config config;
+struct sun6i_csi_device {
+ struct device *dev;

+ struct sun6i_csi_config config;
+ struct sun6i_csi_v4l2 v4l2;
struct sun6i_video video;
+
+ struct regmap *regmap;
+ struct clk *clk_mod;
+ struct clk *clk_ram;
+ struct reset_control *reset;
+
+ int planar_offset[3];
};

/**
@@ -57,22 +64,22 @@ struct sun6i_csi {
* @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*)
* @mbus_code: media bus format code (MEDIA_BUS_FMT_*)
*/
-bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat,
- u32 mbus_code);
+bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev,
+ u32 pixformat, u32 mbus_code);

/**
* sun6i_csi_set_power() - power on/off the csi
* @csi: pointer to the csi
* @enable: on/off
*/
-int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable);
+int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable);

/**
* sun6i_csi_update_config() - update the csi register settings
* @csi: pointer to the csi
* @config: see struct sun6i_csi_config
*/
-int sun6i_csi_update_config(struct sun6i_csi *csi,
+int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
struct sun6i_csi_config *config);

/**
@@ -80,14 +87,15 @@ int sun6i_csi_update_config(struct sun6i_csi *csi,
* @csi: pointer to the csi
* @addr: frame buffer's physical address
*/
-void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr);
+void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
+ dma_addr_t addr);

/**
* sun6i_csi_set_stream() - start/stop csi streaming
* @csi: pointer to the csi
* @enable: start/stop
*/
-void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable);
+void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable);

/* get bpp form v4l2 pixformat */
static inline int sun6i_csi_get_bpp(unsigned int pixformat)
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 682c26536034..314b56ca5b33 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -162,7 +162,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
config.width = video->fmt.fmt.pix.width;
config.height = video->fmt.fmt.pix.height;

- ret = sun6i_csi_update_config(video->csi, &config);
+ ret = sun6i_csi_update_config(video->csi_dev, &config);
if (ret < 0)
goto stop_media_pipeline;

@@ -171,9 +171,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
buf = list_first_entry(&video->dma_queue,
struct sun6i_csi_buffer, list);
buf->queued_to_csi = true;
- sun6i_csi_update_buf_addr(video->csi, buf->dma_addr);
+ sun6i_csi_update_buf_addr(video->csi_dev, buf->dma_addr);

- sun6i_csi_set_stream(video->csi, true);
+ sun6i_csi_set_stream(video->csi_dev, true);

/*
* CSI will lookup the next dma buffer for next frame before the
@@ -194,7 +194,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
*/
next_buf = list_next_entry(buf, list);
next_buf->queued_to_csi = true;
- sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
+ sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr);

spin_unlock_irqrestore(&video->dma_queue_lock, flags);

@@ -205,7 +205,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;

stop_csi_stream:
- sun6i_csi_set_stream(video->csi, false);
+ sun6i_csi_set_stream(video->csi_dev, false);
stop_media_pipeline:
media_pipeline_stop(&video->vdev.entity);
clear_dma_queue:
@@ -229,7 +229,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq)
if (subdev)
v4l2_subdev_call(subdev, video, s_stream, 0);

- sun6i_csi_set_stream(video->csi, false);
+ sun6i_csi_set_stream(video->csi_dev, false);

media_pipeline_stop(&video->vdev.entity);

@@ -266,7 +266,7 @@ void sun6i_video_frame_done(struct sun6i_video *video)
buf = list_first_entry(&video->dma_queue,
struct sun6i_csi_buffer, list);
if (list_is_last(&buf->list, &video->dma_queue)) {
- dev_dbg(video->csi->dev, "Frame dropped!\n");
+ dev_dbg(video->csi_dev->dev, "Frame dropped!\n");
goto unlock;
}

@@ -278,8 +278,8 @@ void sun6i_video_frame_done(struct sun6i_video *video)
*/
if (!next_buf->queued_to_csi) {
next_buf->queued_to_csi = true;
- sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
- dev_dbg(video->csi->dev, "Frame dropped!\n");
+ sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr);
+ dev_dbg(video->csi_dev->dev, "Frame dropped!\n");
goto unlock;
}

@@ -293,9 +293,9 @@ void sun6i_video_frame_done(struct sun6i_video *video)
if (!list_is_last(&next_buf->list, &video->dma_queue)) {
next_buf = list_next_entry(next_buf, list);
next_buf->queued_to_csi = true;
- sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
+ sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr);
} else {
- dev_dbg(video->csi->dev, "Next frame will be dropped!\n");
+ dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n");
}

unlock:
@@ -321,7 +321,7 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "sun6i-video", sizeof(cap->driver));
strscpy(cap->card, video->vdev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- video->csi->dev->of_node->name);
+ video->csi_dev->dev->of_node->name);

return 0;
}
@@ -488,7 +488,7 @@ static int sun6i_video_open(struct file *file)
if (!v4l2_fh_is_singular_file(file))
goto unlock;

- ret = sun6i_csi_set_power(video->csi, true);
+ ret = sun6i_csi_set_power(video->csi_dev, true);
if (ret < 0)
goto fh_release;

@@ -516,7 +516,7 @@ static int sun6i_video_close(struct file *file)
v4l2_pipeline_pm_put(&video->vdev.entity);

if (last_fh)
- sun6i_csi_set_power(video->csi, false);
+ sun6i_csi_set_power(video->csi_dev, false);

mutex_unlock(&video->lock);

@@ -561,7 +561,7 @@ static int sun6i_video_link_validate(struct media_link *link)
video->mbus_code = 0;

if (!media_entity_remote_pad(link->sink->entity->pads)) {
- dev_info(video->csi->dev,
+ dev_info(video->csi_dev->dev,
"video node %s pad not connected\n", vdev->name);
return -ENOLINK;
}
@@ -570,10 +570,10 @@ static int sun6i_video_link_validate(struct media_link *link)
if (ret < 0)
return ret;

- if (!sun6i_csi_is_format_supported(video->csi,
+ if (!sun6i_csi_is_format_supported(video->csi_dev,
video->fmt.fmt.pix.pixelformat,
source_fmt.format.code)) {
- dev_err(video->csi->dev,
+ dev_err(video->csi_dev->dev,
"Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
video->fmt.fmt.pix.pixelformat,
source_fmt.format.code);
@@ -582,7 +582,7 @@ static int sun6i_video_link_validate(struct media_link *link)

if (source_fmt.format.width != video->fmt.fmt.pix.width ||
source_fmt.format.height != video->fmt.fmt.pix.height) {
- dev_err(video->csi->dev,
+ dev_err(video->csi_dev->dev,
"Wrong width or height %ux%u (%ux%u expected)\n",
video->fmt.fmt.pix.width, video->fmt.fmt.pix.height,
source_fmt.format.width, source_fmt.format.height);
@@ -598,15 +598,16 @@ static const struct media_entity_operations sun6i_video_media_ops = {
.link_validate = sun6i_video_link_validate
};

-int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
- const char *name)
+int sun6i_video_init(struct sun6i_video *video,
+ struct sun6i_csi_device *csi_dev, const char *name)
{
+ struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
struct video_device *vdev = &video->vdev;
struct vb2_queue *vidq = &video->vb2_vidq;
struct v4l2_format fmt = { 0 };
int ret;

- video->csi = csi;
+ video->csi_dev = csi_dev;

/* Initialize the media entity... */
video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
@@ -641,11 +642,12 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
vidq->lock = &video->lock;
/* Make sure non-dropped frame */
vidq->min_buffers_needed = 3;
- vidq->dev = csi->dev;
+ vidq->dev = csi_dev->dev;

ret = vb2_queue_init(vidq);
if (ret) {
- v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret);
+ v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n",
+ ret);
goto clean_entity;
}

@@ -656,7 +658,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
vdev->ioctl_ops = &sun6i_video_ioctl_ops;
vdev->vfl_type = VFL_TYPE_VIDEO;
vdev->vfl_dir = VFL_DIR_RX;
- vdev->v4l2_dev = &csi->v4l2_dev;
+ vdev->v4l2_dev = &v4l2->v4l2_dev;
vdev->queue = vidq;
vdev->lock = &video->lock;
vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
@@ -664,7 +666,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,

ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret < 0) {
- v4l2_err(&csi->v4l2_dev,
+ v4l2_err(&v4l2->v4l2_dev,
"video_register_device failed: %d\n", ret);
goto clean_entity;
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
index b9cd919c24ac..30e37ee0d07f 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
@@ -11,12 +11,12 @@
#include <media/v4l2-dev.h>
#include <media/videobuf2-core.h>

-struct sun6i_csi;
+struct sun6i_csi_device;

struct sun6i_video {
+ struct sun6i_csi_device *csi_dev;
struct video_device vdev;
struct media_pad pad;
- struct sun6i_csi *csi;

struct mutex lock;

@@ -29,8 +29,8 @@ struct sun6i_video {
u32 mbus_code;
};

-int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
- const char *name);
+int sun6i_video_init(struct sun6i_video *video,
+ struct sun6i_csi_device *csi_dev, const char *name);
void sun6i_video_cleanup(struct sun6i_video *video);

void sun6i_video_frame_done(struct sun6i_video *video);
--
2.35.2

2022-04-16 02:32:05

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 29/45] media: sun6i-csi: Tidy capture configure code

Some misc code cleanups and preparation for upcoming changes.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../sunxi/sun6i-csi/sun6i_csi_capture.c | 105 ++++++++----------
1 file changed, 46 insertions(+), 59 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index e2070353f93f..9488c7c26f13 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -353,133 +353,120 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev,
static void
sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev)
{
+ struct device *dev = csi_dev->dev;
+ struct regmap *regmap = csi_dev->regmap;
struct v4l2_fwnode_endpoint *endpoint =
&csi_dev->bridge.source_parallel.endpoint;
+ unsigned char bus_width = endpoint->bus.parallel.bus_width;
+ unsigned int flags = endpoint->bus.parallel.flags;
u32 pixelformat, field;
- unsigned char bus_width;
- u32 flags;
- u32 cfg = 0;
- bool input_interlaced = false;
+ u32 value = SUN6I_CSI_IF_CFG_IF_CSI;

sun6i_csi_capture_format(csi_dev, &pixelformat, &field);

if (field == V4L2_FIELD_INTERLACED ||
field == V4L2_FIELD_INTERLACED_TB ||
field == V4L2_FIELD_INTERLACED_BT)
- input_interlaced = true;
-
- bus_width = endpoint->bus.parallel.bus_width;
-
- if (input_interlaced)
- cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
- SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
- SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
+ SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
+ SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
else
- cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;

switch (endpoint->bus_type) {
case V4L2_MBUS_PARALLEL:
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI;
-
- flags = endpoint->bus.parallel.flags;
-
if (bus_width == 16)
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
else
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;

if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
else
- cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
+ value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;

if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
+ value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
else
- cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;
+ value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;

if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
+ value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
else
- cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;
+ value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;

if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
else
- cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
break;
case V4L2_MBUS_BT656:
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI;
-
- flags = endpoint->bus.parallel.flags;
-
if (bus_width == 16)
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
else
- cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;
+ value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;

if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
else
- cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
+ value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;

if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
else
- cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
+ value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
break;
default:
- dev_warn(csi_dev->dev, "Unsupported bus type: %d\n",
- endpoint->bus_type);
+ dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type);
break;
}

switch (bus_width) {
case 8:
- cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
+ /* 16-bit YUV formats use a doubled width in 8-bit mode. */
+ case 16:
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
break;
case 10:
- cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
break;
case 12:
- cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
- break;
- case 16: /* No need to configure DATA_WIDTH for 16bit */
+ value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
break;
default:
- dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width);
+ dev_warn(dev, "unsupported bus width: %u\n", bus_width);
break;
}

- regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg);
+ regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
}

static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev)
{
+ struct regmap *regmap = csi_dev->regmap;
u32 mbus_code, pixelformat, field;
- u32 cfg = 0;
- u32 val;
+ u8 input_format, input_yuv_seq, output_format;
+ u32 value = 0;

sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL);

- val = get_csi_input_format(csi_dev, mbus_code, pixelformat);
- cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val);
-
- val = get_csi_output_format(csi_dev, pixelformat, field);
- cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val);
+ input_format = get_csi_input_format(csi_dev, mbus_code, pixelformat);
+ input_yuv_seq = get_csi_input_seq(csi_dev, mbus_code, pixelformat);
+ output_format = get_csi_output_format(csi_dev, pixelformat, field);

- val = get_csi_input_seq(csi_dev, mbus_code, pixelformat);
- cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val);
+ value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format);
+ value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format);
+ value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq);

if (field == V4L2_FIELD_TOP)
- cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
else if (field == V4L2_FIELD_BOTTOM)
- cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
else
- cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;
+ value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;

- regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg);
+ regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value);
}

static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev)
--
2.35.2

2022-04-16 02:33:04

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 21/45] media: sun6i-csi: Implement address configuration without indirection

Instead of calculating the planar_offset at one point and using it
later in a dedicated function, reimplement address configuration
with v4l2 format info in the buffer_configure function.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 27 ----------------
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 10 ------
.../sunxi/sun6i-csi/sun6i_csi_capture.c | 32 ++++++++++++++++++-
3 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index c7b53e8099d3..98133c1dbf68 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -463,7 +463,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
struct sun6i_csi_config *config = &csi_dev->config;
u32 bytesperline_y;
u32 bytesperline_c;
- int *planar_offset = csi_dev->planar_offset;
u32 width = config->width;
u32 height = config->height;
u32 hor_len = width;
@@ -488,7 +487,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
SUN6I_CSI_CH_VSIZE_LEN(height) |
SUN6I_CSI_CH_VSIZE_START(0));

- planar_offset[0] = 0;
switch (config->pixelformat) {
case V4L2_PIX_FMT_NV12_16L16:
case V4L2_PIX_FMT_NV12:
@@ -497,23 +495,15 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
case V4L2_PIX_FMT_NV61:
bytesperline_y = width;
bytesperline_c = width;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = -1;
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
bytesperline_y = width;
bytesperline_c = width / 2;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = planar_offset[1] +
- bytesperline_c * height / 2;
break;
case V4L2_PIX_FMT_YUV422P:
bytesperline_y = width;
bytesperline_c = width / 2;
- planar_offset[1] = bytesperline_y * height;
- planar_offset[2] = planar_offset[1] +
- bytesperline_c * height;
break;
default: /* raw */
dev_dbg(csi_dev->dev,
@@ -522,8 +512,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
config->width) / 8;
bytesperline_c = 0;
- planar_offset[1] = -1;
- planar_offset[2] = -1;
break;
}

@@ -547,21 +535,6 @@ int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
return 0;
}

-void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
- dma_addr_t addr)
-{
- regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
- SUN6I_CSI_ADDR_VALUE(addr + csi_dev->planar_offset[0]));
- if (csi_dev->planar_offset[1] != -1)
- regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
- SUN6I_CSI_ADDR_VALUE(addr +
- csi_dev->planar_offset[1]));
- if (csi_dev->planar_offset[2] != -1)
- regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
- SUN6I_CSI_ADDR_VALUE(addr +
- csi_dev->planar_offset[2]));
-}
-
void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
{
struct regmap *regmap = csi_dev->regmap;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index f02656dbfd84..44fc4d486877 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -62,8 +62,6 @@ struct sun6i_csi_device {
struct clk *clock_mod;
struct clk *clock_ram;
struct reset_control *reset;
-
- int planar_offset[3];
};

struct sun6i_csi_variant {
@@ -94,14 +92,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable);
int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
struct sun6i_csi_config *config);

-/**
- * sun6i_csi_update_buf_addr() - update the csi frame buffer address
- * @csi: pointer to the csi
- * @addr: frame buffer's physical address
- */
-void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
- dma_addr_t addr);
-
/**
* sun6i_csi_set_stream() - start/stop csi streaming
* @csi: pointer to the csi
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index acbd0ea62fd5..7788cbab7810 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -6,6 +6,7 @@
*/

#include <linux/of.h>
+#include <linux/regmap.h>

#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
@@ -16,6 +17,7 @@

#include "sun6i_csi.h"
#include "sun6i_csi_capture.h"
+#include "sun6i_csi_reg.h"

/* This is got from BSP sources. */
#define MIN_WIDTH (32)
@@ -109,13 +111,41 @@ static void
sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
struct sun6i_csi_buffer *csi_buffer)
{
+ struct regmap *regmap = csi_dev->regmap;
+ const struct v4l2_format_info *info;
struct vb2_buffer *vb2_buffer;
+ unsigned int width, height;
dma_addr_t address;
+ u32 pixelformat;

vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);

- sun6i_csi_update_buf_addr(csi_dev, address);
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+
+ sun6i_csi_capture_dimensions(csi_dev, &width, &height);
+ sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
+
+ info = v4l2_format_info(pixelformat);
+ /* Unsupported formats are single-plane, so we can stop here. */
+ if (!info)
+ return;
+
+ if (info->comp_planes > 1) {
+ address += info->bpp[0] * width * height;
+
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+ }
+
+ if (info->comp_planes > 2) {
+ address += info->bpp[1] * DIV_ROUND_UP(width, info->hdiv) *
+ DIV_ROUND_UP(height, info->vdiv);
+
+ regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(address));
+ }
}

static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)
--
2.35.2

2022-04-16 02:33:14

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Add a helper to detect whether the ISP is available and connected
and store the indication in a driver-wide variable.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
2 files changed, 36 insertions(+)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index a88deb8ba1e7..f185cbd113c7 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -25,6 +25,35 @@
#include "sun6i_csi_capture.h"
#include "sun6i_csi_reg.h"

+/* ISP */
+
+static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
+{
+ struct device *dev = csi_dev->dev;
+ struct fwnode_handle *handle = NULL;
+
+ /* ISP is not available if disabled in kernel config. */
+ if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
+ return 0;
+
+ /*
+ * ISP is not available if not connected via fwnode graph.
+ * This weill also check that the remote parent node is available.
+ */
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ SUN6I_CSI_PORT_ISP, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!handle)
+ return 0;
+
+ fwnode_handle_put(handle);
+
+ dev_info(dev, "ISP link is available\n");
+ csi_dev->isp_available = true;
+
+ return 0;
+}
+
/* Media */

static const struct media_device_ops sun6i_csi_media_ops = {
@@ -306,6 +335,10 @@ static int sun6i_csi_probe(struct platform_device *platform_dev)
if (ret)
return ret;

+ ret = sun6i_csi_isp_detect(csi_dev);
+ if (ret)
+ goto error_resources;
+
ret = sun6i_csi_v4l2_setup(csi_dev);
if (ret)
goto error_resources;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index 6aa83dd11684..9b105c341047 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -22,6 +22,7 @@
enum sun6i_csi_port {
SUN6I_CSI_PORT_PARALLEL = 0,
SUN6I_CSI_PORT_MIPI_CSI2 = 1,
+ SUN6I_CSI_PORT_ISP = 2,
};

struct sun6i_csi_buffer {
@@ -46,6 +47,8 @@ struct sun6i_csi_device {
struct clk *clock_mod;
struct clk *clock_ram;
struct reset_control *reset;
+
+ bool isp_available;
};

struct sun6i_csi_variant {
--
2.35.2

2022-04-16 02:41:52

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 39/45] media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code

Introduce MIPI CSI-2 support to the bridge with a new port, source
and hardware configuration helper.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 1 +
.../sunxi/sun6i-csi/sun6i_csi_bridge.c | 46 +++++++++++++++++--
.../sunxi/sun6i-csi/sun6i_csi_bridge.h | 1 +
3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index 1aeaef84abba..6aa83dd11684 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -21,6 +21,7 @@

enum sun6i_csi_port {
SUN6I_CSI_PORT_PARALLEL = 0,
+ SUN6I_CSI_PORT_MIPI_CSI2 = 1,
};

struct sun6i_csi_buffer {
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
index ec3e04353106..27289d904d5c 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
@@ -226,7 +226,7 @@ static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev)
}

static void
-sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev)
+sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev)
{
struct device *dev = csi_dev->dev;
struct regmap *regmap = csi_dev->regmap;
@@ -316,6 +316,25 @@ sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev)
regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
}

+static void
+sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev)
+{
+ struct regmap *regmap = csi_dev->regmap;
+ u32 value = SUN6I_CSI_IF_CFG_IF_MIPI;
+ u32 field;
+
+ sun6i_csi_bridge_format(csi_dev, NULL, &field);
+
+ if (field == V4L2_FIELD_INTERLACED ||
+ field == V4L2_FIELD_INTERLACED_TB ||
+ field == V4L2_FIELD_INTERLACED_BT)
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED;
+ else
+ value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
+
+ regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
+}
+
static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev)
{
struct regmap *regmap = csi_dev->regmap;
@@ -367,9 +386,16 @@ static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev)
regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value);
}

-static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev)
+static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev,
+ struct sun6i_csi_bridge_source *source)
{
- sun6i_csi_bridge_configure_interface(csi_dev);
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
+
+ if (source == &bridge->source_parallel)
+ sun6i_csi_bridge_configure_parallel(csi_dev);
+ else
+ sun6i_csi_bridge_configure_mipi_csi2(csi_dev);
+
sun6i_csi_bridge_configure_format(csi_dev);
}

@@ -381,6 +407,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)
struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
struct media_entity *bridge_entity = &bridge->subdev.entity;
struct device *dev = csi_dev->dev;
+ struct sun6i_csi_bridge_source *source;
struct v4l2_subdev *source_subdev;
struct media_link *link;
/* Initialize to 0 to use both in disable label (ret != 0) and off. */
@@ -398,6 +425,11 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)

source_subdev = media_entity_to_v4l2_subdev(link->source->entity);

+ if (source_subdev == bridge->source_parallel.subdev)
+ source = &bridge->source_parallel;
+ else
+ source = &bridge->source_mipi_csi2;
+
if (!on) {
v4l2_subdev_call(source_subdev, video, s_stream, 0);
goto disable;
@@ -415,7 +447,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)

/* Configure */

- sun6i_csi_bridge_configure(csi_dev);
+ sun6i_csi_bridge_configure(csi_dev, source);
sun6i_csi_capture_configure(csi_dev);

/* State Update */
@@ -607,6 +639,7 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
struct sun6i_csi_bridge_async_subdev *bridge_async_subdev =
container_of(async_subdev, struct sun6i_csi_bridge_async_subdev,
async_subdev);
+ struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
struct sun6i_csi_bridge_source *source = bridge_async_subdev->source;
bool enabled;

@@ -614,6 +647,9 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
case SUN6I_CSI_PORT_PARALLEL:
enabled = true;
break;
+ case SUN6I_CSI_PORT_MIPI_CSI2:
+ enabled = !bridge->source_parallel.expected;
+ break;
default:
break;
}
@@ -760,6 +796,8 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel,
SUN6I_CSI_PORT_PARALLEL,
parallel_mbus_types);
+ sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2,
+ SUN6I_CSI_PORT_MIPI_CSI2, NULL);

ret = v4l2_async_nf_register(v4l2_dev, notifier);
if (ret) {
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
index cb3b27af4607..ee592a14b9c5 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
@@ -46,6 +46,7 @@ struct sun6i_csi_bridge {
struct mutex lock; /* Mbus format lock. */

struct sun6i_csi_bridge_source source_parallel;
+ struct sun6i_csi_bridge_source source_mipi_csi2;
};

/* Helpers */
--
2.35.2

2022-04-16 02:42:45

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 09/45] media: sun6i-csi: Tidy up video code

Some code cleanups, renames, variable lowerings and moving things around for
better organization. No functional change intended.

Signed-off-by: Paul Kocialkowski <[email protected]>
Reviewed-by: Maxime Ripard <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 4 +-
.../platform/sunxi/sun6i-csi/sun6i_video.c | 512 ++++++++++--------
.../platform/sunxi/sun6i-csi/sun6i_video.h | 18 +-
3 files changed, 288 insertions(+), 246 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 902a69cc27fe..f1cf9f2538a0 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -595,7 +595,7 @@ static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev,

src_pad_index = ret;

- sink = &csi_dev->video.vdev.entity;
+ sink = &csi_dev->video.video_dev.entity;
sink_pad = &csi_dev->video.pad;

dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n",
@@ -708,7 +708,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev)

/* Video */

- ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME);
+ ret = sun6i_video_setup(&csi_dev->video, csi_dev);
if (ret)
goto error_v4l2_device;

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 314b56ca5b33..22243961d4d0 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -24,14 +24,34 @@
#define MAX_HEIGHT (4800)

struct sun6i_csi_buffer {
- struct vb2_v4l2_buffer vb;
+ struct vb2_v4l2_buffer v4l2_buffer;
struct list_head list;

dma_addr_t dma_addr;
bool queued_to_csi;
};

-static const u32 supported_pixformats[] = {
+/* Helpers */
+
+static struct v4l2_subdev *
+sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
+{
+ struct media_pad *remote;
+
+ remote = media_entity_remote_pad(&video->pad);
+
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
+ return NULL;
+
+ if (pad)
+ *pad = remote->index;
+
+ return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* Format */
+
+static const u32 sun6i_video_formats[] = {
V4L2_PIX_FMT_SBGGR8,
V4L2_PIX_FMT_SGBRG8,
V4L2_PIX_FMT_SGRBG8,
@@ -61,77 +81,80 @@ static const u32 supported_pixformats[] = {
V4L2_PIX_FMT_JPEG,
};

-static bool is_pixformat_valid(unsigned int pixformat)
+static bool sun6i_video_format_check(u32 format)
{
unsigned int i;

- for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++)
- if (supported_pixformats[i] == pixformat)
+ for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++)
+ if (sun6i_video_formats[i] == format)
return true;

return false;
}

-static struct v4l2_subdev *
-sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
-{
- struct media_pad *remote;
-
- remote = media_entity_remote_pad(&video->pad);
+/* Queue */

- if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
- return NULL;
-
- if (pad)
- *pad = remote->index;
-
- return media_entity_to_v4l2_subdev(remote->entity);
-}
-
-static int sun6i_video_queue_setup(struct vb2_queue *vq,
- unsigned int *nbuffers,
- unsigned int *nplanes,
+static int sun6i_video_queue_setup(struct vb2_queue *queue,
+ unsigned int *buffers_count,
+ unsigned int *planes_count,
unsigned int sizes[],
struct device *alloc_devs[])
{
- struct sun6i_video *video = vb2_get_drv_priv(vq);
- unsigned int size = video->fmt.fmt.pix.sizeimage;
+ struct sun6i_video *video = vb2_get_drv_priv(queue);
+ unsigned int size = video->format.fmt.pix.sizeimage;

- if (*nplanes)
+ if (*planes_count)
return sizes[0] < size ? -EINVAL : 0;

- *nplanes = 1;
+ *planes_count = 1;
sizes[0] = size;

return 0;
}

-static int sun6i_video_buffer_prepare(struct vb2_buffer *vb)
+static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer)
{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct sun6i_csi_buffer *buf =
- container_of(vbuf, struct sun6i_csi_buffer, vb);
- struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
- unsigned long size = video->fmt.fmt.pix.sizeimage;
-
- if (vb2_plane_size(vb, 0) < size) {
- v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n",
- vb2_plane_size(vb, 0), size);
+ struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue);
+ struct sun6i_csi_device *csi_dev = video->csi_dev;
+ struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
+ struct sun6i_csi_buffer *csi_buffer =
+ container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
+ unsigned long size = video->format.fmt.pix.sizeimage;
+
+ if (vb2_plane_size(buffer, 0) < size) {
+ v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(buffer, 0), size);
return -EINVAL;
}

- vb2_set_plane_payload(vb, 0, size);
-
- buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ vb2_set_plane_payload(buffer, 0, size);

- vbuf->field = video->fmt.fmt.pix.field;
+ csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0);
+ v4l2_buffer->field = video->format.fmt.pix.field;

return 0;
}

-static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
+static void sun6i_video_buffer_queue(struct vb2_buffer *buffer)
+{
+ struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue);
+ struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
+ struct sun6i_csi_buffer *csi_buffer =
+ container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&video->dma_queue_lock, flags);
+ csi_buffer->queued_to_csi = false;
+ list_add_tail(&csi_buffer->list, &video->dma_queue);
+ spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+}
+
+static int sun6i_video_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
{
- struct sun6i_video *video = vb2_get_drv_priv(vq);
+ struct sun6i_video *video = vb2_get_drv_priv(queue);
+ struct video_device *video_dev = &video->video_dev;
struct sun6i_csi_buffer *buf;
struct sun6i_csi_buffer *next_buf;
struct sun6i_csi_config config;
@@ -141,30 +164,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)

video->sequence = 0;

- ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe);
+ ret = media_pipeline_start(&video_dev->entity, &video_dev->pipe);
if (ret < 0)
- goto clear_dma_queue;
+ goto error_dma_queue_flush;

if (video->mbus_code == 0) {
ret = -EINVAL;
- goto stop_media_pipeline;
+ goto error_media_pipeline;
}

subdev = sun6i_video_remote_subdev(video, NULL);
if (!subdev) {
ret = -EINVAL;
- goto stop_media_pipeline;
+ goto error_media_pipeline;
}

- config.pixelformat = video->fmt.fmt.pix.pixelformat;
+ config.pixelformat = video->format.fmt.pix.pixelformat;
config.code = video->mbus_code;
- config.field = video->fmt.fmt.pix.field;
- config.width = video->fmt.fmt.pix.width;
- config.height = video->fmt.fmt.pix.height;
+ config.field = video->format.fmt.pix.field;
+ config.width = video->format.fmt.pix.width;
+ config.height = video->format.fmt.pix.height;

ret = sun6i_csi_update_config(video->csi_dev, &config);
if (ret < 0)
- goto stop_media_pipeline;
+ goto error_media_pipeline;

spin_lock_irqsave(&video->dma_queue_lock, flags);

@@ -200,27 +223,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)

ret = v4l2_subdev_call(subdev, video, s_stream, 1);
if (ret && ret != -ENOIOCTLCMD)
- goto stop_csi_stream;
+ goto error_stream;

return 0;

-stop_csi_stream:
+error_stream:
sun6i_csi_set_stream(video->csi_dev, false);
-stop_media_pipeline:
- media_pipeline_stop(&video->vdev.entity);
-clear_dma_queue:
+
+error_media_pipeline:
+ media_pipeline_stop(&video_dev->entity);
+
+error_dma_queue_flush:
spin_lock_irqsave(&video->dma_queue_lock, flags);
list_for_each_entry(buf, &video->dma_queue, list)
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ vb2_buffer_done(&buf->v4l2_buffer.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
INIT_LIST_HEAD(&video->dma_queue);
spin_unlock_irqrestore(&video->dma_queue_lock, flags);

return ret;
}

-static void sun6i_video_stop_streaming(struct vb2_queue *vq)
+static void sun6i_video_stop_streaming(struct vb2_queue *queue)
{
- struct sun6i_video *video = vb2_get_drv_priv(vq);
+ struct sun6i_video *video = vb2_get_drv_priv(queue);
struct v4l2_subdev *subdev;
unsigned long flags;
struct sun6i_csi_buffer *buf;
@@ -231,35 +257,21 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq)

sun6i_csi_set_stream(video->csi_dev, false);

- media_pipeline_stop(&video->vdev.entity);
+ media_pipeline_stop(&video->video_dev.entity);

/* Release all active buffers */
spin_lock_irqsave(&video->dma_queue_lock, flags);
list_for_each_entry(buf, &video->dma_queue, list)
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR);
INIT_LIST_HEAD(&video->dma_queue);
spin_unlock_irqrestore(&video->dma_queue_lock, flags);
}

-static void sun6i_video_buffer_queue(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct sun6i_csi_buffer *buf =
- container_of(vbuf, struct sun6i_csi_buffer, vb);
- struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
- unsigned long flags;
-
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- buf->queued_to_csi = false;
- list_add_tail(&buf->list, &video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
-}
-
void sun6i_video_frame_done(struct sun6i_video *video)
{
struct sun6i_csi_buffer *buf;
struct sun6i_csi_buffer *next_buf;
- struct vb2_v4l2_buffer *vbuf;
+ struct vb2_v4l2_buffer *v4l2_buffer;

spin_lock(&video->dma_queue_lock);

@@ -267,7 +279,7 @@ void sun6i_video_frame_done(struct sun6i_video *video)
struct sun6i_csi_buffer, list);
if (list_is_last(&buf->list, &video->dma_queue)) {
dev_dbg(video->csi_dev->dev, "Frame dropped!\n");
- goto unlock;
+ goto complete;
}

next_buf = list_next_entry(buf, list);
@@ -280,14 +292,14 @@ void sun6i_video_frame_done(struct sun6i_video *video)
next_buf->queued_to_csi = true;
sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr);
dev_dbg(video->csi_dev->dev, "Frame dropped!\n");
- goto unlock;
+ goto complete;
}

list_del(&buf->list);
- vbuf = &buf->vb;
- vbuf->vb2_buf.timestamp = ktime_get_ns();
- vbuf->sequence = video->sequence;
- vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
+ v4l2_buffer = &buf->v4l2_buffer;
+ v4l2_buffer->vb2_buf.timestamp = ktime_get_ns();
+ v4l2_buffer->sequence = video->sequence;
+ vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE);

/* Prepare buffer for next frame but one. */
if (!list_is_last(&next_buf->list, &video->dma_queue)) {
@@ -298,165 +310,173 @@ void sun6i_video_frame_done(struct sun6i_video *video)
dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n");
}

-unlock:
+complete:
video->sequence++;
spin_unlock(&video->dma_queue_lock);
}

-static const struct vb2_ops sun6i_csi_vb2_ops = {
+static const struct vb2_ops sun6i_video_queue_ops = {
.queue_setup = sun6i_video_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = sun6i_video_buffer_prepare,
+ .buf_queue = sun6i_video_buffer_queue,
.start_streaming = sun6i_video_start_streaming,
.stop_streaming = sun6i_video_stop_streaming,
- .buf_queue = sun6i_video_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};

-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
+/* V4L2 Device */
+
+static int sun6i_video_querycap(struct file *file, void *private,
+ struct v4l2_capability *capability)
{
struct sun6i_video *video = video_drvdata(file);
+ struct sun6i_csi_device *csi_dev = video->csi_dev;
+ struct video_device *video_dev = &video->video_dev;

- strscpy(cap->driver, "sun6i-video", sizeof(cap->driver));
- strscpy(cap->card, video->vdev.name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- video->csi_dev->dev->of_node->name);
+ strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
+ strscpy(capability->card, video_dev->name, sizeof(capability->card));
+ snprintf(capability->bus_info, sizeof(capability->bus_info),
+ "platform:%s", dev_name(csi_dev->dev));

return 0;
}

-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int sun6i_video_enum_fmt(struct file *file, void *private,
+ struct v4l2_fmtdesc *fmtdesc)
{
- u32 index = f->index;
+ u32 index = fmtdesc->index;

- if (index >= ARRAY_SIZE(supported_pixformats))
+ if (index >= ARRAY_SIZE(sun6i_video_formats))
return -EINVAL;

- f->pixelformat = supported_pixformats[index];
+ fmtdesc->pixelformat = sun6i_video_formats[index];

return 0;
}

-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
+static int sun6i_video_g_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_video *video = video_drvdata(file);

- *fmt = video->fmt;
+ *format = video->format;

return 0;
}

-static int sun6i_video_try_fmt(struct sun6i_video *video,
- struct v4l2_format *f)
+static int sun6i_video_format_try(struct sun6i_video *video,
+ struct v4l2_format *format)
{
- struct v4l2_pix_format *pixfmt = &f->fmt.pix;
+ struct v4l2_pix_format *pix_format = &format->fmt.pix;
int bpp;

- if (!is_pixformat_valid(pixfmt->pixelformat))
- pixfmt->pixelformat = supported_pixformats[0];
+ if (!sun6i_video_format_check(pix_format->pixelformat))
+ pix_format->pixelformat = sun6i_video_formats[0];

- v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1,
- &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);
+ v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1,
+ &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);

- bpp = sun6i_csi_get_bpp(pixfmt->pixelformat);
- pixfmt->bytesperline = (pixfmt->width * bpp) >> 3;
- pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+ bpp = sun6i_csi_get_bpp(pix_format->pixelformat);
+ pix_format->bytesperline = (pix_format->width * bpp) >> 3;
+ pix_format->sizeimage = pix_format->bytesperline * pix_format->height;

- if (pixfmt->field == V4L2_FIELD_ANY)
- pixfmt->field = V4L2_FIELD_NONE;
+ if (pix_format->field == V4L2_FIELD_ANY)
+ pix_format->field = V4L2_FIELD_NONE;

- if (pixfmt->pixelformat == V4L2_PIX_FMT_JPEG)
- pixfmt->colorspace = V4L2_COLORSPACE_JPEG;
+ if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
+ pix_format->colorspace = V4L2_COLORSPACE_JPEG;
else
- pixfmt->colorspace = V4L2_COLORSPACE_SRGB;
+ pix_format->colorspace = V4L2_COLORSPACE_SRGB;

- pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
- pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;

return 0;
}

-static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f)
+static int sun6i_video_format_set(struct sun6i_video *video,
+ struct v4l2_format *format)
{
int ret;

- ret = sun6i_video_try_fmt(video, f);
+ ret = sun6i_video_format_try(video, format);
if (ret)
return ret;

- video->fmt = *f;
+ video->format = *format;

return 0;
}

-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int sun6i_video_s_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_video *video = video_drvdata(file);

- if (vb2_is_busy(&video->vb2_vidq))
+ if (vb2_is_busy(&video->queue))
return -EBUSY;

- return sun6i_video_set_fmt(video, f);
+ return sun6i_video_format_set(video, format);
}

-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int sun6i_video_try_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_video *video = video_drvdata(file);

- return sun6i_video_try_fmt(video, f);
+ return sun6i_video_format_try(video, format);
}

-static int vidioc_enum_input(struct file *file, void *fh,
- struct v4l2_input *inp)
+static int sun6i_video_enum_input(struct file *file, void *private,
+ struct v4l2_input *input)
{
- if (inp->index != 0)
+ if (input->index != 0)
return -EINVAL;

- strscpy(inp->name, "camera", sizeof(inp->name));
- inp->type = V4L2_INPUT_TYPE_CAMERA;
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strscpy(input->name, "Camera", sizeof(input->name));

return 0;
}

-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+static int sun6i_video_g_input(struct file *file, void *private,
+ unsigned int *index)
{
- *i = 0;
+ *index = 0;

return 0;
}

-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+static int sun6i_video_s_input(struct file *file, void *private,
+ unsigned int index)
{
- if (i != 0)
+ if (index != 0)
return -EINVAL;

return 0;
}

static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_querycap = sun6i_video_querycap,
+
+ .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt,
+ .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt,
+ .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt,
+ .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt,

- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_input = vidioc_g_input,
+ .vidioc_enum_input = sun6i_video_enum_input,
+ .vidioc_g_input = sun6i_video_g_input,
+ .vidioc_s_input = sun6i_video_s_input,

+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
- .vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
- .vidioc_create_bufs = vb2_ioctl_create_bufs,
- .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,

@@ -465,9 +485,8 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};

-/* -----------------------------------------------------------------------------
- * V4L2 file operations
- */
+/* V4L2 File */
+
static int sun6i_video_open(struct file *file)
{
struct sun6i_video *video = video_drvdata(file);
@@ -478,44 +497,46 @@ static int sun6i_video_open(struct file *file)

ret = v4l2_fh_open(file);
if (ret < 0)
- goto unlock;
+ goto error_lock;

- ret = v4l2_pipeline_pm_get(&video->vdev.entity);
+ ret = v4l2_pipeline_pm_get(&video->video_dev.entity);
if (ret < 0)
- goto fh_release;
-
- /* check if already powered */
- if (!v4l2_fh_is_singular_file(file))
- goto unlock;
+ goto error_v4l2_fh;

- ret = sun6i_csi_set_power(video->csi_dev, true);
- if (ret < 0)
- goto fh_release;
+ /* Power on at first open. */
+ if (v4l2_fh_is_singular_file(file)) {
+ ret = sun6i_csi_set_power(video->csi_dev, true);
+ if (ret < 0)
+ goto error_v4l2_fh;
+ }

mutex_unlock(&video->lock);
+
return 0;

-fh_release:
+error_v4l2_fh:
v4l2_fh_release(file);
-unlock:
+
+error_lock:
mutex_unlock(&video->lock);
+
return ret;
}

static int sun6i_video_close(struct file *file)
{
struct sun6i_video *video = video_drvdata(file);
- bool last_fh;
+ bool last_close;

mutex_lock(&video->lock);

- last_fh = v4l2_fh_is_singular_file(file);
+ last_close = v4l2_fh_is_singular_file(file);

_vb2_fop_release(file, NULL);
+ v4l2_pipeline_pm_put(&video->video_dev.entity);

- v4l2_pipeline_pm_put(&video->vdev.entity);
-
- if (last_fh)
+ /* Power off at last close. */
+ if (last_close)
sun6i_csi_set_power(video->csi_dev, false);

mutex_unlock(&video->lock);
@@ -532,9 +553,8 @@ static const struct v4l2_file_operations sun6i_video_fops = {
.poll = vb2_fop_poll
};

-/* -----------------------------------------------------------------------------
- * Media Operations
- */
+/* Media Entity */
+
static int sun6i_video_link_validate_get_format(struct media_pad *pad,
struct v4l2_subdev_format *fmt)
{
@@ -571,20 +591,20 @@ static int sun6i_video_link_validate(struct media_link *link)
return ret;

if (!sun6i_csi_is_format_supported(video->csi_dev,
- video->fmt.fmt.pix.pixelformat,
+ video->format.fmt.pix.pixelformat,
source_fmt.format.code)) {
dev_err(video->csi_dev->dev,
"Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
- video->fmt.fmt.pix.pixelformat,
+ video->format.fmt.pix.pixelformat,
source_fmt.format.code);
return -EPIPE;
}

- if (source_fmt.format.width != video->fmt.fmt.pix.width ||
- source_fmt.format.height != video->fmt.fmt.pix.height) {
+ if (source_fmt.format.width != video->format.fmt.pix.width ||
+ source_fmt.format.height != video->format.fmt.pix.height) {
dev_err(video->csi_dev->dev,
"Wrong width or height %ux%u (%ux%u expected)\n",
- video->fmt.fmt.pix.width, video->fmt.fmt.pix.height,
+ video->format.fmt.pix.width, video->format.fmt.pix.height,
source_fmt.format.width, source_fmt.format.height);
return -EPIPE;
}
@@ -598,90 +618,112 @@ static const struct media_entity_operations sun6i_video_media_ops = {
.link_validate = sun6i_video_link_validate
};

-int sun6i_video_init(struct sun6i_video *video,
- struct sun6i_csi_device *csi_dev, const char *name)
+/* Video */
+
+int sun6i_video_setup(struct sun6i_video *video,
+ struct sun6i_csi_device *csi_dev)
{
- struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
- struct video_device *vdev = &video->vdev;
- struct vb2_queue *vidq = &video->vb2_vidq;
- struct v4l2_format fmt = { 0 };
+ struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
+ struct video_device *video_dev = &video->video_dev;
+ struct vb2_queue *queue = &video->queue;
+ struct media_pad *pad = &video->pad;
+ struct v4l2_format format = { 0 };
+ struct v4l2_pix_format *pix_format = &format.fmt.pix;
int ret;

video->csi_dev = csi_dev;

- /* Initialize the media entity... */
- video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
- vdev->entity.ops = &sun6i_video_media_ops;
- ret = media_entity_pads_init(&vdev->entity, 1, &video->pad);
+ /* Media Entity */
+
+ video_dev->entity.ops = &sun6i_video_media_ops;
+
+ /* Media Pad */
+
+ pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+
+ ret = media_entity_pads_init(&video_dev->entity, 1, pad);
if (ret < 0)
return ret;

- mutex_init(&video->lock);
+ /* DMA queue */

INIT_LIST_HEAD(&video->dma_queue);
spin_lock_init(&video->dma_queue_lock);

video->sequence = 0;

- /* Setup default format */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.pixelformat = supported_pixformats[0];
- fmt.fmt.pix.width = 1280;
- fmt.fmt.pix.height = 720;
- fmt.fmt.pix.field = V4L2_FIELD_NONE;
- sun6i_video_set_fmt(video, &fmt);
-
- /* Initialize videobuf2 queue */
- vidq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vidq->io_modes = VB2_MMAP | VB2_DMABUF;
- vidq->drv_priv = video;
- vidq->buf_struct_size = sizeof(struct sun6i_csi_buffer);
- vidq->ops = &sun6i_csi_vb2_ops;
- vidq->mem_ops = &vb2_dma_contig_memops;
- vidq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vidq->lock = &video->lock;
- /* Make sure non-dropped frame */
- vidq->min_buffers_needed = 3;
- vidq->dev = csi_dev->dev;
-
- ret = vb2_queue_init(vidq);
+ /* Queue */
+
+ mutex_init(&video->lock);
+
+ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->io_modes = VB2_MMAP | VB2_DMABUF;
+ queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
+ queue->ops = &sun6i_video_queue_ops;
+ queue->mem_ops = &vb2_dma_contig_memops;
+ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->lock = &video->lock;
+ queue->dev = csi_dev->dev;
+ queue->drv_priv = video;
+
+ /* Make sure non-dropped frame. */
+ queue->min_buffers_needed = 3;
+
+ ret = vb2_queue_init(queue);
if (ret) {
- v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n",
- ret);
- goto clean_entity;
+ v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
+ goto error_media_entity;
}

- /* Register video device */
- strscpy(vdev->name, name, sizeof(vdev->name));
- vdev->release = video_device_release_empty;
- vdev->fops = &sun6i_video_fops;
- vdev->ioctl_ops = &sun6i_video_ioctl_ops;
- vdev->vfl_type = VFL_TYPE_VIDEO;
- vdev->vfl_dir = VFL_DIR_RX;
- vdev->v4l2_dev = &v4l2->v4l2_dev;
- vdev->queue = vidq;
- vdev->lock = &video->lock;
- vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
- video_set_drvdata(vdev, video);
-
- ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ /* V4L2 Format */
+
+ format.type = queue->type;
+ pix_format->pixelformat = sun6i_video_formats[0];
+ pix_format->width = 1280;
+ pix_format->height = 720;
+ pix_format->field = V4L2_FIELD_NONE;
+
+ sun6i_video_format_set(video, &format);
+
+ /* Video Device */
+
+ strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name));
+ video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ video_dev->vfl_dir = VFL_DIR_RX;
+ video_dev->release = video_device_release_empty;
+ video_dev->fops = &sun6i_video_fops;
+ video_dev->ioctl_ops = &sun6i_video_ioctl_ops;
+ video_dev->v4l2_dev = v4l2_dev;
+ video_dev->queue = queue;
+ video_dev->lock = &video->lock;
+
+ video_set_drvdata(video_dev, video);
+
+ ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
if (ret < 0) {
- v4l2_err(&v4l2->v4l2_dev,
- "video_register_device failed: %d\n", ret);
- goto clean_entity;
+ v4l2_err(v4l2_dev, "failed to register video device: %d\n",
+ ret);
+ goto error_media_entity;
}

+ v4l2_info(v4l2_dev, "device %s registered as %s\n", video_dev->name,
+ video_device_node_name(video_dev));
+
return 0;

-clean_entity:
- media_entity_cleanup(&video->vdev.entity);
+error_media_entity:
+ media_entity_cleanup(&video_dev->entity);
+
mutex_destroy(&video->lock);
+
return ret;
}

void sun6i_video_cleanup(struct sun6i_video *video)
{
- vb2_video_unregister_device(&video->vdev);
- media_entity_cleanup(&video->vdev.entity);
+ struct video_device *video_dev = &video->video_dev;
+
+ vb2_video_unregister_device(video_dev);
+ media_entity_cleanup(&video_dev->entity);
mutex_destroy(&video->lock);
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
index 30e37ee0d07f..7864f062d05b 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
@@ -15,22 +15,22 @@ struct sun6i_csi_device;

struct sun6i_video {
struct sun6i_csi_device *csi_dev;
- struct video_device vdev;
- struct media_pad pad;

- struct mutex lock;
+ struct video_device video_dev;
+ struct vb2_queue queue;
+ struct mutex lock; /* Queue lock. */
+ struct media_pad pad;

- struct vb2_queue vb2_vidq;
- spinlock_t dma_queue_lock;
struct list_head dma_queue;
+ spinlock_t dma_queue_lock; /* DMA queue lock. */

- unsigned int sequence;
- struct v4l2_format fmt;
+ struct v4l2_format format;
u32 mbus_code;
+ unsigned int sequence;
};

-int sun6i_video_init(struct sun6i_video *video,
- struct sun6i_csi_device *csi_dev, const char *name);
+int sun6i_video_setup(struct sun6i_video *video,
+ struct sun6i_csi_device *csi_dev);
void sun6i_video_cleanup(struct sun6i_video *video);

void sun6i_video_frame_done(struct sun6i_video *video);
--
2.35.2

2022-04-16 02:44:13

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 17/45] media: sun6i-csi: Rename sun6i_video to sun6i_csi_capture

In an effort to distinguish between the core csi engine (to be
represented as the bridge) and the dma engine (the capture video
device), rename the video component to capture, with the appropriate
prefix. No functional change intended.

Signed-off-by: Paul Kocialkowski <[email protected]>
Reviewed-by: Maxime Ripard <[email protected]>
---
.../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 6 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 4 +-
.../{sun6i_video.c => sun6i_csi_capture.c} | 344 +++++++++---------
.../{sun6i_video.h => sun6i_csi_capture.h} | 14 +-
5 files changed, 187 insertions(+), 183 deletions(-)
rename drivers/media/platform/sunxi/sun6i-csi/{sun6i_video.c => sun6i_csi_capture.c} (59%)
rename drivers/media/platform/sunxi/sun6i-csi/{sun6i_video.h => sun6i_csi_capture.h} (64%)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile
index 7a699580a641..87e7a715140a 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/Makefile
+++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-sun6i-csi-y += sun6i_video.o sun6i_csi.o sun6i_csi_bridge.o
+sun6i-csi-y += sun6i_csi.o sun6i_csi_bridge.o sun6i_csi_capture.o

obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index f74984c8fc3b..62f65867c771 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -677,7 +677,7 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
}

if (status & CSI_CH_INT_STA_FD_PD)
- sun6i_video_frame_done(csi_dev);
+ sun6i_csi_capture_frame_done(csi_dev);

regmap_write(regmap, CSI_CH_INT_STA_REG, status);

@@ -856,7 +856,7 @@ static int sun6i_csi_probe(struct platform_device *platform_dev)
if (ret)
goto error_v4l2;

- ret = sun6i_video_setup(csi_dev);
+ ret = sun6i_csi_capture_setup(csi_dev);
if (ret)
goto error_bridge;

@@ -878,7 +878,7 @@ static int sun6i_csi_remove(struct platform_device *pdev)
{
struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev);

- sun6i_video_cleanup(csi_dev);
+ sun6i_csi_capture_cleanup(csi_dev);
sun6i_csi_bridge_cleanup(csi_dev);
sun6i_csi_v4l2_cleanup(csi_dev);
sun6i_csi_resources_cleanup(csi_dev);
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index da0c758252e7..422d7b9939f9 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -14,7 +14,7 @@
#include <media/videobuf2-v4l2.h>

#include "sun6i_csi_bridge.h"
-#include "sun6i_video.h"
+#include "sun6i_csi_capture.h"

#define SUN6I_CSI_NAME "sun6i-csi"
#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device"
@@ -59,7 +59,7 @@ struct sun6i_csi_device {
struct sun6i_csi_config config;
struct sun6i_csi_v4l2 v4l2;
struct sun6i_csi_bridge bridge;
- struct sun6i_video video;
+ struct sun6i_csi_capture capture;

struct regmap *regmap;
struct clk *clock_mod;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
similarity index 59%
rename from drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
rename to drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index e682d84ed263..cb29ddf6af27 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -15,7 +15,7 @@
#include <media/videobuf2-v4l2.h>

#include "sun6i_csi.h"
-#include "sun6i_video.h"
+#include "sun6i_csi_capture.h"

/* This is got from BSP sources. */
#define MIN_WIDTH (32)
@@ -26,11 +26,11 @@
/* Helpers */

static struct v4l2_subdev *
-sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
+sun6i_csi_capture_remote_subdev(struct sun6i_csi_capture *capture, u32 *pad)
{
struct media_pad *remote;

- remote = media_entity_remote_pad(&video->pad);
+ remote = media_entity_remote_pad(&capture->pad);

if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
@@ -43,7 +43,7 @@ sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)

/* Format */

-static const u32 sun6i_video_formats[] = {
+static const u32 sun6i_csi_capture_formats[] = {
V4L2_PIX_FMT_SBGGR8,
V4L2_PIX_FMT_SGBRG8,
V4L2_PIX_FMT_SGRBG8,
@@ -73,51 +73,52 @@ static const u32 sun6i_video_formats[] = {
V4L2_PIX_FMT_JPEG,
};

-static bool sun6i_video_format_check(u32 format)
+static bool sun6i_csi_capture_format_check(u32 format)
{
unsigned int i;

- for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++)
- if (sun6i_video_formats[i] == format)
+ for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++)
+ if (sun6i_csi_capture_formats[i] == format)
return true;

return false;
}

-/* Video */
+/* Capture */

-static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev,
- struct sun6i_csi_buffer *csi_buffer)
+static void
+sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
+ struct sun6i_csi_buffer *csi_buffer)
{
csi_buffer->queued_to_csi = true;
sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr);
}

-static void sun6i_video_configure(struct sun6i_csi_device *csi_dev)
+static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct sun6i_csi_config config = { 0 };

- config.pixelformat = video->format.fmt.pix.pixelformat;
- config.code = video->mbus_code;
- config.field = video->format.fmt.pix.field;
- config.width = video->format.fmt.pix.width;
- config.height = video->format.fmt.pix.height;
+ config.pixelformat = capture->format.fmt.pix.pixelformat;
+ config.code = capture->mbus_code;
+ config.field = capture->format.fmt.pix.field;
+ config.width = capture->format.fmt.pix.width;
+ config.height = capture->format.fmt.pix.height;

sun6i_csi_update_config(csi_dev, &config);
}

/* Queue */

-static int sun6i_video_queue_setup(struct vb2_queue *queue,
- unsigned int *buffers_count,
- unsigned int *planes_count,
- unsigned int sizes[],
- struct device *alloc_devs[])
+static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue,
+ unsigned int *buffers_count,
+ unsigned int *planes_count,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
{
struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
- unsigned int size = video->format.fmt.pix.sizeimage;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ unsigned int size = capture->format.fmt.pix.sizeimage;

if (*planes_count)
return sizes[0] < size ? -EINVAL : 0;
@@ -128,15 +129,15 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue,
return 0;
}

-static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer)
+static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer)
{
struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
struct sun6i_csi_buffer *csi_buffer =
container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
- unsigned long size = video->format.fmt.pix.sizeimage;
+ unsigned long size = capture->format.fmt.pix.sizeimage;

if (vb2_plane_size(buffer, 0) < size) {
v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
@@ -147,62 +148,62 @@ static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer)
vb2_set_plane_payload(buffer, 0, size);

csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0);
- v4l2_buffer->field = video->format.fmt.pix.field;
+ v4l2_buffer->field = capture->format.fmt.pix.field;

return 0;
}

-static void sun6i_video_buffer_queue(struct vb2_buffer *buffer)
+static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer)
{
struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
struct sun6i_csi_buffer *csi_buffer =
container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
unsigned long flags;

- spin_lock_irqsave(&video->dma_queue_lock, flags);
+ spin_lock_irqsave(&capture->dma_queue_lock, flags);
csi_buffer->queued_to_csi = false;
- list_add_tail(&csi_buffer->list, &video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+ list_add_tail(&csi_buffer->list, &capture->dma_queue);
+ spin_unlock_irqrestore(&capture->dma_queue_lock, flags);
}

-static int sun6i_video_start_streaming(struct vb2_queue *queue,
- unsigned int count)
+static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
{
struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
- struct video_device *video_dev = &video->video_dev;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ struct video_device *video_dev = &capture->video_dev;
struct sun6i_csi_buffer *buf;
struct sun6i_csi_buffer *next_buf;
struct v4l2_subdev *subdev;
unsigned long flags;
int ret;

- video->sequence = 0;
+ capture->sequence = 0;

ret = media_pipeline_start(&video_dev->entity, &video_dev->pipe);
if (ret < 0)
goto error_dma_queue_flush;

- if (video->mbus_code == 0) {
+ if (capture->mbus_code == 0) {
ret = -EINVAL;
goto error_media_pipeline;
}

- subdev = sun6i_video_remote_subdev(video, NULL);
+ subdev = sun6i_csi_capture_remote_subdev(capture, NULL);
if (!subdev) {
ret = -EINVAL;
goto error_media_pipeline;
}

- sun6i_video_configure(csi_dev);
+ sun6i_csi_capture_configure(csi_dev);

- spin_lock_irqsave(&video->dma_queue_lock, flags);
+ spin_lock_irqsave(&capture->dma_queue_lock, flags);

- buf = list_first_entry(&video->dma_queue,
+ buf = list_first_entry(&capture->dma_queue,
struct sun6i_csi_buffer, list);
- sun6i_video_buffer_configure(csi_dev, buf);
+ sun6i_csi_capture_buffer_configure(csi_dev, buf);

sun6i_csi_set_stream(csi_dev, true);

@@ -224,9 +225,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue,
* would also drop frame when lacking of queued buffer.
*/
next_buf = list_next_entry(buf, list);
- sun6i_video_buffer_configure(csi_dev, next_buf);
+ sun6i_csi_capture_buffer_configure(csi_dev, next_buf);

- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+ spin_unlock_irqrestore(&capture->dma_queue_lock, flags);

ret = v4l2_subdev_call(subdev, video, s_stream, 1);
if (ret && ret != -ENOIOCTLCMD)
@@ -241,52 +242,52 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue,
media_pipeline_stop(&video_dev->entity);

error_dma_queue_flush:
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- list_for_each_entry(buf, &video->dma_queue, list)
+ spin_lock_irqsave(&capture->dma_queue_lock, flags);
+ list_for_each_entry(buf, &capture->dma_queue, list)
vb2_buffer_done(&buf->v4l2_buffer.vb2_buf,
VB2_BUF_STATE_QUEUED);
- INIT_LIST_HEAD(&video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+ INIT_LIST_HEAD(&capture->dma_queue);
+ spin_unlock_irqrestore(&capture->dma_queue_lock, flags);

return ret;
}

-static void sun6i_video_stop_streaming(struct vb2_queue *queue)
+static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue)
{
struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct v4l2_subdev *subdev;
unsigned long flags;
struct sun6i_csi_buffer *buf;

- subdev = sun6i_video_remote_subdev(video, NULL);
+ subdev = sun6i_csi_capture_remote_subdev(capture, NULL);
if (subdev)
v4l2_subdev_call(subdev, video, s_stream, 0);

sun6i_csi_set_stream(csi_dev, false);

- media_pipeline_stop(&video->video_dev.entity);
+ media_pipeline_stop(&capture->video_dev.entity);

/* Release all active buffers */
- spin_lock_irqsave(&video->dma_queue_lock, flags);
- list_for_each_entry(buf, &video->dma_queue, list)
+ spin_lock_irqsave(&capture->dma_queue_lock, flags);
+ list_for_each_entry(buf, &capture->dma_queue, list)
vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR);
- INIT_LIST_HEAD(&video->dma_queue);
- spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+ INIT_LIST_HEAD(&capture->dma_queue);
+ spin_unlock_irqrestore(&capture->dma_queue_lock, flags);
}

-void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev)
+void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct sun6i_csi_buffer *buf;
struct sun6i_csi_buffer *next_buf;
struct vb2_v4l2_buffer *v4l2_buffer;

- spin_lock(&video->dma_queue_lock);
+ spin_lock(&capture->dma_queue_lock);

- buf = list_first_entry(&video->dma_queue,
+ buf = list_first_entry(&capture->dma_queue,
struct sun6i_csi_buffer, list);
- if (list_is_last(&buf->list, &video->dma_queue)) {
+ if (list_is_last(&buf->list, &capture->dma_queue)) {
dev_dbg(csi_dev->dev, "Frame dropped!\n");
goto complete;
}
@@ -298,7 +299,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev)
* for next ISR call.
*/
if (!next_buf->queued_to_csi) {
- sun6i_video_buffer_configure(csi_dev, next_buf);
+ sun6i_csi_capture_buffer_configure(csi_dev, next_buf);
dev_dbg(csi_dev->dev, "Frame dropped!\n");
goto complete;
}
@@ -306,39 +307,39 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev)
list_del(&buf->list);
v4l2_buffer = &buf->v4l2_buffer;
v4l2_buffer->vb2_buf.timestamp = ktime_get_ns();
- v4l2_buffer->sequence = video->sequence;
+ v4l2_buffer->sequence = capture->sequence;
vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE);

/* Prepare buffer for next frame but one. */
- if (!list_is_last(&next_buf->list, &video->dma_queue)) {
+ if (!list_is_last(&next_buf->list, &capture->dma_queue)) {
next_buf = list_next_entry(next_buf, list);
- sun6i_video_buffer_configure(csi_dev, next_buf);
+ sun6i_csi_capture_buffer_configure(csi_dev, next_buf);
} else {
dev_dbg(csi_dev->dev, "Next frame will be dropped!\n");
}

complete:
- video->sequence++;
- spin_unlock(&video->dma_queue_lock);
+ capture->sequence++;
+ spin_unlock(&capture->dma_queue_lock);
}

-static const struct vb2_ops sun6i_video_queue_ops = {
- .queue_setup = sun6i_video_queue_setup,
- .buf_prepare = sun6i_video_buffer_prepare,
- .buf_queue = sun6i_video_buffer_queue,
- .start_streaming = sun6i_video_start_streaming,
- .stop_streaming = sun6i_video_stop_streaming,
+static const struct vb2_ops sun6i_csi_capture_queue_ops = {
+ .queue_setup = sun6i_csi_capture_queue_setup,
+ .buf_prepare = sun6i_csi_capture_buffer_prepare,
+ .buf_queue = sun6i_csi_capture_buffer_queue,
+ .start_streaming = sun6i_csi_capture_start_streaming,
+ .stop_streaming = sun6i_csi_capture_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};

/* V4L2 Device */

-static int sun6i_video_querycap(struct file *file, void *private,
- struct v4l2_capability *capability)
+static int sun6i_csi_capture_querycap(struct file *file, void *private,
+ struct v4l2_capability *capability)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct video_device *video_dev = &csi_dev->video.video_dev;
+ struct video_device *video_dev = &csi_dev->capture.video_dev;

strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
strscpy(capability->card, video_dev->name, sizeof(capability->card));
@@ -348,38 +349,38 @@ static int sun6i_video_querycap(struct file *file, void *private,
return 0;
}

-static int sun6i_video_enum_fmt(struct file *file, void *private,
- struct v4l2_fmtdesc *fmtdesc)
+static int sun6i_csi_capture_enum_fmt(struct file *file, void *private,
+ struct v4l2_fmtdesc *fmtdesc)
{
u32 index = fmtdesc->index;

- if (index >= ARRAY_SIZE(sun6i_video_formats))
+ if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
return -EINVAL;

- fmtdesc->pixelformat = sun6i_video_formats[index];
+ fmtdesc->pixelformat = sun6i_csi_capture_formats[index];

return 0;
}

-static int sun6i_video_g_fmt(struct file *file, void *private,
- struct v4l2_format *format)
+static int sun6i_csi_capture_g_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;

- *format = video->format;
+ *format = capture->format;

return 0;
}

-static int sun6i_video_format_try(struct sun6i_video *video,
- struct v4l2_format *format)
+static int sun6i_csi_capture_format_try(struct sun6i_csi_capture *capture,
+ struct v4l2_format *format)
{
struct v4l2_pix_format *pix_format = &format->fmt.pix;
int bpp;

- if (!sun6i_video_format_check(pix_format->pixelformat))
- pix_format->pixelformat = sun6i_video_formats[0];
+ if (!sun6i_csi_capture_format_check(pix_format->pixelformat))
+ pix_format->pixelformat = sun6i_csi_capture_formats[0];

v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1,
&pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);
@@ -403,43 +404,43 @@ static int sun6i_video_format_try(struct sun6i_video *video,
return 0;
}

-static int sun6i_video_format_set(struct sun6i_video *video,
- struct v4l2_format *format)
+static int sun6i_csi_capture_format_set(struct sun6i_csi_capture *capture,
+ struct v4l2_format *format)
{
int ret;

- ret = sun6i_video_format_try(video, format);
+ ret = sun6i_csi_capture_format_try(capture, format);
if (ret)
return ret;

- video->format = *format;
+ capture->format = *format;

return 0;
}

-static int sun6i_video_s_fmt(struct file *file, void *private,
- struct v4l2_format *format)
+static int sun6i_csi_capture_s_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;

- if (vb2_is_busy(&video->queue))
+ if (vb2_is_busy(&capture->queue))
return -EBUSY;

- return sun6i_video_format_set(video, format);
+ return sun6i_csi_capture_format_set(capture, format);
}

-static int sun6i_video_try_fmt(struct file *file, void *private,
- struct v4l2_format *format)
+static int sun6i_csi_capture_try_fmt(struct file *file, void *private,
+ struct v4l2_format *format)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;

- return sun6i_video_format_try(video, format);
+ return sun6i_csi_capture_format_try(capture, format);
}

-static int sun6i_video_enum_input(struct file *file, void *private,
- struct v4l2_input *input)
+static int sun6i_csi_capture_enum_input(struct file *file, void *private,
+ struct v4l2_input *input)
{
if (input->index != 0)
return -EINVAL;
@@ -450,16 +451,16 @@ static int sun6i_video_enum_input(struct file *file, void *private,
return 0;
}

-static int sun6i_video_g_input(struct file *file, void *private,
- unsigned int *index)
+static int sun6i_csi_capture_g_input(struct file *file, void *private,
+ unsigned int *index)
{
*index = 0;

return 0;
}

-static int sun6i_video_s_input(struct file *file, void *private,
- unsigned int index)
+static int sun6i_csi_capture_s_input(struct file *file, void *private,
+ unsigned int index)
{
if (index != 0)
return -EINVAL;
@@ -467,17 +468,17 @@ static int sun6i_video_s_input(struct file *file, void *private,
return 0;
}

-static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
- .vidioc_querycap = sun6i_video_querycap,
+static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = {
+ .vidioc_querycap = sun6i_csi_capture_querycap,

- .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt,
- .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt,
- .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt,
- .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt,
+ .vidioc_enum_fmt_vid_cap = sun6i_csi_capture_enum_fmt,
+ .vidioc_g_fmt_vid_cap = sun6i_csi_capture_g_fmt,
+ .vidioc_s_fmt_vid_cap = sun6i_csi_capture_s_fmt,
+ .vidioc_try_fmt_vid_cap = sun6i_csi_capture_try_fmt,

- .vidioc_enum_input = sun6i_video_enum_input,
- .vidioc_g_input = sun6i_video_g_input,
- .vidioc_s_input = sun6i_video_s_input,
+ .vidioc_enum_input = sun6i_csi_capture_enum_input,
+ .vidioc_g_input = sun6i_csi_capture_g_input,
+ .vidioc_s_input = sun6i_csi_capture_s_input,

.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
@@ -496,20 +497,20 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {

/* V4L2 File */

-static int sun6i_video_open(struct file *file)
+static int sun6i_csi_capture_open(struct file *file)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
int ret = 0;

- if (mutex_lock_interruptible(&video->lock))
+ if (mutex_lock_interruptible(&capture->lock))
return -ERESTARTSYS;

ret = v4l2_fh_open(file);
if (ret < 0)
goto error_lock;

- ret = v4l2_pipeline_pm_get(&video->video_dev.entity);
+ ret = v4l2_pipeline_pm_get(&capture->video_dev.entity);
if (ret < 0)
goto error_v4l2_fh;

@@ -520,7 +521,7 @@ static int sun6i_video_open(struct file *file)
goto error_v4l2_fh;
}

- mutex_unlock(&video->lock);
+ mutex_unlock(&capture->lock);

return 0;

@@ -528,37 +529,37 @@ static int sun6i_video_open(struct file *file)
v4l2_fh_release(file);

error_lock:
- mutex_unlock(&video->lock);
+ mutex_unlock(&capture->lock);

return ret;
}

-static int sun6i_video_close(struct file *file)
+static int sun6i_csi_capture_close(struct file *file)
{
struct sun6i_csi_device *csi_dev = video_drvdata(file);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
bool last_close;

- mutex_lock(&video->lock);
+ mutex_lock(&capture->lock);

last_close = v4l2_fh_is_singular_file(file);

_vb2_fop_release(file, NULL);
- v4l2_pipeline_pm_put(&video->video_dev.entity);
+ v4l2_pipeline_pm_put(&capture->video_dev.entity);

/* Power off at last close. */
if (last_close)
sun6i_csi_set_power(csi_dev, false);

- mutex_unlock(&video->lock);
+ mutex_unlock(&capture->lock);

return 0;
}

-static const struct v4l2_file_operations sun6i_video_fops = {
+static const struct v4l2_file_operations sun6i_csi_capture_fops = {
.owner = THIS_MODULE,
- .open = sun6i_video_open,
- .release = sun6i_video_close,
+ .open = sun6i_csi_capture_open,
+ .release = sun6i_csi_capture_close,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
.poll = vb2_fop_poll
@@ -566,8 +567,9 @@ static const struct v4l2_file_operations sun6i_video_fops = {

/* Media Entity */

-static int sun6i_video_link_validate_get_format(struct media_pad *pad,
- struct v4l2_subdev_format *fmt)
+static int
+sun6i_csi_capture_link_validate_get_format(struct media_pad *pad,
+ struct v4l2_subdev_format *fmt)
{
if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
@@ -581,72 +583,74 @@ static int sun6i_video_link_validate_get_format(struct media_pad *pad,
return -EINVAL;
}

-static int sun6i_video_link_validate(struct media_link *link)
+static int sun6i_csi_capture_link_validate(struct media_link *link)
{
struct video_device *vdev = container_of(link->sink->entity,
struct video_device, entity);
struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev);
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct v4l2_subdev_format source_fmt;
int ret;

- video->mbus_code = 0;
+ capture->mbus_code = 0;

if (!media_entity_remote_pad(link->sink->entity->pads)) {
- dev_info(csi_dev->dev, "video node %s pad not connected\n",
+ dev_info(csi_dev->dev, "capture node %s pad not connected\n",
vdev->name);
return -ENOLINK;
}

- ret = sun6i_video_link_validate_get_format(link->source, &source_fmt);
+ ret = sun6i_csi_capture_link_validate_get_format(link->source,
+ &source_fmt);
if (ret < 0)
return ret;

if (!sun6i_csi_is_format_supported(csi_dev,
- video->format.fmt.pix.pixelformat,
+ capture->format.fmt.pix.pixelformat,
source_fmt.format.code)) {
dev_err(csi_dev->dev,
"Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
- video->format.fmt.pix.pixelformat,
+ capture->format.fmt.pix.pixelformat,
source_fmt.format.code);
return -EPIPE;
}

- if (source_fmt.format.width != video->format.fmt.pix.width ||
- source_fmt.format.height != video->format.fmt.pix.height) {
+ if (source_fmt.format.width != capture->format.fmt.pix.width ||
+ source_fmt.format.height != capture->format.fmt.pix.height) {
dev_err(csi_dev->dev,
"Wrong width or height %ux%u (%ux%u expected)\n",
- video->format.fmt.pix.width, video->format.fmt.pix.height,
+ capture->format.fmt.pix.width,
+ capture->format.fmt.pix.height,
source_fmt.format.width, source_fmt.format.height);
return -EPIPE;
}

- video->mbus_code = source_fmt.format.code;
+ capture->mbus_code = source_fmt.format.code;

return 0;
}

-static const struct media_entity_operations sun6i_video_media_ops = {
- .link_validate = sun6i_video_link_validate
+static const struct media_entity_operations sun6i_csi_capture_media_ops = {
+ .link_validate = sun6i_csi_capture_link_validate
};

-/* Video */
+/* Capture */

-int sun6i_video_setup(struct sun6i_csi_device *csi_dev)
+int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_video *video = &csi_dev->video;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev;
struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev;
- struct video_device *video_dev = &video->video_dev;
- struct vb2_queue *queue = &video->queue;
- struct media_pad *pad = &video->pad;
+ struct video_device *video_dev = &capture->video_dev;
+ struct vb2_queue *queue = &capture->queue;
+ struct media_pad *pad = &capture->pad;
struct v4l2_format format = { 0 };
struct v4l2_pix_format *pix_format = &format.fmt.pix;
int ret;

/* Media Entity */

- video_dev->entity.ops = &sun6i_video_media_ops;
+ video_dev->entity.ops = &sun6i_csi_capture_media_ops;

/* Media Pad */

@@ -658,22 +662,22 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev)

/* DMA queue */

- INIT_LIST_HEAD(&video->dma_queue);
- spin_lock_init(&video->dma_queue_lock);
+ INIT_LIST_HEAD(&capture->dma_queue);
+ spin_lock_init(&capture->dma_queue_lock);

- video->sequence = 0;
+ capture->sequence = 0;

/* Queue */

- mutex_init(&video->lock);
+ mutex_init(&capture->lock);

queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
queue->io_modes = VB2_MMAP | VB2_DMABUF;
queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
- queue->ops = &sun6i_video_queue_ops;
+ queue->ops = &sun6i_csi_capture_queue_ops;
queue->mem_ops = &vb2_dma_contig_memops;
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- queue->lock = &video->lock;
+ queue->lock = &capture->lock;
queue->dev = csi_dev->dev;
queue->drv_priv = csi_dev;

@@ -689,12 +693,12 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev)
/* V4L2 Format */

format.type = queue->type;
- pix_format->pixelformat = sun6i_video_formats[0];
+ pix_format->pixelformat = sun6i_csi_capture_formats[0];
pix_format->width = 1280;
pix_format->height = 720;
pix_format->field = V4L2_FIELD_NONE;

- sun6i_video_format_set(video, &format);
+ sun6i_csi_capture_format_set(capture, &format);

/* Video Device */

@@ -702,11 +706,11 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev)
video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
video_dev->vfl_dir = VFL_DIR_RX;
video_dev->release = video_device_release_empty;
- video_dev->fops = &sun6i_video_fops;
- video_dev->ioctl_ops = &sun6i_video_ioctl_ops;
+ video_dev->fops = &sun6i_csi_capture_fops;
+ video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops;
video_dev->v4l2_dev = v4l2_dev;
video_dev->queue = queue;
- video_dev->lock = &video->lock;
+ video_dev->lock = &capture->lock;

video_set_drvdata(video_dev, csi_dev);

@@ -743,17 +747,17 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev)
error_media_entity:
media_entity_cleanup(&video_dev->entity);

- mutex_destroy(&video->lock);
+ mutex_destroy(&capture->lock);

return ret;
}

-void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev)
+void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev)
{
- struct sun6i_video *video = &csi_dev->video;
- struct video_device *video_dev = &video->video_dev;
+ struct sun6i_csi_capture *capture = &csi_dev->capture;
+ struct video_device *video_dev = &capture->video_dev;

vb2_video_unregister_device(video_dev);
media_entity_cleanup(&video_dev->entity);
- mutex_destroy(&video->lock);
+ mutex_destroy(&capture->lock);
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
similarity index 64%
rename from drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
rename to drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
index a917d2da6deb..36bba31fcb48 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h
@@ -5,15 +5,15 @@
* Author: Yong Deng <[email protected]>
*/

-#ifndef __SUN6I_VIDEO_H__
-#define __SUN6I_VIDEO_H__
+#ifndef __SUN6I_CAPTURE_H__
+#define __SUN6I_CAPTURE_H__

#include <media/v4l2-dev.h>
#include <media/videobuf2-core.h>

struct sun6i_csi_device;

-struct sun6i_video {
+struct sun6i_csi_capture {
struct video_device video_dev;
struct vb2_queue queue;
struct mutex lock; /* Queue lock. */
@@ -27,9 +27,9 @@ struct sun6i_video {
unsigned int sequence;
};

-int sun6i_video_setup(struct sun6i_csi_device *csi_dev);
-void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev);
+int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev);

-void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev);
+void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev);

-#endif /* __SUN6I_VIDEO_H__ */
+#endif /* __SUN6I_CAPTURE_H__ */
--
2.35.2

2022-04-16 02:45:53

by Paul Kocialkowski

[permalink] [raw]
Subject: [PATCH v4 19/45] media: sun6i-csi: Rework register definitions, invert misleading fields

This cleans up the register definitions a bit, adds a prefix, remove masks.
Registers are now fully defined, some additional fields were added when
needed. New format definitions are added for future use.

Some fields are wrongly defined (inverted) in Allwinner litterature
(e.g. field vs frame prefixes), which is quite misleading. They are
now corrected to reflect their actual behavior.

This should only be a cosmetic commit. No functional change intended.

Signed-off-by: Paul Kocialkowski <[email protected]>
---
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 182 ++++++-----
.../platform/sunxi/sun6i-csi/sun6i_csi_reg.h | 296 ++++++++++--------
2 files changed, 266 insertions(+), 212 deletions(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 5656faf15d7e..c7b53e8099d3 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -155,7 +155,8 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable)
int ret;

if (!enable) {
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
+ SUN6I_CSI_EN_CSI_EN, 0);
pm_runtime_put(dev);

return 0;
@@ -165,7 +166,8 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable)
if (ret < 0)
return ret;

- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN,
+ SUN6I_CSI_EN_CSI_EN);

return 0;
}
@@ -334,7 +336,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)
struct sun6i_csi_config *config = &csi_dev->config;
unsigned char bus_width;
u32 flags;
- u32 cfg;
+ u32 cfg = 0;
bool input_interlaced = false;

if (config->field == V4L2_FIELD_INTERLACED
@@ -344,52 +346,63 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)

bus_width = endpoint->bus.parallel.bus_width;

- regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg);
-
- cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
- CSI_IF_CFG_IF_DATA_WIDTH_MASK |
- CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK |
- CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK |
- CSI_IF_CFG_SRC_TYPE_MASK);
-
if (input_interlaced)
- cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED;
+ cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
+ SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
+ SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
else
- cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED;
+ cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;

switch (endpoint->bus_type) {
case V4L2_MBUS_PARALLEL:
- cfg |= CSI_IF_CFG_MIPI_IF_CSI;
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI;

flags = endpoint->bus.parallel.flags;

- cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT :
- CSI_IF_CFG_CSI_IF_YUV422_INTLV;
+ if (bus_width == 16)
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;

if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= CSI_IF_CFG_FIELD_POSITIVE;
+ cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;

if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- cfg |= CSI_IF_CFG_VREF_POL_POSITIVE;
+ cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;
+
if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= CSI_IF_CFG_HREF_POL_POSITIVE;
+ cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;

if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
+ cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
break;
case V4L2_MBUS_BT656:
- cfg |= CSI_IF_CFG_MIPI_IF_CSI;
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI;

flags = endpoint->bus.parallel.flags;

- cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 :
- CSI_IF_CFG_CSI_IF_BT656;
+ if (bus_width == 16)
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;

if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= CSI_IF_CFG_FIELD_POSITIVE;
+ cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;

if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
+ cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
+ else
+ cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
break;
default:
dev_warn(csi_dev->dev, "Unsupported bus type: %d\n",
@@ -399,13 +412,13 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)

switch (bus_width) {
case 8:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
+ cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
break;
case 10:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
+ cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
break;
case 12:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
+ cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
break;
case 16: /* No need to configure DATA_WIDTH for 16bit */
break;
@@ -414,42 +427,35 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev)
break;
}

- regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg);
+ regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg);
}

static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev)
{
struct sun6i_csi_config *config = &csi_dev->config;
- u32 cfg;
+ u32 cfg = 0;
u32 val;

- regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg);
-
- cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
- CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
- CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
- CSI_CH_CFG_INPUT_SEQ_MASK);
-
val = get_csi_input_format(csi_dev, config->code,
config->pixelformat);
- cfg |= CSI_CH_CFG_INPUT_FMT(val);
+ cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val);

val = get_csi_output_format(csi_dev, config->pixelformat,
config->field);
- cfg |= CSI_CH_CFG_OUTPUT_FMT(val);
+ cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val);

val = get_csi_input_seq(csi_dev, config->code,
config->pixelformat);
- cfg |= CSI_CH_CFG_INPUT_SEQ(val);
+ cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val);

if (config->field == V4L2_FIELD_TOP)
- cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
+ cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
else if (config->field == V4L2_FIELD_BOTTOM)
- cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
+ cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
else
- cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;
+ cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;

- regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg);
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg);
}

static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
@@ -475,12 +481,12 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
break;
}

- regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG,
- CSI_CH_HSIZE_HOR_LEN(hor_len) |
- CSI_CH_HSIZE_HOR_START(0));
- regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG,
- CSI_CH_VSIZE_VER_LEN(height) |
- CSI_CH_VSIZE_VER_START(0));
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_HSIZE_REG,
+ SUN6I_CSI_CH_HSIZE_LEN(hor_len) |
+ SUN6I_CSI_CH_HSIZE_START(0));
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_VSIZE_REG,
+ SUN6I_CSI_CH_VSIZE_LEN(height) |
+ SUN6I_CSI_CH_VSIZE_START(0));

planar_offset[0] = 0;
switch (config->pixelformat) {
@@ -521,9 +527,9 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev)
break;
}

- regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG,
- CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
- CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_BUF_LEN_REG,
+ SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(bytesperline_c) |
+ SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(bytesperline_y));
}

int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
@@ -544,14 +550,16 @@ int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
dma_addr_t addr)
{
- regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG,
- (addr + csi_dev->planar_offset[0]) >> 2);
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(addr + csi_dev->planar_offset[0]));
if (csi_dev->planar_offset[1] != -1)
- regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG,
- (addr + csi_dev->planar_offset[1]) >> 2);
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(addr +
+ csi_dev->planar_offset[1]));
if (csi_dev->planar_offset[2] != -1)
- regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG,
- (addr + csi_dev->planar_offset[2]) >> 2);
+ regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
+ SUN6I_CSI_ADDR_VALUE(addr +
+ csi_dev->planar_offset[2]));
}

void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
@@ -559,23 +567,25 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
struct regmap *regmap = csi_dev->regmap;

if (!enable) {
- regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
- regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
+ regmap_update_bits(regmap, SUN6I_CSI_CAP_REG,
+ SUN6I_CSI_CAP_VCAP_ON, 0);
+ regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0);
return;
}

- regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
- regmap_write(regmap, CSI_CH_INT_EN_REG,
- CSI_CH_INT_EN_VS_INT_EN |
- CSI_CH_INT_EN_HB_OF_INT_EN |
- CSI_CH_INT_EN_FIFO2_OF_INT_EN |
- CSI_CH_INT_EN_FIFO1_OF_INT_EN |
- CSI_CH_INT_EN_FIFO0_OF_INT_EN |
- CSI_CH_INT_EN_FD_INT_EN |
- CSI_CH_INT_EN_CD_INT_EN);
-
- regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
- CSI_CAP_CH0_VCAP_ON);
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG,
+ SUN6I_CSI_CH_INT_STA_CLEAR);
+ regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG,
+ SUN6I_CSI_CH_INT_EN_VS |
+ SUN6I_CSI_CH_INT_EN_HB_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO2_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO1_OF |
+ SUN6I_CSI_CH_INT_EN_FIFO0_OF |
+ SUN6I_CSI_CH_INT_EN_FD |
+ SUN6I_CSI_CH_INT_EN_CD);
+
+ regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON,
+ SUN6I_CSI_CAP_VCAP_ON);
}

/* Media */
@@ -661,29 +671,31 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
struct regmap *regmap = csi_dev->regmap;
u32 status;

- regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
+ regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status);

if (!(status & 0xFF))
return IRQ_NONE;

- if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) ||
- (status & CSI_CH_INT_STA_FIFO1_OF_PD) ||
- (status & CSI_CH_INT_STA_FIFO2_OF_PD) ||
- (status & CSI_CH_INT_STA_HB_OF_PD)) {
- regmap_write(regmap, CSI_CH_INT_STA_REG, status);
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
- regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
- CSI_EN_CSI_EN);
+ if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) ||
+ (status & SUN6I_CSI_CH_INT_STA_HB_OF)) {
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);
+
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
+ SUN6I_CSI_EN_CSI_EN, 0);
+ regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
+ SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN);
return IRQ_HANDLED;
}

- if (status & CSI_CH_INT_STA_FD_PD)
+ if (status & SUN6I_CSI_CH_INT_STA_FD)
sun6i_csi_capture_frame_done(csi_dev);

- if (status & CSI_CH_INT_STA_VS_PD)
+ if (status & SUN6I_CSI_CH_INT_STA_VS)
sun6i_csi_capture_sync(csi_dev);

- regmap_write(regmap, CSI_CH_INT_STA_REG, status);
+ regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);

return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
index 703fa14bb313..9b0326d6ba3c 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
@@ -10,133 +10,175 @@

#include <linux/kernel.h>

-#define CSI_EN_REG 0x0
-#define CSI_EN_VER_EN BIT(30)
-#define CSI_EN_CSI_EN BIT(0)
-
-#define CSI_IF_CFG_REG 0x4
-#define CSI_IF_CFG_SRC_TYPE_MASK BIT(21)
-#define CSI_IF_CFG_SRC_TYPE_PROGRESSED ((0 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
-#define CSI_IF_CFG_SRC_TYPE_INTERLACED ((1 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
-#define CSI_IF_CFG_FPS_DS_EN BIT(20)
-#define CSI_IF_CFG_FIELD_MASK BIT(19)
-#define CSI_IF_CFG_FIELD_NEGATIVE ((0 << 19) & CSI_IF_CFG_FIELD_MASK)
-#define CSI_IF_CFG_FIELD_POSITIVE ((1 << 19) & CSI_IF_CFG_FIELD_MASK)
-#define CSI_IF_CFG_VREF_POL_MASK BIT(18)
-#define CSI_IF_CFG_VREF_POL_NEGATIVE ((0 << 18) & CSI_IF_CFG_VREF_POL_MASK)
-#define CSI_IF_CFG_VREF_POL_POSITIVE ((1 << 18) & CSI_IF_CFG_VREF_POL_MASK)
-#define CSI_IF_CFG_HREF_POL_MASK BIT(17)
-#define CSI_IF_CFG_HREF_POL_NEGATIVE ((0 << 17) & CSI_IF_CFG_HREF_POL_MASK)
-#define CSI_IF_CFG_HREF_POL_POSITIVE ((1 << 17) & CSI_IF_CFG_HREF_POL_MASK)
-#define CSI_IF_CFG_CLK_POL_MASK BIT(16)
-#define CSI_IF_CFG_CLK_POL_RISING_EDGE ((0 << 16) & CSI_IF_CFG_CLK_POL_MASK)
-#define CSI_IF_CFG_CLK_POL_FALLING_EDGE ((1 << 16) & CSI_IF_CFG_CLK_POL_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_MASK GENMASK(10, 8)
-#define CSI_IF_CFG_IF_DATA_WIDTH_8BIT ((0 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_10BIT ((1 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_IF_DATA_WIDTH_12BIT ((2 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
-#define CSI_IF_CFG_MIPI_IF_MASK BIT(7)
-#define CSI_IF_CFG_MIPI_IF_CSI (0 << 7)
-#define CSI_IF_CFG_MIPI_IF_MIPI BIT(7)
-#define CSI_IF_CFG_CSI_IF_MASK GENMASK(4, 0)
-#define CSI_IF_CFG_CSI_IF_YUV422_INTLV ((0 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_YUV422_16BIT ((1 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_BT656 ((4 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-#define CSI_IF_CFG_CSI_IF_BT1120 ((5 << 0) & CSI_IF_CFG_CSI_IF_MASK)
-
-#define CSI_CAP_REG 0x8
-#define CSI_CAP_CH0_CAP_MASK_MASK GENMASK(5, 2)
-#define CSI_CAP_CH0_CAP_MASK(count) (((count) << 2) & CSI_CAP_CH0_CAP_MASK_MASK)
-#define CSI_CAP_CH0_VCAP_ON BIT(1)
-#define CSI_CAP_CH0_SCAP_ON BIT(0)
-
-#define CSI_SYNC_CNT_REG 0xc
-#define CSI_FIFO_THRS_REG 0x10
-#define CSI_BT656_HEAD_CFG_REG 0x14
-#define CSI_PTN_LEN_REG 0x30
-#define CSI_PTN_ADDR_REG 0x34
-#define CSI_VER_REG 0x3c
-
-#define CSI_CH_CFG_REG 0x44
-#define CSI_CH_CFG_INPUT_FMT_MASK GENMASK(23, 20)
-#define CSI_CH_CFG_INPUT_FMT(fmt) (((fmt) << 20) & CSI_CH_CFG_INPUT_FMT_MASK)
-#define CSI_CH_CFG_OUTPUT_FMT_MASK GENMASK(19, 16)
-#define CSI_CH_CFG_OUTPUT_FMT(fmt) (((fmt) << 16) & CSI_CH_CFG_OUTPUT_FMT_MASK)
-#define CSI_CH_CFG_VFLIP_EN BIT(13)
-#define CSI_CH_CFG_HFLIP_EN BIT(12)
-#define CSI_CH_CFG_FIELD_SEL_MASK GENMASK(11, 10)
-#define CSI_CH_CFG_FIELD_SEL_FIELD0 ((0 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_FIELD_SEL_FIELD1 ((1 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_FIELD_SEL_BOTH ((2 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
-#define CSI_CH_CFG_INPUT_SEQ_MASK GENMASK(9, 8)
-#define CSI_CH_CFG_INPUT_SEQ(seq) (((seq) << 8) & CSI_CH_CFG_INPUT_SEQ_MASK)
-
-#define CSI_CH_SCALE_REG 0x4c
-#define CSI_CH_SCALE_QUART_EN BIT(0)
-
-#define CSI_CH_F0_BUFA_REG 0x50
-
-#define CSI_CH_F1_BUFA_REG 0x58
-
-#define CSI_CH_F2_BUFA_REG 0x60
-
-#define CSI_CH_STA_REG 0x6c
-#define CSI_CH_STA_FIELD_STA_MASK BIT(2)
-#define CSI_CH_STA_FIELD_STA_FIELD0 ((0 << 2) & CSI_CH_STA_FIELD_STA_MASK)
-#define CSI_CH_STA_FIELD_STA_FIELD1 ((1 << 2) & CSI_CH_STA_FIELD_STA_MASK)
-#define CSI_CH_STA_VCAP_STA BIT(1)
-#define CSI_CH_STA_SCAP_STA BIT(0)
-
-#define CSI_CH_INT_EN_REG 0x70
-#define CSI_CH_INT_EN_VS_INT_EN BIT(7)
-#define CSI_CH_INT_EN_HB_OF_INT_EN BIT(6)
-#define CSI_CH_INT_EN_MUL_ERR_INT_EN BIT(5)
-#define CSI_CH_INT_EN_FIFO2_OF_INT_EN BIT(4)
-#define CSI_CH_INT_EN_FIFO1_OF_INT_EN BIT(3)
-#define CSI_CH_INT_EN_FIFO0_OF_INT_EN BIT(2)
-#define CSI_CH_INT_EN_FD_INT_EN BIT(1)
-#define CSI_CH_INT_EN_CD_INT_EN BIT(0)
-
-#define CSI_CH_INT_STA_REG 0x74
-#define CSI_CH_INT_STA_VS_PD BIT(7)
-#define CSI_CH_INT_STA_HB_OF_PD BIT(6)
-#define CSI_CH_INT_STA_MUL_ERR_PD BIT(5)
-#define CSI_CH_INT_STA_FIFO2_OF_PD BIT(4)
-#define CSI_CH_INT_STA_FIFO1_OF_PD BIT(3)
-#define CSI_CH_INT_STA_FIFO0_OF_PD BIT(2)
-#define CSI_CH_INT_STA_FD_PD BIT(1)
-#define CSI_CH_INT_STA_CD_PD BIT(0)
-
-#define CSI_CH_FLD1_VSIZE_REG 0x78
-
-#define CSI_CH_HSIZE_REG 0x80
-#define CSI_CH_HSIZE_HOR_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_HSIZE_HOR_LEN(len) (((len) << 16) & CSI_CH_HSIZE_HOR_LEN_MASK)
-#define CSI_CH_HSIZE_HOR_START_MASK GENMASK(12, 0)
-#define CSI_CH_HSIZE_HOR_START(start) (((start) << 0) & CSI_CH_HSIZE_HOR_START_MASK)
-
-#define CSI_CH_VSIZE_REG 0x84
-#define CSI_CH_VSIZE_VER_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_VSIZE_VER_LEN(len) (((len) << 16) & CSI_CH_VSIZE_VER_LEN_MASK)
-#define CSI_CH_VSIZE_VER_START_MASK GENMASK(12, 0)
-#define CSI_CH_VSIZE_VER_START(start) (((start) << 0) & CSI_CH_VSIZE_VER_START_MASK)
-
-#define CSI_CH_BUF_LEN_REG 0x88
-#define CSI_CH_BUF_LEN_BUF_LEN_C_MASK GENMASK(29, 16)
-#define CSI_CH_BUF_LEN_BUF_LEN_C(len) (((len) << 16) & CSI_CH_BUF_LEN_BUF_LEN_C_MASK)
-#define CSI_CH_BUF_LEN_BUF_LEN_Y_MASK GENMASK(13, 0)
-#define CSI_CH_BUF_LEN_BUF_LEN_Y(len) (((len) << 0) & CSI_CH_BUF_LEN_BUF_LEN_Y_MASK)
-
-#define CSI_CH_FLIP_SIZE_REG 0x8c
-#define CSI_CH_FLIP_SIZE_VER_LEN_MASK GENMASK(28, 16)
-#define CSI_CH_FLIP_SIZE_VER_LEN(len) (((len) << 16) & CSI_CH_FLIP_SIZE_VER_LEN_MASK)
-#define CSI_CH_FLIP_SIZE_VALID_LEN_MASK GENMASK(12, 0)
-#define CSI_CH_FLIP_SIZE_VALID_LEN(len) (((len) << 0) & CSI_CH_FLIP_SIZE_VALID_LEN_MASK)
-
-#define CSI_CH_FRM_CLK_CNT_REG 0x90
-#define CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94
-#define CSI_CH_FIFO_STAT_REG 0x98
-#define CSI_CH_PCLK_STAT_REG 0x9c
+#define SUN6I_CSI_ADDR_VALUE(a) ((a) >> 2)
+
+#define SUN6I_CSI_EN_REG 0x0
+#define SUN6I_CSI_EN_VER_EN BIT(30)
+#define SUN6I_CSI_EN_PTN_CYCLE(v) (((v) << 16) & GENMASK(23, 16))
+#define SUN6I_CSI_EN_SRAM_PWDN BIT(8)
+#define SUN6I_CSI_EN_PTN_START BIT(4)
+#define SUN6I_CSI_EN_CLK_CNT_SPL_VSYNC BIT(3)
+#define SUN6I_CSI_EN_CLK_CNT_EN BIT(2)
+#define SUN6I_CSI_EN_PTN_GEN_EN BIT(1)
+#define SUN6I_CSI_EN_CSI_EN BIT(0)
+
+/* Note that Allwinner manuals and code invert positive/negative definitions. */
+
+#define SUN6I_CSI_IF_CFG_REG 0x4
+#define SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(v) (((v) << 24) & GENMASK(27, 24))
+#define SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE (0 << 21)
+#define SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED (1 << 21)
+#define SUN6I_CSI_IF_CFG_FPS_DS BIT(20)
+#define SUN6I_CSI_IF_CFG_FIELD_POSITIVE (0 << 19)
+#define SUN6I_CSI_IF_CFG_FIELD_NEGATIVE (1 << 19)
+#define SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE (0 << 18)
+#define SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE (1 << 18)
+#define SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE (0 << 17)
+#define SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE (1 << 17)
+#define SUN6I_CSI_IF_CFG_CLK_POL_FALLING (0 << 16)
+#define SUN6I_CSI_IF_CFG_CLK_POL_RISING (1 << 16)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC (0 << 14)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD (1 << 14)
+#define SUN6I_CSI_IF_CFG_FIELD_DT_VSYNC (2 << 14)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8 (0 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_10 (1 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_12 (2 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8_PLUS_2 (3 << 8)
+#define SUN6I_CSI_IF_CFG_DATA_WIDTH_2_TIMES_8 (4 << 8)
+#define SUN6I_CSI_IF_CFG_IF_CSI (0 << 7)
+#define SUN6I_CSI_IF_CFG_IF_MIPI (1 << 7)
+#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW (0 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED (1 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_BT656 (4 << 0)
+#define SUN6I_CSI_IF_CFG_IF_CSI_BT1120 (5 << 0)
+
+#define SUN6I_CSI_CAP_REG 0x8
+#define SUN6I_CSI_CAP_MASK(v) (((v) << 2) & GENMASK(5, 2))
+#define SUN6I_CSI_CAP_VCAP_ON BIT(1)
+#define SUN6I_CSI_CAP_SCAP_ON BIT(0)
+
+#define SUN6I_CSI_SYNC_CNT_REG 0xc
+#define SUN6I_CSI_FIFO_THRS_REG 0x10
+#define SUN6I_CSI_BT656_HEAD_CFG_REG 0x14
+
+#define SUN6I_CSI_PTN_LEN_REG 0x30
+#define SUN6I_CSI_PTN_ADDR_REG 0x34
+#define SUN6I_CSI_VER_REG 0x3c
+
+#define SUN6I_CSI_CH_CFG_REG 0x44
+#define SUN6I_CSI_CH_CFG_PAD_VAL(v) (((v) << 24) & GENMASK(31, 24))
+#define SUN6I_CSI_CH_CFG_INPUT_FMT(v) (((v) << 20) & GENMASK(23, 20))
+#define SUN6I_CSI_CH_CFG_OUTPUT_FMT(v) (((v) << 16) & GENMASK(19, 16))
+#define SUN6I_CSI_CH_CFG_VFLIP_EN BIT(13)
+#define SUN6I_CSI_CH_CFG_HFLIP_EN BIT(12)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0 (0 << 10)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1 (1 << 10)
+#define SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER (2 << 10)
+#define SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(v) (((v) << 8) & GENMASK(9, 8))
+
+#define SUN6I_CSI_INPUT_FMT_RAW 0
+#define SUN6I_CSI_INPUT_FMT_YUV422 3
+#define SUN6I_CSI_INPUT_FMT_YUV420 4
+
+/* Note that Allwinner manuals and code invert frame/field definitions. */
+
+/* RAW */
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8 0
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10 1
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12 2
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565 4
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB888 5
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_PRGB888 6
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8 8
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10 9
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12 10
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565 12
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB888 13
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_PRGB888 14
+
+/* YUV */
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P 0
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P 1
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P 2
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P 3
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP 4
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP 5
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP 6
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP 7
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422MB 8
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB 9
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB 10
+#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422MB 11
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP_10 12
+#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP_10 13
+
+/* YUV Planar */
+#define SUN6I_CSI_INPUT_YUV_SEQ_YUYV 0
+#define SUN6I_CSI_INPUT_YUV_SEQ_YVYU 1
+#define SUN6I_CSI_INPUT_YUV_SEQ_UYVY 2
+#define SUN6I_CSI_INPUT_YUV_SEQ_VYUY 3
+
+/* YUV Semi-planar */
+#define SUN6I_CSI_INPUT_YUV_SEQ_UV 0
+#define SUN6I_CSI_INPUT_YUV_SEQ_VU 1
+
+#define SUN6I_CSI_CH_SCALE_REG 0x4c
+#define SUN6I_CSI_CH_SCALE_QUART_EN BIT(0)
+
+#define SUN6I_CSI_CH_FIFO0_ADDR_REG 0x50
+#define SUN6I_CSI_CH_FIFO1_ADDR_REG 0x58
+#define SUN6I_CSI_CH_FIFO2_ADDR_REG 0x60
+
+#define SUN6I_CSI_CH_STA_REG 0x6c
+#define SUN6I_CSI_CH_STA_FIELD BIT(2)
+#define SUN6I_CSI_CH_STA_VCAP BIT(1)
+#define SUN6I_CSI_CH_STA_SCAP BIT(0)
+
+#define SUN6I_CSI_CH_INT_EN_REG 0x70
+#define SUN6I_CSI_CH_INT_EN_VS BIT(7)
+#define SUN6I_CSI_CH_INT_EN_HB_OF BIT(6)
+#define SUN6I_CSI_CH_INT_EN_MUL_ERR BIT(5)
+#define SUN6I_CSI_CH_INT_EN_FIFO2_OF BIT(4)
+#define SUN6I_CSI_CH_INT_EN_FIFO1_OF BIT(3)
+#define SUN6I_CSI_CH_INT_EN_FIFO0_OF BIT(2)
+#define SUN6I_CSI_CH_INT_EN_FD BIT(1)
+#define SUN6I_CSI_CH_INT_EN_CD BIT(0)
+
+#define SUN6I_CSI_CH_INT_STA_REG 0x74
+#define SUN6I_CSI_CH_INT_STA_CLEAR 0xff
+#define SUN6I_CSI_CH_INT_STA_VS BIT(7)
+#define SUN6I_CSI_CH_INT_STA_HB_OF BIT(6)
+#define SUN6I_CSI_CH_INT_STA_MUL_ERR BIT(5)
+#define SUN6I_CSI_CH_INT_STA_FIFO2_OF BIT(4)
+#define SUN6I_CSI_CH_INT_STA_FIFO1_OF BIT(3)
+#define SUN6I_CSI_CH_INT_STA_FIFO0_OF BIT(2)
+#define SUN6I_CSI_CH_INT_STA_FD BIT(1)
+#define SUN6I_CSI_CH_INT_STA_CD BIT(0)
+
+#define SUN6I_CSI_CH_FLD1_VSIZE_REG 0x78
+#define SUN6I_CSI_CH_FLD1_VSIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_FLD1_VSIZE_VER_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_HSIZE_REG 0x80
+#define SUN6I_CSI_CH_HSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_HSIZE_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_VSIZE_REG 0x84
+#define SUN6I_CSI_CH_VSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_VSIZE_START(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_BUF_LEN_REG 0x88
+#define SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(v) (((v) << 16) & GENMASK(29, 16))
+#define SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(v) ((v) & GENMASK(13, 0))
+
+#define SUN6I_CSI_CH_FLIP_SIZE_REG 0x8c
+#define SUN6I_CSI_CH_FLIP_SIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16))
+#define SUN6I_CSI_CH_FLIP_SIZE_VALID_LEN(v) ((v) & GENMASK(12, 0))
+
+#define SUN6I_CSI_CH_FRM_CLK_CNT_REG 0x90
+#define SUN6I_CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94
+#define SUN6I_CSI_CH_FIFO_STAT_REG 0x98
+#define SUN6I_CSI_CH_PCLK_STAT_REG 0x9c

/*
* csi input data format
--
2.35.2

2022-04-27 18:52:57

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 06/45] media: sun6i-csi: Use runtime pm for clocks and reset

Hi!

Dne petek, 15. april 2022 ob 17:27:32 CEST je Paul Kocialkowski napisal(a):
> Wrap the clock and reset preparation into runtime pm functions
> for better organization of the code. Also fix the clock and
> reset enable order to first deassert reset, as recommended in
> Allwinner litterature.

s/litterature/literature/

Otherwise,
Reviewed-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

>
> Make the driver depend on PM while at it since runtime pm is
> mandatory for the driver to work.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>
> ---
> .../media/platform/sunxi/sun6i-csi/Kconfig | 2 +-
> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++------
> 2 files changed, 60 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig
> b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index
> 0345901617d4..965fbd937841 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig
> +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig
> @@ -2,7 +2,7 @@
> config VIDEO_SUN6I_CSI
> tristate "Allwinner V3s Camera Sensor Interface driver"
> depends on V4L_PLATFORM_DRIVERS
> - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA
> + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM
> depends on ARCH_SUNXI || COMPILE_TEST
> select MEDIA_CONTROLLER
> select VIDEO_V4L2_SUBDEV_API
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> 46d92b925cc8..dcc9e7a125e2 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> @@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device
> *csi_dev, bool enable)
>
> if (!enable) {
> regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
0);
> + pm_runtime_put(dev);
>
> - clk_disable_unprepare(csi_dev->clock_ram);
> - clk_disable_unprepare(csi_dev->clock_mod);
> - reset_control_assert(csi_dev->reset);
> return 0;
> }
>
> - ret = clk_prepare_enable(csi_dev->clock_mod);
> - if (ret) {
> - dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret);
> + ret = pm_runtime_resume_and_get(dev);
> + if (ret < 0)
> return ret;
> - }
> -
> - ret = clk_prepare_enable(csi_dev->clock_ram);
> - if (ret) {
> - dev_err(csi_dev->dev, "Enable clk_dram_csi clk err
%d\n", ret);
> - goto clk_mod_disable;
> - }
> -
> - ret = reset_control_deassert(csi_dev->reset);
> - if (ret) {
> - dev_err(csi_dev->dev, "reset err %d\n", ret);
> - goto clk_ram_disable;
> - }
>
> regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
CSI_EN_CSI_EN);
>
> return 0;
> -
> -clk_ram_disable:
> - clk_disable_unprepare(csi_dev->clock_ram);
> -clk_mod_disable:
> - clk_disable_unprepare(csi_dev->clock_mod);
> - return ret;
> }
>
> static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device
> *csi_dev, @@ -800,6 +778,56 @@ static irqreturn_t sun6i_csi_interrupt(int
> irq, void *private) return IRQ_HANDLED;
> }
>
> +static int sun6i_csi_suspend(struct device *dev)
> +{
> + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
> +
> + reset_control_assert(csi_dev->reset);
> + clk_disable_unprepare(csi_dev->clock_ram);
> + clk_disable_unprepare(csi_dev->clock_mod);
> +
> + return 0;
> +}
> +
> +static int sun6i_csi_resume(struct device *dev)
> +{
> + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = reset_control_deassert(csi_dev->reset);
> + if (ret) {
> + dev_err(dev, "failed to deassert reset\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(csi_dev->clock_mod);
> + if (ret) {
> + dev_err(dev, "failed to enable module clock\n");
> + goto error_reset;
> + }
> +
> + ret = clk_prepare_enable(csi_dev->clock_ram);
> + if (ret) {
> + dev_err(dev, "failed to enable ram clock\n");
> + goto error_clock_mod;
> + }
> +
> + return 0;
> +
> +error_clock_mod:
> + clk_disable_unprepare(csi_dev->clock_mod);
> +
> +error_reset:
> + reset_control_assert(csi_dev->reset);
> +
> + return ret;
> +}
> +
> +static const struct dev_pm_ops sun6i_csi_pm_ops = {
> + .runtime_suspend = sun6i_csi_suspend,
> + .runtime_resume = sun6i_csi_resume,
> +};
> +
> static const struct regmap_config sun6i_csi_regmap_config = {
> .reg_bits = 32,
> .reg_stride = 4,
> @@ -879,6 +907,10 @@ static int sun6i_csi_resources_setup(struct
> sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive;
> }
>
> + /* Runtime PM */
> +
> + pm_runtime_enable(dev);
> +
> return 0;
>
> error_clock_rate_exclusive:
> @@ -889,6 +921,7 @@ static int sun6i_csi_resources_setup(struct
> sun6i_csi_device *csi_dev,
>
> static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev)
> {
> + pm_runtime_disable(csi_dev->dev);
> clk_rate_exclusive_put(csi_dev->clock_mod);
> }
>
> @@ -971,6 +1004,7 @@ static struct platform_driver sun6i_csi_platform_driver
> = { .driver = {
> .name = SUN6I_CSI_NAME,
> .of_match_table =
of_match_ptr(sun6i_csi_of_match),
> + .pm = &sun6i_csi_pm_ops,
> },
> };




2022-04-27 19:27:42

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 21/45] media: sun6i-csi: Implement address configuration without indirection

Dne petek, 15. april 2022 ob 17:27:47 CEST je Paul Kocialkowski napisal(a):
> Instead of calculating the planar_offset at one point and using it
> later in a dedicated function, reimplement address configuration
> with v4l2 format info in the buffer_configure function.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>

Acked-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 27 ----------------
> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 10 ------
> .../sunxi/sun6i-csi/sun6i_csi_capture.c | 32 ++++++++++++++++++-
> 3 files changed, 31 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> c7b53e8099d3..98133c1dbf68 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> @@ -463,7 +463,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device
> *csi_dev) struct sun6i_csi_config *config = &csi_dev->config;
> u32 bytesperline_y;
> u32 bytesperline_c;
> - int *planar_offset = csi_dev->planar_offset;
> u32 width = config->width;
> u32 height = config->height;
> u32 hor_len = width;
> @@ -488,7 +487,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device
> *csi_dev) SUN6I_CSI_CH_VSIZE_LEN(height) |
> SUN6I_CSI_CH_VSIZE_START(0));
>
> - planar_offset[0] = 0;
> switch (config->pixelformat) {
> case V4L2_PIX_FMT_NV12_16L16:
> case V4L2_PIX_FMT_NV12:
> @@ -497,23 +495,15 @@ static void sun6i_csi_set_window(struct
> sun6i_csi_device *csi_dev) case V4L2_PIX_FMT_NV61:
> bytesperline_y = width;
> bytesperline_c = width;
> - planar_offset[1] = bytesperline_y * height;
> - planar_offset[2] = -1;
> break;
> case V4L2_PIX_FMT_YUV420:
> case V4L2_PIX_FMT_YVU420:
> bytesperline_y = width;
> bytesperline_c = width / 2;
> - planar_offset[1] = bytesperline_y * height;
> - planar_offset[2] = planar_offset[1] +
> - bytesperline_c * height / 2;
> break;
> case V4L2_PIX_FMT_YUV422P:
> bytesperline_y = width;
> bytesperline_c = width / 2;
> - planar_offset[1] = bytesperline_y * height;
> - planar_offset[2] = planar_offset[1] +
> - bytesperline_c * height;
> break;
> default: /* raw */
> dev_dbg(csi_dev->dev,
> @@ -522,8 +512,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device
> *csi_dev) bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
> config->width) / 8;
> bytesperline_c = 0;
> - planar_offset[1] = -1;
> - planar_offset[2] = -1;
> break;
> }
>
> @@ -547,21 +535,6 @@ int sun6i_csi_update_config(struct sun6i_csi_device
> *csi_dev, return 0;
> }
>
> -void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
> - dma_addr_t addr)
> -{
> - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
> - SUN6I_CSI_ADDR_VALUE(addr + csi_dev-
>planar_offset[0]));
> - if (csi_dev->planar_offset[1] != -1)
> - regmap_write(csi_dev->regmap,
SUN6I_CSI_CH_FIFO1_ADDR_REG,
> - SUN6I_CSI_ADDR_VALUE(addr +
> - csi_dev-
>planar_offset[1]));
> - if (csi_dev->planar_offset[2] != -1)
> - regmap_write(csi_dev->regmap,
SUN6I_CSI_CH_FIFO2_ADDR_REG,
> - SUN6I_CSI_ADDR_VALUE(addr +
> - csi_dev-
>planar_offset[2]));
> -}
> -
> void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
> {
> struct regmap *regmap = csi_dev->regmap;
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> f02656dbfd84..44fc4d486877 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> @@ -62,8 +62,6 @@ struct sun6i_csi_device {
> struct clk *clock_mod;
> struct clk *clock_ram;
> struct reset_control *reset;
> -
> - int planar_offset[3];
> };
>
> struct sun6i_csi_variant {
> @@ -94,14 +92,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev,
> bool enable); int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev,
> struct sun6i_csi_config *config);
>
> -/**
> - * sun6i_csi_update_buf_addr() - update the csi frame buffer address
> - * @csi: pointer to the csi
> - * @addr: frame buffer's physical address
> - */
> -void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev,
> - dma_addr_t addr);
> -
> /**
> * sun6i_csi_set_stream() - start/stop csi streaming
> * @csi: pointer to the csi
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index
> acbd0ea62fd5..7788cbab7810 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> @@ -6,6 +6,7 @@
> */
>
> #include <linux/of.h>
> +#include <linux/regmap.h>
>
> #include <media/v4l2-device.h>
> #include <media/v4l2-event.h>
> @@ -16,6 +17,7 @@
>
> #include "sun6i_csi.h"
> #include "sun6i_csi_capture.h"
> +#include "sun6i_csi_reg.h"
>
> /* This is got from BSP sources. */
> #define MIN_WIDTH (32)
> @@ -109,13 +111,41 @@ static void
> sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
> struct sun6i_csi_buffer
*csi_buffer)
> {
> + struct regmap *regmap = csi_dev->regmap;
> + const struct v4l2_format_info *info;
> struct vb2_buffer *vb2_buffer;
> + unsigned int width, height;
> dma_addr_t address;
> + u32 pixelformat;
>
> vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
> address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);
>
> - sun6i_csi_update_buf_addr(csi_dev, address);
> + regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
> + SUN6I_CSI_ADDR_VALUE(address));
> +
> + sun6i_csi_capture_dimensions(csi_dev, &width, &height);
> + sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
> +
> + info = v4l2_format_info(pixelformat);
> + /* Unsupported formats are single-plane, so we can stop here. */
> + if (!info)
> + return;
> +
> + if (info->comp_planes > 1) {
> + address += info->bpp[0] * width * height;
> +
> + regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
> + SUN6I_CSI_ADDR_VALUE(address));
> + }
> +
> + if (info->comp_planes > 2) {
> + address += info->bpp[1] * DIV_ROUND_UP(width, info-
>hdiv) *
> + DIV_ROUND_UP(height, info->vdiv);
> +
> + regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
> + SUN6I_CSI_ADDR_VALUE(address));
> + }
> }
>
> static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)




2022-04-27 20:05:37

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 19/45] media: sun6i-csi: Rework register definitions, invert misleading fields

Dne petek, 15. april 2022 ob 17:27:45 CEST je Paul Kocialkowski napisal(a):
> This cleans up the register definitions a bit, adds a prefix, remove masks.
> Registers are now fully defined, some additional fields were added when
> needed. New format definitions are added for future use.
>
> Some fields are wrongly defined (inverted) in Allwinner litterature

s/litterature/literature/

Otherwise,
Acked-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> (e.g. field vs frame prefixes), which is quite misleading. They are
> now corrected to reflect their actual behavior.
>
> This should only be a cosmetic commit. No functional change intended.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>



2022-04-27 20:44:44

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 29/45] media: sun6i-csi: Tidy capture configure code

Dne petek, 15. april 2022 ob 17:27:55 CEST je Paul Kocialkowski napisal(a):
> Some misc code cleanups and preparation for upcoming changes.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>

Acked-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> .../sunxi/sun6i-csi/sun6i_csi_capture.c | 105 ++++++++----------
> 1 file changed, 46 insertions(+), 59 deletions(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index
> e2070353f93f..9488c7c26f13 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> @@ -353,133 +353,120 @@ static enum csi_input_seq get_csi_input_seq(struct
> sun6i_csi_device *csi_dev, static void
> sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev)
> {
> + struct device *dev = csi_dev->dev;
> + struct regmap *regmap = csi_dev->regmap;
> struct v4l2_fwnode_endpoint *endpoint =
> &csi_dev->bridge.source_parallel.endpoint;
> + unsigned char bus_width = endpoint->bus.parallel.bus_width;
> + unsigned int flags = endpoint->bus.parallel.flags;
> u32 pixelformat, field;
> - unsigned char bus_width;
> - u32 flags;
> - u32 cfg = 0;
> - bool input_interlaced = false;
> + u32 value = SUN6I_CSI_IF_CFG_IF_CSI;
>
> sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
>
> if (field == V4L2_FIELD_INTERLACED ||
> field == V4L2_FIELD_INTERLACED_TB ||
> field == V4L2_FIELD_INTERLACED_BT)
> - input_interlaced = true;
> -
> - bus_width = endpoint->bus.parallel.bus_width;
> -
> - if (input_interlaced)
> - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
> - SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
> - SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
> + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED |
> + SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) |
> + SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC;
> else
> - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
> + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
>
> switch (endpoint->bus_type) {
> case V4L2_MBUS_PARALLEL:
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI;
> -
> - flags = endpoint->bus.parallel.flags;
> -
> if (bus_width == 16)
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
> + value |=
SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED;
> else
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;
> + value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW;
>
> if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
> - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
> + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
> else
> - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
> + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
>
> if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
> - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
> + value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE;
> else
> - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;
> + value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE;
>
> if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
> - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
> + value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE;
> else
> - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;
> + value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE;
>
> if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
> - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
> + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
> else
> - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
> + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
> break;
> case V4L2_MBUS_BT656:
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI;
> -
> - flags = endpoint->bus.parallel.flags;
> -
> if (bus_width == 16)
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
> + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120;
> else
> - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;
> + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656;
>
> if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
> - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
> + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE;
> else
> - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
> + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE;
>
> if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
> - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
> + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING;
> else
> - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
> + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING;
> break;
> default:
> - dev_warn(csi_dev->dev, "Unsupported bus type: %d\n",
> - endpoint->bus_type);
> + dev_warn(dev, "unsupported bus type: %d\n", endpoint-
>bus_type);
> break;
> }
>
> switch (bus_width) {
> case 8:
> - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
> + /* 16-bit YUV formats use a doubled width in 8-bit mode. */
> + case 16:
> + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8;
> break;
> case 10:
> - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
> + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10;
> break;
> case 12:
> - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
> - break;
> - case 16: /* No need to configure DATA_WIDTH for 16bit */
> + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12;
> break;
> default:
> - dev_warn(csi_dev->dev, "Unsupported bus width: %u\n",
bus_width);
> + dev_warn(dev, "unsupported bus width: %u\n", bus_width);
> break;
> }
>
> - regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg);
> + regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
> }
>
> static void sun6i_csi_capture_configure_format(struct sun6i_csi_device
> *csi_dev) {
> + struct regmap *regmap = csi_dev->regmap;
> u32 mbus_code, pixelformat, field;
> - u32 cfg = 0;
> - u32 val;
> + u8 input_format, input_yuv_seq, output_format;
> + u32 value = 0;
>
> sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
> sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL);
>
> - val = get_csi_input_format(csi_dev, mbus_code, pixelformat);
> - cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val);
> -
> - val = get_csi_output_format(csi_dev, pixelformat, field);
> - cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val);
> + input_format = get_csi_input_format(csi_dev, mbus_code,
pixelformat);
> + input_yuv_seq = get_csi_input_seq(csi_dev, mbus_code, pixelformat);
> + output_format = get_csi_output_format(csi_dev, pixelformat, field);
>
> - val = get_csi_input_seq(csi_dev, mbus_code, pixelformat);
> - cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val);
> + value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format);
> + value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format);
> + value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq);
>
> if (field == V4L2_FIELD_TOP)
> - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
> + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0;
> else if (field == V4L2_FIELD_BOTTOM)
> - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
> + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1;
> else
> - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;
> + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER;
>
> - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg);
> + regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value);
> }
>
> static void sun6i_csi_capture_configure_window(struct sun6i_csi_device
> *csi_dev)




2022-04-27 20:55:19

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 45/45] MAINTAINERS: Add myself as sun6i-csi maintainer and rename/move entry

Dne petek, 15. april 2022 ob 17:28:11 CEST je Paul Kocialkowski napisal(a):
> Given the substantial rework of the driver that I carried out and the
> knowledge acquired about the hardware along the way, make myself a
> maintainer of the sun6i-csi driver.
>
> Also rename and move the entry while at it since the driver is not
> specific to the V3s.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>

Acked-by; Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> MAINTAINERS | 17 +++++++++--------
> 1 file changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0c7a3c792837..43f456982ecc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -761,6 +761,15 @@ T: git git://linuxtv.org/media_tree.git
> F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-
csi.yaml
> F: drivers/media/platform/sunxi/sun4i-csi/
>
> +ALLWINNER A31 CSI DRIVER
> +M: Yong Deng <[email protected]>
> +M: Paul Kocialkowski <[email protected]>
> +L: [email protected]
> +S: Maintained
> +T: git git://linuxtv.org/media_tree.git
> +F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-
csi.yaml
> +F: drivers/media/platform/sunxi/sun6i-csi/
> +
> ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER
> M: Paul Kocialkowski <[email protected]>
> L: [email protected]
> @@ -5232,14 +5241,6 @@ M: Jaya Kumar <[email protected]>
> S: Maintained
> F: sound/pci/cs5535audio/
>
> -CSI DRIVERS FOR ALLWINNER V3s
> -M: Yong Deng <[email protected]>
> -L: [email protected]
> -S: Maintained
> -T: git git://linuxtv.org/media_tree.git
> -F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-
csi.yaml
> -F: drivers/media/platform/sunxi/sun6i-csi/
> -
> CW1200 WLAN driver
> M: Solomon Peachy <[email protected]>
> S: Maintained




2022-04-27 23:54:49

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 39/45] media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code

Dne petek, 15. april 2022 ob 17:28:05 CEST je Paul Kocialkowski napisal(a):
> Introduce MIPI CSI-2 support to the bridge with a new port, source
> and hardware configuration helper.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>

Acked-by: Jernej Skrabec <[email protected]>

Best regards,
Jernej

> ---
> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 1 +
> .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 46 +++++++++++++++++--
> .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 1 +
> 3 files changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> 1aeaef84abba..6aa83dd11684 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> @@ -21,6 +21,7 @@
>
> enum sun6i_csi_port {
> SUN6I_CSI_PORT_PARALLEL = 0,
> + SUN6I_CSI_PORT_MIPI_CSI2 = 1,
> };
>
> struct sun6i_csi_buffer {
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index
> ec3e04353106..27289d904d5c 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
> @@ -226,7 +226,7 @@ static void sun6i_csi_bridge_disable(struct
> sun6i_csi_device *csi_dev) }
>
> static void
> -sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev)
> +sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev)
> {
> struct device *dev = csi_dev->dev;
> struct regmap *regmap = csi_dev->regmap;
> @@ -316,6 +316,25 @@ sun6i_csi_bridge_configure_interface(struct
> sun6i_csi_device *csi_dev) regmap_write(regmap, SUN6I_CSI_IF_CFG_REG,
> value);
> }
>
> +static void
> +sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev)
> +{
> + struct regmap *regmap = csi_dev->regmap;
> + u32 value = SUN6I_CSI_IF_CFG_IF_MIPI;
> + u32 field;
> +
> + sun6i_csi_bridge_format(csi_dev, NULL, &field);
> +
> + if (field == V4L2_FIELD_INTERLACED ||
> + field == V4L2_FIELD_INTERLACED_TB ||
> + field == V4L2_FIELD_INTERLACED_BT)
> + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED;
> + else
> + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
> +
> + regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
> +}
> +
> static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device
> *csi_dev) {
> struct regmap *regmap = csi_dev->regmap;
> @@ -367,9 +386,16 @@ static void sun6i_csi_bridge_configure_format(struct
> sun6i_csi_device *csi_dev) regmap_write(regmap, SUN6I_CSI_CH_CFG_REG,
> value);
> }
>
> -static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev)
> +static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev,
> + struct
sun6i_csi_bridge_source *source)
> {
> - sun6i_csi_bridge_configure_interface(csi_dev);
> + struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
> +
> + if (source == &bridge->source_parallel)
> + sun6i_csi_bridge_configure_parallel(csi_dev);
> + else
> + sun6i_csi_bridge_configure_mipi_csi2(csi_dev);
> +
> sun6i_csi_bridge_configure_format(csi_dev);
> }
>
> @@ -381,6 +407,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev
> *subdev, int on) struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
> struct media_entity *bridge_entity = &bridge->subdev.entity;
> struct device *dev = csi_dev->dev;
> + struct sun6i_csi_bridge_source *source;
> struct v4l2_subdev *source_subdev;
> struct media_link *link;
> /* Initialize to 0 to use both in disable label (ret != 0) and off.
*/
> @@ -398,6 +425,11 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev
> *subdev, int on)
>
> source_subdev = media_entity_to_v4l2_subdev(link->source->entity);
>
> + if (source_subdev == bridge->source_parallel.subdev)
> + source = &bridge->source_parallel;
> + else
> + source = &bridge->source_mipi_csi2;
> +
> if (!on) {
> v4l2_subdev_call(source_subdev, video, s_stream, 0);
> goto disable;
> @@ -415,7 +447,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev
> *subdev, int on)
>
> /* Configure */
>
> - sun6i_csi_bridge_configure(csi_dev);
> + sun6i_csi_bridge_configure(csi_dev, source);
> sun6i_csi_capture_configure(csi_dev);
>
> /* State Update */
> @@ -607,6 +639,7 @@ sun6i_csi_bridge_notifier_bound(struct
> v4l2_async_notifier *notifier, struct sun6i_csi_bridge_async_subdev
> *bridge_async_subdev =
> container_of(async_subdev, struct
sun6i_csi_bridge_async_subdev,
> async_subdev);
> + struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
> struct sun6i_csi_bridge_source *source = bridge_async_subdev-
>source;
> bool enabled;
>
> @@ -614,6 +647,9 @@ sun6i_csi_bridge_notifier_bound(struct
> v4l2_async_notifier *notifier, case SUN6I_CSI_PORT_PARALLEL:
> enabled = true;
> break;
> + case SUN6I_CSI_PORT_MIPI_CSI2:
> + enabled = !bridge->source_parallel.expected;
> + break;
> default:
> break;
> }
> @@ -760,6 +796,8 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device
> *csi_dev) sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel,
> SUN6I_CSI_PORT_PARALLEL,
> parallel_mbus_types);
> + sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2,
> + SUN6I_CSI_PORT_MIPI_CSI2,
NULL);
>
> ret = v4l2_async_nf_register(v4l2_dev, notifier);
> if (ret) {
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h index
> cb3b27af4607..ee592a14b9c5 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
> @@ -46,6 +46,7 @@ struct sun6i_csi_bridge {
> struct mutex lock; /* Mbus format lock. */
>
> struct sun6i_csi_bridge_source source_parallel;
> + struct sun6i_csi_bridge_source source_mipi_csi2;
> };
>
> /* Helpers */




2022-04-28 05:59:18

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski napisal(a):
> Add a helper to detect whether the ISP is available and connected
> and store the indication in a driver-wide variable.
>
> Signed-off-by: Paul Kocialkowski <[email protected]>
> ---
> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> 2 files changed, 36 insertions(+)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> a88deb8ba1e7..f185cbd113c7 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> @@ -25,6 +25,35 @@
> #include "sun6i_csi_capture.h"
> #include "sun6i_csi_reg.h"
>
> +/* ISP */
> +
> +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> +{
> + struct device *dev = csi_dev->dev;
> + struct fwnode_handle *handle = NULL;
> +
> + /* ISP is not available if disabled in kernel config. */
> + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))

Where is this symbol defined?

Best regards,
Jernej

> + return 0;
> +
> + /*
> + * ISP is not available if not connected via fwnode graph.
> + * This weill also check that the remote parent node is available.
> + */
> + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
> +
SUN6I_CSI_PORT_ISP, 0,
> +
FWNODE_GRAPH_ENDPOINT_NEXT);
> + if (!handle)
> + return 0;
> +
> + fwnode_handle_put(handle);
> +
> + dev_info(dev, "ISP link is available\n");
> + csi_dev->isp_available = true;
> +
> + return 0;
> +}
> +
> /* Media */
>
> static const struct media_device_ops sun6i_csi_media_ops = {
> @@ -306,6 +335,10 @@ static int sun6i_csi_probe(struct platform_device
> *platform_dev) if (ret)
> return ret;
>
> + ret = sun6i_csi_isp_detect(csi_dev);
> + if (ret)
> + goto error_resources;
> +
> ret = sun6i_csi_v4l2_setup(csi_dev);
> if (ret)
> goto error_resources;
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> 6aa83dd11684..9b105c341047 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> @@ -22,6 +22,7 @@
> enum sun6i_csi_port {
> SUN6I_CSI_PORT_PARALLEL = 0,
> SUN6I_CSI_PORT_MIPI_CSI2 = 1,
> + SUN6I_CSI_PORT_ISP = 2,
> };
>
> struct sun6i_csi_buffer {
> @@ -46,6 +47,8 @@ struct sun6i_csi_device {
> struct clk *clock_mod;
> struct clk *clock_ram;
> struct reset_control *reset;
> +
> + bool isp_available;
> };
>
> struct sun6i_csi_variant {




2022-04-28 10:50:42

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

On Thu, Apr 28, 2022 at 09:55:56AM +0200, Paul Kocialkowski wrote:
> Hi Jernej,
>
> Thanks a lot for all your reviews!
>
> On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> > Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski napisal(a):
> > > Add a helper to detect whether the ISP is available and connected
> > > and store the indication in a driver-wide variable.
> > >
> > > Signed-off-by: Paul Kocialkowski <[email protected]>
> > > ---
> > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > > 2 files changed, 36 insertions(+)
> > >
> > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > > a88deb8ba1e7..f185cbd113c7 100644
> > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > @@ -25,6 +25,35 @@
> > > #include "sun6i_csi_capture.h"
> > > #include "sun6i_csi_reg.h"
> > >
> > > +/* ISP */
> > > +
> > > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > > +{
> > > + struct device *dev = csi_dev->dev;
> > > + struct fwnode_handle *handle = NULL;
> > > +
> > > + /* ISP is not available if disabled in kernel config. */
> > > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
> >
> > Where is this symbol defined?
>
> That is defined through Kconfig's auto-generated header, from the associated
> option for the ISP driver. It is defined in the ISP support series so this
> will effectively always be false for now.

Can the ISP be compiled as a module, but the CSI driver built-in? If so,
that would create a dependency from the kernel image to a module, which
won't compile.

Maxime


Attachments:
(No filename) (1.79 kB)
signature.asc (235.00 B)
Download all attachments

2022-04-28 13:02:42

by Paul Kocialkowski

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Hi Jernej,

On Thu 28 Apr 22, 10:09, Jernej Škrabec wrote:
> Dne četrtek, 28. april 2022 ob 09:55:56 CEST je Paul Kocialkowski napisal(a):
> > Hi Jernej,
> >
> > Thanks a lot for all your reviews!
> >
> > On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> > > Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski
> napisal(a):
> > > > Add a helper to detect whether the ISP is available and connected
> > > > and store the indication in a driver-wide variable.
> > > >
> > > > Signed-off-by: Paul Kocialkowski <[email protected]>
> > > > ---
> > > >
> > > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > > > 2 files changed, 36 insertions(+)
> > > >
> > > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > > > a88deb8ba1e7..f185cbd113c7 100644
> > > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > @@ -25,6 +25,35 @@
> > > >
> > > > #include "sun6i_csi_capture.h"
> > > > #include "sun6i_csi_reg.h"
> > > >
> > > > +/* ISP */
> > > > +
> > > > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > > > +{
> > > > + struct device *dev = csi_dev->dev;
> > > > + struct fwnode_handle *handle = NULL;
> > > > +
> > > > + /* ISP is not available if disabled in kernel config. */
> > > > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
> > >
> > > Where is this symbol defined?
> >
> > That is defined through Kconfig's auto-generated header, from the associated
> > option for the ISP driver. It is defined in the ISP support series so this
> > will effectively always be false for now.
>
> Well, then, that driver should be merged before this patch. While I understand
> that it's likely that ISP driver with such name will eventually materialize in
> kernel, I don't want to rely on things that are not set in stone, e.g. already
> merged.

Okay that would make sense, the patches adding ISP support in sun6i-csi could
be moved to the series adding support for the ISP.

Cheers,

Paul

> Best regards,
> Jernej
>
> >
> > > Best regards,
> > > Jernej
> > >
> > > > + return 0;
> > > > +
> > > > + /*
> > > > + * ISP is not available if not connected via fwnode graph.
> > > > + * This weill also check that the remote parent node is available.
> > > > + */
> > > > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
> > > > +
> > >
> > > SUN6I_CSI_PORT_ISP, 0,
> > >
> > > > +
> > >
> > > FWNODE_GRAPH_ENDPOINT_NEXT);
> > >
> > > > + if (!handle)
> > > > + return 0;
> > > > +
> > > > + fwnode_handle_put(handle);
> > > > +
> > > > + dev_info(dev, "ISP link is available\n");
> > > > + csi_dev->isp_available = true;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > >
> > > > /* Media */
> > > >
> > > > static const struct media_device_ops sun6i_csi_media_ops = {
> > > >
> > > > @@ -306,6 +335,10 @@ static int sun6i_csi_probe(struct platform_device
> > > > *platform_dev) if (ret)
> > > >
> > > > return ret;
> > > >
> > > > + ret = sun6i_csi_isp_detect(csi_dev);
> > > > + if (ret)
> > > > + goto error_resources;
> > > > +
> > > >
> > > > ret = sun6i_csi_v4l2_setup(csi_dev);
> > > > if (ret)
> > > >
> > > > goto error_resources;
> > > >
> > > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> > > > 6aa83dd11684..9b105c341047 100644
> > > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > > @@ -22,6 +22,7 @@
> > > >
> > > > enum sun6i_csi_port {
> > > >
> > > > SUN6I_CSI_PORT_PARALLEL = 0,
> > > > SUN6I_CSI_PORT_MIPI_CSI2 = 1,
> > > >
> > > > + SUN6I_CSI_PORT_ISP = 2,
> > > >
> > > > };
> > > >
> > > > struct sun6i_csi_buffer {
> > > >
> > > > @@ -46,6 +47,8 @@ struct sun6i_csi_device {
> > > >
> > > > struct clk *clock_mod;
> > > > struct clk *clock_ram;
> > > > struct reset_control *reset;
> > > >
> > > > +
> > > > + bool isp_available;
> > > >
> > > > };
> > > >
> > > > struct sun6i_csi_variant {
>
>
>
>

--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


Attachments:
(No filename) (4.43 kB)
signature.asc (499.00 B)
Download all attachments

2022-04-28 15:04:46

by Paul Kocialkowski

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Hi Jernej,

Thanks a lot for all your reviews!

On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski napisal(a):
> > Add a helper to detect whether the ISP is available and connected
> > and store the indication in a driver-wide variable.
> >
> > Signed-off-by: Paul Kocialkowski <[email protected]>
> > ---
> > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > 2 files changed, 36 insertions(+)
> >
> > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > a88deb8ba1e7..f185cbd113c7 100644
> > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > @@ -25,6 +25,35 @@
> > #include "sun6i_csi_capture.h"
> > #include "sun6i_csi_reg.h"
> >
> > +/* ISP */
> > +
> > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > +{
> > + struct device *dev = csi_dev->dev;
> > + struct fwnode_handle *handle = NULL;
> > +
> > + /* ISP is not available if disabled in kernel config. */
> > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
>
> Where is this symbol defined?

That is defined through Kconfig's auto-generated header, from the associated
option for the ISP driver. It is defined in the ISP support series so this
will effectively always be false for now.

> Best regards,
> Jernej
>
> > + return 0;
> > +
> > + /*
> > + * ISP is not available if not connected via fwnode graph.
> > + * This weill also check that the remote parent node is available.
> > + */
> > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
> > +
> SUN6I_CSI_PORT_ISP, 0,
> > +
> FWNODE_GRAPH_ENDPOINT_NEXT);
> > + if (!handle)
> > + return 0;
> > +
> > + fwnode_handle_put(handle);
> > +
> > + dev_info(dev, "ISP link is available\n");
> > + csi_dev->isp_available = true;
> > +
> > + return 0;
> > +}
> > +
> > /* Media */
> >
> > static const struct media_device_ops sun6i_csi_media_ops = {
> > @@ -306,6 +335,10 @@ static int sun6i_csi_probe(struct platform_device
> > *platform_dev) if (ret)
> > return ret;
> >
> > + ret = sun6i_csi_isp_detect(csi_dev);
> > + if (ret)
> > + goto error_resources;
> > +
> > ret = sun6i_csi_v4l2_setup(csi_dev);
> > if (ret)
> > goto error_resources;
> > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> > 6aa83dd11684..9b105c341047 100644
> > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > @@ -22,6 +22,7 @@
> > enum sun6i_csi_port {
> > SUN6I_CSI_PORT_PARALLEL = 0,
> > SUN6I_CSI_PORT_MIPI_CSI2 = 1,
> > + SUN6I_CSI_PORT_ISP = 2,
> > };
> >
> > struct sun6i_csi_buffer {
> > @@ -46,6 +47,8 @@ struct sun6i_csi_device {
> > struct clk *clock_mod;
> > struct clk *clock_ram;
> > struct reset_control *reset;
> > +
> > + bool isp_available;
> > };
> >
> > struct sun6i_csi_variant {
>
>
>
>

--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


Attachments:
(No filename) (3.28 kB)
signature.asc (499.00 B)
Download all attachments

2022-04-28 17:29:41

by Paul Kocialkowski

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Hi Maxime,

On Thu 28 Apr 22, 10:11, Maxime Ripard wrote:
> On Thu, Apr 28, 2022 at 09:55:56AM +0200, Paul Kocialkowski wrote:
> > Hi Jernej,
> >
> > Thanks a lot for all your reviews!
> >
> > On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> > > Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski napisal(a):
> > > > Add a helper to detect whether the ISP is available and connected
> > > > and store the indication in a driver-wide variable.
> > > >
> > > > Signed-off-by: Paul Kocialkowski <[email protected]>
> > > > ---
> > > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > > > 2 files changed, 36 insertions(+)
> > > >
> > > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > > > a88deb8ba1e7..f185cbd113c7 100644
> > > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > @@ -25,6 +25,35 @@
> > > > #include "sun6i_csi_capture.h"
> > > > #include "sun6i_csi_reg.h"
> > > >
> > > > +/* ISP */
> > > > +
> > > > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > > > +{
> > > > + struct device *dev = csi_dev->dev;
> > > > + struct fwnode_handle *handle = NULL;
> > > > +
> > > > + /* ISP is not available if disabled in kernel config. */
> > > > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
> > >
> > > Where is this symbol defined?
> >
> > That is defined through Kconfig's auto-generated header, from the associated
> > option for the ISP driver. It is defined in the ISP support series so this
> > will effectively always be false for now.
>
> Can the ISP be compiled as a module, but the CSI driver built-in?

I think so yes, I don't see any reason why not.

> If so,
> that would create a dependency from the kernel image to a module, which
> won't compile.

I think this would introduce a run-time dependency (sun6i-csi needing sun6i-isp
in order to register) but I don't understand why it wouldn't compile though.
Could you ellaborate a bit?

Thanks!

Paul

--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


Attachments:
(No filename) (2.28 kB)
signature.asc (499.00 B)
Download all attachments

2022-04-29 10:37:35

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

Dne četrtek, 28. april 2022 ob 09:55:56 CEST je Paul Kocialkowski napisal(a):
> Hi Jernej,
>
> Thanks a lot for all your reviews!
>
> On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> > Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski
napisal(a):
> > > Add a helper to detect whether the ISP is available and connected
> > > and store the indication in a driver-wide variable.
> > >
> > > Signed-off-by: Paul Kocialkowski <[email protected]>
> > > ---
> > >
> > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > > 2 files changed, 36 insertions(+)
> > >
> > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > > a88deb8ba1e7..f185cbd113c7 100644
> > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > @@ -25,6 +25,35 @@
> > >
> > > #include "sun6i_csi_capture.h"
> > > #include "sun6i_csi_reg.h"
> > >
> > > +/* ISP */
> > > +
> > > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > > +{
> > > + struct device *dev = csi_dev->dev;
> > > + struct fwnode_handle *handle = NULL;
> > > +
> > > + /* ISP is not available if disabled in kernel config. */
> > > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
> >
> > Where is this symbol defined?
>
> That is defined through Kconfig's auto-generated header, from the associated
> option for the ISP driver. It is defined in the ISP support series so this
> will effectively always be false for now.

Well, then, that driver should be merged before this patch. While I understand
that it's likely that ISP driver with such name will eventually materialize in
kernel, I don't want to rely on things that are not set in stone, e.g. already
merged.

Best regards,
Jernej

>
> > Best regards,
> > Jernej
> >
> > > + return 0;
> > > +
> > > + /*
> > > + * ISP is not available if not connected via fwnode graph.
> > > + * This weill also check that the remote parent node is available.
> > > + */
> > > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
> > > +
> >
> > SUN6I_CSI_PORT_ISP, 0,
> >
> > > +
> >
> > FWNODE_GRAPH_ENDPOINT_NEXT);
> >
> > > + if (!handle)
> > > + return 0;
> > > +
> > > + fwnode_handle_put(handle);
> > > +
> > > + dev_info(dev, "ISP link is available\n");
> > > + csi_dev->isp_available = true;
> > > +
> > > + return 0;
> > > +}
> > > +
> > >
> > > /* Media */
> > >
> > > static const struct media_device_ops sun6i_csi_media_ops = {
> > >
> > > @@ -306,6 +335,10 @@ static int sun6i_csi_probe(struct platform_device
> > > *platform_dev) if (ret)
> > >
> > > return ret;
> > >
> > > + ret = sun6i_csi_isp_detect(csi_dev);
> > > + if (ret)
> > > + goto error_resources;
> > > +
> > >
> > > ret = sun6i_csi_v4l2_setup(csi_dev);
> > > if (ret)
> > >
> > > goto error_resources;
> > >
> > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index
> > > 6aa83dd11684..9b105c341047 100644
> > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> > > @@ -22,6 +22,7 @@
> > >
> > > enum sun6i_csi_port {
> > >
> > > SUN6I_CSI_PORT_PARALLEL = 0,
> > > SUN6I_CSI_PORT_MIPI_CSI2 = 1,
> > >
> > > + SUN6I_CSI_PORT_ISP = 2,
> > >
> > > };
> > >
> > > struct sun6i_csi_buffer {
> > >
> > > @@ -46,6 +47,8 @@ struct sun6i_csi_device {
> > >
> > > struct clk *clock_mod;
> > > struct clk *clock_ram;
> > > struct reset_control *reset;
> > >
> > > +
> > > + bool isp_available;
> > >
> > > };
> > >
> > > struct sun6i_csi_variant {




2022-05-03 01:10:09

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v4 43/45] media: sun6i-csi: Detect the availability of the ISP

On Thu, Apr 28, 2022 at 01:43:44PM +0200, Paul Kocialkowski wrote:
> Hi Maxime,
>
> On Thu 28 Apr 22, 10:11, Maxime Ripard wrote:
> > On Thu, Apr 28, 2022 at 09:55:56AM +0200, Paul Kocialkowski wrote:
> > > Hi Jernej,
> > >
> > > Thanks a lot for all your reviews!
> > >
> > > On Wed 27 Apr 22, 22:07, Jernej Škrabec wrote:
> > > > Dne petek, 15. april 2022 ob 17:28:09 CEST je Paul Kocialkowski napisal(a):
> > > > > Add a helper to detect whether the ISP is available and connected
> > > > > and store the indication in a driver-wide variable.
> > > > >
> > > > > Signed-off-by: Paul Kocialkowski <[email protected]>
> > > > > ---
> > > > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++
> > > > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++
> > > > > 2 files changed, 36 insertions(+)
> > > > >
> > > > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index
> > > > > a88deb8ba1e7..f185cbd113c7 100644
> > > > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> > > > > @@ -25,6 +25,35 @@
> > > > > #include "sun6i_csi_capture.h"
> > > > > #include "sun6i_csi_reg.h"
> > > > >
> > > > > +/* ISP */
> > > > > +
> > > > > +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev)
> > > > > +{
> > > > > + struct device *dev = csi_dev->dev;
> > > > > + struct fwnode_handle *handle = NULL;
> > > > > +
> > > > > + /* ISP is not available if disabled in kernel config. */
> > > > > + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP))
> > > >
> > > > Where is this symbol defined?
> > >
> > > That is defined through Kconfig's auto-generated header, from the associated
> > > option for the ISP driver. It is defined in the ISP support series so this
> > > will effectively always be false for now.
> >
> > Can the ISP be compiled as a module, but the CSI driver built-in?
>
> I think so yes, I don't see any reason why not.
>
> > If so,
> > that would create a dependency from the kernel image to a module, which
> > won't compile.
>
> I think this would introduce a run-time dependency (sun6i-csi needing sun6i-isp
> in order to register) but I don't understand why it wouldn't compile though.
> Could you ellaborate a bit?

Never mind, that was a brainfart, I was somehow thinking you wer calling
a function there.

Maxime