media: rcar-csi2: Add r8a779a0 support
authorNiklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Sat, 12 Jun 2021 08:46:29 +0000 (10:46 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 30 Sep 2021 08:07:33 +0000 (10:07 +0200)
Add support for the R-Car V3U (r8a779a0) to the driver. The V3U have the
CSI-2 modules connected to ISPs instead of directly to the R-Car VIN DMA
engines.

The ISP performs channel selection based on CSI-2 VC/DT pairs and routes
the video data. This requires the R-Car CSI-2 media entity to modeled
differently then on other SoCs as it on the V3U only have a single
source pad connected to the ISP.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/rcar-vin/rcar-csi2.c

index e28eff0..f5ec7cc 100644 (file)
@@ -126,6 +126,12 @@ struct rcar_csi2;
 #define PHTW_CWEN                      BIT(8)
 #define PHTW_TESTDIN_CODE(n)           ((n & 0xff))
 
+#define PHYFRX_REG                     0x64
+#define PHYFRX_FORCERX_MODE_3          BIT(3)
+#define PHYFRX_FORCERX_MODE_2          BIT(2)
+#define PHYFRX_FORCERX_MODE_1          BIT(1)
+#define PHYFRX_FORCERX_MODE_0          BIT(0)
+
 struct phtw_value {
        u16 data;
        u16 code;
@@ -136,6 +142,31 @@ struct rcsi2_mbps_reg {
        u16 reg;
 };
 
+static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
+       { .mbps = 1500, .reg = 0xcc },
+       { .mbps = 1550, .reg = 0x1d },
+       { .mbps = 1600, .reg = 0x27 },
+       { .mbps = 1650, .reg = 0x30 },
+       { .mbps = 1700, .reg = 0x39 },
+       { .mbps = 1750, .reg = 0x42 },
+       { .mbps = 1800, .reg = 0x4b },
+       { .mbps = 1850, .reg = 0x55 },
+       { .mbps = 1900, .reg = 0x5e },
+       { .mbps = 1950, .reg = 0x67 },
+       { .mbps = 2000, .reg = 0x71 },
+       { .mbps = 2050, .reg = 0x79 },
+       { .mbps = 2100, .reg = 0x83 },
+       { .mbps = 2150, .reg = 0x8c },
+       { .mbps = 2200, .reg = 0x95 },
+       { .mbps = 2250, .reg = 0x9e },
+       { .mbps = 2300, .reg = 0xa7 },
+       { .mbps = 2350, .reg = 0xb0 },
+       { .mbps = 2400, .reg = 0xba },
+       { .mbps = 2450, .reg = 0xc3 },
+       { .mbps = 2500, .reg = 0xcc },
+       { /* sentinel */ },
+};
+
 static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
        { .mbps =   80, .reg = 0x86 },
        { .mbps =   90, .reg = 0x86 },
@@ -200,6 +231,72 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
 #define PHYPLL_REG                     0x68
 #define PHYPLL_HSFREQRANGE(n)          ((n) << 16)
 
+static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
+       { .mbps =   80, .reg = 0x00 },
+       { .mbps =   90, .reg = 0x10 },
+       { .mbps =  100, .reg = 0x20 },
+       { .mbps =  110, .reg = 0x30 },
+       { .mbps =  120, .reg = 0x01 },
+       { .mbps =  130, .reg = 0x11 },
+       { .mbps =  140, .reg = 0x21 },
+       { .mbps =  150, .reg = 0x31 },
+       { .mbps =  160, .reg = 0x02 },
+       { .mbps =  170, .reg = 0x12 },
+       { .mbps =  180, .reg = 0x22 },
+       { .mbps =  190, .reg = 0x32 },
+       { .mbps =  205, .reg = 0x03 },
+       { .mbps =  220, .reg = 0x13 },
+       { .mbps =  235, .reg = 0x23 },
+       { .mbps =  250, .reg = 0x33 },
+       { .mbps =  275, .reg = 0x04 },
+       { .mbps =  300, .reg = 0x14 },
+       { .mbps =  325, .reg = 0x25 },
+       { .mbps =  350, .reg = 0x35 },
+       { .mbps =  400, .reg = 0x05 },
+       { .mbps =  450, .reg = 0x16 },
+       { .mbps =  500, .reg = 0x26 },
+       { .mbps =  550, .reg = 0x37 },
+       { .mbps =  600, .reg = 0x07 },
+       { .mbps =  650, .reg = 0x18 },
+       { .mbps =  700, .reg = 0x28 },
+       { .mbps =  750, .reg = 0x39 },
+       { .mbps =  800, .reg = 0x09 },
+       { .mbps =  850, .reg = 0x19 },
+       { .mbps =  900, .reg = 0x29 },
+       { .mbps =  950, .reg = 0x3a },
+       { .mbps = 1000, .reg = 0x0a },
+       { .mbps = 1050, .reg = 0x1a },
+       { .mbps = 1100, .reg = 0x2a },
+       { .mbps = 1150, .reg = 0x3b },
+       { .mbps = 1200, .reg = 0x0b },
+       { .mbps = 1250, .reg = 0x1b },
+       { .mbps = 1300, .reg = 0x2b },
+       { .mbps = 1350, .reg = 0x3c },
+       { .mbps = 1400, .reg = 0x0c },
+       { .mbps = 1450, .reg = 0x1c },
+       { .mbps = 1500, .reg = 0x2c },
+       { .mbps = 1550, .reg = 0x3d },
+       { .mbps = 1600, .reg = 0x0d },
+       { .mbps = 1650, .reg = 0x1d },
+       { .mbps = 1700, .reg = 0x2e },
+       { .mbps = 1750, .reg = 0x3e },
+       { .mbps = 1800, .reg = 0x0e },
+       { .mbps = 1850, .reg = 0x1e },
+       { .mbps = 1900, .reg = 0x2f },
+       { .mbps = 1950, .reg = 0x3f },
+       { .mbps = 2000, .reg = 0x0f },
+       { .mbps = 2050, .reg = 0x40 },
+       { .mbps = 2100, .reg = 0x41 },
+       { .mbps = 2150, .reg = 0x42 },
+       { .mbps = 2200, .reg = 0x43 },
+       { .mbps = 2300, .reg = 0x45 },
+       { .mbps = 2350, .reg = 0x46 },
+       { .mbps = 2400, .reg = 0x47 },
+       { .mbps = 2450, .reg = 0x48 },
+       { .mbps = 2500, .reg = 0x49 },
+       { /* sentinel */ },
+};
+
 static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
        { .mbps =   80, .reg = 0x00 },
        { .mbps =   90, .reg = 0x10 },
