aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchit Taneja <architt@codeaurora.org>2015-07-31 04:36:10 -0400
committerRob Clark <robdclark@gmail.com>2015-08-15 18:27:25 -0400
commitc118e29033aa5b38b593ebd0e02f8b1224c20ed3 (patch)
tree0e5fc90b41d59377dfb0928f45cda2f32f78ee06
parent6f054ec5b9ced3041f29541ae79402198678fc06 (diff)
drm/msm/dsi: Allow dsi to connect to an external bridge
There are platforms where the DSI output can be connected to another encoder bridge chip (DSI to HDMI, DSI to LVDS etc). Add support for external bridge support to the dsi driver. We assume that the external bridge chip would be of the type drm_bridge. The dsi driver's internal drm_bridge (msm_dsi->bridge) is linked to the external bridge's drm_bridge struct. In the case we're connected to an external bridge, we don't need to create and manage a connector within our driver, it's the bridge driver's responsibility to create one. v2: - Move the external bridge attaching stuff to dsi manager to make things cleaner. - Force the bridge to connect to a video mode encoder for now (the dsi mode flags may have not been populated by modeset_init) Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c28
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h12
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c9
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c49
4 files changed, 90 insertions, 8 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index ffaf77f623c6..6edcd6f57e70 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -190,6 +190,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
190 struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM]) 190 struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
191{ 191{
192 struct msm_drm_private *priv = dev->dev_private; 192 struct msm_drm_private *priv = dev->dev_private;
193 struct drm_bridge *ext_bridge;
193 int ret, i; 194 int ret, i;
194 195
195 if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] || 196 if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
@@ -217,10 +218,25 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
217 msm_dsi->encoders[i] = encoders[i]; 218 msm_dsi->encoders[i] = encoders[i];
218 } 219 }
219 220
220 msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id); 221 /*
222 * check if the dsi encoder output is connected to a panel or an
223 * external bridge. We create a connector only if we're connected to a
224 * drm_panel device. When we're connected to an external bridge, we
225 * assume that the drm_bridge driver will create the connector itself.
226 */
227 ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
228
229 if (ext_bridge)
230 msm_dsi->connector =
231 msm_dsi_manager_ext_bridge_init(msm_dsi->id);
232 else
233 msm_dsi->connector =
234 msm_dsi_manager_connector_init(msm_dsi->id);
235
221 if (IS_ERR(msm_dsi->connector)) { 236 if (IS_ERR(msm_dsi->connector)) {
222 ret = PTR_ERR(msm_dsi->connector); 237 ret = PTR_ERR(msm_dsi->connector);
223 dev_err(dev->dev, "failed to create dsi connector: %d\n", ret); 238 dev_err(dev->dev,
239 "failed to create dsi connector: %d\n", ret);
224 msm_dsi->connector = NULL; 240 msm_dsi->connector = NULL;
225 goto fail; 241 goto fail;
226 } 242 }
@@ -236,10 +252,12 @@ fail:
236 msm_dsi_manager_bridge_destroy(msm_dsi->bridge); 252 msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
237 msm_dsi->bridge = NULL; 253 msm_dsi->bridge = NULL;
238 } 254 }
239 if (msm_dsi->connector) { 255
256 /* don't destroy connector if we didn't make it */
257 if (msm_dsi->connector && !msm_dsi->external_bridge)
240 msm_dsi->connector->funcs->destroy(msm_dsi->connector); 258 msm_dsi->connector->funcs->destroy(msm_dsi->connector);
241 msm_dsi->connector = NULL; 259
242 } 260 msm_dsi->connector = NULL;
243 } 261 }
244 262
245 return ret; 263 return ret;
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 1636513347e0..09492bfc0e02 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -54,12 +54,20 @@ struct msm_dsi {
54 struct drm_device *dev; 54 struct drm_device *dev;
55 struct platform_device *pdev; 55 struct platform_device *pdev;
56 56
57 /* connector managed by us when we're connected to a drm_panel */
57 struct drm_connector *connector; 58 struct drm_connector *connector;
59 /* internal dsi bridge attached to MDP interface */
58 struct drm_bridge *bridge; 60 struct drm_bridge *bridge;
59 61
60 struct mipi_dsi_host *host; 62 struct mipi_dsi_host *host;
61 struct msm_dsi_phy *phy; 63 struct msm_dsi_phy *phy;
64
65 /*
66 * panel/external_bridge connected to dsi bridge output, only one of the
67 * two can be valid at a time
68 */
62 struct drm_panel *panel; 69 struct drm_panel *panel;
70 struct drm_bridge *external_bridge;
63 unsigned long device_flags; 71 unsigned long device_flags;
64 72
65 struct device *phy_dev; 73 struct device *phy_dev;
@@ -75,6 +83,7 @@ struct msm_dsi {
75struct drm_bridge *msm_dsi_manager_bridge_init(u8 id); 83struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
76void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge); 84void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
77struct drm_connector *msm_dsi_manager_connector_init(u8 id); 85struct drm_connector *msm_dsi_manager_connector_init(u8 id);
86struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id);
78int msm_dsi_manager_phy_enable(int id, 87int msm_dsi_manager_phy_enable(int id,
79 const unsigned long bit_rate, const unsigned long esc_rate, 88 const unsigned long bit_rate, const unsigned long esc_rate,
80 u32 *clk_pre, u32 *clk_post); 89 u32 *clk_pre, u32 *clk_post);
@@ -87,7 +96,7 @@ void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
87/* msm dsi */ 96/* msm dsi */
88static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi) 97static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
89{ 98{
90 return msm_dsi->panel; 99 return msm_dsi->panel || msm_dsi->external_bridge;
91} 100}
92 101
93struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi); 102struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
@@ -143,6 +152,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
143 struct drm_display_mode *mode); 152 struct drm_display_mode *mode);
144struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, 153struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
145 unsigned long *panel_flags); 154 unsigned long *panel_flags);
155struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
146int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer); 156int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
147void msm_dsi_host_unregister(struct mipi_dsi_host *host); 157void msm_dsi_host_unregister(struct mipi_dsi_host *host);
148int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, 158int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 0fa55354ad2c..af40d428ff44 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1646,7 +1646,8 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
1646 */ 1646 */
1647 if (check_defer && msm_host->device_node) { 1647 if (check_defer && msm_host->device_node) {
1648 if (!of_drm_find_panel(msm_host->device_node)) 1648 if (!of_drm_find_panel(msm_host->device_node))
1649 return -EPROBE_DEFER; 1649 if (!of_drm_find_bridge(msm_host->device_node))
1650 return -EPROBE_DEFER;
1650 } 1651 }
1651 } 1652 }
1652 1653
@@ -2073,3 +2074,9 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
2073 return panel; 2074 return panel;
2074} 2075}
2075 2076
2077struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host)
2078{
2079 struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
2080
2081 return of_drm_find_bridge(msm_host->device_node);
2082}
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 60dbd829d7a9..dc3d322375e9 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -517,7 +517,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
517 .mode_set = dsi_mgr_bridge_mode_set, 517 .mode_set = dsi_mgr_bridge_mode_set,
518}; 518};
519 519
520/* initialize connector */ 520/* initialize connector when we're connected to a drm_panel */
521struct drm_connector *msm_dsi_manager_connector_init(u8 id) 521struct drm_connector *msm_dsi_manager_connector_init(u8 id)
522{ 522{
523 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 523 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
@@ -602,6 +602,53 @@ fail:
602 return ERR_PTR(ret); 602 return ERR_PTR(ret);
603} 603}
604 604
605struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
606{
607 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
608 struct drm_device *dev = msm_dsi->dev;
609 struct drm_encoder *encoder;
610 struct drm_bridge *int_bridge, *ext_bridge;
611 struct drm_connector *connector;
612 struct list_head *connector_list;
613
614 int_bridge = msm_dsi->bridge;
615 ext_bridge = msm_dsi->external_bridge =
616 msm_dsi_host_get_bridge(msm_dsi->host);
617
618 /*
619 * HACK: we may not know the external DSI bridge device's mode
620 * flags here. We'll get to know them only when the device
621 * attaches to the dsi host. For now, assume the bridge supports
622 * DSI video mode
623 */
624 encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
625
626 /* link the internal dsi bridge to the external bridge */
627 int_bridge->next = ext_bridge;
628 /* set the external bridge's encoder as dsi's encoder */
629 ext_bridge->encoder = encoder;
630
631 drm_bridge_attach(dev, ext_bridge);
632
633 /*
634 * we need the drm_connector created by the external bridge
635 * driver (or someone else) to feed it to our driver's
636 * priv->connector[] list, mainly for msm_fbdev_init()
637 */
638 connector_list = &dev->mode_config.connector_list;
639
640 list_for_each_entry(connector, connector_list, head) {
641 int i;
642
643 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
644 if (connector->encoder_ids[i] == encoder->base.id)
645 return connector;
646 }
647 }
648
649 return ERR_PTR(-ENODEV);
650}
651
605void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) 652void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
606{ 653{
607} 654}