root/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_plane_state_to_atmel_hlcdc_plane_state
  2. atmel_hlcdc_format_to_plane_mode
  3. atmel_hlcdc_plane_phiscaler_get_factor
  4. atmel_hlcdc_plane_scaler_set_phicoeff
  5. atmel_hlcdc_plane_setup_scaler
  6. atmel_hlcdc_plane_update_pos_and_size
  7. atmel_hlcdc_plane_update_general_settings
  8. atmel_hlcdc_plane_update_format
  9. atmel_hlcdc_plane_update_clut
  10. atmel_hlcdc_plane_update_buffers
  11. atmel_hlcdc_plane_prepare_ahb_routing
  12. atmel_hlcdc_plane_prepare_disc_area
  13. atmel_hlcdc_plane_update_disc_area
  14. atmel_hlcdc_plane_atomic_check
  15. atmel_hlcdc_plane_atomic_disable
  16. atmel_hlcdc_plane_atomic_update
  17. atmel_hlcdc_plane_init_properties
  18. atmel_hlcdc_plane_irq
  19. atmel_hlcdc_plane_alloc_dscrs
  20. atmel_hlcdc_plane_reset
  21. atmel_hlcdc_plane_atomic_duplicate_state
  22. atmel_hlcdc_plane_atomic_destroy_state
  23. atmel_hlcdc_plane_create
  24. atmel_hlcdc_create_planes

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2014 Free Electrons
   4  * Copyright (C) 2014 Atmel
   5  *
   6  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
   7  */
   8 
   9 #include <linux/dmapool.h>
  10 #include <linux/mfd/atmel-hlcdc.h>
  11 
  12 #include <drm/drm_atomic.h>
  13 #include <drm/drm_atomic_helper.h>
  14 #include <drm/drm_fb_cma_helper.h>
  15 #include <drm/drm_fourcc.h>
  16 #include <drm/drm_gem_cma_helper.h>
  17 #include <drm/drm_plane_helper.h>
  18 
  19 #include "atmel_hlcdc_dc.h"
  20 
  21 /**
  22  * Atmel HLCDC Plane state structure.
  23  *
  24  * @base: DRM plane state
  25  * @crtc_x: x position of the plane relative to the CRTC
  26  * @crtc_y: y position of the plane relative to the CRTC
  27  * @crtc_w: visible width of the plane
  28  * @crtc_h: visible height of the plane
  29  * @src_x: x buffer position
  30  * @src_y: y buffer position
  31  * @src_w: buffer width
  32  * @src_h: buffer height
  33  * @disc_x: x discard position
  34  * @disc_y: y discard position
  35  * @disc_w: discard width
  36  * @disc_h: discard height
  37  * @bpp: bytes per pixel deduced from pixel_format
  38  * @offsets: offsets to apply to the GEM buffers
  39  * @xstride: value to add to the pixel pointer between each line
  40  * @pstride: value to add to the pixel pointer between each pixel
  41  * @nplanes: number of planes (deduced from pixel_format)
  42  * @dscrs: DMA descriptors
  43  */
  44 struct atmel_hlcdc_plane_state {
  45         struct drm_plane_state base;
  46         int crtc_x;
  47         int crtc_y;
  48         unsigned int crtc_w;
  49         unsigned int crtc_h;
  50         uint32_t src_x;
  51         uint32_t src_y;
  52         uint32_t src_w;
  53         uint32_t src_h;
  54 
  55         int disc_x;
  56         int disc_y;
  57         int disc_w;
  58         int disc_h;
  59 
  60         int ahb_id;
  61 
  62         /* These fields are private and should not be touched */
  63         int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
  64         unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
  65         int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
  66         int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
  67         int nplanes;
  68 
  69         /* DMA descriptors. */
  70         struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
  71 };
  72 
  73 static inline struct atmel_hlcdc_plane_state *
  74 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
  75 {
  76         return container_of(s, struct atmel_hlcdc_plane_state, base);
  77 }
  78 
  79 #define SUBPIXEL_MASK                   0xffff
  80 
  81 static uint32_t rgb_formats[] = {
  82         DRM_FORMAT_C8,
  83         DRM_FORMAT_XRGB4444,
  84         DRM_FORMAT_ARGB4444,
  85         DRM_FORMAT_RGBA4444,
  86         DRM_FORMAT_ARGB1555,
  87         DRM_FORMAT_RGB565,
  88         DRM_FORMAT_RGB888,
  89         DRM_FORMAT_XRGB8888,
  90         DRM_FORMAT_ARGB8888,
  91         DRM_FORMAT_RGBA8888,
  92 };
  93 
  94 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
  95         .formats = rgb_formats,
  96         .nformats = ARRAY_SIZE(rgb_formats),
  97 };
  98 
  99 static uint32_t rgb_and_yuv_formats[] = {
 100         DRM_FORMAT_C8,
 101         DRM_FORMAT_XRGB4444,
 102         DRM_FORMAT_ARGB4444,
 103         DRM_FORMAT_RGBA4444,
 104         DRM_FORMAT_ARGB1555,
 105         DRM_FORMAT_RGB565,
 106         DRM_FORMAT_RGB888,
 107         DRM_FORMAT_XRGB8888,
 108         DRM_FORMAT_ARGB8888,
 109         DRM_FORMAT_RGBA8888,
 110         DRM_FORMAT_AYUV,
 111         DRM_FORMAT_YUYV,
 112         DRM_FORMAT_UYVY,
 113         DRM_FORMAT_YVYU,
 114         DRM_FORMAT_VYUY,
 115         DRM_FORMAT_NV21,
 116         DRM_FORMAT_NV61,
 117         DRM_FORMAT_YUV422,
 118         DRM_FORMAT_YUV420,
 119 };
 120 
 121 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
 122         .formats = rgb_and_yuv_formats,
 123         .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
 124 };
 125 
 126 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
 127 {
 128         switch (format) {
 129         case DRM_FORMAT_C8:
 130                 *mode = ATMEL_HLCDC_C8_MODE;
 131                 break;
 132         case DRM_FORMAT_XRGB4444:
 133                 *mode = ATMEL_HLCDC_XRGB4444_MODE;
 134                 break;
 135         case DRM_FORMAT_ARGB4444:
 136                 *mode = ATMEL_HLCDC_ARGB4444_MODE;
 137                 break;
 138         case DRM_FORMAT_RGBA4444:
 139                 *mode = ATMEL_HLCDC_RGBA4444_MODE;
 140                 break;
 141         case DRM_FORMAT_RGB565:
 142                 *mode = ATMEL_HLCDC_RGB565_MODE;
 143                 break;
 144         case DRM_FORMAT_RGB888:
 145                 *mode = ATMEL_HLCDC_RGB888_MODE;
 146                 break;
 147         case DRM_FORMAT_ARGB1555:
 148                 *mode = ATMEL_HLCDC_ARGB1555_MODE;
 149                 break;
 150         case DRM_FORMAT_XRGB8888:
 151                 *mode = ATMEL_HLCDC_XRGB8888_MODE;
 152                 break;
 153         case DRM_FORMAT_ARGB8888:
 154                 *mode = ATMEL_HLCDC_ARGB8888_MODE;
 155                 break;
 156         case DRM_FORMAT_RGBA8888:
 157                 *mode = ATMEL_HLCDC_RGBA8888_MODE;
 158                 break;
 159         case DRM_FORMAT_AYUV:
 160                 *mode = ATMEL_HLCDC_AYUV_MODE;
 161                 break;
 162         case DRM_FORMAT_YUYV:
 163                 *mode = ATMEL_HLCDC_YUYV_MODE;
 164                 break;
 165         case DRM_FORMAT_UYVY:
 166                 *mode = ATMEL_HLCDC_UYVY_MODE;
 167                 break;
 168         case DRM_FORMAT_YVYU:
 169                 *mode = ATMEL_HLCDC_YVYU_MODE;
 170                 break;
 171         case DRM_FORMAT_VYUY:
 172                 *mode = ATMEL_HLCDC_VYUY_MODE;
 173                 break;
 174         case DRM_FORMAT_NV21:
 175                 *mode = ATMEL_HLCDC_NV21_MODE;
 176                 break;
 177         case DRM_FORMAT_NV61:
 178                 *mode = ATMEL_HLCDC_NV61_MODE;
 179                 break;
 180         case DRM_FORMAT_YUV420:
 181                 *mode = ATMEL_HLCDC_YUV420_MODE;
 182                 break;
 183         case DRM_FORMAT_YUV422:
 184                 *mode = ATMEL_HLCDC_YUV422_MODE;
 185                 break;
 186         default:
 187                 return -ENOTSUPP;
 188         }
 189 
 190         return 0;
 191 }
 192 
 193 static u32 heo_downscaling_xcoef[] = {
 194         0x11343311,
 195         0x000000f7,
 196         0x1635300c,
 197         0x000000f9,
 198         0x1b362c08,
 199         0x000000fb,
 200         0x1f372804,
 201         0x000000fe,
 202         0x24382400,
 203         0x00000000,
 204         0x28371ffe,
 205         0x00000004,
 206         0x2c361bfb,
 207         0x00000008,
 208         0x303516f9,
 209         0x0000000c,
 210 };
 211 
 212 static u32 heo_downscaling_ycoef[] = {
 213         0x00123737,
 214         0x00173732,
 215         0x001b382d,
 216         0x001f3928,
 217         0x00243824,
 218         0x0028391f,
 219         0x002d381b,
 220         0x00323717,
 221 };
 222 
 223 static u32 heo_upscaling_xcoef[] = {
 224         0xf74949f7,
 225         0x00000000,
 226         0xf55f33fb,
 227         0x000000fe,
 228         0xf5701efe,
 229         0x000000ff,
 230         0xf87c0dff,
 231         0x00000000,
 232         0x00800000,
 233         0x00000000,
 234         0x0d7cf800,
 235         0x000000ff,
 236         0x1e70f5ff,
 237         0x000000fe,
 238         0x335ff5fe,
 239         0x000000fb,
 240 };
 241 
 242 static u32 heo_upscaling_ycoef[] = {
 243         0x00004040,
 244         0x00075920,
 245         0x00056f0c,
 246         0x00027b03,
 247         0x00008000,
 248         0x00037b02,
 249         0x000c6f05,
 250         0x00205907,
 251 };
 252 
 253 #define ATMEL_HLCDC_XPHIDEF     4
 254 #define ATMEL_HLCDC_YPHIDEF     4
 255 
 256 static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
 257                                                   u32 dstsize,
 258                                                   u32 phidef)
 259 {
 260         u32 factor, max_memsize;
 261 
 262         factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
 263         max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
 264 
 265         if (max_memsize > srcsize - 1)
 266                 factor--;
 267 
 268         return factor;
 269 }
 270 
 271 static void
 272 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
 273                                       const u32 *coeff_tab, int size,
 274                                       unsigned int cfg_offs)
 275 {
 276         int i;
 277 
 278         for (i = 0; i < size; i++)
 279                 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
 280                                             coeff_tab[i]);
 281 }
 282 
 283 void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
 284                                     struct atmel_hlcdc_plane_state *state)
 285 {
 286         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 287         u32 xfactor, yfactor;
 288 
 289         if (!desc->layout.scaler_config)
 290                 return;
 291 
 292         if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
 293                 atmel_hlcdc_layer_write_cfg(&plane->layer,
 294                                             desc->layout.scaler_config, 0);
 295                 return;
 296         }
 297 
 298         if (desc->layout.phicoeffs.x) {
 299                 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
 300                                                         state->crtc_w,
 301                                                         ATMEL_HLCDC_XPHIDEF);
 302 
 303                 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
 304                                                         state->crtc_h,
 305                                                         ATMEL_HLCDC_YPHIDEF);
 306 
 307                 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
 308                                 state->crtc_w < state->src_w ?
 309                                 heo_downscaling_xcoef :
 310                                 heo_upscaling_xcoef,
 311                                 ARRAY_SIZE(heo_upscaling_xcoef),
 312                                 desc->layout.phicoeffs.x);
 313 
 314                 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
 315                                 state->crtc_h < state->src_h ?
 316                                 heo_downscaling_ycoef :
 317                                 heo_upscaling_ycoef,
 318                                 ARRAY_SIZE(heo_upscaling_ycoef),
 319                                 desc->layout.phicoeffs.y);
 320         } else {
 321                 xfactor = (1024 * state->src_w) / state->crtc_w;
 322                 yfactor = (1024 * state->src_h) / state->crtc_h;
 323         }
 324 
 325         atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
 326                                     ATMEL_HLCDC_LAYER_SCALER_ENABLE |
 327                                     ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
 328                                                                      yfactor));
 329 }
 330 
 331 static void
 332 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
 333                                       struct atmel_hlcdc_plane_state *state)
 334 {
 335         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 336 
 337         if (desc->layout.size)
 338                 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
 339                                         ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
 340                                                                state->crtc_h));
 341 
 342         if (desc->layout.memsize)
 343                 atmel_hlcdc_layer_write_cfg(&plane->layer,
 344                                         desc->layout.memsize,
 345                                         ATMEL_HLCDC_LAYER_SIZE(state->src_w,
 346                                                                state->src_h));
 347 
 348         if (desc->layout.pos)
 349                 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
 350                                         ATMEL_HLCDC_LAYER_POS(state->crtc_x,
 351                                                               state->crtc_y));
 352 
 353         atmel_hlcdc_plane_setup_scaler(plane, state);
 354 }
 355 
 356 static void
 357 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
 358                                         struct atmel_hlcdc_plane_state *state)
 359 {
 360         unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
 361         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 362         const struct drm_format_info *format = state->base.fb->format;
 363 
 364         /*
 365          * Rotation optimization is not working on RGB888 (rotation is still
 366          * working but without any optimization).
 367          */
 368         if (format->format == DRM_FORMAT_RGB888)
 369                 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
 370 
 371         atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
 372                                     cfg);
 373 
 374         cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
 375 
 376         if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
 377                 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
 378                        ATMEL_HLCDC_LAYER_ITER;
 379 
 380                 if (format->has_alpha)
 381                         cfg |= ATMEL_HLCDC_LAYER_LAEN;
 382                 else
 383                         cfg |= ATMEL_HLCDC_LAYER_GAEN |
 384                                ATMEL_HLCDC_LAYER_GA(state->base.alpha);
 385         }
 386 
 387         if (state->disc_h && state->disc_w)
 388                 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
 389 
 390         atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
 391                                     cfg);
 392 }
 393 
 394 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
 395                                         struct atmel_hlcdc_plane_state *state)
 396 {
 397         u32 cfg;
 398         int ret;
 399 
 400         ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
 401                                                &cfg);
 402         if (ret)
 403                 return;
 404 
 405         if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
 406              state->base.fb->format->format == DRM_FORMAT_NV61) &&
 407             drm_rotation_90_or_270(state->base.rotation))
 408                 cfg |= ATMEL_HLCDC_YUV422ROT;
 409 
 410         atmel_hlcdc_layer_write_cfg(&plane->layer,
 411                                     ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
 412 }
 413 
 414 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
 415                                           struct atmel_hlcdc_plane_state *state)
 416 {
 417         struct drm_crtc *crtc = state->base.crtc;
 418         struct drm_color_lut *lut;
 419         int idx;
 420 
 421         if (!crtc || !crtc->state)
 422                 return;
 423 
 424         if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
 425                 return;
 426 
 427         lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
 428 
 429         for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
 430                 u32 val = ((lut->red << 8) & 0xff0000) |
 431                         (lut->green & 0xff00) |
 432                         (lut->blue >> 8);
 433 
 434                 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
 435         }
 436 }
 437 
 438 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
 439                                         struct atmel_hlcdc_plane_state *state)
 440 {
 441         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 442         struct drm_framebuffer *fb = state->base.fb;
 443         u32 sr;
 444         int i;
 445 
 446         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
 447 
 448         for (i = 0; i < state->nplanes; i++) {
 449                 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
 450 
 451                 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
 452 
 453                 atmel_hlcdc_layer_write_reg(&plane->layer,
 454                                             ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
 455                                             state->dscrs[i]->self);
 456 
 457                 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
 458                         atmel_hlcdc_layer_write_reg(&plane->layer,
 459                                         ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
 460                                         state->dscrs[i]->addr);
 461                         atmel_hlcdc_layer_write_reg(&plane->layer,
 462                                         ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
 463                                         state->dscrs[i]->ctrl);
 464                         atmel_hlcdc_layer_write_reg(&plane->layer,
 465                                         ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
 466                                         state->dscrs[i]->self);
 467                 }
 468 
 469                 if (desc->layout.xstride[i])
 470                         atmel_hlcdc_layer_write_cfg(&plane->layer,
 471                                                     desc->layout.xstride[i],
 472                                                     state->xstride[i]);
 473 
 474                 if (desc->layout.pstride[i])
 475                         atmel_hlcdc_layer_write_cfg(&plane->layer,
 476                                                     desc->layout.pstride[i],
 477                                                     state->pstride[i]);
 478         }
 479 }
 480 
 481 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
 482 {
 483         unsigned int ahb_load[2] = { };
 484         struct drm_plane *plane;
 485 
 486         drm_atomic_crtc_state_for_each_plane(plane, c_state) {
 487                 struct atmel_hlcdc_plane_state *plane_state;
 488                 struct drm_plane_state *plane_s;
 489                 unsigned int pixels, load = 0;
 490                 int i;
 491 
 492                 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
 493                 if (IS_ERR(plane_s))
 494                         return PTR_ERR(plane_s);
 495 
 496                 plane_state =
 497                         drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
 498 
 499                 pixels = (plane_state->src_w * plane_state->src_h) -
 500                          (plane_state->disc_w * plane_state->disc_h);
 501 
 502                 for (i = 0; i < plane_state->nplanes; i++)
 503                         load += pixels * plane_state->bpp[i];
 504 
 505                 if (ahb_load[0] <= ahb_load[1])
 506                         plane_state->ahb_id = 0;
 507                 else
 508                         plane_state->ahb_id = 1;
 509 
 510                 ahb_load[plane_state->ahb_id] += load;
 511         }
 512 
 513         return 0;
 514 }
 515 
 516 int
 517 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
 518 {
 519         int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
 520         const struct atmel_hlcdc_layer_cfg_layout *layout;
 521         struct atmel_hlcdc_plane_state *primary_state;
 522         struct drm_plane_state *primary_s;
 523         struct atmel_hlcdc_plane *primary;
 524         struct drm_plane *ovl;
 525 
 526         primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
 527         layout = &primary->layer.desc->layout;
 528         if (!layout->disc_pos || !layout->disc_size)
 529                 return 0;
 530 
 531         primary_s = drm_atomic_get_plane_state(c_state->state,
 532                                                &primary->base);
 533         if (IS_ERR(primary_s))
 534                 return PTR_ERR(primary_s);
 535 
 536         primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
 537 
 538         drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
 539                 struct atmel_hlcdc_plane_state *ovl_state;
 540                 struct drm_plane_state *ovl_s;
 541 
 542                 if (ovl == c_state->crtc->primary)
 543                         continue;
 544 
 545                 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
 546                 if (IS_ERR(ovl_s))
 547                         return PTR_ERR(ovl_s);
 548 
 549                 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
 550 
 551                 if (!ovl_s->visible ||
 552                     !ovl_s->fb ||
 553                     ovl_s->fb->format->has_alpha ||
 554                     ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
 555                         continue;
 556 
 557                 /* TODO: implement a smarter hidden area detection */
 558                 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
 559                         continue;
 560 
 561                 disc_x = ovl_state->crtc_x;
 562                 disc_y = ovl_state->crtc_y;
 563                 disc_h = ovl_state->crtc_h;
 564                 disc_w = ovl_state->crtc_w;
 565         }
 566 
 567         primary_state->disc_x = disc_x;
 568         primary_state->disc_y = disc_y;
 569         primary_state->disc_w = disc_w;
 570         primary_state->disc_h = disc_h;
 571 
 572         return 0;
 573 }
 574 
 575 static void
 576 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
 577                                    struct atmel_hlcdc_plane_state *state)
 578 {
 579         const struct atmel_hlcdc_layer_cfg_layout *layout;
 580 
 581         layout = &plane->layer.desc->layout;
 582         if (!layout->disc_pos || !layout->disc_size)
 583                 return;
 584 
 585         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
 586                                 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
 587                                                            state->disc_y));
 588 
 589         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
 590                                 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
 591                                                             state->disc_h));
 592 }
 593 
 594 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
 595                                           struct drm_plane_state *s)
 596 {
 597         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 598         struct atmel_hlcdc_plane_state *state =
 599                                 drm_plane_state_to_atmel_hlcdc_plane_state(s);
 600         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 601         struct drm_framebuffer *fb = state->base.fb;
 602         const struct drm_display_mode *mode;
 603         struct drm_crtc_state *crtc_state;
 604         unsigned int tmp;
 605         int ret;
 606         int i;
 607 
 608         if (!state->base.crtc || !fb)
 609                 return 0;
 610 
 611         crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
 612         mode = &crtc_state->adjusted_mode;
 613 
 614         ret = drm_atomic_helper_check_plane_state(s, crtc_state,
 615                                                   (1 << 16) / 2048,
 616                                                   INT_MAX, true, true);
 617         if (ret || !s->visible)
 618                 return ret;
 619 
 620         state->src_x = s->src.x1;
 621         state->src_y = s->src.y1;
 622         state->src_w = drm_rect_width(&s->src);
 623         state->src_h = drm_rect_height(&s->src);
 624         state->crtc_x = s->dst.x1;
 625         state->crtc_y = s->dst.y1;
 626         state->crtc_w = drm_rect_width(&s->dst);
 627         state->crtc_h = drm_rect_height(&s->dst);
 628 
 629         if ((state->src_x | state->src_y | state->src_w | state->src_h) &
 630             SUBPIXEL_MASK)
 631                 return -EINVAL;
 632 
 633         state->src_x >>= 16;
 634         state->src_y >>= 16;
 635         state->src_w >>= 16;
 636         state->src_h >>= 16;
 637 
 638         state->nplanes = fb->format->num_planes;
 639         if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
 640                 return -EINVAL;
 641 
 642         for (i = 0; i < state->nplanes; i++) {
 643                 unsigned int offset = 0;
 644                 int xdiv = i ? fb->format->hsub : 1;
 645                 int ydiv = i ? fb->format->vsub : 1;
 646 
 647                 state->bpp[i] = fb->format->cpp[i];
 648                 if (!state->bpp[i])
 649                         return -EINVAL;
 650 
 651                 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
 652                 case DRM_MODE_ROTATE_90:
 653                         offset = (state->src_y / ydiv) *
 654                                  fb->pitches[i];
 655                         offset += ((state->src_x + state->src_w - 1) /
 656                                    xdiv) * state->bpp[i];
 657                         state->xstride[i] = -(((state->src_h - 1) / ydiv) *
 658                                             fb->pitches[i]) -
 659                                           (2 * state->bpp[i]);
 660                         state->pstride[i] = fb->pitches[i] - state->bpp[i];
 661                         break;
 662                 case DRM_MODE_ROTATE_180:
 663                         offset = ((state->src_y + state->src_h - 1) /
 664                                   ydiv) * fb->pitches[i];
 665                         offset += ((state->src_x + state->src_w - 1) /
 666                                    xdiv) * state->bpp[i];
 667                         state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
 668                                            state->bpp[i]) - fb->pitches[i];
 669                         state->pstride[i] = -2 * state->bpp[i];
 670                         break;
 671                 case DRM_MODE_ROTATE_270:
 672                         offset = ((state->src_y + state->src_h - 1) /
 673                                   ydiv) * fb->pitches[i];
 674                         offset += (state->src_x / xdiv) * state->bpp[i];
 675                         state->xstride[i] = ((state->src_h - 1) / ydiv) *
 676                                           fb->pitches[i];
 677                         state->pstride[i] = -fb->pitches[i] - state->bpp[i];
 678                         break;
 679                 case DRM_MODE_ROTATE_0:
 680                 default:
 681                         offset = (state->src_y / ydiv) * fb->pitches[i];
 682                         offset += (state->src_x / xdiv) * state->bpp[i];
 683                         state->xstride[i] = fb->pitches[i] -
 684                                           ((state->src_w / xdiv) *
 685                                            state->bpp[i]);
 686                         state->pstride[i] = 0;
 687                         break;
 688                 }
 689 
 690                 state->offsets[i] = offset + fb->offsets[i];
 691         }
 692 
 693         /*
 694          * Swap width and size in case of 90 or 270 degrees rotation
 695          */
 696         if (drm_rotation_90_or_270(state->base.rotation)) {
 697                 tmp = state->src_w;
 698                 state->src_w = state->src_h;
 699                 state->src_h = tmp;
 700         }
 701 
 702         if (!desc->layout.size &&
 703             (mode->hdisplay != state->crtc_w ||
 704              mode->vdisplay != state->crtc_h))
 705                 return -EINVAL;
 706 
 707         if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
 708             (!desc->layout.memsize ||
 709              state->base.fb->format->has_alpha))
 710                 return -EINVAL;
 711 
 712         return 0;
 713 }
 714 
 715 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
 716                                              struct drm_plane_state *old_state)
 717 {
 718         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 719 
 720         /* Disable interrupts */
 721         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
 722                                     0xffffffff);
 723 
 724         /* Disable the layer */
 725         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
 726                                     ATMEL_HLCDC_LAYER_RST |
 727                                     ATMEL_HLCDC_LAYER_A2Q |
 728                                     ATMEL_HLCDC_LAYER_UPDATE);
 729 
 730         /* Clear all pending interrupts */
 731         atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 732 }
 733 
 734 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
 735                                             struct drm_plane_state *old_s)
 736 {
 737         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 738         struct atmel_hlcdc_plane_state *state =
 739                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 740         u32 sr;
 741 
 742         if (!p->state->crtc || !p->state->fb)
 743                 return;
 744 
 745         if (!state->base.visible) {
 746                 atmel_hlcdc_plane_atomic_disable(p, old_s);
 747                 return;
 748         }
 749 
 750         atmel_hlcdc_plane_update_pos_and_size(plane, state);
 751         atmel_hlcdc_plane_update_general_settings(plane, state);
 752         atmel_hlcdc_plane_update_format(plane, state);
 753         atmel_hlcdc_plane_update_clut(plane, state);
 754         atmel_hlcdc_plane_update_buffers(plane, state);
 755         atmel_hlcdc_plane_update_disc_area(plane, state);
 756 
 757         /* Enable the overrun interrupts. */
 758         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
 759                                     ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
 760                                     ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
 761                                     ATMEL_HLCDC_LAYER_OVR_IRQ(2));
 762 
 763         /* Apply the new config at the next SOF event. */
 764         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
 765         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
 766                         ATMEL_HLCDC_LAYER_UPDATE |
 767                         (sr & ATMEL_HLCDC_LAYER_EN ?
 768                          ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
 769 }
 770 
 771 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
 772 {
 773         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 774 
 775         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
 776             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
 777                 int ret;
 778 
 779                 ret = drm_plane_create_alpha_property(&plane->base);
 780                 if (ret)
 781                         return ret;
 782         }
 783 
 784         if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
 785                 int ret;
 786 
 787                 ret = drm_plane_create_rotation_property(&plane->base,
 788                                                          DRM_MODE_ROTATE_0,
 789                                                          DRM_MODE_ROTATE_0 |
 790                                                          DRM_MODE_ROTATE_90 |
 791                                                          DRM_MODE_ROTATE_180 |
 792                                                          DRM_MODE_ROTATE_270);
 793                 if (ret)
 794                         return ret;
 795         }
 796 
 797         if (desc->layout.csc) {
 798                 /*
 799                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
 800                  * userspace modify these factors (using a BLOB property ?).
 801                  */
 802                 atmel_hlcdc_layer_write_cfg(&plane->layer,
 803                                             desc->layout.csc,
 804                                             0x4c900091);
 805                 atmel_hlcdc_layer_write_cfg(&plane->layer,
 806                                             desc->layout.csc + 1,
 807                                             0x7a5f5090);
 808                 atmel_hlcdc_layer_write_cfg(&plane->layer,
 809                                             desc->layout.csc + 2,
 810                                             0x40040890);
 811         }
 812 
 813         return 0;
 814 }
 815 
 816 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
 817 {
 818         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 819         u32 isr;
 820 
 821         isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 822 
 823         /*
 824          * There's not much we can do in case of overrun except informing
 825          * the user. However, we are in interrupt context here, hence the
 826          * use of dev_dbg().
 827          */
 828         if (isr &
 829             (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
 830              ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
 831                 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
 832                         desc->name);
 833 }
 834 
 835 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
 836         .atomic_check = atmel_hlcdc_plane_atomic_check,
 837         .atomic_update = atmel_hlcdc_plane_atomic_update,
 838         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
 839 };
 840 
 841 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
 842                                          struct atmel_hlcdc_plane_state *state)
 843 {
 844         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
 845         int i;
 846 
 847         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
 848                 struct atmel_hlcdc_dma_channel_dscr *dscr;
 849                 dma_addr_t dscr_dma;
 850 
 851                 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
 852                 if (!dscr)
 853                         goto err;
 854 
 855                 dscr->addr = 0;
 856                 dscr->next = dscr_dma;
 857                 dscr->self = dscr_dma;
 858                 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
 859 
 860                 state->dscrs[i] = dscr;
 861         }
 862 
 863         return 0;
 864 
 865 err:
 866         for (i--; i >= 0; i--) {
 867                 dma_pool_free(dc->dscrpool, state->dscrs[i],
 868                               state->dscrs[i]->self);
 869         }
 870 
 871         return -ENOMEM;
 872 }
 873 
 874 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
 875 {
 876         struct atmel_hlcdc_plane_state *state;
 877 
 878         if (p->state) {
 879                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 880 
 881                 if (state->base.fb)
 882                         drm_framebuffer_put(state->base.fb);
 883 
 884                 kfree(state);
 885                 p->state = NULL;
 886         }
 887 
 888         state = kzalloc(sizeof(*state), GFP_KERNEL);
 889         if (state) {
 890                 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
 891                         kfree(state);
 892                         dev_err(p->dev->dev,
 893                                 "Failed to allocate initial plane state\n");
 894                         return;
 895                 }
 896                 __drm_atomic_helper_plane_reset(p, &state->base);
 897         }
 898 }
 899 
 900 static struct drm_plane_state *
 901 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
 902 {
 903         struct atmel_hlcdc_plane_state *state =
 904                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 905         struct atmel_hlcdc_plane_state *copy;
 906 
 907         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 908         if (!copy)
 909                 return NULL;
 910 
 911         if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
 912                 kfree(copy);
 913                 return NULL;
 914         }
 915 
 916         if (copy->base.fb)
 917                 drm_framebuffer_get(copy->base.fb);
 918 
 919         return &copy->base;
 920 }
 921 
 922 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
 923                                                    struct drm_plane_state *s)
 924 {
 925         struct atmel_hlcdc_plane_state *state =
 926                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
 927         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
 928         int i;
 929 
 930         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
 931                 dma_pool_free(dc->dscrpool, state->dscrs[i],
 932                               state->dscrs[i]->self);
 933         }
 934 
 935         if (s->fb)
 936                 drm_framebuffer_put(s->fb);
 937 
 938         kfree(state);
 939 }
 940 
 941 static const struct drm_plane_funcs layer_plane_funcs = {
 942         .update_plane = drm_atomic_helper_update_plane,
 943         .disable_plane = drm_atomic_helper_disable_plane,
 944         .destroy = drm_plane_cleanup,
 945         .reset = atmel_hlcdc_plane_reset,
 946         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
 947         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
 948 };
 949 
 950 static int atmel_hlcdc_plane_create(struct drm_device *dev,
 951                                     const struct atmel_hlcdc_layer_desc *desc)
 952 {
 953         struct atmel_hlcdc_dc *dc = dev->dev_private;
 954         struct atmel_hlcdc_plane *plane;
 955         enum drm_plane_type type;
 956         int ret;
 957 
 958         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
 959         if (!plane)
 960                 return -ENOMEM;
 961 
 962         atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
 963 
 964         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
 965                 type = DRM_PLANE_TYPE_PRIMARY;
 966         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
 967                 type = DRM_PLANE_TYPE_CURSOR;
 968         else
 969                 type = DRM_PLANE_TYPE_OVERLAY;
 970 
 971         ret = drm_universal_plane_init(dev, &plane->base, 0,
 972                                        &layer_plane_funcs,
 973                                        desc->formats->formats,
 974                                        desc->formats->nformats,
 975                                        NULL, type, NULL);
 976         if (ret)
 977                 return ret;
 978 
 979         drm_plane_helper_add(&plane->base,
 980                              &atmel_hlcdc_layer_plane_helper_funcs);
 981 
 982         /* Set default property values*/
 983         ret = atmel_hlcdc_plane_init_properties(plane);
 984         if (ret)
 985                 return ret;
 986 
 987         dc->layers[desc->id] = &plane->layer;
 988 
 989         return 0;
 990 }
 991 
 992 int atmel_hlcdc_create_planes(struct drm_device *dev)
 993 {
 994         struct atmel_hlcdc_dc *dc = dev->dev_private;
 995         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
 996         int nlayers = dc->desc->nlayers;
 997         int i, ret;
 998 
 999         dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1000                                 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1001                                 sizeof(u64), 0);
1002         if (!dc->dscrpool)
1003                 return -ENOMEM;
1004 
1005         for (i = 0; i < nlayers; i++) {
1006                 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1007                     descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1008                     descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1009                         continue;
1010 
1011                 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1012                 if (ret)
1013                         return ret;
1014         }
1015 
1016         return 0;
1017 }

/* [<][>][^][v][top][bottom][index][help] */