blob: a4a47b06a39d406edf76003c414465d38d9d88cf [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[] = {
Peter Rosin364a7bf2017-06-22 07:03:11 +020086 DRM_FORMAT_C8,
Boris Brezillon1a396782015-01-06 11:13:28 +010087 DRM_FORMAT_XRGB4444,
88 DRM_FORMAT_ARGB4444,
89 DRM_FORMAT_RGBA4444,
90 DRM_FORMAT_ARGB1555,
91 DRM_FORMAT_RGB565,
92 DRM_FORMAT_RGB888,
93 DRM_FORMAT_XRGB8888,
94 DRM_FORMAT_ARGB8888,
95 DRM_FORMAT_RGBA8888,
96};
97
98struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
99 .formats = rgb_formats,
100 .nformats = ARRAY_SIZE(rgb_formats),
101};
102
103static uint32_t rgb_and_yuv_formats[] = {
Peter Rosin364a7bf2017-06-22 07:03:11 +0200104 DRM_FORMAT_C8,
Boris Brezillon1a396782015-01-06 11:13:28 +0100105 DRM_FORMAT_XRGB4444,
106 DRM_FORMAT_ARGB4444,
107 DRM_FORMAT_RGBA4444,
108 DRM_FORMAT_ARGB1555,
109 DRM_FORMAT_RGB565,
110 DRM_FORMAT_RGB888,
111 DRM_FORMAT_XRGB8888,
112 DRM_FORMAT_ARGB8888,
113 DRM_FORMAT_RGBA8888,
114 DRM_FORMAT_AYUV,
115 DRM_FORMAT_YUYV,
116 DRM_FORMAT_UYVY,
117 DRM_FORMAT_YVYU,
118 DRM_FORMAT_VYUY,
119 DRM_FORMAT_NV21,
120 DRM_FORMAT_NV61,
121 DRM_FORMAT_YUV422,
122 DRM_FORMAT_YUV420,
123};
124
125struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
126 .formats = rgb_and_yuv_formats,
127 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
128};
129
130static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
131{
132 switch (format) {
Peter Rosin364a7bf2017-06-22 07:03:11 +0200133 case DRM_FORMAT_C8:
134 *mode = ATMEL_HLCDC_C8_MODE;
135 break;
Boris Brezillon1a396782015-01-06 11:13:28 +0100136 case DRM_FORMAT_XRGB4444:
137 *mode = ATMEL_HLCDC_XRGB4444_MODE;
138 break;
139 case DRM_FORMAT_ARGB4444:
140 *mode = ATMEL_HLCDC_ARGB4444_MODE;
141 break;
142 case DRM_FORMAT_RGBA4444:
143 *mode = ATMEL_HLCDC_RGBA4444_MODE;
144 break;
145 case DRM_FORMAT_RGB565:
146 *mode = ATMEL_HLCDC_RGB565_MODE;
147 break;
148 case DRM_FORMAT_RGB888:
149 *mode = ATMEL_HLCDC_RGB888_MODE;
150 break;
151 case DRM_FORMAT_ARGB1555:
152 *mode = ATMEL_HLCDC_ARGB1555_MODE;
153 break;
154 case DRM_FORMAT_XRGB8888:
155 *mode = ATMEL_HLCDC_XRGB8888_MODE;
156 break;
157 case DRM_FORMAT_ARGB8888:
158 *mode = ATMEL_HLCDC_ARGB8888_MODE;
159 break;
160 case DRM_FORMAT_RGBA8888:
161 *mode = ATMEL_HLCDC_RGBA8888_MODE;
162 break;
163 case DRM_FORMAT_AYUV:
164 *mode = ATMEL_HLCDC_AYUV_MODE;
165 break;
166 case DRM_FORMAT_YUYV:
167 *mode = ATMEL_HLCDC_YUYV_MODE;
168 break;
169 case DRM_FORMAT_UYVY:
170 *mode = ATMEL_HLCDC_UYVY_MODE;
171 break;
172 case DRM_FORMAT_YVYU:
173 *mode = ATMEL_HLCDC_YVYU_MODE;
174 break;
175 case DRM_FORMAT_VYUY:
176 *mode = ATMEL_HLCDC_VYUY_MODE;
177 break;
178 case DRM_FORMAT_NV21:
179 *mode = ATMEL_HLCDC_NV21_MODE;
180 break;
181 case DRM_FORMAT_NV61:
182 *mode = ATMEL_HLCDC_NV61_MODE;
183 break;
184 case DRM_FORMAT_YUV420:
185 *mode = ATMEL_HLCDC_YUV420_MODE;
186 break;
187 case DRM_FORMAT_YUV422:
188 *mode = ATMEL_HLCDC_YUV422_MODE;
189 break;
190 default:
191 return -ENOTSUPP;
192 }
193
194 return 0;
195}
196
Boris Brezillon2389fc12015-02-05 16:32:33 +0100197static bool atmel_hlcdc_format_embeds_alpha(u32 format)
Boris Brezillon1a396782015-01-06 11:13:28 +0100198{
199 int i;
200
201 for (i = 0; i < sizeof(format); i++) {
202 char tmp = (format >> (8 * i)) & 0xff;
203
204 if (tmp == 'A')
205 return true;
206 }
207
208 return false;
209}
210
211static u32 heo_downscaling_xcoef[] = {
212 0x11343311,
213 0x000000f7,
214 0x1635300c,
215 0x000000f9,
216 0x1b362c08,
217 0x000000fb,
218 0x1f372804,
219 0x000000fe,
220 0x24382400,
221 0x00000000,
222 0x28371ffe,
223 0x00000004,
224 0x2c361bfb,
225 0x00000008,
226 0x303516f9,
227 0x0000000c,
228};
229
230static u32 heo_downscaling_ycoef[] = {
231 0x00123737,
232 0x00173732,
233 0x001b382d,
234 0x001f3928,
235 0x00243824,
236 0x0028391f,
237 0x002d381b,
238 0x00323717,
239};
240
241static u32 heo_upscaling_xcoef[] = {
242 0xf74949f7,
243 0x00000000,
244 0xf55f33fb,
245 0x000000fe,
246 0xf5701efe,
247 0x000000ff,
248 0xf87c0dff,
249 0x00000000,
250 0x00800000,
251 0x00000000,
252 0x0d7cf800,
253 0x000000ff,
254 0x1e70f5ff,
255 0x000000fe,
256 0x335ff5fe,
257 0x000000fb,
258};
259
260static u32 heo_upscaling_ycoef[] = {
261 0x00004040,
262 0x00075920,
263 0x00056f0c,
264 0x00027b03,
265 0x00008000,
266 0x00037b02,
267 0x000c6f05,
268 0x00205907,
269};
270
Boris Brezillon9a45d332017-02-06 18:57:19 +0100271#define ATMEL_HLCDC_XPHIDEF 4
272#define ATMEL_HLCDC_YPHIDEF 4
273
274static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
275 u32 dstsize,
276 u32 phidef)
277{
278 u32 factor, max_memsize;
279
280 factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
281 max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
282
283 if (max_memsize > srcsize - 1)
284 factor--;
285
286 return factor;
287}
288
289static void
290atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
291 const u32 *coeff_tab, int size,
292 unsigned int cfg_offs)
293{
294 int i;
295
296 for (i = 0; i < size; i++)
297 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
298 coeff_tab[i]);
299}
300
301void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
302 struct atmel_hlcdc_plane_state *state)
303{
304 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
305 u32 xfactor, yfactor;
306
307 if (!desc->layout.scaler_config)
308 return;
309
310 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
311 atmel_hlcdc_layer_write_cfg(&plane->layer,
312 desc->layout.scaler_config, 0);
313 return;
314 }
315
316 if (desc->layout.phicoeffs.x) {
317 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
318 state->crtc_w,
319 ATMEL_HLCDC_XPHIDEF);
320
321 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
322 state->crtc_h,
323 ATMEL_HLCDC_YPHIDEF);
324
325 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
326 state->crtc_w < state->src_w ?
327 heo_downscaling_xcoef :
328 heo_upscaling_xcoef,
329 ARRAY_SIZE(heo_upscaling_xcoef),
330 desc->layout.phicoeffs.x);
331
332 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
333 state->crtc_h < state->src_h ?
334 heo_downscaling_ycoef :
335 heo_upscaling_ycoef,
336 ARRAY_SIZE(heo_upscaling_ycoef),
337 desc->layout.phicoeffs.y);
338 } else {
339 xfactor = (1024 * state->src_w) / state->crtc_w;
340 yfactor = (1024 * state->src_h) / state->crtc_h;
341 }
342
343 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
344 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
345 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
346 yfactor));
347}
348
Boris Brezillon1a396782015-01-06 11:13:28 +0100349static void
350atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100351 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100352{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100353 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100354
Boris Brezillon9a45d332017-02-06 18:57:19 +0100355 if (desc->layout.size)
356 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
357 ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
358 state->crtc_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100359
Boris Brezillon9a45d332017-02-06 18:57:19 +0100360 if (desc->layout.memsize)
361 atmel_hlcdc_layer_write_cfg(&plane->layer,
362 desc->layout.memsize,
363 ATMEL_HLCDC_LAYER_SIZE(state->src_w,
364 state->src_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100365
Boris Brezillon9a45d332017-02-06 18:57:19 +0100366 if (desc->layout.pos)
367 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
368 ATMEL_HLCDC_LAYER_POS(state->crtc_x,
369 state->crtc_y));
Boris Brezillon1a396782015-01-06 11:13:28 +0100370
Boris Brezillon9a45d332017-02-06 18:57:19 +0100371 atmel_hlcdc_plane_setup_scaler(plane, state);
Boris Brezillon1a396782015-01-06 11:13:28 +0100372}
373
374static void
375atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100376 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100377{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100378 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
379 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
380 u32 format = state->base.fb->format->format;
381
382 /*
383 * Rotation optimization is not working on RGB888 (rotation is still
384 * working but without any optimization).
385 */
386 if (format == DRM_FORMAT_RGB888)
387 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
388
389 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
390 cfg);
391
392 cfg = ATMEL_HLCDC_LAYER_DMA;
Boris Brezillon1a396782015-01-06 11:13:28 +0100393
394 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
395 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
396 ATMEL_HLCDC_LAYER_ITER;
397
Boris Brezillon9a45d332017-02-06 18:57:19 +0100398 if (atmel_hlcdc_format_embeds_alpha(format))
Boris Brezillon1a396782015-01-06 11:13:28 +0100399 cfg |= ATMEL_HLCDC_LAYER_LAEN;
400 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100401 cfg |= ATMEL_HLCDC_LAYER_GAEN |
402 ATMEL_HLCDC_LAYER_GA(state->alpha);
Boris Brezillon1a396782015-01-06 11:13:28 +0100403 }
404
Boris Brezillon9a45d332017-02-06 18:57:19 +0100405 if (state->disc_h && state->disc_w)
406 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
Boris Brezillon1a396782015-01-06 11:13:28 +0100407
Boris Brezillon9a45d332017-02-06 18:57:19 +0100408 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
409 cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100410}
411
412static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100413 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100414{
415 u32 cfg;
416 int ret;
417
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200418 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100419 &cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100420 if (ret)
421 return;
422
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200423 if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
424 state->base.fb->format->format == DRM_FORMAT_NV61) &&
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300425 drm_rotation_90_or_270(state->base.rotation))
Boris Brezillon1a396782015-01-06 11:13:28 +0100426 cfg |= ATMEL_HLCDC_YUV422ROT;
427
Boris Brezillon9a45d332017-02-06 18:57:19 +0100428 atmel_hlcdc_layer_write_cfg(&plane->layer,
429 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100430}
431
Peter Rosin364a7bf2017-06-22 07:03:11 +0200432static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane)
433{
434 struct drm_crtc *crtc = plane->base.crtc;
435 struct drm_color_lut *lut;
436 int idx;
437
438 if (!crtc || !crtc->state)
439 return;
440
441 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
442 return;
443
444 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
445
446 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
447 u32 val = ((lut->red << 8) & 0xff0000) |
448 (lut->green & 0xff00) |
449 (lut->blue >> 8);
450
451 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
452 }
453}
454
Boris Brezillon1a396782015-01-06 11:13:28 +0100455static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100456 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100457{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100458 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
459 struct drm_framebuffer *fb = state->base.fb;
460 u32 sr;
Boris Brezillon1a396782015-01-06 11:13:28 +0100461 int i;
462
Boris Brezillon9a45d332017-02-06 18:57:19 +0100463 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100464
Boris Brezillon2389fc12015-02-05 16:32:33 +0100465 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100466 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
467
468 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
469
470 atmel_hlcdc_layer_write_reg(&plane->layer,
471 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
472 state->dscrs[i]->self);
473
474 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
475 atmel_hlcdc_layer_write_reg(&plane->layer,
476 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
477 state->dscrs[i]->addr);
478 atmel_hlcdc_layer_write_reg(&plane->layer,
479 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
480 state->dscrs[i]->ctrl);
481 atmel_hlcdc_layer_write_reg(&plane->layer,
482 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
483 state->dscrs[i]->self);
Boris Brezillon1a396782015-01-06 11:13:28 +0100484 }
485
Boris Brezillon9a45d332017-02-06 18:57:19 +0100486 if (desc->layout.xstride[i])
487 atmel_hlcdc_layer_write_cfg(&plane->layer,
488 desc->layout.xstride[i],
489 state->xstride[i]);
490
491 if (desc->layout.pstride[i])
492 atmel_hlcdc_layer_write_cfg(&plane->layer,
493 desc->layout.pstride[i],
494 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100495 }
496}
497
Boris Brezillonebab87a2016-03-15 18:01:08 +0100498int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
499{
500 unsigned int ahb_load[2] = { };
501 struct drm_plane *plane;
502
503 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
504 struct atmel_hlcdc_plane_state *plane_state;
505 struct drm_plane_state *plane_s;
506 unsigned int pixels, load = 0;
507 int i;
508
509 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
510 if (IS_ERR(plane_s))
511 return PTR_ERR(plane_s);
512
513 plane_state =
514 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
515
516 pixels = (plane_state->src_w * plane_state->src_h) -
517 (plane_state->disc_w * plane_state->disc_h);
518
519 for (i = 0; i < plane_state->nplanes; i++)
520 load += pixels * plane_state->bpp[i];
521
522 if (ahb_load[0] <= ahb_load[1])
523 plane_state->ahb_id = 0;
524 else
525 plane_state->ahb_id = 1;
526
527 ahb_load[plane_state->ahb_id] += load;
528 }
529
530 return 0;
531}
532
Boris Brezillon59570172015-02-06 16:25:06 +0100533int
534atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
535{
536 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
537 const struct atmel_hlcdc_layer_cfg_layout *layout;
538 struct atmel_hlcdc_plane_state *primary_state;
539 struct drm_plane_state *primary_s;
540 struct atmel_hlcdc_plane *primary;
541 struct drm_plane *ovl;
542
543 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
544 layout = &primary->layer.desc->layout;
545 if (!layout->disc_pos || !layout->disc_size)
546 return 0;
547
548 primary_s = drm_atomic_get_plane_state(c_state->state,
549 &primary->base);
550 if (IS_ERR(primary_s))
551 return PTR_ERR(primary_s);
552
553 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
554
555 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
556 struct atmel_hlcdc_plane_state *ovl_state;
557 struct drm_plane_state *ovl_s;
558
559 if (ovl == c_state->crtc->primary)
560 continue;
561
562 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
563 if (IS_ERR(ovl_s))
564 return PTR_ERR(ovl_s);
565
566 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
567
568 if (!ovl_s->fb ||
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200569 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
Boris Brezillon59570172015-02-06 16:25:06 +0100570 ovl_state->alpha != 255)
571 continue;
572
573 /* TODO: implement a smarter hidden area detection */
574 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
575 continue;
576
577 disc_x = ovl_state->crtc_x;
578 disc_y = ovl_state->crtc_y;
579 disc_h = ovl_state->crtc_h;
580 disc_w = ovl_state->crtc_w;
581 }
582
Boris Brezillon59570172015-02-06 16:25:06 +0100583 primary_state->disc_x = disc_x;
584 primary_state->disc_y = disc_y;
585 primary_state->disc_w = disc_w;
586 primary_state->disc_h = disc_h;
Boris Brezillon59570172015-02-06 16:25:06 +0100587
588 return 0;
589}
590
591static void
592atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
593 struct atmel_hlcdc_plane_state *state)
594{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100595 const struct atmel_hlcdc_layer_cfg_layout *layout;
Boris Brezillon59570172015-02-06 16:25:06 +0100596
Boris Brezillon9a45d332017-02-06 18:57:19 +0100597 layout = &plane->layer.desc->layout;
598 if (!layout->disc_pos || !layout->disc_size)
Boris Brezillon59570172015-02-06 16:25:06 +0100599 return;
600
Boris Brezillon9a45d332017-02-06 18:57:19 +0100601 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
602 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
603 state->disc_y));
Boris Brezillon59570172015-02-06 16:25:06 +0100604
Boris Brezillon9a45d332017-02-06 18:57:19 +0100605 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
606 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
607 state->disc_h));
Boris Brezillon59570172015-02-06 16:25:06 +0100608}
609
Boris Brezillon2389fc12015-02-05 16:32:33 +0100610static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
611 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100612{
613 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100614 struct atmel_hlcdc_plane_state *state =
615 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100616 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100617 struct drm_framebuffer *fb = state->base.fb;
618 const struct drm_display_mode *mode;
619 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100620 unsigned int patched_crtc_w;
621 unsigned int patched_crtc_h;
622 unsigned int patched_src_w;
623 unsigned int patched_src_h;
624 unsigned int tmp;
625 int x_offset = 0;
626 int y_offset = 0;
627 int hsub = 1;
628 int vsub = 1;
629 int i;
630
Boris Brezillon2389fc12015-02-05 16:32:33 +0100631 if (!state->base.crtc || !fb)
632 return 0;
633
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100634 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100635 mode = &crtc_state->adjusted_mode;
636
637 state->src_x = s->src_x;
638 state->src_y = s->src_y;
639 state->src_h = s->src_h;
640 state->src_w = s->src_w;
641 state->crtc_x = s->crtc_x;
642 state->crtc_y = s->crtc_y;
643 state->crtc_h = s->crtc_h;
644 state->crtc_w = s->crtc_w;
645 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100646 SUBPIXEL_MASK)
647 return -EINVAL;
648
Boris Brezillon2389fc12015-02-05 16:32:33 +0100649 state->src_x >>= 16;
650 state->src_y >>= 16;
651 state->src_w >>= 16;
652 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100653
Ville Syrjäläbcb0b462016-12-14 23:30:22 +0200654 state->nplanes = fb->format->num_planes;
Boris Brezillon9a45d332017-02-06 18:57:19 +0100655 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100656 return -EINVAL;
657
658 /*
659 * Swap width and size in case of 90 or 270 degrees rotation
660 */
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300661 if (drm_rotation_90_or_270(state->base.rotation)) {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100662 tmp = state->crtc_w;
663 state->crtc_w = state->crtc_h;
664 state->crtc_h = tmp;
665 tmp = state->src_w;
666 state->src_w = state->src_h;
667 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100668 }
669
Boris Brezillon2389fc12015-02-05 16:32:33 +0100670 if (state->crtc_x + state->crtc_w > mode->hdisplay)
671 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100672 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100673 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100674
Boris Brezillon2389fc12015-02-05 16:32:33 +0100675 if (state->crtc_x < 0) {
676 patched_crtc_w += state->crtc_x;
677 x_offset = -state->crtc_x;
678 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100679 }
680
Boris Brezillon2389fc12015-02-05 16:32:33 +0100681 if (state->crtc_y + state->crtc_h > mode->vdisplay)
682 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100683 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100684 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100685
Boris Brezillon2389fc12015-02-05 16:32:33 +0100686 if (state->crtc_y < 0) {
687 patched_crtc_h += state->crtc_y;
688 y_offset = -state->crtc_y;
689 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100690 }
691
Boris Brezillon2389fc12015-02-05 16:32:33 +0100692 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
693 state->crtc_w);
694 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
695 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100696
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200697 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
698 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100699
Boris Brezillon2389fc12015-02-05 16:32:33 +0100700 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100701 unsigned int offset = 0;
702 int xdiv = i ? hsub : 1;
703 int ydiv = i ? vsub : 1;
704
Ville Syrjälä353c8592016-12-14 23:30:57 +0200705 state->bpp[i] = fb->format->cpp[i];
Boris Brezillon2389fc12015-02-05 16:32:33 +0100706 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100707 return -EINVAL;
708
Robert Fossc2c446a2017-05-19 16:50:17 -0400709 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
710 case DRM_MODE_ROTATE_90:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100711 offset = ((y_offset + state->src_y + patched_src_w - 1) /
712 ydiv) * fb->pitches[i];
713 offset += ((x_offset + state->src_x) / xdiv) *
714 state->bpp[i];
715 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
716 fb->pitches[i];
717 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100718 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400719 case DRM_MODE_ROTATE_180:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100720 offset = ((y_offset + state->src_y + patched_src_h - 1) /
721 ydiv) * fb->pitches[i];
722 offset += ((x_offset + state->src_x + patched_src_w - 1) /
723 xdiv) * state->bpp[i];
724 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
725 state->bpp[i]) - fb->pitches[i];
726 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100727 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400728 case DRM_MODE_ROTATE_270:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100729 offset = ((y_offset + state->src_y) / ydiv) *
730 fb->pitches[i];
731 offset += ((x_offset + state->src_x + patched_src_h - 1) /
732 xdiv) * state->bpp[i];
733 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
734 fb->pitches[i]) -
735 (2 * state->bpp[i]);
736 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100737 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400738 case DRM_MODE_ROTATE_0:
Boris Brezillon1a396782015-01-06 11:13:28 +0100739 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100740 offset = ((y_offset + state->src_y) / ydiv) *
741 fb->pitches[i];
742 offset += ((x_offset + state->src_x) / xdiv) *
743 state->bpp[i];
744 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100745 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100746 state->bpp[i]);
747 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100748 break;
749 }
750
Boris Brezillon2389fc12015-02-05 16:32:33 +0100751 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100752 }
753
Boris Brezillon2389fc12015-02-05 16:32:33 +0100754 state->src_w = patched_src_w;
755 state->src_h = patched_src_h;
756 state->crtc_w = patched_crtc_w;
757 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100758
Boris Brezillon9a45d332017-02-06 18:57:19 +0100759 if (!desc->layout.size &&
Boris Brezillon2389fc12015-02-05 16:32:33 +0100760 (mode->hdisplay != state->crtc_w ||
761 mode->vdisplay != state->crtc_h))
762 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100763
Boris Brezillon9a45d332017-02-06 18:57:19 +0100764 if (desc->max_height && state->crtc_h > desc->max_height)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100765 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100766
Boris Brezillon9a45d332017-02-06 18:57:19 +0100767 if (desc->max_width && state->crtc_w > desc->max_width)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100768 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100769
Boris Brezillon2389fc12015-02-05 16:32:33 +0100770 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
Boris Brezillon9a45d332017-02-06 18:57:19 +0100771 (!desc->layout.memsize ||
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200772 atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
Boris Brezillon2389fc12015-02-05 16:32:33 +0100773 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100774
Boris Brezillon2389fc12015-02-05 16:32:33 +0100775 if (state->crtc_x < 0 || state->crtc_y < 0)
776 return -EINVAL;
777
778 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
779 state->crtc_h + state->crtc_y > mode->vdisplay)
780 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100781
782 return 0;
783}
784
Boris Brezillon2389fc12015-02-05 16:32:33 +0100785static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
786 struct drm_plane_state *old_s)
787{
788 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
789 struct atmel_hlcdc_plane_state *state =
790 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100791 u32 sr;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100792
793 if (!p->state->crtc || !p->state->fb)
794 return;
795
796 atmel_hlcdc_plane_update_pos_and_size(plane, state);
797 atmel_hlcdc_plane_update_general_settings(plane, state);
798 atmel_hlcdc_plane_update_format(plane, state);
Peter Rosin364a7bf2017-06-22 07:03:11 +0200799 atmel_hlcdc_plane_update_clut(plane);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100800 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100801 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100802
Boris Brezillon9a45d332017-02-06 18:57:19 +0100803 /* Enable the overrun interrupts. */
804 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
805 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
806 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
807 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
808
809 /* Apply the new config at the next SOF event. */
810 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
811 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
812 ATMEL_HLCDC_LAYER_UPDATE |
813 (sr & ATMEL_HLCDC_LAYER_EN ?
814 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
Boris Brezillon2389fc12015-02-05 16:32:33 +0100815}
816
817static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
818 struct drm_plane_state *old_state)
819{
820 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
821
Boris Brezillon9a45d332017-02-06 18:57:19 +0100822 /* Disable interrupts */
823 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
824 0xffffffff);
825
826 /* Disable the layer */
827 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
828 ATMEL_HLCDC_LAYER_RST |
829 ATMEL_HLCDC_LAYER_A2Q |
830 ATMEL_HLCDC_LAYER_UPDATE);
831
832 /* Clear all pending interrupts */
833 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100834}
835
836static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
837{
838 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
839
840 if (plane->base.fb)
841 drm_framebuffer_unreference(plane->base.fb);
842
Boris Brezillon1a396782015-01-06 11:13:28 +0100843 drm_plane_cleanup(p);
Boris Brezillon1a396782015-01-06 11:13:28 +0100844}
845
Boris Brezillon2389fc12015-02-05 16:32:33 +0100846static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
847 struct drm_plane_state *s,
848 struct drm_property *property,
849 uint64_t val)
Boris Brezillon1a396782015-01-06 11:13:28 +0100850{
851 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
852 struct atmel_hlcdc_plane_properties *props = plane->properties;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100853 struct atmel_hlcdc_plane_state *state =
854 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon1a396782015-01-06 11:13:28 +0100855
856 if (property == props->alpha)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100857 state->alpha = val;
858 else
859 return -EINVAL;
860
861 return 0;
862}
863
864static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
865 const struct drm_plane_state *s,
866 struct drm_property *property,
867 uint64_t *val)
868{
869 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
870 struct atmel_hlcdc_plane_properties *props = plane->properties;
871 const struct atmel_hlcdc_plane_state *state =
872 container_of(s, const struct atmel_hlcdc_plane_state, base);
873
874 if (property == props->alpha)
875 *val = state->alpha;
Boris Brezillon1a396782015-01-06 11:13:28 +0100876 else
877 return -EINVAL;
878
879 return 0;
880}
881
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300882static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
Boris Brezillon9a45d332017-02-06 18:57:19 +0100883 struct atmel_hlcdc_plane_properties *props)
Boris Brezillon1a396782015-01-06 11:13:28 +0100884{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100885 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100886
887 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
Boris Brezillon9a45d332017-02-06 18:57:19 +0100888 desc->type == ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +0100889 drm_object_attach_property(&plane->base.base,
890 props->alpha, 255);
891
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300892 if (desc->layout.xstride && desc->layout.pstride) {
893 int ret;
894
895 ret = drm_plane_create_rotation_property(&plane->base,
Robert Fossc2c446a2017-05-19 16:50:17 -0400896 DRM_MODE_ROTATE_0,
897 DRM_MODE_ROTATE_0 |
898 DRM_MODE_ROTATE_90 |
899 DRM_MODE_ROTATE_180 |
900 DRM_MODE_ROTATE_270);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300901 if (ret)
902 return ret;
903 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100904
905 if (desc->layout.csc) {
906 /*
907 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
908 * userspace modify these factors (using a BLOB property ?).
909 */
Boris Brezillon9a45d332017-02-06 18:57:19 +0100910 atmel_hlcdc_layer_write_cfg(&plane->layer,
911 desc->layout.csc,
912 0x4c900091);
913 atmel_hlcdc_layer_write_cfg(&plane->layer,
914 desc->layout.csc + 1,
915 0x7a5f5090);
916 atmel_hlcdc_layer_write_cfg(&plane->layer,
917 desc->layout.csc + 2,
918 0x40040890);
Boris Brezillon1a396782015-01-06 11:13:28 +0100919 }
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300920
921 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100922}
923
Boris Brezillon9a45d332017-02-06 18:57:19 +0100924void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
925{
926 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
927 u32 isr;
928
929 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
930
931 /*
932 * There's not much we can do in case of overrun except informing
933 * the user. However, we are in interrupt context here, hence the
934 * use of dev_dbg().
935 */
936 if (isr &
937 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
938 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
939 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
940 desc->name);
941}
942
Arvind Yadavd95a8e72017-07-03 21:53:54 +0530943static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100944 .atomic_check = atmel_hlcdc_plane_atomic_check,
945 .atomic_update = atmel_hlcdc_plane_atomic_update,
946 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
947};
948
Boris Brezillon9a45d332017-02-06 18:57:19 +0100949static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
950 struct atmel_hlcdc_plane_state *state)
951{
952 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
953 int i;
954
955 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
956 struct atmel_hlcdc_dma_channel_dscr *dscr;
957 dma_addr_t dscr_dma;
958
959 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
960 if (!dscr)
961 goto err;
962
963 dscr->addr = 0;
964 dscr->next = dscr_dma;
965 dscr->self = dscr_dma;
966 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
967
968 state->dscrs[i] = dscr;
969 }
970
971 return 0;
972
973err:
974 for (i--; i >= 0; i--) {
975 dma_pool_free(dc->dscrpool, state->dscrs[i],
976 state->dscrs[i]->self);
977 }
978
979 return -ENOMEM;
980}
981
Boris Brezillon2389fc12015-02-05 16:32:33 +0100982static void atmel_hlcdc_plane_reset(struct drm_plane *p)
983{
984 struct atmel_hlcdc_plane_state *state;
985
986 if (p->state) {
987 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
988
989 if (state->base.fb)
990 drm_framebuffer_unreference(state->base.fb);
991
992 kfree(state);
993 p->state = NULL;
994 }
995
996 state = kzalloc(sizeof(*state), GFP_KERNEL);
997 if (state) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100998 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
999 kfree(state);
1000 dev_err(p->dev->dev,
1001 "Failed to allocate initial plane state\n");
1002 return;
1003 }
1004
Boris Brezillon2389fc12015-02-05 16:32:33 +01001005 state->alpha = 255;
1006 p->state = &state->base;
1007 p->state->plane = p;
1008 }
1009}
1010
1011static struct drm_plane_state *
1012atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
1013{
1014 struct atmel_hlcdc_plane_state *state =
1015 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1016 struct atmel_hlcdc_plane_state *copy;
1017
1018 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
1019 if (!copy)
1020 return NULL;
1021
Boris Brezillon9a45d332017-02-06 18:57:19 +01001022 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
1023 kfree(copy);
1024 return NULL;
1025 }
Boris Brezillon59570172015-02-06 16:25:06 +01001026
Boris Brezillon2389fc12015-02-05 16:32:33 +01001027 if (copy->base.fb)
1028 drm_framebuffer_reference(copy->base.fb);
1029
1030 return &copy->base;
1031}
1032
Boris Brezillon9a45d332017-02-06 18:57:19 +01001033static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001034 struct drm_plane_state *s)
1035{
1036 struct atmel_hlcdc_plane_state *state =
1037 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +01001038 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1039 int i;
1040
1041 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1042 dma_pool_free(dc->dscrpool, state->dscrs[i],
1043 state->dscrs[i]->self);
1044 }
Boris Brezillon2389fc12015-02-05 16:32:33 +01001045
1046 if (s->fb)
1047 drm_framebuffer_unreference(s->fb);
1048
1049 kfree(state);
1050}
1051
Arvind Yadavd95a8e72017-07-03 21:53:54 +05301052static const struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +01001053 .update_plane = drm_atomic_helper_update_plane,
1054 .disable_plane = drm_atomic_helper_disable_plane,
1055 .set_property = drm_atomic_helper_plane_set_property,
Boris Brezillon1a396782015-01-06 11:13:28 +01001056 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001057 .reset = atmel_hlcdc_plane_reset,
1058 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1059 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1060 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
1061 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
Boris Brezillon1a396782015-01-06 11:13:28 +01001062};
1063
Boris Brezillon9a45d332017-02-06 18:57:19 +01001064static int atmel_hlcdc_plane_create(struct drm_device *dev,
1065 const struct atmel_hlcdc_layer_desc *desc,
1066 struct atmel_hlcdc_plane_properties *props)
Boris Brezillon1a396782015-01-06 11:13:28 +01001067{
Boris Brezillon9a45d332017-02-06 18:57:19 +01001068 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001069 struct atmel_hlcdc_plane *plane;
1070 enum drm_plane_type type;
1071 int ret;
1072
1073 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1074 if (!plane)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001075 return -ENOMEM;
Boris Brezillon1a396782015-01-06 11:13:28 +01001076
Boris Brezillon9a45d332017-02-06 18:57:19 +01001077 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1078 plane->properties = props;
Boris Brezillon1a396782015-01-06 11:13:28 +01001079
1080 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1081 type = DRM_PLANE_TYPE_PRIMARY;
1082 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1083 type = DRM_PLANE_TYPE_CURSOR;
1084 else
1085 type = DRM_PLANE_TYPE_OVERLAY;
1086
1087 ret = drm_universal_plane_init(dev, &plane->base, 0,
1088 &layer_plane_funcs,
1089 desc->formats->formats,
Ben Widawskye6fc3b62017-07-23 20:46:38 -07001090 desc->formats->nformats,
1091 NULL, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +01001092 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001093 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001094
Boris Brezillon2389fc12015-02-05 16:32:33 +01001095 drm_plane_helper_add(&plane->base,
1096 &atmel_hlcdc_layer_plane_helper_funcs);
1097
Boris Brezillon1a396782015-01-06 11:13:28 +01001098 /* Set default property values*/
Boris Brezillon9a45d332017-02-06 18:57:19 +01001099 ret = atmel_hlcdc_plane_init_properties(plane, props);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +03001100 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001101 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001102
Boris Brezillon9a45d332017-02-06 18:57:19 +01001103 dc->layers[desc->id] = &plane->layer;
1104
1105 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001106}
1107
1108static struct atmel_hlcdc_plane_properties *
1109atmel_hlcdc_plane_create_properties(struct drm_device *dev)
1110{
1111 struct atmel_hlcdc_plane_properties *props;
1112
1113 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
1114 if (!props)
1115 return ERR_PTR(-ENOMEM);
1116
1117 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
1118 if (!props->alpha)
1119 return ERR_PTR(-ENOMEM);
1120
Boris Brezillon1a396782015-01-06 11:13:28 +01001121 return props;
1122}
1123
Boris Brezillon9a45d332017-02-06 18:57:19 +01001124int atmel_hlcdc_create_planes(struct drm_device *dev)
Boris Brezillon1a396782015-01-06 11:13:28 +01001125{
1126 struct atmel_hlcdc_dc *dc = dev->dev_private;
1127 struct atmel_hlcdc_plane_properties *props;
Boris Brezillon1a396782015-01-06 11:13:28 +01001128 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1129 int nlayers = dc->desc->nlayers;
Boris Brezillon9a45d332017-02-06 18:57:19 +01001130 int i, ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001131
1132 props = atmel_hlcdc_plane_create_properties(dev);
1133 if (IS_ERR(props))
Boris Brezillon9a45d332017-02-06 18:57:19 +01001134 return PTR_ERR(props);
Boris Brezillon1a396782015-01-06 11:13:28 +01001135
Boris Brezillon9a45d332017-02-06 18:57:19 +01001136 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1137 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1138 sizeof(u64), 0);
1139 if (!dc->dscrpool)
1140 return -ENOMEM;
1141
Boris Brezillon1a396782015-01-06 11:13:28 +01001142 for (i = 0; i < nlayers; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +01001143 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1144 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1145 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +01001146 continue;
1147
Boris Brezillon9a45d332017-02-06 18:57:19 +01001148 ret = atmel_hlcdc_plane_create(dev, &descs[i], props);
1149 if (ret)
1150 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001151 }
1152
Boris Brezillon9a45d332017-02-06 18:57:19 +01001153 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001154}