Commit e5400750 authored by Stephan Gerhold's avatar Stephan Gerhold Committed by Rob Clark

drm/msm/dsi: Delay drm_panel_enable() until dsi_mgr_bridge_enable()

At the moment, the MSM DSI driver calls drm_panel_enable() rather early
from the DSI bridge pre_enable() function. At this point, the encoder
(e.g. MDP5) is not enabled, so we have not started transmitting
video data.

However, the drm_panel_funcs documentation states that enable()
should be called on the panel *after* video data is being transmitted:

  The .prepare() function is typically called before the display controller
  starts to transmit video data. [...] After the display controller has
  started transmitting video data, it's safe to call the .enable() function.
  This will typically enable the backlight to make the image on screen visible.

Calling drm_panel_enable() too early causes problems for some panels:
The TFT LCD panel used in the Samsung Galaxy Tab A 9.7 (2015) (APQ8016)
uses the MIPI_DCS_SET_DISPLAY_BRIGHTNESS command to control
backlight/brightness of the screen. The enable sequence is therefore:

  drm_panel_enable()
    drm_panel_funcs.enable():
      backlight_enable()
        backlight_ops.update_status():
          mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);

The panel seems to silently ignore the MIPI_DCS_SET_DISPLAY_BRIGHTNESS
command if it is sent too early. This prevents setting the initial brightness,
causing the display to be enabled with minimum brightness instead.
Adding various delays in the panel initialization code does not result
in any difference.

On the other hand, moving drm_panel_enable() to dsi_mgr_bridge_enable()
fixes the problem, indicating that the panel requires the video stream
to be active before the brightness command is accepted.

Therefore: Move drm_panel_enable() to dsi_mgr_bridge_enable() to
delay calling it until video data is being transmitted.

Move drm_panel_disable() to dsi_mgr_bridge_disable() for similar reasons.
(This is not strictly required for the panel affected above...)
Tested-by: default avatarJasper Korten <jja2000@gmail.com>
Signed-off-by: default avatarStephan Gerhold <stephan@gerhold.net>
Tested-by: default avatarJeffrey Hugo <jeffrey.l.hugo@gmail.com>
Reviewed-by: default avatarJeffrey Hugo <jeffrey.l.hugo@gmail.com>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent fea2d7d9
......@@ -432,20 +432,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
}
}
if (panel) {
ret = drm_panel_enable(panel);
if (ret) {
pr_err("%s: enable panel %d failed, %d\n", __func__, id,
ret);
goto panel_en_fail;
}
}
return;
panel_en_fail:
if (is_dual_dsi && msm_dsi1)
msm_dsi_host_disable(msm_dsi1->host);
host1_en_fail:
msm_dsi_host_disable(host);
host_en_fail:
......@@ -464,12 +452,51 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
{
DBG("");
int id = dsi_mgr_bridge_get_id(bridge);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_panel *panel = msm_dsi->panel;
bool is_dual_dsi = IS_DUAL_DSI();
int ret;
DBG("id=%d", id);
if (!msm_dsi_device_connected(msm_dsi))
return;
/* Do nothing with the host if it is slave-DSI in case of dual DSI */
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
return;
if (panel) {
ret = drm_panel_enable(panel);
if (ret) {
pr_err("%s: enable panel %d failed, %d\n", __func__, id,
ret);
}
}
}
static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
{
DBG("");
int id = dsi_mgr_bridge_get_id(bridge);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_panel *panel = msm_dsi->panel;
bool is_dual_dsi = IS_DUAL_DSI();
int ret;
DBG("id=%d", id);
if (!msm_dsi_device_connected(msm_dsi))
return;
/* Do nothing with the host if it is slave-DSI in case of dual DSI */
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
return;
if (panel) {
ret = drm_panel_disable(panel);
if (ret)
pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
ret);
}
}
static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
......@@ -495,13 +522,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
goto disable_phy;
if (panel) {
ret = drm_panel_disable(panel);
if (ret)
pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
ret);
}
ret = msm_dsi_host_disable(host);
if (ret)
pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment