2021-03-15 13:16:44

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 00/18] media: gmsl: Reliability improvement

Hello,
this series follows
https://patchwork.linuxtv.org/project/linux-media/list/?series=4650

Compared to the previous iteration the most substantial changes are
- max9271: Add a wakeup() function
- max9271: Add a patch to report errors from max9271_write()
- rdacm21: Re-work ov10640 initialization
Laurent spotted a mis-use of the SPWDN gpio signal. Fixing it an re-applying
the v1 patch that adds the correct delays to the power-up sequence fixes all
the ov10640 sporadic initialization errors \o/
Details in the commit message
- rdacm21: Increase OV490 firmware boot timeout. Details in the commit message.
- media: Propose de-depreaction of subdev init() core operation
- Squash max9286 and rdacm20/21 initialization sequence rework to maintain
bisectability as suggestd by Kieran and Laurent
- Drop i2c speed adjustment as it seems not to have any impact on reliability

Run more than 300 boot tests on the in-development version of the series.
The previous iteration fixed the failure rate down to 13% from the 25% of the
current mainline version.

This new iteration on which I run 80 boot tests gave me a single failure when
tested with RDACM21 and R8A77970 Eagle board \o/

Thanks
j

Jacopo Mondi (18):
media: i2c: rdamc21: Fix warning on u8 cast
media: i2c: rdacm20: Enable noise immunity
media: i2c: rdacm20: Embedded 'serializer' field
media: i2c: rdacm20: Replace goto with a loop
media: i2c: rdacm20: Report camera module name
media: i2c: max9271: Check max9271_write() return
media: i2c: rdacm20: Check return values
media: i2c: rdacm20: Re-work ov10635 reset
media: i2c: max9271: Introduce wake_up() function
media: i2c: max9286: Adjust parameters indent
media: i2c: rdacm21: Fix OV10640 powerdown
media: i2c: rdacm21: Give more time to OV490 to boot
media: i2c: max9286: Rename reverse_channel_mv
media: i2c: max9286: Cache channel amplitude
media: i2c: max9286: Define high channel amplitude
media: v4l2-subdev: De-deprecate init() subdev op
media: gmsl: Reimplement initialization sequence
media: i2c: max9286: Rework comments in .bound()

drivers/media/i2c/max9271.c | 37 +++++++--
drivers/media/i2c/max9271.h | 9 ++
drivers/media/i2c/max9286.c | 61 ++++++++------
drivers/media/i2c/rdacm20.c | 160 ++++++++++++++++++++----------------
drivers/media/i2c/rdacm21.c | 74 ++++++++++-------
include/media/v4l2-subdev.h | 15 +++-
6 files changed, 223 insertions(+), 133 deletions(-)

--
2.30.0


2021-03-15 13:16:46

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 01/18] media: i2c: rdamc21: Fix warning on u8 cast

Sparse reports a warning on a cast to u8 of a 16 bits constant.

drivers/media/i2c/rdacm21.c:348:62: warning: cast truncates bits
from constant value (300a becomes a)

Even if the behaviour is intended, silence the sparse warning replacing
the cast with a bitwise & operation.

Reported-by: Hans Verkuil <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm21.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index dcc21515e5a4..179d107f494c 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -345,7 +345,7 @@ static int ov10640_initialize(struct rdacm21_device *dev)
/* Read OV10640 ID to test communications. */
ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
- ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, (u8)OV10640_CHIP_ID);
+ ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff);

/* Trigger SCCB slave transaction and give it some time to complete. */
ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
--
2.30.0

2021-03-15 13:16:53

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 02/18] media: i2c: rdacm20: Enable noise immunity

Enable the noise immunity threshold at the end of the rdacm20
initialization routine.

The rdacm20 camera module has been so far tested with a startup
delay that allowed the embedded MCU to program the serializer. If
the initialization routine is run before the MCU programs the
serializer and the image sensor and their addresses gets changed
by the rdacm20 driver it is required to manually enable the noise
immunity threshold to make the communication on the control channel
more reliable.

Reviewed-by: Kieran Bingham <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 90eb73f0e6e9..f7fd5ae955d0 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -541,7 +541,13 @@ static int rdacm20_initialize(struct rdacm20_device *dev)

dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");

- return 0;
+ /*
+ * Set reverse channel high threshold to increase noise immunity.
+ *
+ * This should be compensated by increasing the reverse channel
+ * amplitude on the remote deserializer side.
+ */
+ return max9271_set_high_threshold(&dev->serializer, true);
}

static int rdacm20_probe(struct i2c_client *client)
--
2.30.0

2021-03-15 13:17:08

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 04/18] media: i2c: rdacm20: Replace goto with a loop

During the camera module initialization the image sensor PID is read to
verify it can correctly be identified. The current implementation is
rather confused and uses a loop implemented with a label and a goto.

Replace it with a more compact for() loop.

No functional changes intended.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 29 +++++++++++++----------------
1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 4d9bac87cba8..e190fd2e611a 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -59,6 +59,8 @@
*/
#define OV10635_PIXEL_RATE (44000000)

+#define OV10635_PID_TIMEOUT 3
+
static const struct ov10635_reg {
u16 reg;
u8 val;
@@ -452,7 +454,7 @@ static const struct v4l2_subdev_ops rdacm20_subdev_ops = {

static int rdacm20_initialize(struct rdacm20_device *dev)
{
- unsigned int retry = 3;
+ unsigned int i;
int ret;

/* Verify communication with the MAX9271: ping to wakeup. */
@@ -501,23 +503,18 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
return ret;
usleep_range(10000, 15000);

-again:
- ret = ov10635_read16(dev, OV10635_PID);
- if (ret < 0) {
- if (retry--)
- goto again;
+ for (i = 0; i < OV10635_PID_TIMEOUT; ++i) {
+ ret = ov10635_read16(dev, OV10635_PID);
+ if (ret == OV10635_VERSION)
+ break;
+ else if (ret >= 0)
+ /* Sometimes we get a successful read but a wrong id. */
+ dev_dbg(dev->dev, "OV10635 ID mismatch (%d)\n", ret);

- dev_err(dev->dev, "OV10635 ID read failed (%d)\n",
- ret);
- return -ENXIO;
+ usleep_range(1000, 2000);
}
-
- if (ret != OV10635_VERSION) {
- if (retry--)
- goto again;
-
- dev_err(dev->dev, "OV10635 ID mismatch (0x%04x)\n",
- ret);
+ if (i == OV10635_PID_TIMEOUT) {
+ dev_err(dev->dev, "OV10635 ID read failed (%d)\n", ret);
return -ENXIO;
}

--
2.30.0

2021-03-15 13:17:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 06/18] media: i2c: max9271: Check max9271_write() return

Check the return value of the max9271_write() function in the
max9271 library driver.

While at it, modify an existing condition to be made identical
to other checks.

Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9271.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
index c495582dcff6..2c7dc7fb9846 100644
--- a/drivers/media/i2c/max9271.c
+++ b/drivers/media/i2c/max9271.c
@@ -106,7 +106,10 @@ int max9271_set_serial_link(struct max9271_device *dev, bool enable)
* Short delays here appear to show bit-errors in the writes following.
* Therefore a conservative delay seems best here.
*/
- max9271_write(dev, 0x04, val);
+ ret = max9271_write(dev, 0x04, val);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);

return 0;
@@ -118,7 +121,7 @@ int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
int ret;

ret = max9271_write(dev, 0x0d, i2c_config);
- if (ret)
+ if (ret < 0)
return ret;

/* The delay required after an I2C bus configuration change is not
@@ -143,7 +146,10 @@ int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
* Enable or disable reverse channel high threshold to increase
* immunity to power supply noise.
*/
- max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+ ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+ if (ret < 0)
+ return ret;
+
usleep_range(2000, 2500);

return 0;
@@ -152,6 +158,8 @@ EXPORT_SYMBOL_GPL(max9271_set_high_threshold);

int max9271_configure_gmsl_link(struct max9271_device *dev)
{
+ int ret;
+
/*
* Configure the GMSL link:
*
@@ -162,16 +170,24 @@ int max9271_configure_gmsl_link(struct max9271_device *dev)
*
* TODO: Make the GMSL link configuration parametric.
*/
- max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
- MAX9271_EDC_1BIT_PARITY);
+ ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
+ MAX9271_EDC_1BIT_PARITY);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);

/*
* Adjust spread spectrum to +4% and auto-detect pixel clock
* and serial link rate.
*/
- max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
- MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
+ ret = max9271_write(dev, 0x02,
+ MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
+ MAX9271_PCLK_AUTODETECT |
+ MAX9271_SERIAL_AUTODETECT);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);

return 0;
--
2.30.0

2021-03-15 13:17:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 05/18] media: i2c: rdacm20: Report camera module name

When the device is identified the driver currently reports the
names of the chips embedded in the camera module.

Report the name of the camera module itself instead.
Cosmetic change only.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index e190fd2e611a..85456e00ba4f 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -536,7 +536,7 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
if (ret)
return ret;

- dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
+ dev_info(dev->dev, "Identified RDACM20 camera module\n");

/*
* Set reverse channel high threshold to increase noise immunity.
--
2.30.0

2021-03-15 13:17:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 07/18] media: i2c: rdacm20: Check return values

The camera module initialization routine does not check the return
value of a few functions. Fix that.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 85456e00ba4f..312450db958d 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -470,11 +470,16 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
* Ensure that we have a good link configuration before attempting to
* identify the device.
*/
- max9271_configure_i2c(&dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
- MAX9271_I2CSLVTO_1024US |
- MAX9271_I2CMSTBT_105KBPS);
+ ret = max9271_configure_i2c(&dev->serializer,
+ MAX9271_I2CSLVSH_469NS_234NS |
+ MAX9271_I2CSLVTO_1024US |
+ MAX9271_I2CMSTBT_105KBPS);
+ if (ret)
+ return ret;

- max9271_configure_gmsl_link(&dev->serializer);
+ ret = max9271_configure_gmsl_link(&dev->serializer);
+ if (ret)
+ return ret;

ret = max9271_verify_id(&dev->serializer);
if (ret < 0)
--
2.30.0

2021-03-15 13:17:17

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 09/18] media: i2c: max9271: Introduce wake_up() function

The MAX9271 chip manual prescribes a delay of 5 milliseconds
after the chip exists from low power state.

Add a new function to the max9271 library driver that wakes up the chip
with a dummy i2c transaction and implements the correct delay of 5
milliseconds after the chip exits from low power state.

Use the newly introduced function in the rdacm20 and rdacm21 camera
drivers. The former was not respecting the required delay while the
latter was waiting for a too-short timeout.

