Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+90 -21
+43 -19
Documentation/devicetree/bindings/drm/imx/ldb.txt
··· 44 44 LVDS Channel 45 45 ============ 46 46 47 - Each LVDS Channel has to contain a display-timings node that describes the 48 - video timings for the connected LVDS display. For detailed information, also 49 - have a look at Documentation/devicetree/bindings/video/display-timing.txt. 47 + Each LVDS Channel has to contain either an of graph link to a panel device node 48 + or a display-timings node that describes the video timings for the connected 49 + LVDS display as well as the fsl,data-mapping and fsl,data-width properties. 50 50 51 51 Required properties: 52 52 - reg : should be <0> or <1> 53 + - port: Input and output port nodes with endpoint definitions as defined in 54 + Documentation/devicetree/bindings/graph.txt. 55 + On i.MX5, the internal two-input-multiplexer is used. Due to hardware 56 + limitations, only one input port (port@[0,1]) can be used for each channel 57 + (lvds-channel@[0,1], respectively). 58 + On i.MX6, there should be four input ports (port@[0-3]) that correspond 59 + to the four LVDS multiplexer inputs. 60 + A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected 61 + to a panel input port. Optionally, the output port can be left out if 62 + display-timings are used instead. 63 + 64 + Optional properties (required if display-timings are used): 65 + - display-timings : A node that describes the display timings as defined in 66 + Documentation/devicetree/bindings/video/display-timing.txt. 53 67 - fsl,data-mapping : should be "spwg" or "jeida" 54 68 This describes how the color bits are laid out in the 55 69 serialized LVDS signal. 56 70 - fsl,data-width : should be <18> or <24> 57 - - port: A port node with endpoint definitions as defined in 58 - Documentation/devicetree/bindings/media/video-interfaces.txt. 59 - On i.MX5, the internal two-input-multiplexer is used. 60 - Due to hardware limitations, only one port (port@[0,1]) 61 - can be used for each channel (lvds-channel@[0,1], respectively) 62 - On i.MX6, there should be four ports (port@[0-3]) that correspond 63 - to the four LVDS multiplexer inputs. 64 71 65 72 example: 66 73 ··· 80 73 #size-cells = <0>; 81 74 compatible = "fsl,imx53-ldb"; 82 75 gpr = <&gpr>; 83 - clocks = <&clks 122>, <&clks 120>, 84 - <&clks 115>, <&clks 116>, 85 - <&clks 123>, <&clks 85>; 76 + clocks = <&clks IMX5_CLK_LDB_DI0_SEL>, 77 + <&clks IMX5_CLK_LDB_DI1_SEL>, 78 + <&clks IMX5_CLK_IPU_DI0_SEL>, 79 + <&clks IMX5_CLK_IPU_DI1_SEL>, 80 + <&clks IMX5_CLK_LDB_DI0_GATE>, 81 + <&clks IMX5_CLK_LDB_DI1_GATE>; 86 82 clock-names = "di0_pll", "di1_pll", 87 83 "di0_sel", "di1_sel", 88 84 "di0", "di1"; 89 85 86 + /* Using an of-graph endpoint link to connect the panel */ 90 87 lvds-channel@0 { 91 88 #address-cells = <1>; 92 89 #size-cells = <0>; 93 90 reg = <0>; 94 - fsl,data-mapping = "spwg"; 95 - fsl,data-width = <24>; 96 - 97 - display-timings { 98 - /* ... */ 99 - }; 100 91 101 92 port@0 { 102 93 reg = <0>; ··· 103 98 remote-endpoint = <&ipu_di0_lvds0>; 104 99 }; 105 100 }; 101 + 102 + port@2 { 103 + reg = <2>; 104 + 105 + lvds0_out: endpoint { 106 + remote-endpoint = <&panel_in>; 107 + }; 108 + }; 106 109 }; 107 110 111 + /* Using display-timings and fsl,data-mapping/width instead */ 108 112 lvds-channel@1 { 109 113 #address-cells = <1>; 110 114 #size-cells = <0>; ··· 131 117 lvds1_in: endpoint { 132 118 remote-endpoint = <&ipu_di1_lvds1>; 133 119 }; 120 + }; 121 + }; 122 + }; 123 + 124 + panel: lvds-panel { 125 + /* ... */ 126 + 127 + port { 128 + panel_in: endpoint { 129 + remote-endpoint = <&lvds0_out>; 134 130 }; 135 131 }; 136 132 };
+1
drivers/gpu/drm/imx/Kconfig
··· 36 36 config DRM_IMX_LDB 37 37 tristate "Support for LVDS displays" 38 38 depends on DRM_IMX && MFD_SYSCON 39 + select DRM_PANEL 39 40 help 40 41 Choose this to enable the internal LVDS Display Bridge (LDB) 41 42 found on i.MX53 and i.MX6 processors.
+46 -2
drivers/gpu/drm/imx/imx-ldb.c
··· 19 19 #include <drm/drmP.h> 20 20 #include <drm/drm_fb_helper.h> 21 21 #include <drm/drm_crtc_helper.h> 22 + #include <drm/drm_panel.h> 22 23 #include <linux/mfd/syscon.h> 23 24 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 24 - #include <linux/of_address.h> 25 25 #include <linux/of_device.h> 26 + #include <linux/of_graph.h> 26 27 #include <video/of_videomode.h> 27 28 #include <linux/regmap.h> 28 29 #include <linux/videodev2.h> ··· 56 55 struct imx_ldb *ldb; 57 56 struct drm_connector connector; 58 57 struct drm_encoder encoder; 58 + struct drm_panel *panel; 59 59 struct device_node *child; 60 60 int chno; 61 61 void *edid; ··· 92 90 { 93 91 struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); 94 92 int num_modes = 0; 93 + 94 + if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && 95 + imx_ldb_ch->panel->funcs->get_modes) { 96 + num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); 97 + if (num_modes > 0) 98 + return num_modes; 99 + } 95 100 96 101 if (imx_ldb_ch->edid) { 97 102 drm_mode_connector_update_edid_property(connector, ··· 199 190 int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; 200 191 int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); 201 192 193 + drm_panel_prepare(imx_ldb_ch->panel); 194 + 202 195 if (dual) { 203 196 clk_prepare_enable(ldb->clk[0]); 204 197 clk_prepare_enable(ldb->clk[1]); ··· 234 223 } 235 224 236 225 regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); 226 + 227 + drm_panel_enable(imx_ldb_ch->panel); 237 228 } 238 229 239 230 static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, ··· 300 287 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) 301 288 return; 302 289 290 + drm_panel_disable(imx_ldb_ch->panel); 291 + 303 292 if (imx_ldb_ch == &ldb->channel[0]) 304 293 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 305 294 else if (imx_ldb_ch == &ldb->channel[1]) ··· 313 298 clk_disable_unprepare(ldb->clk[0]); 314 299 clk_disable_unprepare(ldb->clk[1]); 315 300 } 301 + 302 + drm_panel_unprepare(imx_ldb_ch->panel); 316 303 } 317 304 318 305 static struct drm_connector_funcs imx_ldb_connector_funcs = { ··· 387 370 &imx_ldb_connector_helper_funcs); 388 371 drm_connector_init(drm, &imx_ldb_ch->connector, 389 372 &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); 373 + 374 + if (imx_ldb_ch->panel) 375 + drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); 390 376 391 377 drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, 392 378 &imx_ldb_ch->encoder); ··· 505 485 506 486 for_each_child_of_node(np, child) { 507 487 struct imx_ldb_channel *channel; 488 + struct device_node *port; 508 489 509 490 ret = of_property_read_u32(child, "reg", &i); 510 491 if (ret || i < 0 || i > 1) ··· 524 503 channel->chno = i; 525 504 channel->child = child; 526 505 506 + /* 507 + * The output port is port@4 with an external 4-port mux or 508 + * port@2 with the internal 2-port mux. 509 + */ 510 + port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); 511 + if (port) { 512 + struct device_node *endpoint, *remote; 513 + 514 + endpoint = of_get_child_by_name(port, "endpoint"); 515 + if (endpoint) { 516 + remote = of_graph_get_remote_port_parent(endpoint); 517 + if (remote) 518 + channel->panel = of_drm_find_panel(remote); 519 + else 520 + return -EPROBE_DEFER; 521 + if (!channel->panel) { 522 + dev_err(dev, "panel not found: %s\n", 523 + remote->full_name); 524 + return -EPROBE_DEFER; 525 + } 526 + } 527 + } 528 + 527 529 edidp = of_get_property(child, "edid", &channel->edid_len); 528 530 if (edidp) { 529 531 channel->edid = kmemdup(edidp, channel->edid_len, 530 532 GFP_KERNEL); 531 - } else { 533 + } else if (!channel->panel) { 532 534 ret = of_get_drm_display_mode(child, &channel->mode, 0); 533 535 if (!ret) 534 536 channel->mode_valid = 1;