2 * i.MX drm driver - parallel display implementation
4 * Copyright (C) 2012 Sascha Hauer, Pengutronix
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/component.h>
17 #include <linux/module.h>
19 #include <drm/drm_fb_helper.h>
20 #include <drm/drm_crtc_helper.h>
21 #include <drm/drm_panel.h>
22 #include <linux/videodev2.h>
23 #include <video/of_display_timing.h>
24 #include <linux/of_graph.h>
28 #define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
29 #define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
31 struct imx_parallel_display
{
32 struct drm_connector connector
;
33 struct drm_encoder encoder
;
39 struct drm_display_mode mode
;
40 struct drm_panel
*panel
;
43 static enum drm_connector_status
imx_pd_connector_detect(
44 struct drm_connector
*connector
, bool force
)
46 return connector_status_connected
;
49 static int imx_pd_connector_get_modes(struct drm_connector
*connector
)
51 struct imx_parallel_display
*imxpd
= con_to_imxpd(connector
);
52 struct device_node
*np
= imxpd
->dev
->of_node
;
55 if (imxpd
->panel
&& imxpd
->panel
->funcs
&&
56 imxpd
->panel
->funcs
->get_modes
) {
57 num_modes
= imxpd
->panel
->funcs
->get_modes(imxpd
->panel
);
63 drm_mode_connector_update_edid_property(connector
, imxpd
->edid
);
64 num_modes
= drm_add_edid_modes(connector
, imxpd
->edid
);
67 if (imxpd
->mode_valid
) {
68 struct drm_display_mode
*mode
= drm_mode_create(connector
->dev
);
72 drm_mode_copy(mode
, &imxpd
->mode
);
73 mode
->type
|= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
,
74 drm_mode_probed_add(connector
, mode
);
79 struct drm_display_mode
*mode
= drm_mode_create(connector
->dev
);
83 of_get_drm_display_mode(np
, &imxpd
->mode
, OF_USE_NATIVE_MODE
);
84 drm_mode_copy(mode
, &imxpd
->mode
);
85 mode
->type
|= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
,
86 drm_mode_probed_add(connector
, mode
);
93 static struct drm_encoder
*imx_pd_connector_best_encoder(
94 struct drm_connector
*connector
)
96 struct imx_parallel_display
*imxpd
= con_to_imxpd(connector
);
98 return &imxpd
->encoder
;
101 static void imx_pd_encoder_dpms(struct drm_encoder
*encoder
, int mode
)
103 struct imx_parallel_display
*imxpd
= enc_to_imxpd(encoder
);
105 if (mode
!= DRM_MODE_DPMS_ON
)
106 drm_panel_disable(imxpd
->panel
);
108 drm_panel_enable(imxpd
->panel
);
111 static bool imx_pd_encoder_mode_fixup(struct drm_encoder
*encoder
,
112 const struct drm_display_mode
*mode
,
113 struct drm_display_mode
*adjusted_mode
)
118 static void imx_pd_encoder_prepare(struct drm_encoder
*encoder
)
120 struct imx_parallel_display
*imxpd
= enc_to_imxpd(encoder
);
122 imx_drm_set_bus_format(encoder
, imxpd
->bus_format
);
125 static void imx_pd_encoder_commit(struct drm_encoder
*encoder
)
127 struct imx_parallel_display
*imxpd
= enc_to_imxpd(encoder
);
129 drm_panel_prepare(imxpd
->panel
);
130 drm_panel_enable(imxpd
->panel
);
133 static void imx_pd_encoder_mode_set(struct drm_encoder
*encoder
,
134 struct drm_display_mode
*orig_mode
,
135 struct drm_display_mode
*mode
)
139 static void imx_pd_encoder_disable(struct drm_encoder
*encoder
)
141 struct imx_parallel_display
*imxpd
= enc_to_imxpd(encoder
);
143 drm_panel_disable(imxpd
->panel
);
144 drm_panel_unprepare(imxpd
->panel
);
147 static struct drm_connector_funcs imx_pd_connector_funcs
= {
148 .dpms
= drm_helper_connector_dpms
,
149 .fill_modes
= drm_helper_probe_single_connector_modes
,
150 .detect
= imx_pd_connector_detect
,
151 .destroy
= imx_drm_connector_destroy
,
154 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs
= {
155 .get_modes
= imx_pd_connector_get_modes
,
156 .best_encoder
= imx_pd_connector_best_encoder
,
159 static struct drm_encoder_funcs imx_pd_encoder_funcs
= {
160 .destroy
= imx_drm_encoder_destroy
,
163 static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs
= {
164 .dpms
= imx_pd_encoder_dpms
,
165 .mode_fixup
= imx_pd_encoder_mode_fixup
,
166 .prepare
= imx_pd_encoder_prepare
,
167 .commit
= imx_pd_encoder_commit
,
168 .mode_set
= imx_pd_encoder_mode_set
,
169 .disable
= imx_pd_encoder_disable
,
172 static int imx_pd_register(struct drm_device
*drm
,
173 struct imx_parallel_display
*imxpd
)
177 ret
= imx_drm_encoder_parse_of(drm
, &imxpd
->encoder
,
178 imxpd
->dev
->of_node
);
182 /* set the connector's dpms to OFF so that
183 * drm_helper_connector_dpms() won't return
184 * immediately since the current state is ON
187 imxpd
->connector
.dpms
= DRM_MODE_DPMS_OFF
;
189 drm_encoder_helper_add(&imxpd
->encoder
, &imx_pd_encoder_helper_funcs
);
190 drm_encoder_init(drm
, &imxpd
->encoder
, &imx_pd_encoder_funcs
,
191 DRM_MODE_ENCODER_NONE
);
193 drm_connector_helper_add(&imxpd
->connector
,
194 &imx_pd_connector_helper_funcs
);
195 drm_connector_init(drm
, &imxpd
->connector
, &imx_pd_connector_funcs
,
196 DRM_MODE_CONNECTOR_VGA
);
199 drm_panel_attach(imxpd
->panel
, &imxpd
->connector
);
201 drm_mode_connector_attach_encoder(&imxpd
->connector
, &imxpd
->encoder
);
203 imxpd
->connector
.encoder
= &imxpd
->encoder
;
208 static int imx_pd_bind(struct device
*dev
, struct device
*master
, void *data
)
210 struct drm_device
*drm
= data
;
211 struct device_node
*np
= dev
->of_node
;
212 struct device_node
*port
;
214 struct imx_parallel_display
*imxpd
;
218 imxpd
= devm_kzalloc(dev
, sizeof(*imxpd
), GFP_KERNEL
);
222 edidp
= of_get_property(np
, "edid", &imxpd
->edid_len
);
224 imxpd
->edid
= kmemdup(edidp
, imxpd
->edid_len
, GFP_KERNEL
);
226 ret
= of_property_read_string(np
, "interface-pix-fmt", &fmt
);
228 if (!strcmp(fmt
, "rgb24"))
229 imxpd
->bus_format
= MEDIA_BUS_FMT_RGB888_1X24
;
230 else if (!strcmp(fmt
, "rgb565"))
231 imxpd
->bus_format
= MEDIA_BUS_FMT_RGB565_1X16
;
232 else if (!strcmp(fmt
, "bgr666"))
233 imxpd
->bus_format
= MEDIA_BUS_FMT_RGB666_1X18
;
234 else if (!strcmp(fmt
, "lvds666"))
235 imxpd
->bus_format
= MEDIA_BUS_FMT_RGB666_1X24_CPADHI
;
238 /* port@1 is the output port */
239 port
= of_graph_get_port_by_id(np
, 1);
241 struct device_node
*endpoint
, *remote
;
243 endpoint
= of_get_child_by_name(port
, "endpoint");
245 remote
= of_graph_get_remote_port_parent(endpoint
);
247 imxpd
->panel
= of_drm_find_panel(remote
);
249 return -EPROBE_DEFER
;
255 ret
= imx_pd_register(drm
, imxpd
);
259 dev_set_drvdata(dev
, imxpd
);
264 static void imx_pd_unbind(struct device
*dev
, struct device
*master
,
267 struct imx_parallel_display
*imxpd
= dev_get_drvdata(dev
);
269 imxpd
->encoder
.funcs
->destroy(&imxpd
->encoder
);
270 imxpd
->connector
.funcs
->destroy(&imxpd
->connector
);
275 static const struct component_ops imx_pd_ops
= {
277 .unbind
= imx_pd_unbind
,
280 static int imx_pd_probe(struct platform_device
*pdev
)
282 return component_add(&pdev
->dev
, &imx_pd_ops
);
285 static int imx_pd_remove(struct platform_device
*pdev
)
287 component_del(&pdev
->dev
, &imx_pd_ops
);
292 static const struct of_device_id imx_pd_dt_ids
[] = {
293 { .compatible
= "fsl,imx-parallel-display", },
296 MODULE_DEVICE_TABLE(of
, imx_pd_dt_ids
);
298 static struct platform_driver imx_pd_driver
= {
299 .probe
= imx_pd_probe
,
300 .remove
= imx_pd_remove
,
302 .of_match_table
= imx_pd_dt_ids
,
303 .name
= "imx-parallel-display",
307 module_platform_driver(imx_pd_driver
);
309 MODULE_DESCRIPTION("i.MX parallel display driver");
310 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
311 MODULE_LICENSE("GPL");
312 MODULE_ALIAS("platform:imx-parallel-display");