Do not handle the initial i2c address configuration in the library
driver function as the camera module drivers control address
reprogramming.

Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9271.c | 7 +++++++
drivers/media/i2c/max9271.h | 9 +++++++++
drivers/media/i2c/rdacm20.c | 2 +-
drivers/media/i2c/rdacm21.c | 3 +--
4 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
index 2c7dc7fb9846..f7bfe7266763 100644
--- a/drivers/media/i2c/max9271.c
+++ b/drivers/media/i2c/max9271.c
@@ -80,6 +80,13 @@ static int max9271_pclk_detect(struct max9271_device *dev)
return -EIO;
}

+void max9271_wake_up(struct max9271_device *dev)
+{
+ i2c_smbus_read_byte(dev->client);
+ usleep_range(5000, 8000);
+}
+EXPORT_SYMBOL_GPL(max9271_wake_up);
+
int max9271_set_serial_link(struct max9271_device *dev, bool enable)
{
int ret;
diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271.h
index d78fb21441e9..dc5e4e70ba6f 100644
--- a/drivers/media/i2c/max9271.h
+++ b/drivers/media/i2c/max9271.h
@@ -85,6 +85,15 @@ struct max9271_device {
struct i2c_client *client;
};

+/**
+ * max9271_wake_up() - Wake up the serializer by issuing an i2c transaction
+ * @dev: The max9271 device
+ *
+ * This function shall be called before any other interaction with the
+ * serializer.
+ */
+void max9271_wake_up(struct max9271_device *dev);
+
/**
* max9271_set_serial_link() - Enable/disable serial link
* @dev: The max9271 device
diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index b9aaa0f7db42..2265ef7c65d4 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -459,7 +459,7 @@ static int rdacm20_initialize(struct rdacm20_device *dev)

/* Verify communication with the MAX9271: ping to wakeup. */
dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
- i2c_smbus_read_byte(dev->serializer.client);
+ max9271_wake_up(&dev->serializer);

/* Serial link disabled during config as it needs a valid pixel clock. */
ret = max9271_set_serial_link(&dev->serializer, false);
diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 179d107f494c..7bce55adfd7c 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -452,8 +452,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)

/* Verify communication with the MAX9271: ping to wakeup. */
dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
- i2c_smbus_read_byte(dev->serializer.client);
- usleep_range(3000, 5000);
+ max9271_wake_up(&dev->serializer);

/* Enable reverse channel and disable the serial link. */
ret = max9271_set_serial_link(&dev->serializer, false);
--
2.30.0

2021-03-15 13:17:21

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 10/18] media: i2c: max9286: Adjust parameters indent

The parameters to max9286_i2c_mux_configure() fits on the previous
line. Adjust it.

Cosmetic change only.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 6fd4d59fcc72..1d9951215868 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -287,9 +287,8 @@ static int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)

priv->mux_channel = chan;

- max9286_i2c_mux_configure(priv,
- MAX9286_FWDCCEN(chan) |
- MAX9286_REVCCEN(chan));
+ max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) |
+ MAX9286_REVCCEN(chan));

return 0;
}
--
2.30.0

2021-03-15 13:17:21

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 08/18] media: i2c: rdacm20: Re-work ov10635 reset

The OV10635 image sensor embedded in the camera module is currently
reset after the MAX9271 initialization with two long delays that were
most probably not correctly characterized.

Re-work the image sensor reset procedure by holding the chip in reset
during the MAX9271 configuration, removing the long sleep delays and
only wait after the chip exits from reset for 350-500 microseconds
interval, which is larger than the minimum (2048 * (1 / XVCLK)) timeout
characterized in the chip manual.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 312450db958d..b9aaa0f7db42 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -477,6 +477,19 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
if (ret)
return ret;

+ /*
+ * Hold OV10635 in reset during max9271 configuration. The reset signal
+ * has to be asserted for at least 200 microseconds.
+ */
+ ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
+ if (ret)
+ return ret;
+
+ ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
+ if (ret)
+ return ret;
+ usleep_range(200, 500);
+
ret = max9271_configure_gmsl_link(&dev->serializer);
if (ret)
return ret;
@@ -491,22 +504,14 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
dev->serializer.client->addr = dev->addrs[0];

/*
- * Reset the sensor by cycling the OV10635 reset signal connected to the
- * MAX9271 GPIO1 and verify communication with the OV10635.
+ * Release ov10635 from reset and initialize it. The image sensor
+ * requires at least 2048 XVCLK cycles (85 micro-seconds at 24MHz)
+ * before being available. Stay safe and wait up to 500 micro-seconds.
*/
- ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
- if (ret)
- return ret;
-
- ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
- if (ret)
- return ret;
- usleep_range(10000, 15000);
-
ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
- usleep_range(10000, 15000);
+ usleep_range(100, 500);

for (i = 0; i < OV10635_PID_TIMEOUT; ++i) {
ret = ov10635_read16(dev, OV10635_PID);
--
2.30.0

2021-03-15 13:17:25

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 11/18] media: i2c: rdacm21: Fix OV10640 powerdown

The OV10640 image sensor powerdown signal is controlled by the first
line of the OV490 GPIO pad #1, but the pad #0 identifier
OV490_GPIO_OUTPUT_VALUE0 was erroneously used. As a result the image
sensor powerdown signal was never asserted but was kept high by an
internal pull-up resistor, causing sporadic failures during the
image sensor startup phase.

Fix this by using the correct GPIO pad identifier.

While at it also fix the GPIO signal handling sequence, as the reset
line was released before the powerdown one, and introduce the correct
delays in between the two operations.

Wait the mandatory 1 millisecond delay after the powerup lane is
asserted. The reset delay is not characterized in the chip manual if
not as "255 XVCLK + initialization". Wait for at least 3 milliseconds
to guarantee the SCCB bus is available.

This commit fixes a sporadic start-up error triggered by a failure to
read the OV10640 chip ID:
rdacm21 8-0054: OV10640 ID mismatch: (0x01)

Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm21.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 7bce55adfd7c..50a9b0d8255d 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -333,13 +333,15 @@ static int ov10640_initialize(struct rdacm21_device *dev)
{
u8 val;

- /* Power-up OV10640 by setting RESETB and PWDNB pins high. */
+ /* Power-up OV10640 by setting PWDNB and RESETB pins high. */
ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);
ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);
+
+ ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);
+ usleep_range(1500, 3000);
ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
- ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_SPWDN0);
usleep_range(3000, 5000);

/* Read OV10640 ID to test communications. */
--
2.30.0

2021-03-15 13:17:35

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

It has been observed through repeated testing (250 boots) that in the
10% of the cases the RDACM21 initialization sequence errors out due a
timeout waiting for the OV490 firmware to complete its boot phase.

Albeit being the current timeout relatively large (300-600 milliseconds),
doubling it reduces the sporadic error rate down to 1 over an 80 boot
sequences test run.

The firmware boot delay is unfortunately not characterized in the camera
module manual.

Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm21.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 50a9b0d8255d..07cf077d8efd 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -53,7 +53,7 @@
#define OV490_PID 0x8080300a
#define OV490_VER 0x8080300b
#define OV490_PID_TIMEOUT 20
-#define OV490_OUTPUT_EN_TIMEOUT 300
+#define OV490_OUTPUT_EN_TIMEOUT 600

#define OV490_GPIO0 BIT(0)
#define OV490_SPWDN0 BIT(0)
--
2.30.0

2021-03-15 13:18:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 13/18] media: i2c: max9286: Rename reverse_channel_mv

Rename the reverse_channel_mv variable to init_rev_chan_mv as
the next patch will cache the reverse channel amplitude in
a new driver variable.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 1d9951215868..82ec05e96cb7 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -163,7 +163,8 @@ struct max9286_priv {
unsigned int mux_channel;
bool mux_open;

- u32 reverse_channel_mv;
+ /* The initial reverse control channel amplitude. */
+ u32 init_rev_chan_mv;

struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *pixelrate;
@@ -563,7 +564,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
* - Disable auto-ack as communication on the control channel are now
* stable.
*/
- if (priv->reverse_channel_mv < 170)
+ if (priv->init_rev_chan_mv < 170)
max9286_reverse_channel_setup(priv, 170);
max9286_check_config_link(priv, priv->source_mask);

@@ -971,7 +972,7 @@ static int max9286_setup(struct max9286_priv *priv)
* only. This should be disabled after the mux is initialised.
*/
max9286_configure_i2c(priv, true);
- max9286_reverse_channel_setup(priv, priv->reverse_channel_mv);
+ max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv);

/*
* Enable GMSL links, mask unused ones and autodetect link
@@ -1236,9 +1237,9 @@ static int max9286_parse_dt(struct max9286_priv *priv)
if (of_property_read_u32(dev->of_node,
"maxim,reverse-channel-microvolt",
&reverse_channel_microvolt))
- priv->reverse_channel_mv = 170;
+ priv->init_rev_chan_mv = 170;
else
- priv->reverse_channel_mv = reverse_channel_microvolt / 1000U;
+ priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U;

priv->route_mask = priv->source_mask;

--
2.30.0

2021-03-15 13:18:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 14/18] media: i2c: max9286: Cache channel amplitude

Cache the current channel amplitude in a driver variable
to skip updating it if the newly requested value is the same
as the currently configured one.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 82ec05e96cb7..ed1cdefe7c30 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -165,6 +165,7 @@ struct max9286_priv {

/* The initial reverse control channel amplitude. */
u32 init_rev_chan_mv;
+ u32 rev_chan_mv;

struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *pixelrate;
@@ -341,8 +342,15 @@ static void max9286_configure_i2c(struct max9286_priv *priv, bool localack)
static void max9286_reverse_channel_setup(struct max9286_priv *priv,
unsigned int chan_amplitude)
{
+ u8 chan_config;
+
+ if (priv->rev_chan_mv == chan_amplitude)
+ return;
+
+ priv->rev_chan_mv = chan_amplitude;
+
/* Reverse channel transmission time: default to 1. */
- u8 chan_config = MAX9286_REV_TRF(1);
+ chan_config = MAX9286_REV_TRF(1);

/*
* Reverse channel setup.
@@ -564,8 +572,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
* - Disable auto-ack as communication on the control channel are now
* stable.
*/
- if (priv->init_rev_chan_mv < 170)
- max9286_reverse_channel_setup(priv, 170);
+ max9286_reverse_channel_setup(priv, 170);
max9286_check_config_link(priv, priv->source_mask);

/*
--
2.30.0

2021-03-15 13:18:20

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 16/18] media: v4l2-subdev: De-deprecate init() subdev op

The init() subdev core operation is deemed to be deprecated for new
subdevice drivers. However it could prove useful for complex
architectures to defer operation that require access to the
communication bus if said bus is not available (or fully configured)
at the time when the subdevice probe() function is run.

As an example, the GMSL architecture requires the GMSL configuration
link to be configured on the host side after the remote subdevice
has completed its probe function. After the configuration on the host
side has been performed, the subdevice registers can be accessed through
the communication bus.

In particular:

HOST REMOTE

probe()
|
---------------------> |
probe() {
bus config()
}
|<--------------------|
v4l2 async bound {
bus config()
call subdev init()
|-------------------->|
init() {
access register on the bus()
}
|<-------------------
}

In the GMSL use case the bus configuration requires the enablement of the
noise immunity threshold on the remote side which ensures reliability
of communications in electrically noisy environments. After the subdevice
has enabled the threshold at the end of its probe() sequence the host
side shall compensate it with an higher signal amplitude. Once this
sequence has completed the bus can be accessed with noise protection
enabled and all the operations that require a considerable number of
transactions on the bus (such as the image sensor configuration
sequence) are run in the subdevice init() operation implementation.

Signed-off-by: Jacopo Mondi <[email protected]>
---
include/media/v4l2-subdev.h | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index d0e9a5bdb08b..3068d9940669 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -148,9 +148,18 @@ struct v4l2_subdev_io_pin_config {
* each pin being configured. This function could be called at times
* other than just subdevice initialization.
*
- * @init: initialize the sensor registers to some sort of reasonable default
- * values. Do not use for new drivers and should be removed in existing
- * drivers.
+ * @init: initialize the subdevice registers to some sort of reasonable default
+ * values. Do not use for new drivers (and should be removed in existing
+ * ones) for regular architectures where the image sensor is connected to
+ * the host receiver. For more complex architectures where the subdevice
+ * initialization should be deferred to the completion of the probe
+ * sequence of some intermediate component, or the communication bus
+ * requires configurations on the host side that depend on the completion
+ * of the probe sequence of the remote subdevices, the usage of this
+ * operation could be considered to allow the devices along the pipeline to
+ * probe and register in the media graph and to defer any operation that
+ * require actual access to the communication bus to their init() function
+ * implementation.
*
* @load_fw: load firmware.
*
--
2.30.0

2021-03-15 13:18:39

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 18/18] media: i2c: max9286: Rework comments in .bound()

Re-phrase a comment in .bound() callback to make it clear we register
a subdev notifier and remove a redundant comment about disabling i2c
auto-ack.

No functional changes intended.

Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index b6347639901e..16b2cb9b44a2 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -556,9 +556,9 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
subdev->name, src_pad, index);

/*
- * We can only register v4l2_async_notifiers, which do not provide a
- * means to register a complete callback. bound_sources allows us to
- * identify when all remote serializers have completed their probe.
+ * As we register a subdev notifiers we won't get a .complete() callback
+ * here, so we have to use bound_sources to identify when all remote
+ * serializers have probed.
*/
if (priv->bound_sources != priv->source_mask)
return 0;
@@ -581,16 +581,12 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
/*
* All enabled sources have probed and enabled their reverse control
* channels:
+ * - The reverse channel amplitude stays high
* - Verify all configuration links are properly detected
- * - Disable auto-ack as communication on the control channel are now
- * stable.
+ * - Disable auto-ack as communications on the control channel are now
+ * stable
*/
max9286_check_config_link(priv, priv->source_mask);
-
- /*
- * Re-configure I2C with local acknowledge disabled after cameras have
- * probed.
- */
max9286_configure_i2c(priv, false);

return max9286_set_pixelrate(priv);
--
2.30.0

2021-03-15 13:19:02

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 03/18] media: i2c: rdacm20: Embedded 'serializer' field

There's no reason to allocate dynamically the 'serializer' field in
the driver structure.

Embed the field and adjust all its users in the driver.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/rdacm20.c | 38 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index f7fd5ae955d0..4d9bac87cba8 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -312,7 +312,7 @@ static const struct ov10635_reg {

struct rdacm20_device {
struct device *dev;
- struct max9271_device *serializer;
+ struct max9271_device serializer;
struct i2c_client *sensor;
struct v4l2_subdev sd;
struct media_pad pad;
@@ -399,7 +399,7 @@ static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rdacm20_device *dev = sd_to_rdacm20(sd);

- return max9271_set_serial_link(dev->serializer, enable);
+ return max9271_set_serial_link(&dev->serializer, enable);
}

static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
@@ -456,11 +456,11 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
int ret;

/* Verify communication with the MAX9271: ping to wakeup. */
- dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
- i2c_smbus_read_byte(dev->serializer->client);
+ dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
+ i2c_smbus_read_byte(dev->serializer.client);

/* Serial link disabled during config as it needs a valid pixel clock. */
- ret = max9271_set_serial_link(dev->serializer, false);
+ ret = max9271_set_serial_link(&dev->serializer, false);
if (ret)
return ret;

@@ -468,35 +468,35 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
* Ensure that we have a good link configuration before attempting to
* identify the device.
*/
- max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
- MAX9271_I2CSLVTO_1024US |
- MAX9271_I2CMSTBT_105KBPS);
+ max9271_configure_i2c(&dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
+ MAX9271_I2CSLVTO_1024US |
+ MAX9271_I2CMSTBT_105KBPS);

- max9271_configure_gmsl_link(dev->serializer);
+ max9271_configure_gmsl_link(&dev->serializer);

- ret = max9271_verify_id(dev->serializer);
+ ret = max9271_verify_id(&dev->serializer);
if (ret < 0)
return ret;

- ret = max9271_set_address(dev->serializer, dev->addrs[0]);
+ ret = max9271_set_address(&dev->serializer, dev->addrs[0]);
if (ret < 0)
return ret;
- dev->serializer->client->addr = dev->addrs[0];
+ dev->serializer.client->addr = dev->addrs[0];

/*
* Reset the sensor by cycling the OV10635 reset signal connected to the
* MAX9271 GPIO1 and verify communication with the OV10635.
*/
- ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;

- ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
usleep_range(10000, 15000);

- ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
usleep_range(10000, 15000);
@@ -560,13 +560,7 @@ static int rdacm20_probe(struct i2c_client *client)
if (!dev)
return -ENOMEM;
dev->dev = &client->dev;
-
- dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
- GFP_KERNEL);
- if (!dev->serializer)
- return -ENOMEM;
-
- dev->serializer->client = client;
+ dev->serializer.client = client;

ret = of_property_read_u32_array(client->dev.of_node, "reg",
dev->addrs, 2);
--
2.30.0

2021-03-15 13:20:04

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 15/18] media: i2c: max9286: Define high channel amplitude

Provide a macro to define the reverse channel amplitude to
be used to compensate the remote serializer noise immunity.

While at it, update a comment.

Reviewed-by: Kieran Bingham <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index ed1cdefe7c30..9124d5fa6ea3 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -113,6 +113,7 @@
#define MAX9286_REV_TRF(n) ((n) << 4)
#define MAX9286_REV_AMP(n) ((((n) - 30) / 10) << 1) /* in mV */
#define MAX9286_REV_AMP_X BIT(0)
+#define MAX9286_REV_AMP_HIGH 170
/* Register 0x3f */
#define MAX9286_EN_REV_CFG BIT(6)
#define MAX9286_REV_FLEN(n) ((n) - 20)
@@ -567,12 +568,12 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
* channels:
*
* - Increase the reverse channel amplitude to compensate for the
- * remote ends high threshold, if not done already
+ * remote ends high threshold
* - Verify all configuration links are properly detected
* - Disable auto-ack as communication on the control channel are now
* stable.
*/
- max9286_reverse_channel_setup(priv, 170);
+ max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
max9286_check_config_link(priv, priv->source_mask);

/*
--
2.30.0

2021-03-15 13:20:16

by Jacopo Mondi

[permalink] [raw]
Subject: [PATCH v2 17/18] media: gmsl: Reimplement initialization sequence

The current probe() procedure of the RDACM20 and RDACM20 GMSL cameras is
performed with the embedded MAX9271 serializer's noise immunity
threshold disabled. Once the camera has been initialized by probing the
embedded chips, the threshold is enabled and then compensated on the
deserializer's side by increasing the reverse channel signal amplitude
once all cameras have bound.

The probe routine is thus run without noise immunity activated which
in noisy environment conditions makes the probe sequence less reliable as
the chips configuration requires a relatively high amount of i2c
transactions.

Break chip initialization in two:
- At probe time only configure the serializer's reverse channel with
noise immunity activated, to reduce the number of transactions
performed without noise immunity protection enabled
- Move the chips initialization to the .init() core subdev operation
called by the deserializer after all camera have probed and
have increased their noise immunity threshold

The initialization routine looks like the following:

MAX9286 RDACM20/21

probe()
|
---------------------> |
probe() {
enable_threshold()
}
|<--------------------|
v4l2 async bound {
compensate_amplitude()
call subdev init()
|-------------------->|
init() {
access camera registers()
}
|<-------------------
}

Reviewed-by: Laurent Pinchart <[email protected]>
Reviewed-by: Kieran Bingham <[email protected]>
Signed-off-by: Jacopo Mondi <[email protected]>
---
drivers/media/i2c/max9286.c | 19 ++++++++---
drivers/media/i2c/rdacm20.c | 63 ++++++++++++++++++++++---------------
drivers/media/i2c/rdacm21.c | 63 ++++++++++++++++++++++---------------
3 files changed, 91 insertions(+), 54 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 9124d5fa6ea3..b6347639901e 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -563,17 +563,28 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
if (priv->bound_sources != priv->source_mask)
return 0;

+ /*
+ * Initialize all the remote camera. Increase the channel amplitude
+ * to compensate for the remote noise immunity threshold.
+ */
+ max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
+ for_each_source(priv, source) {
+ ret = v4l2_subdev_call(source->sd, core, init, 0);
+ if (ret) {
+ dev_err(&priv->client->dev,
+ "Failed to initialize camera device %u\n",
+ index);
+ return ret;
+ }
+ }
+
/*
* All enabled sources have probed and enabled their reverse control
* channels:
- *
- * - Increase the reverse channel amplitude to compensate for the
- * remote ends high threshold
* - Verify all configuration links are properly detected
* - Disable auto-ack as communication on the control channel are now
* stable.
*/
- max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
max9286_check_config_link(priv, priv->source_mask);

