1 // SPDX-License-Identifier: GPL-2.0+
3 * i.MX drm driver - parallel display implementation
5 * Copyright (C) 2012 Sascha Hauer, Pengutronix
8 #include <linux/component.h>
9 #include <linux/media-bus-format.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/videodev2.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_bridge.h>
17 #include <drm/drm_bridge_connector.h>
18 #include <drm/drm_managed.h>
19 #include <drm/drm_of.h>
20 #include <drm/drm_probe_helper.h>
21 #include <drm/drm_simple_kms_helper.h>
22 #include <drm/bridge/imx.h>
26 struct imx_parallel_display_encoder
{
27 struct drm_encoder encoder
;
28 struct drm_bridge bridge
;
29 struct imx_parallel_display
*pd
;
32 struct imx_parallel_display
{
35 struct drm_bridge
*next_bridge
;
38 static inline struct imx_parallel_display
*bridge_to_imxpd(struct drm_bridge
*b
)
40 return container_of(b
, struct imx_parallel_display_encoder
, bridge
)->pd
;
43 static const u32 imx_pd_bus_fmts
[] = {
44 MEDIA_BUS_FMT_RGB888_1X24
,
45 MEDIA_BUS_FMT_BGR888_1X24
,
46 MEDIA_BUS_FMT_GBR888_1X24
,
47 MEDIA_BUS_FMT_RGB666_1X18
,
48 MEDIA_BUS_FMT_RGB666_1X24_CPADHI
,
49 MEDIA_BUS_FMT_RGB565_1X16
,
53 imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge
*bridge
,
54 struct drm_bridge_state
*bridge_state
,
55 struct drm_crtc_state
*crtc_state
,
56 struct drm_connector_state
*conn_state
,
57 unsigned int *num_output_fmts
)
59 struct drm_display_info
*di
= &conn_state
->connector
->display_info
;
60 struct imx_parallel_display
*imxpd
= bridge_to_imxpd(bridge
);
63 if (!imxpd
->bus_format
&& !di
->num_bus_formats
) {
64 *num_output_fmts
= ARRAY_SIZE(imx_pd_bus_fmts
);
65 return kmemdup(imx_pd_bus_fmts
, sizeof(imx_pd_bus_fmts
),
70 output_fmts
= kmalloc(sizeof(*output_fmts
), GFP_KERNEL
);
74 if (!imxpd
->bus_format
&& di
->num_bus_formats
)
75 output_fmts
[0] = di
->bus_formats
[0];
77 output_fmts
[0] = imxpd
->bus_format
;
82 static bool imx_pd_format_supported(u32 output_fmt
)
86 for (i
= 0; i
< ARRAY_SIZE(imx_pd_bus_fmts
); i
++) {
87 if (imx_pd_bus_fmts
[i
] == output_fmt
)
95 imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge
*bridge
,
96 struct drm_bridge_state
*bridge_state
,
97 struct drm_crtc_state
*crtc_state
,
98 struct drm_connector_state
*conn_state
,
100 unsigned int *num_input_fmts
)
102 struct imx_parallel_display
*imxpd
= bridge_to_imxpd(bridge
);
106 * If the next bridge does not support bus format negotiation, let's
107 * use the static bus format definition (imxpd->bus_format) if it's
108 * specified, RGB888 when it's not.
110 if (output_fmt
== MEDIA_BUS_FMT_FIXED
)
111 output_fmt
= imxpd
->bus_format
? : MEDIA_BUS_FMT_RGB888_1X24
;
113 /* Now make sure the requested output format is supported. */
114 if ((imxpd
->bus_format
&& imxpd
->bus_format
!= output_fmt
) ||
115 !imx_pd_format_supported(output_fmt
)) {
121 input_fmts
= kmalloc(sizeof(*input_fmts
), GFP_KERNEL
);
125 input_fmts
[0] = output_fmt
;
129 static int imx_pd_bridge_atomic_check(struct drm_bridge
*bridge
,
130 struct drm_bridge_state
*bridge_state
,
131 struct drm_crtc_state
*crtc_state
,
132 struct drm_connector_state
*conn_state
)
134 struct imx_crtc_state
*imx_crtc_state
= to_imx_crtc_state(crtc_state
);
135 struct drm_display_info
*di
= &conn_state
->connector
->display_info
;
136 struct drm_bridge_state
*next_bridge_state
= NULL
;
137 struct drm_bridge
*next_bridge
;
138 u32 bus_flags
, bus_fmt
;
140 next_bridge
= drm_bridge_get_next_bridge(bridge
);
142 next_bridge_state
= drm_atomic_get_new_bridge_state(crtc_state
->state
,
145 if (next_bridge_state
)
146 bus_flags
= next_bridge_state
->input_bus_cfg
.flags
;
148 bus_flags
= di
->bus_flags
;
150 bus_fmt
= bridge_state
->input_bus_cfg
.format
;
151 if (!imx_pd_format_supported(bus_fmt
))
154 bridge_state
->output_bus_cfg
.flags
= bus_flags
;
155 bridge_state
->input_bus_cfg
.flags
= bus_flags
;
156 imx_crtc_state
->bus_flags
= bus_flags
;
157 imx_crtc_state
->bus_format
= bridge_state
->input_bus_cfg
.format
;
158 imx_crtc_state
->di_hsync_pin
= 2;
159 imx_crtc_state
->di_vsync_pin
= 3;
164 static int imx_pd_bridge_attach(struct drm_bridge
*bridge
,
165 enum drm_bridge_attach_flags flags
)
167 struct imx_parallel_display
*imxpd
= bridge_to_imxpd(bridge
);
169 return drm_bridge_attach(bridge
->encoder
, imxpd
->next_bridge
, bridge
, flags
);
172 static const struct drm_bridge_funcs imx_pd_bridge_funcs
= {
173 .attach
= imx_pd_bridge_attach
,
174 .atomic_reset
= drm_atomic_helper_bridge_reset
,
175 .atomic_duplicate_state
= drm_atomic_helper_bridge_duplicate_state
,
176 .atomic_destroy_state
= drm_atomic_helper_bridge_destroy_state
,
177 .atomic_check
= imx_pd_bridge_atomic_check
,
178 .atomic_get_input_bus_fmts
= imx_pd_bridge_atomic_get_input_bus_fmts
,
179 .atomic_get_output_bus_fmts
= imx_pd_bridge_atomic_get_output_bus_fmts
,
182 static int imx_pd_bind(struct device
*dev
, struct device
*master
, void *data
)
184 struct drm_device
*drm
= data
;
185 struct imx_parallel_display
*imxpd
= dev_get_drvdata(dev
);
186 struct imx_parallel_display_encoder
*imxpd_encoder
;
187 struct drm_connector
*connector
;
188 struct drm_encoder
*encoder
;
189 struct drm_bridge
*bridge
;
192 imxpd_encoder
= drmm_simple_encoder_alloc(drm
, struct imx_parallel_display_encoder
,
193 encoder
, DRM_MODE_ENCODER_NONE
);
194 if (IS_ERR(imxpd_encoder
))
195 return PTR_ERR(imxpd_encoder
);
197 imxpd_encoder
->pd
= imxpd
;
198 encoder
= &imxpd_encoder
->encoder
;
199 bridge
= &imxpd_encoder
->bridge
;
201 ret
= imx_drm_encoder_parse_of(drm
, encoder
, imxpd
->dev
->of_node
);
205 bridge
->funcs
= &imx_pd_bridge_funcs
;
206 drm_bridge_attach(encoder
, bridge
, NULL
, DRM_BRIDGE_ATTACH_NO_CONNECTOR
);
208 connector
= drm_bridge_connector_init(drm
, encoder
);
209 if (IS_ERR(connector
))
210 return PTR_ERR(connector
);
212 drm_connector_attach_encoder(connector
, encoder
);
217 static const struct component_ops imx_pd_ops
= {
221 static int imx_pd_probe(struct platform_device
*pdev
)
223 struct device
*dev
= &pdev
->dev
;
224 struct device_node
*np
= dev
->of_node
;
225 struct imx_parallel_display
*imxpd
;
230 imxpd
= devm_kzalloc(dev
, sizeof(*imxpd
), GFP_KERNEL
);
234 /* port@1 is the output port */
235 imxpd
->next_bridge
= devm_drm_of_get_bridge(dev
, np
, 1, 0);
236 if (imxpd
->next_bridge
== ERR_PTR(-ENODEV
))
237 imxpd
->next_bridge
= devm_imx_drm_legacy_bridge(dev
, np
, DRM_MODE_CONNECTOR_DPI
);
238 if (IS_ERR(imxpd
->next_bridge
)) {
239 ret
= PTR_ERR(imxpd
->next_bridge
);
243 ret
= of_property_read_string(np
, "interface-pix-fmt", &fmt
);
245 if (!strcmp(fmt
, "rgb24"))
246 bus_format
= MEDIA_BUS_FMT_RGB888_1X24
;
247 else if (!strcmp(fmt
, "rgb565"))
248 bus_format
= MEDIA_BUS_FMT_RGB565_1X16
;
249 else if (!strcmp(fmt
, "bgr666"))
250 bus_format
= MEDIA_BUS_FMT_RGB666_1X18
;
251 else if (!strcmp(fmt
, "lvds666"))
252 bus_format
= MEDIA_BUS_FMT_RGB666_1X24_CPADHI
;
254 imxpd
->bus_format
= bus_format
;
258 platform_set_drvdata(pdev
, imxpd
);
260 return component_add(dev
, &imx_pd_ops
);
263 static void imx_pd_remove(struct platform_device
*pdev
)
265 component_del(&pdev
->dev
, &imx_pd_ops
);
268 static const struct of_device_id imx_pd_dt_ids
[] = {
269 { .compatible
= "fsl,imx-parallel-display", },
272 MODULE_DEVICE_TABLE(of
, imx_pd_dt_ids
);
274 static struct platform_driver imx_pd_driver
= {
275 .probe
= imx_pd_probe
,
276 .remove
= imx_pd_remove
,
278 .of_match_table
= imx_pd_dt_ids
,
279 .name
= "imx-parallel-display",
283 module_platform_driver(imx_pd_driver
);
285 MODULE_DESCRIPTION("i.MX parallel display driver");
286 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
287 MODULE_LICENSE("GPL");
288 MODULE_ALIAS("platform:imx-parallel-display");