diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/dsi_manager.c')
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_manager.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 0c1b7dde377c9..cb84d185d73a5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -34,6 +34,32 @@ static struct msm_dsi_manager msm_dsim_glb; #define IS_SYNC_NEEDED() (msm_dsim_glb.is_sync_needed) #define IS_MASTER_DSI_LINK(id) (msm_dsim_glb.master_dsi_link_id == id) +#ifdef CONFIG_OF +static bool dsi_mgr_power_on_early(struct drm_bridge *bridge) +{ + struct drm_bridge *next_bridge = drm_bridge_get_next_bridge(bridge); + + /* + * If the next bridge in the chain is the Parade ps8640 bridge chip + * then don't power on early since it seems to violate the expectations + * of the firmware that the bridge chip is running. + * + * NOTE: this is expected to be a temporary special case. It's expected + * that we'll eventually have a framework that allows the next level + * bridge to indicate whether it needs us to power on before it or + * after it. When that framework is in place then we'll use it and + * remove this special case. + */ + return !(next_bridge && next_bridge->of_node && + of_device_is_compatible(next_bridge->of_node, "parade,ps8640")); +} +#else +static inline bool dsi_mgr_power_on_early(struct drm_bridge *bridge) +{ + return true; +} +#endif + static inline struct msm_dsi *dsi_mgr_get_dsi(int id) { return msm_dsim_glb.dsi[id]; @@ -389,6 +415,9 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id)) return; + if (!dsi_mgr_power_on_early(bridge)) + dsi_mgr_bridge_power_on(bridge); + /* Always call panel functions once, because even for dual panels, * there is only one drm_panel instance. */ @@ -570,7 +599,19 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, if (is_bonded_dsi && other_dsi) msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode); - dsi_mgr_bridge_power_on(bridge); + if (dsi_mgr_power_on_early(bridge)) + dsi_mgr_bridge_power_on(bridge); +} + +static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + int id = dsi_mgr_bridge_get_id(bridge); + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct mipi_dsi_host *host = msm_dsi->host; + + return msm_dsi_host_check_dsc(host, mode); } static const struct drm_connector_funcs dsi_mgr_connector_funcs = { @@ -593,6 +634,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = { .disable = dsi_mgr_bridge_disable, .post_disable = dsi_mgr_bridge_post_disable, .mode_set = dsi_mgr_bridge_mode_set, + .mode_valid = dsi_mgr_bridge_mode_valid, }; /* initialize connector when we're connected to a drm_panel */ @@ -638,7 +680,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) return connector; fail: - connector->funcs->destroy(msm_dsi->connector); + connector->funcs->destroy(connector); return ERR_PTR(ret); } @@ -665,6 +707,8 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) bridge = &dsi_bridge->base; bridge->funcs = &dsi_mgr_bridge_funcs; + drm_bridge_add(bridge); + ret = drm_bridge_attach(encoder, bridge, NULL, 0); if (ret) goto fail; @@ -735,6 +779,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) { + drm_bridge_remove(bridge); } int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg) |