2020-12-14 09:26:27

by Tom Hebb

[permalink] [raw]
Subject: [RESEND PATCH] drm/rockchip: dsi: move all lane config except LCDC mux to bind()

When we first enable the DSI encoder, we currently program some per-chip
configuration that we look up in rk3399_chip_data based on the device
tree compatible we match. This data configures various parameters of the
MIPI lanes, including on RK3399 whether DSI1 is slaved to DSI0 in a
dual-mode configuration. It also selects which LCDC (i.e. VOP) to scan
out from.

This causes a problem in RK3399 dual-mode configurations, though: panel
prepare() callbacks run before the encoder gets enabled and expect to be
able to write commands to the DSI bus, but the bus isn't fully
functional until the lane and master/slave configuration have been
programmed. As a result, dual-mode panels (and possibly others too) fail
to turn on when the rockchipdrm driver is initially loaded.

Because the LCDC mux is the only thing we don't know until enable time
(and is the only thing that can ever change), we can actually move most
of the initialization to bind() and get it out of the way early. That's
what this change does. (Rockchip's 4.4 BSP kernel does it in mode_set(),
which also avoids the issue, but bind() seems like the more correct
place to me.)

Tested on a Google Scarlet board (Acer Chromebook Tab 10), which has a
Kingdisplay KD097D04 dual-mode panel. Prior to this change, the panel's
backlight would turn on but no image would appear when initially loading
rockchipdrm. If I kept rockchipdrm loaded and reloaded the panel driver,
it would come on. With this change, the panel successfully turns on
during initial rockchipdrm load as expected.

Fixes: 2d4f7bdafd70 ("drm/rockchip: dsi: migrate to use dw-mipi-dsi bridge driver")
Signed-off-by: Thomas Hebb <[email protected]>
---
Resending since I wasn't subscribed to dri-devel

.../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 36 ++++++++++++++-----
1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index ce044db8c97e..d0c9610ad220 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -691,13 +691,8 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
.get_timing = dw_mipi_dsi_phy_get_timing,
};

-static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
- int mux)
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
{
- if (dsi->cdata->lcdsel_grf_reg)
- regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
- mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
-
if (dsi->cdata->lanecfg1_grf_reg)
regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
dsi->cdata->lanecfg1);
@@ -711,6 +706,13 @@ static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
dsi->cdata->enable);
}

+static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
+ int mux)
+{
+ regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+ mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+}
+
static int
dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
@@ -766,9 +768,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
return;
}

- dw_mipi_dsi_rockchip_config(dsi, mux);
+ dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
if (dsi->slave)
- dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+ dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);

clk_disable_unprepare(dsi->grf_clk);
}
@@ -922,6 +924,24 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
return ret;
}

+ /*
+ * With the GRF clock running, write lane and dual-mode configurations
+ * that won't change immediately. If we waited until enable() to do
+ * this, things like panel preparation would not be able to send
+ * commands over DSI.
+ */
+ ret = clk_prepare_enable(dsi->grf_clk);
+ if (ret) {
+ DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+ return ret;
+ }
+
+ dw_mipi_dsi_rockchip_config(dsi);
+ if (dsi->slave)
+ dw_mipi_dsi_rockchip_config(dsi->slave);
+
+ clk_disable_unprepare(dsi->grf_clk);
+
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
--
2.29.2


2021-01-21 11:18:21

by aleksandr.o.makarov

[permalink] [raw]
Subject: Re: [RESEND PATCH] drm/rockchip: dsi: move all lane config except LCDC mux to bind()

