Skip to content

Commit

Permalink
drm/msm/dsi: Use one connector for dual DSI mode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chandan Uddaraju authored and Sean Paul committed Jul 26, 2018
1 parent ed9976a commit 8b03ad3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 86 deletions.
3 changes: 3 additions & 0 deletions drivers/gpu/drm/msm/dsi/dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
goto fail;
}

if (!msm_dsi_manager_validate_current_config(msm_dsi->id))
goto fail;

msm_dsi->encoder = encoder;

msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/msm/dsi/dsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
int msm_dsi_manager_register(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 */
static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
Expand Down
112 changes: 26 additions & 86 deletions drivers/gpu/drm/msm/dsi/dsi_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,102 +306,25 @@ static void dsi_mgr_connector_destroy(struct drm_connector *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)
{
int id = dsi_mgr_connector_get_id(connector);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_panel *panel = msm_dsi->panel;
int ret, num;
int num;

if (!panel)
return 0;

/* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
* panel should not attach to any connector.
* Only temporarily attach panel to the current connector here,
* to let panel set mode to this connector.
/*
* In dual DSI mode, we have one connector that can be
* attached to the drm_panel.
*/
drm_panel_attach(panel, connector);
num = drm_panel_get_modes(panel);
drm_panel_detach(panel);
if (!num)
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;
}

Expand Down Expand Up @@ -455,8 +378,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
if (ret)
goto phy_en_fail;

/* Do nothing with the host if it is DSI 1 in case of dual DSI */
if (is_dual_dsi && (DSI_1 == id))
/* 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;

ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_dual_dsi);
Expand Down Expand Up @@ -557,11 +480,11 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
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
* 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;

if (panel) {
Expand Down Expand Up @@ -622,7 +545,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
mode->vsync_end, mode->vtotal,
mode->type, mode->flags);

if (is_dual_dsi && (DSI_1 == id))
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
return;

msm_dsi_host_set_display_mode(host, adjusted_mode);
Expand Down Expand Up @@ -690,6 +613,23 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id)
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 */
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
{
Expand Down

0 comments on commit 8b03ad3

Please sign in to comment.