diff mbox series

[RFC] media: i2c: ds90ub960: Enable second i2c interface

Message ID 20250305121705.2143540-1-y-abhilashchandra@ti.com
State New
Headers show
Series [RFC] media: i2c: ds90ub960: Enable second i2c interface | expand

Commit Message

Yemike Abhilash Chandra March 5, 2025, 12:17 p.m. UTC
The DS90UB960-Q1 includes a second I2C interface for independent control
of the deserializer and remote devices. However, the current driver does
not utilize it, thus restricting users to either CSI TX0 or CSI TX1 on
the primary I2C interface. Enable the second I2C interface, allowing
flexible routing where CSI TX0 can be used on the primary and CSI TX1 on
the secondary, or vice versa by enabling appropriate ports in DT. To
achieve the same only modify the bits relevant to the enabled RX and TX
ports of that interface and during probe and enable_streams call, few
registers were being reset to HW reset state, these operations are not
necessary for functionality and resets the state when secondary I2C
interface is probed, thus drop them.

DS90UB960 data sheet: https://www.ti.com/lit/ds/symlink/ds90ub960-q1.pdf
Signed-off-by: Yemike Abhilash Chandra <y-abhilashchandra@ti.com>
---
 drivers/media/i2c/ds90ub960.c | 64 +++++++++++++++++++++++++++--------
 1 file changed, 49 insertions(+), 15 deletions(-)

Comments

Tomi Valkeinen March 18, 2025, 2:46 p.m. UTC | #1
Hi,

On 05/03/2025 14:17, Yemike Abhilash Chandra wrote:
> The DS90UB960-Q1 includes a second I2C interface for independent control
> of the deserializer and remote devices. However, the current driver does
> not utilize it, thus restricting users to either CSI TX0 or CSI TX1 on
> the primary I2C interface. Enable the second I2C interface, allowing
> flexible routing where CSI TX0 can be used on the primary and CSI TX1 on
> the secondary, or vice versa by enabling appropriate ports in DT. To
> achieve the same only modify the bits relevant to the enabled RX and TX
> ports of that interface and during probe and enable_streams call, few
> registers were being reset to HW reset state, these operations are not
> necessary for functionality and resets the state when secondary I2C
> interface is probed, thus drop them.

I'm a bit confused about the description. My recollection is that both 
CSI TX0 and TX1 can be programmed just fine from the first I2C 
interface. Is that not so?

Also, even if the driver supports both CSI TXes, at the moment v4l2 
framework doesn't work with it, at least in many cases. E.g. if you 
connect one TX to a CSIRX, the other TX to another CSIRX, and those 
CSIRXes are independent, have their own media graphs, it's not going to 
work at all.

So I guess my question is, what's the target here, how did you test 
this, etc?

  Tomi
Yemike Abhilash Chandra March 20, 2025, 10:36 a.m. UTC | #2
Hi Tomi

On 18/03/25 20:16, Tomi Valkeinen wrote:
> Hi,
> 
> On 05/03/2025 14:17, Yemike Abhilash Chandra wrote:
>> The DS90UB960-Q1 includes a second I2C interface for independent control
>> of the deserializer and remote devices. However, the current driver does
>> not utilize it, thus restricting users to either CSI TX0 or CSI TX1 on
>> the primary I2C interface. Enable the second I2C interface, allowing
>> flexible routing where CSI TX0 can be used on the primary and CSI TX1 on
>> the secondary, or vice versa by enabling appropriate ports in DT. To
>> achieve the same only modify the bits relevant to the enabled RX and TX
>> ports of that interface and during probe and enable_streams call, few
>> registers were being reset to HW reset state, these operations are not
>> necessary for functionality and resets the state when secondary I2C
>> interface is probed, thus drop them.
> 
> I'm a bit confused about the description. My recollection is that both 
> CSI TX0 and TX1 can be programmed just fine from the first I2C 
> interface. Is that not so?
> 

I apologize for not giving the entire context while sending the RFC.
The purpose of this patch is not only to enable secondary I2C interface
but also to overcome the v4l2 framework limitation by doing that.

> Also, even if the driver supports both CSI TXes, at the moment v4l2 
> framework doesn't work with it, at least in many cases. E.g. if you 
> connect one TX to a CSIRX, the other TX to another CSIRX, and those 
> CSIRXes are independent, have their own media graphs, it's not going to 
> work at all.
> 

Lets say that the overlay applied is as shown in [1]

