blob: 4bea0ddb3f3e3be88eb8b8be6f3e69cf8663836b [file] [log] [blame]
Sascha Hauerf326f792012-09-21 10:07:50 +02001/*
2 * i.MX IPUv3 Graphics driver
3 *
4 * Copyright (C) 2011 Sascha Hauer, Pengutronix
5 *
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.
Sascha Hauerf326f792012-09-21 10:07:50 +020014 */
Russell King17b50012013-11-03 11:23:34 +000015#include <linux/component.h>
Sascha Hauerf326f792012-09-21 10:07:50 +020016#include <linux/module.h>
17#include <linux/export.h>
18#include <linux/device.h>
19#include <linux/platform_device.h>
20#include <drm/drmP.h>
Sascha Hauerf326f792012-09-21 10:07:50 +020021#include <drm/drm_crtc_helper.h>
22#include <linux/fb.h>
23#include <linux/clk.h>
Philipp Zabelb8d181e2013-10-10 16:18:45 +020024#include <linux/errno.h>
Lucas Stach17a8d082016-02-09 14:51:26 +010025#include <linux/reservation.h>
26#include <linux/dma-buf.h>
Sascha Hauerf326f792012-09-21 10:07:50 +020027#include <drm/drm_gem_cma_helper.h>
28#include <drm/drm_fb_cma_helper.h>
29
Philipp Zabel39b90042013-09-30 16:13:39 +020030#include <video/imx-ipu-v3.h>
Sascha Hauerf326f792012-09-21 10:07:50 +020031#include "imx-drm.h"
Philipp Zabelb8d181e2013-10-10 16:18:45 +020032#include "ipuv3-plane.h"
Sascha Hauerf326f792012-09-21 10:07:50 +020033
34#define DRIVER_DESC "i.MX IPUv3 Graphics"
35
Lucas Stach0bfc2b32016-02-04 10:15:10 +010036enum ipu_flip_status {
37 IPU_FLIP_NONE,
38 IPU_FLIP_PENDING,
Lucas Stach17a8d082016-02-09 14:51:26 +010039 IPU_FLIP_SUBMITTED,
Lucas Stach0bfc2b32016-02-04 10:15:10 +010040};
41
Lucas Stach0a7ad342016-02-09 14:29:49 +010042struct ipu_flip_work {
43 struct work_struct unref_work;
44 struct drm_gem_object *bo;
45 struct drm_pending_vblank_event *page_flip_event;
Lucas Stach17a8d082016-02-09 14:51:26 +010046 struct work_struct fence_work;
47 struct ipu_crtc *crtc;
48 struct fence *excl;
49 unsigned shared_count;
50 struct fence **shared;
Lucas Stach0a7ad342016-02-09 14:29:49 +010051};
52
Sascha Hauerf326f792012-09-21 10:07:50 +020053struct ipu_crtc {
Sascha Hauerf326f792012-09-21 10:07:50 +020054 struct device *dev;
55 struct drm_crtc base;
56 struct imx_drm_crtc *imx_crtc;
Philipp Zabelb8d181e2013-10-10 16:18:45 +020057
58 /* plane[0] is the full plane, plane[1] is the partial plane */
59 struct ipu_plane *plane[2];
60
Sascha Hauerf326f792012-09-21 10:07:50 +020061 struct ipu_dc *dc;
Sascha Hauerf326f792012-09-21 10:07:50 +020062 struct ipu_di *di;
63 int enabled;
Lucas Stach0bfc2b32016-02-04 10:15:10 +010064 enum ipu_flip_status flip_state;
Lucas Stach0a7ad342016-02-09 14:29:49 +010065 struct workqueue_struct *flip_queue;
66 struct ipu_flip_work *flip_work;
Sascha Hauerf326f792012-09-21 10:07:50 +020067 int irq;
Philipp Zabel2872c802015-02-02 17:25:59 +010068 u32 bus_format;
Philipp Zabel2ea42602013-04-08 18:04:35 +020069 int di_hsync_pin;
70 int di_vsync_pin;
Sascha Hauerf326f792012-09-21 10:07:50 +020071};
72
73#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
74
Sascha Hauerf326f792012-09-21 10:07:50 +020075static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
76{
Philipp Zabel1e6d4862014-04-14 23:53:23 +020077 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
78
Sascha Hauerf326f792012-09-21 10:07:50 +020079 if (ipu_crtc->enabled)
80 return;
81
Philipp Zabel1e6d4862014-04-14 23:53:23 +020082 ipu_dc_enable(ipu);
Philipp Zabelb8d181e2013-10-10 16:18:45 +020083 ipu_plane_enable(ipu_crtc->plane[0]);
Philipp Zabelc115edb2014-04-14 23:53:22 +020084 /* Start DC channel and DI after IDMAC */
85 ipu_dc_enable_channel(ipu_crtc->dc);
86 ipu_di_enable(ipu_crtc->di);
Sascha Hauerf326f792012-09-21 10:07:50 +020087
88 ipu_crtc->enabled = 1;
89}
90
91static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
92{
Philipp Zabel1e6d4862014-04-14 23:53:23 +020093 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
94
Sascha Hauerf326f792012-09-21 10:07:50 +020095 if (!ipu_crtc->enabled)
96 return;
97
Philipp Zabelc115edb2014-04-14 23:53:22 +020098 /* Stop DC channel and DI before IDMAC */
Sascha Hauerf326f792012-09-21 10:07:50 +020099 ipu_dc_disable_channel(ipu_crtc->dc);
Sascha Hauerf326f792012-09-21 10:07:50 +0200100 ipu_di_disable(ipu_crtc->di);
Philipp Zabelc115edb2014-04-14 23:53:22 +0200101 ipu_plane_disable(ipu_crtc->plane[0]);
Philipp Zabel1e6d4862014-04-14 23:53:23 +0200102 ipu_dc_disable(ipu);
Sascha Hauerf326f792012-09-21 10:07:50 +0200103
104 ipu_crtc->enabled = 0;
105}
106
107static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
108{
109 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
110
Philipp Zabela8e4e232012-11-12 16:29:01 +0100111 dev_dbg(ipu_crtc->dev, "%s mode: %d\n", __func__, mode);
Sascha Hauerf326f792012-09-21 10:07:50 +0200112
113 switch (mode) {
114 case DRM_MODE_DPMS_ON:
115 ipu_fb_enable(ipu_crtc);
116 break;
117 case DRM_MODE_DPMS_STANDBY:
118 case DRM_MODE_DPMS_SUSPEND:
119 case DRM_MODE_DPMS_OFF:
120 ipu_fb_disable(ipu_crtc);
121 break;
122 }
123}
124
Lucas Stach0a7ad342016-02-09 14:29:49 +0100125static void ipu_flip_unref_work_func(struct work_struct *__work)
126{
127 struct ipu_flip_work *work =
128 container_of(__work, struct ipu_flip_work, unref_work);
129
130 drm_gem_object_unreference_unlocked(work->bo);
131 kfree(work);
132}
133
Lucas Stach17a8d082016-02-09 14:51:26 +0100134static void ipu_flip_fence_work_func(struct work_struct *__work)
135{
136 struct ipu_flip_work *work =
137 container_of(__work, struct ipu_flip_work, fence_work);
138 int i;
139
140 /* wait for all fences attached to the FB obj to signal */
141 if (work->excl) {
142 fence_wait(work->excl, false);
143 fence_put(work->excl);
144 }
145 for (i = 0; i < work->shared_count; i++) {
146 fence_wait(work->shared[i], false);
147 fence_put(work->shared[i]);
148 }
149
150 work->crtc->flip_state = IPU_FLIP_SUBMITTED;
151}
152
Sascha Hauerf326f792012-09-21 10:07:50 +0200153static int ipu_page_flip(struct drm_crtc *crtc,
154 struct drm_framebuffer *fb,
Keith Packarded8d1972013-07-22 18:49:58 -0700155 struct drm_pending_vblank_event *event,
156 uint32_t page_flip_flags)
Sascha Hauerf326f792012-09-21 10:07:50 +0200157{
Lucas Stach17a8d082016-02-09 14:51:26 +0100158 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
Sascha Hauerf326f792012-09-21 10:07:50 +0200159 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
Lucas Stach0a7ad342016-02-09 14:29:49 +0100160 struct ipu_flip_work *flip_work;
Sascha Hauerf326f792012-09-21 10:07:50 +0200161 int ret;
162
Lucas Stach0bfc2b32016-02-04 10:15:10 +0100163 if (ipu_crtc->flip_state != IPU_FLIP_NONE)
Sascha Hauerf326f792012-09-21 10:07:50 +0200164 return -EBUSY;
165
166 ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
167 if (ret) {
168 dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
169 list_del(&event->base.link);
170
171 return ret;
172 }
173
Lucas Stach0a7ad342016-02-09 14:29:49 +0100174 flip_work = kzalloc(sizeof *flip_work, GFP_KERNEL);
175 if (!flip_work) {
176 ret = -ENOMEM;
177 goto put_vblank;
178 }
179 INIT_WORK(&flip_work->unref_work, ipu_flip_unref_work_func);
180 flip_work->page_flip_event = event;
181
182 /* get BO backing the old framebuffer and take a reference */
183 flip_work->bo = &drm_fb_cma_get_gem_obj(crtc->primary->fb, 0)->base;
184 drm_gem_object_reference(flip_work->bo);
185
186 ipu_crtc->flip_work = flip_work;
Lucas Stach17a8d082016-02-09 14:51:26 +0100187 /*
188 * If the object has a DMABUF attached, we need to wait on its fences
189 * if there are any.
190 */
191 if (cma_obj->base.dma_buf) {
192 INIT_WORK(&flip_work->fence_work, ipu_flip_fence_work_func);
193 flip_work->crtc = ipu_crtc;
194
195 ret = reservation_object_get_fences_rcu(
196 cma_obj->base.dma_buf->resv, &flip_work->excl,
197 &flip_work->shared_count, &flip_work->shared);
198
199 if (unlikely(ret)) {
200 DRM_ERROR("failed to get fences for buffer\n");
201 goto free_flip_work;
202 }
203
204 /* No need to queue the worker if the are no fences */
205 if (!flip_work->excl && !flip_work->shared_count) {
206 ipu_crtc->flip_state = IPU_FLIP_SUBMITTED;
207 } else {
208 ipu_crtc->flip_state = IPU_FLIP_PENDING;
209 queue_work(ipu_crtc->flip_queue,
210 &flip_work->fence_work);
211 }
212 } else {
213 ipu_crtc->flip_state = IPU_FLIP_SUBMITTED;
214 }
Sascha Hauerf326f792012-09-21 10:07:50 +0200215
216 return 0;
Lucas Stach0a7ad342016-02-09 14:29:49 +0100217
Lucas Stach17a8d082016-02-09 14:51:26 +0100218free_flip_work:
219 drm_gem_object_unreference_unlocked(flip_work->bo);
220 kfree(flip_work);
221 ipu_crtc->flip_work = NULL;
Lucas Stach0a7ad342016-02-09 14:29:49 +0100222put_vblank:
223 imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
224
225 return ret;
Sascha Hauerf326f792012-09-21 10:07:50 +0200226}
227
228static const struct drm_crtc_funcs ipu_crtc_funcs = {
229 .set_config = drm_crtc_helper_set_config,
230 .destroy = drm_crtc_cleanup,
231 .page_flip = ipu_page_flip,
232};
233
Sascha Hauerf326f792012-09-21 10:07:50 +0200234static int ipu_crtc_mode_set(struct drm_crtc *crtc,
235 struct drm_display_mode *orig_mode,
236 struct drm_display_mode *mode,
237 int x, int y,
238 struct drm_framebuffer *old_fb)
239{
Russell Kingd50141d2014-12-21 15:58:19 +0000240 struct drm_device *dev = crtc->dev;
241 struct drm_encoder *encoder;
Sascha Hauerf326f792012-09-21 10:07:50 +0200242 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
Sascha Hauerf326f792012-09-21 10:07:50 +0200243 struct ipu_di_signal_cfg sig_cfg = {};
Russell Kingd50141d2014-12-21 15:58:19 +0000244 unsigned long encoder_types = 0;
Russell Kingd50141d2014-12-21 15:58:19 +0000245 int ret;
Sascha Hauerf326f792012-09-21 10:07:50 +0200246
247 dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
248 mode->hdisplay);
249 dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
250 mode->vdisplay);
251
Russell Kingd50141d2014-12-21 15:58:19 +0000252 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
253 if (encoder->crtc == crtc)
254 encoder_types |= BIT(encoder->encoder_type);
255
256 dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
257 __func__, encoder_types);
258
259 /*
Philipp Zabele0d155c2014-07-11 17:28:45 +0200260 * If we have DAC or LDB, then we need the IPU DI clock to be
261 * the same as the LDB DI clock. For TVDAC, derive the IPU DI
262 * clock from 27 MHz TVE_DI clock, but allow to divide it.
Russell Kingd50141d2014-12-21 15:58:19 +0000263 */
264 if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
Russell Kingd50141d2014-12-21 15:58:19 +0000265 BIT(DRM_MODE_ENCODER_LVDS)))
266 sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
Philipp Zabele0d155c2014-07-11 17:28:45 +0200267 else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
268 sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
Russell Kingd50141d2014-12-21 15:58:19 +0000269 else
270 sig_cfg.clkflags = 0;
271
Sascha Hauerf326f792012-09-21 10:07:50 +0200272 sig_cfg.enable_pol = 1;
Denis Carikli85de9d12014-04-07 14:44:43 +0200273 sig_cfg.clk_pol = 0;
Philipp Zabel2872c802015-02-02 17:25:59 +0100274 sig_cfg.bus_format = ipu_crtc->bus_format;
Sascha Hauerf326f792012-09-21 10:07:50 +0200275 sig_cfg.v_to_h_sync = 0;
Philipp Zabel2ea42602013-04-08 18:04:35 +0200276 sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
277 sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
278
Steve Longerbeamb6835a72014-12-18 18:00:25 -0800279 drm_display_mode_to_videomode(mode, &sig_cfg.mode);
280
281 ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
282 mode->flags & DRM_MODE_FLAG_INTERLACE,
Philipp Zabel2872c802015-02-02 17:25:59 +0100283 ipu_crtc->bus_format, mode->hdisplay);
Sascha Hauerf326f792012-09-21 10:07:50 +0200284 if (ret) {
285 dev_err(ipu_crtc->dev,
286 "initializing display controller failed with %d\n",
287 ret);
288 return ret;
289 }
290
291 ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
292 if (ret) {
293 dev_err(ipu_crtc->dev,
294 "initializing panel failed with %d\n", ret);
295 return ret;
296 }
297
Yannis Damigos30e94a52014-08-19 18:26:46 +0300298 return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode,
299 crtc->primary->fb,
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200300 0, 0, mode->hdisplay, mode->vdisplay,
Philipp Zabeldd7fa6d2014-07-11 18:02:06 +0200301 x, y, mode->hdisplay, mode->vdisplay,
302 mode->flags & DRM_MODE_FLAG_INTERLACE);
Sascha Hauerf326f792012-09-21 10:07:50 +0200303}
304
305static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
306{
Sascha Hauerf326f792012-09-21 10:07:50 +0200307 unsigned long flags;
308 struct drm_device *drm = ipu_crtc->base.dev;
Lucas Stach0a7ad342016-02-09 14:29:49 +0100309 struct ipu_flip_work *work = ipu_crtc->flip_work;
Sascha Hauerf326f792012-09-21 10:07:50 +0200310
311 spin_lock_irqsave(&drm->event_lock, flags);
Lucas Stach0a7ad342016-02-09 14:29:49 +0100312 if (work->page_flip_event)
Russell King69d21fc2015-11-25 10:25:39 +0000313 drm_crtc_send_vblank_event(&ipu_crtc->base,
Lucas Stach0a7ad342016-02-09 14:29:49 +0100314 work->page_flip_event);
Sascha Hauerf326f792012-09-21 10:07:50 +0200315 imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
Sascha Hauerf326f792012-09-21 10:07:50 +0200316 spin_unlock_irqrestore(&drm->event_lock, flags);
317}
318
319static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
320{
321 struct ipu_crtc *ipu_crtc = dev_id;
322
323 imx_drm_handle_vblank(ipu_crtc->imx_crtc);
324
Lucas Stach17a8d082016-02-09 14:51:26 +0100325 if (ipu_crtc->flip_state == IPU_FLIP_SUBMITTED) {
Yannis Damigos30e94a52014-08-19 18:26:46 +0300326 struct ipu_plane *plane = ipu_crtc->plane[0];
327
Yannis Damigos30e94a52014-08-19 18:26:46 +0300328 ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
329 plane->x, plane->y);
Sascha Hauerf326f792012-09-21 10:07:50 +0200330 ipu_crtc_handle_pageflip(ipu_crtc);
Lucas Stach0a7ad342016-02-09 14:29:49 +0100331 queue_work(ipu_crtc->flip_queue,
332 &ipu_crtc->flip_work->unref_work);
Lucas Stach0bfc2b32016-02-04 10:15:10 +0100333 ipu_crtc->flip_state = IPU_FLIP_NONE;
Sascha Hauerf326f792012-09-21 10:07:50 +0200334 }
335
336 return IRQ_HANDLED;
337}
338
339static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
340 const struct drm_display_mode *mode,
341 struct drm_display_mode *adjusted_mode)
342{
Steve Longerbeam0c460a52014-12-18 18:00:23 -0800343 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
344 struct videomode vm;
345 int ret;
346
347 drm_display_mode_to_videomode(adjusted_mode, &vm);
348
349 ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
350 if (ret)
351 return false;
352
353 drm_display_mode_from_videomode(&vm, adjusted_mode);
354
Sascha Hauerf326f792012-09-21 10:07:50 +0200355 return true;
356}
357
358static void ipu_crtc_prepare(struct drm_crtc *crtc)
359{
360 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
361
362 ipu_fb_disable(ipu_crtc);
363}
364
365static void ipu_crtc_commit(struct drm_crtc *crtc)
366{
367 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
368
369 ipu_fb_enable(ipu_crtc);
370}
371
Ville Syrjälä7ae847d2015-12-15 12:21:09 +0100372static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
Sascha Hauerf326f792012-09-21 10:07:50 +0200373 .dpms = ipu_crtc_dpms,
374 .mode_fixup = ipu_crtc_mode_fixup,
375 .mode_set = ipu_crtc_mode_set,
376 .prepare = ipu_crtc_prepare,
377 .commit = ipu_crtc_commit,
Sascha Hauerf326f792012-09-21 10:07:50 +0200378};
379
380static int ipu_enable_vblank(struct drm_crtc *crtc)
381{
Lucas Stach411b0332016-02-09 11:43:08 +0100382 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
383
384 enable_irq(ipu_crtc->irq);
385
Sascha Hauerf326f792012-09-21 10:07:50 +0200386 return 0;
387}
388
389static void ipu_disable_vblank(struct drm_crtc *crtc)
390{
Lucas Stach411b0332016-02-09 11:43:08 +0100391 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
392
393 disable_irq_nosync(ipu_crtc->irq);
Sascha Hauerf326f792012-09-21 10:07:50 +0200394}
395
Russell Kingd50141d2014-12-21 15:58:19 +0000396static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
Philipp Zabel2872c802015-02-02 17:25:59 +0100397 u32 bus_format, int hsync_pin, int vsync_pin)
Sascha Hauerf326f792012-09-21 10:07:50 +0200398{
399 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
400
Philipp Zabel2872c802015-02-02 17:25:59 +0100401 ipu_crtc->bus_format = bus_format;
Philipp Zabel2ea42602013-04-08 18:04:35 +0200402 ipu_crtc->di_hsync_pin = hsync_pin;
403 ipu_crtc->di_vsync_pin = vsync_pin;
Sascha Hauerf326f792012-09-21 10:07:50 +0200404
Sascha Hauerf326f792012-09-21 10:07:50 +0200405 return 0;
406}
407
408static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
409 .enable_vblank = ipu_enable_vblank,
410 .disable_vblank = ipu_disable_vblank,
411 .set_interface_pix_fmt = ipu_set_interface_pix_fmt,
412 .crtc_funcs = &ipu_crtc_funcs,
413 .crtc_helper_funcs = &ipu_helper_funcs,
414};
415
416static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
417{
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200418 if (!IS_ERR_OR_NULL(ipu_crtc->dc))
419 ipu_dc_put(ipu_crtc->dc);
Sascha Hauerf326f792012-09-21 10:07:50 +0200420 if (!IS_ERR_OR_NULL(ipu_crtc->di))
421 ipu_di_put(ipu_crtc->di);
422}
423
424static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
425 struct ipu_client_platformdata *pdata)
426{
427 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
428 int ret;
429
Sascha Hauerf326f792012-09-21 10:07:50 +0200430 ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
431 if (IS_ERR(ipu_crtc->dc)) {
432 ret = PTR_ERR(ipu_crtc->dc);
433 goto err_out;
434 }
435
Sascha Hauerf326f792012-09-21 10:07:50 +0200436 ipu_crtc->di = ipu_di_get(ipu, pdata->di);
437 if (IS_ERR(ipu_crtc->di)) {
438 ret = PTR_ERR(ipu_crtc->di);
439 goto err_out;
440 }
441
Sascha Hauerf326f792012-09-21 10:07:50 +0200442 return 0;
443err_out:
444 ipu_put_resources(ipu_crtc);
445
446 return ret;
447}
448
449static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
Russell King32266b42013-11-03 12:26:23 +0000450 struct ipu_client_platformdata *pdata, struct drm_device *drm)
Sascha Hauerf326f792012-09-21 10:07:50 +0200451{
Philipp Zabel47b1be52013-02-20 10:57:01 +0800452 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200453 int dp = -EINVAL;
Sascha Hauerf326f792012-09-21 10:07:50 +0200454 int ret;
455
456 ret = ipu_get_resources(ipu_crtc, pdata);
457 if (ret) {
458 dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
459 ret);
460 return ret;
461 }
462
Philipp Zabel43895592015-11-06 11:08:02 +0100463 if (pdata->dp >= 0)
464 dp = IPU_DP_FLOW_SYNC_BG;
465 ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
466 DRM_PLANE_TYPE_PRIMARY);
Liu Yinga7ed3c22015-11-06 22:42:45 +0800467 if (IS_ERR(ipu_crtc->plane[0])) {
468 ret = PTR_ERR(ipu_crtc->plane[0]);
469 goto err_put_resources;
470 }
Philipp Zabel43895592015-11-06 11:08:02 +0100471
Philipp Zabel655b43c2014-03-05 10:20:52 +0100472 ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
Philipp Zabel43895592015-11-06 11:08:02 +0100473 &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
474 ipu_crtc->dev->of_node);
Sascha Hauerf326f792012-09-21 10:07:50 +0200475 if (ret) {
476 dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
477 goto err_put_resources;
478 }
479
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200480 ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
481 if (ret) {
482 dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
483 ret);
484 goto err_remove_crtc;
485 }
486
487 /* If this crtc is using the DP, add an overlay plane */
488 if (pdata->dp >= 0 && pdata->dma[1] > 0) {
Philipp Zabel43895592015-11-06 11:08:02 +0100489 ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
490 IPU_DP_FLOW_SYNC_FG,
491 drm_crtc_mask(&ipu_crtc->base),
492 DRM_PLANE_TYPE_OVERLAY);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200493 if (IS_ERR(ipu_crtc->plane[1]))
494 ipu_crtc->plane[1] = NULL;
495 }
496
497 ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
Philipp Zabel47b1be52013-02-20 10:57:01 +0800498 ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
499 "imx_drm", ipu_crtc);
500 if (ret < 0) {
501 dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200502 goto err_put_plane_res;
Philipp Zabel47b1be52013-02-20 10:57:01 +0800503 }
Lucas Stach411b0332016-02-09 11:43:08 +0100504 /* Only enable IRQ when we actually need it to trigger work. */
505 disable_irq(ipu_crtc->irq);
Philipp Zabel47b1be52013-02-20 10:57:01 +0800506
Lucas Stach0a7ad342016-02-09 14:29:49 +0100507 ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip");
508
Sascha Hauerf326f792012-09-21 10:07:50 +0200509 return 0;
510
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200511err_put_plane_res:
512 ipu_plane_put_resources(ipu_crtc->plane[0]);
513err_remove_crtc:
514 imx_drm_remove_crtc(ipu_crtc->imx_crtc);
Sascha Hauerf326f792012-09-21 10:07:50 +0200515err_put_resources:
516 ipu_put_resources(ipu_crtc);
517
518 return ret;
519}
520
Russell King17b50012013-11-03 11:23:34 +0000521static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
Sascha Hauerf326f792012-09-21 10:07:50 +0200522{
Russell King17b50012013-11-03 11:23:34 +0000523 struct ipu_client_platformdata *pdata = dev->platform_data;
Russell King32266b42013-11-03 12:26:23 +0000524 struct drm_device *drm = data;
Sascha Hauerf326f792012-09-21 10:07:50 +0200525 struct ipu_crtc *ipu_crtc;
526 int ret;
527
Russell King17b50012013-11-03 11:23:34 +0000528 ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
529 if (!ipu_crtc)
530 return -ENOMEM;
531
532 ipu_crtc->dev = dev;
533
Russell King32266b42013-11-03 12:26:23 +0000534 ret = ipu_crtc_init(ipu_crtc, pdata, drm);
Russell King17b50012013-11-03 11:23:34 +0000535 if (ret)
536 return ret;
537
538 dev_set_drvdata(dev, ipu_crtc);
539
540 return 0;
541}
542
543static void ipu_drm_unbind(struct device *dev, struct device *master,
544 void *data)
545{
546 struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
547
548 imx_drm_remove_crtc(ipu_crtc->imx_crtc);
549
Lucas Stach0a7ad342016-02-09 14:29:49 +0100550 destroy_workqueue(ipu_crtc->flip_queue);
Russell King17b50012013-11-03 11:23:34 +0000551 ipu_plane_put_resources(ipu_crtc->plane[0]);
552 ipu_put_resources(ipu_crtc);
553}
554
555static const struct component_ops ipu_crtc_ops = {
556 .bind = ipu_drm_bind,
557 .unbind = ipu_drm_unbind,
558};
559
560static int ipu_drm_probe(struct platform_device *pdev)
561{
Philipp Zabel655b43c2014-03-05 10:20:52 +0100562 struct device *dev = &pdev->dev;
Russell King17b50012013-11-03 11:23:34 +0000563 int ret;
564
Philipp Zabel655b43c2014-03-05 10:20:52 +0100565 if (!dev->platform_data)
Sascha Hauerf326f792012-09-21 10:07:50 +0200566 return -EINVAL;
567
Philipp Zabel655b43c2014-03-05 10:20:52 +0100568 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
Russell King4cdbb4f2013-06-10 16:56:16 +0100569 if (ret)
570 return ret;
Sascha Hauerf326f792012-09-21 10:07:50 +0200571
Philipp Zabel655b43c2014-03-05 10:20:52 +0100572 return component_add(dev, &ipu_crtc_ops);
Sascha Hauerf326f792012-09-21 10:07:50 +0200573}
574
Bill Pemberton8aa1be42012-11-19 13:26:38 -0500575static int ipu_drm_remove(struct platform_device *pdev)
Sascha Hauerf326f792012-09-21 10:07:50 +0200576{
Russell King17b50012013-11-03 11:23:34 +0000577 component_del(&pdev->dev, &ipu_crtc_ops);
Sascha Hauerf326f792012-09-21 10:07:50 +0200578 return 0;
579}
580
581static struct platform_driver ipu_drm_driver = {
582 .driver = {
583 .name = "imx-ipuv3-crtc",
584 },
585 .probe = ipu_drm_probe,
Bill Pemberton99c28f12012-11-19 13:20:51 -0500586 .remove = ipu_drm_remove,
Sascha Hauerf326f792012-09-21 10:07:50 +0200587};
588module_platform_driver(ipu_drm_driver);
589
590MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
591MODULE_DESCRIPTION(DRIVER_DESC);
592MODULE_LICENSE("GPL");
Fabio Estevamce9c1ce2013-08-18 21:40:06 -0300593MODULE_ALIAS("platform:imx-ipuv3-crtc");