2021-02-18 17:04:33 +00:00
|
|
|
From 63f4970ce038e60455a6225b317d0b259e046c94 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
|
|
|
|
Date: Tue, 16 Jun 2020 16:12:39 +0200
|
|
|
|
Subject: [PATCH] media: pxa_camera: Use the new set_mbus_config op
|
|
|
|
|
|
|
|
Upstream https://patchwork.linuxtv.org/patch/64671/
|
|
|
|
|
|
|
|
Move the PXA camera driver to use the new set_mbus_config pad operation.
|
|
|
|
For this platform the change is not only cosmetic, as the pxa driver is
|
|
|
|
currently the only driver in mainline to make use of the g_mbus_config
|
|
|
|
and s_mbus_config video operations.
|
|
|
|
|
|
|
|
The existing driver semantic is the following:
|
|
|
|
- Collect all supported mbus config flags from the remote end
|
|
|
|
- Match them with the supported PXA mbus configuration flags
|
|
|
|
- If the remote subdevice allows multiple options for for VSYNC, HSYNC
|
|
|
|
and PCLK polarity, use platform data requested settings
|
|
|
|
|
|
|
|
The semantic of the new get_mbus_config and set_mbus_config differs from
|
|
|
|
the corresponding video ops, particularly in the fact get_mbus_config
|
|
|
|
reports the current mbus configuration and not the set of supported
|
|
|
|
configuration options, with set_mbus_config always reporting the actual
|
|
|
|
mbus configuration applied to the remote subdevice.
|
|
|
|
|
|
|
|
Adapt the driver to perform the following
|
|
|
|
- Set the remote subdevice mbus configuration according to the PXA
|
|
|
|
platform data preferences.
|
|
|
|
- If the applied configuration differs from the requested one (i.e. the
|
|
|
|
remote subdevice does not allow changing one setting) make sure that
|
|
|
|
- The remote end does not claim for DATA_ACTIVE_LOW, which seems not
|
|
|
|
supported by the platform
|
|
|
|
- The bus mastering roles match
|
|
|
|
|
|
|
|
While at there remove a few checks performed on the media bus
|
|
|
|
configuration at get_format() time as they do not belong there.
|
|
|
|
|
|
|
|
Compile-tested only.
|
|
|
|
|
|
|
|
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
|
|
|
|
---
|
|
|
|
drivers/media/platform/pxa_camera.c | 189 ++++++++--------------------
|
|
|
|
1 file changed, 51 insertions(+), 138 deletions(-)
|
|
|
|
|
|
|
|
--- a/drivers/media/platform/pxa_camera.c
|
|
|
|
+++ b/drivers/media/platform/pxa_camera.c
|
|
|
|
@@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *p
|
|
|
|
return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
|
|
|
|
}
|
|
|
|
|
|
|
|
-static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
|
|
|
|
- unsigned int flags)
|
|
|
|
-{
|
|
|
|
- unsigned long common_flags;
|
|
|
|
- bool hsync = true, vsync = true, pclk, data, mode;
|
|
|
|
- bool mipi_lanes, mipi_clock;
|
|
|
|
-
|
|
|
|
- common_flags = cfg->flags & flags;
|
|
|
|
-
|
|
|
|
- switch (cfg->type) {
|
|
|
|
- case V4L2_MBUS_PARALLEL:
|
|
|
|
- hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_HSYNC_ACTIVE_LOW);
|
|
|
|
- vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_VSYNC_ACTIVE_LOW);
|
|
|
|
- /* fall through */
|
|
|
|
- case V4L2_MBUS_BT656:
|
|
|
|
- pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
|
|
|
|
- V4L2_MBUS_PCLK_SAMPLE_FALLING);
|
|
|
|
- data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_DATA_ACTIVE_LOW);
|
|
|
|
- mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
|
|
|
|
- return (!hsync || !vsync || !pclk || !data || !mode) ?
|
|
|
|
- 0 : common_flags;
|
|
|
|
- case V4L2_MBUS_CSI2_DPHY:
|
|
|
|
- mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
|
|
|
|
- mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
|
|
|
|
- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
|
|
|
|
- return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
|
|
|
|
- default:
|
|
|
|
- WARN_ON(1);
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
|
|
* struct pxa_camera_format_xlate - match between host and sensor formats
|
|
|
|
* @code: code of a sensor provided format
|
|
|
|
@@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int ir
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
-static int test_platform_param(struct pxa_camera_dev *pcdev,
|
|
|
|
- unsigned char buswidth, unsigned long *flags)
|
|
|
|
-{
|
|
|
|
- /*
|
|
|
|
- * Platform specified synchronization and pixel clock polarities are
|
|
|
|
- * only a recommendation and are only used during probing. The PXA270
|
|
|
|
- * quick capture interface supports both.
|
|
|
|
- */
|
|
|
|
- *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
|
|
|
|
- V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) |
|
|
|
|
- V4L2_MBUS_HSYNC_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_HSYNC_ACTIVE_LOW |
|
|
|
|
- V4L2_MBUS_VSYNC_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_VSYNC_ACTIVE_LOW |
|
|
|
|
- V4L2_MBUS_DATA_ACTIVE_HIGH |
|
|
|
|
- V4L2_MBUS_PCLK_SAMPLE_RISING |
|
|
|
|
- V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
|
|
|
-
|
|
|
|
- /* If requested data width is supported by the platform, use it */
|
|
|
|
- if ((1 << (buswidth - 1)) & pcdev->width_flags)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- return -EINVAL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev,
|
|
|
|
unsigned long flags, __u32 pixfmt)
|
|
|
|
{
|
2021-03-04 20:37:13 +00:00
|
|
|
@@ -1601,99 +1540,78 @@ static int pxa_camera_init_videobuf2(str
|
2021-02-18 17:04:33 +00:00
|
|
|
*/
|
|
|
|
static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
|
|
|
|
{
|
|
|
|
+ unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample;
|
|
|
|
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
|
|
|
|
u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc;
|
|
|
|
- unsigned long bus_flags, common_flags;
|
|
|
|
+ int mbus_config;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
- ret = test_platform_param(pcdev,
|
|
|
|
- pcdev->current_fmt->host_fmt->bits_per_sample,
|
|
|
|
- &bus_flags);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
-
|
|
|
|
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
|
|
|
|
- if (!ret) {
|
|
|
|
- common_flags = pxa_mbus_config_compatible(&cfg,
|
|
|
|
- bus_flags);
|
|
|
|
- if (!common_flags) {
|
|
|
|
- dev_warn(pcdev_to_dev(pcdev),
|
|
|
|
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
|
|
|
|
- cfg.flags, bus_flags);
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
- } else if (ret != -ENOIOCTLCMD) {
|
|
|
|
- return ret;
|
|
|
|
- } else {
|
|
|
|
- common_flags = bus_flags;
|
|
|
|
+ if (!((1 << (bus_width - 1)) & pcdev->width_flags)) {
|
|
|
|
+ dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u",
|
|
|
|
+ bus_width);
|
|
|
|
+ return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcdev->channels = 1;
|
|
|
|
|
|
|
|
/* Make choices, based on platform preferences */
|
|
|
|
- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
|
|
|
|
- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
|
|
|
|
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
|
|
|
|
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
|
|
|
|
- else
|
|
|
|
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
|
|
|
|
- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
|
|
|
|
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
|
|
|
|
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
|
|
|
|
- else
|
|
|
|
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
|
|
|
|
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
|
|
|
|
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
|
|
|
|
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
|
|
|
|
- else
|
|
|
|
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cfg.flags = common_flags;
|
|
|
|
- ret = sensor_call(pcdev, video, s_mbus_config, &cfg);
|
|
|
|
- if (ret < 0 && ret != -ENOIOCTLCMD) {
|
|
|
|
- dev_dbg(pcdev_to_dev(pcdev),
|
|
|
|
- "camera s_mbus_config(0x%lx) returned %d\n",
|
|
|
|
- common_flags, ret);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
+ mbus_config = 0;
|
|
|
|
+ if (pcdev->platform_flags & PXA_CAMERA_MASTER)
|
|
|
|
+ mbus_config |= V4L2_MBUS_MASTER;
|
|
|
|
+ else
|
|
|
|
+ mbus_config |= V4L2_MBUS_SLAVE;
|
|
|
|
|
|
|
|
- pxa_camera_setup_cicr(pcdev, common_flags, pixfmt);
|
|
|
|
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
|
|
|
|
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH;
|
|
|
|
+ else
|
|
|
|
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW;
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
|
|
|
|
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH;
|
|
|
|
+ else
|
|
|
|
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW;
|
|
|
|
|
|
|
|
-static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev,
|
|
|
|
- unsigned char buswidth)
|
|
|
|
-{
|
|
|
|
- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
|
|
|
|
- unsigned long bus_flags, common_flags;
|
|
|
|
- int ret = test_platform_param(pcdev, buswidth, &bus_flags);
|
|
|
|
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
|
|
|
|
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING;
|
|
|
|
+ else
|
|
|
|
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
|
|
|
+ mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH;
|
|
|
|
|
|
|
|
- if (ret < 0)
|
|
|
|
+ cfg.flags = mbus_config;
|
|
|
|
+ ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg);
|
|
|
|
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
|
|
|
|
+ dev_err(pcdev_to_dev(pcdev),
|
|
|
|
+ "Failed to call set_mbus_config: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the requested media bus configuration has not been fully applied
|
|
|
|
+ * make sure it is supported by the platform.
|
|
|
|
+ *
|
|
|
|
+ * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering
|
|
|
|
+ * roles should match.
|
|
|
|
+ */
|
|
|
|
+ if (cfg.flags != mbus_config) {
|
|
|
|
+ unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER |
|
|
|
|
+ V4L2_MBUS_SLAVE);
|
|
|
|
+ if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER |
|
|
|
|
+ V4L2_MBUS_SLAVE))) {
|
|
|
|
+ dev_err(pcdev_to_dev(pcdev),
|
|
|
|
+ "Unsupported mbus configuration: bus mastering\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
|
|
|
|
- if (!ret) {
|
|
|
|
- common_flags = pxa_mbus_config_compatible(&cfg,
|
|
|
|
- bus_flags);
|
|
|
|
- if (!common_flags) {
|
|
|
|
- dev_warn(pcdev_to_dev(pcdev),
|
|
|
|
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
|
|
|
|
- cfg.flags, bus_flags);
|
|
|
|
+ if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) {
|
|
|
|
+ dev_err(pcdev_to_dev(pcdev),
|
|
|
|
+ "Unsupported mbus configuration: DATA_ACTIVE_LOW\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
- } else if (ret == -ENOIOCTLCMD) {
|
|
|
|
- ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- return ret;
|
|
|
|
+ pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = {
|
2021-03-04 20:37:13 +00:00
|
|
|
@@ -1741,11 +1659,6 @@ static int pxa_camera_get_formats(struct
|
2021-02-18 17:04:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- /* This also checks support for the requested bits-per-sample */
|
|
|
|
- ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
switch (code.code) {
|
|
|
|
case MEDIA_BUS_FMT_UYVY8_2X8:
|
|
|
|
formats++;
|