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