diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2016-04-11 06:16:33 -0400 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2016-08-22 09:34:18 -0400 |
commit | 894f5a9f4b4aaf154fce121d80199a2e2146d6d1 (patch) | |
tree | 8600f72ea7a22ec8a62fa1ad4a24317a8a0fe23c | |
parent | a8444c7ee2c02b567731a6edcd5d328f85aac1b1 (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.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_rgb.c | 58 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 |
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 | ||
170 | static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder, | 180 | static 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 | ||
435 | struct 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", ®); | ||
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 | |||
435 | static int sun4i_tcon_bind(struct device *dev, struct device *master, | 469 | static 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 = { | |||
514 | static int sun4i_tcon_probe(struct platform_device *pdev) | 548 | static 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 | ||
169 | struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); | ||
169 | struct drm_panel *sun4i_tcon_find_panel(struct device_node *node); | 170 | struct drm_panel *sun4i_tcon_find_panel(struct device_node *node); |
170 | 171 | ||
171 | /* Global Control */ | 172 | /* Global Control */ |