aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2016-04-11 06:16:33 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2016-08-22 09:34:18 -0400
commit894f5a9f4b4aaf154fce121d80199a2e2146d6d1 (patch)
tree8600f72ea7a22ec8a62fa1ad4a24317a8a0fe23c
parenta8444c7ee2c02b567731a6edcd5d328f85aac1b1 (diff)
drm/sun4i: Add bridge support
Our RGB bus can be either connected to a bridge or a panel. While the panel support was already there, the bridge was not. Fix that. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c58
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c43
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.h1
4 files changed, 87 insertions, 19 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 7092daaf6c43..942f62e2441c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -257,8 +257,8 @@ static int sun4i_drv_add_endpoints(struct device *dev,
257 } 257 }
258 258
259 /* 259 /*
260 * If the node is our TCON, the first port is used for our 260 * If the node is our TCON, the first port is used for
261 * panel, and will not be part of the 261 * panel or bridges, and will not be part of the
262 * component framework. 262 * component framework.
263 */ 263 */
264 if (sun4i_drv_node_is_tcon(node)) { 264 if (sun4i_drv_node_is_tcon(node)) {
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index d32f08f9ce5f..d4e52522ec53 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -151,7 +151,12 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
151 151
152 DRM_DEBUG_DRIVER("Enabling RGB output\n"); 152 DRM_DEBUG_DRIVER("Enabling RGB output\n");
153 153
154 drm_panel_enable(tcon->panel); 154 if (!IS_ERR(tcon->panel))
155 drm_panel_enable(tcon->panel);
156
157 if (!IS_ERR(encoder->bridge))
158 drm_bridge_enable(encoder->bridge);
159
155 sun4i_tcon_channel_enable(tcon, 0); 160 sun4i_tcon_channel_enable(tcon, 0);
156} 161}
157 162
@@ -164,7 +169,12 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
164 DRM_DEBUG_DRIVER("Disabling RGB output\n"); 169 DRM_DEBUG_DRIVER("Disabling RGB output\n");
165 170
166 sun4i_tcon_channel_disable(tcon, 0); 171 sun4i_tcon_channel_disable(tcon, 0);
167 drm_panel_disable(tcon->panel); 172
173 if (!IS_ERR(encoder->bridge))
174 drm_bridge_disable(encoder->bridge);
175
176 if (!IS_ERR(tcon->panel))
177 drm_panel_disable(tcon->panel);
168} 178}
169 179
170static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder, 180static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
@@ -203,6 +213,7 @@ int sun4i_rgb_init(struct drm_device *drm)
203{ 213{
204 struct sun4i_drv *drv = drm->dev_private; 214 struct sun4i_drv *drv = drm->dev_private;
205 struct sun4i_tcon *tcon = drv->tcon; 215 struct sun4i_tcon *tcon = drv->tcon;
216 struct drm_encoder *encoder;
206 struct sun4i_rgb *rgb; 217 struct sun4i_rgb *rgb;
207 int ret; 218 int ret;
208 219
@@ -210,10 +221,12 @@ int sun4i_rgb_init(struct drm_device *drm)
210 if (!rgb) 221 if (!rgb)
211 return -ENOMEM; 222 return -ENOMEM;
212 rgb->drv = drv; 223 rgb->drv = drv;
224 encoder = &rgb->encoder;
213 225
214 tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node); 226 tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
215 if (IS_ERR(tcon->panel)) { 227 encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
216 dev_info(drm->dev, "No panel found... RGB output disabled\n"); 228 if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
229 dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
217 return 0; 230 return 0;
218 } 231 }
219 232
@@ -232,19 +245,36 @@ int sun4i_rgb_init(struct drm_device *drm)
232 /* The RGB encoder can only work with the TCON channel 0 */ 245 /* The RGB encoder can only work with the TCON channel 0 */
233 rgb->encoder.possible_crtcs = BIT(0); 246 rgb->encoder.possible_crtcs = BIT(0);
234 247
235 drm_connector_helper_add(&rgb->connector, 248 if (!IS_ERR(tcon->panel)) {
236 &sun4i_rgb_con_helper_funcs); 249 drm_connector_helper_add(&rgb->connector,
237 ret = drm_connector_init(drm, &rgb->connector, 250 &sun4i_rgb_con_helper_funcs);
238 &sun4i_rgb_con_funcs, 251 ret = drm_connector_init(drm, &rgb->connector,
239 DRM_MODE_CONNECTOR_Unknown); 252 &sun4i_rgb_con_funcs,
240 if (ret) { 253 DRM_MODE_CONNECTOR_Unknown);
241 dev_err(drm->dev, "Couldn't initialise the rgb connector\n"); 254 if (ret) {
242 goto err_cleanup_connector; 255 dev_err(drm->dev, "Couldn't initialise the rgb connector\n");
256 goto err_cleanup_connector;
257 }
258
259 drm_mode_connector_attach_encoder(&rgb->connector,
260 &rgb->encoder);
261
262 ret = drm_panel_attach(tcon->panel, &rgb->connector);
263 if (ret) {
264 dev_err(drm->dev, "Couldn't attach our panel\n");
265 goto err_cleanup_connector;
266 }
243 } 267 }
244 268
245 drm_mode_connector_attach_encoder(&rgb->connector, &rgb->encoder); 269 if (!IS_ERR(encoder->bridge)) {
270 encoder->bridge->encoder = &rgb->encoder;
246 271
247 drm_panel_attach(tcon->panel, &rgb->connector); 272 ret = drm_bridge_attach(drm, encoder->bridge);
273 if (ret) {
274 dev_err(drm->dev, "Couldn't attach our bridge\n");
275 goto err_cleanup_connector;
276 }
277 }
248 278
249 return 0; 279 return 0;
250 280
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index d2f7489d29a5..2145ecf2cf5d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -432,6 +432,40 @@ struct drm_panel *sun4i_tcon_find_panel(struct device_node *node)
432 return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER); 432 return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER);
433} 433}
434 434
435struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node)
436{
437 struct device_node *port, *remote, *child;
438 struct device_node *end_node = NULL;
439
440 /* Inputs are listed first, then outputs */
441 port = of_graph_get_port_by_id(node, 1);
442
443 /*
444 * Our first output is the RGB interface where the panel will
445 * be connected.
446 */
447 for_each_child_of_node(port, child) {
448 u32 reg;
449
450 of_property_read_u32(child, "reg", &reg);
451 if (reg == 0)
452 end_node = child;
453 }
454
455 if (!end_node) {
456 DRM_DEBUG_DRIVER("Missing bridge endpoint\n");
457 return ERR_PTR(-ENODEV);
458 }
459
460 remote = of_graph_get_remote_port_parent(end_node);
461 if (!remote) {
462 DRM_DEBUG_DRIVER("Enable to parse remote node\n");
463 return ERR_PTR(-EINVAL);
464 }
465
466 return of_drm_find_bridge(remote) ?: ERR_PTR(-EPROBE_DEFER);
467}
468
435static int sun4i_tcon_bind(struct device *dev, struct device *master, 469static int sun4i_tcon_bind(struct device *dev, struct device *master,
436 void *data) 470 void *data)
437{ 471{
@@ -514,19 +548,22 @@ static struct component_ops sun4i_tcon_ops = {
514static int sun4i_tcon_probe(struct platform_device *pdev) 548static int sun4i_tcon_probe(struct platform_device *pdev)
515{ 549{
516 struct device_node *node = pdev->dev.of_node; 550 struct device_node *node = pdev->dev.of_node;
551 struct drm_bridge *bridge;
517 struct drm_panel *panel; 552 struct drm_panel *panel;
518 553
519 /* 554 /*
520 * The panel is not ready. 555 * Neither the bridge or the panel is ready.
521 * Defer the probe. 556 * Defer the probe.
522 */ 557 */
523 panel = sun4i_tcon_find_panel(node); 558 panel = sun4i_tcon_find_panel(node);
559 bridge = sun4i_tcon_find_bridge(node);
524 560
525 /* 561 /*
526 * If we don't have a panel endpoint, just go on 562 * If we don't have a panel endpoint, just go on
527 */ 563 */
528 if (PTR_ERR(panel) == -EPROBE_DEFER) { 564 if ((PTR_ERR(panel) == -EPROBE_DEFER) &&
529 DRM_DEBUG_DRIVER("Still waiting for our panel. Deferring...\n"); 565 (PTR_ERR(bridge) == -EPROBE_DEFER)) {
566 DRM_DEBUG_DRIVER("Still waiting for our panel/bridge. Deferring...\n");
530 return -EPROBE_DEFER; 567 return -EPROBE_DEFER;
531 } 568 }
532 569
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 4f81d86ee5a4..100bfa093277 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -166,6 +166,7 @@ struct sun4i_tcon {
166 struct drm_panel *panel; 166 struct drm_panel *panel;
167}; 167};
168 168
169struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
169struct drm_panel *sun4i_tcon_find_panel(struct device_node *node); 170struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
170 171
171/* Global Control */ 172/* Global Control */