/*
diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 2265ef7c65d4..57bf4d362cad 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -437,35 +437,12 @@ static int rdacm20_get_fmt(struct v4l2_subdev *sd,
return 0;
}

-static const struct v4l2_subdev_video_ops rdacm20_video_ops = {
- .s_stream = rdacm20_s_stream,
-};
-
-static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = {
- .enum_mbus_code = rdacm20_enum_mbus_code,
- .get_fmt = rdacm20_get_fmt,
- .set_fmt = rdacm20_get_fmt,
-};
-
-static const struct v4l2_subdev_ops rdacm20_subdev_ops = {
- .video = &rdacm20_video_ops,
- .pad = &rdacm20_subdev_pad_ops,
-};
-
-static int rdacm20_initialize(struct rdacm20_device *dev)
+static int rdacm20_init(struct v4l2_subdev *sd, unsigned int val)
{
+ struct rdacm20_device *dev = sd_to_rdacm20(sd);
unsigned int i;
int ret;

- /* Verify communication with the MAX9271: ping to wakeup. */
- dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
- max9271_wake_up(&dev->serializer);
-
- /* Serial link disabled during config as it needs a valid pixel clock. */
- ret = max9271_set_serial_link(&dev->serializer, false);
- if (ret)
- return ret;
-
/*
* Ensure that we have a good link configuration before attempting to
* identify the device.
@@ -548,6 +525,42 @@ static int rdacm20_initialize(struct rdacm20_device *dev)

dev_info(dev->dev, "Identified RDACM20 camera module\n");

+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops rdacm20_core_ops = {
+ .init = rdacm20_init,
+};
+
+static const struct v4l2_subdev_video_ops rdacm20_video_ops = {
+ .s_stream = rdacm20_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = {
+ .enum_mbus_code = rdacm20_enum_mbus_code,
+ .get_fmt = rdacm20_get_fmt,
+ .set_fmt = rdacm20_get_fmt,
+};
+
+static const struct v4l2_subdev_ops rdacm20_subdev_ops = {
+ .core = &rdacm20_core_ops,
+ .video = &rdacm20_video_ops,
+ .pad = &rdacm20_subdev_pad_ops,
+};
+
+static int rdacm20_initialize(struct rdacm20_device *dev)
+{
+ int ret;
+
+ /* Verify communication with the MAX9271: ping to wakeup. */
+ dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
+ max9271_wake_up(&dev->serializer);
+
+ /* Serial link disabled during config as it needs a valid pixel clock. */
+ ret = max9271_set_serial_link(&dev->serializer, false);
+ if (ret)
+ return ret;
+
/*
* Set reverse channel high threshold to increase noise immunity.
*
diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 07cf077d8efd..0fc339d43d98 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -314,21 +314,6 @@ static int rdacm21_get_fmt(struct v4l2_subdev *sd,
return 0;
}

-static const struct v4l2_subdev_video_ops rdacm21_video_ops = {
- .s_stream = rdacm21_s_stream,
-};
-
-static const struct v4l2_subdev_pad_ops rdacm21_subdev_pad_ops = {
- .enum_mbus_code = rdacm21_enum_mbus_code,
- .get_fmt = rdacm21_get_fmt,
- .set_fmt = rdacm21_get_fmt,
-};
-
-static const struct v4l2_subdev_ops rdacm21_subdev_ops = {
- .video = &rdacm21_video_ops,
- .pad = &rdacm21_subdev_pad_ops,
-};
-
static int ov10640_initialize(struct rdacm21_device *dev)
{
u8 val;
@@ -448,19 +433,11 @@ static int ov490_initialize(struct rdacm21_device *dev)
return 0;
}

-static int rdacm21_initialize(struct rdacm21_device *dev)
+static int rdacm21_init(struct v4l2_subdev *sd, unsigned int val)
{
+ struct rdacm21_device *dev = sd_to_rdacm21(sd);
int ret;

- /* Verify communication with the MAX9271: ping to wakeup. */
- dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
- max9271_wake_up(&dev->serializer);
-
- /* Enable reverse channel and disable the serial link. */
- ret = max9271_set_serial_link(&dev->serializer, false);
- if (ret)
- return ret;
-
/* Configure I2C bus at 105Kbps speed and configure GMSL. */
ret = max9271_configure_i2c(&dev->serializer,
MAX9271_I2CSLVSH_469NS_234NS |
@@ -507,6 +484,42 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
if (ret)
return ret;

+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops rdacm21_core_ops = {
+ .init = rdacm21_init,
+};
+
+static const struct v4l2_subdev_video_ops rdacm21_video_ops = {
+ .s_stream = rdacm21_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops rdacm21_subdev_pad_ops = {
+ .enum_mbus_code = rdacm21_enum_mbus_code,
+ .get_fmt = rdacm21_get_fmt,
+ .set_fmt = rdacm21_get_fmt,
+};
+
+static const struct v4l2_subdev_ops rdacm21_subdev_ops = {
+ .core = &rdacm21_core_ops,
+ .video = &rdacm21_video_ops,
+ .pad = &rdacm21_subdev_pad_ops,
+};
+
+static int rdacm21_initialize(struct rdacm21_device *dev)
+{
+ int ret;
+
+ /* Verify communication with the MAX9271: ping to wakeup. */
+ dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
+ max9271_wake_up(&dev->serializer);
+
+ /* Enable reverse channel and disable the serial link. */
+ ret = max9271_set_serial_link(&dev->serializer, false);
+ if (ret)
+ return ret;
+
/*
* Set reverse channel high threshold to increase noise immunity.
*
--
2.30.0

2021-03-15 15:29:26

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 01/18] media: i2c: rdamc21: Fix warning on u8 cast

Hi Jacopo,

On 15/03/2021 13:14, Jacopo Mondi wrote:
> Sparse reports a warning on a cast to u8 of a 16 bits constant.
>
> drivers/media/i2c/rdacm21.c:348:62: warning: cast truncates bits
> from constant value (300a becomes a)
>
> Even if the behaviour is intended, silence the sparse warning replacing
> the cast with a bitwise & operation.
>
> Reported-by: Hans Verkuil <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>

Sounds good to me.

Reviewed-by: Kieran Bingham <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index dcc21515e5a4..179d107f494c 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -345,7 +345,7 @@ static int ov10640_initialize(struct rdacm21_device *dev)
> /* Read OV10640 ID to test communications. */
> ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
> ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
> - ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, (u8)OV10640_CHIP_ID);
> + ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff);
>
> /* Trigger SCCB slave transaction and give it some time to complete. */
> ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
>

2021-03-15 15:31:04

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 03/18] media: i2c: rdacm20: Embedded 'serializer' field

Hi Jacopo,

in $SUBJECT s/Embedded/Embed/

But it's trivial so no worries unless there's another iteration.


On 15/03/2021 13:14, Jacopo Mondi wrote:
> There's no reason to allocate dynamically the 'serializer' field in
> the driver structure.
>
> Embed the field and adjust all its users in the driver.
>
> Reviewed-by: Kieran Bingham <[email protected]>

Still holds ;-)

> Reviewed-by: Laurent Pinchart <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/rdacm20.c | 38 ++++++++++++++++---------------------
> 1 file changed, 16 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index f7fd5ae955d0..4d9bac87cba8 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -312,7 +312,7 @@ static const struct ov10635_reg {
>
> struct rdacm20_device {
> struct device *dev;
> - struct max9271_device *serializer;
> + struct max9271_device serializer;
> struct i2c_client *sensor;
> struct v4l2_subdev sd;
> struct media_pad pad;
> @@ -399,7 +399,7 @@ static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
> {
> struct rdacm20_device *dev = sd_to_rdacm20(sd);
>
> - return max9271_set_serial_link(dev->serializer, enable);
> + return max9271_set_serial_link(&dev->serializer, enable);
> }
>
> static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
> @@ -456,11 +456,11 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
> int ret;
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> - dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
> - i2c_smbus_read_byte(dev->serializer->client);
> + dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
> + i2c_smbus_read_byte(dev->serializer.client);
>
> /* Serial link disabled during config as it needs a valid pixel clock. */
> - ret = max9271_set_serial_link(dev->serializer, false);
> + ret = max9271_set_serial_link(&dev->serializer, false);
> if (ret)
> return ret;
>
> @@ -468,35 +468,35 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
> * Ensure that we have a good link configuration before attempting to
> * identify the device.
> */
> - max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
> - MAX9271_I2CSLVTO_1024US |
> - MAX9271_I2CMSTBT_105KBPS);
> + max9271_configure_i2c(&dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
> + MAX9271_I2CSLVTO_1024US |
> + MAX9271_I2CMSTBT_105KBPS);
>
> - max9271_configure_gmsl_link(dev->serializer);
> + max9271_configure_gmsl_link(&dev->serializer);
>
> - ret = max9271_verify_id(dev->serializer);
> + ret = max9271_verify_id(&dev->serializer);
> if (ret < 0)
> return ret;
>
> - ret = max9271_set_address(dev->serializer, dev->addrs[0]);
> + ret = max9271_set_address(&dev->serializer, dev->addrs[0]);
> if (ret < 0)
> return ret;
> - dev->serializer->client->addr = dev->addrs[0];
> + dev->serializer.client->addr = dev->addrs[0];
>
> /*
> * Reset the sensor by cycling the OV10635 reset signal connected to the
> * MAX9271 GPIO1 and verify communication with the OV10635.
> */
> - ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT);
> + ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
> if (ret)
> return ret;
>
> - ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT);
> + ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
> if (ret)
> return ret;
> usleep_range(10000, 15000);
>
> - ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT);
> + ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);
> if (ret)
> return ret;
> usleep_range(10000, 15000);
> @@ -560,13 +560,7 @@ static int rdacm20_probe(struct i2c_client *client)
> if (!dev)
> return -ENOMEM;
> dev->dev = &client->dev;
> -
> - dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
> - GFP_KERNEL);
> - if (!dev->serializer)
> - return -ENOMEM;
> -
> - dev->serializer->client = client;
> + dev->serializer.client = client;
>
> ret = of_property_read_u32_array(client->dev.of_node, "reg",
> dev->addrs, 2);
>

2021-03-15 15:40:35

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 04/18] media: i2c: rdacm20: Replace goto with a loop

Hi Jacopo,

