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 | ||
