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