diff options
author | Peter Senna Tschudin <peter.senna@collabora.com> | 2016-08-04 18:36:58 -0400 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2016-08-11 05:34:22 -0400 |
commit | dc80d7038883feca2abd08975165bc0d83c84762 (patch) | |
tree | 7985a8fedbabcf37c8c8ed964ba4357b1291fcb3 /drivers/gpu/drm/imx/imx-ldb.c | |
parent | 3a2ad5028cf2cc3067c7d8bf7fab68d9c1c3c0e8 (diff) |
drm/imx-ldb: Add support to drm-bridge
Add support to attach a drm_bridge to imx-ldb in addition to
existing support to attach a LVDS panel.
This patch does a simple code refactoring by moving code
from for_each_child_of_node iterator to a new function named
imx_ldb_panel_ddc(). This was necessary to allow the panel ddc
code to run only when the imx_ldb is not attached to a bridge.
Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Thierry Reding <treding@nvidia.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/drm/imx/imx-ldb.c')
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 7b588b44b845..4eed3a6addad 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c | |||
@@ -57,7 +57,11 @@ struct imx_ldb_channel { | |||
57 | struct imx_ldb *ldb; | 57 | struct imx_ldb *ldb; |
58 | struct drm_connector connector; | 58 | struct drm_connector connector; |
59 | struct drm_encoder encoder; | 59 | struct drm_encoder encoder; |
60 | |||
61 | /* Defines what is connected to the ldb, only one at a time */ | ||
60 | struct drm_panel *panel; | 62 | struct drm_panel *panel; |
63 | struct drm_bridge *bridge; | ||
64 | |||
61 | struct device_node *child; | 65 | struct device_node *child; |
62 | struct i2c_adapter *ddc; | 66 | struct i2c_adapter *ddc; |
63 | int chno; | 67 | int chno; |
@@ -468,10 +472,30 @@ static int imx_ldb_register(struct drm_device *drm, | |||
468 | drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, | 472 | drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, |
469 | DRM_MODE_ENCODER_LVDS, NULL); | 473 | DRM_MODE_ENCODER_LVDS, NULL); |
470 | 474 | ||
471 | drm_connector_helper_add(&imx_ldb_ch->connector, | 475 | if (imx_ldb_ch->bridge) { |
472 | &imx_ldb_connector_helper_funcs); | 476 | imx_ldb_ch->bridge->encoder = encoder; |
473 | drm_connector_init(drm, &imx_ldb_ch->connector, | 477 | |
474 | &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | 478 | imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge; |
479 | ret = drm_bridge_attach(drm, imx_ldb_ch->bridge); | ||
480 | if (ret) { | ||
481 | DRM_ERROR("Failed to initialize bridge with drm\n"); | ||
482 | return ret; | ||
483 | } | ||
484 | } else { | ||
485 | /* | ||
486 | * We want to add the connector whenever there is no bridge | ||
487 | * that brings its own, not only when there is a panel. For | ||
488 | * historical reasons, the ldb driver can also work without | ||
489 | * a panel. | ||
490 | */ | ||
491 | drm_connector_helper_add(&imx_ldb_ch->connector, | ||
492 | &imx_ldb_connector_helper_funcs); | ||
493 | drm_connector_init(drm, &imx_ldb_ch->connector, | ||
494 | &imx_ldb_connector_funcs, | ||
495 | DRM_MODE_CONNECTOR_LVDS); | ||
496 | drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, | ||
497 | encoder); | ||
498 | } | ||
475 | 499 | ||
476 | if (imx_ldb_ch->panel) { | 500 | if (imx_ldb_ch->panel) { |
477 | ret = drm_panel_attach(imx_ldb_ch->panel, | 501 | ret = drm_panel_attach(imx_ldb_ch->panel, |
@@ -480,8 +504,6 @@ static int imx_ldb_register(struct drm_device *drm, | |||
480 | return ret; | 504 | return ret; |
481 | } | 505 | } |
482 | 506 | ||
483 | drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder); | ||
484 | |||
485 | return 0; | 507 | return 0; |
486 | } | 508 | } |
487 | 509 | ||
@@ -550,6 +572,46 @@ static const struct of_device_id imx_ldb_dt_ids[] = { | |||
550 | }; | 572 | }; |
551 | MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); | 573 | MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); |
552 | 574 | ||
575 | static int imx_ldb_panel_ddc(struct device *dev, | ||
576 | struct imx_ldb_channel *channel, struct device_node *child) | ||
577 | { | ||
578 | struct device_node *ddc_node; | ||
579 | const u8 *edidp; | ||
580 | int ret; | ||
581 | |||
582 | ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); | ||
583 | if (ddc_node) { | ||
584 | channel->ddc = of_find_i2c_adapter_by_node(ddc_node); | ||
585 | of_node_put(ddc_node); | ||
586 | if (!channel->ddc) { | ||
587 | dev_warn(dev, "failed to get ddc i2c adapter\n"); | ||
588 | return -EPROBE_DEFER; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | if (!channel->ddc) { | ||
593 | /* if no DDC available, fallback to hardcoded EDID */ | ||
594 | dev_dbg(dev, "no ddc available\n"); | ||
595 | |||
596 | edidp = of_get_property(child, "edid", | ||
597 | &channel->edid_len); | ||
598 | if (edidp) { | ||
599 | channel->edid = kmemdup(edidp, | ||
600 | channel->edid_len, | ||
601 | GFP_KERNEL); | ||
602 | } else if (!channel->panel) { | ||
603 | /* fallback to display-timings node */ | ||
604 | ret = of_get_drm_display_mode(child, | ||
605 | &channel->mode, | ||
606 | &channel->bus_flags, | ||
607 | OF_USE_NATIVE_MODE); | ||
608 | if (!ret) | ||
609 | channel->mode_valid = 1; | ||
610 | } | ||
611 | } | ||
612 | return 0; | ||
613 | } | ||
614 | |||
553 | static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | 615 | static int imx_ldb_bind(struct device *dev, struct device *master, void *data) |
554 | { | 616 | { |
555 | struct drm_device *drm = data; | 617 | struct drm_device *drm = data; |
@@ -557,7 +619,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
557 | const struct of_device_id *of_id = | 619 | const struct of_device_id *of_id = |
558 | of_match_device(imx_ldb_dt_ids, dev); | 620 | of_match_device(imx_ldb_dt_ids, dev); |
559 | struct device_node *child; | 621 | struct device_node *child; |
560 | const u8 *edidp; | ||
561 | struct imx_ldb *imx_ldb; | 622 | struct imx_ldb *imx_ldb; |
562 | int dual; | 623 | int dual; |
563 | int ret; | 624 | int ret; |
@@ -607,7 +668,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
607 | 668 | ||
608 | for_each_child_of_node(np, child) { | 669 | for_each_child_of_node(np, child) { |
609 | struct imx_ldb_channel *channel; | 670 | struct imx_ldb_channel *channel; |
610 | struct device_node *ddc_node; | ||
611 | struct device_node *ep; | 671 | struct device_node *ep; |
612 | int bus_format; | 672 | int bus_format; |
613 | 673 | ||
@@ -640,47 +700,25 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
640 | 700 | ||
641 | remote = of_graph_get_remote_port_parent(ep); | 701 | remote = of_graph_get_remote_port_parent(ep); |
642 | of_node_put(ep); | 702 | of_node_put(ep); |
643 | if (remote) | 703 | if (remote) { |
644 | channel->panel = of_drm_find_panel(remote); | 704 | channel->panel = of_drm_find_panel(remote); |
645 | else | 705 | channel->bridge = of_drm_find_bridge(remote); |
706 | } else | ||
646 | return -EPROBE_DEFER; | 707 | return -EPROBE_DEFER; |
647 | of_node_put(remote); | 708 | of_node_put(remote); |
648 | if (!channel->panel) { | ||
649 | dev_err(dev, "panel not found: %s\n", | ||
650 | remote->full_name); | ||
651 | return -EPROBE_DEFER; | ||
652 | } | ||
653 | } | ||
654 | 709 | ||
655 | ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); | 710 | if (!channel->panel && !channel->bridge) { |
656 | if (ddc_node) { | 711 | dev_err(dev, "panel/bridge not found: %s\n", |
657 | channel->ddc = of_find_i2c_adapter_by_node(ddc_node); | 712 | remote->full_name); |
658 | of_node_put(ddc_node); | ||
659 | if (!channel->ddc) { | ||
660 | dev_warn(dev, "failed to get ddc i2c adapter\n"); | ||
661 | return -EPROBE_DEFER; | 713 | return -EPROBE_DEFER; |
662 | } | 714 | } |
663 | } | 715 | } |
664 | 716 | ||
665 | if (!channel->ddc) { | 717 | /* panel ddc only if there is no bridge */ |
666 | /* if no DDC available, fallback to hardcoded EDID */ | 718 | if (!channel->bridge) { |
667 | dev_dbg(dev, "no ddc available\n"); | 719 | ret = imx_ldb_panel_ddc(dev, channel, child); |
668 | 720 | if (ret) | |
669 | edidp = of_get_property(child, "edid", | 721 | return ret; |
670 | &channel->edid_len); | ||
671 | if (edidp) { | ||
672 | channel->edid = kmemdup(edidp, | ||
673 | channel->edid_len, | ||
674 | GFP_KERNEL); | ||
675 | } else if (!channel->panel) { | ||
676 | /* fallback to display-timings node */ | ||
677 | ret = of_get_drm_display_mode(child, | ||
678 | &channel->mode, | ||
679 | &channel->bus_flags, | ||
680 | OF_USE_NATIVE_MODE); | ||
681 | if (!ret) | ||
682 | channel->mode_valid = 1; | ||
683 | } | ||
684 | } | 722 | } |
685 | 723 | ||
686 | bus_format = of_get_bus_format(dev, child); | 724 | bus_format = of_get_bus_format(dev, child); |