1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2014 Free Electrons
4 * Copyright (C) 2014 Atmel
5 *
6 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
7 */
8
9 #include <linux/dmapool.h>
10 #include <linux/mfd/atmel-hlcdc.h>
11
12 #include <drm/drm_atomic.h>
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_blend.h>
15 #include <drm/drm_fb_dma_helper.h>
16 #include <drm/drm_fourcc.h>
17 #include <drm/drm_framebuffer.h>
18 #include <drm/drm_gem_dma_helper.h>
19 #include <drm/drm_print.h>
20
21 #include "atmel_hlcdc_dc.h"
22
23 /**
24 * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
25 *
26 * @base: DRM plane state
27 * @crtc_x: x position of the plane relative to the CRTC
28 * @crtc_y: y position of the plane relative to the CRTC
29 * @crtc_w: visible width of the plane
30 * @crtc_h: visible height of the plane
31 * @src_x: x buffer position
32 * @src_y: y buffer position
33 * @src_w: buffer width
34 * @src_h: buffer height
35 * @disc_x: x discard position
36 * @disc_y: y discard position
37 * @disc_w: discard width
38 * @disc_h: discard height
39 * @ahb_id: AHB identification number
40 * @bpp: bytes per pixel deduced from pixel_format
41 * @offsets: offsets to apply to the GEM buffers
42 * @xstride: value to add to the pixel pointer between each line
43 * @pstride: value to add to the pixel pointer between each pixel
44 * @nplanes: number of planes (deduced from pixel_format)
45 * @dscrs: DMA descriptors
46 */
47 struct atmel_hlcdc_plane_state {
48 struct drm_plane_state base;
49 int crtc_x;
50 int crtc_y;
51 unsigned int crtc_w;
52 unsigned int crtc_h;
53 uint32_t src_x;
54 uint32_t src_y;
55 uint32_t src_w;
56 uint32_t src_h;
57
58 int disc_x;
59 int disc_y;
60 int disc_w;
61 int disc_h;
62
63 int ahb_id;
64
65 /* These fields are private and should not be touched */
66 int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
67 unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
68 int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
69 int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
70 int nplanes;
71
72 /* DMA descriptors. */
73 struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
74 };
75
76 static inline struct atmel_hlcdc_plane_state *
drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state * s)77 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
78 {
79 return container_of(s, struct atmel_hlcdc_plane_state, base);
80 }
81
82 static uint32_t rgb_formats[] = {
83 DRM_FORMAT_C8,
84 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
95 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
96 .formats = rgb_formats,
97 .nformats = ARRAY_SIZE(rgb_formats),
98 };
99
100 static uint32_t rgb_and_yuv_formats[] = {
101 DRM_FORMAT_C8,
102 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
122 struct 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
atmel_hlcdc_format_to_plane_mode(u32 format,u32 * mode)127 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
128 {
129 switch (format) {
130 case DRM_FORMAT_C8:
131 *mode = ATMEL_HLCDC_C8_MODE;
132 break;
133 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
194 static 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
213 static u32 heo_downscaling_ycoef[] = {
214 0x00123737,
215 0x00173732,
216 0x001b382d,
217 0x001f3928,
218 0x00243824,
219 0x0028391f,
220 0x002d381b,
221 0x00323717,
222 };
223
224 static 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
243 static u32 heo_upscaling_ycoef[] = {
244 0x00004040,
245 0x00075920,
246 0x00056f0c,
247 0x00027b03,
248 0x00008000,
249 0x00037b02,
250 0x000c6f05,
251 0x00205907,
252 };
253
254 #define ATMEL_HLCDC_XPHIDEF 4
255 #define ATMEL_HLCDC_YPHIDEF 4
256
atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,u32 dstsize,u32 phidef)257 static 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
272 static void
atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane * plane,const u32 * coeff_tab,int size,unsigned int cfg_offs)273 atmel_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
284 static
atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)285 void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
286 struct atmel_hlcdc_plane_state *state)
287 {
288 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
289 u32 xfactor, yfactor;
290
291 if (!desc->layout.scaler_config)
292 return;
293
294 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
295 atmel_hlcdc_layer_write_cfg(&plane->layer,
296 desc->layout.scaler_config, 0);
297 return;
298 }
299
300 if (desc->layout.phicoeffs.x) {
301 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
302 state->crtc_w,
303 ATMEL_HLCDC_XPHIDEF);
304
305 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
306 state->crtc_h,
307 ATMEL_HLCDC_YPHIDEF);
308
309 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
310 state->crtc_w < state->src_w ?
311 heo_downscaling_xcoef :
312 heo_upscaling_xcoef,
313 ARRAY_SIZE(heo_upscaling_xcoef),
314 desc->layout.phicoeffs.x);
315
316 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
317 state->crtc_h < state->src_h ?
318 heo_downscaling_ycoef :
319 heo_upscaling_ycoef,
320 ARRAY_SIZE(heo_upscaling_ycoef),
321 desc->layout.phicoeffs.y);
322 } else {
323 xfactor = (1024 * state->src_w) / state->crtc_w;
324 yfactor = (1024 * state->src_h) / state->crtc_h;
325 }
326
327 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
328 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
329 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
330 yfactor));
331 }
332
333 static
atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)334 void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
335 struct atmel_hlcdc_plane_state *state)
336 {
337 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
338 u32 xfactor, yfactor;
339
340 if (!desc->layout.scaler_config)
341 return;
342
343 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
344 atmel_hlcdc_layer_write_cfg(&plane->layer,
345 desc->layout.scaler_config, 0);
346 return;
347 }
348
349 /* xfactor = round[(2^20 * XMEMSIZE)/XSIZE)] */
350 xfactor = (u32)(((1 << 20) * state->src_w) / state->crtc_w);
351
352 /* yfactor = round[(2^20 * YMEMSIZE)/YSIZE)] */
353 yfactor = (u32)(((1 << 20) * state->src_h) / state->crtc_h);
354
355 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
356 ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE |
357 ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE |
358 ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE |
359 ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE);
360
361 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 1,
362 yfactor);
363 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 3,
364 xfactor);
365
366 /*
367 * With YCbCr 4:2:0 window resampling, configuration register
368 * LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT values are half
369 * the value of yfactor and xfactor.
370 *
371 * On the other hand, with YCbCr 4:2:2 window resampling, only the
372 * configuration register LCDC_HEOCFG27.HXSCFACT value is half the value
373 * of the xfactor; the value of LCDC_HEOCFG25.VXSCFACT is yfactor (no
374 * division by 2).
375 */
376 switch (state->base.fb->format->format) {
377 /* YCbCr 4:2:2 */
378 case DRM_FORMAT_YUYV:
379 case DRM_FORMAT_UYVY:
380 case DRM_FORMAT_YVYU:
381 case DRM_FORMAT_VYUY:
382 case DRM_FORMAT_YUV422:
383 case DRM_FORMAT_NV61:
384 xfactor /= 2;
385 break;
386
387 /* YCbCr 4:2:0 */
388 case DRM_FORMAT_YUV420:
389 case DRM_FORMAT_NV21:
390 yfactor /= 2;
391 xfactor /= 2;
392 break;
393 default:
394 break;
395 }
396
397 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
398 yfactor);
399 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 4,
400 xfactor);
401 }
402
403 static void
atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)404 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
405 struct atmel_hlcdc_plane_state *state)
406 {
407 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
408 struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
409
410 if (desc->layout.size)
411 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
412 ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
413 state->crtc_h));
414
415 if (desc->layout.memsize)
416 atmel_hlcdc_layer_write_cfg(&plane->layer,
417 desc->layout.memsize,
418 ATMEL_HLCDC_LAYER_SIZE(state->src_w,
419 state->src_h));
420
421 if (desc->layout.pos)
422 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
423 ATMEL_HLCDC_LAYER_POS(state->crtc_x,
424 state->crtc_y));
425
426 dc->desc->ops->plane_setup_scaler(plane, state);
427 }
428
429 static
atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)430 void atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
431 struct atmel_hlcdc_plane_state *state)
432 {
433 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
434 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
435 const struct drm_format_info *format = state->base.fb->format;
436
437 /*
438 * Rotation optimization is not working on RGB888 (rotation is still
439 * working but without any optimization).
440 */
441 if (format->format == DRM_FORMAT_RGB888)
442 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
443
444 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
445 cfg);
446
447 cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
448
449 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
450 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
451 ATMEL_HLCDC_LAYER_ITER;
452
453 if (format->has_alpha)
454 cfg |= ATMEL_HLCDC_LAYER_LAEN;
455 else
456 cfg |= ATMEL_HLCDC_LAYER_GAEN |
457 ATMEL_HLCDC_LAYER_GA(state->base.alpha);
458 }
459
460 if (state->disc_h && state->disc_w)
461 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
462
463 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
464 cfg);
465 }
466
467 static
atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)468 void atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
469 struct atmel_hlcdc_plane_state *state)
470 {
471 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
472 const struct drm_format_info *format = state->base.fb->format;
473 unsigned int cfg;
474
475 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_XLCDC_LAYER_DMA_CFG,
476 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id);
477
478 cfg = ATMEL_XLCDC_LAYER_DMA | ATMEL_XLCDC_LAYER_REP;
479
480 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
481 /*
482 * Alpha Blending bits specific to SAM9X7 SoC
483 */
484 cfg |= ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS |
485 ATMEL_XLCDC_LAYER_SFACTA_ONE |
486 ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS |
487 ATMEL_XLCDC_LAYER_DFACTA_ONE;
488 if (format->has_alpha)
489 cfg |= ATMEL_XLCDC_LAYER_A0(0xff);
490 else
491 cfg |= ATMEL_XLCDC_LAYER_A0(state->base.alpha);
492 }
493
494 if (state->disc_h && state->disc_w)
495 cfg |= ATMEL_XLCDC_LAYER_DISCEN;
496
497 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
498 cfg);
499 }
500
atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)501 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
502 struct atmel_hlcdc_plane_state *state)
503 {
504 u32 cfg;
505 int ret;
506
507 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
508 &cfg);
509 if (ret)
510 return;
511
512 if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
513 state->base.fb->format->format == DRM_FORMAT_NV61) &&
514 drm_rotation_90_or_270(state->base.rotation))
515 cfg |= ATMEL_HLCDC_YUV422ROT;
516
517 atmel_hlcdc_layer_write_cfg(&plane->layer,
518 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
519 }
520
atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)521 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
522 struct atmel_hlcdc_plane_state *state)
523 {
524 struct drm_crtc *crtc = state->base.crtc;
525 struct drm_color_lut *lut;
526 int idx;
527
528 if (!crtc || !crtc->state)
529 return;
530
531 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
532 return;
533
534 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
535
536 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
537 u32 val = ((lut->red << 8) & 0xff0000) |
538 (lut->green & 0xff00) |
539 (lut->blue >> 8);
540
541 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
542 }
543 }
544
atmel_hlcdc_update_buffers(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state,u32 sr,int i)545 static void atmel_hlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
546 struct atmel_hlcdc_plane_state *state,
547 u32 sr, int i)
548 {
549 atmel_hlcdc_layer_write_reg(&plane->layer,
550 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
551 state->dscrs[i]->self);
552
553 if (sr & ATMEL_HLCDC_LAYER_EN)
554 return;
555
556 atmel_hlcdc_layer_write_reg(&plane->layer,
557 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
558 state->dscrs[i]->addr);
559 atmel_hlcdc_layer_write_reg(&plane->layer,
560 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
561 state->dscrs[i]->ctrl);
562 atmel_hlcdc_layer_write_reg(&plane->layer,
563 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
564 state->dscrs[i]->self);
565 }
566
atmel_xlcdc_update_buffers(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state,u32 sr,int i)567 static void atmel_xlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
568 struct atmel_hlcdc_plane_state *state,
569 u32 sr, int i)
570 {
571 atmel_hlcdc_layer_write_reg(&plane->layer,
572 ATMEL_XLCDC_LAYER_PLANE_ADDR(i),
573 state->dscrs[i]->addr);
574 }
575
atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)576 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
577 struct atmel_hlcdc_plane_state *state)
578 {
579 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
580 struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
581 struct drm_framebuffer *fb = state->base.fb;
582 u32 sr;
583 int i;
584
585 if (!dc->desc->is_xlcdc)
586 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
587
588 for (i = 0; i < state->nplanes; i++) {
589 struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i);
590
591 state->dscrs[i]->addr = gem->dma_addr + state->offsets[i];
592
593 dc->desc->ops->lcdc_update_buffers(plane, state, sr, i);
594
595 if (desc->layout.xstride[i])
596 atmel_hlcdc_layer_write_cfg(&plane->layer,
597 desc->layout.xstride[i],
598 state->xstride[i]);
599
600 if (desc->layout.pstride[i])
601 atmel_hlcdc_layer_write_cfg(&plane->layer,
602 desc->layout.pstride[i],
603 state->pstride[i]);
604 }
605 }
606
atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state * c_state)607 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
608 {
609 unsigned int ahb_load[2] = { };
610 struct drm_plane *plane;
611
612 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
613 struct atmel_hlcdc_plane_state *plane_state;
614 struct drm_plane_state *plane_s;
615 unsigned int pixels, load = 0;
616 int i;
617
618 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
619 if (IS_ERR(plane_s))
620 return PTR_ERR(plane_s);
621
622 plane_state =
623 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
624
625 pixels = (plane_state->src_w * plane_state->src_h) -
626 (plane_state->disc_w * plane_state->disc_h);
627
628 for (i = 0; i < plane_state->nplanes; i++)
629 load += pixels * plane_state->bpp[i];
630
631 if (ahb_load[0] <= ahb_load[1])
632 plane_state->ahb_id = 0;
633 else
634 plane_state->ahb_id = 1;
635
636 ahb_load[plane_state->ahb_id] += load;
637 }
638
639 return 0;
640 }
641
642 int
atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state * c_state)643 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
644 {
645 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
646 const struct atmel_hlcdc_layer_cfg_layout *layout;
647 struct atmel_hlcdc_plane_state *primary_state;
648 struct drm_plane_state *primary_s;
649 struct atmel_hlcdc_plane *primary;
650 struct drm_plane *ovl;
651
652 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
653 layout = &primary->layer.desc->layout;
654 if (!layout->disc_pos || !layout->disc_size)
655 return 0;
656
657 primary_s = drm_atomic_get_plane_state(c_state->state,
658 &primary->base);
659 if (IS_ERR(primary_s))
660 return PTR_ERR(primary_s);
661
662 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
663
664 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
665 struct atmel_hlcdc_plane_state *ovl_state;
666 struct drm_plane_state *ovl_s;
667
668 if (ovl == c_state->crtc->primary)
669 continue;
670
671 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
672 if (IS_ERR(ovl_s))
673 return PTR_ERR(ovl_s);
674
675 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
676
677 if (!ovl_s->visible ||
678 !ovl_s->fb ||
679 ovl_s->fb->format->has_alpha ||
680 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
681 continue;
682
683 /* TODO: implement a smarter hidden area detection */
684 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
685 continue;
686
687 disc_x = ovl_state->crtc_x;
688 disc_y = ovl_state->crtc_y;
689 disc_h = ovl_state->crtc_h;
690 disc_w = ovl_state->crtc_w;
691 }
692
693 primary_state->disc_x = disc_x;
694 primary_state->disc_y = disc_y;
695 primary_state->disc_w = disc_w;
696 primary_state->disc_h = disc_h;
697
698 return 0;
699 }
700
701 static void
atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_plane_state * state)702 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
703 struct atmel_hlcdc_plane_state *state)
704 {
705 const struct atmel_hlcdc_layer_cfg_layout *layout;
706
707 layout = &plane->layer.desc->layout;
708 if (!layout->disc_pos || !layout->disc_size)
709 return;
710
711 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
712 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
713 state->disc_y));
714
715 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
716 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
717 state->disc_h));
718 }
719
atmel_hlcdc_plane_atomic_check(struct drm_plane * p,struct drm_atomic_state * state)720 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
721 struct drm_atomic_state *state)
722 {
723 struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
724 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
725 struct atmel_hlcdc_plane_state *hstate =
726 drm_plane_state_to_atmel_hlcdc_plane_state(s);
727 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
728 struct drm_framebuffer *fb = hstate->base.fb;
729 const struct drm_display_mode *mode;
730 struct drm_crtc_state *crtc_state;
731 int ret;
732 int i;
733
734 if (!hstate->base.crtc || WARN_ON(!fb))
735 return 0;
736
737 crtc_state = drm_atomic_get_new_crtc_state(state, s->crtc);
738 mode = &crtc_state->adjusted_mode;
739
740 ret = drm_atomic_helper_check_plane_state(s, crtc_state,
741 (1 << 16) / 2048,
742 INT_MAX, true, true);
743 if (ret || !s->visible)
744 return ret;
745
746 hstate->src_x = s->src.x1 >> 16;
747 hstate->src_y = s->src.y1 >> 16;
748 hstate->src_w = drm_rect_width(&s->src) >> 16;
749 hstate->src_h = drm_rect_height(&s->src) >> 16;
750 hstate->crtc_x = s->dst.x1;
751 hstate->crtc_y = s->dst.y1;
752 hstate->crtc_w = drm_rect_width(&s->dst);
753 hstate->crtc_h = drm_rect_height(&s->dst);
754
755 hstate->nplanes = fb->format->num_planes;
756 if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
757 return -EINVAL;
758
759 for (i = 0; i < hstate->nplanes; i++) {
760 unsigned int offset = 0;
761 int xdiv = i ? fb->format->hsub : 1;
762 int ydiv = i ? fb->format->vsub : 1;
763
764 hstate->bpp[i] = fb->format->cpp[i];
765 if (!hstate->bpp[i])
766 return -EINVAL;
767
768 switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
769 case DRM_MODE_ROTATE_90:
770 offset = (hstate->src_y / ydiv) *
771 fb->pitches[i];
772 offset += ((hstate->src_x + hstate->src_w - 1) /
773 xdiv) * hstate->bpp[i];
774 hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
775 fb->pitches[i]) -
776 (2 * hstate->bpp[i]);
777 hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
778 break;
779 case DRM_MODE_ROTATE_180:
780 offset = ((hstate->src_y + hstate->src_h - 1) /
781 ydiv) * fb->pitches[i];
782 offset += ((hstate->src_x + hstate->src_w - 1) /
783 xdiv) * hstate->bpp[i];
784 hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
785 hstate->bpp[i]) - fb->pitches[i];
786 hstate->pstride[i] = -2 * hstate->bpp[i];
787 break;
788 case DRM_MODE_ROTATE_270:
789 offset = ((hstate->src_y + hstate->src_h - 1) /
790 ydiv) * fb->pitches[i];
791 offset += (hstate->src_x / xdiv) * hstate->bpp[i];
792 hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
793 fb->pitches[i];
794 hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
795 break;
796 case DRM_MODE_ROTATE_0:
797 default:
798 offset = (hstate->src_y / ydiv) * fb->pitches[i];
799 offset += (hstate->src_x / xdiv) * hstate->bpp[i];
800 hstate->xstride[i] = fb->pitches[i] -
801 ((hstate->src_w / xdiv) *
802 hstate->bpp[i]);
803 hstate->pstride[i] = 0;
804 break;
805 }
806
807 hstate->offsets[i] = offset + fb->offsets[i];
808 }
809
810 /*
811 * Swap width and size in case of 90 or 270 degrees rotation
812 */
813 if (drm_rotation_90_or_270(hstate->base.rotation)) {
814 swap(hstate->src_w, hstate->src_h);
815 }
816
817 if (!desc->layout.size &&
818 (mode->hdisplay != hstate->crtc_w ||
819 mode->vdisplay != hstate->crtc_h))
820 return -EINVAL;
821
822 if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
823 (!desc->layout.memsize ||
824 hstate->base.fb->format->has_alpha))
825 return -EINVAL;
826
827 return 0;
828 }
829
atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_dc * dc)830 static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
831 struct atmel_hlcdc_dc *dc)
832 {
833 /* Disable interrupts */
834 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
835 0xffffffff);
836
837 /* Disable the layer */
838 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
839 ATMEL_HLCDC_LAYER_RST |
840 ATMEL_HLCDC_LAYER_A2Q |
841 ATMEL_HLCDC_LAYER_UPDATE);
842
843 /* Clear all pending interrupts */
844 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
845 }
846
atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_dc * dc)847 static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
848 struct atmel_hlcdc_dc *dc)
849 {
850 /* Disable interrupts */
851 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IDR,
852 0xffffffff);
853
854 /* Disable the layer */
855 atmel_hlcdc_layer_write_reg(&plane->layer,
856 ATMEL_XLCDC_LAYER_ENR, 0);
857
858 /*
859 * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
860 * (where xxx indicates each layer) requires writing one to the
861 * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
862 */
863 regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
864 ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
865 ATMEL_XLCDC_HEO_UPDATE);
866
867 /* Clear all pending interrupts */
868 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
869 }
870
atmel_hlcdc_plane_atomic_disable(struct drm_plane * p,struct drm_atomic_state * state)871 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
872 struct drm_atomic_state *state)
873 {
874 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
875 struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
876
877 dc->desc->ops->lcdc_atomic_disable(plane, dc);
878 }
879
atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_dc * dc)880 static void atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
881 struct atmel_hlcdc_dc *dc)
882 {
883 u32 sr;
884
885 /* Enable the overrun interrupts. */
886 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
887 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
888 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
889 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
890
891 /* Apply the new config at the next SOF event. */
892 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
893 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
894 ATMEL_HLCDC_LAYER_UPDATE |
895 (sr & ATMEL_HLCDC_LAYER_EN ?
896 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
897 }
898
atmel_xlcdc_atomic_update(struct atmel_hlcdc_plane * plane,struct atmel_hlcdc_dc * dc)899 static void atmel_xlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
900 struct atmel_hlcdc_dc *dc)
901 {
902 /* Enable the overrun interrupts. */
903 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IER,
904 ATMEL_XLCDC_LAYER_OVR_IRQ(0) |
905 ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
906 ATMEL_XLCDC_LAYER_OVR_IRQ(2));
907
908 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_ENR,
909 ATMEL_XLCDC_LAYER_EN);
910
911 /*
912 * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
913 * (where xxx indicates each layer) requires writing one to the
914 * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
915 */
916 regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
917 ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
918 ATMEL_XLCDC_HEO_UPDATE);
919 }
920
atmel_hlcdc_plane_atomic_update(struct drm_plane * p,struct drm_atomic_state * state)921 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
922 struct drm_atomic_state *state)
923 {
924 struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
925 p);
926 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
927 struct atmel_hlcdc_plane_state *hstate =
928 drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
929 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
930
931 if (!new_s->crtc || !new_s->fb)
932 return;
933
934 if (!hstate->base.visible) {
935 atmel_hlcdc_plane_atomic_disable(p, state);
936 return;
937 }
938
939 atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
940 dc->desc->ops->lcdc_update_general_settings(plane, hstate);
941 atmel_hlcdc_plane_update_format(plane, hstate);
942 atmel_hlcdc_plane_update_clut(plane, hstate);
943 atmel_hlcdc_plane_update_buffers(plane, hstate);
944 atmel_hlcdc_plane_update_disc_area(plane, hstate);
945
946 dc->desc->ops->lcdc_atomic_update(plane, dc);
947 }
948
atmel_hlcdc_csc_init(struct atmel_hlcdc_plane * plane,const struct atmel_hlcdc_layer_desc * desc)949 static void atmel_hlcdc_csc_init(struct atmel_hlcdc_plane *plane,
950 const struct atmel_hlcdc_layer_desc *desc)
951 {
952 /*
953 * TODO: declare a "yuv-to-rgb-conv-factors" property to let
954 * userspace modify these factors (using a BLOB property ?).
955 */
956 static const u32 hlcdc_csc_coeffs[] = {
957 0x4c900091,
958 0x7a5f5090,
959 0x40040890
960 };
961
962 for (int i = 0; i < ARRAY_SIZE(hlcdc_csc_coeffs); i++) {
963 atmel_hlcdc_layer_write_cfg(&plane->layer,
964 desc->layout.csc + i,
965 hlcdc_csc_coeffs[i]);
966 }
967 }
968
atmel_xlcdc_csc_init(struct atmel_hlcdc_plane * plane,const struct atmel_hlcdc_layer_desc * desc)969 static void atmel_xlcdc_csc_init(struct atmel_hlcdc_plane *plane,
970 const struct atmel_hlcdc_layer_desc *desc)
971 {
972 /*
973 * yuv-to-rgb-conv-factors are now defined from LCDC_HEOCFG16 to
974 * LCDC_HEOCFG21 registers in SAM9X7.
975 */
976 static const u32 xlcdc_csc_coeffs[] = {
977 0x00000488,
978 0x00000648,
979 0x1EA00480,
980 0x00001D28,
981 0x08100480,
982 0x00000000,
983 0x00000007
984 };
985
986 for (int i = 0; i < ARRAY_SIZE(xlcdc_csc_coeffs); i++) {
987 atmel_hlcdc_layer_write_cfg(&plane->layer,
988 desc->layout.csc + i,
989 xlcdc_csc_coeffs[i]);
990 }
991
992 if (desc->layout.vxs_config && desc->layout.hxs_config) {
993 /*
994 * Updating vxs.config and hxs.config fixes the
995 * Green Color Issue in SAM9X7 EGT Video Player App
996 */
997 atmel_hlcdc_layer_write_cfg(&plane->layer,
998 desc->layout.vxs_config,
999 ATMEL_XLCDC_LAYER_VXSYCFG_ONE |
1000 ATMEL_XLCDC_LAYER_VXSYTAP2_ENABLE |
1001 ATMEL_XLCDC_LAYER_VXSCCFG_ONE |
1002 ATMEL_XLCDC_LAYER_VXSCTAP2_ENABLE);
1003
1004 atmel_hlcdc_layer_write_cfg(&plane->layer,
1005 desc->layout.hxs_config,
1006 ATMEL_XLCDC_LAYER_HXSYCFG_ONE |
1007 ATMEL_XLCDC_LAYER_HXSYTAP2_ENABLE |
1008 ATMEL_XLCDC_LAYER_HXSCCFG_ONE |
1009 ATMEL_XLCDC_LAYER_HXSCTAP2_ENABLE);
1010 }
1011 }
1012
atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane * plane)1013 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
1014 {
1015 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
1016 struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
1017
1018 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
1019 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
1020 int ret;
1021
1022 ret = drm_plane_create_alpha_property(&plane->base);
1023 if (ret)
1024 return ret;
1025 }
1026
1027 if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
1028 int ret;
1029
1030 ret = drm_plane_create_rotation_property(&plane->base,
1031 DRM_MODE_ROTATE_0,
1032 DRM_MODE_ROTATE_0 |
1033 DRM_MODE_ROTATE_90 |
1034 DRM_MODE_ROTATE_180 |
1035 DRM_MODE_ROTATE_270);
1036 if (ret)
1037 return ret;
1038 }
1039
1040 if (desc->layout.csc)
1041 dc->desc->ops->lcdc_csc_init(plane, desc);
1042
1043 return 0;
1044 }
1045
atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane * plane,const struct atmel_hlcdc_layer_desc * desc)1046 static void atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1047 const struct atmel_hlcdc_layer_desc *desc)
1048 {
1049 u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
1050
1051 /*
1052 * There's not much we can do in case of overrun except informing
1053 * the user. However, we are in interrupt context here, hence the
1054 * use of dev_dbg().
1055 */
1056 if (isr &
1057 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
1058 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
1059 drm_dbg(plane->base.dev, "overrun on plane %s\n",
1060 desc->name);
1061 }
1062
atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane * plane,const struct atmel_hlcdc_layer_desc * desc)1063 static void atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1064 const struct atmel_hlcdc_layer_desc *desc)
1065 {
1066 u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
1067
1068 /*
1069 * There's not much we can do in case of overrun except informing
1070 * the user. However, we are in interrupt context here, hence the
1071 * use of dev_dbg().
1072 */
1073 if (isr &
1074 (ATMEL_XLCDC_LAYER_OVR_IRQ(0) | ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
1075 ATMEL_XLCDC_LAYER_OVR_IRQ(2)))
1076 drm_dbg(plane->base.dev, "overrun on plane %s\n",
1077 desc->name);
1078 }
1079
atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane * plane)1080 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
1081 {
1082 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
1083 struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
1084
1085 dc->desc->ops->lcdc_irq_dbg(plane, desc);
1086 }
1087
1088 const struct atmel_lcdc_dc_ops atmel_hlcdc_ops = {
1089 .plane_setup_scaler = atmel_hlcdc_plane_setup_scaler,
1090 .lcdc_update_buffers = atmel_hlcdc_update_buffers,
1091 .lcdc_atomic_disable = atmel_hlcdc_atomic_disable,
1092 .lcdc_update_general_settings = atmel_hlcdc_plane_update_general_settings,
1093 .lcdc_atomic_update = atmel_hlcdc_atomic_update,
1094 .lcdc_csc_init = atmel_hlcdc_csc_init,
1095 .lcdc_irq_dbg = atmel_hlcdc_irq_dbg,
1096 };
1097
1098 const struct atmel_lcdc_dc_ops atmel_xlcdc_ops = {
1099 .plane_setup_scaler = atmel_xlcdc_plane_setup_scaler,
1100 .lcdc_update_buffers = atmel_xlcdc_update_buffers,
1101 .lcdc_atomic_disable = atmel_xlcdc_atomic_disable,
1102 .lcdc_update_general_settings = atmel_xlcdc_plane_update_general_settings,
1103 .lcdc_atomic_update = atmel_xlcdc_atomic_update,
1104 .lcdc_csc_init = atmel_xlcdc_csc_init,
1105 .lcdc_irq_dbg = atmel_xlcdc_irq_dbg,
1106 };
1107
1108 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
1109 .atomic_check = atmel_hlcdc_plane_atomic_check,
1110 .atomic_update = atmel_hlcdc_plane_atomic_update,
1111 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
1112 };
1113
atmel_hlcdc_plane_alloc_dscrs(struct drm_plane * p,struct atmel_hlcdc_plane_state * state)1114 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
1115 struct atmel_hlcdc_plane_state *state)
1116 {
1117 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1118 int i;
1119
1120 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1121 struct atmel_hlcdc_dma_channel_dscr *dscr;
1122 dma_addr_t dscr_dma;
1123
1124 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
1125 if (!dscr)
1126 goto err;
1127
1128 dscr->addr = 0;
1129 dscr->next = dscr_dma;
1130 dscr->self = dscr_dma;
1131 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
1132
1133 state->dscrs[i] = dscr;
1134 }
1135
1136 return 0;
1137
1138 err:
1139 for (i--; i >= 0; i--) {
1140 dma_pool_free(dc->dscrpool, state->dscrs[i],
1141 state->dscrs[i]->self);
1142 }
1143
1144 return -ENOMEM;
1145 }
1146
1147 static struct drm_plane_state *
atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane * p)1148 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
1149 {
1150 struct atmel_hlcdc_plane_state *state =
1151 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1152 struct atmel_hlcdc_plane_state *copy;
1153
1154 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
1155 if (!copy)
1156 return NULL;
1157
1158 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
1159 kfree(copy);
1160 return NULL;
1161 }
1162
1163 __drm_atomic_helper_plane_duplicate_state(p, ©->base);
1164
1165 return ©->base;
1166 }
1167
atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane * p,struct drm_plane_state * s)1168 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
1169 struct drm_plane_state *s)
1170 {
1171 struct atmel_hlcdc_plane_state *state =
1172 drm_plane_state_to_atmel_hlcdc_plane_state(s);
1173 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1174 int i;
1175
1176 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1177 dma_pool_free(dc->dscrpool, state->dscrs[i],
1178 state->dscrs[i]->self);
1179 }
1180
1181 __drm_atomic_helper_plane_destroy_state(s);
1182
1183 kfree(state);
1184 }
1185
atmel_hlcdc_plane_reset(struct drm_plane * p)1186 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
1187 {
1188 struct atmel_hlcdc_plane_state *state;
1189 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1190 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
1191
1192 if (p->state) {
1193 atmel_hlcdc_plane_atomic_destroy_state(p, p->state);
1194 p->state = NULL;
1195 }
1196
1197 state = kzalloc_obj(*state);
1198 if (state) {
1199 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
1200 kfree(state);
1201 drm_err(p->dev,
1202 "Failed to allocate initial plane state\n");
1203 return;
1204 }
1205 __drm_atomic_helper_plane_reset(p, &state->base);
1206 }
1207
1208 if (plane->layer.desc->layout.csc)
1209 dc->desc->ops->lcdc_csc_init(plane, plane->layer.desc);
1210 }
1211
1212 static const struct drm_plane_funcs layer_plane_funcs = {
1213 .update_plane = drm_atomic_helper_update_plane,
1214 .disable_plane = drm_atomic_helper_disable_plane,
1215 .reset = atmel_hlcdc_plane_reset,
1216 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1217 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1218 };
1219
atmel_hlcdc_plane_create(struct drm_device * dev,const struct atmel_hlcdc_layer_desc * desc)1220 static int atmel_hlcdc_plane_create(struct drm_device *dev,
1221 const struct atmel_hlcdc_layer_desc *desc)
1222 {
1223 struct atmel_hlcdc_dc *dc = dev->dev_private;
1224 struct atmel_hlcdc_plane *plane;
1225 enum drm_plane_type type;
1226 int ret;
1227
1228 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1229 type = DRM_PLANE_TYPE_PRIMARY;
1230 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1231 type = DRM_PLANE_TYPE_CURSOR;
1232 else
1233 type = DRM_PLANE_TYPE_OVERLAY;
1234
1235 plane = drmm_universal_plane_alloc(dev, struct atmel_hlcdc_plane, base, 0,
1236 &layer_plane_funcs, desc->formats->formats,
1237 desc->formats->nformats, NULL, type, NULL);
1238 if (IS_ERR(plane))
1239 return PTR_ERR(plane);
1240
1241 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1242
1243 drm_plane_helper_add(&plane->base,
1244 &atmel_hlcdc_layer_plane_helper_funcs);
1245
1246 /* Set default property values*/
1247 ret = atmel_hlcdc_plane_init_properties(plane);
1248 if (ret)
1249 return ret;
1250
1251 dc->layers[desc->id] = &plane->layer;
1252
1253 return 0;
1254 }
1255
atmel_hlcdc_create_planes(struct drm_device * dev)1256 int atmel_hlcdc_create_planes(struct drm_device *dev)
1257 {
1258 struct atmel_hlcdc_dc *dc = dev->dev_private;
1259 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1260 int nlayers = dc->desc->nlayers;
1261 int i, ret;
1262
1263 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1264 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1265 sizeof(u64), 0);
1266 if (!dc->dscrpool)
1267 return -ENOMEM;
1268
1269 for (i = 0; i < nlayers; i++) {
1270 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1271 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1272 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1273 continue;
1274
1275 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1276 if (ret)
1277 return ret;
1278 }
1279
1280 return 0;
1281 }
1282