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