@@ -355,6 +452,7 @@ struct rcar_csi2_info {
        unsigned int csi0clkfreqrange;
        unsigned int num_channels;
        bool clear_ulps;
+       bool use_isp;
 };
 
 struct rcar_csi2 {
@@ -609,9 +707,12 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
        rcsi2_write(priv, PHTC_REG, 0);
 
        /* Configure */
-       rcsi2_write(priv, VCDT_REG, vcdt);
-       if (vcdt2)
-               rcsi2_write(priv, VCDT2_REG, vcdt2);
+       if (!priv->info->use_isp) {
+               rcsi2_write(priv, VCDT_REG, vcdt);
+               if (vcdt2)
+                       rcsi2_write(priv, VCDT2_REG, vcdt2);
+       }
+
        /* Lanes are zero indexed. */
        rcsi2_write(priv, LSWAP_REG,
                    LSWAP_L0SEL(priv->lane_swap[0] - 1) |
@@ -636,6 +737,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
                rcsi2_write(priv, CSI0CLKFCPR_REG,
                            CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
 
+       if (priv->info->use_isp)
+               rcsi2_write(priv, PHYFRX_REG,
+                           PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 |
+                           PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0);
+
        rcsi2_write(priv, PHYCNT_REG, phycnt);
        rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
                    LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
@@ -647,6 +753,9 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
        if (ret)
                return ret;
 
+       if (priv->info->use_isp)
+               rcsi2_write(priv, PHYFRX_REG, 0);
+
        /* Run post PHY start initialization, if needed. */
        if (priv->info->phy_post_init) {
                ret = priv->info->phy_post_init(priv);
@@ -1063,6 +1172,62 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv)
        return rcsi2_phtw_write_array(priv, step1);
 }
 
+static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
+                              unsigned int mbps)
+{
+       /* In case of 1500Mbps or less */
+       static const struct phtw_value step1[] = {
+               { .data = 0xcc, .code = 0xe2 },
+               { /* sentinel */ },
+       };
+
+       static const struct phtw_value step2[] = {
+               { .data = 0x01, .code = 0xe3 },
+               { .data = 0x11, .code = 0xe4 },
+               { .data = 0x01, .code = 0xe5 },
+               { /* sentinel */ },
+       };
+
+       /* In case of 1500Mbps or less */
+       static const struct phtw_value step3[] = {
+               { .data = 0x38, .code = 0x08 },
+               { /* sentinel */ },
+       };
+
+       static const struct phtw_value step4[] = {
+               { .data = 0x01, .code = 0x00 },
+               { .data = 0x4b, .code = 0xac },
+               { .data = 0x03, .code = 0x00 },
+               { .data = 0x80, .code = 0x07 },
+               { /* sentinel */ },
+       };
+
+       int ret;
+
+       if (mbps != 0 && mbps <= 1500)
+               ret = rcsi2_phtw_write_array(priv, step1);
+       else
+               ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2);
+       if (ret)
+               return ret;
+
+       ret = rcsi2_phtw_write_array(priv, step2);
+       if (ret)
+               return ret;
+
+       if (mbps != 0 && mbps <= 1500) {
+               ret = rcsi2_phtw_write_array(priv, step3);
+               if (ret)
+                       return ret;
+       }
+
+       ret = rcsi2_phtw_write_array(priv, step4);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 /* -----------------------------------------------------------------------------
  * Platform Device Driver.
  */
@@ -1155,6 +1320,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
        .num_channels = 2,
 };
 
