On Thu Nov 21 14:41:08 2024 +0100, Niklas Söderlund wrote:
> Later versions of the V4H datasheet adds documentation for the line
> order register needed to support all possible configurations. Extend the
> driver to take the line order for each data line into account when
> configuring the device.
> 
> Unfortunately not all registers initially thought to be involved in line
> order configuration where directly related. One magic value is still in
> the driver and left as-is, but it is not related to line order as that
> procedure have now been documented.
> 
> Signed-off-by: Niklas Söderlund <niklas.soderlund+rene...@ragnatech.se>
> Signed-off-by: Sakari Ailus <sakari.ai...@linux.intel.com>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org>

Patch committed.

Thanks,
Mauro Carvalho Chehab

 drivers/media/platform/renesas/rcar-csi2.c | 74 +++++++++++++++++++++++++++---
 1 file changed, 67 insertions(+), 7 deletions(-)

---

diff --git a/drivers/media/platform/renesas/rcar-csi2.c 
b/drivers/media/platform/renesas/rcar-csi2.c
index 27ffdd28cbf7..8a0b6a68e194 100644
--- a/drivers/media/platform/renesas/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-csi2.c
@@ -183,17 +183,19 @@ struct rcar_csi2;
 #define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n)    (0x23840 + ((n) * 2)) 
/* n = 0 - 11 */
 #define V4H_CORE_DIG_RW_COMMON_REG(n)                  (0x23880 + ((n) * 2)) 
/* n = 0 - 15 */
 #define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n)  (0x239e0 + ((n) * 2)) 
/* n = 0 - 3 */
-#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG              0x2a400
 #define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG            0x2a60c
 
 /* V4H C-PHY */
 #define V4H_CORE_DIG_RW_TRIO0_REG(n)                   (0x22100 + ((n) * 2)) 
/* n = 0 - 3 */
 #define V4H_CORE_DIG_RW_TRIO1_REG(n)                   (0x22500 + ((n) * 2)) 
/* n = 0 - 3 */
 #define V4H_CORE_DIG_RW_TRIO2_REG(n)                   (0x22900 + ((n) * 2)) 
/* n = 0 - 3 */
+#define V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG              0x2a000
 #define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG               0x2a080
 #define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n)           (0x2a100 + ((n) * 2)) 
/* n = 0 - 6 */
+#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG              0x2a400
 #define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG               0x2a480
 #define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n)           (0x2a500 + ((n) * 2)) 
/* n = 0 - 6 */
+#define V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG              0x2a800
 #define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG               0x2a880
 #define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n)           (0x2a900 + ((n) * 2)) 
/* n = 0 - 6 */
 
@@ -672,6 +674,21 @@ static const struct rcar_csi2_format 
*rcsi2_code_to_fmt(unsigned int code)
        return NULL;
 }
 
+struct rcsi2_cphy_line_order {
+       enum v4l2_mbus_csi2_cphy_line_orders_type order;
+       u16 cfg;
+       u16 ctrl29;
+};
+
+static const struct rcsi2_cphy_line_order rcsi2_cphy_line_orders[] = {
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_ABC, .cfg = 0x0, .ctrl29 = 
0x0 },
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_ACB, .cfg = 0xa, .ctrl29 = 
0x1 },
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_BAC, .cfg = 0xc, .ctrl29 = 
0x1 },
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_BCA, .cfg = 0x5, .ctrl29 = 
0x0 },
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_CAB, .cfg = 0x3, .ctrl29 = 
0x0 },
+       { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_CBA, .cfg = 0x9, .ctrl29 = 
0x1 }
+};
+
 enum rcar_csi2_pads {
        RCAR_CSI2_SINK,
        RCAR_CSI2_SOURCE_VC0,
@@ -722,6 +739,7 @@ struct rcar_csi2 {
        bool cphy;
        unsigned short lanes;
        unsigned char lane_swap[4];
+       enum v4l2_mbus_csi2_cphy_line_orders_type line_orders[3];
 };
 
 static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
@@ -754,11 +772,24 @@ static void rcsi2_write(struct rcar_csi2 *priv, unsigned 
int reg, u32 data)
        iowrite32(data, priv->base + reg);
 }
 
+static u16 rcsi2_read16(struct rcar_csi2 *priv, unsigned int reg)
+{
+       return ioread16(priv->base + reg);
+}
+
 static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data)
 {
        iowrite16(data, priv->base + reg);
 }
 
+static void rcsi2_modify16(struct rcar_csi2 *priv, unsigned int reg, u16 data, 
u16 mask)
+{
+       u16 val;
+
+       val = rcsi2_read16(priv, reg) & ~mask;
+       rcsi2_write16(priv, reg, val | data);
+}
+
 static int rcsi2_phtw_write(struct rcar_csi2 *priv, u8 data, u8 code)
 {
        unsigned int timeout;
@@ -1112,6 +1143,26 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 
*priv,
        return 0;
 }
 
+static void rsci2_set_line_order(struct rcar_csi2 *priv,
+                                enum v4l2_mbus_csi2_cphy_line_orders_type 
order,
+                                unsigned int cfgreg, unsigned int ctrlreg)
+{
+       const struct rcsi2_cphy_line_order *info = NULL;
+
+       for (unsigned int i = 0; i < ARRAY_SIZE(rcsi2_cphy_line_orders); i++) {
+               if (rcsi2_cphy_line_orders[i].order == order) {
+                       info = &rcsi2_cphy_line_orders[i];
+                       break;
+               }
+       }
+
+       if (!info)
+               return;
+
+       rcsi2_modify16(priv, cfgreg, info->cfg, 0x000f);
+       rcsi2_modify16(priv, ctrlreg, info->ctrl29, 0x0100);
+}
+
 static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match)
 {
        unsigned int timeout;
@@ -1189,12 +1240,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 
*priv, int msps)
        rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1);
        rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1);
 
-       /*
-        * Configure pin-swap.
-        * TODO: This registers is not documented yet, the values should depend
-        * on the 'clock-lanes' and 'data-lanes' devicetree properties.
-        */
-       rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5);
+       /* Configure data line order. */
+       rsci2_set_line_order(priv, priv->line_orders[0],
+                            V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG,
+                            V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9));
+       rsci2_set_line_order(priv, priv->line_orders[1],
+                            V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG,
+                            V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(9));
+       rsci2_set_line_order(priv, priv->line_orders[2],
+                            V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG,
+                            V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(9));
+
+       /* TODO: This registers is not documented. */
        rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000);
 
        /* Leave Shutdown mode */
@@ -1732,6 +1789,9 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
                }
        }
 
+       for (i = 0; i < ARRAY_SIZE(priv->line_orders); i++)
+               priv->line_orders[i] = vep->bus.mipi_csi2.line_orders[i];
+
        return 0;
 }
 

Reply via email to