drm: rcar-du: rzg2l_mipi_dsi: Enhance device lanes check
authorBiju Das <biju.das.jz@bp.renesas.com>
Tue, 20 Sep 2022 10:55:01 +0000 (11:55 +0100)
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Wed, 9 Nov 2022 14:45:58 +0000 (16:45 +0200)
Enhance device lanes check by reading TXSETR register at probe(),
and enforced in rzg2l_mipi_dsi_host_attach().

As per HW manual, we can read TXSETR register only after
DPHY initialization.

Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
drivers/gpu/drm/rcar-du/rzg2l_mipi_dsi.c

index 8579208db218b7f802f8518626a10e4b950c0d67..aa95b85a29643710e5cdad5cf57c37ce5274cdbc 100644 (file)
@@ -171,6 +171,11 @@ static void rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 d
        iowrite32(data, dsi->mmio + LINK_REG_OFFSET + reg);
 }
 
+static u32 rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
+{
+       return ioread32(dsi->mmio + reg);
+}
+
 static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
 {
        return ioread32(dsi->mmio + LINK_REG_OFFSET + reg);
@@ -180,19 +185,11 @@ static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
  * Hardware Setup
  */
 
-static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
-                                 const struct drm_display_mode *mode)
+static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+                                   unsigned long hsfreq)
 {
        const struct rzg2l_mipi_dsi_timings *dphy_timings;
-       unsigned long hsfreq;
-       unsigned int i, bpp;
-       u32 txsetr;
-       u32 clstptsetr;
-       u32 lptrnstsetr;
-       u32 clkkpt;
-       u32 clkbfht;
-       u32 clkstpt;
-       u32 golpbkt;
+       unsigned int i;
        u32 dphyctrl0;
        u32 dphytim0;
        u32 dphytim1;
@@ -200,19 +197,6 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
        u32 dphytim3;
        int ret;
 
-       /*
-        * Relationship between hsclk and vclk must follow
-        * vclk * bpp = hsclk * 8 * lanes
-        * where vclk: video clock (Hz)
-        *       bpp: video pixel bit depth
-        *       hsclk: DSI HS Byte clock frequency (Hz)
-        *       lanes: number of data lanes
-        *
-        * hsclk(bit) = hsclk(byte) * 8
-        */
-       bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
-       hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes);
-
        /* All DSI global operation timings are set with recommended setting */
        for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) {
                dphy_timings = &rzg2l_mipi_dsi_global_timings[i];
@@ -220,12 +204,6 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
                        break;
        }
 
-       ret = pm_runtime_resume_and_get(dsi->dev);
-       if (ret < 0)
-               return ret;
-
-       clk_set_rate(dsi->vclk, mode->clock * 1000);
-
        /* Initializing DPHY before accessing LINK */
        dphyctrl0 = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN |
                    DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR;
@@ -259,10 +237,62 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
 
        ret = reset_control_deassert(dsi->rstc);
        if (ret < 0)
-               goto err_pm_put;
+               return ret;
 
        udelay(1);
 
+       return 0;
+}
+
+static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
+{
+       u32 dphyctrl0;
+
+       dphyctrl0 = rzg2l_mipi_dsi_phy_read(dsi, DSIDPHYCTRL0);
+
+       dphyctrl0 &= ~(DSIDPHYCTRL0_EN_LDO1200 | DSIDPHYCTRL0_EN_BGR);
+       rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
+
+       reset_control_assert(dsi->rstc);
+}
+
+static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
+                                 const struct drm_display_mode *mode)
+{
+       unsigned long hsfreq;
+       unsigned int bpp;
+       u32 txsetr;
+       u32 clstptsetr;
+       u32 lptrnstsetr;
+       u32 clkkpt;
+       u32 clkbfht;
+       u32 clkstpt;
+       u32 golpbkt;
+       int ret;
+
+       /*
+        * Relationship between hsclk and vclk must follow
+        * vclk * bpp = hsclk * 8 * lanes
+        * where vclk: video clock (Hz)
+        *       bpp: video pixel bit depth
+        *       hsclk: DSI HS Byte clock frequency (Hz)
+        *       lanes: number of data lanes
+        *
+        * hsclk(bit) = hsclk(byte) * 8
+        */
+       bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+       hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes);
+
+       ret = pm_runtime_resume_and_get(dsi->dev);
+       if (ret < 0)
+               return ret;
+
+       clk_set_rate(dsi->vclk, mode->clock * 1000);
+
+       ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq);
+       if (ret < 0)
+               goto err_phy;
+
        /* Enable Data lanes and Clock lanes */
        txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN;
        rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr);
@@ -301,7 +331,8 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
 
        return 0;
 
-err_pm_put:
+err_phy:
+       rzg2l_mipi_dsi_dphy_exit(dsi);
        pm_runtime_put(dsi->dev);
 
        return ret;
@@ -309,7 +340,7 @@ err_pm_put:
 
 static void rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi *dsi)
 {
-       reset_control_assert(dsi->rstc);
+       rzg2l_mipi_dsi_dphy_exit(dsi);
        pm_runtime_put(dsi->dev);
 }
 
@@ -666,7 +697,9 @@ static const struct dev_pm_ops rzg2l_mipi_pm_ops = {
 
 static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
 {
+       unsigned int num_data_lanes;
        struct rzg2l_mipi_dsi *dsi;
+       u32 txsetr;
        int ret;
 
        dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
@@ -681,7 +714,7 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
                return dev_err_probe(dsi->dev, ret,
                                     "missing or invalid data-lanes property\n");
 
-       dsi->num_data_lanes = ret;
+       num_data_lanes = ret;
 
        dsi->mmio = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dsi->mmio))
@@ -710,6 +743,24 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dsi->dev);
 
+       ret = pm_runtime_resume_and_get(dsi->dev);
+       if (ret < 0)
+               goto err_pm_disable;
+
+       /*
+        * TXSETR register can be read only after DPHY init. But during probe
+        * mode->clock and format are not available. So initialize DPHY with
+        * timing parameters for 80Mbps.
+        */
+       ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000);
+       if (ret < 0)
+               goto err_phy;
+
+       txsetr = rzg2l_mipi_dsi_link_read(dsi, TXSETR);
+       dsi->num_data_lanes = min(((txsetr >> 16) & 3) + 1, num_data_lanes);
+       rzg2l_mipi_dsi_dphy_exit(dsi);
+       pm_runtime_put(dsi->dev);
+
        /* Initialize the DRM bridge. */
        dsi->bridge.funcs = &rzg2l_mipi_dsi_bridge_ops;
        dsi->bridge.of_node = dsi->dev->of_node;
@@ -723,6 +774,9 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
 
        return 0;
 
+err_phy:
+       rzg2l_mipi_dsi_dphy_exit(dsi);
+       pm_runtime_put(dsi->dev);
 err_pm_disable:
        pm_runtime_disable(dsi->dev);
        return ret;