blob: 47e0992f39083161d46c5d1759f0c06f5cf2c0de [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
Boris Brezillon9a45d332017-02-06 18:57:19 +010034 * @disc_x: x discard position
35 * @disc_y: y discard position
36 * @disc_w: discard width
37 * @disc_h: discard height
Boris Brezillon2389fc12015-02-05 16:32:33 +010038 * @bpp: bytes per pixel deduced from pixel_format
39 * @offsets: offsets to apply to the GEM buffers
40 * @xstride: value to add to the pixel pointer between each line
41 * @pstride: value to add to the pixel pointer between each pixel
42 * @nplanes: number of planes (deduced from pixel_format)
Boris Brezillon9a45d332017-02-06 18:57:19 +010043 * @dscrs: DMA descriptors
Boris Brezillon2389fc12015-02-05 16:32:33 +010044 */
45struct atmel_hlcdc_plane_state {
46 struct drm_plane_state base;
47 int crtc_x;
48 int crtc_y;
49 unsigned int crtc_w;
50 unsigned int crtc_h;
51 uint32_t src_x;
52 uint32_t src_y;
53 uint32_t src_w;
54 uint32_t src_h;
55
Boris Brezillon59570172015-02-06 16:25:06 +010056 int disc_x;
57 int disc_y;
58 int disc_w;
59 int disc_h;
60
Boris Brezillonebab87a2016-03-15 18:01:08 +010061 int ahb_id;
62
Boris Brezillon2389fc12015-02-05 16:32:33 +010063 /* These fields are private and should not be touched */
Boris Brezillon9a45d332017-02-06 18:57:19 +010064 int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
65 unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
66 int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
67 int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
Boris Brezillon2389fc12015-02-05 16:32:33 +010068 int nplanes;
Boris Brezillon9a45d332017-02-06 18:57:19 +010069
70 /* DMA descriptors. */
71 struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
Boris Brezillon2389fc12015-02-05 16:32:33 +010072};
73
74static inline struct atmel_hlcdc_plane_state *
75drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
76{
77 return container_of(s, struct atmel_hlcdc_plane_state, base);
78}
79
Boris Brezillon1a396782015-01-06 11:13:28 +010080#define SUBPIXEL_MASK 0xffff
81
82static uint32_t rgb_formats[] = {
Peter Rosin364a7bf2017-06-22 07:03:11 +020083 DRM_FORMAT_C8,
Boris Brezillon1a396782015-01-06 11:13:28 +010084 DRM_FORMAT_XRGB4444,
85 DRM_FORMAT_ARGB4444,
86 DRM_FORMAT_RGBA4444,
87 DRM_FORMAT_ARGB1555,
88 DRM_FORMAT_RGB565,
89 DRM_FORMAT_RGB888,
90 DRM_FORMAT_XRGB8888,
91 DRM_FORMAT_ARGB8888,
92 DRM_FORMAT_RGBA8888,
93};
94
95struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
96 .formats = rgb_formats,
97 .nformats = ARRAY_SIZE(rgb_formats),
98};
99
100static uint32_t rgb_and_yuv_formats[] = {
Peter Rosin364a7bf2017-06-22 07:03:11 +0200101 DRM_FORMAT_C8,
Boris Brezillon1a396782015-01-06 11:13:28 +0100102 DRM_FORMAT_XRGB4444,
103 DRM_FORMAT_ARGB4444,
104 DRM_FORMAT_RGBA4444,
105 DRM_FORMAT_ARGB1555,
106 DRM_FORMAT_RGB565,
107 DRM_FORMAT_RGB888,
108 DRM_FORMAT_XRGB8888,
109 DRM_FORMAT_ARGB8888,
110 DRM_FORMAT_RGBA8888,
111 DRM_FORMAT_AYUV,
112 DRM_FORMAT_YUYV,
113 DRM_FORMAT_UYVY,
114 DRM_FORMAT_YVYU,
115 DRM_FORMAT_VYUY,
116 DRM_FORMAT_NV21,
117 DRM_FORMAT_NV61,
118 DRM_FORMAT_YUV422,
119 DRM_FORMAT_YUV420,
120};
121
122struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
123 .formats = rgb_and_yuv_formats,
124 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
125};
126
127static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
128{
129 switch (format) {
Peter Rosin364a7bf2017-06-22 07:03:11 +0200130 case DRM_FORMAT_C8:
131 *mode = ATMEL_HLCDC_C8_MODE;
132 break;
Boris Brezillon1a396782015-01-06 11:13:28 +0100133 case DRM_FORMAT_XRGB4444:
134 *mode = ATMEL_HLCDC_XRGB4444_MODE;
135 break;
136 case DRM_FORMAT_ARGB4444:
137 *mode = ATMEL_HLCDC_ARGB4444_MODE;
138 break;
139 case DRM_FORMAT_RGBA4444:
140 *mode = ATMEL_HLCDC_RGBA4444_MODE;
141 break;
142 case DRM_FORMAT_RGB565:
143 *mode = ATMEL_HLCDC_RGB565_MODE;
144 break;
145 case DRM_FORMAT_RGB888:
146 *mode = ATMEL_HLCDC_RGB888_MODE;
147 break;
148 case DRM_FORMAT_ARGB1555:
149 *mode = ATMEL_HLCDC_ARGB1555_MODE;
150 break;
151 case DRM_FORMAT_XRGB8888:
152 *mode = ATMEL_HLCDC_XRGB8888_MODE;
153 break;
154 case DRM_FORMAT_ARGB8888:
155 *mode = ATMEL_HLCDC_ARGB8888_MODE;
156 break;
157 case DRM_FORMAT_RGBA8888:
158 *mode = ATMEL_HLCDC_RGBA8888_MODE;
159 break;
160 case DRM_FORMAT_AYUV:
161 *mode = ATMEL_HLCDC_AYUV_MODE;
162 break;
163 case DRM_FORMAT_YUYV:
164 *mode = ATMEL_HLCDC_YUYV_MODE;
165 break;
166 case DRM_FORMAT_UYVY:
167 *mode = ATMEL_HLCDC_UYVY_MODE;
168 break;
169 case DRM_FORMAT_YVYU:
170 *mode = ATMEL_HLCDC_YVYU_MODE;
171 break;
172 case DRM_FORMAT_VYUY:
173 *mode = ATMEL_HLCDC_VYUY_MODE;
174 break;
175 case DRM_FORMAT_NV21:
176 *mode = ATMEL_HLCDC_NV21_MODE;
177 break;
178 case DRM_FORMAT_NV61:
179 *mode = ATMEL_HLCDC_NV61_MODE;
180 break;
181 case DRM_FORMAT_YUV420:
182 *mode = ATMEL_HLCDC_YUV420_MODE;
183 break;
184 case DRM_FORMAT_YUV422:
185 *mode = ATMEL_HLCDC_YUV422_MODE;
186 break;
187 default:
188 return -ENOTSUPP;
189 }
190
191 return 0;
192}
193
Boris Brezillon1a396782015-01-06 11:13:28 +0100194static u32 heo_downscaling_xcoef[] = {
195 0x11343311,
196 0x000000f7,
197 0x1635300c,
198 0x000000f9,
199 0x1b362c08,
200 0x000000fb,
201 0x1f372804,
202 0x000000fe,
203 0x24382400,
204 0x00000000,
205 0x28371ffe,
206 0x00000004,
207 0x2c361bfb,
208 0x00000008,
209 0x303516f9,
210 0x0000000c,
211};
212
213static u32 heo_downscaling_ycoef[] = {
214 0x00123737,
215 0x00173732,
216 0x001b382d,
217 0x001f3928,
218 0x00243824,
219 0x0028391f,
220 0x002d381b,
221 0x00323717,
222};
223
224static u32 heo_upscaling_xcoef[] = {
225 0xf74949f7,
226 0x00000000,
227 0xf55f33fb,
228 0x000000fe,
229 0xf5701efe,
230 0x000000ff,
231 0xf87c0dff,
232 0x00000000,
233 0x00800000,
234 0x00000000,
235 0x0d7cf800,
236 0x000000ff,
237 0x1e70f5ff,
238 0x000000fe,
239 0x335ff5fe,
240 0x000000fb,
241};
242
243static u32 heo_upscaling_ycoef[] = {
244 0x00004040,
245 0x00075920,
246 0x00056f0c,
247 0x00027b03,
248 0x00008000,
249 0x00037b02,
250 0x000c6f05,
251 0x00205907,
252};
253
Boris Brezillon9a45d332017-02-06 18:57:19 +0100254#define ATMEL_HLCDC_XPHIDEF 4
255#define ATMEL_HLCDC_YPHIDEF 4
256
257static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
258 u32 dstsize,
259 u32 phidef)
260{
261 u32 factor, max_memsize;
262
263 factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
264 max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
265
266 if (max_memsize > srcsize - 1)
267 factor--;
268
269 return factor;
270}
271
272static void
273atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
274 const u32 *coeff_tab, int size,
275 unsigned int cfg_offs)
276{
277 int i;
278
279 for (i = 0; i < size; i++)
280 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
281 coeff_tab[i]);
282}
283
284void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
285 struct atmel_hlcdc_plane_state *state)
286{
287 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
288 u32 xfactor, yfactor;
289
290 if (!desc->layout.scaler_config)
291 return;
292
293 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
294 atmel_hlcdc_layer_write_cfg(&plane->layer,
295 desc->layout.scaler_config, 0);
296 return;
297 }
298
299 if (desc->layout.phicoeffs.x) {
300 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
301 state->crtc_w,
302 ATMEL_HLCDC_XPHIDEF);
303
304 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
305 state->crtc_h,
306 ATMEL_HLCDC_YPHIDEF);
307
308 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
309 state->crtc_w < state->src_w ?
310 heo_downscaling_xcoef :
311 heo_upscaling_xcoef,
312 ARRAY_SIZE(heo_upscaling_xcoef),
313 desc->layout.phicoeffs.x);
314
315 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
316 state->crtc_h < state->src_h ?
317 heo_downscaling_ycoef :
318 heo_upscaling_ycoef,
319 ARRAY_SIZE(heo_upscaling_ycoef),
320 desc->layout.phicoeffs.y);
321 } else {
322 xfactor = (1024 * state->src_w) / state->crtc_w;
323 yfactor = (1024 * state->src_h) / state->crtc_h;
324 }
325
326 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
327 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
328 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
329 yfactor));
330}
331
Boris Brezillon1a396782015-01-06 11:13:28 +0100332static void
333atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100334 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100335{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100336 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100337
Boris Brezillon9a45d332017-02-06 18:57:19 +0100338 if (desc->layout.size)
339 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
340 ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
341 state->crtc_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100342
Boris Brezillon9a45d332017-02-06 18:57:19 +0100343 if (desc->layout.memsize)
344 atmel_hlcdc_layer_write_cfg(&plane->layer,
345 desc->layout.memsize,
346 ATMEL_HLCDC_LAYER_SIZE(state->src_w,
347 state->src_h));
Boris Brezillon1a396782015-01-06 11:13:28 +0100348
Boris Brezillon9a45d332017-02-06 18:57:19 +0100349 if (desc->layout.pos)
350 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
351 ATMEL_HLCDC_LAYER_POS(state->crtc_x,
352 state->crtc_y));
Boris Brezillon1a396782015-01-06 11:13:28 +0100353
Boris Brezillon9a45d332017-02-06 18:57:19 +0100354 atmel_hlcdc_plane_setup_scaler(plane, state);
Boris Brezillon1a396782015-01-06 11:13:28 +0100355}
356
357static void
358atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100359 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100360{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100361 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
362 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Maxime Riparde2e287f2017-12-22 15:31:27 +0100363 const struct drm_format_info *format = state->base.fb->format;
Boris Brezillon9a45d332017-02-06 18:57:19 +0100364
365 /*
366 * Rotation optimization is not working on RGB888 (rotation is still
367 * working but without any optimization).
368 */
Maxime Riparde2e287f2017-12-22 15:31:27 +0100369 if (format->format == DRM_FORMAT_RGB888)
Boris Brezillon9a45d332017-02-06 18:57:19 +0100370 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
371
372 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
373 cfg);
374
375 cfg = ATMEL_HLCDC_LAYER_DMA;
Boris Brezillon1a396782015-01-06 11:13:28 +0100376
377 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
378 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
379 ATMEL_HLCDC_LAYER_ITER;
380
Maxime Riparde2e287f2017-12-22 15:31:27 +0100381 if (format->has_alpha)
Boris Brezillon1a396782015-01-06 11:13:28 +0100382 cfg |= ATMEL_HLCDC_LAYER_LAEN;
383 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100384 cfg |= ATMEL_HLCDC_LAYER_GAEN |
Maxime Ripard7f73c102018-04-11 09:39:26 +0200385 ATMEL_HLCDC_LAYER_GA(state->base.alpha >> 8);
Boris Brezillon1a396782015-01-06 11:13:28 +0100386 }
387
Boris Brezillon9a45d332017-02-06 18:57:19 +0100388 if (state->disc_h && state->disc_w)
389 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
Boris Brezillon1a396782015-01-06 11:13:28 +0100390
Boris Brezillon9a45d332017-02-06 18:57:19 +0100391 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
392 cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100393}
394
395static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100396 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100397{
398 u32 cfg;
399 int ret;
400
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200401 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100402 &cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100403 if (ret)
404 return;
405
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200406 if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
407 state->base.fb->format->format == DRM_FORMAT_NV61) &&
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300408 drm_rotation_90_or_270(state->base.rotation))
Boris Brezillon1a396782015-01-06 11:13:28 +0100409 cfg |= ATMEL_HLCDC_YUV422ROT;
410
Boris Brezillon9a45d332017-02-06 18:57:19 +0100411 atmel_hlcdc_layer_write_cfg(&plane->layer,
412 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
Boris Brezillon1a396782015-01-06 11:13:28 +0100413}
414
Peter Rosin364a7bf2017-06-22 07:03:11 +0200415static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane)
416{
417 struct drm_crtc *crtc = plane->base.crtc;
418 struct drm_color_lut *lut;
419 int idx;
420
421 if (!crtc || !crtc->state)
422 return;
423
424 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
425 return;
426
427 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
428
429 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
430 u32 val = ((lut->red << 8) & 0xff0000) |
431 (lut->green & 0xff00) |
432 (lut->blue >> 8);
433
434 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
435 }
436}
437
Boris Brezillon1a396782015-01-06 11:13:28 +0100438static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100439 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100440{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100441 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
442 struct drm_framebuffer *fb = state->base.fb;
443 u32 sr;
Boris Brezillon1a396782015-01-06 11:13:28 +0100444 int i;
445
Boris Brezillon9a45d332017-02-06 18:57:19 +0100446 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100447
Boris Brezillon2389fc12015-02-05 16:32:33 +0100448 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100449 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
450
451 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
452
453 atmel_hlcdc_layer_write_reg(&plane->layer,
454 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
455 state->dscrs[i]->self);
456
457 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
458 atmel_hlcdc_layer_write_reg(&plane->layer,
459 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
460 state->dscrs[i]->addr);
461 atmel_hlcdc_layer_write_reg(&plane->layer,
462 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
463 state->dscrs[i]->ctrl);
464 atmel_hlcdc_layer_write_reg(&plane->layer,
465 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
466 state->dscrs[i]->self);
Boris Brezillon1a396782015-01-06 11:13:28 +0100467 }
468
Boris Brezillon9a45d332017-02-06 18:57:19 +0100469 if (desc->layout.xstride[i])
470 atmel_hlcdc_layer_write_cfg(&plane->layer,
471 desc->layout.xstride[i],
472 state->xstride[i]);
473
474 if (desc->layout.pstride[i])
475 atmel_hlcdc_layer_write_cfg(&plane->layer,
476 desc->layout.pstride[i],
477 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100478 }
479}
480
Boris Brezillonebab87a2016-03-15 18:01:08 +0100481int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
482{
483 unsigned int ahb_load[2] = { };
484 struct drm_plane *plane;
485
486 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
487 struct atmel_hlcdc_plane_state *plane_state;
488 struct drm_plane_state *plane_s;
489 unsigned int pixels, load = 0;
490 int i;
491
492 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
493 if (IS_ERR(plane_s))
494 return PTR_ERR(plane_s);
495
496 plane_state =
497 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
498
499 pixels = (plane_state->src_w * plane_state->src_h) -
500 (plane_state->disc_w * plane_state->disc_h);
501
502 for (i = 0; i < plane_state->nplanes; i++)
503 load += pixels * plane_state->bpp[i];
504
505 if (ahb_load[0] <= ahb_load[1])
506 plane_state->ahb_id = 0;
507 else
508 plane_state->ahb_id = 1;
509
510 ahb_load[plane_state->ahb_id] += load;
511 }
512
513 return 0;
514}
515
Boris Brezillon59570172015-02-06 16:25:06 +0100516int
517atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
518{
519 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
520 const struct atmel_hlcdc_layer_cfg_layout *layout;
521 struct atmel_hlcdc_plane_state *primary_state;
522 struct drm_plane_state *primary_s;
523 struct atmel_hlcdc_plane *primary;
524 struct drm_plane *ovl;
525
526 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
527 layout = &primary->layer.desc->layout;
528 if (!layout->disc_pos || !layout->disc_size)
529 return 0;
530
531 primary_s = drm_atomic_get_plane_state(c_state->state,
532 &primary->base);
533 if (IS_ERR(primary_s))
534 return PTR_ERR(primary_s);
535
536 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
537
538 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
539 struct atmel_hlcdc_plane_state *ovl_state;
540 struct drm_plane_state *ovl_s;
541
542 if (ovl == c_state->crtc->primary)
543 continue;
544
545 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
546 if (IS_ERR(ovl_s))
547 return PTR_ERR(ovl_s);
548
549 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
550
551 if (!ovl_s->fb ||
Maxime Riparde2e287f2017-12-22 15:31:27 +0100552 ovl_s->fb->format->has_alpha ||
Maxime Ripard7f73c102018-04-11 09:39:26 +0200553 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
Boris Brezillon59570172015-02-06 16:25:06 +0100554 continue;
555
556 /* TODO: implement a smarter hidden area detection */
557 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
558 continue;
559
560 disc_x = ovl_state->crtc_x;
561 disc_y = ovl_state->crtc_y;
562 disc_h = ovl_state->crtc_h;
563 disc_w = ovl_state->crtc_w;
564 }
565
Boris Brezillon59570172015-02-06 16:25:06 +0100566 primary_state->disc_x = disc_x;
567 primary_state->disc_y = disc_y;
568 primary_state->disc_w = disc_w;
569 primary_state->disc_h = disc_h;
Boris Brezillon59570172015-02-06 16:25:06 +0100570
571 return 0;
572}
573
574static void
575atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
576 struct atmel_hlcdc_plane_state *state)
577{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100578 const struct atmel_hlcdc_layer_cfg_layout *layout;
Boris Brezillon59570172015-02-06 16:25:06 +0100579
Boris Brezillon9a45d332017-02-06 18:57:19 +0100580 layout = &plane->layer.desc->layout;
581 if (!layout->disc_pos || !layout->disc_size)
Boris Brezillon59570172015-02-06 16:25:06 +0100582 return;
583
Boris Brezillon9a45d332017-02-06 18:57:19 +0100584 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
585 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
586 state->disc_y));
Boris Brezillon59570172015-02-06 16:25:06 +0100587
Boris Brezillon9a45d332017-02-06 18:57:19 +0100588 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
589 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
590 state->disc_h));
Boris Brezillon59570172015-02-06 16:25:06 +0100591}
592
Boris Brezillon2389fc12015-02-05 16:32:33 +0100593static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
594 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100595{
596 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100597 struct atmel_hlcdc_plane_state *state =
598 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100599 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100600 struct drm_framebuffer *fb = state->base.fb;
601 const struct drm_display_mode *mode;
602 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100603 unsigned int patched_crtc_w;
604 unsigned int patched_crtc_h;
605 unsigned int patched_src_w;
606 unsigned int patched_src_h;
607 unsigned int tmp;
608 int x_offset = 0;
609 int y_offset = 0;
610 int hsub = 1;
611 int vsub = 1;
612 int i;
613
Boris Brezillon2389fc12015-02-05 16:32:33 +0100614 if (!state->base.crtc || !fb)
615 return 0;
616
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100617 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100618 mode = &crtc_state->adjusted_mode;
619
620 state->src_x = s->src_x;
621 state->src_y = s->src_y;
622 state->src_h = s->src_h;
623 state->src_w = s->src_w;
624 state->crtc_x = s->crtc_x;
625 state->crtc_y = s->crtc_y;
626 state->crtc_h = s->crtc_h;
627 state->crtc_w = s->crtc_w;
628 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100629 SUBPIXEL_MASK)
630 return -EINVAL;
631
Boris Brezillon2389fc12015-02-05 16:32:33 +0100632 state->src_x >>= 16;
633 state->src_y >>= 16;
634 state->src_w >>= 16;
635 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100636
Ville Syrjäläbcb0b462016-12-14 23:30:22 +0200637 state->nplanes = fb->format->num_planes;
Boris Brezillon9a45d332017-02-06 18:57:19 +0100638 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100639 return -EINVAL;
640
641 /*
642 * Swap width and size in case of 90 or 270 degrees rotation
643 */
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300644 if (drm_rotation_90_or_270(state->base.rotation)) {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100645 tmp = state->crtc_w;
646 state->crtc_w = state->crtc_h;
647 state->crtc_h = tmp;
648 tmp = state->src_w;
649 state->src_w = state->src_h;
650 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100651 }
652
Boris Brezillon2389fc12015-02-05 16:32:33 +0100653 if (state->crtc_x + state->crtc_w > mode->hdisplay)
654 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100655 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100656 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100657
Boris Brezillon2389fc12015-02-05 16:32:33 +0100658 if (state->crtc_x < 0) {
659 patched_crtc_w += state->crtc_x;
660 x_offset = -state->crtc_x;
661 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100662 }
663
Boris Brezillon2389fc12015-02-05 16:32:33 +0100664 if (state->crtc_y + state->crtc_h > mode->vdisplay)
665 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100666 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100667 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100668
Boris Brezillon2389fc12015-02-05 16:32:33 +0100669 if (state->crtc_y < 0) {
670 patched_crtc_h += state->crtc_y;
671 y_offset = -state->crtc_y;
672 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100673 }
674
Boris Brezillon2389fc12015-02-05 16:32:33 +0100675 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
676 state->crtc_w);
677 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
678 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100679
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200680 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
681 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100682
Boris Brezillon2389fc12015-02-05 16:32:33 +0100683 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100684 unsigned int offset = 0;
685 int xdiv = i ? hsub : 1;
686 int ydiv = i ? vsub : 1;
687
Ville Syrjälä353c8592016-12-14 23:30:57 +0200688 state->bpp[i] = fb->format->cpp[i];
Boris Brezillon2389fc12015-02-05 16:32:33 +0100689 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100690 return -EINVAL;
691
Robert Fossc2c446a2017-05-19 16:50:17 -0400692 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
693 case DRM_MODE_ROTATE_90:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100694 offset = ((y_offset + state->src_y + patched_src_w - 1) /
695 ydiv) * fb->pitches[i];
696 offset += ((x_offset + state->src_x) / xdiv) *
697 state->bpp[i];
698 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
699 fb->pitches[i];
700 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100701 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400702 case DRM_MODE_ROTATE_180:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100703 offset = ((y_offset + state->src_y + patched_src_h - 1) /
704 ydiv) * fb->pitches[i];
705 offset += ((x_offset + state->src_x + patched_src_w - 1) /
706 xdiv) * state->bpp[i];
707 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
708 state->bpp[i]) - fb->pitches[i];
709 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100710 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400711 case DRM_MODE_ROTATE_270:
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 + patched_src_h - 1) /
715 xdiv) * state->bpp[i];
716 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
717 fb->pitches[i]) -
718 (2 * state->bpp[i]);
719 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100720 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400721 case DRM_MODE_ROTATE_0:
Boris Brezillon1a396782015-01-06 11:13:28 +0100722 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100723 offset = ((y_offset + state->src_y) / ydiv) *
724 fb->pitches[i];
725 offset += ((x_offset + state->src_x) / xdiv) *
726 state->bpp[i];
727 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100728 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100729 state->bpp[i]);
730 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100731 break;
732 }
733
Boris Brezillon2389fc12015-02-05 16:32:33 +0100734 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100735 }
736
Boris Brezillon2389fc12015-02-05 16:32:33 +0100737 state->src_w = patched_src_w;
738 state->src_h = patched_src_h;
739 state->crtc_w = patched_crtc_w;
740 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100741
Boris Brezillon9a45d332017-02-06 18:57:19 +0100742 if (!desc->layout.size &&
Boris Brezillon2389fc12015-02-05 16:32:33 +0100743 (mode->hdisplay != state->crtc_w ||
744 mode->vdisplay != state->crtc_h))
745 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100746
Boris Brezillon9a45d332017-02-06 18:57:19 +0100747 if (desc->max_height && state->crtc_h > desc->max_height)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100748 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100749
Boris Brezillon9a45d332017-02-06 18:57:19 +0100750 if (desc->max_width && state->crtc_w > desc->max_width)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100751 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100752
Boris Brezillon2389fc12015-02-05 16:32:33 +0100753 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
Boris Brezillon9a45d332017-02-06 18:57:19 +0100754 (!desc->layout.memsize ||
Maxime Riparde2e287f2017-12-22 15:31:27 +0100755 state->base.fb->format->has_alpha))
Boris Brezillon2389fc12015-02-05 16:32:33 +0100756 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100757
Boris Brezillon2389fc12015-02-05 16:32:33 +0100758 if (state->crtc_x < 0 || state->crtc_y < 0)
759 return -EINVAL;
760
761 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
762 state->crtc_h + state->crtc_y > mode->vdisplay)
763 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100764
765 return 0;
766}
767
Boris Brezillon2389fc12015-02-05 16:32:33 +0100768static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
769 struct drm_plane_state *old_s)
770{
771 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
772 struct atmel_hlcdc_plane_state *state =
773 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100774 u32 sr;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100775
776 if (!p->state->crtc || !p->state->fb)
777 return;
778
779 atmel_hlcdc_plane_update_pos_and_size(plane, state);
780 atmel_hlcdc_plane_update_general_settings(plane, state);
781 atmel_hlcdc_plane_update_format(plane, state);
Peter Rosin364a7bf2017-06-22 07:03:11 +0200782 atmel_hlcdc_plane_update_clut(plane);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100783 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100784 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100785
Boris Brezillon9a45d332017-02-06 18:57:19 +0100786 /* Enable the overrun interrupts. */
787 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
788 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
789 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
790 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
791
792 /* Apply the new config at the next SOF event. */
793 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
794 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
795 ATMEL_HLCDC_LAYER_UPDATE |
796 (sr & ATMEL_HLCDC_LAYER_EN ?
797 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
Boris Brezillon2389fc12015-02-05 16:32:33 +0100798}
799
800static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
801 struct drm_plane_state *old_state)
802{
803 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
804
Boris Brezillon9a45d332017-02-06 18:57:19 +0100805 /* Disable interrupts */
806 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
807 0xffffffff);
808
809 /* Disable the layer */
810 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
811 ATMEL_HLCDC_LAYER_RST |
812 ATMEL_HLCDC_LAYER_A2Q |
813 ATMEL_HLCDC_LAYER_UPDATE);
814
815 /* Clear all pending interrupts */
816 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100817}
818
819static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
820{
821 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
822
823 if (plane->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300824 drm_framebuffer_put(plane->base.fb);
Boris Brezillon1a396782015-01-06 11:13:28 +0100825
Boris Brezillon1a396782015-01-06 11:13:28 +0100826 drm_plane_cleanup(p);
Boris Brezillon1a396782015-01-06 11:13:28 +0100827}
828
Maxime Ripard7f73c102018-04-11 09:39:26 +0200829static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
Boris Brezillon1a396782015-01-06 11:13:28 +0100830{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100831 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100832
833 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
Maxime Ripard7f73c102018-04-11 09:39:26 +0200834 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
835 int ret;
836
837 ret = drm_plane_create_alpha_property(&plane->base);
838 if (ret)
839 return ret;
840 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100841
Stefan Agner9fcf2b32018-06-17 10:48:22 +0200842 if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300843 int ret;
844
845 ret = drm_plane_create_rotation_property(&plane->base,
Robert Fossc2c446a2017-05-19 16:50:17 -0400846 DRM_MODE_ROTATE_0,
847 DRM_MODE_ROTATE_0 |
848 DRM_MODE_ROTATE_90 |
849 DRM_MODE_ROTATE_180 |
850 DRM_MODE_ROTATE_270);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300851 if (ret)
852 return ret;
853 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100854
855 if (desc->layout.csc) {
856 /*
857 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
858 * userspace modify these factors (using a BLOB property ?).
859 */
Boris Brezillon9a45d332017-02-06 18:57:19 +0100860 atmel_hlcdc_layer_write_cfg(&plane->layer,
861 desc->layout.csc,
862 0x4c900091);
863 atmel_hlcdc_layer_write_cfg(&plane->layer,
864 desc->layout.csc + 1,
865 0x7a5f5090);
866 atmel_hlcdc_layer_write_cfg(&plane->layer,
867 desc->layout.csc + 2,
868 0x40040890);
Boris Brezillon1a396782015-01-06 11:13:28 +0100869 }
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300870
871 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100872}
873
Boris Brezillon9a45d332017-02-06 18:57:19 +0100874void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
875{
876 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
877 u32 isr;
878
879 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
880
881 /*
882 * There's not much we can do in case of overrun except informing
883 * the user. However, we are in interrupt context here, hence the
884 * use of dev_dbg().
885 */
886 if (isr &
887 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
888 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
889 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
890 desc->name);
891}
892
Arvind Yadavd95a8e72017-07-03 21:53:54 +0530893static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100894 .atomic_check = atmel_hlcdc_plane_atomic_check,
895 .atomic_update = atmel_hlcdc_plane_atomic_update,
896 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
897};
898
Boris Brezillon9a45d332017-02-06 18:57:19 +0100899static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
900 struct atmel_hlcdc_plane_state *state)
901{
902 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
903 int i;
904
905 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
906 struct atmel_hlcdc_dma_channel_dscr *dscr;
907 dma_addr_t dscr_dma;
908
909 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
910 if (!dscr)
911 goto err;
912
913 dscr->addr = 0;
914 dscr->next = dscr_dma;
915 dscr->self = dscr_dma;
916 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
917
918 state->dscrs[i] = dscr;
919 }
920
921 return 0;
922
923err:
924 for (i--; i >= 0; i--) {
925 dma_pool_free(dc->dscrpool, state->dscrs[i],
926 state->dscrs[i]->self);
927 }
928
929 return -ENOMEM;
930}
931
Boris Brezillon2389fc12015-02-05 16:32:33 +0100932static void atmel_hlcdc_plane_reset(struct drm_plane *p)
933{
934 struct atmel_hlcdc_plane_state *state;
935
936 if (p->state) {
937 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
938
939 if (state->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300940 drm_framebuffer_put(state->base.fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100941
942 kfree(state);
943 p->state = NULL;
944 }
945
946 state = kzalloc(sizeof(*state), GFP_KERNEL);
947 if (state) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100948 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
949 kfree(state);
950 dev_err(p->dev->dev,
951 "Failed to allocate initial plane state\n");
952 return;
953 }
954
Boris Brezillon2389fc12015-02-05 16:32:33 +0100955 p->state = &state->base;
Maxime Ripard7f73c102018-04-11 09:39:26 +0200956 p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100957 p->state->plane = p;
958 }
959}
960
961static struct drm_plane_state *
962atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
963{
964 struct atmel_hlcdc_plane_state *state =
965 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
966 struct atmel_hlcdc_plane_state *copy;
967
968 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
969 if (!copy)
970 return NULL;
971
Boris Brezillon9a45d332017-02-06 18:57:19 +0100972 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
973 kfree(copy);
974 return NULL;
975 }
Boris Brezillon59570172015-02-06 16:25:06 +0100976
Boris Brezillon2389fc12015-02-05 16:32:33 +0100977 if (copy->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300978 drm_framebuffer_get(copy->base.fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100979
980 return &copy->base;
981}
982
Boris Brezillon9a45d332017-02-06 18:57:19 +0100983static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100984 struct drm_plane_state *s)
985{
986 struct atmel_hlcdc_plane_state *state =
987 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100988 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
989 int i;
990
991 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
992 dma_pool_free(dc->dscrpool, state->dscrs[i],
993 state->dscrs[i]->self);
994 }
Boris Brezillon2389fc12015-02-05 16:32:33 +0100995
996 if (s->fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300997 drm_framebuffer_put(s->fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100998
999 kfree(state);
1000}
1001
Arvind Yadavd95a8e72017-07-03 21:53:54 +05301002static const struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +01001003 .update_plane = drm_atomic_helper_update_plane,
1004 .disable_plane = drm_atomic_helper_disable_plane,
Boris Brezillon1a396782015-01-06 11:13:28 +01001005 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001006 .reset = atmel_hlcdc_plane_reset,
1007 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1008 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
Boris Brezillon1a396782015-01-06 11:13:28 +01001009};
1010
Boris Brezillon9a45d332017-02-06 18:57:19 +01001011static int atmel_hlcdc_plane_create(struct drm_device *dev,
Maxime Ripard7f73c102018-04-11 09:39:26 +02001012 const struct atmel_hlcdc_layer_desc *desc)
Boris Brezillon1a396782015-01-06 11:13:28 +01001013{
Boris Brezillon9a45d332017-02-06 18:57:19 +01001014 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001015 struct atmel_hlcdc_plane *plane;
1016 enum drm_plane_type type;
1017 int ret;
1018
1019 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1020 if (!plane)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001021 return -ENOMEM;
Boris Brezillon1a396782015-01-06 11:13:28 +01001022
Boris Brezillon9a45d332017-02-06 18:57:19 +01001023 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
Boris Brezillon1a396782015-01-06 11:13:28 +01001024
1025 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1026 type = DRM_PLANE_TYPE_PRIMARY;
1027 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1028 type = DRM_PLANE_TYPE_CURSOR;
1029 else
1030 type = DRM_PLANE_TYPE_OVERLAY;
1031
1032 ret = drm_universal_plane_init(dev, &plane->base, 0,
1033 &layer_plane_funcs,
1034 desc->formats->formats,
Ben Widawskye6fc3b62017-07-23 20:46:38 -07001035 desc->formats->nformats,
1036 NULL, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +01001037 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001038 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001039
Boris Brezillon2389fc12015-02-05 16:32:33 +01001040 drm_plane_helper_add(&plane->base,
1041 &atmel_hlcdc_layer_plane_helper_funcs);
1042
Boris Brezillon1a396782015-01-06 11:13:28 +01001043 /* Set default property values*/
Maxime Ripard7f73c102018-04-11 09:39:26 +02001044 ret = atmel_hlcdc_plane_init_properties(plane);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +03001045 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001046 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001047
Boris Brezillon9a45d332017-02-06 18:57:19 +01001048 dc->layers[desc->id] = &plane->layer;
1049
1050 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001051}
1052
Boris Brezillon9a45d332017-02-06 18:57:19 +01001053int atmel_hlcdc_create_planes(struct drm_device *dev)
Boris Brezillon1a396782015-01-06 11:13:28 +01001054{
1055 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001056 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1057 int nlayers = dc->desc->nlayers;
Boris Brezillon9a45d332017-02-06 18:57:19 +01001058 int i, ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001059
Boris Brezillon9a45d332017-02-06 18:57:19 +01001060 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1061 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1062 sizeof(u64), 0);
1063 if (!dc->dscrpool)
1064 return -ENOMEM;
1065
Boris Brezillon1a396782015-01-06 11:13:28 +01001066 for (i = 0; i < nlayers; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +01001067 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1068 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1069 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +01001070 continue;
1071
Maxime Ripard7f73c102018-04-11 09:39:26 +02001072 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
Boris Brezillon9a45d332017-02-06 18:57:19 +01001073 if (ret)
1074 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001075 }
1076
Boris Brezillon9a45d332017-02-06 18:57:19 +01001077 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001078}