| From ee2771bbb976a4d50b929dfe6cb26a835aed591b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 18 Apr 2021 19:04:10 -0700 |
| Subject: drm/rockchip: dsi: move all lane config except LCDC mux to bind() |
| |
| From: Thomas Hebb <tommyhebb@gmail.com> |
| |
| [ Upstream commit 43c2de1002d2b70fb5941fa14e97a34e3dc214d4 ] |
| |
| 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 <tommyhebb@gmail.com> |
| Tested-by: Jonathan Liu <net147@gmail.com> |
| Signed-off-by: Heiko Stuebner <heiko@sntech.de> |
| Link: https://patchwork.freedesktop.org/patch/msgid/55fe7f3454d8c91dc3837ba5aa741d4a0e67378f.1618797813.git.tommyhebb@gmail.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../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 542dcf7eddd6..75a76408cb29 100644 |
| --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c |
| +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c |
| @@ -692,13 +692,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); |
| @@ -712,6 +707,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, |
| @@ -767,9 +769,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); |
| } |
| @@ -923,6 +925,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.30.2 |
| |