blob: 15c74527ba49f148d9ea41f94eca3d1e07566dc7 [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
Ville Syrjälä0010ac32018-04-05 18:13:50 +0300415static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
416 struct atmel_hlcdc_plane_state *state)
Peter Rosin364a7bf2017-06-22 07:03:11 +0200417{
Ville Syrjälä0010ac32018-04-05 18:13:50 +0300418 struct drm_crtc *crtc = state->base.crtc;
Peter Rosin364a7bf2017-06-22 07:03:11 +0200419 struct drm_color_lut *lut;
420 int idx;
421
422 if (!crtc || !crtc->state)
423 return;
424
425 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
426 return;
427
428 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
429
430 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
431 u32 val = ((lut->red << 8) & 0xff0000) |
432 (lut->green & 0xff00) |
433 (lut->blue >> 8);
434
435 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
436 }
437}
438
Boris Brezillon1a396782015-01-06 11:13:28 +0100439static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100440 struct atmel_hlcdc_plane_state *state)
Boris Brezillon1a396782015-01-06 11:13:28 +0100441{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100442 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
443 struct drm_framebuffer *fb = state->base.fb;
444 u32 sr;
Boris Brezillon1a396782015-01-06 11:13:28 +0100445 int i;
446
Boris Brezillon9a45d332017-02-06 18:57:19 +0100447 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100448
Boris Brezillon2389fc12015-02-05 16:32:33 +0100449 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100450 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
451
452 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
453
454 atmel_hlcdc_layer_write_reg(&plane->layer,
455 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
456 state->dscrs[i]->self);
457
458 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
459 atmel_hlcdc_layer_write_reg(&plane->layer,
460 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
461 state->dscrs[i]->addr);
462 atmel_hlcdc_layer_write_reg(&plane->layer,
463 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
464 state->dscrs[i]->ctrl);
465 atmel_hlcdc_layer_write_reg(&plane->layer,
466 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
467 state->dscrs[i]->self);
Boris Brezillon1a396782015-01-06 11:13:28 +0100468 }
469
Boris Brezillon9a45d332017-02-06 18:57:19 +0100470 if (desc->layout.xstride[i])
471 atmel_hlcdc_layer_write_cfg(&plane->layer,
472 desc->layout.xstride[i],
473 state->xstride[i]);
474
475 if (desc->layout.pstride[i])
476 atmel_hlcdc_layer_write_cfg(&plane->layer,
477 desc->layout.pstride[i],
478 state->pstride[i]);
Boris Brezillon1a396782015-01-06 11:13:28 +0100479 }
480}
481
Boris Brezillonebab87a2016-03-15 18:01:08 +0100482int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
483{
484 unsigned int ahb_load[2] = { };
485 struct drm_plane *plane;
486
487 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
488 struct atmel_hlcdc_plane_state *plane_state;
489 struct drm_plane_state *plane_s;
490 unsigned int pixels, load = 0;
491 int i;
492
493 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
494 if (IS_ERR(plane_s))
495 return PTR_ERR(plane_s);
496
497 plane_state =
498 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
499
500 pixels = (plane_state->src_w * plane_state->src_h) -
501 (plane_state->disc_w * plane_state->disc_h);
502
503 for (i = 0; i < plane_state->nplanes; i++)
504 load += pixels * plane_state->bpp[i];
505
506 if (ahb_load[0] <= ahb_load[1])
507 plane_state->ahb_id = 0;
508 else
509 plane_state->ahb_id = 1;
510
511 ahb_load[plane_state->ahb_id] += load;
512 }
513
514 return 0;
515}
516
Boris Brezillon59570172015-02-06 16:25:06 +0100517int
518atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
519{
520 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
521 const struct atmel_hlcdc_layer_cfg_layout *layout;
522 struct atmel_hlcdc_plane_state *primary_state;
523 struct drm_plane_state *primary_s;
524 struct atmel_hlcdc_plane *primary;
525 struct drm_plane *ovl;
526
527 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
528 layout = &primary->layer.desc->layout;
529 if (!layout->disc_pos || !layout->disc_size)
530 return 0;
531
532 primary_s = drm_atomic_get_plane_state(c_state->state,
533 &primary->base);
534 if (IS_ERR(primary_s))
535 return PTR_ERR(primary_s);
536
537 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
538
539 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
540 struct atmel_hlcdc_plane_state *ovl_state;
541 struct drm_plane_state *ovl_s;
542
543 if (ovl == c_state->crtc->primary)
544 continue;
545
546 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
547 if (IS_ERR(ovl_s))
548 return PTR_ERR(ovl_s);
549
550 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
551
552 if (!ovl_s->fb ||
Maxime Riparde2e287f2017-12-22 15:31:27 +0100553 ovl_s->fb->format->has_alpha ||
Maxime Ripard7f73c102018-04-11 09:39:26 +0200554 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
Boris Brezillon59570172015-02-06 16:25:06 +0100555 continue;
556
557 /* TODO: implement a smarter hidden area detection */
558 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
559 continue;
560
561 disc_x = ovl_state->crtc_x;
562 disc_y = ovl_state->crtc_y;
563 disc_h = ovl_state->crtc_h;
564 disc_w = ovl_state->crtc_w;
565 }
566
Boris Brezillon59570172015-02-06 16:25:06 +0100567 primary_state->disc_x = disc_x;
568 primary_state->disc_y = disc_y;
569 primary_state->disc_w = disc_w;
570 primary_state->disc_h = disc_h;
Boris Brezillon59570172015-02-06 16:25:06 +0100571
572 return 0;
573}
574
575static void
576atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
577 struct atmel_hlcdc_plane_state *state)
578{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100579 const struct atmel_hlcdc_layer_cfg_layout *layout;
Boris Brezillon59570172015-02-06 16:25:06 +0100580
Boris Brezillon9a45d332017-02-06 18:57:19 +0100581 layout = &plane->layer.desc->layout;
582 if (!layout->disc_pos || !layout->disc_size)
Boris Brezillon59570172015-02-06 16:25:06 +0100583 return;
584
Boris Brezillon9a45d332017-02-06 18:57:19 +0100585 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
586 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
587 state->disc_y));
Boris Brezillon59570172015-02-06 16:25:06 +0100588
Boris Brezillon9a45d332017-02-06 18:57:19 +0100589 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
590 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
591 state->disc_h));
Boris Brezillon59570172015-02-06 16:25:06 +0100592}
593
Boris Brezillon2389fc12015-02-05 16:32:33 +0100594static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
595 struct drm_plane_state *s)
Boris Brezillon1a396782015-01-06 11:13:28 +0100596{
597 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100598 struct atmel_hlcdc_plane_state *state =
599 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100600 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100601 struct drm_framebuffer *fb = state->base.fb;
602 const struct drm_display_mode *mode;
603 struct drm_crtc_state *crtc_state;
Boris Brezillon1a396782015-01-06 11:13:28 +0100604 unsigned int patched_crtc_w;
605 unsigned int patched_crtc_h;
606 unsigned int patched_src_w;
607 unsigned int patched_src_h;
608 unsigned int tmp;
609 int x_offset = 0;
610 int y_offset = 0;
611 int hsub = 1;
612 int vsub = 1;
613 int i;
614
Boris Brezillon2389fc12015-02-05 16:32:33 +0100615 if (!state->base.crtc || !fb)
616 return 0;
617
Andrzej Hajdab47ff7e2016-03-15 13:46:28 +0100618 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100619 mode = &crtc_state->adjusted_mode;
620
621 state->src_x = s->src_x;
622 state->src_y = s->src_y;
623 state->src_h = s->src_h;
624 state->src_w = s->src_w;
625 state->crtc_x = s->crtc_x;
626 state->crtc_y = s->crtc_y;
627 state->crtc_h = s->crtc_h;
628 state->crtc_w = s->crtc_w;
629 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
Boris Brezillon1a396782015-01-06 11:13:28 +0100630 SUBPIXEL_MASK)
631 return -EINVAL;
632
Boris Brezillon2389fc12015-02-05 16:32:33 +0100633 state->src_x >>= 16;
634 state->src_y >>= 16;
635 state->src_w >>= 16;
636 state->src_h >>= 16;
Boris Brezillon1a396782015-01-06 11:13:28 +0100637
Ville Syrjäläbcb0b462016-12-14 23:30:22 +0200638 state->nplanes = fb->format->num_planes;
Boris Brezillon9a45d332017-02-06 18:57:19 +0100639 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
Boris Brezillon1a396782015-01-06 11:13:28 +0100640 return -EINVAL;
641
642 /*
643 * Swap width and size in case of 90 or 270 degrees rotation
644 */
Ville Syrjäläbd2ef252016-09-26 19:30:46 +0300645 if (drm_rotation_90_or_270(state->base.rotation)) {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100646 tmp = state->crtc_w;
647 state->crtc_w = state->crtc_h;
648 state->crtc_h = tmp;
649 tmp = state->src_w;
650 state->src_w = state->src_h;
651 state->src_h = tmp;
Boris Brezillon1a396782015-01-06 11:13:28 +0100652 }
653
Boris Brezillon2389fc12015-02-05 16:32:33 +0100654 if (state->crtc_x + state->crtc_w > mode->hdisplay)
655 patched_crtc_w = mode->hdisplay - state->crtc_x;
Boris Brezillon1a396782015-01-06 11:13:28 +0100656 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100657 patched_crtc_w = state->crtc_w;
Boris Brezillon1a396782015-01-06 11:13:28 +0100658
Boris Brezillon2389fc12015-02-05 16:32:33 +0100659 if (state->crtc_x < 0) {
660 patched_crtc_w += state->crtc_x;
661 x_offset = -state->crtc_x;
662 state->crtc_x = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100663 }
664
Boris Brezillon2389fc12015-02-05 16:32:33 +0100665 if (state->crtc_y + state->crtc_h > mode->vdisplay)
666 patched_crtc_h = mode->vdisplay - state->crtc_y;
Boris Brezillon1a396782015-01-06 11:13:28 +0100667 else
Boris Brezillon2389fc12015-02-05 16:32:33 +0100668 patched_crtc_h = state->crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100669
Boris Brezillon2389fc12015-02-05 16:32:33 +0100670 if (state->crtc_y < 0) {
671 patched_crtc_h += state->crtc_y;
672 y_offset = -state->crtc_y;
673 state->crtc_y = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100674 }
675
Boris Brezillon2389fc12015-02-05 16:32:33 +0100676 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
677 state->crtc_w);
678 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
679 state->crtc_h);
Boris Brezillon1a396782015-01-06 11:13:28 +0100680
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200681 hsub = drm_format_horz_chroma_subsampling(fb->format->format);
682 vsub = drm_format_vert_chroma_subsampling(fb->format->format);
Boris Brezillon1a396782015-01-06 11:13:28 +0100683
Boris Brezillon2389fc12015-02-05 16:32:33 +0100684 for (i = 0; i < state->nplanes; i++) {
Boris Brezillon1a396782015-01-06 11:13:28 +0100685 unsigned int offset = 0;
686 int xdiv = i ? hsub : 1;
687 int ydiv = i ? vsub : 1;
688
Ville Syrjälä353c8592016-12-14 23:30:57 +0200689 state->bpp[i] = fb->format->cpp[i];
Boris Brezillon2389fc12015-02-05 16:32:33 +0100690 if (!state->bpp[i])
Boris Brezillon1a396782015-01-06 11:13:28 +0100691 return -EINVAL;
692
Robert Fossc2c446a2017-05-19 16:50:17 -0400693 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
694 case DRM_MODE_ROTATE_90:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100695 offset = ((y_offset + state->src_y + patched_src_w - 1) /
696 ydiv) * fb->pitches[i];
697 offset += ((x_offset + state->src_x) / xdiv) *
698 state->bpp[i];
699 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
700 fb->pitches[i];
701 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100702 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400703 case DRM_MODE_ROTATE_180:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100704 offset = ((y_offset + state->src_y + patched_src_h - 1) /
705 ydiv) * fb->pitches[i];
706 offset += ((x_offset + state->src_x + patched_src_w - 1) /
707 xdiv) * state->bpp[i];
708 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
709 state->bpp[i]) - fb->pitches[i];
710 state->pstride[i] = -2 * state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100711 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400712 case DRM_MODE_ROTATE_270:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100713 offset = ((y_offset + state->src_y) / ydiv) *
714 fb->pitches[i];
715 offset += ((x_offset + state->src_x + patched_src_h - 1) /
716 xdiv) * state->bpp[i];
717 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
718 fb->pitches[i]) -
719 (2 * state->bpp[i]);
720 state->pstride[i] = fb->pitches[i] - state->bpp[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100721 break;
Robert Fossc2c446a2017-05-19 16:50:17 -0400722 case DRM_MODE_ROTATE_0:
Boris Brezillon1a396782015-01-06 11:13:28 +0100723 default:
Boris Brezillon2389fc12015-02-05 16:32:33 +0100724 offset = ((y_offset + state->src_y) / ydiv) *
725 fb->pitches[i];
726 offset += ((x_offset + state->src_x) / xdiv) *
727 state->bpp[i];
728 state->xstride[i] = fb->pitches[i] -
Boris Brezillon1a396782015-01-06 11:13:28 +0100729 ((patched_src_w / xdiv) *
Boris Brezillon2389fc12015-02-05 16:32:33 +0100730 state->bpp[i]);
731 state->pstride[i] = 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100732 break;
733 }
734
Boris Brezillon2389fc12015-02-05 16:32:33 +0100735 state->offsets[i] = offset + fb->offsets[i];
Boris Brezillon1a396782015-01-06 11:13:28 +0100736 }
737
Boris Brezillon2389fc12015-02-05 16:32:33 +0100738 state->src_w = patched_src_w;
739 state->src_h = patched_src_h;
740 state->crtc_w = patched_crtc_w;
741 state->crtc_h = patched_crtc_h;
Boris Brezillon1a396782015-01-06 11:13:28 +0100742
Boris Brezillon9a45d332017-02-06 18:57:19 +0100743 if (!desc->layout.size &&
Boris Brezillon2389fc12015-02-05 16:32:33 +0100744 (mode->hdisplay != state->crtc_w ||
745 mode->vdisplay != state->crtc_h))
746 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100747
Boris Brezillon9a45d332017-02-06 18:57:19 +0100748 if (desc->max_height && state->crtc_h > desc->max_height)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100749 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100750
Boris Brezillon9a45d332017-02-06 18:57:19 +0100751 if (desc->max_width && state->crtc_w > desc->max_width)
Boris Brezillon2389fc12015-02-05 16:32:33 +0100752 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100753
Boris Brezillon2389fc12015-02-05 16:32:33 +0100754 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
Boris Brezillon9a45d332017-02-06 18:57:19 +0100755 (!desc->layout.memsize ||
Maxime Riparde2e287f2017-12-22 15:31:27 +0100756 state->base.fb->format->has_alpha))
Boris Brezillon2389fc12015-02-05 16:32:33 +0100757 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100758
Boris Brezillon2389fc12015-02-05 16:32:33 +0100759 if (state->crtc_x < 0 || state->crtc_y < 0)
760 return -EINVAL;
761
762 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
763 state->crtc_h + state->crtc_y > mode->vdisplay)
764 return -EINVAL;
Boris Brezillon1a396782015-01-06 11:13:28 +0100765
766 return 0;
767}
768
Boris Brezillon2389fc12015-02-05 16:32:33 +0100769static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
770 struct drm_plane_state *old_s)
771{
772 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
773 struct atmel_hlcdc_plane_state *state =
774 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100775 u32 sr;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100776
777 if (!p->state->crtc || !p->state->fb)
778 return;
779
780 atmel_hlcdc_plane_update_pos_and_size(plane, state);
781 atmel_hlcdc_plane_update_general_settings(plane, state);
782 atmel_hlcdc_plane_update_format(plane, state);
Ville Syrjälä0010ac32018-04-05 18:13:50 +0300783 atmel_hlcdc_plane_update_clut(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100784 atmel_hlcdc_plane_update_buffers(plane, state);
Boris Brezillon59570172015-02-06 16:25:06 +0100785 atmel_hlcdc_plane_update_disc_area(plane, state);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100786
Boris Brezillon9a45d332017-02-06 18:57:19 +0100787 /* Enable the overrun interrupts. */
788 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
789 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
790 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
791 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
792
793 /* Apply the new config at the next SOF event. */
794 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
795 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
796 ATMEL_HLCDC_LAYER_UPDATE |
797 (sr & ATMEL_HLCDC_LAYER_EN ?
798 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
Boris Brezillon2389fc12015-02-05 16:32:33 +0100799}
800
801static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
802 struct drm_plane_state *old_state)
803{
804 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
805
Boris Brezillon9a45d332017-02-06 18:57:19 +0100806 /* Disable interrupts */
807 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
808 0xffffffff);
809
810 /* Disable the layer */
811 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
812 ATMEL_HLCDC_LAYER_RST |
813 ATMEL_HLCDC_LAYER_A2Q |
814 ATMEL_HLCDC_LAYER_UPDATE);
815
816 /* Clear all pending interrupts */
817 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
Boris Brezillon1a396782015-01-06 11:13:28 +0100818}
819
820static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
821{
822 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
823
824 if (plane->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300825 drm_framebuffer_put(plane->base.fb);
Boris Brezillon1a396782015-01-06 11:13:28 +0100826
Boris Brezillon1a396782015-01-06 11:13:28 +0100827 drm_plane_cleanup(p);
Boris Brezillon1a396782015-01-06 11:13:28 +0100828}
829
Maxime Ripard7f73c102018-04-11 09:39:26 +0200830static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
Boris Brezillon1a396782015-01-06 11:13:28 +0100831{
Boris Brezillon9a45d332017-02-06 18:57:19 +0100832 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
Boris Brezillon1a396782015-01-06 11:13:28 +0100833
834 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
Maxime Ripard7f73c102018-04-11 09:39:26 +0200835 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
836 int ret;
837
838 ret = drm_plane_create_alpha_property(&plane->base);
839 if (ret)
840 return ret;
841 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100842
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300843 if (desc->layout.xstride && desc->layout.pstride) {
844 int ret;
845
846 ret = drm_plane_create_rotation_property(&plane->base,
Robert Fossc2c446a2017-05-19 16:50:17 -0400847 DRM_MODE_ROTATE_0,
848 DRM_MODE_ROTATE_0 |
849 DRM_MODE_ROTATE_90 |
850 DRM_MODE_ROTATE_180 |
851 DRM_MODE_ROTATE_270);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300852 if (ret)
853 return ret;
854 }
Boris Brezillon1a396782015-01-06 11:13:28 +0100855
856 if (desc->layout.csc) {
857 /*
858 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
859 * userspace modify these factors (using a BLOB property ?).
860 */
Boris Brezillon9a45d332017-02-06 18:57:19 +0100861 atmel_hlcdc_layer_write_cfg(&plane->layer,
862 desc->layout.csc,
863 0x4c900091);
864 atmel_hlcdc_layer_write_cfg(&plane->layer,
865 desc->layout.csc + 1,
866 0x7a5f5090);
867 atmel_hlcdc_layer_write_cfg(&plane->layer,
868 desc->layout.csc + 2,
869 0x40040890);
Boris Brezillon1a396782015-01-06 11:13:28 +0100870 }
Ville Syrjälä9fe58f02016-09-26 19:30:50 +0300871
872 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +0100873}
874
Boris Brezillon9a45d332017-02-06 18:57:19 +0100875void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
876{
877 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
878 u32 isr;
879
880 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
881
882 /*
883 * There's not much we can do in case of overrun except informing
884 * the user. However, we are in interrupt context here, hence the
885 * use of dev_dbg().
886 */
887 if (isr &
888 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
889 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
890 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
891 desc->name);
892}
893
Arvind Yadavd95a8e72017-07-03 21:53:54 +0530894static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +0100895 .atomic_check = atmel_hlcdc_plane_atomic_check,
896 .atomic_update = atmel_hlcdc_plane_atomic_update,
897 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
898};
899
Boris Brezillon9a45d332017-02-06 18:57:19 +0100900static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
901 struct atmel_hlcdc_plane_state *state)
902{
903 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
904 int i;
905
906 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
907 struct atmel_hlcdc_dma_channel_dscr *dscr;
908 dma_addr_t dscr_dma;
909
910 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
911 if (!dscr)
912 goto err;
913
914 dscr->addr = 0;
915 dscr->next = dscr_dma;
916 dscr->self = dscr_dma;
917 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
918
919 state->dscrs[i] = dscr;
920 }
921
922 return 0;
923
924err:
925 for (i--; i >= 0; i--) {
926 dma_pool_free(dc->dscrpool, state->dscrs[i],
927 state->dscrs[i]->self);
928 }
929
930 return -ENOMEM;
931}
932
Boris Brezillon2389fc12015-02-05 16:32:33 +0100933static void atmel_hlcdc_plane_reset(struct drm_plane *p)
934{
935 struct atmel_hlcdc_plane_state *state;
936
937 if (p->state) {
938 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
939
940 if (state->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300941 drm_framebuffer_put(state->base.fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100942
943 kfree(state);
944 p->state = NULL;
945 }
946
947 state = kzalloc(sizeof(*state), GFP_KERNEL);
948 if (state) {
Boris Brezillon9a45d332017-02-06 18:57:19 +0100949 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
950 kfree(state);
951 dev_err(p->dev->dev,
952 "Failed to allocate initial plane state\n");
953 return;
954 }
955
Boris Brezillon2389fc12015-02-05 16:32:33 +0100956 p->state = &state->base;
Maxime Ripard7f73c102018-04-11 09:39:26 +0200957 p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
Boris Brezillon2389fc12015-02-05 16:32:33 +0100958 p->state->plane = p;
959 }
960}
961
962static struct drm_plane_state *
963atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
964{
965 struct atmel_hlcdc_plane_state *state =
966 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
967 struct atmel_hlcdc_plane_state *copy;
968
969 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
970 if (!copy)
971 return NULL;
972
Boris Brezillon9a45d332017-02-06 18:57:19 +0100973 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
974 kfree(copy);
975 return NULL;
976 }
Boris Brezillon59570172015-02-06 16:25:06 +0100977
Boris Brezillon2389fc12015-02-05 16:32:33 +0100978 if (copy->base.fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300979 drm_framebuffer_get(copy->base.fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100980
981 return &copy->base;
982}
983
Boris Brezillon9a45d332017-02-06 18:57:19 +0100984static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
Boris Brezillon2389fc12015-02-05 16:32:33 +0100985 struct drm_plane_state *s)
986{
987 struct atmel_hlcdc_plane_state *state =
988 drm_plane_state_to_atmel_hlcdc_plane_state(s);
Boris Brezillon9a45d332017-02-06 18:57:19 +0100989 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
990 int i;
991
992 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
993 dma_pool_free(dc->dscrpool, state->dscrs[i],
994 state->dscrs[i]->self);
995 }
Boris Brezillon2389fc12015-02-05 16:32:33 +0100996
997 if (s->fb)
Cihangir Akturkf3a73542017-08-03 14:58:20 +0300998 drm_framebuffer_put(s->fb);
Boris Brezillon2389fc12015-02-05 16:32:33 +0100999
1000 kfree(state);
1001}
1002
Arvind Yadavd95a8e72017-07-03 21:53:54 +05301003static const struct drm_plane_funcs layer_plane_funcs = {
Boris Brezillon2389fc12015-02-05 16:32:33 +01001004 .update_plane = drm_atomic_helper_update_plane,
1005 .disable_plane = drm_atomic_helper_disable_plane,
Boris Brezillon1a396782015-01-06 11:13:28 +01001006 .destroy = atmel_hlcdc_plane_destroy,
Boris Brezillon2389fc12015-02-05 16:32:33 +01001007 .reset = atmel_hlcdc_plane_reset,
1008 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1009 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
Boris Brezillon1a396782015-01-06 11:13:28 +01001010};
1011
Boris Brezillon9a45d332017-02-06 18:57:19 +01001012static int atmel_hlcdc_plane_create(struct drm_device *dev,
Maxime Ripard7f73c102018-04-11 09:39:26 +02001013 const struct atmel_hlcdc_layer_desc *desc)
Boris Brezillon1a396782015-01-06 11:13:28 +01001014{
Boris Brezillon9a45d332017-02-06 18:57:19 +01001015 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001016 struct atmel_hlcdc_plane *plane;
1017 enum drm_plane_type type;
1018 int ret;
1019
1020 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1021 if (!plane)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001022 return -ENOMEM;
Boris Brezillon1a396782015-01-06 11:13:28 +01001023
Boris Brezillon9a45d332017-02-06 18:57:19 +01001024 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
Boris Brezillon1a396782015-01-06 11:13:28 +01001025
1026 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1027 type = DRM_PLANE_TYPE_PRIMARY;
1028 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1029 type = DRM_PLANE_TYPE_CURSOR;
1030 else
1031 type = DRM_PLANE_TYPE_OVERLAY;
1032
1033 ret = drm_universal_plane_init(dev, &plane->base, 0,
1034 &layer_plane_funcs,
1035 desc->formats->formats,
Ben Widawskye6fc3b62017-07-23 20:46:38 -07001036 desc->formats->nformats,
1037 NULL, type, NULL);
Boris Brezillon1a396782015-01-06 11:13:28 +01001038 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001039 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001040
Boris Brezillon2389fc12015-02-05 16:32:33 +01001041 drm_plane_helper_add(&plane->base,
1042 &atmel_hlcdc_layer_plane_helper_funcs);
1043
Boris Brezillon1a396782015-01-06 11:13:28 +01001044 /* Set default property values*/
Maxime Ripard7f73c102018-04-11 09:39:26 +02001045 ret = atmel_hlcdc_plane_init_properties(plane);
Ville Syrjälä9fe58f02016-09-26 19:30:50 +03001046 if (ret)
Boris Brezillon9a45d332017-02-06 18:57:19 +01001047 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001048
Boris Brezillon9a45d332017-02-06 18:57:19 +01001049 dc->layers[desc->id] = &plane->layer;
1050
1051 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001052}
1053
Boris Brezillon9a45d332017-02-06 18:57:19 +01001054int atmel_hlcdc_create_planes(struct drm_device *dev)
Boris Brezillon1a396782015-01-06 11:13:28 +01001055{
1056 struct atmel_hlcdc_dc *dc = dev->dev_private;
Boris Brezillon1a396782015-01-06 11:13:28 +01001057 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1058 int nlayers = dc->desc->nlayers;
Boris Brezillon9a45d332017-02-06 18:57:19 +01001059 int i, ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001060
Boris Brezillon9a45d332017-02-06 18:57:19 +01001061 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1062 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1063 sizeof(u64), 0);
1064 if (!dc->dscrpool)
1065 return -ENOMEM;
1066
Boris Brezillon1a396782015-01-06 11:13:28 +01001067 for (i = 0; i < nlayers; i++) {
Boris Brezillon9a45d332017-02-06 18:57:19 +01001068 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1069 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1070 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
Boris Brezillon1a396782015-01-06 11:13:28 +01001071 continue;
1072
Maxime Ripard7f73c102018-04-11 09:39:26 +02001073 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
Boris Brezillon9a45d332017-02-06 18:57:19 +01001074 if (ret)
1075 return ret;
Boris Brezillon1a396782015-01-06 11:13:28 +01001076 }
1077
Boris Brezillon9a45d332017-02-06 18:57:19 +01001078 return 0;
Boris Brezillon1a396782015-01-06 11:13:28 +01001079}