[1]: 
https://gist.github.com/Yemike-Abhilash-Chandra/5c53a5f3a77954b28c5bd4c27cd336a5

On the physical connection, if we have one V3Link Fusion, where:
CSITX0 is connected to CSIRX0 and CSITX1 is connected to CSIRX1
and the following overlays are applied:

ti/k3-am68-sk-v3link-fusion-dual-csitx.dtbo \ (same overlay as in [1])
ti/k3-v3link-imx219-0-2.dtbo ti/k3-v3link-imx219-0-3.dtbo \
ti/k3-v3link-imx219-1-0.dtbo ti/k3-v3link-imx219-1-1.dtbo

and now each media graph will contain two IMX219 sensors and a
UB960 , with the same UB960 being emulated in both media graphs.
This configuration assigns CSITX0 to the first media
graph and CSITX1 to the second media graph and the
sensors in the first media graph are programmed using the
primary I2C bus, while the sensors in the second media graph
are programmed using the secondary I2C bus.

and this will not break the existing usage, as it will
dynamically check the overlay applied and use primary and
secondary I2C interface accordingly ( primary for Port4
CSITX0 and secondary for port5 CSITX1 )

> So I guess my question is, what's the target here, how did you test 
> this, etc?
> 

for the details I discussed above, I have attached detailed logs
including applying the v3link overlay [1] and sensor overlays
and setting up routes. I ran a free running capture after that.

[2]: 
https://gist.github.com/Yemike-Abhilash-Chandra/1afc731e098fd23cad32dd5438852219

>   Tomi
>
Tomi Valkeinen April 2, 2025, 11:27 a.m. UTC | #3
Hi,

On 20/03/2025 12:36, Yemike Abhilash Chandra wrote:
> Hi Tomi
> 
> On 18/03/25 20:16, Tomi Valkeinen wrote:
>> Hi,
>>
>> On 05/03/2025 14:17, Yemike Abhilash Chandra wrote:
>>> The DS90UB960-Q1 includes a second I2C interface for independent control
>>> of the deserializer and remote devices. However, the current driver does
>>> not utilize it, thus restricting users to either CSI TX0 or CSI TX1 on
>>> the primary I2C interface. Enable the second I2C interface, allowing
>>> flexible routing where CSI TX0 can be used on the primary and CSI TX1 on
>>> the secondary, or vice versa by enabling appropriate ports in DT. To
>>> achieve the same only modify the bits relevant to the enabled RX and TX
>>> ports of that interface and during probe and enable_streams call, few
>>> registers were being reset to HW reset state, these operations are not
>>> necessary for functionality and resets the state when secondary I2C
>>> interface is probed, thus drop them.
>>
>> I'm a bit confused about the description. My recollection is that both 
>> CSI TX0 and TX1 can be programmed just fine from the first I2C 
>> interface. Is that not so?
>>
> 
> I apologize for not giving the entire context while sending the RFC.
> The purpose of this patch is not only to enable secondary I2C interface
> but also to overcome the v4l2 framework limitation by doing that.
> 
>> Also, even if the driver supports both CSI TXes, at the moment v4l2 
>> framework doesn't work with it, at least in many cases. E.g. if you 
>> connect one TX to a CSIRX, the other TX to another CSIRX, and those 
>> CSIRXes are independent, have their own media graphs, it's not going 
>> to work at all.
>>
> 
> Lets say that the overlay applied is as shown in [1]
> 
> [1]: https://gist.github.com/Yemike-Abhilash- 
> Chandra/5c53a5f3a77954b28c5bd4c27cd336a5

Ok. No, we can't merge anything like that. You're creating two linux 
devices for a single HW device, without any specific support for such. 
If it works for you, it's just by luck.

  Tomi
diff mbox series

Patch

diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c
index 5dde8452739b..4c0052e05071 100644
--- a/drivers/media/i2c/ds90ub960.c
+++ b/drivers/media/i2c/ds90ub960.c
@@ -73,6 +73,9 @@ 
 
 #define UB960_NUM_BC_GPIOS		4
 
+#define UB960_ALL_RX_PORTS_MASK	GENMASK(3, 0)
+#define UB960_CSI_TX0			BIT(4)
+
 /*
  * Register map
  *
@@ -111,6 +114,7 @@ 
 #define UB960_SR_SCL_HIGH_TIME			0x0a
 #define UB960_SR_SCL_LOW_TIME			0x0b
 #define UB960_SR_RX_PORT_CTL			0x0c
+#define UB960_SR_RX_PORT_CTL_BCC_MAP		GENMASK(7, 4)
 #define UB960_SR_IO_CTL				0x0d
 #define UB960_SR_GPIO_PIN_STS			0x0e
 #define UB960_SR_GPIO_INPUT_CTL			0x0f
@@ -524,6 +528,8 @@  struct ub960_data {
 
 	u32 tx_data_rate;		/* Nominal data rate (Gb/s) */
 	s64 tx_link_freq[1];
