drm/msm/dsi: Use one connector for dual DSI mode
Current DSI driver uses two connectors for dual DSI case even though we only have one panel. Fix this by implementing one connector/bridge for dual DSI use case. Use master DSI controllers to register one connector/bridge. Changes in v3: - None Reviewed-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org> [seanpaul removed unused local var causing a build warning] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
parent
ed9976a09b
commit
8b03ad30e3
@ -208,6 +208,9 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!msm_dsi_manager_validate_current_config(msm_dsi->id))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
msm_dsi->encoder = encoder;
|
msm_dsi->encoder = encoder;
|
||||||
|
|
||||||
msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
|
msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
|
||||||
|
@ -100,6 +100,7 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
|
|||||||
void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags);
|
void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags);
|
||||||
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
|
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
|
||||||
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
|
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
|
||||||
|
bool msm_dsi_manager_validate_current_config(u8 id);
|
||||||
|
|
||||||
/* msm dsi */
|
/* msm dsi */
|
||||||
static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
|
static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
|
||||||
|
@ -306,102 +306,25 @@ static void dsi_mgr_connector_destroy(struct drm_connector *connector)
|
|||||||
kfree(dsi_connector);
|
kfree(dsi_connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
|
|
||||||
{
|
|
||||||
struct drm_display_mode *mode, *m;
|
|
||||||
|
|
||||||
/* Only support left-right mode */
|
|
||||||
list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
|
|
||||||
mode->clock >>= 1;
|
|
||||||
mode->hdisplay >>= 1;
|
|
||||||
mode->hsync_start >>= 1;
|
|
||||||
mode->hsync_end >>= 1;
|
|
||||||
mode->htotal >>= 1;
|
|
||||||
drm_mode_set_name(mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dsi_dual_connector_tile_init(
|
|
||||||
struct drm_connector *connector, int id)
|
|
||||||
{
|
|
||||||
struct drm_display_mode *mode;
|
|
||||||
/* Fake topology id */
|
|
||||||
char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
|
|
||||||
|
|
||||||
if (connector->tile_group) {
|
|
||||||
DBG("Tile property has been initialized");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use the first mode only for now */
|
|
||||||
mode = list_first_entry(&connector->probed_modes,
|
|
||||||
struct drm_display_mode,
|
|
||||||
head);
|
|
||||||
if (!mode)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
connector->tile_group = drm_mode_get_tile_group(
|
|
||||||
connector->dev, topo_id);
|
|
||||||
if (!connector->tile_group)
|
|
||||||
connector->tile_group = drm_mode_create_tile_group(
|
|
||||||
connector->dev, topo_id);
|
|
||||||
if (!connector->tile_group) {
|
|
||||||
pr_err("%s: failed to create tile group\n", __func__);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
connector->has_tile = true;
|
|
||||||
connector->tile_is_single_monitor = true;
|
|
||||||
|
|
||||||
/* mode has been fixed */
|
|
||||||
connector->tile_h_size = mode->hdisplay;
|
|
||||||
connector->tile_v_size = mode->vdisplay;
|
|
||||||
|
|
||||||
/* Only support left-right mode */
|
|
||||||
connector->num_h_tile = 2;
|
|
||||||
connector->num_v_tile = 1;
|
|
||||||
|
|
||||||
connector->tile_v_loc = 0;
|
|
||||||
connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
|
static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
int id = dsi_mgr_connector_get_id(connector);
|
int id = dsi_mgr_connector_get_id(connector);
|
||||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||||
struct drm_panel *panel = msm_dsi->panel;
|
struct drm_panel *panel = msm_dsi->panel;
|
||||||
int ret, num;
|
int num;
|
||||||
|
|
||||||
if (!panel)
|
if (!panel)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
|
/*
|
||||||
* panel should not attach to any connector.
|
* In dual DSI mode, we have one connector that can be
|
||||||
* Only temporarily attach panel to the current connector here,
|
* attached to the drm_panel.
|
||||||
* to let panel set mode to this connector.
|
|
||||||
*/
|
*/
|
||||||
drm_panel_attach(panel, connector);
|
drm_panel_attach(panel, connector);
|
||||||
num = drm_panel_get_modes(panel);
|
num = drm_panel_get_modes(panel);
|
||||||
drm_panel_detach(panel);
|
|
||||||
if (!num)
|
if (!num)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (IS_DUAL_DSI()) {
|
|
||||||
/* report half resolution to user */
|
|
||||||
dsi_dual_connector_fix_modes(connector);
|
|
||||||
ret = dsi_dual_connector_tile_init(connector, id);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = drm_connector_set_tile_property(connector);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: set tile property failed, %d\n",
|
|
||||||
__func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,8 +378,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto phy_en_fail;
|
goto phy_en_fail;
|
||||||
|
|
||||||
/* Do nothing with the host if it is DSI 1 in case of dual DSI */
|
/* Do nothing with the host if it is slave-DSI in case of dual DSI */
|
||||||
if (is_dual_dsi && (DSI_1 == id))
|
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_dual_dsi);
|
ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_dual_dsi);
|
||||||
@ -557,11 +480,11 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do nothing with the host if it is DSI 1 in case of dual DSI.
|
* Do nothing with the host if it is slave-DSI in case of dual DSI.
|
||||||
* It is safe to call dsi_mgr_phy_disable() here because a single PHY
|
* It is safe to call dsi_mgr_phy_disable() here because a single PHY
|
||||||
* won't be diabled until both PHYs request disable.
|
* won't be diabled until both PHYs request disable.
|
||||||
*/
|
*/
|
||||||
if (is_dual_dsi && (DSI_1 == id))
|
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
|
||||||
goto disable_phy;
|
goto disable_phy;
|
||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
@ -622,7 +545,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
|
|||||||
mode->vsync_end, mode->vtotal,
|
mode->vsync_end, mode->vtotal,
|
||||||
mode->type, mode->flags);
|
mode->type, mode->flags);
|
||||||
|
|
||||||
if (is_dual_dsi && (DSI_1 == id))
|
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
msm_dsi_host_set_display_mode(host, adjusted_mode);
|
msm_dsi_host_set_display_mode(host, adjusted_mode);
|
||||||
@ -690,6 +613,23 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id)
|
|||||||
return connector;
|
return connector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool msm_dsi_manager_validate_current_config(u8 id)
|
||||||
|
{
|
||||||
|
bool is_dual_dsi = IS_DUAL_DSI();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For dual DSI, we only have one drm panel. For this
|
||||||
|
* use case, we register only one bridge/connector.
|
||||||
|
* Skip bridge/connector initialisation if it is
|
||||||
|
* slave-DSI for dual DSI configuration.
|
||||||
|
*/
|
||||||
|
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) {
|
||||||
|
DBG("Skip bridge registration for slave DSI->id: %d\n", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* initialize bridge */
|
/* initialize bridge */
|
||||||
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
|
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user