blob: 1124200bb280d8f58eb59e5370aa91b7916bb134 [file] [log] [blame]
Boris Brezillon1a396782015-01-06 11:13:28 +01001/*
2 * Copyright (C) 2014 Free Electrons
3 * Copyright (C) 2014 Atmel
4 *
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "atmel_hlcdc_dc.h"
21
Boris Brezillon2389fc12015-02-05 16:32:33 +010022/**
23 * Atmel HLCDC Plane state structure.
24 *
25 * @base: DRM plane state
26 * @crtc_x: x position of the plane relative to the CRTC
27 * @crtc_y: y position of the plane relative to the CRTC
28 * @crtc_w: visible width of the plane
29 * @crtc_h: visible height of the plane
30 * @src_x: x buffer position
31 * @src_y: y buffer position
32 * @src_w: buffer width
33 * @src_h: buffer height
34 * @alpha: alpha blending of the plane
Boris Brezillon9a45d332017-02-06 18:57:19 +010035 * @disc_x: x discard position
36 * @disc_y: y discard position
37 * @disc_w: discard width
38 * @disc_h: discard height
Boris Brezillon2389fc12015-02-05 16:32:33 +010039 * @bpp: bytes per pixel deduced from pixel_format
40 * @offsets: offsets to apply to the GEM buffers
41 * @xstride: value to add to the pixel pointer between each line
42 * @pstride: value to add to the pixel pointer between each pixel
43 * @nplanes: number of planes (deduced from pixel_format)
Boris Brezillon9a45d332017-02-06 18:57:19 +010044 * @dscrs: DMA descriptors
Boris Brezillon2389fc12015-02-05 16:32:33 +010045 */
46struct atmel_hlcdc_plane_state {
47 struct drm_plane_state base;
48 int crtc_x;
49 int crtc_y;
50 unsigned int crtc_w;
51 unsigned int crtc_h;
52 uint32_t src_x;
53 uint32_t src_y;
54 uint32_t src_w;
55 uint32_t src_h;
56
57 u8 alpha;
58
Boris Brezillon59570172015-02-06 16:25:06 +010059 int disc_x;
60 int disc_y;
61 int disc_w;
62 int disc_h;
63
Boris Brezillonebab87a2016-03-15 18:01:08 +010064 int ahb_id;
65
Boris Brezillon2389fc12015-02-05 16:32:33 +010066 /* These fields are private and should not be touched */
Boris Brezillon9a45d332017-02-06 18:57:19 +010067 int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
68 unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
69 int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
70 int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
Boris Brezillon2389fc12015-02-05 16:32:33 +010071 int nplanes;
Boris Brezillon9a45d332017-02-06 18:57:19 +010072
73 /* DMA descriptors. */
74 struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
Boris Brezillon2389fc12015-02-05 16:32:33 +010075};
76
77static inline struct atmel_hlcdc_plane_state *
78drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
79{
80 return container_of(s, struct atmel_hlcdc_plane_state, base);
81}
82
Boris Brezillon1a396782015-01-06 11:13:28 +010083#define SUBPIXEL_MASK 0xffff
84
85static uint32_t rgb_formats[] = {
86 DRM_FORMAT_XRGB4444,
87 DRM_FORMAT_ARGB4444,
88 DRM_FORMAT_RGBA4444,
89 DRM_FORMAT_ARGB1555,
90 DRM_FORMAT_RGB565,
91 DRM_FORMAT_RGB888,
92 DRM_FORMAT_XRGB8888,
93 DRM_FORMAT_ARGB8888,
94 DRM_FORMAT_RGBA8888,
95};
96
97struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
98 .formats = rgb_formats,
99 .nformats = ARRAY_SIZE(rgb_formats),
100};
101
102static uint32_t rgb_and_yuv_formats[] = {
103 DRM_FORMAT_XRGB4444,
104 DRM_FORMAT_ARGB4444,
105 DRM_FORMAT_RGBA4444,
106 DRM_FORMAT_ARGB1555,
107 DRM_FORMAT_RGB565,
108 DRM_FORMAT_RGB888,
109 DRM_FORMAT_XRGB8888,
110 DRM_FORMAT_ARGB8888,
111 DRM_FORMAT_RGBA8888,
112 DRM_FORMAT_AYUV,
113 DRM_FORMAT_YUYV,
114 DRM_FORMAT_UYVY,
115 DRM_FORMAT_YVYU,
116 DRM_FORMAT_VYUY,
117 DRM_FORMAT_NV21,
118 DRM_FORMAT_NV61,
119 DRM_FORMAT_YUV422,
120 DRM_FORMAT_YUV420,
121};
122
123struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
124 .formats = rgb_and_yuv_formats,
125 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
126};
127
128static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
129{
130 switch (format) {
131 case DRM_FORMAT_XRGB4444:
132 *mode = ATMEL_HLCDC_XRGB4444_MODE;
133 break;
134 case DRM_FORMAT_ARGB4444:
135 *mode = ATMEL_HLCDC_ARGB4444_MODE;
136 break;
137 case DRM_FORMAT_RGBA4444:
138 *mode = ATMEL_HLCDC_RGBA4444_MODE;
139 break;
140 case DRM_FORMAT_RGB565:
141 *mode = ATMEL_HLCDC_RGB565_MODE;
142 break;
143 case DRM_FORMAT_RGB888:
144 *mode = ATMEL_HLCDC_RGB888_MODE;
145 break;
146 case DRM_FORMAT_ARGB1555:
147 *mode = ATMEL_HLCDC_ARGB1555_MODE;
148 break;
149 case DRM_FORMAT_XRGB8888:
150 *mode = ATMEL_HLCDC_XRGB8888_MODE;
151 break;
152 case DRM_FORMAT_ARGB8888:
153 *mode = ATMEL_HLCDC_ARGB8888_MODE;
154 break;
155 case DRM_FORMAT_RGBA8888:
156 *mode = ATMEL_HLCDC_RGBA8888_MODE;
157 break;
158 case DRM_FORMAT_AYUV:
159 *mode = ATMEL_HLCDC_AYUV_MODE;
160 break;
161 case DRM_FORMAT_YUYV:
162 *mode = ATMEL_HLCDC_YUYV_MODE;
163 break;
164 case DRM_FORMAT_UYVY:
165 *mode = ATMEL_HLCDC_UYVY_MODE;
166 break;
167 case DRM_FORMAT_YVYU:
168 *mode = ATMEL_HLCDC_YVYU_MODE;
169 break;
170 case DRM_FORMAT_VYUY:
171 *mode = ATMEL_HLCDC_VYUY_MODE;
172 break;
173 case DRM_FORMAT_NV21:
174 *mode = ATMEL_HLCDC_NV21_MODE;
175 break;
176 case DRM_FORMAT_NV61:
177 *mode = ATMEL_HLCDC_NV61_MODE;
178 break;
179 case DRM_FORMAT_YUV420:
180 *mode = ATMEL_HLCDC_YUV420_MODE;
181 break;
182 case DRM_FORMAT_YUV422:
183 *mode = ATMEL_HLCDC_YUV422_MODE;
184 break;
185 default:
186 return -ENOTSUPP;
187 }
188
189 return 0;
190}
191
Boris Brezillon2389fc12015-02-05 16:32:33 +0100192static bool atmel_hlcdc_format_embeds_alpha(u32 format)
Boris Brezillon1a396782015-01-06 11:13:28 +0100193{
194 int i;
195
196 for (i = 0; i < sizeof(format); i++) {
197 char tmp = (format >> (8 * i)) & 0xff;
198
199 if (tmp == 'A')
200 return true;
201 }
202
203 return false;
204}
205
206static u32 heo_downscaling_xcoef[] = {
207 0x11343311,
208 0x000000f7,
209 0x1635300c,
210 0x000000f9,
211 0x1b362c08,
212 0x000000fb,
213 0x1f372804,
214 0x000000fe,
215 0x24382400,
216 0x00000000,
217 0x28371ffe,
218 0x00000004,
219 0x2c361bfb,
220 0x00000008,
221 0x303516f9,
222 0x0000000c,
223};
224
225static u32 heo_downscaling_ycoef[] = {
226 0x00123737,
227 0x00173732,
228 0x001b382d,
229 0x001f3928,
230 0x00243824,
231 0x0028391f,
232 0x002d381b,
233 0x00323717,
234};
235
236static u32 heo_upscaling_xcoef[] = {
237 0xf74949f7,
238 0x00000000,
239 0xf55f33fb,
240 0x000000fe,
241 0xf5701efe,
242 0x000000ff,
243 0xf87c0dff,
244 0x00000000,
245 0x00800000,
246 0x00000000,
247 0x0d7cf800,
248 0x000000ff,
249 0x1e70f5ff,
250 0x000000fe,
251 0x335ff5fe,
252 0x000000fb,
253};
254
255static u32 heo_upscaling_ycoef[] = {
256 0x00004040,
257 0x00075920,
258 0x00056f0c,
259 0x00027b03,
260 0x00008000,
261 0x00037b02,
262 0x000c6f05,
263 0x00205907,
264};
265
Boris Brezillon9a45d332017-02-06 18:57:19 +0100266#define ATMEL_HLCDC_XPHIDEF 4
267#define ATMEL_HLCDC_YPHIDEF 4
268
269static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
270 u32 dstsize,
271 u32 phidef)
272{
273 u32 factor, max_memsize;
274
275 factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
276 max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
277
278 if (max_memsize > srcsize - 1)
279 factor--;
280
281 return factor;
282}
283
284static void
285atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
286 const u32 *coeff_tab, int size,
287 unsigned int cfg_offs)
288{
289 int i;
290
291 for (i = 0; i < size; i++)
292 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
293 coeff_tab[i]);
294}
295
296void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
297 struct atmel_hlcdc_plane_state *state)
298{
299 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
300 u32 xfactor, yfactor;
301
302 if (!desc->layout.scaler_config)
303 return;
304
305 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
306 atmel_hlcdc_layer_write_cfg(&plane->layer,
307 desc->layout.scaler_config, 0);
308 return;
309 }
310
311 if (desc->layout.phicoeffs.x) {
312 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
313 state->crtc_w,
314 ATMEL_HLCDC_XPHIDEF);
315
316 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
317 state->crtc_h,
318 ATMEL_HLCDC_YPHIDEF);
319
320 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
321 state->crtc_w < state->src_w ?
322 heo_downscaling_xcoef :
323 heo_upscaling_xcoef,
324 ARRAY_SIZE(heo_upscaling_xcoef),
325 desc->layout.phicoeffs.x);
326
327 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
328 state->crtc_h < state->src_h ?
329 heo_downscaling_ycoef :
330 heo_upscaling_ycoef,
331 ARRAY_SIZE(heo_upscaling_ycoef),
332 desc->layout.phicoeffs.y);
333 } else {
334 xfactor = (1024 * state->src_w) / state->crtc_w;
335 yfactor = (1024 * state->src_h) / state->crtc_h;
336 }
337
338 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
339 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
340 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
341 yfactor));
342}
343
Boris Brezillon1a396782015-01-06 11:13:28 +0100344static void
345atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100346 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100347{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100348 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100349
Boris Brezillon9a45d332017-02-06 18:57:19 +0100350 if (desc->layout.size)
351 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
352 ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
353 state->crtc_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100354
Boris Brezillon9a45d332017-02-06 18:57:19 +0100355 if (desc->layout.memsize)
356 atmel_hlcdc_layer_write_cfg(&plane->layer,
357 desc->layout.memsize,
358 ATMEL_HLCDC_LAYER_SIZE(state->src_w,
359 state->src_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100360
Boris Brezillon9a45d332017-02-06 18:57:19 +0100361 if (desc->layout.pos)
362 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
363 ATMEL_HLCDC_LAYER_POS(state->crtc_x,
364 state->crtc_y));
Boris Brezillon1a396782015-01-06 11:13:28 +0100365
Boris Brezillon9a45d332017-02-06 18:57:19 +0100366 atmel_hlcdc_plane_setup_scaler(plane, state);
Boris Brezillon1a396782015-01-06 11:13:28 +0100367}
368
369static void
370atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100371 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100372{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100373 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
374 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
375 u32 format = state->base.fb->format->format;
376
377 /*
378 * Rotation optimization is not working on RGB888 (rotation is still
379 * working but without any optimization).
380 */
381 if (format == DRM_FORMAT_RGB888)
382 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
383
384 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
385 cfg);
386
387 cfg = ATMEL_HLCDC_LAYER_DMA;
Boris Brezillon1a396782015-01-06 11:13:28 +0100388
389 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
390 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
391 ATMEL_HLCDC_LAYER_ITER;
392
Boris Brezillon9a45d332017-02-06 18:57:19 +0100393 if (atmel_hlcdc_format_embeds_alpha(format))
Boris Brezillon1a396782015-01-06 11:13:28 +0100394 cfg |= ATMEL_HLCDC_LAYER_LAEN;
395 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100396 cfg |= ATMEL_HLCDC_LAYER_GAEN |
397 ATMEL_HLCDC_LAYER_GA(state->alpha);
Boris Brezillon1a396782015-01-06 11:13:28 +0100398 }
399
Boris Brezillon9a45d332017-02-06 18:57:19 +0100400 if (state->disc_h && state->disc_w)
401 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
Boris Brezillon1a396782015-01-06 11:13:28 +0100402
Boris Brezillon9a45d332017-02-06 18:57:19 +0100403 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
404 cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100405}
406
407static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100408 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100409{
410 u32 cfg;
411 int ret;
412
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200413 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100414 &cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100415 if (ret)
416 return;
417
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200418 if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
419 state->base.fb->format->format == DRM_FORMAT_NV61) &&
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300420 drm_rotation_90_or_270(state->base.rotation))
Boris Brezillon1a396782015-01-06 11:13:28 +0100421 cfg |= ATMEL_HLCDC_YUV422ROT;
422
Boris Brezillon9a45d332017-02-06 18:57:19 +0100423 atmel_hlcdc_layer_write_cfg(&plane->layer,
424 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100425}
426
427static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100428 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100429{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100430 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
431 struct drm_framebuffer *fb = state->base.fb;
432 u32 sr;
Boris Brezillon1a396782015-01-06 11:13:28 +0100433 int i;
434
Boris Brezillon9a45d332017-02-06 18:57:19 +0100435 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100436
Boris Brezillon2389fc12015-02-05 16:32:33 +0100437 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100438 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
439
440 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
441
442 atmel_hlcdc_layer_write_reg(&plane->layer,
443 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
444 state->dscrs[i]->self);
445
446 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
447 atmel_hlcdc_layer_write_reg(&plane->layer,
448 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
449 state->dscrs[i]->addr);
450 atmel_hlcdc_layer_write_reg(&plane->layer,
451 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
452 state->dscrs[i]->ctrl);
453 atmel_hlcdc_layer_write_reg(&plane->layer,
454 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
455 state->dscrs[i]->self);
Boris Brezillon1a396782015-01-06 11:13:28 +0100456 }
457
Boris Brezillon9a45d332017-02-06 18:57:19 +0100458 if (desc->layout.xstride[i])
459 atmel_hlcdc_layer_write_cfg(&plane->layer,
460 desc->layout.xstride[i],
461 state->xstride[i]);
462
463 if (desc->layout.pstride[i])
464 atmel_hlcdc_layer_write_cfg(&plane->layer,
465 desc->layout.pstride[i],
466 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100467 }
468}
469
Boris Brezillonebab87a2016-03-15 18:01:08 +0100470int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
471{
472 unsigned int ahb_load[2] = { };
473 struct drm_plane *plane;
474
475 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
476 struct atmel_hlcdc_plane_state *plane_state;
477 struct drm_plane_state *plane_s;
478 unsigned int pixels, load = 0;
479 int i;
480
481 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
482 if (IS_ERR(plane_s))
483 return PTR_ERR(plane_s);
484
485 plane_state =
486 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
487
488 pixels = (plane_state->src_w * plane_state->src_h) -
489 (plane_state->disc_w * plane_state->disc_h);
490
491 for (i = 0; i < plane_state->nplanes; i++)
492 load += pixels * plane_state->bpp[i];
493
494 if (ahb_load[0] <= ahb_load[1])
495 plane_state->ahb_id = 0;
496 else
497 plane_state->ahb_id = 1;
498
499 ahb_load[plane_state->ahb_id] += load;
500 }
501
502 return 0;
503}
504
Boris Brezillon59570172015-02-06 16:25:06 +0100505int
506atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
507{
508 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
509 const struct atmel_hlcdc_layer_cfg_layout *layout;
510 struct atmel_hlcdc_plane_state *primary_state;
511 struct drm_plane_state *primary_s;
512 struct atmel_hlcdc_plane *primary;
513 struct drm_plane *ovl;
514
515 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
516 layout = &primary->layer.desc->layout;
517 if (!layout->disc_pos || !layout->disc_size)
518 return 0;
519
520 primary_s = drm_atomic_get_plane_state(c_state->state,
521 &primary->base);
522 if (IS_ERR(primary_s))
523 return PTR_ERR(primary_s);
524
525 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
526
527 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
528 struct atmel_hlcdc_plane_state *ovl_state;
529 struct drm_plane_state *ovl_s;
530
531 if (ovl == c_state->crtc->primary)
532 continue;
533
534 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
535 if (IS_ERR(ovl_s))
536 return PTR_ERR(ovl_s);
537
538 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
539
540 if (!ovl_s->fb ||
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200541 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
Boris Brezillon59570172015-02-06 16:25:06 +0100542 ovl_state->alpha != 255)
543 continue;
544
545 /* TODO: implement a smarter hidden area detection */
546 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
547 continue;
548
549 disc_x = ovl_state->crtc_x;
550 disc_y = ovl_state->crtc_y;
551 disc_h = ovl_state->crtc_h;
552 disc_w = ovl_state->crtc_w;
553 }
554
Boris Brezillon59570172015-02-06 16:25:06 +0100555 primary_state->disc_x = disc_x;
556 primary_state->disc_y = disc_y;
557 primary_state->disc_w = disc_w;
558 primary_state->disc_h = disc_h;
Boris Brezillon59570172015-02-06 16:25:06 +0100559
560 return 0;
561}
562
563static void
564atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
565 struct atmel_hlcdc_plane_state *state)
566{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100567 const struct atmel_hlcdc_layer_cfg_layout *layout;
Boris Brezillon59570172015-02-06 16:25:06 +0100568
Boris Brezillon9a45d332017-02-06 18:57:19 +0100569 layout = &plane->layer.desc->layout;
570 if (!layout->disc_pos || !layout->disc_size)
Boris Brezillon59570172015-02-06 16:25:06 +0100571 return;
572
Boris Brezillon9a45d332017-02-06 18:57:19 +0100573 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
574 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
575 state->disc_y));
Boris Brezillon59570172015-02-06 16:25:06 +0100576
Boris Brezillon9a45d332017-02-06 18:57:19 +0100577 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
578 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
579 state->disc_h));
Boris Brezillon59570172015-02-06 16:25:06 +0100580}
581
Boris Brezillon2389fc12015-02-05 16:32:33 +0100582static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
583 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100584{
585 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100586 struct atmel_hlcdc_plane_state *state =
587 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100588 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100589 struct drm_framebuffer *fb = state->base.fb;
590 const struct drm_display_mode *mode;
591 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100592 unsigned int patched_crtc_w;
593 unsigned int patched_crtc_h;
594 unsigned int patched_src_w;
595 unsigned int patched_src_h;
596 unsigned int tmp;
597 int x_offset = 0;
598 int y_offset = 0;
599 int hsub = 1;
600 int vsub = 1;
601 int i;
602
Boris Brezillon2389fc12015-02-05 16:32:33 +0100603 if (!state->base.crtc || !fb)
604 return 0;
605
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100606 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100607 mode = &crtc_state->adjusted_mode;
608
609 state->src_x = s->src_x;
610 state->src_y = s->src_y;
611 state->src_h = s->src_h;
612 state->src_w = s->src_w;
613 state->crtc_x = s->crtc_x;
614 state->crtc_y = s->crtc_y;
615 state->crtc_h = s->crtc_h;
616 state->crtc_w = s->crtc_w;
617 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100618 SUBPIXEL_MASK)
619 return -EINVAL;
620
Boris Brezillon2389fc12015-02-05 16:32:33 +0100621 state->src_x >>= 16;
622 state->src_y >>= 16;
623 state->src_w >>= 16;
624 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100625
Ville Syrjäläbcb0b462016-12-14 23:30:22 +0200626 state->nplanes = fb->format->num_planes;
Boris Brezillon9a45d332017-02-06 18:57:19 +0100627 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100628 return -EINVAL;
629
630 /*
631 * Swap width and size in case of 90 or 270 degrees rotation
632 */
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300633 if (drm_rotation_90_or_270(state->base.rotation)) {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100634 tmp = state->crtc_w;
635 state->crtc_w = state->crtc_h;
636 state->crtc_h = tmp;
637 tmp = state->src_w;
638 state->src_w = state->src_h;
639 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100640 }
641
Boris Brezillon2389fc12015-02-05 16:32:33 +0100642 if (state->crtc_x + state->crtc_w > mode->hdisplay)
643 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100644 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100645 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100646
Boris Brezillon2389fc12015-02-05 16:32:33 +0100647 if (state->crtc_x < 0) {
648 patched_crtc_w += state->crtc_x;
649 x_offset = -state->crtc_x;
650 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100651 }
652
Boris Brezillon2389fc12015-02-05 16:32:33 +0100653 if (state->crtc_y + state->crtc_h > mode->vdisplay)
654 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100655 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100656 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100657
Boris Brezillon2389fc12015-02-05 16:32:33 +0100658 if (state->crtc_y < 0) {
659 patched_crtc_h += state->crtc_y;
660 y_offset = -state->crtc_y;
661 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100662 }
663
Boris Brezillon2389fc12015-02-05 16:32:33 +0100664 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
665 state->crtc_w);
666 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
667 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100668
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200669 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
670 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100671
Boris Brezillon2389fc12015-02-05 16:32:33 +0100672 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100673 unsigned int offset = 0;
674 int xdiv = i ? hsub : 1;
675 int ydiv = i ? vsub : 1;
676
Ville Syrjälä353c8592016-12-14 23:30:57 +0200677 state->bpp[i] = fb->format->cpp[i];
Boris Brezillon2389fc12015-02-05 16:32:33 +0100678 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100679 return -EINVAL;
680
Robert Fossc2c446a2017-05-19 16:50:17 -0400681 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
682 case DRM_MODE_ROTATE_90:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100683 offset = ((y_offset + state->src_y + patched_src_w - 1) /
684 ydiv) * fb->pitches[i];
685 offset += ((x_offset + state->src_x) / xdiv) *
686 state->bpp[i];
687 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
688 fb->pitches[i];
689 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100690 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400691 case DRM_MODE_ROTATE_180:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100692 offset = ((y_offset + state->src_y + patched_src_h - 1) /
693 ydiv) * fb->pitches[i];
694 offset += ((x_offset + state->src_x + patched_src_w - 1) /
695 xdiv) * state->bpp[i];
696 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
697 state->bpp[i]) - fb->pitches[i];
698 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100699 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400700 case DRM_MODE_ROTATE_270:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100701 offset = ((y_offset + state->src_y) / ydiv) *
702 fb->pitches[i];
703 offset += ((x_offset + state->src_x + patched_src_h - 1) /
704 xdiv) * state->bpp[i];
705 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
706 fb->pitches[i]) -
707 (2 * state->bpp[i]);
708 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100709 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400710 case DRM_MODE_ROTATE_0:
Boris Brezillon1a396782015-01-06 11:13:28 +0100711 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100712 offset = ((y_offset + state->src_y) / ydiv) *
713 fb->pitches[i];
714 offset += ((x_offset + state->src_x) / xdiv) *
715 state->bpp[i];
716 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100717 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100718 state->bpp[i]);
719 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100720 break;
721 }
722
Boris Brezillon2389fc12015-02-05 16:32:33 +0100723 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100724 }
725
Boris Brezillon2389fc12015-02-05 16:32:33 +0100726 state->src_w = patched_src_w;
727 state->src_h = patched_src_h;
728 state->crtc_w = patched_crtc_w;
729 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100730
Boris Brezillon9a45d332017-02-06 18:57:19 +0100731 if (!desc->layout.size &&
Boris Brezillon2389fc12015-02-05 16:32:33 +0100732 (mode->hdisplay != state->crtc_w ||
733 mode->vdisplay != state->crtc_h))
734 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100735
Boris Brezillon9a45d332017-02-06 18:57:19 +0100736 if (desc->max_height && state->crtc_h > desc->max_height)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100737 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100738
Boris Brezillon9a45d332017-02-06 18:57:19 +0100739 if (desc->max_width && state->crtc_w > desc->max_width)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100740 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100741
Boris Brezillon2389fc12015-02-05 16:32:33 +0100742 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
Boris Brezillon9a45d332017-02-06 18:57:19 +0100743 (!desc->layout.memsize ||
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200744 atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
Boris Brezillon2389fc12015-02-05 16:32:33 +0100745 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100746
Boris Brezillon2389fc12015-02-05 16:32:33 +0100747 if (state->crtc_x < 0 || state->crtc_y < 0)
748 return -EINVAL;
749
750 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
751 state->crtc_h + state->crtc_y > mode->vdisplay)
752 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100753
754 return 0;
755}
756
Boris Brezillon2389fc12015-02-05 16:32:33 +0100757static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
758 struct drm_plane_state *old_s)
759{
760 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
761 struct atmel_hlcdc_plane_state *state =
762 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100763 u32 sr;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100764
765 if (!p->state->crtc || !p->state->fb)
766 return;
767
768 atmel_hlcdc_plane_update_pos_and_size(plane, state);
769 atmel_hlcdc_plane_update_general_settings(plane, state);
770 atmel_hlcdc_plane_update_format(plane, state);
771 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100772 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100773
Boris Brezillon9a45d332017-02-06 18:57:19 +0100774 /* Enable the overrun interrupts. */
775 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
776 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
777 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
778 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
779
780 /* Apply the new config at the next SOF event. */
781 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
782 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
783 ATMEL_HLCDC_LAYER_UPDATE |
784 (sr & ATMEL_HLCDC_LAYER_EN ?
785 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
Boris Brezillon2389fc12015-02-05 16:32:33 +0100786}
787
788static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
789 struct drm_plane_state *old_state)
790{
791 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
792
Boris Brezillon9a45d332017-02-06 18:57:19 +0100793 /* Disable interrupts */
794 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
795 0xffffffff);
796
797 /* Disable the layer */
798 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
799 ATMEL_HLCDC_LAYER_RST |
800 ATMEL_HLCDC_LAYER_A2Q |
801 ATMEL_HLCDC_LAYER_UPDATE);
802
803 /* Clear all pending interrupts */
804 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100805}
806
807static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
808{
809 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
810
811 if (plane->base.fb)
812 drm_framebuffer_unreference(plane->base.fb);
813
Boris Brezillon1a396782015-01-06 11:13:28 +0100814 drm_plane_cleanup(p);
Boris Brezillon1a396782015-01-06 11:13:28 +0100815}
816
Boris Brezillon2389fc12015-02-05 16:32:33 +0100817static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
818 struct drm_plane_state *s,
819 struct drm_property *property,
820 uint64_t val)
Boris Brezillon1a396782015-01-06 11:13:28 +0100821{
822 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
823 struct atmel_hlcdc_plane_properties *props = plane->properties;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100824 struct atmel_hlcdc_plane_state *state =
825 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100826
827 if (property == props->alpha)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100828 state->alpha = val;
829 else
830 return -EINVAL;
831
832 return 0;
833}
834
835static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
836 const struct drm_plane_state *s,
837 struct drm_property *property,
838 uint64_t *val)
839{
840 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
841 struct atmel_hlcdc_plane_properties *props = plane->properties;
842 const struct atmel_hlcdc_plane_state *state =
843 container_of(s, const struct atmel_hlcdc_plane_state, base);
844
845 if (property == props->alpha)
846 *val = state->alpha;
Boris Brezillon1a396782015-01-06 11:13:28 +0100847 else
848 return -EINVAL;
849
850 return 0;
851}
852
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300853static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
Boris Brezillon9a45d332017-02-06 18:57:19 +0100854 struct atmel_hlcdc_plane_properties *props)
Boris Brezillon1a396782015-01-06 11:13:28 +0100855{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100856 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100857
858 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
Boris Brezillon9a45d332017-02-06 18:57:19 +0100859 desc->type == ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +0100860 drm_object_attach_property(&plane->base.base,
861 props->alpha, 255);
862
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300863 if (desc->layout.xstride && desc->layout.pstride) {
864 int ret;
865
866 ret = drm_plane_create_rotation_property(&plane->base,
Robert Fossc2c446a2017-05-19 16:50:17 -0400867 DRM_MODE_ROTATE_0,
868 DRM_MODE_ROTATE_0 |
869 DRM_MODE_ROTATE_90 |
870 DRM_MODE_ROTATE_180 |
871 DRM_MODE_ROTATE_270);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300872 if (ret)
873 return ret;
874 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100875
876 if (desc->layout.csc) {
877 /*
878 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
879 * userspace modify these factors (using a BLOB property ?).
880 */
Boris Brezillon9a45d332017-02-06 18:57:19 +0100881 atmel_hlcdc_layer_write_cfg(&plane->layer,
882 desc->layout.csc,
883 0x4c900091);
884 atmel_hlcdc_layer_write_cfg(&plane->layer,
885 desc->layout.csc + 1,
886 0x7a5f5090);
887 atmel_hlcdc_layer_write_cfg(&plane->layer,
888 desc->layout.csc + 2,
889 0x40040890);
Boris Brezillon1a396782015-01-06 11:13:28 +0100890 }
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300891
892 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100893}
894
Boris Brezillon9a45d332017-02-06 18:57:19 +0100895void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
896{
897 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
898 u32 isr;
899
900 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
901
902 /*
903 * There's not much we can do in case of overrun except informing
904 * the user. However, we are in interrupt context here, hence the
905 * use of dev_dbg().
906 */
907 if (isr &
908 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
909 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
910 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
911 desc->name);
912}
913
Boris Brezillon2389fc12015-02-05 16:32:33 +0100914static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100915 .atomic_check = atmel_hlcdc_plane_atomic_check,
916 .atomic_update = atmel_hlcdc_plane_atomic_update,
917 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
918};
919
Boris Brezillon9a45d332017-02-06 18:57:19 +0100920static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
921 struct atmel_hlcdc_plane_state *state)
922{
923 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
924 int i;
925
926 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
927 struct atmel_hlcdc_dma_channel_dscr *dscr;
928 dma_addr_t dscr_dma;
929
930 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
931 if (!dscr)
932 goto err;
933
934 dscr->addr = 0;
935 dscr->next = dscr_dma;
936 dscr->self = dscr_dma;
937 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
938
939 state->dscrs[i] = dscr;
940 }
941
942 return 0;
943
944err:
945 for (i--; i >= 0; i--) {
946 dma_pool_free(dc->dscrpool, state->dscrs[i],
947 state->dscrs[i]->self);
948 }
949
950 return -ENOMEM;
951}
952
Boris Brezillon2389fc12015-02-05 16:32:33 +0100953static void atmel_hlcdc_plane_reset(struct drm_plane *p)
954{
955 struct atmel_hlcdc_plane_state *state;
956
957 if (p->state) {
958 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
959
960 if (state->base.fb)
961 drm_framebuffer_unreference(state->base.fb);
962
963 kfree(state);
964 p->state = NULL;
965 }
966
967 state = kzalloc(sizeof(*state), GFP_KERNEL);
968 if (state) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100969 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
970 kfree(state);
971 dev_err(p->dev->dev,
972 "Failed to allocate initial plane state\n");
973 return;
974 }
975
Boris Brezillon2389fc12015-02-05 16:32:33 +0100976 state->alpha = 255;
977 p->state = &state->base;
978 p->state->plane = p;
979 }
980}
981
982static struct drm_plane_state *
983atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
984{
985 struct atmel_hlcdc_plane_state *state =
986 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
987 struct atmel_hlcdc_plane_state *copy;
988
989 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
990 if (!copy)
991 return NULL;
992
Boris Brezillon9a45d332017-02-06 18:57:19 +0100993 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
994 kfree(copy);
995 return NULL;
996 }
Boris Brezillon59570172015-02-06 16:25:06 +0100997
Boris Brezillon2389fc12015-02-05 16:32:33 +0100998 if (copy->base.fb)
999 drm_framebuffer_reference(copy->base.fb);
1000
1001 return &copy->base;
1002}
1003
Boris Brezillon9a45d332017-02-06 18:57:19 +01001004static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001005 struct drm_plane_state *s)
1006{
1007 struct atmel_hlcdc_plane_state *state =
1008 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +01001009 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1010 int i;
1011
1012 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1013 dma_pool_free(dc->dscrpool, state->dscrs[i],
1014 state->dscrs[i]->self);
1015 }
Boris Brezillon2389fc12015-02-05 16:32:33 +01001016
1017 if (s->fb)
1018 drm_framebuffer_unreference(s->fb);
1019
1020 kfree(state);
1021}
1022
Boris Brezillon1a396782015-01-06 11:13:28 +01001023static struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +01001024 .update_plane = drm_atomic_helper_update_plane,
1025 .disable_plane = drm_atomic_helper_disable_plane,
1026 .set_property = drm_atomic_helper_plane_set_property,
Boris Brezillon1a396782015-01-06 11:13:28 +01001027 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001028 .reset = atmel_hlcdc_plane_reset,
1029 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1030 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1031 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
1032 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
Boris Brezillon1a396782015-01-06 11:13:28 +01001033};
1034
Boris Brezillon9a45d332017-02-06 18:57:19 +01001035static int atmel_hlcdc_plane_create(struct drm_device *dev,
1036 const struct atmel_hlcdc_layer_desc *desc,
1037 struct atmel_hlcdc_plane_properties *props)
Boris Brezillon1a396782015-01-06 11:13:28 +01001038{
Boris Brezillon9a45d332017-02-06 18:57:19 +01001039 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001040 struct atmel_hlcdc_plane *plane;
1041 enum drm_plane_type type;
1042 int ret;
1043
1044 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1045 if (!plane)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001046 return -ENOMEM;
Boris Brezillon1a396782015-01-06 11:13:28 +01001047
Boris Brezillon9a45d332017-02-06 18:57:19 +01001048 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1049 plane->properties = props;
Boris Brezillon1a396782015-01-06 11:13:28 +01001050
1051 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1052 type = DRM_PLANE_TYPE_PRIMARY;
1053 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1054 type = DRM_PLANE_TYPE_CURSOR;
1055 else
1056 type = DRM_PLANE_TYPE_OVERLAY;
1057
1058 ret = drm_universal_plane_init(dev, &plane->base, 0,
1059 &layer_plane_funcs,
1060 desc->formats->formats,
Ville Syrjäläb0b3b792015-12-09 16:19:55 +02001061 desc->formats->nformats, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +01001062 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001063 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001064
Boris Brezillon2389fc12015-02-05 16:32:33 +01001065 drm_plane_helper_add(&plane->base,
1066 &atmel_hlcdc_layer_plane_helper_funcs);
1067
Boris Brezillon1a396782015-01-06 11:13:28 +01001068 /* Set default property values*/
Boris Brezillon9a45d332017-02-06 18:57:19 +01001069 ret = atmel_hlcdc_plane_init_properties(plane, props);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +03001070 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001071 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001072
Boris Brezillon9a45d332017-02-06 18:57:19 +01001073 dc->layers[desc->id] = &plane->layer;
1074
1075 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001076}
1077
1078static struct atmel_hlcdc_plane_properties *
1079atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1080{
1081 struct atmel_hlcdc_plane_properties *props;
1082
1083 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1084 if (!props)
1085 return ERR_PTR(-ENOMEM);
1086
1087 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1088 if (!props->alpha)
1089 return ERR_PTR(-ENOMEM);
1090
Boris Brezillon1a396782015-01-06 11:13:28 +01001091 return props;
1092}
1093
Boris Brezillon9a45d332017-02-06 18:57:19 +01001094int atmel_hlcdc_create_planes(struct drm_device *dev)
Boris Brezillon1a396782015-01-06 11:13:28 +01001095{
1096 struct atmel_hlcdc_dc *dc = dev->dev_private;
1097 struct atmel_hlcdc_plane_properties *props;
Boris Brezillon1a396782015-01-06 11:13:28 +01001098 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1099 int nlayers = dc->desc->nlayers;
Boris Brezillon9a45d332017-02-06 18:57:19 +01001100 int i, ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001101
1102 props = atmel_hlcdc_plane_create_properties(dev);
1103 if (IS_ERR(props))
Boris Brezillon9a45d332017-02-06 18:57:19 +01001104 return PTR_ERR(props);
Boris Brezillon1a396782015-01-06 11:13:28 +01001105
Boris Brezillon9a45d332017-02-06 18:57:19 +01001106 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1107 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1108 sizeof(u64), 0);
1109 if (!dc->dscrpool)
1110 return -ENOMEM;
1111
Boris Brezillon1a396782015-01-06 11:13:28 +01001112 for (i = 0; i < nlayers; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +01001113 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1114 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1115 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +01001116 continue;
1117
Boris Brezillon9a45d332017-02-06 18:57:19 +01001118 ret = atmel_hlcdc_plane_create(dev, &descs[i], props);
1119 if (ret)
1120 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001121 }
1122
Boris Brezillon9a45d332017-02-06 18:57:19 +01001123 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001124}