+	u8 rx_mask;
+	u8 tx_mask;
 
 	struct i2c_atr *atr;
 
@@ -2168,6 +2174,17 @@  static void ub960_init_rx_port_ub9702(struct ub960_data *priv,
 static int ub960_init_rx_ports(struct ub960_data *priv)
 {
 	unsigned int nport;
+	u8 enabled_rxports_mask;
+	u8 enabled_rxports;
+	int ret;
+
+	/* Configure i2c interface for RX ports */
+	enabled_rxports_mask = FIELD_PREP(UB960_SR_RX_PORT_CTL_BCC_MAP, priv->rx_mask);
+	enabled_rxports = (priv->tx_mask & UB960_CSI_TX0)  ? 0x00 : enabled_rxports_mask;
+
+	ret = ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, enabled_rxports_mask, enabled_rxports);
+	if (ret)
+		return ret;
 
 	for (nport = 0; nport < priv->hw_data->num_rxports; nport++) {
 		struct ub960_rxport *rxport = priv->rxports[nport];
@@ -2509,14 +2526,6 @@  static int ub960_configure_ports_for_streaming(struct ub960_data *priv,
 		}
 	}
 
-	/* Configure RX ports */
-
-	/*
-	 * Keep all port forwardings disabled by default. Forwarding will be
-	 * enabled in ub960_enable_rx_port.
-	 */
-	fwd_ctl = GENMASK(7, 4);
-
 	for (unsigned int nport = 0; nport < priv->hw_data->num_rxports;
 	     nport++) {
 		struct ub960_rxport *rxport = priv->rxports[nport];
@@ -2570,9 +2579,9 @@  static int ub960_configure_ports_for_streaming(struct ub960_data *priv,
 			fwd_ctl &= ~BIT(nport); /* forward to TX0 */
 	}
 
-	ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl);
+	ret = ub960_update_bits(priv, UB960_SR_FWD_CTL1, priv->rx_mask, fwd_ctl);
 
-	return 0;
+	return ret;
 }
 
 static void ub960_update_streaming_status(struct ub960_data *priv)
@@ -3574,6 +3583,32 @@  static int ub960_parse_dt_txports(struct ub960_data *priv)
 	return 0;
 }
 
+static int ub960_parse_active_ports(struct ub960_data *priv)
+{
+	struct device *dev = &priv->client->dev;
+	int nport;
+
+	priv->rx_mask = 0;
+	priv->tx_mask = 0;
+
+	for (nport = 0; nport < priv->hw_data->num_rxports + priv->hw_data->num_txports; nport++) {
+		struct fwnode_handle *ep_fwnode;
+
+		ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), nport, 0, 0);
+		if (!ep_fwnode)
+			continue;
+
+		if (nport < priv->hw_data->num_rxports)
+			priv->rx_mask |= BIT(nport);
+		else
+			priv->tx_mask |= BIT(nport);
+
+		fwnode_handle_put(ep_fwnode);
+	}
+
+	return 0;
+}
+
 static int ub960_parse_dt(struct ub960_data *priv)
 {
 	int ret;
@@ -3900,11 +3935,6 @@  static int ub960_enable_core_hw(struct ub960_data *priv)
 		!!(dev_sts & BIT(4)), refclk_freq,
 		clk_get_rate(priv->refclk) / HZ_PER_MHZ);
 
-	/* Disable all RX ports by default */
-	ret = ub960_write(priv, UB960_SR_RX_PORT_CTL, 0);
-	if (ret)
-		goto err_pd_gpio;
-
 	/* release GPIO lock */
 	if (priv->hw_data->is_ub9702) {
 		ret = ub960_update_bits(priv, UB960_SR_RESET,
@@ -3969,6 +3999,10 @@  static int ub960_probe(struct i2c_client *client)
 	if (ret)
 		goto err_mutex_destroy;
 
+	ret = ub960_parse_active_ports(priv);
+	if (ret)
+		goto err_disable_core_hw;
+
 	ret = ub960_parse_dt(priv);
 	if (ret)
 		goto err_disable_core_hw;