Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
52370 views
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 <[email protected]>
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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, &copy->base);
1164
1165
return &copy->base;
1166
}
1167
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
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(sizeof(*state), GFP_KERNEL);
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
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
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
1283