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 * 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 */
  44struct 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
  73static inline struct atmel_hlcdc_plane_state *
  74drm_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
  81static 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
  94struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
  95        .formats = rgb_formats,
  96        .nformats = ARRAY_SIZE(rgb_formats),
  97};
  98
  99static 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
 121struct 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
 126static 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
 193static 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
 212static u32 heo_downscaling_ycoef[] = {
 213        0x00123737,
 214        0x00173732,
 215        0x001b382d,
 216        0x001f3928,
 217        0x00243824,
 218        0x0028391f,
 219        0x002d381b,
 220        0x00323717,
 221};
 222
 223static 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
 242static 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
 256static 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
 271static void
 272atmel_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
 283void 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
 331static void
 332atmel_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
 356static void
 357atmel_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
 394static 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
 414static 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
 438static 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
 481int 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
 516int
 517atmel_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
 575static void
 576atmel_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
 594static 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        int ret;
 605        int i;
 606
 607        if (!state->base.crtc || WARN_ON(!fb))
 608                return 0;
 609
 610        crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
 611        mode = &crtc_state->adjusted_mode;
 612
 613        ret = drm_atomic_helper_check_plane_state(s, crtc_state,
 614                                                  (1 << 16) / 2048,
 615                                                  INT_MAX, true, true);
 616        if (ret || !s->visible)
 617                return ret;
 618
 619        state->src_x = s->src.x1;
 620        state->src_y = s->src.y1;
 621        state->src_w = drm_rect_width(&s->src);
 622        state->src_h = drm_rect_height(&s->src);
 623        state->crtc_x = s->dst.x1;
 624        state->crtc_y = s->dst.y1;
 625        state->crtc_w = drm_rect_width(&s->dst);
 626        state->crtc_h = drm_rect_height(&s->dst);
 627
 628        if ((state->src_x | state->src_y | state->src_w | state->src_h) &
 629            SUBPIXEL_MASK)
 630                return -EINVAL;
 631
 632        state->src_x >>= 16;
 633        state->src_y >>= 16;
 634        state->src_w >>= 16;
 635        state->src_h >>= 16;
 636
 637        state->nplanes = fb->format->num_planes;
 638        if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
 639                return -EINVAL;
 640
 641        for (i = 0; i < state->nplanes; i++) {
 642                unsigned int offset = 0;
 643                int xdiv = i ? fb->format->hsub : 1;
 644                int ydiv = i ? fb->format->vsub : 1;
 645
 646                state->bpp[i] = fb->format->cpp[i];
 647                if (!state->bpp[i])
 648                        return -EINVAL;
 649
 650                switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
 651                case DRM_MODE_ROTATE_90:
 652                        offset = (state->src_y / ydiv) *
 653                                 fb->pitches[i];
 654                        offset += ((state->src_x + state->src_w - 1) /
 655                                   xdiv) * state->bpp[i];
 656                        state->xstride[i] = -(((state->src_h - 1) / ydiv) *
 657                                            fb->pitches[i]) -
 658                                          (2 * state->bpp[i]);
 659                        state->pstride[i] = fb->pitches[i] - state->bpp[i];
 660                        break;
 661                case DRM_MODE_ROTATE_180:
 662                        offset = ((state->src_y + state->src_h - 1) /
 663                                  ydiv) * fb->pitches[i];
 664                        offset += ((state->src_x + state->src_w - 1) /
 665                                   xdiv) * state->bpp[i];
 666                        state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
 667                                           state->bpp[i]) - fb->pitches[i];
 668                        state->pstride[i] = -2 * state->bpp[i];
 669                        break;
 670                case DRM_MODE_ROTATE_270:
 671                        offset = ((state->src_y + state->src_h - 1) /
 672                                  ydiv) * fb->pitches[i];
 673                        offset += (state->src_x / xdiv) * state->bpp[i];
 674                        state->xstride[i] = ((state->src_h - 1) / ydiv) *
 675                                          fb->pitches[i];
 676                        state->pstride[i] = -fb->pitches[i] - state->bpp[i];
 677                        break;
 678                case DRM_MODE_ROTATE_0:
 679                default:
 680                        offset = (state->src_y / ydiv) * fb->pitches[i];
 681                        offset += (state->src_x / xdiv) * state->bpp[i];
 682                        state->xstride[i] = fb->pitches[i] -
 683                                          ((state->src_w / xdiv) *
 684                                           state->bpp[i]);
 685                        state->pstride[i] = 0;
 686                        break;
 687                }
 688
 689                state->offsets[i] = offset + fb->offsets[i];
 690        }
 691
 692        /*
 693         * Swap width and size in case of 90 or 270 degrees rotation
 694         */
 695        if (drm_rotation_90_or_270(state->base.rotation)) {
 696                swap(state->src_w, state->src_h);
 697        }
 698
 699        if (!desc->layout.size &&
 700            (mode->hdisplay != state->crtc_w ||
 701             mode->vdisplay != state->crtc_h))
 702                return -EINVAL;
 703
 704        if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
 705            (!desc->layout.memsize ||
 706             state->base.fb->format->has_alpha))
 707                return -EINVAL;
 708
 709        return 0;
 710}
 711
 712static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
 713                                             struct drm_plane_state *old_state)
 714{
 715        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 716
 717        /* Disable interrupts */
 718        atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
 719                                    0xffffffff);
 720
 721        /* Disable the layer */
 722        atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
 723                                    ATMEL_HLCDC_LAYER_RST |
 724                                    ATMEL_HLCDC_LAYER_A2Q |
 725                                    ATMEL_HLCDC_LAYER_UPDATE);
 726
 727        /* Clear all pending interrupts */
 728        atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 729}
 730
 731static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
 732                                            struct drm_plane_state *old_s)
 733{
 734        struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 735        struct atmel_hlcdc_plane_state *state =
 736                        drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 737        u32 sr;
 738
 739        if (!p->state->crtc || !p->state->fb)
 740                return;
 741
 742        if (!state->base.visible) {
 743                atmel_hlcdc_plane_atomic_disable(p, old_s);
 744                return;
 745        }
 746
 747        atmel_hlcdc_plane_update_pos_and_size(plane, state);
 748        atmel_hlcdc_plane_update_general_settings(plane, state);
 749        atmel_hlcdc_plane_update_format(plane, state);
 750        atmel_hlcdc_plane_update_clut(plane, state);
 751        atmel_hlcdc_plane_update_buffers(plane, state);
 752        atmel_hlcdc_plane_update_disc_area(plane, state);
 753
 754        /* Enable the overrun interrupts. */
 755        atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
 756                                    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
 757                                    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
 758                                    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
 759
 760        /* Apply the new config at the next SOF event. */
 761        sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
 762        atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
 763                        ATMEL_HLCDC_LAYER_UPDATE |
 764                        (sr & ATMEL_HLCDC_LAYER_EN ?
 765                         ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
 766}
 767
 768static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
 769{
 770        const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 771
 772        if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
 773            desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
 774                int ret;
 775
 776                ret = drm_plane_create_alpha_property(&plane->base);
 777                if (ret)
 778                        return ret;
 779        }
 780
 781        if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
 782                int ret;
 783
 784                ret = drm_plane_create_rotation_property(&plane->base,
 785                                                         DRM_MODE_ROTATE_0,
 786                                                         DRM_MODE_ROTATE_0 |
 787                                                         DRM_MODE_ROTATE_90 |
 788                                                         DRM_MODE_ROTATE_180 |
 789                                                         DRM_MODE_ROTATE_270);
 790                if (ret)
 791                        return ret;
 792        }
 793
 794        if (desc->layout.csc) {
 795                /*
 796                 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
 797                 * userspace modify these factors (using a BLOB property ?).
 798                 */
 799                atmel_hlcdc_layer_write_cfg(&plane->layer,
 800                                            desc->layout.csc,
 801                                            0x4c900091);
 802                atmel_hlcdc_layer_write_cfg(&plane->layer,
 803                                            desc->layout.csc + 1,
 804                                            0x7a5f5090);
 805                atmel_hlcdc_layer_write_cfg(&plane->layer,
 806                                            desc->layout.csc + 2,
 807                                            0x40040890);
 808        }
 809
 810        return 0;
 811}
 812
 813void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
 814{
 815        const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 816        u32 isr;
 817
 818        isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 819
 820        /*
 821         * There's not much we can do in case of overrun except informing
 822         * the user. However, we are in interrupt context here, hence the
 823         * use of dev_dbg().
 824         */
 825        if (isr &
 826            (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
 827             ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
 828                dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
 829                        desc->name);
 830}
 831
 832static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
 833        .atomic_check = atmel_hlcdc_plane_atomic_check,
 834        .atomic_update = atmel_hlcdc_plane_atomic_update,
 835        .atomic_disable = atmel_hlcdc_plane_atomic_disable,
 836};
 837
 838static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
 839                                         struct atmel_hlcdc_plane_state *state)
 840{
 841        struct atmel_hlcdc_dc *dc = p->dev->dev_private;
 842        int i;
 843
 844        for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
 845                struct atmel_hlcdc_dma_channel_dscr *dscr;
 846                dma_addr_t dscr_dma;
 847
 848                dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
 849                if (!dscr)
 850                        goto err;
 851
 852                dscr->addr = 0;
 853                dscr->next = dscr_dma;
 854                dscr->self = dscr_dma;
 855                dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
 856
 857                state->dscrs[i] = dscr;
 858        }
 859
 860        return 0;
 861
 862err:
 863        for (i--; i >= 0; i--) {
 864                dma_pool_free(dc->dscrpool, state->dscrs[i],
 865                              state->dscrs[i]->self);
 866        }
 867
 868        return -ENOMEM;
 869}
 870
 871static void atmel_hlcdc_plane_reset(struct drm_plane *p)
 872{
 873        struct atmel_hlcdc_plane_state *state;
 874
 875        if (p->state) {
 876                state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 877
 878                if (state->base.fb)
 879                        drm_framebuffer_put(state->base.fb);
 880
 881                kfree(state);
 882                p->state = NULL;
 883        }
 884
 885        state = kzalloc(sizeof(*state), GFP_KERNEL);
 886        if (state) {
 887                if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
 888                        kfree(state);
 889                        dev_err(p->dev->dev,
 890                                "Failed to allocate initial plane state\n");
 891                        return;
 892                }
 893                __drm_atomic_helper_plane_reset(p, &state->base);
 894        }
 895}
 896
 897static struct drm_plane_state *
 898atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
 899{
 900        struct atmel_hlcdc_plane_state *state =
 901                        drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
 902        struct atmel_hlcdc_plane_state *copy;
 903
 904        copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 905        if (!copy)
 906                return NULL;
 907
 908        if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
 909                kfree(copy);
 910                return NULL;
 911        }
 912
 913        if (copy->base.fb)
 914                drm_framebuffer_get(copy->base.fb);
 915
 916        return &copy->base;
 917}
 918
 919static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
 920                                                   struct drm_plane_state *s)
 921{
 922        struct atmel_hlcdc_plane_state *state =
 923                        drm_plane_state_to_atmel_hlcdc_plane_state(s);
 924        struct atmel_hlcdc_dc *dc = p->dev->dev_private;
 925        int i;
 926
 927        for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
 928                dma_pool_free(dc->dscrpool, state->dscrs[i],
 929                              state->dscrs[i]->self);
 930        }
 931
 932        if (s->fb)
 933                drm_framebuffer_put(s->fb);
 934
 935        kfree(state);
 936}
 937
 938static const struct drm_plane_funcs layer_plane_funcs = {
 939        .update_plane = drm_atomic_helper_update_plane,
 940        .disable_plane = drm_atomic_helper_disable_plane,
 941        .destroy = drm_plane_cleanup,
 942        .reset = atmel_hlcdc_plane_reset,
 943        .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
 944        .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
 945};
 946
 947static int atmel_hlcdc_plane_create(struct drm_device *dev,
 948                                    const struct atmel_hlcdc_layer_desc *desc)
 949{
 950        struct atmel_hlcdc_dc *dc = dev->dev_private;
 951        struct atmel_hlcdc_plane *plane;
 952        enum drm_plane_type type;
 953        int ret;
 954
 955        plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
 956        if (!plane)
 957                return -ENOMEM;
 958
 959        atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
 960
 961        if (desc->type == ATMEL_HLCDC_BASE_LAYER)
 962                type = DRM_PLANE_TYPE_PRIMARY;
 963        else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
 964                type = DRM_PLANE_TYPE_CURSOR;
 965        else
 966                type = DRM_PLANE_TYPE_OVERLAY;
 967
 968        ret = drm_universal_plane_init(dev, &plane->base, 0,
 969                                       &layer_plane_funcs,
 970                                       desc->formats->formats,
 971                                       desc->formats->nformats,
 972                                       NULL, type, NULL);
 973        if (ret)
 974                return ret;
 975
 976        drm_plane_helper_add(&plane->base,
 977                             &atmel_hlcdc_layer_plane_helper_funcs);
 978
 979        /* Set default property values*/
 980        ret = atmel_hlcdc_plane_init_properties(plane);
 981        if (ret)
 982                return ret;
 983
 984        dc->layers[desc->id] = &plane->layer;
 985
 986        return 0;
 987}
 988
 989int atmel_hlcdc_create_planes(struct drm_device *dev)
 990{
 991        struct atmel_hlcdc_dc *dc = dev->dev_private;
 992        const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
 993        int nlayers = dc->desc->nlayers;
 994        int i, ret;
 995
 996        dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
 997                                sizeof(struct atmel_hlcdc_dma_channel_dscr),
 998                                sizeof(u64), 0);
 999        if (!dc->dscrpool)
1000                return -ENOMEM;
1001
1002        for (i = 0; i < nlayers; i++) {
1003                if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1004                    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1005                    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1006                        continue;
1007
1008                ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1009                if (ret)
1010                        return ret;
1011        }
1012
1013        return 0;
1014}
1015