On 15/03/2021 13:14, Jacopo Mondi wrote:
> During the camera module initialization the image sensor PID is read to
> verify it can correctly be identified. The current implementation is
> rather confused and uses a loop implemented with a label and a goto.
>
> Replace it with a more compact for() loop.
>
> No functional changes intended.
>
> Reviewed-by: Kieran Bingham <[email protected]>
> Reviewed-by: Laurent Pinchart <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/rdacm20.c | 29 +++++++++++++----------------
> 1 file changed, 13 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index 4d9bac87cba8..e190fd2e611a 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -59,6 +59,8 @@
> */
> #define OV10635_PIXEL_RATE (44000000)
>
> +#define OV10635_PID_TIMEOUT 3
> +
> static const struct ov10635_reg {
> u16 reg;
> u8 val;
> @@ -452,7 +454,7 @@ static const struct v4l2_subdev_ops rdacm20_subdev_ops = {
>
> static int rdacm20_initialize(struct rdacm20_device *dev)
> {
> - unsigned int retry = 3;
> + unsigned int i;
> int ret;
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> @@ -501,23 +503,18 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
> return ret;
> usleep_range(10000, 15000);
>
> -again:
> - ret = ov10635_read16(dev, OV10635_PID);
> - if (ret < 0) {
> - if (retry--)
> - goto again;
> + for (i = 0; i < OV10635_PID_TIMEOUT; ++i) {
> + ret = ov10635_read16(dev, OV10635_PID);
> + if (ret == OV10635_VERSION)
> + break;
> + else if (ret >= 0)
> + /* Sometimes we get a successful read but a wrong id. */

Trivial/nit, I'd have written "but an incorrect ID."

But that's not worthy of any respin.

> + dev_dbg(dev->dev, "OV10635 ID mismatch (%d)\n", ret);

Thanks, this alleviates my concerns from the previous version.



>
> - dev_err(dev->dev, "OV10635 ID read failed (%d)\n",
> - ret);
> - return -ENXIO;
> + usleep_range(1000, 2000);
> }
> -
> - if (ret != OV10635_VERSION) {
> - if (retry--)
> - goto again;
> -
> - dev_err(dev->dev, "OV10635 ID mismatch (0x%04x)\n",
> - ret);
> + if (i == OV10635_PID_TIMEOUT) {
> + dev_err(dev->dev, "OV10635 ID read failed (%d)\n", ret);
> return -ENXIO;
> }
>
>

2021-03-15 15:48:17

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 06/18] media: i2c: max9271: Check max9271_write() return

Hi Jacopo,

On 15/03/2021 13:15, Jacopo Mondi wrote:
> Check the return value of the max9271_write() function in the
> max9271 library driver.
>
> While at it, modify an existing condition to be made identical
> to other checks.

Excellent, much better to catch write errors early.

Reviewed-by: Kieran Bingham <[email protected]>


> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/max9271.c | 30 +++++++++++++++++++++++-------
> 1 file changed, 23 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
> index c495582dcff6..2c7dc7fb9846 100644
> --- a/drivers/media/i2c/max9271.c
> +++ b/drivers/media/i2c/max9271.c
> @@ -106,7 +106,10 @@ int max9271_set_serial_link(struct max9271_device *dev, bool enable)
> * Short delays here appear to show bit-errors in the writes following.
> * Therefore a conservative delay seems best here.
> */
> - max9271_write(dev, 0x04, val);
> + ret = max9271_write(dev, 0x04, val);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> return 0;
> @@ -118,7 +121,7 @@ int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
> int ret;
>
> ret = max9271_write(dev, 0x0d, i2c_config);
> - if (ret)
> + if (ret < 0)
> return ret;
>
> /* The delay required after an I2C bus configuration change is not
> @@ -143,7 +146,10 @@ int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
> * Enable or disable reverse channel high threshold to increase
> * immunity to power supply noise.
> */
> - max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
> + ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
> + if (ret < 0)
> + return ret;
> +
> usleep_range(2000, 2500);
>
> return 0;
> @@ -152,6 +158,8 @@ EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
>
> int max9271_configure_gmsl_link(struct max9271_device *dev)
> {
> + int ret;
> +
> /*
> * Configure the GMSL link:
> *
> @@ -162,16 +170,24 @@ int max9271_configure_gmsl_link(struct max9271_device *dev)
> *
> * TODO: Make the GMSL link configuration parametric.
> */
> - max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
> - MAX9271_EDC_1BIT_PARITY);
> + ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
> + MAX9271_EDC_1BIT_PARITY);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> /*
> * Adjust spread spectrum to +4% and auto-detect pixel clock
> * and serial link rate.
> */
> - max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
> - MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
> + ret = max9271_write(dev, 0x02,
> + MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
> + MAX9271_PCLK_AUTODETECT |
> + MAX9271_SERIAL_AUTODETECT);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> return 0;
>

2021-03-15 17:16:55

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] media: i2c: max9271: Introduce wake_up() function

On 15/03/2021 13:15, Jacopo Mondi wrote:
> The MAX9271 chip manual prescribes a delay of 5 milliseconds
> after the chip exists from low power state.
>
> Add a new function to the max9271 library driver that wakes up the chip
> with a dummy i2c transaction and implements the correct delay of 5
> milliseconds after the chip exits from low power state.
>
> Use the newly introduced function in the rdacm20 and rdacm21 camera
> drivers. The former was not respecting the required delay while the
> latter was waiting for a too-short timeout.
>
> Do not handle the initial i2c address configuration in the library
> driver function as the camera module drivers control address
> reprogramming.

I still think that the MAX9271_DEFAULT_ADDR belongs in the max9271
library, but this patch is functionally good to me, and correcting those
delays is certainly a good thing to fix here.

Reviewed-by: Kieran Bingham <[email protected]>


> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/max9271.c | 7 +++++++
> drivers/media/i2c/max9271.h | 9 +++++++++
> drivers/media/i2c/rdacm20.c | 2 +-
> drivers/media/i2c/rdacm21.c | 3 +--
> 4 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
> index 2c7dc7fb9846..f7bfe7266763 100644
> --- a/drivers/media/i2c/max9271.c
> +++ b/drivers/media/i2c/max9271.c
> @@ -80,6 +80,13 @@ static int max9271_pclk_detect(struct max9271_device *dev)
> return -EIO;
> }
>
> +void max9271_wake_up(struct max9271_device *dev)
> +{
> + i2c_smbus_read_byte(dev->client);
> + usleep_range(5000, 8000);
> +}
> +EXPORT_SYMBOL_GPL(max9271_wake_up);
> +
> int max9271_set_serial_link(struct max9271_device *dev, bool enable)
> {
> int ret;
> diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271.h
> index d78fb21441e9..dc5e4e70ba6f 100644
> --- a/drivers/media/i2c/max9271.h
> +++ b/drivers/media/i2c/max9271.h
> @@ -85,6 +85,15 @@ struct max9271_device {
> struct i2c_client *client;
> };
>
> +/**
> + * max9271_wake_up() - Wake up the serializer by issuing an i2c transaction
> + * @dev: The max9271 device
> + *
> + * This function shall be called before any other interaction with the
> + * serializer.
> + */
> +void max9271_wake_up(struct max9271_device *dev);
> +
> /**
> * max9271_set_serial_link() - Enable/disable serial link
> * @dev: The max9271 device
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index b9aaa0f7db42..2265ef7c65d4 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -459,7 +459,7 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
> - i2c_smbus_read_byte(dev->serializer.client);
> + max9271_wake_up(&dev->serializer);
>
> /* Serial link disabled during config as it needs a valid pixel clock. */
> ret = max9271_set_serial_link(&dev->serializer, false);
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 179d107f494c..7bce55adfd7c 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -452,8 +452,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
> - i2c_smbus_read_byte(dev->serializer.client);
> - usleep_range(3000, 5000);
> + max9271_wake_up(&dev->serializer);
>
> /* Enable reverse channel and disable the serial link. */
> ret = max9271_set_serial_link(&dev->serializer, false);
>

2021-03-15 17:24:04

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 11/18] media: i2c: rdacm21: Fix OV10640 powerdown

Hi Jacopo,

On 15/03/2021 13:15, Jacopo Mondi wrote:
> The OV10640 image sensor powerdown signal is controlled by the first
> line of the OV490 GPIO pad #1, but the pad #0 identifier
> OV490_GPIO_OUTPUT_VALUE0 was erroneously used. As a result the image
> sensor powerdown signal was never asserted but was kept high by an
> internal pull-up resistor, causing sporadic failures during the
> image sensor startup phase.
>
> Fix this by using the correct GPIO pad identifier.
>
> While at it also fix the GPIO signal handling sequence, as the reset
> line was released before the powerdown one, and introduce the correct
> delays in between the two operations.
>
> Wait the mandatory 1 millisecond delay after the powerup lane is

Technically you wait 1.5 milliseconds below - but I think that's fine
here ;-)

> asserted. The reset delay is not characterized in the chip manual if
> not as "255 XVCLK + initialization". Wait for at least 3 milliseconds
> to guarantee the SCCB bus is available.
>
> This commit fixes a sporadic start-up error triggered by a failure to
> read the OV10640 chip ID:
> rdacm21 8-0054: OV10640 ID mismatch: (0x01)
>
> Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> Signed-off-by: Jacopo Mondi <[email protected]>

Sometime it might be nice to see this look more like the GPIO
interfaces, but I think this is fine for now.

Reviewed-by: Kieran Bingham <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 7bce55adfd7c..50a9b0d8255d 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -333,13 +333,15 @@ static int ov10640_initialize(struct rdacm21_device *dev)
> {
> u8 val;
>
> - /* Power-up OV10640 by setting RESETB and PWDNB pins high. */
> + /* Power-up OV10640 by setting PWDNB and RESETB pins high. */
> ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
> ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
> ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);
> ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);
> +
> + ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);
> + usleep_range(1500, 3000);
> ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
> - ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_SPWDN0);
> usleep_range(3000, 5000);
>
> /* Read OV10640 ID to test communications. */
>

2021-03-15 18:40:16

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

On 15/03/2021 13:15, Jacopo Mondi wrote:
> It has been observed through repeated testing (250 boots) that in the
> 10% of the cases the RDACM21 initialization sequence errors out due a
> timeout waiting for the OV490 firmware to complete its boot phase.
>
> Albeit being the current timeout relatively large (300-600 milliseconds),
> doubling it reduces the sporadic error rate down to 1 over an 80 boot
> sequences test run.
>
> The firmware boot delay is unfortunately not characterized in the camera
> module manual.
>

I wonder if we could characterize this alone by pulling this down until
we see failures increase, with all the other fixes in place...

I don't think that's required, but it might be something to check later
if we don't get rid of that 1/80 failure.



> Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Kieran Bingham <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 50a9b0d8255d..07cf077d8efd 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -53,7 +53,7 @@
> #define OV490_PID 0x8080300a
> #define OV490_VER 0x8080300b
> #define OV490_PID_TIMEOUT 20
> -#define OV490_OUTPUT_EN_TIMEOUT 300
> +#define OV490_OUTPUT_EN_TIMEOUT 600
>
> #define OV490_GPIO0 BIT(0)
> #define OV490_SPWDN0 BIT(0)
>

2021-03-15 18:41:51

by Kieran Bingham

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] media: i2c: max9286: Rework comments in .bound()

On 15/03/2021 13:15, Jacopo Mondi wrote:
> Re-phrase a comment in .bound() callback to make it clear we register
> a subdev notifier and remove a redundant comment about disabling i2c
> auto-ack.
>
> No functional changes intended.
>
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Kieran Bingham <[email protected]>

> ---
> drivers/media/i2c/max9286.c | 16 ++++++----------
> 1 file changed, 6 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> index b6347639901e..16b2cb9b44a2 100644
> --- a/drivers/media/i2c/max9286.c
> +++ b/drivers/media/i2c/max9286.c
> @@ -556,9 +556,9 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
> subdev->name, src_pad, index);
>
> /*
> - * We can only register v4l2_async_notifiers, which do not provide a
> - * means to register a complete callback. bound_sources allows us to
> - * identify when all remote serializers have completed their probe.
> + * As we register a subdev notifiers we won't get a .complete() callback
> + * here, so we have to use bound_sources to identify when all remote
> + * serializers have probed.
> */
> if (priv->bound_sources != priv->source_mask)
> return 0;
> @@ -581,16 +581,12 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
> /*
> * All enabled sources have probed and enabled their reverse control
> * channels:
> + * - The reverse channel amplitude stays high
> * - Verify all configuration links are properly detected
> - * - Disable auto-ack as communication on the control channel are now
> - * stable.
> + * - Disable auto-ack as communications on the control channel are now
> + * stable
> */
> max9286_check_config_link(priv, priv->source_mask);
> -
> - /*
> - * Re-configure I2C with local acknowledge disabled after cameras have
> - * probed.
> - */
> max9286_configure_i2c(priv, false);
>
> return max9286_set_pixelrate(priv);
>