+static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
+       .init_phtw = rcsi2_init_phtw_v3u,
+       .hsfreqrange = hsfreqrange_v3u,
+       .csi0clkfreqrange = 0x20,
+       .clear_ulps = true,
+       .use_isp = true,
+};
+
 static const struct of_device_id rcar_csi2_of_table[] = {
        {
                .compatible = "renesas,r8a774a1-csi2",
@@ -1200,6 +1373,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
                .compatible = "renesas,r8a77990-csi2",
                .data = &rcar_csi2_info_r8a77990,
        },
+       {
+               .compatible = "renesas,r8a779a0-csi2",
+               .data = &rcar_csi2_info_r8a779a0,
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
@@ -1220,7 +1397,7 @@ static int rcsi2_probe(struct platform_device *pdev)
 {
        const struct soc_device_attribute *attr;
        struct rcar_csi2 *priv;
-       unsigned int i;
+       unsigned int i, num_pads;
        int ret;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -1265,11 +1442,13 @@ static int rcsi2_probe(struct platform_device *pdev)
        priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
        priv->subdev.entity.ops = &rcar_csi2_entity_ops;
 
+       num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD;
+
        priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
-       for (i = RCAR_CSI2_SOURCE_VC0; i < NR_OF_RCAR_CSI2_PAD; i++)
+       for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
                priv->pads[i].flags = MEDIA_PAD_FL_SOURCE;
 
-       ret = media_entity_pads_init(&priv->subdev.entity, NR_OF_RCAR_CSI2_PAD,
+       ret = media_entity_pads_init(&priv->subdev.entity, num_pads,
                                     priv->pads);
        if (ret)
                goto error;