В Вс, 13/12/2020 в 12:58 -0800, Thomas Hebb пишет:
> When we first enable the DSI encoder, we currently program some per-chip
> configuration that we look up in rk3399_chip_data based on the device
> tree compatible we match. This data configures various parameters of the
> MIPI lanes, including on RK3399 whether DSI1 is slaved to DSI0 in a
> dual-mode configuration. It also selects which LCDC (i.e. VOP) to scan
> out from.
>
> This causes a problem in RK3399 dual-mode configurations, though: panel
> prepare() callbacks run before the encoder gets enabled and expect to be
> able to write commands to the DSI bus, but the bus isn't fully
> functional until the lane and master/slave configuration have been
> programmed. As a result, dual-mode panels (and possibly others too) fail
> to turn on when the rockchipdrm driver is initially loaded.
>
> Because the LCDC mux is the only thing we don't know until enable time
> (and is the only thing that can ever change), we can actually move most
> of the initialization to bind() and get it out of the way early. That's
> what this change does. (Rockchip's 4.4 BSP kernel does it in mode_set(),
> which also avoids the issue, but bind() seems like the more correct
> place to me.)
>
> Tested on a Google Scarlet board (Acer Chromebook Tab 10), which has a
> Kingdisplay KD097D04 dual-mode panel. Prior to this change, the panel's
> backlight would turn on but no image would appear when initially loading
> rockchipdrm. If I kept rockchipdrm loaded and reloaded the panel driver,
> it would come on. With this change, the panel successfully turns on
> during initial rockchipdrm load as expected.
>
> Fixes: 2d4f7bdafd70 ("drm/rockchip: dsi: migrate to use dw-mipi-dsi bridge driver")
> Signed-off-by: Thomas Hebb <[email protected]>
> ---
> Resending since I wasn't subscribed to dri-devel
>
>  .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 36 ++++++++++++++-----
>  1 file changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> index ce044db8c97e..d0c9610ad220 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> @@ -691,13 +691,8 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
>   .get_timing = dw_mipi_dsi_phy_get_timing,
>  };
>  
>
> -static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
> - int mux)
> +static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
>  {
> - if (dsi->cdata->lcdsel_grf_reg)
> - regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
> - mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
> -
>   if (dsi->cdata->lanecfg1_grf_reg)
>   regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
>   dsi->cdata->lanecfg1);
> @@ -711,6 +706,13 @@ static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
>   dsi->cdata->enable);
>  }
>  
>
> +static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
> + int mux)
> +{
> + regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
> + mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
> +}
> +
>  static int
>  dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
>   struct drm_crtc_state *crtc_state,
> @@ -766,9 +768,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>   return;
>   }
>  
>
> - dw_mipi_dsi_rockchip_config(dsi, mux);
> + dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
>   if (dsi->slave)
> - dw_mipi_dsi_rockchip_config(dsi->slave, mux);
> + dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);
>  
>
>   clk_disable_unprepare(dsi->grf_clk);
>  }
> @@ -922,6 +924,24 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
>   return ret;
>   }
>  
>
> + /*
> + * With the GRF clock running, write lane and dual-mode configurations
> + * that won't change immediately. If we waited until enable() to do
> + * this, things like panel preparation would not be able to send
> + * commands over DSI.
> + */
> + ret = clk_prepare_enable(dsi->grf_clk);
> + if (ret) {
> + DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> + return ret;
> + }
> +
> + dw_mipi_dsi_rockchip_config(dsi);
> + if (dsi->slave)
> + dw_mipi_dsi_rockchip_config(dsi->slave);
> +
> + clk_disable_unprepare(dsi->grf_clk);
> +
>   ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
>   if (ret) {
>   DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");

Have tested this patch on a Pine64 RockPro64 v2.1 with Linux v5.4.44

All works good when DRM_PANEL_KINGDISPLAY_KD097D04=m

Something bad happens when DRM_PANEL_KINGDISPLAY_KD097D04=y - the panel
driver starts again to fail to write prepare() commands to DSI:

[ 28.709049] 005: dw-mipi-dsi-rockchip ff960000.mipi: failed to write
command FIFO
[ 28.709056] 005: panel-kingdisplay-kd097d04 ff960000.mipi.0:
[drm:kingdisplay_panel_prepare] *ERROR* failed write init cmds: -110



Attachments:
dmesg-21-01-2021-13:02 (25.64 kB)