diff options
Diffstat (limited to 'drivers/gpu/drm/imx/imx-ldb.c')
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 48 |
1 files changed, 46 insertions, 2 deletions
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 | ||
228 | static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, | 241 | static 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 | ||
303 | static struct drm_connector_funcs imx_ldb_connector_funcs = { | 320 | static 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; |