2021-03-15 22:01:46

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 01/18] media: i2c: rdamc21: Fix warning on u8 cast

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:14:55PM +0100, Jacopo Mondi wrote:
> Sparse reports a warning on a cast to u8 of a 16 bits constant.
>
> drivers/media/i2c/rdacm21.c:348:62: warning: cast truncates bits
> from constant value (300a becomes a)
>
> Even if the behaviour is intended, silence the sparse warning replacing
> the cast with a bitwise & operation.
>
> Reported-by: Hans Verkuil <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Laurent Pinchart <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index dcc21515e5a4..179d107f494c 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -345,7 +345,7 @@ static int ov10640_initialize(struct rdacm21_device *dev)
> /* Read OV10640 ID to test communications. */
> ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
> ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
> - ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, (u8)OV10640_CHIP_ID);
> + ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff);
>
> /* Trigger SCCB slave transaction and give it some time to complete. */
> ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);

--
Regards,

Laurent Pinchart

2021-03-15 22:01:48

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 02/18] media: i2c: rdacm20: Enable noise immunity

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:14:56PM +0100, Jacopo Mondi wrote:
> Enable the noise immunity threshold at the end of the rdacm20
> initialization routine.
>
> The rdacm20 camera module has been so far tested with a startup
> delay that allowed the embedded MCU to program the serializer. If
> the initialization routine is run before the MCU programs the
> serializer and the image sensor and their addresses gets changed
> by the rdacm20 driver it is required to manually enable the noise
> immunity threshold to make the communication on the control channel
> more reliable.

I'm still worried by the race with the MCU. Any update on dumping the
MCU configuration to check what it initializes ?

> Reviewed-by: Kieran Bingham <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/rdacm20.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index 90eb73f0e6e9..f7fd5ae955d0 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -541,7 +541,13 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
>
> dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
>
> - return 0;
> + /*
> + * Set reverse channel high threshold to increase noise immunity.
> + *
> + * This should be compensated by increasing the reverse channel
> + * amplitude on the remote deserializer side.
> + */
> + return max9271_set_high_threshold(&dev->serializer, true);
> }
>
> static int rdacm20_probe(struct i2c_client *client)

--
Regards,

Laurent Pinchart

2021-03-15 22:01:52

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 06/18] media: i2c: max9271: Check max9271_write() return

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:00PM +0100, Jacopo Mondi wrote:
> Check the return value of the max9271_write() function in the
> max9271 library driver.
>
> While at it, modify an existing condition to be made identical
> to other checks.
>
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Laurent Pinchart <[email protected]>

> ---
> drivers/media/i2c/max9271.c | 30 +++++++++++++++++++++++-------
> 1 file changed, 23 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
> index c495582dcff6..2c7dc7fb9846 100644
> --- a/drivers/media/i2c/max9271.c
> +++ b/drivers/media/i2c/max9271.c
> @@ -106,7 +106,10 @@ int max9271_set_serial_link(struct max9271_device *dev, bool enable)
> * Short delays here appear to show bit-errors in the writes following.
> * Therefore a conservative delay seems best here.
> */
> - max9271_write(dev, 0x04, val);
> + ret = max9271_write(dev, 0x04, val);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> return 0;
> @@ -118,7 +121,7 @@ int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
> int ret;
>
> ret = max9271_write(dev, 0x0d, i2c_config);
> - if (ret)
> + if (ret < 0)
> return ret;
>
> /* The delay required after an I2C bus configuration change is not
> @@ -143,7 +146,10 @@ int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
> * Enable or disable reverse channel high threshold to increase
> * immunity to power supply noise.
> */
> - max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
> + ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
> + if (ret < 0)
> + return ret;
> +
> usleep_range(2000, 2500);
>
> return 0;
> @@ -152,6 +158,8 @@ EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
>
> int max9271_configure_gmsl_link(struct max9271_device *dev)
> {
> + int ret;
> +
> /*
> * Configure the GMSL link:
> *
> @@ -162,16 +170,24 @@ int max9271_configure_gmsl_link(struct max9271_device *dev)
> *
> * TODO: Make the GMSL link configuration parametric.
> */
> - max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
> - MAX9271_EDC_1BIT_PARITY);
> + ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
> + MAX9271_EDC_1BIT_PARITY);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> /*
> * Adjust spread spectrum to +4% and auto-detect pixel clock
> * and serial link rate.
> */
> - max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
> - MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
> + ret = max9271_write(dev, 0x02,
> + MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
> + MAX9271_PCLK_AUTODETECT |
> + MAX9271_SERIAL_AUTODETECT);
> + if (ret < 0)
> + return ret;
> +
> usleep_range(5000, 8000);
>
> return 0;

--
Regards,

Laurent Pinchart

2021-03-15 22:04:15

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] media: i2c: max9271: Introduce wake_up() function

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:03PM +0100, Jacopo Mondi wrote:
> The MAX9271 chip manual prescribes a delay of 5 milliseconds
> after the chip exists from low power state.

I don't think we'll ever try to access the chip within 5ms of the
beginning of its existence.

s/exists/exits/

:-)

> Add a new function to the max9271 library driver that wakes up the chip
> with a dummy i2c transaction and implements the correct delay of 5
> milliseconds after the chip exits from low power state.
>
> Use the newly introduced function in the rdacm20 and rdacm21 camera
> drivers. The former was not respecting the required delay while the
> latter was waiting for a too-short timeout.
>
> Do not handle the initial i2c address configuration in the library
> driver function as the camera module drivers control address
> reprogramming.

Isn't the initial address fixed though ? Nonetheless, this can be
addressed separately, so

Reviewed-by: Laurent Pinchart <[email protected]>

> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> drivers/media/i2c/max9271.c | 7 +++++++
> drivers/media/i2c/max9271.h | 9 +++++++++
> drivers/media/i2c/rdacm20.c | 2 +-
> drivers/media/i2c/rdacm21.c | 3 +--
> 4 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
> index 2c7dc7fb9846..f7bfe7266763 100644
> --- a/drivers/media/i2c/max9271.c
> +++ b/drivers/media/i2c/max9271.c
> @@ -80,6 +80,13 @@ static int max9271_pclk_detect(struct max9271_device *dev)
> return -EIO;
> }
>
> +void max9271_wake_up(struct max9271_device *dev)
> +{
> + i2c_smbus_read_byte(dev->client);
> + usleep_range(5000, 8000);
> +}
> +EXPORT_SYMBOL_GPL(max9271_wake_up);
> +
> int max9271_set_serial_link(struct max9271_device *dev, bool enable)
> {
> int ret;
> diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271.h
> index d78fb21441e9..dc5e4e70ba6f 100644
> --- a/drivers/media/i2c/max9271.h
> +++ b/drivers/media/i2c/max9271.h
> @@ -85,6 +85,15 @@ struct max9271_device {
> struct i2c_client *client;
> };
>
> +/**
> + * max9271_wake_up() - Wake up the serializer by issuing an i2c transaction
> + * @dev: The max9271 device
> + *
> + * This function shall be called before any other interaction with the
> + * serializer.
> + */
> +void max9271_wake_up(struct max9271_device *dev);
> +
> /**
> * max9271_set_serial_link() - Enable/disable serial link
> * @dev: The max9271 device
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index b9aaa0f7db42..2265ef7c65d4 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -459,7 +459,7 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
> - i2c_smbus_read_byte(dev->serializer.client);
> + max9271_wake_up(&dev->serializer);
>
> /* Serial link disabled during config as it needs a valid pixel clock. */
> ret = max9271_set_serial_link(&dev->serializer, false);
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 179d107f494c..7bce55adfd7c 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -452,8 +452,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
>
> /* Verify communication with the MAX9271: ping to wakeup. */
> dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
> - i2c_smbus_read_byte(dev->serializer.client);
> - usleep_range(3000, 5000);
> + max9271_wake_up(&dev->serializer);
>
> /* Enable reverse channel and disable the serial link. */
> ret = max9271_set_serial_link(&dev->serializer, false);

--
Regards,

Laurent Pinchart

2021-03-16 05:03:25

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 11/18] media: i2c: rdacm21: Fix OV10640 powerdown

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:05PM +0100, Jacopo Mondi wrote:
> The OV10640 image sensor powerdown signal is controlled by the first
> line of the OV490 GPIO pad #1, but the pad #0 identifier
> OV490_GPIO_OUTPUT_VALUE0 was erroneously used. As a result the image
> sensor powerdown signal was never asserted but was kept high by an
> internal pull-up resistor, causing sporadic failures during the
> image sensor startup phase.
>
> Fix this by using the correct GPIO pad identifier.
>
> While at it also fix the GPIO signal handling sequence, as the reset
> line was released before the powerdown one, and introduce the correct
> delays in between the two operations.
>
> Wait the mandatory 1 millisecond delay after the powerup lane is
> asserted. The reset delay is not characterized in the chip manual if
> not as "255 XVCLK + initialization". Wait for at least 3 milliseconds
> to guarantee the SCCB bus is available.
>
> This commit fixes a sporadic start-up error triggered by a failure to
> read the OV10640 chip ID:
> rdacm21 8-0054: OV10640 ID mismatch: (0x01)
>
> Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Laurent Pinchart <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 7bce55adfd7c..50a9b0d8255d 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -333,13 +333,15 @@ static int ov10640_initialize(struct rdacm21_device *dev)
> {
> u8 val;
>
> - /* Power-up OV10640 by setting RESETB and PWDNB pins high. */
> + /* Power-up OV10640 by setting PWDNB and RESETB pins high. */
> ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
> ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
> ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);
> ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);
> +
> + ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);
> + usleep_range(1500, 3000);
> ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
> - ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_SPWDN0);
> usleep_range(3000, 5000);
>
> /* Read OV10640 ID to test communications. */

--
Regards,

Laurent Pinchart

2021-03-16 05:10:21

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:06PM +0100, Jacopo Mondi wrote:
> It has been observed through repeated testing (250 boots) that in the
> 10% of the cases the RDACM21 initialization sequence errors out due a
> timeout waiting for the OV490 firmware to complete its boot phase.
>
> Albeit being the current timeout relatively large (300-600 milliseconds),

"Even if the current timeout is already relatively large" ?

