0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/dmapool.h>
0010 #include <linux/mfd/atmel-hlcdc.h>
0011
0012 #include <drm/drm_atomic.h>
0013 #include <drm/drm_atomic_helper.h>
0014 #include <drm/drm_blend.h>
0015 #include <drm/drm_fb_cma_helper.h>
0016 #include <drm/drm_fourcc.h>
0017 #include <drm/drm_framebuffer.h>
0018 #include <drm/drm_gem_cma_helper.h>
0019 #include <drm/drm_plane_helper.h>
0020
0021 #include "atmel_hlcdc_dc.h"
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 struct atmel_hlcdc_plane_state {
0048 struct drm_plane_state base;
0049 int crtc_x;
0050 int crtc_y;
0051 unsigned int crtc_w;
0052 unsigned int crtc_h;
0053 uint32_t src_x;
0054 uint32_t src_y;
0055 uint32_t src_w;
0056 uint32_t src_h;
0057
0058 int disc_x;
0059 int disc_y;
0060 int disc_w;
0061 int disc_h;
0062
0063 int ahb_id;
0064
0065
0066 int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
0067 unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
0068 int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
0069 int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
0070 int nplanes;
0071
0072
0073 struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
0074 };
0075
0076 static inline struct atmel_hlcdc_plane_state *
0077 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
0078 {
0079 return container_of(s, struct atmel_hlcdc_plane_state, base);
0080 }
0081
0082 #define SUBPIXEL_MASK 0xffff
0083
0084 static uint32_t rgb_formats[] = {
0085 DRM_FORMAT_C8,
0086 DRM_FORMAT_XRGB4444,
0087 DRM_FORMAT_ARGB4444,
0088 DRM_FORMAT_RGBA4444,
0089 DRM_FORMAT_ARGB1555,
0090 DRM_FORMAT_RGB565,
0091 DRM_FORMAT_RGB888,
0092 DRM_FORMAT_XRGB8888,
0093 DRM_FORMAT_ARGB8888,
0094 DRM_FORMAT_RGBA8888,
0095 };
0096
0097 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
0098 .formats = rgb_formats,
0099 .nformats = ARRAY_SIZE(rgb_formats),
0100 };
0101
0102 static uint32_t rgb_and_yuv_formats[] = {
0103 DRM_FORMAT_C8,
0104 DRM_FORMAT_XRGB4444,
0105 DRM_FORMAT_ARGB4444,
0106 DRM_FORMAT_RGBA4444,
0107 DRM_FORMAT_ARGB1555,
0108 DRM_FORMAT_RGB565,
0109 DRM_FORMAT_RGB888,
0110 DRM_FORMAT_XRGB8888,
0111 DRM_FORMAT_ARGB8888,
0112 DRM_FORMAT_RGBA8888,
0113 DRM_FORMAT_AYUV,
0114 DRM_FORMAT_YUYV,
0115 DRM_FORMAT_UYVY,
0116 DRM_FORMAT_YVYU,
0117 DRM_FORMAT_VYUY,
0118 DRM_FORMAT_NV21,
0119 DRM_FORMAT_NV61,
0120 DRM_FORMAT_YUV422,
0121 DRM_FORMAT_YUV420,
0122 };
0123
0124 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
0125 .formats = rgb_and_yuv_formats,
0126 .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
0127 };
0128
0129 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
0130 {
0131 switch (format) {
0132 case DRM_FORMAT_C8:
0133 *mode = ATMEL_HLCDC_C8_MODE;
0134 break;
0135 case DRM_FORMAT_XRGB4444:
0136 *mode = ATMEL_HLCDC_XRGB4444_MODE;
0137 break;
0138 case DRM_FORMAT_ARGB4444:
0139 *mode = ATMEL_HLCDC_ARGB4444_MODE;
0140 break;
0141 case DRM_FORMAT_RGBA4444:
0142 *mode = ATMEL_HLCDC_RGBA4444_MODE;
0143 break;
0144 case DRM_FORMAT_RGB565:
0145 *mode = ATMEL_HLCDC_RGB565_MODE;
0146 break;
0147 case DRM_FORMAT_RGB888:
0148 *mode = ATMEL_HLCDC_RGB888_MODE;
0149 break;
0150 case DRM_FORMAT_ARGB1555:
0151 *mode = ATMEL_HLCDC_ARGB1555_MODE;
0152 break;
0153 case DRM_FORMAT_XRGB8888:
0154 *mode = ATMEL_HLCDC_XRGB8888_MODE;
0155 break;
0156 case DRM_FORMAT_ARGB8888:
0157 *mode = ATMEL_HLCDC_ARGB8888_MODE;
0158 break;
0159 case DRM_FORMAT_RGBA8888:
0160 *mode = ATMEL_HLCDC_RGBA8888_MODE;
0161 break;
0162 case DRM_FORMAT_AYUV:
0163 *mode = ATMEL_HLCDC_AYUV_MODE;
0164 break;
0165 case DRM_FORMAT_YUYV:
0166 *mode = ATMEL_HLCDC_YUYV_MODE;
0167 break;
0168 case DRM_FORMAT_UYVY:
0169 *mode = ATMEL_HLCDC_UYVY_MODE;
0170 break;
0171 case DRM_FORMAT_YVYU:
0172 *mode = ATMEL_HLCDC_YVYU_MODE;
0173 break;
0174 case DRM_FORMAT_VYUY:
0175 *mode = ATMEL_HLCDC_VYUY_MODE;
0176 break;
0177 case DRM_FORMAT_NV21:
0178 *mode = ATMEL_HLCDC_NV21_MODE;
0179 break;
0180 case DRM_FORMAT_NV61:
0181 *mode = ATMEL_HLCDC_NV61_MODE;
0182 break;
0183 case DRM_FORMAT_YUV420:
0184 *mode = ATMEL_HLCDC_YUV420_MODE;
0185 break;
0186 case DRM_FORMAT_YUV422:
0187 *mode = ATMEL_HLCDC_YUV422_MODE;
0188 break;
0189 default:
0190 return -ENOTSUPP;
0191 }
0192
0193 return 0;
0194 }
0195
0196 static u32 heo_downscaling_xcoef[] = {
0197 0x11343311,
0198 0x000000f7,
0199 0x1635300c,
0200 0x000000f9,
0201 0x1b362c08,
0202 0x000000fb,
0203 0x1f372804,
0204 0x000000fe,
0205 0x24382400,
0206 0x00000000,
0207 0x28371ffe,
0208 0x00000004,
0209 0x2c361bfb,
0210 0x00000008,
0211 0x303516f9,
0212 0x0000000c,
0213 };
0214
0215 static u32 heo_downscaling_ycoef[] = {
0216 0x00123737,
0217 0x00173732,
0218 0x001b382d,
0219 0x001f3928,
0220 0x00243824,
0221 0x0028391f,
0222 0x002d381b,
0223 0x00323717,
0224 };
0225
0226 static u32 heo_upscaling_xcoef[] = {
0227 0xf74949f7,
0228 0x00000000,
0229 0xf55f33fb,
0230 0x000000fe,
0231 0xf5701efe,
0232 0x000000ff,
0233 0xf87c0dff,
0234 0x00000000,
0235 0x00800000,
0236 0x00000000,
0237 0x0d7cf800,
0238 0x000000ff,
0239 0x1e70f5ff,
0240 0x000000fe,
0241 0x335ff5fe,
0242 0x000000fb,
0243 };
0244
0245 static u32 heo_upscaling_ycoef[] = {
0246 0x00004040,
0247 0x00075920,
0248 0x00056f0c,
0249 0x00027b03,
0250 0x00008000,
0251 0x00037b02,
0252 0x000c6f05,
0253 0x00205907,
0254 };
0255
0256 #define ATMEL_HLCDC_XPHIDEF 4
0257 #define ATMEL_HLCDC_YPHIDEF 4
0258
0259 static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
0260 u32 dstsize,
0261 u32 phidef)
0262 {
0263 u32 factor, max_memsize;
0264
0265 factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
0266 max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
0267
0268 if (max_memsize > srcsize - 1)
0269 factor--;
0270
0271 return factor;
0272 }
0273
0274 static void
0275 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
0276 const u32 *coeff_tab, int size,
0277 unsigned int cfg_offs)
0278 {
0279 int i;
0280
0281 for (i = 0; i < size; i++)
0282 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
0283 coeff_tab[i]);
0284 }
0285
0286 static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
0287 struct atmel_hlcdc_plane_state *state)
0288 {
0289 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0290 u32 xfactor, yfactor;
0291
0292 if (!desc->layout.scaler_config)
0293 return;
0294
0295 if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
0296 atmel_hlcdc_layer_write_cfg(&plane->layer,
0297 desc->layout.scaler_config, 0);
0298 return;
0299 }
0300
0301 if (desc->layout.phicoeffs.x) {
0302 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
0303 state->crtc_w,
0304 ATMEL_HLCDC_XPHIDEF);
0305
0306 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
0307 state->crtc_h,
0308 ATMEL_HLCDC_YPHIDEF);
0309
0310 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
0311 state->crtc_w < state->src_w ?
0312 heo_downscaling_xcoef :
0313 heo_upscaling_xcoef,
0314 ARRAY_SIZE(heo_upscaling_xcoef),
0315 desc->layout.phicoeffs.x);
0316
0317 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
0318 state->crtc_h < state->src_h ?
0319 heo_downscaling_ycoef :
0320 heo_upscaling_ycoef,
0321 ARRAY_SIZE(heo_upscaling_ycoef),
0322 desc->layout.phicoeffs.y);
0323 } else {
0324 xfactor = (1024 * state->src_w) / state->crtc_w;
0325 yfactor = (1024 * state->src_h) / state->crtc_h;
0326 }
0327
0328 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
0329 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
0330 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
0331 yfactor));
0332 }
0333
0334 static void
0335 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
0336 struct atmel_hlcdc_plane_state *state)
0337 {
0338 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0339
0340 if (desc->layout.size)
0341 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
0342 ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
0343 state->crtc_h));
0344
0345 if (desc->layout.memsize)
0346 atmel_hlcdc_layer_write_cfg(&plane->layer,
0347 desc->layout.memsize,
0348 ATMEL_HLCDC_LAYER_SIZE(state->src_w,
0349 state->src_h));
0350
0351 if (desc->layout.pos)
0352 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
0353 ATMEL_HLCDC_LAYER_POS(state->crtc_x,
0354 state->crtc_y));
0355
0356 atmel_hlcdc_plane_setup_scaler(plane, state);
0357 }
0358
0359 static void
0360 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
0361 struct atmel_hlcdc_plane_state *state)
0362 {
0363 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
0364 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0365 const struct drm_format_info *format = state->base.fb->format;
0366
0367
0368
0369
0370
0371 if (format->format == DRM_FORMAT_RGB888)
0372 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
0373
0374 atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
0375 cfg);
0376
0377 cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
0378
0379 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
0380 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
0381 ATMEL_HLCDC_LAYER_ITER;
0382
0383 if (format->has_alpha)
0384 cfg |= ATMEL_HLCDC_LAYER_LAEN;
0385 else
0386 cfg |= ATMEL_HLCDC_LAYER_GAEN |
0387 ATMEL_HLCDC_LAYER_GA(state->base.alpha);
0388 }
0389
0390 if (state->disc_h && state->disc_w)
0391 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
0392
0393 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
0394 cfg);
0395 }
0396
0397 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
0398 struct atmel_hlcdc_plane_state *state)
0399 {
0400 u32 cfg;
0401 int ret;
0402
0403 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
0404 &cfg);
0405 if (ret)
0406 return;
0407
0408 if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
0409 state->base.fb->format->format == DRM_FORMAT_NV61) &&
0410 drm_rotation_90_or_270(state->base.rotation))
0411 cfg |= ATMEL_HLCDC_YUV422ROT;
0412
0413 atmel_hlcdc_layer_write_cfg(&plane->layer,
0414 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
0415 }
0416
0417 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
0418 struct atmel_hlcdc_plane_state *state)
0419 {
0420 struct drm_crtc *crtc = state->base.crtc;
0421 struct drm_color_lut *lut;
0422 int idx;
0423
0424 if (!crtc || !crtc->state)
0425 return;
0426
0427 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
0428 return;
0429
0430 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
0431
0432 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
0433 u32 val = ((lut->red << 8) & 0xff0000) |
0434 (lut->green & 0xff00) |
0435 (lut->blue >> 8);
0436
0437 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
0438 }
0439 }
0440
0441 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
0442 struct atmel_hlcdc_plane_state *state)
0443 {
0444 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0445 struct drm_framebuffer *fb = state->base.fb;
0446 u32 sr;
0447 int i;
0448
0449 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
0450
0451 for (i = 0; i < state->nplanes; i++) {
0452 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
0453
0454 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
0455
0456 atmel_hlcdc_layer_write_reg(&plane->layer,
0457 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
0458 state->dscrs[i]->self);
0459
0460 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
0461 atmel_hlcdc_layer_write_reg(&plane->layer,
0462 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
0463 state->dscrs[i]->addr);
0464 atmel_hlcdc_layer_write_reg(&plane->layer,
0465 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
0466 state->dscrs[i]->ctrl);
0467 atmel_hlcdc_layer_write_reg(&plane->layer,
0468 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
0469 state->dscrs[i]->self);
0470 }
0471
0472 if (desc->layout.xstride[i])
0473 atmel_hlcdc_layer_write_cfg(&plane->layer,
0474 desc->layout.xstride[i],
0475 state->xstride[i]);
0476
0477 if (desc->layout.pstride[i])
0478 atmel_hlcdc_layer_write_cfg(&plane->layer,
0479 desc->layout.pstride[i],
0480 state->pstride[i]);
0481 }
0482 }
0483
0484 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
0485 {
0486 unsigned int ahb_load[2] = { };
0487 struct drm_plane *plane;
0488
0489 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
0490 struct atmel_hlcdc_plane_state *plane_state;
0491 struct drm_plane_state *plane_s;
0492 unsigned int pixels, load = 0;
0493 int i;
0494
0495 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
0496 if (IS_ERR(plane_s))
0497 return PTR_ERR(plane_s);
0498
0499 plane_state =
0500 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
0501
0502 pixels = (plane_state->src_w * plane_state->src_h) -
0503 (plane_state->disc_w * plane_state->disc_h);
0504
0505 for (i = 0; i < plane_state->nplanes; i++)
0506 load += pixels * plane_state->bpp[i];
0507
0508 if (ahb_load[0] <= ahb_load[1])
0509 plane_state->ahb_id = 0;
0510 else
0511 plane_state->ahb_id = 1;
0512
0513 ahb_load[plane_state->ahb_id] += load;
0514 }
0515
0516 return 0;
0517 }
0518
0519 int
0520 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
0521 {
0522 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
0523 const struct atmel_hlcdc_layer_cfg_layout *layout;
0524 struct atmel_hlcdc_plane_state *primary_state;
0525 struct drm_plane_state *primary_s;
0526 struct atmel_hlcdc_plane *primary;
0527 struct drm_plane *ovl;
0528
0529 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
0530 layout = &primary->layer.desc->layout;
0531 if (!layout->disc_pos || !layout->disc_size)
0532 return 0;
0533
0534 primary_s = drm_atomic_get_plane_state(c_state->state,
0535 &primary->base);
0536 if (IS_ERR(primary_s))
0537 return PTR_ERR(primary_s);
0538
0539 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
0540
0541 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
0542 struct atmel_hlcdc_plane_state *ovl_state;
0543 struct drm_plane_state *ovl_s;
0544
0545 if (ovl == c_state->crtc->primary)
0546 continue;
0547
0548 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
0549 if (IS_ERR(ovl_s))
0550 return PTR_ERR(ovl_s);
0551
0552 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
0553
0554 if (!ovl_s->visible ||
0555 !ovl_s->fb ||
0556 ovl_s->fb->format->has_alpha ||
0557 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
0558 continue;
0559
0560
0561 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
0562 continue;
0563
0564 disc_x = ovl_state->crtc_x;
0565 disc_y = ovl_state->crtc_y;
0566 disc_h = ovl_state->crtc_h;
0567 disc_w = ovl_state->crtc_w;
0568 }
0569
0570 primary_state->disc_x = disc_x;
0571 primary_state->disc_y = disc_y;
0572 primary_state->disc_w = disc_w;
0573 primary_state->disc_h = disc_h;
0574
0575 return 0;
0576 }
0577
0578 static void
0579 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
0580 struct atmel_hlcdc_plane_state *state)
0581 {
0582 const struct atmel_hlcdc_layer_cfg_layout *layout;
0583
0584 layout = &plane->layer.desc->layout;
0585 if (!layout->disc_pos || !layout->disc_size)
0586 return;
0587
0588 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
0589 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
0590 state->disc_y));
0591
0592 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
0593 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
0594 state->disc_h));
0595 }
0596
0597 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
0598 struct drm_atomic_state *state)
0599 {
0600 struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
0601 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
0602 struct atmel_hlcdc_plane_state *hstate =
0603 drm_plane_state_to_atmel_hlcdc_plane_state(s);
0604 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0605 struct drm_framebuffer *fb = hstate->base.fb;
0606 const struct drm_display_mode *mode;
0607 struct drm_crtc_state *crtc_state;
0608 int ret;
0609 int i;
0610
0611 if (!hstate->base.crtc || WARN_ON(!fb))
0612 return 0;
0613
0614 crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
0615 mode = &crtc_state->adjusted_mode;
0616
0617 ret = drm_atomic_helper_check_plane_state(s, crtc_state,
0618 (1 << 16) / 2048,
0619 INT_MAX, true, true);
0620 if (ret || !s->visible)
0621 return ret;
0622
0623 hstate->src_x = s->src.x1;
0624 hstate->src_y = s->src.y1;
0625 hstate->src_w = drm_rect_width(&s->src);
0626 hstate->src_h = drm_rect_height(&s->src);
0627 hstate->crtc_x = s->dst.x1;
0628 hstate->crtc_y = s->dst.y1;
0629 hstate->crtc_w = drm_rect_width(&s->dst);
0630 hstate->crtc_h = drm_rect_height(&s->dst);
0631
0632 if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
0633 SUBPIXEL_MASK)
0634 return -EINVAL;
0635
0636 hstate->src_x >>= 16;
0637 hstate->src_y >>= 16;
0638 hstate->src_w >>= 16;
0639 hstate->src_h >>= 16;
0640
0641 hstate->nplanes = fb->format->num_planes;
0642 if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
0643 return -EINVAL;
0644
0645 for (i = 0; i < hstate->nplanes; i++) {
0646 unsigned int offset = 0;
0647 int xdiv = i ? fb->format->hsub : 1;
0648 int ydiv = i ? fb->format->vsub : 1;
0649
0650 hstate->bpp[i] = fb->format->cpp[i];
0651 if (!hstate->bpp[i])
0652 return -EINVAL;
0653
0654 switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
0655 case DRM_MODE_ROTATE_90:
0656 offset = (hstate->src_y / ydiv) *
0657 fb->pitches[i];
0658 offset += ((hstate->src_x + hstate->src_w - 1) /
0659 xdiv) * hstate->bpp[i];
0660 hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
0661 fb->pitches[i]) -
0662 (2 * hstate->bpp[i]);
0663 hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
0664 break;
0665 case DRM_MODE_ROTATE_180:
0666 offset = ((hstate->src_y + hstate->src_h - 1) /
0667 ydiv) * fb->pitches[i];
0668 offset += ((hstate->src_x + hstate->src_w - 1) /
0669 xdiv) * hstate->bpp[i];
0670 hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
0671 hstate->bpp[i]) - fb->pitches[i];
0672 hstate->pstride[i] = -2 * hstate->bpp[i];
0673 break;
0674 case DRM_MODE_ROTATE_270:
0675 offset = ((hstate->src_y + hstate->src_h - 1) /
0676 ydiv) * fb->pitches[i];
0677 offset += (hstate->src_x / xdiv) * hstate->bpp[i];
0678 hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
0679 fb->pitches[i];
0680 hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
0681 break;
0682 case DRM_MODE_ROTATE_0:
0683 default:
0684 offset = (hstate->src_y / ydiv) * fb->pitches[i];
0685 offset += (hstate->src_x / xdiv) * hstate->bpp[i];
0686 hstate->xstride[i] = fb->pitches[i] -
0687 ((hstate->src_w / xdiv) *
0688 hstate->bpp[i]);
0689 hstate->pstride[i] = 0;
0690 break;
0691 }
0692
0693 hstate->offsets[i] = offset + fb->offsets[i];
0694 }
0695
0696
0697
0698
0699 if (drm_rotation_90_or_270(hstate->base.rotation)) {
0700 swap(hstate->src_w, hstate->src_h);
0701 }
0702
0703 if (!desc->layout.size &&
0704 (mode->hdisplay != hstate->crtc_w ||
0705 mode->vdisplay != hstate->crtc_h))
0706 return -EINVAL;
0707
0708 if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
0709 (!desc->layout.memsize ||
0710 hstate->base.fb->format->has_alpha))
0711 return -EINVAL;
0712
0713 return 0;
0714 }
0715
0716 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
0717 struct drm_atomic_state *state)
0718 {
0719 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
0720
0721
0722 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
0723 0xffffffff);
0724
0725
0726 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
0727 ATMEL_HLCDC_LAYER_RST |
0728 ATMEL_HLCDC_LAYER_A2Q |
0729 ATMEL_HLCDC_LAYER_UPDATE);
0730
0731
0732 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
0733 }
0734
0735 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
0736 struct drm_atomic_state *state)
0737 {
0738 struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
0739 p);
0740 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
0741 struct atmel_hlcdc_plane_state *hstate =
0742 drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
0743 u32 sr;
0744
0745 if (!new_s->crtc || !new_s->fb)
0746 return;
0747
0748 if (!hstate->base.visible) {
0749 atmel_hlcdc_plane_atomic_disable(p, state);
0750 return;
0751 }
0752
0753 atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
0754 atmel_hlcdc_plane_update_general_settings(plane, hstate);
0755 atmel_hlcdc_plane_update_format(plane, hstate);
0756 atmel_hlcdc_plane_update_clut(plane, hstate);
0757 atmel_hlcdc_plane_update_buffers(plane, hstate);
0758 atmel_hlcdc_plane_update_disc_area(plane, hstate);
0759
0760
0761 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
0762 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
0763 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
0764 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
0765
0766
0767 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
0768 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
0769 ATMEL_HLCDC_LAYER_UPDATE |
0770 (sr & ATMEL_HLCDC_LAYER_EN ?
0771 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
0772 }
0773
0774 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
0775 {
0776 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0777
0778 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
0779 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
0780 int ret;
0781
0782 ret = drm_plane_create_alpha_property(&plane->base);
0783 if (ret)
0784 return ret;
0785 }
0786
0787 if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
0788 int ret;
0789
0790 ret = drm_plane_create_rotation_property(&plane->base,
0791 DRM_MODE_ROTATE_0,
0792 DRM_MODE_ROTATE_0 |
0793 DRM_MODE_ROTATE_90 |
0794 DRM_MODE_ROTATE_180 |
0795 DRM_MODE_ROTATE_270);
0796 if (ret)
0797 return ret;
0798 }
0799
0800 if (desc->layout.csc) {
0801
0802
0803
0804
0805 atmel_hlcdc_layer_write_cfg(&plane->layer,
0806 desc->layout.csc,
0807 0x4c900091);
0808 atmel_hlcdc_layer_write_cfg(&plane->layer,
0809 desc->layout.csc + 1,
0810 0x7a5f5090);
0811 atmel_hlcdc_layer_write_cfg(&plane->layer,
0812 desc->layout.csc + 2,
0813 0x40040890);
0814 }
0815
0816 return 0;
0817 }
0818
0819 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
0820 {
0821 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
0822 u32 isr;
0823
0824 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
0825
0826
0827
0828
0829
0830
0831 if (isr &
0832 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
0833 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
0834 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
0835 desc->name);
0836 }
0837
0838 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
0839 .atomic_check = atmel_hlcdc_plane_atomic_check,
0840 .atomic_update = atmel_hlcdc_plane_atomic_update,
0841 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
0842 };
0843
0844 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
0845 struct atmel_hlcdc_plane_state *state)
0846 {
0847 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
0848 int i;
0849
0850 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
0851 struct atmel_hlcdc_dma_channel_dscr *dscr;
0852 dma_addr_t dscr_dma;
0853
0854 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
0855 if (!dscr)
0856 goto err;
0857
0858 dscr->addr = 0;
0859 dscr->next = dscr_dma;
0860 dscr->self = dscr_dma;
0861 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
0862
0863 state->dscrs[i] = dscr;
0864 }
0865
0866 return 0;
0867
0868 err:
0869 for (i--; i >= 0; i--) {
0870 dma_pool_free(dc->dscrpool, state->dscrs[i],
0871 state->dscrs[i]->self);
0872 }
0873
0874 return -ENOMEM;
0875 }
0876
0877 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
0878 {
0879 struct atmel_hlcdc_plane_state *state;
0880
0881 if (p->state) {
0882 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
0883
0884 if (state->base.fb)
0885 drm_framebuffer_put(state->base.fb);
0886
0887 kfree(state);
0888 p->state = NULL;
0889 }
0890
0891 state = kzalloc(sizeof(*state), GFP_KERNEL);
0892 if (state) {
0893 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
0894 kfree(state);
0895 dev_err(p->dev->dev,
0896 "Failed to allocate initial plane state\n");
0897 return;
0898 }
0899 __drm_atomic_helper_plane_reset(p, &state->base);
0900 }
0901 }
0902
0903 static struct drm_plane_state *
0904 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
0905 {
0906 struct atmel_hlcdc_plane_state *state =
0907 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
0908 struct atmel_hlcdc_plane_state *copy;
0909
0910 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
0911 if (!copy)
0912 return NULL;
0913
0914 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
0915 kfree(copy);
0916 return NULL;
0917 }
0918
0919 if (copy->base.fb)
0920 drm_framebuffer_get(copy->base.fb);
0921
0922 return ©->base;
0923 }
0924
0925 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
0926 struct drm_plane_state *s)
0927 {
0928 struct atmel_hlcdc_plane_state *state =
0929 drm_plane_state_to_atmel_hlcdc_plane_state(s);
0930 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
0931 int i;
0932
0933 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
0934 dma_pool_free(dc->dscrpool, state->dscrs[i],
0935 state->dscrs[i]->self);
0936 }
0937
0938 if (s->fb)
0939 drm_framebuffer_put(s->fb);
0940
0941 kfree(state);
0942 }
0943
0944 static const struct drm_plane_funcs layer_plane_funcs = {
0945 .update_plane = drm_atomic_helper_update_plane,
0946 .disable_plane = drm_atomic_helper_disable_plane,
0947 .destroy = drm_plane_cleanup,
0948 .reset = atmel_hlcdc_plane_reset,
0949 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
0950 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
0951 };
0952
0953 static int atmel_hlcdc_plane_create(struct drm_device *dev,
0954 const struct atmel_hlcdc_layer_desc *desc)
0955 {
0956 struct atmel_hlcdc_dc *dc = dev->dev_private;
0957 struct atmel_hlcdc_plane *plane;
0958 enum drm_plane_type type;
0959 int ret;
0960
0961 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
0962 if (!plane)
0963 return -ENOMEM;
0964
0965 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
0966
0967 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
0968 type = DRM_PLANE_TYPE_PRIMARY;
0969 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
0970 type = DRM_PLANE_TYPE_CURSOR;
0971 else
0972 type = DRM_PLANE_TYPE_OVERLAY;
0973
0974 ret = drm_universal_plane_init(dev, &plane->base, 0,
0975 &layer_plane_funcs,
0976 desc->formats->formats,
0977 desc->formats->nformats,
0978 NULL, type, NULL);
0979 if (ret)
0980 return ret;
0981
0982 drm_plane_helper_add(&plane->base,
0983 &atmel_hlcdc_layer_plane_helper_funcs);
0984
0985
0986 ret = atmel_hlcdc_plane_init_properties(plane);
0987 if (ret)
0988 return ret;
0989
0990 dc->layers[desc->id] = &plane->layer;
0991
0992 return 0;
0993 }
0994
0995 int atmel_hlcdc_create_planes(struct drm_device *dev)
0996 {
0997 struct atmel_hlcdc_dc *dc = dev->dev_private;
0998 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
0999 int nlayers = dc->desc->nlayers;
1000 int i, ret;
1001
1002 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1003 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1004 sizeof(u64), 0);
1005 if (!dc->dscrpool)
1006 return -ENOMEM;
1007
1008 for (i = 0; i < nlayers; i++) {
1009 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1010 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1011 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1012 continue;
1013
1014 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1015 if (ret)
1016 return ret;
1017 }
1018
1019 return 0;
1020 }