aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2014-03-06 08:54:39 -0500
committerPhilipp Zabel <p.zabel@pengutronix.de>2015-03-31 06:44:49 -0400
commit751e2676ee9272a0fbde6566afde33c1106d7da1 (patch)
treedb63630644c046470a78af04a0ee81d5a46d5512 /drivers/gpu/drm
parent2872c8072aae65fa55cafea50e73d69d423df168 (diff)
drm/imx: imx-ldb: add drm_panel support
This patch allows to optionally attach the lvds-channel to a panel supported by a drm_panel driver using of-graph bindings, instead of supplying the modes via display-timings in the device tree. This depends on of_graph_get_port_by_id and uses the OF graph to link the optional DRM panel to the LDB lvds-channel. The output port number is 1 on devices without the 4-port input multiplexer (i.MX5) and 4 on devices with the mux (i.MX6). Before: ldb { ... lvds-channel@0 { ... display-timings { native-timing = <&timing1>; timing1: etm0700g0dh6 { hactive = <800>; vactive = <480>; clock-frequency = <33260000>; hsync-len = <128>; hback-porch = <88>; hfront-porch = <40>; vsync-len = <2>; vback-porch = <33>; vfront-porch = <10>; hsync-active = <0>; vsync-active = <0>; ... }; }; ... }; }; After: ldb { ... lvds-channel@0 { ... port@4 { reg = <4>; lvds_out: endpoint { remote_endpoint = <&panel_in>; }; }; }; }; panel { compatible = "edt,etm0700g0dh6", "simple-panel"; ... port { panel_in: endpoint { remote-endpoint = <&lvds_out>; }; }; }; [Fixed build error due to missing select on DRM_PANEL --rmk] Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/imx/Kconfig1
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c48
2 files changed, 47 insertions, 2 deletions
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 33cdddf26684..2b81a417cf29 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -36,6 +36,7 @@ config DRM_IMX_TVE
36config DRM_IMX_LDB 36config DRM_IMX_LDB
37 tristate "Support for LVDS displays" 37 tristate "Support for LVDS displays"
38 depends on DRM_IMX && MFD_SYSCON 38 depends on DRM_IMX && MFD_SYSCON
39 select DRM_PANEL
39 help 40 help
40 Choose this to enable the internal LVDS Display Bridge (LDB) 41 Choose this to enable the internal LVDS Display Bridge (LDB)
41 found on i.MX53 and i.MX6 processors. 42 found on i.MX53 and i.MX6 processors.
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index cd062b11a102..4286399590c3 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -19,10 +19,11 @@
19#include <drm/drmP.h> 19#include <drm/drmP.h>
20#include <drm/drm_fb_helper.h> 20#include <drm/drm_fb_helper.h>
21#include <drm/drm_crtc_helper.h> 21#include <drm/drm_crtc_helper.h>
22#include <drm/drm_panel.h>
22#include <linux/mfd/syscon.h> 23#include <linux/mfd/syscon.h>
23#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 24#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
24#include <linux/of_address.h>
25#include <linux/of_device.h> 25#include <linux/of_device.h>
26#include <linux/of_graph.h>
26#include <video/of_videomode.h> 27#include <video/of_videomode.h>
27#include <linux/regmap.h> 28#include <linux/regmap.h>
28#include <linux/videodev2.h> 29#include <linux/videodev2.h>
@@ -55,6 +56,7 @@ struct imx_ldb_channel {
55 struct imx_ldb *ldb; 56 struct imx_ldb *ldb;
56 struct drm_connector connector; 57 struct drm_connector connector;
57 struct drm_encoder encoder; 58 struct drm_encoder encoder;
59 struct drm_panel *panel;
58 struct device_node *child; 60 struct device_node *child;
59 int chno; 61 int chno;
60 void *edid; 62 void *edid;
@@ -91,6 +93,13 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
91 struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); 93 struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
92 int num_modes = 0; 94 int num_modes = 0;
93 95
96 if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
97 imx_ldb_ch->panel->funcs->get_modes) {
98 num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
99 if (num_modes > 0)
100 return num_modes;
101 }
102
94 if (imx_ldb_ch->edid) { 103 if (imx_ldb_ch->edid) {
95 drm_mode_connector_update_edid_property(connector, 104 drm_mode_connector_update_edid_property(connector,
96 imx_ldb_ch->edid); 105 imx_ldb_ch->edid);
@@ -190,6 +199,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
190 int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; 199 int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
191 int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); 200 int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
192 201
202 drm_panel_prepare(imx_ldb_ch->panel);
203
193 if (dual) { 204 if (dual) {
194 clk_prepare_enable(ldb->clk[0]); 205 clk_prepare_enable(ldb->clk[0]);
195 clk_prepare_enable(ldb->clk[1]); 206 clk_prepare_enable(ldb->clk[1]);
@@ -223,6 +234,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
223 } 234 }
224 235
225 regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); 236 regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
237
238 drm_panel_enable(imx_ldb_ch->panel);
226} 239}
227 240
228static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, 241static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
@@ -287,6 +300,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
287 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) 300 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
288 return; 301 return;
289 302
303 drm_panel_disable(imx_ldb_ch->panel);
304
290 if (imx_ldb_ch == &ldb->channel[0]) 305 if (imx_ldb_ch == &ldb->channel[0])
291 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 306 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
292 else if (imx_ldb_ch == &ldb->channel[1]) 307 else if (imx_ldb_ch == &ldb->channel[1])
@@ -298,6 +313,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
298 clk_disable_unprepare(ldb->clk[0]); 313 clk_disable_unprepare(ldb->clk[0]);
299 clk_disable_unprepare(ldb->clk[1]); 314 clk_disable_unprepare(ldb->clk[1]);
300 } 315 }
316
317 drm_panel_unprepare(imx_ldb_ch->panel);
301} 318}
302 319
303static struct drm_connector_funcs imx_ldb_connector_funcs = { 320static struct drm_connector_funcs imx_ldb_connector_funcs = {
@@ -371,6 +388,9 @@ static int imx_ldb_register(struct drm_device *drm,
371 drm_connector_init(drm, &imx_ldb_ch->connector, 388 drm_connector_init(drm, &imx_ldb_ch->connector,
372 &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); 389 &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
373 390
391 if (imx_ldb_ch->panel)
392 drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
393
374 drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, 394 drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
375 &imx_ldb_ch->encoder); 395 &imx_ldb_ch->encoder);
376 396
@@ -485,6 +505,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
485 505
486 for_each_child_of_node(np, child) { 506 for_each_child_of_node(np, child) {
487 struct imx_ldb_channel *channel; 507 struct imx_ldb_channel *channel;
508 struct device_node *port;
488 509
489 ret = of_property_read_u32(child, "reg", &i); 510 ret = of_property_read_u32(child, "reg", &i);
490 if (ret || i < 0 || i > 1) 511 if (ret || i < 0 || i > 1)
@@ -503,11 +524,34 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
503 channel->chno = i; 524 channel->chno = i;
504 channel->child = child; 525 channel->child = child;
505 526
527 /*
528 * The output port is port@4 with an external 4-port mux or
529 * port@2 with the internal 2-port mux.
530 */
531 port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2);
532 if (port) {
533 struct device_node *endpoint, *remote;
534
535 endpoint = of_get_child_by_name(port, "endpoint");
536 if (endpoint) {
537 remote = of_graph_get_remote_port_parent(endpoint);
538 if (remote)
539 channel->panel = of_drm_find_panel(remote);
540 else
541 return -EPROBE_DEFER;
542 if (!channel->panel) {
543 dev_err(dev, "panel not found: %s\n",
544 remote->full_name);
545 return -EPROBE_DEFER;
546 }
547 }
548 }
549
506 edidp = of_get_property(child, "edid", &channel->edid_len); 550 edidp = of_get_property(child, "edid", &channel->edid_len);
507 if (edidp) { 551 if (edidp) {
508 channel->edid = kmemdup(edidp, channel->edid_len, 552 channel->edid = kmemdup(edidp, channel->edid_len,
509 GFP_KERNEL); 553 GFP_KERNEL);
510 } else { 554 } else if (!channel->panel) {
511 ret = of_get_drm_display_mode(child, &channel->mode, 0); 555 ret = of_get_drm_display_mode(child, &channel->mode, 0);
512 if (!ret) 556 if (!ret)
513 channel->mode_valid = 1; 557 channel->mode_valid = 1;