2 * i.MX IPUv3 Graphics driver
4 * Copyright (C) 2011 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,
20 #include <linux/component.h>
21 #include <linux/module.h>
22 #include <linux/export.h>
23 #include <linux/device.h>
24 #include <linux/platform_device.h>
26 #include <drm/drm_crtc_helper.h>
28 #include <linux/clk.h>
29 #include <linux/errno.h>
30 #include <drm/drm_gem_cma_helper.h>
31 #include <drm/drm_fb_cma_helper.h>
33 #include <video/imx-ipu-v3.h>
35 #include "ipuv3-plane.h"
37 #define DRIVER_DESC "i.MX IPUv3 Graphics"
42 struct imx_drm_crtc
*imx_crtc
;
44 /* plane[0] is the full plane, plane[1] is the partial plane */
45 struct ipu_plane
*plane
[2];
50 struct drm_pending_vblank_event
*page_flip_event
;
51 struct drm_framebuffer
*newfb
;
53 u32 interface_pix_fmt
;
54 unsigned long di_clkflags
;
59 #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
61 static void ipu_fb_enable(struct ipu_crtc
*ipu_crtc
)
63 struct ipu_soc
*ipu
= dev_get_drvdata(ipu_crtc
->dev
->parent
);
65 if (ipu_crtc
->enabled
)
69 ipu_plane_enable(ipu_crtc
->plane
[0]);
70 /* Start DC channel and DI after IDMAC */
71 ipu_dc_enable_channel(ipu_crtc
->dc
);
72 ipu_di_enable(ipu_crtc
->di
);
74 ipu_crtc
->enabled
= 1;
77 static void ipu_fb_disable(struct ipu_crtc
*ipu_crtc
)
79 struct ipu_soc
*ipu
= dev_get_drvdata(ipu_crtc
->dev
->parent
);
81 if (!ipu_crtc
->enabled
)
84 /* Stop DC channel and DI before IDMAC */
85 ipu_dc_disable_channel(ipu_crtc
->dc
);
86 ipu_di_disable(ipu_crtc
->di
);
87 ipu_plane_disable(ipu_crtc
->plane
[0]);
90 ipu_crtc
->enabled
= 0;
93 static void ipu_crtc_dpms(struct drm_crtc
*crtc
, int mode
)
95 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
97 dev_dbg(ipu_crtc
->dev
, "%s mode: %d\n", __func__
, mode
);
100 case DRM_MODE_DPMS_ON
:
101 ipu_fb_enable(ipu_crtc
);
103 case DRM_MODE_DPMS_STANDBY
:
104 case DRM_MODE_DPMS_SUSPEND
:
105 case DRM_MODE_DPMS_OFF
:
106 ipu_fb_disable(ipu_crtc
);
111 static int ipu_page_flip(struct drm_crtc
*crtc
,
112 struct drm_framebuffer
*fb
,
113 struct drm_pending_vblank_event
*event
,
114 uint32_t page_flip_flags
)
116 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
122 ret
= imx_drm_crtc_vblank_get(ipu_crtc
->imx_crtc
);
124 dev_dbg(ipu_crtc
->dev
, "failed to acquire vblank counter\n");
125 list_del(&event
->base
.link
);
130 ipu_crtc
->newfb
= fb
;
131 ipu_crtc
->page_flip_event
= event
;
132 crtc
->primary
->fb
= fb
;
137 static const struct drm_crtc_funcs ipu_crtc_funcs
= {
138 .set_config
= drm_crtc_helper_set_config
,
139 .destroy
= drm_crtc_cleanup
,
140 .page_flip
= ipu_page_flip
,
143 static int ipu_crtc_mode_set(struct drm_crtc
*crtc
,
144 struct drm_display_mode
*orig_mode
,
145 struct drm_display_mode
*mode
,
147 struct drm_framebuffer
*old_fb
)
149 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
151 struct ipu_di_signal_cfg sig_cfg
= {};
154 dev_dbg(ipu_crtc
->dev
, "%s: mode->hdisplay: %d\n", __func__
,
156 dev_dbg(ipu_crtc
->dev
, "%s: mode->vdisplay: %d\n", __func__
,
159 out_pixel_fmt
= ipu_crtc
->interface_pix_fmt
;
161 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
162 sig_cfg
.interlaced
= 1;
163 if (mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
164 sig_cfg
.Hsync_pol
= 1;
165 if (mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
166 sig_cfg
.Vsync_pol
= 1;
168 sig_cfg
.enable_pol
= 1;
170 sig_cfg
.width
= mode
->hdisplay
;
171 sig_cfg
.height
= mode
->vdisplay
;
172 sig_cfg
.pixel_fmt
= out_pixel_fmt
;
173 sig_cfg
.h_start_width
= mode
->htotal
- mode
->hsync_end
;
174 sig_cfg
.h_sync_width
= mode
->hsync_end
- mode
->hsync_start
;
175 sig_cfg
.h_end_width
= mode
->hsync_start
- mode
->hdisplay
;
177 sig_cfg
.v_start_width
= mode
->vtotal
- mode
->vsync_end
;
178 sig_cfg
.v_sync_width
= mode
->vsync_end
- mode
->vsync_start
;
179 sig_cfg
.v_end_width
= mode
->vsync_start
- mode
->vdisplay
;
180 sig_cfg
.pixelclock
= mode
->clock
* 1000;
181 sig_cfg
.clkflags
= ipu_crtc
->di_clkflags
;
183 sig_cfg
.v_to_h_sync
= 0;
185 sig_cfg
.hsync_pin
= ipu_crtc
->di_hsync_pin
;
186 sig_cfg
.vsync_pin
= ipu_crtc
->di_vsync_pin
;
188 ret
= ipu_dc_init_sync(ipu_crtc
->dc
, ipu_crtc
->di
, sig_cfg
.interlaced
,
189 out_pixel_fmt
, mode
->hdisplay
);
191 dev_err(ipu_crtc
->dev
,
192 "initializing display controller failed with %d\n",
197 ret
= ipu_di_init_sync_panel(ipu_crtc
->di
, &sig_cfg
);
199 dev_err(ipu_crtc
->dev
,
200 "initializing panel failed with %d\n", ret
);
204 return ipu_plane_mode_set(ipu_crtc
->plane
[0], crtc
, mode
, crtc
->primary
->fb
,
205 0, 0, mode
->hdisplay
, mode
->vdisplay
,
206 x
, y
, mode
->hdisplay
, mode
->vdisplay
);
209 static void ipu_crtc_handle_pageflip(struct ipu_crtc
*ipu_crtc
)
212 struct drm_device
*drm
= ipu_crtc
->base
.dev
;
214 spin_lock_irqsave(&drm
->event_lock
, flags
);
215 if (ipu_crtc
->page_flip_event
)
216 drm_send_vblank_event(drm
, -1, ipu_crtc
->page_flip_event
);
217 ipu_crtc
->page_flip_event
= NULL
;
218 imx_drm_crtc_vblank_put(ipu_crtc
->imx_crtc
);
219 spin_unlock_irqrestore(&drm
->event_lock
, flags
);
222 static irqreturn_t
ipu_irq_handler(int irq
, void *dev_id
)
224 struct ipu_crtc
*ipu_crtc
= dev_id
;
226 imx_drm_handle_vblank(ipu_crtc
->imx_crtc
);
228 if (ipu_crtc
->newfb
) {
229 ipu_crtc
->newfb
= NULL
;
230 ipu_plane_set_base(ipu_crtc
->plane
[0], ipu_crtc
->base
.primary
->fb
,
231 ipu_crtc
->plane
[0]->x
, ipu_crtc
->plane
[0]->y
);
232 ipu_crtc_handle_pageflip(ipu_crtc
);
238 static bool ipu_crtc_mode_fixup(struct drm_crtc
*crtc
,
239 const struct drm_display_mode
*mode
,
240 struct drm_display_mode
*adjusted_mode
)
245 static void ipu_crtc_prepare(struct drm_crtc
*crtc
)
247 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
249 ipu_fb_disable(ipu_crtc
);
252 static void ipu_crtc_commit(struct drm_crtc
*crtc
)
254 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
256 ipu_fb_enable(ipu_crtc
);
259 static struct drm_crtc_helper_funcs ipu_helper_funcs
= {
260 .dpms
= ipu_crtc_dpms
,
261 .mode_fixup
= ipu_crtc_mode_fixup
,
262 .mode_set
= ipu_crtc_mode_set
,
263 .prepare
= ipu_crtc_prepare
,
264 .commit
= ipu_crtc_commit
,
267 static int ipu_enable_vblank(struct drm_crtc
*crtc
)
272 static void ipu_disable_vblank(struct drm_crtc
*crtc
)
274 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
276 ipu_crtc
->page_flip_event
= NULL
;
277 ipu_crtc
->newfb
= NULL
;
280 static int ipu_set_interface_pix_fmt(struct drm_crtc
*crtc
, u32 encoder_type
,
281 u32 pixfmt
, int hsync_pin
, int vsync_pin
)
283 struct ipu_crtc
*ipu_crtc
= to_ipu_crtc(crtc
);
285 ipu_crtc
->interface_pix_fmt
= pixfmt
;
286 ipu_crtc
->di_hsync_pin
= hsync_pin
;
287 ipu_crtc
->di_vsync_pin
= vsync_pin
;
289 switch (encoder_type
) {
290 case DRM_MODE_ENCODER_DAC
:
291 case DRM_MODE_ENCODER_TVDAC
:
292 case DRM_MODE_ENCODER_LVDS
:
293 ipu_crtc
->di_clkflags
= IPU_DI_CLKMODE_SYNC
|
296 case DRM_MODE_ENCODER_TMDS
:
297 case DRM_MODE_ENCODER_NONE
:
298 ipu_crtc
->di_clkflags
= 0;
305 static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs
= {
306 .enable_vblank
= ipu_enable_vblank
,
307 .disable_vblank
= ipu_disable_vblank
,
308 .set_interface_pix_fmt
= ipu_set_interface_pix_fmt
,
309 .crtc_funcs
= &ipu_crtc_funcs
,
310 .crtc_helper_funcs
= &ipu_helper_funcs
,
313 static void ipu_put_resources(struct ipu_crtc
*ipu_crtc
)
315 if (!IS_ERR_OR_NULL(ipu_crtc
->dc
))
316 ipu_dc_put(ipu_crtc
->dc
);
317 if (!IS_ERR_OR_NULL(ipu_crtc
->di
))
318 ipu_di_put(ipu_crtc
->di
);
321 static int ipu_get_resources(struct ipu_crtc
*ipu_crtc
,
322 struct ipu_client_platformdata
*pdata
)
324 struct ipu_soc
*ipu
= dev_get_drvdata(ipu_crtc
->dev
->parent
);
327 ipu_crtc
->dc
= ipu_dc_get(ipu
, pdata
->dc
);
328 if (IS_ERR(ipu_crtc
->dc
)) {
329 ret
= PTR_ERR(ipu_crtc
->dc
);
333 ipu_crtc
->di
= ipu_di_get(ipu
, pdata
->di
);
334 if (IS_ERR(ipu_crtc
->di
)) {
335 ret
= PTR_ERR(ipu_crtc
->di
);
341 ipu_put_resources(ipu_crtc
);
346 static int ipu_crtc_init(struct ipu_crtc
*ipu_crtc
,
347 struct ipu_client_platformdata
*pdata
, struct drm_device
*drm
)
349 struct ipu_soc
*ipu
= dev_get_drvdata(ipu_crtc
->dev
->parent
);
354 ret
= ipu_get_resources(ipu_crtc
, pdata
);
356 dev_err(ipu_crtc
->dev
, "getting resources failed with %d.\n",
361 ret
= imx_drm_add_crtc(drm
, &ipu_crtc
->base
, &ipu_crtc
->imx_crtc
,
362 &ipu_crtc_helper_funcs
, ipu_crtc
->dev
->of_node
);
364 dev_err(ipu_crtc
->dev
, "adding crtc failed with %d.\n", ret
);
365 goto err_put_resources
;
369 dp
= IPU_DP_FLOW_SYNC_BG
;
370 id
= imx_drm_crtc_id(ipu_crtc
->imx_crtc
);
371 ipu_crtc
->plane
[0] = ipu_plane_init(ipu_crtc
->base
.dev
, ipu
,
372 pdata
->dma
[0], dp
, BIT(id
), true);
373 ret
= ipu_plane_get_resources(ipu_crtc
->plane
[0]);
375 dev_err(ipu_crtc
->dev
, "getting plane 0 resources failed with %d.\n",
377 goto err_remove_crtc
;
380 /* If this crtc is using the DP, add an overlay plane */
381 if (pdata
->dp
>= 0 && pdata
->dma
[1] > 0) {
382 ipu_crtc
->plane
[1] = ipu_plane_init(ipu_crtc
->base
.dev
, ipu
,
386 if (IS_ERR(ipu_crtc
->plane
[1]))
387 ipu_crtc
->plane
[1] = NULL
;
390 ipu_crtc
->irq
= ipu_plane_irq(ipu_crtc
->plane
[0]);
391 ret
= devm_request_irq(ipu_crtc
->dev
, ipu_crtc
->irq
, ipu_irq_handler
, 0,
392 "imx_drm", ipu_crtc
);
394 dev_err(ipu_crtc
->dev
, "irq request failed with %d.\n", ret
);
395 goto err_put_plane_res
;
401 ipu_plane_put_resources(ipu_crtc
->plane
[0]);
403 imx_drm_remove_crtc(ipu_crtc
->imx_crtc
);
405 ipu_put_resources(ipu_crtc
);
410 static struct device_node
*ipu_drm_get_port_by_id(struct device_node
*parent
,
413 struct device_node
*port
;
416 port
= of_get_child_by_name(parent
, "port");
418 ret
= of_property_read_u32(port
, "reg", &id
);
419 if (!ret
&& id
== port_id
)
423 port
= of_get_next_child(parent
, port
);
426 } while (of_node_cmp(port
->name
, "port"));
432 static int ipu_drm_bind(struct device
*dev
, struct device
*master
, void *data
)
434 struct ipu_client_platformdata
*pdata
= dev
->platform_data
;
435 struct drm_device
*drm
= data
;
436 struct ipu_crtc
*ipu_crtc
;
439 ipu_crtc
= devm_kzalloc(dev
, sizeof(*ipu_crtc
), GFP_KERNEL
);
445 ret
= ipu_crtc_init(ipu_crtc
, pdata
, drm
);
449 dev_set_drvdata(dev
, ipu_crtc
);
454 static void ipu_drm_unbind(struct device
*dev
, struct device
*master
,
457 struct ipu_crtc
*ipu_crtc
= dev_get_drvdata(dev
);
459 imx_drm_remove_crtc(ipu_crtc
->imx_crtc
);
461 ipu_plane_put_resources(ipu_crtc
->plane
[0]);
462 ipu_put_resources(ipu_crtc
);
465 static const struct component_ops ipu_crtc_ops
= {
466 .bind
= ipu_drm_bind
,
467 .unbind
= ipu_drm_unbind
,
470 static int ipu_drm_probe(struct platform_device
*pdev
)
472 struct device
*dev
= &pdev
->dev
;
473 struct ipu_client_platformdata
*pdata
= dev
->platform_data
;
476 if (!dev
->platform_data
)
480 /* Associate crtc device with the corresponding DI port node */
481 dev
->of_node
= ipu_drm_get_port_by_id(dev
->parent
->of_node
,
484 dev_err(dev
, "missing port@%d node in %s\n",
485 pdata
->di
+ 2, dev
->parent
->of_node
->full_name
);
490 ret
= dma_set_coherent_mask(dev
, DMA_BIT_MASK(32));
494 return component_add(dev
, &ipu_crtc_ops
);
497 static int ipu_drm_remove(struct platform_device
*pdev
)
499 component_del(&pdev
->dev
, &ipu_crtc_ops
);
503 static struct platform_driver ipu_drm_driver
= {
505 .name
= "imx-ipuv3-crtc",
507 .probe
= ipu_drm_probe
,
508 .remove
= ipu_drm_remove
,
510 module_platform_driver(ipu_drm_driver
);
512 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
513 MODULE_DESCRIPTION(DRIVER_DESC
);
514 MODULE_LICENSE("GPL");
515 MODULE_ALIAS("platform:imx-ipuv3-crtc");