diff options
Diffstat (limited to 'drivers/gpu/drm/imx/imx-ldb.c')
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index a58eee59550a..beff793bb717 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | 25 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> |
26 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
27 | #include <linux/of_graph.h> | 27 | #include <linux/of_graph.h> |
28 | #include <video/of_display_timing.h> | ||
28 | #include <video/of_videomode.h> | 29 | #include <video/of_videomode.h> |
29 | #include <linux/regmap.h> | 30 | #include <linux/regmap.h> |
30 | #include <linux/videodev2.h> | 31 | #include <linux/videodev2.h> |
@@ -59,6 +60,7 @@ struct imx_ldb_channel { | |||
59 | struct drm_encoder encoder; | 60 | struct drm_encoder encoder; |
60 | struct drm_panel *panel; | 61 | struct drm_panel *panel; |
61 | struct device_node *child; | 62 | struct device_node *child; |
63 | struct i2c_adapter *ddc; | ||
62 | int chno; | 64 | int chno; |
63 | void *edid; | 65 | void *edid; |
64 | int edid_len; | 66 | int edid_len; |
@@ -107,6 +109,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) | |||
107 | return num_modes; | 109 | return num_modes; |
108 | } | 110 | } |
109 | 111 | ||
112 | if (!imx_ldb_ch->edid && imx_ldb_ch->ddc) | ||
113 | imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); | ||
114 | |||
110 | if (imx_ldb_ch->edid) { | 115 | if (imx_ldb_ch->edid) { |
111 | drm_mode_connector_update_edid_property(connector, | 116 | drm_mode_connector_update_edid_property(connector, |
112 | imx_ldb_ch->edid); | 117 | imx_ldb_ch->edid); |
@@ -553,7 +558,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
553 | 558 | ||
554 | for_each_child_of_node(np, child) { | 559 | for_each_child_of_node(np, child) { |
555 | struct imx_ldb_channel *channel; | 560 | struct imx_ldb_channel *channel; |
556 | struct device_node *port; | 561 | struct device_node *ddc_node; |
562 | struct device_node *ep; | ||
557 | 563 | ||
558 | ret = of_property_read_u32(child, "reg", &i); | 564 | ret = of_property_read_u32(child, "reg", &i); |
559 | if (ret || i < 0 || i > 1) | 565 | if (ret || i < 0 || i > 1) |
@@ -576,33 +582,54 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
576 | * The output port is port@4 with an external 4-port mux or | 582 | * The output port is port@4 with an external 4-port mux or |
577 | * port@2 with the internal 2-port mux. | 583 | * port@2 with the internal 2-port mux. |
578 | */ | 584 | */ |
579 | port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); | 585 | ep = of_graph_get_endpoint_by_regs(child, |
580 | if (port) { | 586 | imx_ldb->lvds_mux ? 4 : 2, |
581 | struct device_node *endpoint, *remote; | 587 | -1); |
582 | 588 | if (ep) { | |
583 | endpoint = of_get_child_by_name(port, "endpoint"); | 589 | struct device_node *remote; |
584 | if (endpoint) { | 590 | |
585 | remote = of_graph_get_remote_port_parent(endpoint); | 591 | remote = of_graph_get_remote_port_parent(ep); |
586 | if (remote) | 592 | of_node_put(ep); |
587 | channel->panel = of_drm_find_panel(remote); | 593 | if (remote) |
588 | else | 594 | channel->panel = of_drm_find_panel(remote); |
589 | return -EPROBE_DEFER; | 595 | else |
590 | if (!channel->panel) { | 596 | return -EPROBE_DEFER; |
591 | dev_err(dev, "panel not found: %s\n", | 597 | of_node_put(remote); |
592 | remote->full_name); | 598 | if (!channel->panel) { |
593 | return -EPROBE_DEFER; | 599 | dev_err(dev, "panel not found: %s\n", |
594 | } | 600 | remote->full_name); |
601 | return -EPROBE_DEFER; | ||
595 | } | 602 | } |
596 | } | 603 | } |
597 | 604 | ||
598 | edidp = of_get_property(child, "edid", &channel->edid_len); | 605 | ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); |
599 | if (edidp) { | 606 | if (ddc_node) { |
600 | channel->edid = kmemdup(edidp, channel->edid_len, | 607 | channel->ddc = of_find_i2c_adapter_by_node(ddc_node); |
601 | GFP_KERNEL); | 608 | of_node_put(ddc_node); |
602 | } else if (!channel->panel) { | 609 | if (!channel->ddc) { |
603 | ret = of_get_drm_display_mode(child, &channel->mode, 0); | 610 | dev_warn(dev, "failed to get ddc i2c adapter\n"); |
604 | if (!ret) | 611 | return -EPROBE_DEFER; |
605 | channel->mode_valid = 1; | 612 | } |
613 | } | ||
614 | |||
615 | if (!channel->ddc) { | ||
616 | /* if no DDC available, fallback to hardcoded EDID */ | ||
617 | dev_dbg(dev, "no ddc available\n"); | ||
618 | |||
619 | edidp = of_get_property(child, "edid", | ||
620 | &channel->edid_len); | ||
621 | if (edidp) { | ||
622 | channel->edid = kmemdup(edidp, | ||
623 | channel->edid_len, | ||
624 | GFP_KERNEL); | ||
625 | } else if (!channel->panel) { | ||
626 | /* fallback to display-timings node */ | ||
627 | ret = of_get_drm_display_mode(child, | ||
628 | &channel->mode, | ||
629 | OF_USE_NATIVE_MODE); | ||
630 | if (!ret) | ||
631 | channel->mode_valid = 1; | ||
632 | } | ||
606 | } | 633 | } |
607 | 634 | ||
608 | channel->bus_format = of_get_bus_format(dev, child); | 635 | channel->bus_format = of_get_bus_format(dev, child); |
@@ -647,6 +674,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, | |||
647 | channel->encoder.funcs->destroy(&channel->encoder); | 674 | channel->encoder.funcs->destroy(&channel->encoder); |
648 | 675 | ||
649 | kfree(channel->edid); | 676 | kfree(channel->edid); |
677 | i2c_put_adapter(channel->ddc); | ||
650 | } | 678 | } |
651 | } | 679 | } |
652 | 680 | ||