These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / imx / ipuv3-plane.c
1 /*
2  * i.MX IPUv3 DP Overlay Planes
3  *
4  * Copyright (C) 2013 Philipp Zabel, 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.
14  */
15
16 #include <drm/drmP.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
19
20 #include "video/imx-ipu-v3.h"
21 #include "ipuv3-plane.h"
22
23 #define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
24
25 static const uint32_t ipu_plane_formats[] = {
26         DRM_FORMAT_ARGB1555,
27         DRM_FORMAT_XRGB1555,
28         DRM_FORMAT_ABGR1555,
29         DRM_FORMAT_XBGR1555,
30         DRM_FORMAT_RGBA5551,
31         DRM_FORMAT_BGRA5551,
32         DRM_FORMAT_ARGB4444,
33         DRM_FORMAT_ARGB8888,
34         DRM_FORMAT_XRGB8888,
35         DRM_FORMAT_ABGR8888,
36         DRM_FORMAT_XBGR8888,
37         DRM_FORMAT_RGBA8888,
38         DRM_FORMAT_RGBX8888,
39         DRM_FORMAT_BGRA8888,
40         DRM_FORMAT_BGRA8888,
41         DRM_FORMAT_YUYV,
42         DRM_FORMAT_YVYU,
43         DRM_FORMAT_YUV420,
44         DRM_FORMAT_YVU420,
45 };
46
47 int ipu_plane_irq(struct ipu_plane *ipu_plane)
48 {
49         return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
50                                      IPU_IRQ_EOF);
51 }
52
53 static int calc_vref(struct drm_display_mode *mode)
54 {
55         unsigned long htotal, vtotal;
56
57         htotal = mode->htotal;
58         vtotal = mode->vtotal;
59
60         if (!htotal || !vtotal)
61                 return 60;
62
63         return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
64 }
65
66 static inline int calc_bandwidth(int width, int height, unsigned int vref)
67 {
68         return width * height * vref;
69 }
70
71 int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
72                        int x, int y)
73 {
74         struct drm_gem_cma_object *cma_obj;
75         unsigned long eba;
76         int active;
77
78         cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
79         if (!cma_obj) {
80                 DRM_DEBUG_KMS("entry is null.\n");
81                 return -EFAULT;
82         }
83
84         dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
85                 &cma_obj->paddr, x, y);
86
87         eba = cma_obj->paddr + fb->offsets[0] +
88               fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
89
90         if (ipu_plane->enabled) {
91                 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
92                 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
93                 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
94         } else {
95                 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
96                 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
97         }
98
99         /* cache offsets for subsequent pageflips */
100         ipu_plane->x = x;
101         ipu_plane->y = y;
102
103         return 0;
104 }
105
106 int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
107                        struct drm_display_mode *mode,
108                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
109                        unsigned int crtc_w, unsigned int crtc_h,
110                        uint32_t src_x, uint32_t src_y,
111                        uint32_t src_w, uint32_t src_h, bool interlaced)
112 {
113         struct device *dev = ipu_plane->base.dev->dev;
114         int ret;
115
116         /* no scaling */
117         if (src_w != crtc_w || src_h != crtc_h)
118                 return -EINVAL;
119
120         /* clip to crtc bounds */
121         if (crtc_x < 0) {
122                 if (-crtc_x > crtc_w)
123                         return -EINVAL;
124                 src_x += -crtc_x;
125                 src_w -= -crtc_x;
126                 crtc_w -= -crtc_x;
127                 crtc_x = 0;
128         }
129         if (crtc_y < 0) {
130                 if (-crtc_y > crtc_h)
131                         return -EINVAL;
132                 src_y += -crtc_y;
133                 src_h -= -crtc_y;
134                 crtc_h -= -crtc_y;
135                 crtc_y = 0;
136         }
137         if (crtc_x + crtc_w > mode->hdisplay) {
138                 if (crtc_x > mode->hdisplay)
139                         return -EINVAL;
140                 crtc_w = mode->hdisplay - crtc_x;
141                 src_w = crtc_w;
142         }
143         if (crtc_y + crtc_h > mode->vdisplay) {
144                 if (crtc_y > mode->vdisplay)
145                         return -EINVAL;
146                 crtc_h = mode->vdisplay - crtc_y;
147                 src_h = crtc_h;
148         }
149         /* full plane minimum width is 13 pixels */
150         if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
151                 return -EINVAL;
152         if (crtc_h < 2)
153                 return -EINVAL;
154
155         /*
156          * since we cannot touch active IDMAC channels, we do not support
157          * resizing the enabled plane or changing its format
158          */
159         if (ipu_plane->enabled) {
160                 if (src_w != ipu_plane->w || src_h != ipu_plane->h ||
161                     fb->pixel_format != ipu_plane->base.fb->pixel_format)
162                         return -EINVAL;
163
164                 return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
165         }
166
167         switch (ipu_plane->dp_flow) {
168         case IPU_DP_FLOW_SYNC_BG:
169                 ret = ipu_dp_setup_channel(ipu_plane->dp,
170                                 IPUV3_COLORSPACE_RGB,
171                                 IPUV3_COLORSPACE_RGB);
172                 if (ret) {
173                         dev_err(dev,
174                                 "initializing display processor failed with %d\n",
175                                 ret);
176                         return ret;
177                 }
178                 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
179                 break;
180         case IPU_DP_FLOW_SYNC_FG:
181                 ipu_dp_setup_channel(ipu_plane->dp,
182                                 ipu_drm_fourcc_to_colorspace(fb->pixel_format),
183                                 IPUV3_COLORSPACE_UNKNOWN);
184                 ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
185                 /* Enable local alpha on partial plane */
186                 switch (fb->pixel_format) {
187                 case DRM_FORMAT_ARGB1555:
188                 case DRM_FORMAT_ABGR1555:
189                 case DRM_FORMAT_RGBA5551:
190                 case DRM_FORMAT_BGRA5551:
191                 case DRM_FORMAT_ARGB4444:
192                 case DRM_FORMAT_ARGB8888:
193                 case DRM_FORMAT_ABGR8888:
194                 case DRM_FORMAT_RGBA8888:
195                 case DRM_FORMAT_BGRA8888:
196                         ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
197                         break;
198                 default:
199                         break;
200                 }
201         }
202
203         ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
204         if (ret) {
205                 dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
206                 return ret;
207         }
208
209         ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
210                         calc_bandwidth(crtc_w, crtc_h,
211                                        calc_vref(mode)), 64);
212         if (ret) {
213                 dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
214                 return ret;
215         }
216
217         ipu_cpmem_zero(ipu_plane->ipu_ch);
218         ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
219         ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
220         if (ret < 0) {
221                 dev_err(dev, "unsupported pixel format 0x%08x\n",
222                         fb->pixel_format);
223                 return ret;
224         }
225         ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
226         ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
227         ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
228
229         ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
230         if (ret < 0)
231                 return ret;
232         if (interlaced)
233                 ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
234
235         ipu_plane->w = src_w;
236         ipu_plane->h = src_h;
237
238         return 0;
239 }
240
241 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
242 {
243         if (!IS_ERR_OR_NULL(ipu_plane->dp))
244                 ipu_dp_put(ipu_plane->dp);
245         if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
246                 ipu_dmfc_put(ipu_plane->dmfc);
247         if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
248                 ipu_idmac_put(ipu_plane->ipu_ch);
249 }
250
251 int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
252 {
253         int ret;
254
255         ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
256         if (IS_ERR(ipu_plane->ipu_ch)) {
257                 ret = PTR_ERR(ipu_plane->ipu_ch);
258                 DRM_ERROR("failed to get idmac channel: %d\n", ret);
259                 return ret;
260         }
261
262         ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
263         if (IS_ERR(ipu_plane->dmfc)) {
264                 ret = PTR_ERR(ipu_plane->dmfc);
265                 DRM_ERROR("failed to get dmfc: ret %d\n", ret);
266                 goto err_out;
267         }
268
269         if (ipu_plane->dp_flow >= 0) {
270                 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
271                 if (IS_ERR(ipu_plane->dp)) {
272                         ret = PTR_ERR(ipu_plane->dp);
273                         DRM_ERROR("failed to get dp flow: %d\n", ret);
274                         goto err_out;
275                 }
276         }
277
278         return 0;
279 err_out:
280         ipu_plane_put_resources(ipu_plane);
281
282         return ret;
283 }
284
285 void ipu_plane_enable(struct ipu_plane *ipu_plane)
286 {
287         if (ipu_plane->dp)
288                 ipu_dp_enable(ipu_plane->ipu);
289         ipu_dmfc_enable_channel(ipu_plane->dmfc);
290         ipu_idmac_enable_channel(ipu_plane->ipu_ch);
291         if (ipu_plane->dp)
292                 ipu_dp_enable_channel(ipu_plane->dp);
293
294         ipu_plane->enabled = true;
295 }
296
297 void ipu_plane_disable(struct ipu_plane *ipu_plane)
298 {
299         ipu_plane->enabled = false;
300
301         ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
302
303         if (ipu_plane->dp)
304                 ipu_dp_disable_channel(ipu_plane->dp);
305         ipu_idmac_disable_channel(ipu_plane->ipu_ch);
306         ipu_dmfc_disable_channel(ipu_plane->dmfc);
307         if (ipu_plane->dp)
308                 ipu_dp_disable(ipu_plane->ipu);
309 }
310
311 /*
312  * drm_plane API
313  */
314
315 static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
316                             struct drm_framebuffer *fb, int crtc_x, int crtc_y,
317                             unsigned int crtc_w, unsigned int crtc_h,
318                             uint32_t src_x, uint32_t src_y,
319                             uint32_t src_w, uint32_t src_h)
320 {
321         struct ipu_plane *ipu_plane = to_ipu_plane(plane);
322         int ret = 0;
323
324         DRM_DEBUG_KMS("plane - %p\n", plane);
325
326         if (!ipu_plane->enabled)
327                 ret = ipu_plane_get_resources(ipu_plane);
328         if (ret < 0)
329                 return ret;
330
331         ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
332                         crtc_x, crtc_y, crtc_w, crtc_h,
333                         src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
334                         false);
335         if (ret < 0) {
336                 ipu_plane_put_resources(ipu_plane);
337                 return ret;
338         }
339
340         if (crtc != plane->crtc)
341                 dev_info(plane->dev->dev, "crtc change: %p -> %p\n",
342                                 plane->crtc, crtc);
343         plane->crtc = crtc;
344
345         if (!ipu_plane->enabled)
346                 ipu_plane_enable(ipu_plane);
347
348         return 0;
349 }
350
351 static int ipu_disable_plane(struct drm_plane *plane)
352 {
353         struct ipu_plane *ipu_plane = to_ipu_plane(plane);
354
355         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
356
357         if (ipu_plane->enabled)
358                 ipu_plane_disable(ipu_plane);
359
360         ipu_plane_put_resources(ipu_plane);
361
362         return 0;
363 }
364
365 static void ipu_plane_destroy(struct drm_plane *plane)
366 {
367         struct ipu_plane *ipu_plane = to_ipu_plane(plane);
368
369         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
370
371         ipu_disable_plane(plane);
372         drm_plane_cleanup(plane);
373         kfree(ipu_plane);
374 }
375
376 static struct drm_plane_funcs ipu_plane_funcs = {
377         .update_plane   = ipu_update_plane,
378         .disable_plane  = ipu_disable_plane,
379         .destroy        = ipu_plane_destroy,
380 };
381
382 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
383                                  int dma, int dp, unsigned int possible_crtcs,
384                                  enum drm_plane_type type)
385 {
386         struct ipu_plane *ipu_plane;
387         int ret;
388
389         DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
390                       dma, dp, possible_crtcs);
391
392         ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
393         if (!ipu_plane) {
394                 DRM_ERROR("failed to allocate plane\n");
395                 return ERR_PTR(-ENOMEM);
396         }
397
398         ipu_plane->ipu = ipu;
399         ipu_plane->dma = dma;
400         ipu_plane->dp_flow = dp;
401
402         ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
403                                        &ipu_plane_funcs, ipu_plane_formats,
404                                        ARRAY_SIZE(ipu_plane_formats), type);
405         if (ret) {
406                 DRM_ERROR("failed to initialize plane\n");
407                 kfree(ipu_plane);
408                 return ERR_PTR(ret);
409         }
410
411         return ipu_plane;
412 }