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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 #include <linux/module.h>
23 #include <drm/drm_fb_helper.h>
24 #include <drm/drm_crtc_helper.h>
25 #include <linux/videodev2.h>
29 #define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
30 #define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
32 struct imx_parallel_display
{
33 struct drm_connector connector
;
34 struct imx_drm_connector
*imx_drm_connector
;
35 struct drm_encoder encoder
;
36 struct imx_drm_encoder
*imx_drm_encoder
;
40 u32 interface_pix_fmt
;
42 struct drm_display_mode mode
;
45 static enum drm_connector_status
imx_pd_connector_detect(
46 struct drm_connector
*connector
, bool force
)
48 return connector_status_connected
;
51 static void imx_pd_connector_destroy(struct drm_connector
*connector
)
53 /* do not free here */
56 static int imx_pd_connector_get_modes(struct drm_connector
*connector
)
58 struct imx_parallel_display
*imxpd
= con_to_imxpd(connector
);
59 struct device_node
*np
= imxpd
->dev
->of_node
;
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
);
69 drm_mode_copy(mode
, &imxpd
->mode
);
70 mode
->type
|= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
,
71 drm_mode_probed_add(connector
, mode
);
76 struct drm_display_mode
*mode
= drm_mode_create(connector
->dev
);
77 of_get_drm_display_mode(np
, &imxpd
->mode
, 0);
78 drm_mode_copy(mode
, &imxpd
->mode
);
79 mode
->type
|= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
,
80 drm_mode_probed_add(connector
, mode
);
87 static int imx_pd_connector_mode_valid(struct drm_connector
*connector
,
88 struct drm_display_mode
*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
)
105 static bool imx_pd_encoder_mode_fixup(struct drm_encoder
*encoder
,
106 const struct drm_display_mode
*mode
,
107 struct drm_display_mode
*adjusted_mode
)
112 static void imx_pd_encoder_prepare(struct drm_encoder
*encoder
)
114 struct imx_parallel_display
*imxpd
= enc_to_imxpd(encoder
);
116 imx_drm_crtc_panel_format(encoder
->crtc
, DRM_MODE_ENCODER_NONE
,
117 imxpd
->interface_pix_fmt
);
120 static void imx_pd_encoder_commit(struct drm_encoder
*encoder
)
124 static void imx_pd_encoder_mode_set(struct drm_encoder
*encoder
,
125 struct drm_display_mode
*mode
,
126 struct drm_display_mode
*adjusted_mode
)
130 static void imx_pd_encoder_disable(struct drm_encoder
*encoder
)
134 static void imx_pd_encoder_destroy(struct drm_encoder
*encoder
)
136 /* do not free here */
139 static struct drm_connector_funcs imx_pd_connector_funcs
= {
140 .dpms
= drm_helper_connector_dpms
,
141 .fill_modes
= drm_helper_probe_single_connector_modes
,
142 .detect
= imx_pd_connector_detect
,
143 .destroy
= imx_pd_connector_destroy
,
146 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs
= {
147 .get_modes
= imx_pd_connector_get_modes
,
148 .best_encoder
= imx_pd_connector_best_encoder
,
149 .mode_valid
= imx_pd_connector_mode_valid
,
152 static struct drm_encoder_funcs imx_pd_encoder_funcs
= {
153 .destroy
= imx_pd_encoder_destroy
,
156 static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs
= {
157 .dpms
= imx_pd_encoder_dpms
,
158 .mode_fixup
= imx_pd_encoder_mode_fixup
,
159 .prepare
= imx_pd_encoder_prepare
,
160 .commit
= imx_pd_encoder_commit
,
161 .mode_set
= imx_pd_encoder_mode_set
,
162 .disable
= imx_pd_encoder_disable
,
165 static int imx_pd_register(struct imx_parallel_display
*imxpd
)
169 drm_mode_connector_attach_encoder(&imxpd
->connector
, &imxpd
->encoder
);
171 imxpd
->connector
.funcs
= &imx_pd_connector_funcs
;
172 imxpd
->encoder
.funcs
= &imx_pd_encoder_funcs
;
174 imxpd
->encoder
.encoder_type
= DRM_MODE_ENCODER_NONE
;
175 imxpd
->connector
.connector_type
= DRM_MODE_CONNECTOR_VGA
;
177 drm_encoder_helper_add(&imxpd
->encoder
, &imx_pd_encoder_helper_funcs
);
178 ret
= imx_drm_add_encoder(&imxpd
->encoder
, &imxpd
->imx_drm_encoder
,
181 dev_err(imxpd
->dev
, "adding encoder failed with %d\n", ret
);
185 drm_connector_helper_add(&imxpd
->connector
,
186 &imx_pd_connector_helper_funcs
);
188 ret
= imx_drm_add_connector(&imxpd
->connector
,
189 &imxpd
->imx_drm_connector
, THIS_MODULE
);
191 imx_drm_remove_encoder(imxpd
->imx_drm_encoder
);
192 dev_err(imxpd
->dev
, "adding connector failed with %d\n", ret
);
196 imxpd
->connector
.encoder
= &imxpd
->encoder
;
201 static int imx_pd_probe(struct platform_device
*pdev
)
203 struct device_node
*np
= pdev
->dev
.of_node
;
205 struct imx_parallel_display
*imxpd
;
209 imxpd
= devm_kzalloc(&pdev
->dev
, sizeof(*imxpd
), GFP_KERNEL
);
213 edidp
= of_get_property(np
, "edid", &imxpd
->edid_len
);
215 imxpd
->edid
= kmemdup(edidp
, imxpd
->edid_len
, GFP_KERNEL
);
217 ret
= of_property_read_string(np
, "interface-pix-fmt", &fmt
);
219 if (!strcmp(fmt
, "rgb24"))
220 imxpd
->interface_pix_fmt
= V4L2_PIX_FMT_RGB24
;
221 else if (!strcmp(fmt
, "rgb565"))
222 imxpd
->interface_pix_fmt
= V4L2_PIX_FMT_RGB565
;
223 else if (!strcmp(fmt
, "bgr666"))
224 imxpd
->interface_pix_fmt
= V4L2_PIX_FMT_BGR666
;
227 imxpd
->dev
= &pdev
->dev
;
229 ret
= imx_pd_register(imxpd
);
233 ret
= imx_drm_encoder_add_possible_crtcs(imxpd
->imx_drm_encoder
, np
);
235 platform_set_drvdata(pdev
, imxpd
);
240 static int imx_pd_remove(struct platform_device
*pdev
)
242 struct imx_parallel_display
*imxpd
= platform_get_drvdata(pdev
);
243 struct drm_connector
*connector
= &imxpd
->connector
;
244 struct drm_encoder
*encoder
= &imxpd
->encoder
;
246 drm_mode_connector_detach_encoder(connector
, encoder
);
248 imx_drm_remove_connector(imxpd
->imx_drm_connector
);
249 imx_drm_remove_encoder(imxpd
->imx_drm_encoder
);
254 static const struct of_device_id imx_pd_dt_ids
[] = {
255 { .compatible
= "fsl,imx-parallel-display", },
258 MODULE_DEVICE_TABLE(of
, imx_pd_dt_ids
);
260 static struct platform_driver imx_pd_driver
= {
261 .probe
= imx_pd_probe
,
262 .remove
= imx_pd_remove
,
264 .of_match_table
= imx_pd_dt_ids
,
265 .name
= "imx-parallel-display",
266 .owner
= THIS_MODULE
,
270 module_platform_driver(imx_pd_driver
);
272 MODULE_DESCRIPTION("i.MX parallel display driver");
273 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
274 MODULE_LICENSE("GPL");
275 MODULE_ALIAS("platform:imx-parallel-display");