Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2014 Free Electrons
0004  * Copyright (C) 2014 Atmel
0005  *
0006  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
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  * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
0025  *
0026  * @base: DRM plane state
0027  * @crtc_x: x position of the plane relative to the CRTC
0028  * @crtc_y: y position of the plane relative to the CRTC
0029  * @crtc_w: visible width of the plane
0030  * @crtc_h: visible height of the plane
0031  * @src_x: x buffer position
0032  * @src_y: y buffer position
0033  * @src_w: buffer width
0034  * @src_h: buffer height
0035  * @disc_x: x discard position
0036  * @disc_y: y discard position
0037  * @disc_w: discard width
0038  * @disc_h: discard height
0039  * @ahb_id: AHB identification number
0040  * @bpp: bytes per pixel deduced from pixel_format
0041  * @offsets: offsets to apply to the GEM buffers
0042  * @xstride: value to add to the pixel pointer between each line
0043  * @pstride: value to add to the pixel pointer between each pixel
0044  * @nplanes: number of planes (deduced from pixel_format)
0045  * @dscrs: DMA descriptors
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     /* These fields are private and should not be touched */
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     /* DMA descriptors. */
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      * Rotation optimization is not working on RGB888 (rotation is still
0369      * working but without any optimization).
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         /* TODO: implement a smarter hidden area detection */
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      * Swap width and size in case of 90 or 270 degrees rotation
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     /* Disable interrupts */
0722     atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
0723                     0xffffffff);
0724 
0725     /* Disable the layer */
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     /* Clear all pending interrupts */
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     /* Enable the overrun interrupts. */
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     /* Apply the new config at the next SOF event. */
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          * TODO: decare a "yuv-to-rgb-conv-factors" property to let
0803          * userspace modify these factors (using a BLOB property ?).
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      * There's not much we can do in case of overrun except informing
0828      * the user. However, we are in interrupt context here, hence the
0829      * use of dev_dbg().
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 &copy->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     /* Set default property values*/
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 }