> doubling it reduces the sporadic error rate down to 1 over an 80 boot
> sequences test run.
>
> The firmware boot delay is unfortunately not characterized in the camera
> module manual.
>
> Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Laurent Pinchart <[email protected]>

> ---
> drivers/media/i2c/rdacm21.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 50a9b0d8255d..07cf077d8efd 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -53,7 +53,7 @@
> #define OV490_PID 0x8080300a
> #define OV490_VER 0x8080300b
> #define OV490_PID_TIMEOUT 20
> -#define OV490_OUTPUT_EN_TIMEOUT 300
> +#define OV490_OUTPUT_EN_TIMEOUT 600
>
> #define OV490_GPIO0 BIT(0)
> #define OV490_SPWDN0 BIT(0)

--
Regards,

Laurent Pinchart

2021-03-16 05:11:05

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 16/18] media: v4l2-subdev: De-deprecate init() subdev op

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:10PM +0100, Jacopo Mondi wrote:
> The init() subdev core operation is deemed to be deprecated for new
> subdevice drivers. However it could prove useful for complex
> architectures to defer operation that require access to the
> communication bus if said bus is not available (or fully configured)
> at the time when the subdevice probe() function is run.
>
> As an example, the GMSL architecture requires the GMSL configuration
> link to be configured on the host side after the remote subdevice
> has completed its probe function. After the configuration on the host
> side has been performed, the subdevice registers can be accessed through
> the communication bus.
>
> In particular:
>
> HOST REMOTE
>
> probe()
> |
> ---------------------> |
> probe() {
> bus config()
> }
> |<--------------------|
> v4l2 async bound {
> bus config()
> call subdev init()
> |-------------------->|
> init() {
> access register on the bus()
> }
> |<-------------------
> }
>
> In the GMSL use case the bus configuration requires the enablement of the
> noise immunity threshold on the remote side which ensures reliability
> of communications in electrically noisy environments. After the subdevice
> has enabled the threshold at the end of its probe() sequence the host
> side shall compensate it with an higher signal amplitude. Once this
> sequence has completed the bus can be accessed with noise protection
> enabled and all the operations that require a considerable number of
> transactions on the bus (such as the image sensor configuration
> sequence) are run in the subdevice init() operation implementation.

I think this can be considered as a reasonable use of .init(). I'd like
to get feedback from Hans and Sakari (CC'ed) though.

> Signed-off-by: Jacopo Mondi <[email protected]>
> ---
> include/media/v4l2-subdev.h | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index d0e9a5bdb08b..3068d9940669 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -148,9 +148,18 @@ struct v4l2_subdev_io_pin_config {
> * each pin being configured. This function could be called at times
> * other than just subdevice initialization.
> *
> - * @init: initialize the sensor registers to some sort of reasonable default
> - * values. Do not use for new drivers and should be removed in existing
> - * drivers.
> + * @init: initialize the subdevice registers to some sort of reasonable default
> + * values. Do not use for new drivers (and should be removed in existing
> + * ones) for regular architectures where the image sensor is connected to
> + * the host receiver. For more complex architectures where the subdevice
> + * initialization should be deferred to the completion of the probe
> + * sequence of some intermediate component, or the communication bus
> + * requires configurations on the host side that depend on the completion
> + * of the probe sequence of the remote subdevices, the usage of this
> + * operation could be considered to allow the devices along the pipeline to
> + * probe and register in the media graph and to defer any operation that
> + * require actual access to the communication bus to their init() function
> + * implementation.
> *
> * @load_fw: load firmware.
> *

--
Regards,

Laurent Pinchart

2021-03-16 05:14:11

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] media: i2c: max9286: Rework comments in .bound()

Hi Jacopo,

Thank you for the patch.

On Mon, Mar 15, 2021 at 02:15:12PM +0100, Jacopo Mondi wrote:
> Re-phrase a comment in .bound() callback to make it clear we register

s/Re-phrase/Rephrase/

> a subdev notifier and remove a redundant comment about disabling i2c
> auto-ack.
>
> No functional changes intended.
>
> Signed-off-by: Jacopo Mondi <[email protected]>

Reviewed-by: Laurent Pinchart <[email protected]>

> ---
> drivers/media/i2c/max9286.c | 16 ++++++----------
> 1 file changed, 6 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> index b6347639901e..16b2cb9b44a2 100644
> --- a/drivers/media/i2c/max9286.c
> +++ b/drivers/media/i2c/max9286.c
> @@ -556,9 +556,9 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
> subdev->name, src_pad, index);
>
> /*
> - * We can only register v4l2_async_notifiers, which do not provide a
> - * means to register a complete callback. bound_sources allows us to
> - * identify when all remote serializers have completed their probe.
> + * As we register a subdev notifiers we won't get a .complete() callback
> + * here, so we have to use bound_sources to identify when all remote
> + * serializers have probed.
> */
> if (priv->bound_sources != priv->source_mask)
> return 0;
> @@ -581,16 +581,12 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
> /*
> * All enabled sources have probed and enabled their reverse control
> * channels:
> + * - The reverse channel amplitude stays high
> * - Verify all configuration links are properly detected
> - * - Disable auto-ack as communication on the control channel are now
> - * stable.
> + * - Disable auto-ack as communications on the control channel are now
> + * stable
> */
> max9286_check_config_link(priv, priv->source_mask);
> -
> - /*
> - * Re-configure I2C with local acknowledge disabled after cameras have
> - * probed.
> - */
> max9286_configure_i2c(priv, false);
>
> return max9286_set_pixelrate(priv);

--
Regards,

Laurent Pinchart

2021-03-16 20:09:59

by jacopo mondi

[permalink] [raw]
Subject: Re: [PATCH v2 02/18] media: i2c: rdacm20: Enable noise immunity

Hi Laurent,

On Mon, Mar 15, 2021 at 11:37:26PM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Mon, Mar 15, 2021 at 02:14:56PM +0100, Jacopo Mondi wrote:
> > Enable the noise immunity threshold at the end of the rdacm20
> > initialization routine.
> >
> > The rdacm20 camera module has been so far tested with a startup
> > delay that allowed the embedded MCU to program the serializer. If
> > the initialization routine is run before the MCU programs the
> > serializer and the image sensor and their addresses gets changed
> > by the rdacm20 driver it is required to manually enable the noise
> > immunity threshold to make the communication on the control channel
> > more reliable.
>
> I'm still worried by the race with the MCU. Any update on dumping the
> MCU configuration to check what it initializes ?
>

Not yet, you're right ...

I mainly focused on testing with rdacm21, what if I strip the rdacm20
changes out from this series ? I will have to keep the init()
operation introduction to maintain compatibility with max9286 changes,
and in case of no regressions, we can keep the 8 seconds delay in the
.dtsi. However it will break upstream support on Eagle for rdacm20 as
we don't have a regulator where to insert the startup delay there, and
a downstream patch that waits for 8 seconds in the deserializer driver
should be used instead...

> > Reviewed-by: Kieran Bingham <[email protected]>
> > Signed-off-by: Jacopo Mondi <[email protected]>
> > ---
> > drivers/media/i2c/rdacm20.c | 8 +++++++-
> > 1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> > index 90eb73f0e6e9..f7fd5ae955d0 100644
> > --- a/drivers/media/i2c/rdacm20.c
> > +++ b/drivers/media/i2c/rdacm20.c
> > @@ -541,7 +541,13 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
> >
> > dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
> >
> > - return 0;
> > + /*
> > + * Set reverse channel high threshold to increase noise immunity.
> > + *
> > + * This should be compensated by increasing the reverse channel
> > + * amplitude on the remote deserializer side.
> > + */
> > + return max9271_set_high_threshold(&dev->serializer, true);
> > }
> >
> > static int rdacm20_probe(struct i2c_client *client)
>
> --
> Regards,
>
> Laurent Pinchart

2021-03-16 21:22:42

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 02/18] media: i2c: rdacm20: Enable noise immunity

Hi Jacopo,

On Tue, Mar 16, 2021 at 01:56:07PM +0100, Jacopo Mondi wrote:
> On Mon, Mar 15, 2021 at 11:37:26PM +0200, Laurent Pinchart wrote:
> > On Mon, Mar 15, 2021 at 02:14:56PM +0100, Jacopo Mondi wrote:
> > > Enable the noise immunity threshold at the end of the rdacm20
> > > initialization routine.
> > >
> > > The rdacm20 camera module has been so far tested with a startup
> > > delay that allowed the embedded MCU to program the serializer. If
> > > the initialization routine is run before the MCU programs the
> > > serializer and the image sensor and their addresses gets changed
> > > by the rdacm20 driver it is required to manually enable the noise
> > > immunity threshold to make the communication on the control channel
> > > more reliable.
> >
> > I'm still worried by the race with the MCU. Any update on dumping the
> > MCU configuration to check what it initializes ?
>
> Not yet, you're right ...
>
> I mainly focused on testing with rdacm21, what if I strip the rdacm20
> changes out from this series ? I will have to keep the init()
> operation introduction to maintain compatibility with max9286 changes,
> and in case of no regressions, we can keep the 8 seconds delay in the
> .dtsi. However it will break upstream support on Eagle for rdacm20 as
> we don't have a regulator where to insert the startup delay there, and
> a downstream patch that waits for 8 seconds in the deserializer driver
> should be used instead...

I don't think the rdacm20 changes need to wait. Even this one could be
merged as-is, as long as we consider it to be a temporary workaround and
don't build anything on top that would make it more difficult to address
the issue properly (a TODO comment in the code could help).

> > > Reviewed-by: Kieran Bingham <[email protected]>
> > > Signed-off-by: Jacopo Mondi <[email protected]>
> > > ---
> > > drivers/media/i2c/rdacm20.c | 8 +++++++-
> > > 1 file changed, 7 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> > > index 90eb73f0e6e9..f7fd5ae955d0 100644
> > > --- a/drivers/media/i2c/rdacm20.c
> > > +++ b/drivers/media/i2c/rdacm20.c
> > > @@ -541,7 +541,13 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
> > >
> > > dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
> > >
> > > - return 0;
> > > + /*
> > > + * Set reverse channel high threshold to increase noise immunity.
> > > + *
> > > + * This should be compensated by increasing the reverse channel
> > > + * amplitude on the remote deserializer side.
> > > + */
> > > + return max9271_set_high_threshold(&dev->serializer, true);
> > > }
> > >
> > > static int rdacm20_probe(struct i2c_client *client)

--
Regards,

Laurent Pinchart

2021-03-17 10:06:43

by jacopo mondi

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

Hi Kieran, Laurent,

On Mon, Mar 15, 2021 at 05:22:37PM +0000, Kieran Bingham wrote:
> On 15/03/2021 13:15, Jacopo Mondi wrote:
> > It has been observed through repeated testing (250 boots) that in the
> > 10% of the cases the RDACM21 initialization sequence errors out due a
> > timeout waiting for the OV490 firmware to complete its boot phase.
> >
> > Albeit being the current timeout relatively large (300-600 milliseconds),
> > doubling it reduces the sporadic error rate down to 1 over an 80 boot
> > sequences test run.
> >
> > The firmware boot delay is unfortunately not characterized in the camera
> > module manual.
> >
>
> I wonder if we could characterize this alone by pulling this down until
> we see failures increase, with all the other fixes in place...
>
> I don't think that's required, but it might be something to check later
> if we don't get rid of that 1/80 failure.

This is actually driving me crazy :/

I had another test run with a surprising 10% failures.
All the failures were due to the ov490 firmware boot I'm trying to
mitigate here.

I went up to give it -6 seconds- and I still get failures in the same
percentage. Another run of 20 boots gave 30% failures with the delay I
have here in this patch. Just to make sure I was not going crazy I
reduced the delay to 1msec and I get an 80% failure rate.

Still, I've seen the 1 on 80 failures (I swear! I have logs! :)

I've checked what the BSP does, and if after some 300 attempts the
ov490 doesn't boot, they simply go an reset it.
https://github.com/renesas-rcar/linux-bsp/commit/0cf6e36f5bf49e1c2aab87139ec5b588623c56f8#diff-d770cad7d6f04923d9e89dfe7da369bb3006776d6e4fb8ef79353d5fab3cd25aR827
(sorry, I don't seem to be able to point you to the ov490.c#827 with
an URL)

I assume we don't want anything like this in an upstream driver, but
I'm really running out of any plausible explanation :(

>
>
>
> > Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> > Signed-off-by: Jacopo Mondi <[email protected]>
>
> Reviewed-by: Kieran Bingham <[email protected]>
>
> > ---
> > drivers/media/i2c/rdacm21.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > index 50a9b0d8255d..07cf077d8efd 100644
> > --- a/drivers/media/i2c/rdacm21.c
> > +++ b/drivers/media/i2c/rdacm21.c
> > @@ -53,7 +53,7 @@
> > #define OV490_PID 0x8080300a
> > #define OV490_VER 0x8080300b
> > #define OV490_PID_TIMEOUT 20
> > -#define OV490_OUTPUT_EN_TIMEOUT 300
> > +#define OV490_OUTPUT_EN_TIMEOUT 600
> >
> > #define OV490_GPIO0 BIT(0)
> > #define OV490_SPWDN0 BIT(0)
> >
>

2021-03-19 00:31:40

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

Hi Jacopo,

On Wed, Mar 17, 2021 at 11:04:45AM +0100, Jacopo Mondi wrote:
> On Mon, Mar 15, 2021 at 05:22:37PM +0000, Kieran Bingham wrote:
> > On 15/03/2021 13:15, Jacopo Mondi wrote:
> > > It has been observed through repeated testing (250 boots) that in the
> > > 10% of the cases the RDACM21 initialization sequence errors out due a
> > > timeout waiting for the OV490 firmware to complete its boot phase.
> > >
> > > Albeit being the current timeout relatively large (300-600 milliseconds),
> > > doubling it reduces the sporadic error rate down to 1 over an 80 boot
> > > sequences test run.
> > >
> > > The firmware boot delay is unfortunately not characterized in the camera
> > > module manual.
> >
> > I wonder if we could characterize this alone by pulling this down until
> > we see failures increase, with all the other fixes in place...
> >
> > I don't think that's required, but it might be something to check later
> > if we don't get rid of that 1/80 failure.
>
> This is actually driving me crazy :/
>
> I had another test run with a surprising 10% failures.
> All the failures were due to the ov490 firmware boot I'm trying to
> mitigate here.
>
> I went up to give it -6 seconds- and I still get failures in the same
> percentage. Another run of 20 boots gave 30% failures with the delay I
> have here in this patch. Just to make sure I was not going crazy I
> reduced the delay to 1msec and I get an 80% failure rate.
>
> Still, I've seen the 1 on 80 failures (I swear! I have logs! :)
>
> I've checked what the BSP does, and if after some 300 attempts the
> ov490 doesn't boot, they simply go an reset it.
> https://github.com/renesas-rcar/linux-bsp/commit/0cf6e36f5bf49e1c2aab87139ec5b588623c56f8#diff-d770cad7d6f04923d9e89dfe7da369bb3006776d6e4fb8ef79353d5fab3cd25aR827
> (sorry, I don't seem to be able to point you to the ov490.c#827 with
> an URL)

It resets both the sensor and the OV490. It could be interested to try
the latter selectively to see what happens.

I also suspect that the OV490 has debugging features (possibly including
a RAM log buffer that we could read over I2C), but we're probably
getting out of scope here.

> I assume we don't want anything like this in an upstream driver, but
> I'm really running out of any plausible explanation :(

As discussed, let's try the reset workaround, to see if it helps.

I wonder if opening the camera and probing signals would be a useful
option :-)

> > > Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> > > Signed-off-by: Jacopo Mondi <[email protected]>
> >
> > Reviewed-by: Kieran Bingham <[email protected]>
> >
> > > ---
> > > drivers/media/i2c/rdacm21.c | 2 +-
> > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > > index 50a9b0d8255d..07cf077d8efd 100644
> > > --- a/drivers/media/i2c/rdacm21.c
> > > +++ b/drivers/media/i2c/rdacm21.c
> > > @@ -53,7 +53,7 @@
> > > #define OV490_PID 0x8080300a
> > > #define OV490_VER 0x8080300b
> > > #define OV490_PID_TIMEOUT 20
> > > -#define OV490_OUTPUT_EN_TIMEOUT 300
> > > +#define OV490_OUTPUT_EN_TIMEOUT 600
> > >
> > > #define OV490_GPIO0 BIT(0)
> > > #define OV490_SPWDN0 BIT(0)

--
Regards,

Laurent Pinchart

2021-03-19 14:55:26

by jacopo mondi

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] media: i2c: rdacm21: Give more time to OV490 to boot

Hi Laurent,

On Fri, Mar 19, 2021 at 02:29:30AM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Wed, Mar 17, 2021 at 11:04:45AM +0100, Jacopo Mondi wrote:
> > On Mon, Mar 15, 2021 at 05:22:37PM +0000, Kieran Bingham wrote:
> > > On 15/03/2021 13:15, Jacopo Mondi wrote:
> > > > It has been observed through repeated testing (250 boots) that in the
> > > > 10% of the cases the RDACM21 initialization sequence errors out due a
> > > > timeout waiting for the OV490 firmware to complete its boot phase.
> > > >
> > > > Albeit being the current timeout relatively large (300-600 milliseconds),
> > > > doubling it reduces the sporadic error rate down to 1 over an 80 boot
> > > > sequences test run.
> > > >
> > > > The firmware boot delay is unfortunately not characterized in the camera
> > > > module manual.
> > >
> > > I wonder if we could characterize this alone by pulling this down until
> > > we see failures increase, with all the other fixes in place...
> > >
> > > I don't think that's required, but it might be something to check later
> > > if we don't get rid of that 1/80 failure.
> >
> > This is actually driving me crazy :/
> >
> > I had another test run with a surprising 10% failures.
> > All the failures were due to the ov490 firmware boot I'm trying to
> > mitigate here.
> >
> > I went up to give it -6 seconds- and I still get failures in the same
> > percentage. Another run of 20 boots gave 30% failures with the delay I
> > have here in this patch. Just to make sure I was not going crazy I
> > reduced the delay to 1msec and I get an 80% failure rate.
> >
> > Still, I've seen the 1 on 80 failures (I swear! I have logs! :)
> >
> > I've checked what the BSP does, and if after some 300 attempts the
> > ov490 doesn't boot, they simply go an reset it.
> > https://github.com/renesas-rcar/linux-bsp/commit/0cf6e36f5bf49e1c2aab87139ec5b588623c56f8#diff-d770cad7d6f04923d9e89dfe7da369bb3006776d6e4fb8ef79353d5fab3cd25aR827
> > (sorry, I don't seem to be able to point you to the ov490.c#827 with
> > an URL)
>
> It resets both the sensor and the OV490. It could be interested to try
> the latter selectively to see what happens.
>

They do not make any difference :)

But..

> I also suspect that the OV490 has debugging features (possibly including
> a RAM log buffer that we could read over I2C), but we're probably
> getting out of scope here.
>
> > I assume we don't want anything like this in an upstream driver, but
> > I'm really running out of any plausible explanation :(
>
> As discussed, let's try the reset workaround, to see if it helps.
>
> I wonder if opening the camera and probing signals would be a useful
> option :-)

... I really think I've got something working (for real this time :)

Basically, as patch "media: i2c: rdacm21: Fix OV10640 powerdown" of
this series describes, the OV10640 power-up was broken before you
spotted the usage of the wrong gpio pad and it was working because of
an internal pull-up on the SPWDN line, which was erroneously left
floating. Once that was fixed, the OV10640 was always identified
correctly, leaving us with this puzzling "ov490 boot timeout error"
that manifested with more or less the same frequency of the ov10640
identification issue.

In the current implementation we power up the OV490 and wait for its
firmware to boot -before- powering up the ov10640 sensor. Most
probably (or looking at the results I get noaw, most certainly) the
OV490 firmware checks for the sensor to be available and probably
tries to program it. So we're back to the issue we originally had when
the sensor was powered because of the pull up resistor, failing to
boot in case the sensor didn't startup correctly which happened in the
20% of the cases.

If I do power up the OV10640 -before- the OV490 all the firmware boot
errors are now gone. I need to tune a bit the timeouts as after the
OV490 boot the OV10640 requires some time before being accessible.
Once I nail down the right timeouts I'll send v3. So far I got 0
errors on 50 boot attempts, finally \o/

Thanks for keep pushing, I would have swear this was an issue with the
HW design and was very close to give up like a month ago!

V3 out soon!

Thanks
j


>
> > > > Fixes: a59f853b3b4b ("media: i2c: Add driver for RDACM21 camera module")
> > > > Signed-off-by: Jacopo Mondi <[email protected]>
> > >
> > > Reviewed-by: Kieran Bingham <[email protected]>
> > >
> > > > ---
> > > > drivers/media/i2c/rdacm21.c | 2 +-
> > > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > > > index 50a9b0d8255d..07cf077d8efd 100644
> > > > --- a/drivers/media/i2c/rdacm21.c
> > > > +++ b/drivers/media/i2c/rdacm21.c
> > > > @@ -53,7 +53,7 @@
> > > > #define OV490_PID 0x8080300a
> > > > #define OV490_VER 0x8080300b
> > > > #define OV490_PID_TIMEOUT 20
> > > > -#define OV490_OUTPUT_EN_TIMEOUT 300
> > > > +#define OV490_OUTPUT_EN_TIMEOUT 600
> > > >
> > > > #define OV490_GPIO0 BIT(0)
> > > > #define OV490_SPWDN0 BIT(0)
>
> --
> Regards,
>
> Laurent Pinchart