linux/drivers/gpu/drm/vc4/vc4_plane.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Broadcom
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9/**
  10 * DOC: VC4 plane module
  11 *
  12 * Each DRM plane is a layer of pixels being scanned out by the HVS.
  13 *
  14 * At atomic modeset check time, we compute the HVS display element
  15 * state that would be necessary for displaying the plane (giving us a
  16 * chance to figure out if a plane configuration is invalid), then at
  17 * atomic flush time the CRTC will ask us to write our element state
  18 * into the region of the HVS that it has allocated for us.
  19 */
  20
  21#include <drm/drm_atomic.h>
  22#include <drm/drm_atomic_helper.h>
  23#include <drm/drm_fb_cma_helper.h>
  24#include <drm/drm_plane_helper.h>
  25
  26#include "uapi/drm/vc4_drm.h"
  27#include "vc4_drv.h"
  28#include "vc4_regs.h"
  29
  30static const struct hvs_format {
  31        u32 drm; /* DRM_FORMAT_* */
  32        u32 hvs; /* HVS_FORMAT_* */
  33        u32 pixel_order;
  34} hvs_formats[] = {
  35        {
  36                .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
  37                .pixel_order = HVS_PIXEL_ORDER_ABGR,
  38        },
  39        {
  40                .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
  41                .pixel_order = HVS_PIXEL_ORDER_ABGR,
  42        },
  43        {
  44                .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
  45                .pixel_order = HVS_PIXEL_ORDER_ARGB,
  46        },
  47        {
  48                .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
  49                .pixel_order = HVS_PIXEL_ORDER_ARGB,
  50        },
  51        {
  52                .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
  53                .pixel_order = HVS_PIXEL_ORDER_XRGB,
  54        },
  55        {
  56                .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
  57                .pixel_order = HVS_PIXEL_ORDER_XBGR,
  58        },
  59        {
  60                .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
  61                .pixel_order = HVS_PIXEL_ORDER_ABGR,
  62        },
  63        {
  64                .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
  65                .pixel_order = HVS_PIXEL_ORDER_ABGR,
  66        },
  67        {
  68                .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
  69                .pixel_order = HVS_PIXEL_ORDER_XRGB,
  70        },
  71        {
  72                .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
  73                .pixel_order = HVS_PIXEL_ORDER_XBGR,
  74        },
  75        {
  76                .drm = DRM_FORMAT_YUV422,
  77                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
  78                .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
  79        },
  80        {
  81                .drm = DRM_FORMAT_YVU422,
  82                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
  83                .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
  84        },
  85        {
  86                .drm = DRM_FORMAT_YUV420,
  87                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
  88                .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
  89        },
  90        {
  91                .drm = DRM_FORMAT_YVU420,
  92                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
  93                .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
  94        },
  95        {
  96                .drm = DRM_FORMAT_NV12,
  97                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
  98                .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
  99        },
 100        {
 101                .drm = DRM_FORMAT_NV21,
 102                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
 103                .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 104        },
 105        {
 106                .drm = DRM_FORMAT_NV16,
 107                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
 108                .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
 109        },
 110        {
 111                .drm = DRM_FORMAT_NV61,
 112                .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
 113                .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 114        },
 115};
 116
 117static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
 118{
 119        unsigned i;
 120
 121        for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
 122                if (hvs_formats[i].drm == drm_format)
 123                        return &hvs_formats[i];
 124        }
 125
 126        return NULL;
 127}
 128
 129static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
 130{
 131        if (dst > src)
 132                return VC4_SCALING_PPF;
 133        else if (dst < src)
 134                return VC4_SCALING_TPZ;
 135        else
 136                return VC4_SCALING_NONE;
 137}
 138
 139static bool plane_enabled(struct drm_plane_state *state)
 140{
 141        return state->fb && state->crtc;
 142}
 143
 144static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
 145{
 146        struct vc4_plane_state *vc4_state;
 147
 148        if (WARN_ON(!plane->state))
 149                return NULL;
 150
 151        vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);
 152        if (!vc4_state)
 153                return NULL;
 154
 155        memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
 156
 157        __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
 158
 159        if (vc4_state->dlist) {
 160                vc4_state->dlist = kmemdup(vc4_state->dlist,
 161                                           vc4_state->dlist_count * 4,
 162                                           GFP_KERNEL);
 163                if (!vc4_state->dlist) {
 164                        kfree(vc4_state);
 165                        return NULL;
 166                }
 167                vc4_state->dlist_size = vc4_state->dlist_count;
 168        }
 169
 170        return &vc4_state->base;
 171}
 172
 173static void vc4_plane_destroy_state(struct drm_plane *plane,
 174                                    struct drm_plane_state *state)
 175{
 176        struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
 177        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 178
 179        if (vc4_state->lbm.allocated) {
 180                unsigned long irqflags;
 181
 182                spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
 183                drm_mm_remove_node(&vc4_state->lbm);
 184                spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
 185        }
 186
 187        kfree(vc4_state->dlist);
 188        __drm_atomic_helper_plane_destroy_state(&vc4_state->base);
 189        kfree(state);
 190}
 191
 192/* Called during init to allocate the plane's atomic state. */
 193static void vc4_plane_reset(struct drm_plane *plane)
 194{
 195        struct vc4_plane_state *vc4_state;
 196
 197        WARN_ON(plane->state);
 198
 199        vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
 200        if (!vc4_state)
 201                return;
 202
 203        plane->state = &vc4_state->base;
 204        vc4_state->base.plane = plane;
 205}
 206
 207static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
 208{
 209        if (vc4_state->dlist_count == vc4_state->dlist_size) {
 210                u32 new_size = max(4u, vc4_state->dlist_count * 2);
 211                u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL);
 212
 213                if (!new_dlist)
 214                        return;
 215                memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4);
 216
 217                kfree(vc4_state->dlist);
 218                vc4_state->dlist = new_dlist;
 219                vc4_state->dlist_size = new_size;
 220        }
 221
 222        vc4_state->dlist[vc4_state->dlist_count++] = val;
 223}
 224
 225/* Returns the scl0/scl1 field based on whether the dimensions need to
 226 * be up/down/non-scaled.
 227 *
 228 * This is a replication of a table from the spec.
 229 */
 230static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
 231{
 232        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 233
 234        switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
 235        case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
 236                return SCALER_CTL0_SCL_H_PPF_V_PPF;
 237        case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
 238                return SCALER_CTL0_SCL_H_TPZ_V_PPF;
 239        case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
 240                return SCALER_CTL0_SCL_H_PPF_V_TPZ;
 241        case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
 242                return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
 243        case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
 244                return SCALER_CTL0_SCL_H_PPF_V_NONE;
 245        case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
 246                return SCALER_CTL0_SCL_H_NONE_V_PPF;
 247        case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
 248                return SCALER_CTL0_SCL_H_NONE_V_TPZ;
 249        case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
 250                return SCALER_CTL0_SCL_H_TPZ_V_NONE;
 251        default:
 252        case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
 253                /* The unity case is independently handled by
 254                 * SCALER_CTL0_UNITY.
 255                 */
 256                return 0;
 257        }
 258}
 259
 260static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
 261{
 262        struct drm_plane *plane = state->plane;
 263        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 264        struct drm_framebuffer *fb = state->fb;
 265        struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
 266        u32 subpixel_src_mask = (1 << 16) - 1;
 267        u32 format = fb->format->format;
 268        int num_planes = fb->format->num_planes;
 269        u32 h_subsample = 1;
 270        u32 v_subsample = 1;
 271        int i;
 272
 273        for (i = 0; i < num_planes; i++)
 274                vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
 275
 276        /* We don't support subpixel source positioning for scaling. */
 277        if ((state->src_x & subpixel_src_mask) ||
 278            (state->src_y & subpixel_src_mask) ||
 279            (state->src_w & subpixel_src_mask) ||
 280            (state->src_h & subpixel_src_mask)) {
 281                return -EINVAL;
 282        }
 283
 284        vc4_state->src_x = state->src_x >> 16;
 285        vc4_state->src_y = state->src_y >> 16;
 286        vc4_state->src_w[0] = state->src_w >> 16;
 287        vc4_state->src_h[0] = state->src_h >> 16;
 288
 289        vc4_state->crtc_x = state->crtc_x;
 290        vc4_state->crtc_y = state->crtc_y;
 291        vc4_state->crtc_w = state->crtc_w;
 292        vc4_state->crtc_h = state->crtc_h;
 293
 294        vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
 295                                                       vc4_state->crtc_w);
 296        vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
 297                                                       vc4_state->crtc_h);
 298
 299        if (num_planes > 1) {
 300                vc4_state->is_yuv = true;
 301
 302                h_subsample = drm_format_horz_chroma_subsampling(format);
 303                v_subsample = drm_format_vert_chroma_subsampling(format);
 304                vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
 305                vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
 306
 307                vc4_state->x_scaling[1] =
 308                        vc4_get_scaling_mode(vc4_state->src_w[1],
 309                                             vc4_state->crtc_w);
 310                vc4_state->y_scaling[1] =
 311                        vc4_get_scaling_mode(vc4_state->src_h[1],
 312                                             vc4_state->crtc_h);
 313
 314                /* YUV conversion requires that scaling be enabled,
 315                 * even on a plane that's otherwise 1:1.  Choose TPZ
 316                 * for simplicity.
 317                 */
 318                if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
 319                        vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
 320                if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
 321                        vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
 322        }
 323
 324        vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
 325                               vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
 326                               vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
 327                               vc4_state->y_scaling[1] == VC4_SCALING_NONE);
 328
 329        /* No configuring scaling on the cursor plane, since it gets
 330           non-vblank-synced updates, and scaling requires requires
 331           LBM changes which have to be vblank-synced.
 332         */
 333        if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
 334                return -EINVAL;
 335
 336        /* Clamp the on-screen start x/y to 0.  The hardware doesn't
 337         * support negative y, and negative x wastes bandwidth.
 338         */
 339        if (vc4_state->crtc_x < 0) {
 340                for (i = 0; i < num_planes; i++) {
 341                        u32 cpp = fb->format->cpp[i];
 342                        u32 subs = ((i == 0) ? 1 : h_subsample);
 343
 344                        vc4_state->offsets[i] += (cpp *
 345                                                  (-vc4_state->crtc_x) / subs);
 346                }
 347                vc4_state->src_w[0] += vc4_state->crtc_x;
 348                vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
 349                vc4_state->crtc_x = 0;
 350        }
 351
 352        if (vc4_state->crtc_y < 0) {
 353                for (i = 0; i < num_planes; i++) {
 354                        u32 subs = ((i == 0) ? 1 : v_subsample);
 355
 356                        vc4_state->offsets[i] += (fb->pitches[i] *
 357                                                  (-vc4_state->crtc_y) / subs);
 358                }
 359                vc4_state->src_h[0] += vc4_state->crtc_y;
 360                vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
 361                vc4_state->crtc_y = 0;
 362        }
 363
 364        return 0;
 365}
 366
 367static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
 368{
 369        u32 scale, recip;
 370
 371        scale = (1 << 16) * src / dst;
 372
 373        /* The specs note that while the reciprocal would be defined
 374         * as (1<<32)/scale, ~0 is close enough.
 375         */
 376        recip = ~0 / scale;
 377
 378        vc4_dlist_write(vc4_state,
 379                        VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
 380                        VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
 381        vc4_dlist_write(vc4_state,
 382                        VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
 383}
 384
 385static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
 386{
 387        u32 scale = (1 << 16) * src / dst;
 388
 389        vc4_dlist_write(vc4_state,
 390                        SCALER_PPF_AGC |
 391                        VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
 392                        VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
 393}
 394
 395static u32 vc4_lbm_size(struct drm_plane_state *state)
 396{
 397        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 398        /* This is the worst case number.  One of the two sizes will
 399         * be used depending on the scaling configuration.
 400         */
 401        u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
 402        u32 lbm;
 403
 404        if (!vc4_state->is_yuv) {
 405                if (vc4_state->is_unity)
 406                        return 0;
 407                else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
 408                        lbm = pix_per_line * 8;
 409                else {
 410                        /* In special cases, this multiplier might be 12. */
 411                        lbm = pix_per_line * 16;
 412                }
 413        } else {
 414                /* There are cases for this going down to a multiplier
 415                 * of 2, but according to the firmware source, the
 416                 * table in the docs is somewhat wrong.
 417                 */
 418                lbm = pix_per_line * 16;
 419        }
 420
 421        lbm = roundup(lbm, 32);
 422
 423        return lbm;
 424}
 425
 426static void vc4_write_scaling_parameters(struct drm_plane_state *state,
 427                                         int channel)
 428{
 429        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 430
 431        /* Ch0 H-PPF Word 0: Scaling Parameters */
 432        if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
 433                vc4_write_ppf(vc4_state,
 434                              vc4_state->src_w[channel], vc4_state->crtc_w);
 435        }
 436
 437        /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
 438        if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
 439                vc4_write_ppf(vc4_state,
 440                              vc4_state->src_h[channel], vc4_state->crtc_h);
 441                vc4_dlist_write(vc4_state, 0xc0c0c0c0);
 442        }
 443
 444        /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
 445        if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
 446                vc4_write_tpz(vc4_state,
 447                              vc4_state->src_w[channel], vc4_state->crtc_w);
 448        }
 449
 450        /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
 451        if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
 452                vc4_write_tpz(vc4_state,
 453                              vc4_state->src_h[channel], vc4_state->crtc_h);
 454                vc4_dlist_write(vc4_state, 0xc0c0c0c0);
 455        }
 456}
 457
 458/* Writes out a full display list for an active plane to the plane's
 459 * private dlist state.
 460 */
 461static int vc4_plane_mode_set(struct drm_plane *plane,
 462                              struct drm_plane_state *state)
 463{
 464        struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
 465        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 466        struct drm_framebuffer *fb = state->fb;
 467        u32 ctl0_offset = vc4_state->dlist_count;
 468        const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
 469        int num_planes = drm_format_num_planes(format->drm);
 470        bool covers_screen;
 471        u32 scl0, scl1, pitch0;
 472        u32 lbm_size, tiling;
 473        unsigned long irqflags;
 474        int ret, i;
 475
 476        ret = vc4_plane_setup_clipping_and_scaling(state);
 477        if (ret)
 478                return ret;
 479
 480        /* Allocate the LBM memory that the HVS will use for temporary
 481         * storage due to our scaling/format conversion.
 482         */
 483        lbm_size = vc4_lbm_size(state);
 484        if (lbm_size) {
 485                if (!vc4_state->lbm.allocated) {
 486                        spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
 487                        ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
 488                                                         &vc4_state->lbm,
 489                                                         lbm_size, 32, 0, 0);
 490                        spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
 491                } else {
 492                        WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
 493                }
 494        }
 495
 496        if (ret)
 497                return ret;
 498
 499        /* SCL1 is used for Cb/Cr scaling of planar formats.  For RGB
 500         * and 4:4:4, scl1 should be set to scl0 so both channels of
 501         * the scaler do the same thing.  For YUV, the Y plane needs
 502         * to be put in channel 1 and Cb/Cr in channel 0, so we swap
 503         * the scl fields here.
 504         */
 505        if (num_planes == 1) {
 506                scl0 = vc4_get_scl_field(state, 0);
 507                scl1 = scl0;
 508        } else {
 509                scl0 = vc4_get_scl_field(state, 1);
 510                scl1 = vc4_get_scl_field(state, 0);
 511        }
 512
 513        switch (fb->modifier) {
 514        case DRM_FORMAT_MOD_LINEAR:
 515                tiling = SCALER_CTL0_TILING_LINEAR;
 516                pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
 517                break;
 518
 519        case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
 520                /* For T-tiled, the FB pitch is "how many bytes from
 521                 * one row to the next, such that pitch * tile_h ==
 522                 * tile_size * tiles_per_row."
 523                 */
 524                u32 tile_size_shift = 12; /* T tiles are 4kb */
 525                u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
 526                u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
 527
 528                tiling = SCALER_CTL0_TILING_256B_OR_T;
 529
 530                pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
 531                          VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
 532                          VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
 533                break;
 534        }
 535
 536        default:
 537                DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
 538                              (long long)fb->modifier);
 539                return -EINVAL;
 540        }
 541
 542        /* Control word */
 543        vc4_dlist_write(vc4_state,
 544                        SCALER_CTL0_VALID |
 545                        (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
 546                        (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
 547                        VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
 548                        (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
 549                        VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
 550                        VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
 551
 552        /* Position Word 0: Image Positions and Alpha Value */
 553        vc4_state->pos0_offset = vc4_state->dlist_count;
 554        vc4_dlist_write(vc4_state,
 555                        VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) |
 556                        VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
 557                        VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
 558
 559        /* Position Word 1: Scaled Image Dimensions. */
 560        if (!vc4_state->is_unity) {
 561                vc4_dlist_write(vc4_state,
 562                                VC4_SET_FIELD(vc4_state->crtc_w,
 563                                              SCALER_POS1_SCL_WIDTH) |
 564                                VC4_SET_FIELD(vc4_state->crtc_h,
 565                                              SCALER_POS1_SCL_HEIGHT));
 566        }
 567
 568        /* Position Word 2: Source Image Size, Alpha */
 569        vc4_state->pos2_offset = vc4_state->dlist_count;
 570        vc4_dlist_write(vc4_state,
 571                        VC4_SET_FIELD(fb->format->has_alpha ?
 572                                      SCALER_POS2_ALPHA_MODE_PIPELINE :
 573                                      SCALER_POS2_ALPHA_MODE_FIXED,
 574                                      SCALER_POS2_ALPHA_MODE) |
 575                        (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
 576                        VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
 577                        VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
 578
 579        /* Position Word 3: Context.  Written by the HVS. */
 580        vc4_dlist_write(vc4_state, 0xc0c0c0c0);
 581
 582
 583        /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
 584         *
 585         * The pointers may be any byte address.
 586         */
 587        vc4_state->ptr0_offset = vc4_state->dlist_count;
 588        for (i = 0; i < num_planes; i++)
 589                vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
 590
 591        /* Pointer Context Word 0/1/2: Written by the HVS */
 592        for (i = 0; i < num_planes; i++)
 593                vc4_dlist_write(vc4_state, 0xc0c0c0c0);
 594
 595        /* Pitch word 0 */
 596        vc4_dlist_write(vc4_state, pitch0);
 597
 598        /* Pitch word 1/2 */
 599        for (i = 1; i < num_planes; i++) {
 600                vc4_dlist_write(vc4_state,
 601                                VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
 602        }
 603
 604        /* Colorspace conversion words */
 605        if (vc4_state->is_yuv) {
 606                vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
 607                vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
 608                vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
 609        }
 610
 611        if (!vc4_state->is_unity) {
 612                /* LBM Base Address. */
 613                if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
 614                    vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
 615                        vc4_dlist_write(vc4_state, vc4_state->lbm.start);
 616                }
 617
 618                if (num_planes > 1) {
 619                        /* Emit Cb/Cr as channel 0 and Y as channel
 620                         * 1. This matches how we set up scl0/scl1
 621                         * above.
 622                         */
 623                        vc4_write_scaling_parameters(state, 1);
 624                }
 625                vc4_write_scaling_parameters(state, 0);
 626
 627                /* If any PPF setup was done, then all the kernel
 628                 * pointers get uploaded.
 629                 */
 630                if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
 631                    vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
 632                    vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
 633                    vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
 634                        u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
 635                                                   SCALER_PPF_KERNEL_OFFSET);
 636
 637                        /* HPPF plane 0 */
 638                        vc4_dlist_write(vc4_state, kernel);
 639                        /* VPPF plane 0 */
 640                        vc4_dlist_write(vc4_state, kernel);
 641                        /* HPPF plane 1 */
 642                        vc4_dlist_write(vc4_state, kernel);
 643                        /* VPPF plane 1 */
 644                        vc4_dlist_write(vc4_state, kernel);
 645                }
 646        }
 647
 648        vc4_state->dlist[ctl0_offset] |=
 649                VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
 650
 651        /* crtc_* are already clipped coordinates. */
 652        covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
 653                        vc4_state->crtc_w == state->crtc->mode.hdisplay &&
 654                        vc4_state->crtc_h == state->crtc->mode.vdisplay;
 655        /* Background fill might be necessary when the plane has per-pixel
 656         * alpha content and blends from the background or does not cover
 657         * the entire screen.
 658         */
 659        vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen;
 660
 661        return 0;
 662}
 663
 664/* If a modeset involves changing the setup of a plane, the atomic
 665 * infrastructure will call this to validate a proposed plane setup.
 666 * However, if a plane isn't getting updated, this (and the
 667 * corresponding vc4_plane_atomic_update) won't get called.  Thus, we
 668 * compute the dlist here and have all active plane dlists get updated
 669 * in the CRTC's flush.
 670 */
 671static int vc4_plane_atomic_check(struct drm_plane *plane,
 672                                  struct drm_plane_state *state)
 673{
 674        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 675
 676        vc4_state->dlist_count = 0;
 677
 678        if (plane_enabled(state))
 679                return vc4_plane_mode_set(plane, state);
 680        else
 681                return 0;
 682}
 683
 684static void vc4_plane_atomic_update(struct drm_plane *plane,
 685                                    struct drm_plane_state *old_state)
 686{
 687        /* No contents here.  Since we don't know where in the CRTC's
 688         * dlist we should be stored, our dlist is uploaded to the
 689         * hardware with vc4_plane_write_dlist() at CRTC atomic_flush
 690         * time.
 691         */
 692}
 693
 694u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)
 695{
 696        struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
 697        int i;
 698
 699        vc4_state->hw_dlist = dlist;
 700
 701        /* Can't memcpy_toio() because it needs to be 32-bit writes. */
 702        for (i = 0; i < vc4_state->dlist_count; i++)
 703                writel(vc4_state->dlist[i], &dlist[i]);
 704
 705        return vc4_state->dlist_count;
 706}
 707
 708u32 vc4_plane_dlist_size(const struct drm_plane_state *state)
 709{
 710        const struct vc4_plane_state *vc4_state =
 711                container_of(state, typeof(*vc4_state), base);
 712
 713        return vc4_state->dlist_count;
 714}
 715
 716/* Updates the plane to immediately (well, once the FIFO needs
 717 * refilling) scan out from at a new framebuffer.
 718 */
 719void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
 720{
 721        struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
 722        struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
 723        uint32_t addr;
 724
 725        /* We're skipping the address adjustment for negative origin,
 726         * because this is only called on the primary plane.
 727         */
 728        WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
 729        addr = bo->paddr + fb->offsets[0];
 730
 731        /* Write the new address into the hardware immediately.  The
 732         * scanout will start from this address as soon as the FIFO
 733         * needs to refill with pixels.
 734         */
 735        writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
 736
 737        /* Also update the CPU-side dlist copy, so that any later
 738         * atomic updates that don't do a new modeset on our plane
 739         * also use our updated address.
 740         */
 741        vc4_state->dlist[vc4_state->ptr0_offset] = addr;
 742}
 743
 744static int vc4_prepare_fb(struct drm_plane *plane,
 745                          struct drm_plane_state *state)
 746{
 747        struct vc4_bo *bo;
 748        struct dma_fence *fence;
 749        int ret;
 750
 751        if ((plane->state->fb == state->fb) || !state->fb)
 752                return 0;
 753
 754        bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
 755
 756        ret = vc4_bo_inc_usecnt(bo);
 757        if (ret)
 758                return ret;
 759
 760        fence = reservation_object_get_excl_rcu(bo->resv);
 761        drm_atomic_set_fence_for_plane(state, fence);
 762
 763        return 0;
 764}
 765
 766static void vc4_cleanup_fb(struct drm_plane *plane,
 767                           struct drm_plane_state *state)
 768{
 769        struct vc4_bo *bo;
 770
 771        if (plane->state->fb == state->fb || !state->fb)
 772                return;
 773
 774        bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
 775        vc4_bo_dec_usecnt(bo);
 776}
 777
 778static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
 779        .atomic_check = vc4_plane_atomic_check,
 780        .atomic_update = vc4_plane_atomic_update,
 781        .prepare_fb = vc4_prepare_fb,
 782        .cleanup_fb = vc4_cleanup_fb,
 783};
 784
 785static void vc4_plane_destroy(struct drm_plane *plane)
 786{
 787        drm_plane_helper_disable(plane);
 788        drm_plane_cleanup(plane);
 789}
 790
 791/* Implements immediate (non-vblank-synced) updates of the cursor
 792 * position, or falls back to the atomic helper otherwise.
 793 */
 794static int
 795vc4_update_plane(struct drm_plane *plane,
 796                 struct drm_crtc *crtc,
 797                 struct drm_framebuffer *fb,
 798                 int crtc_x, int crtc_y,
 799                 unsigned int crtc_w, unsigned int crtc_h,
 800                 uint32_t src_x, uint32_t src_y,
 801                 uint32_t src_w, uint32_t src_h,
 802                 struct drm_modeset_acquire_ctx *ctx)
 803{
 804        struct drm_plane_state *plane_state;
 805        struct vc4_plane_state *vc4_state;
 806
 807        if (plane != crtc->cursor)
 808                goto out;
 809
 810        plane_state = plane->state;
 811        vc4_state = to_vc4_plane_state(plane_state);
 812
 813        if (!plane_state)
 814                goto out;
 815
 816        /* No configuring new scaling in the fast path. */
 817        if (crtc_w != plane_state->crtc_w ||
 818            crtc_h != plane_state->crtc_h ||
 819            src_w != plane_state->src_w ||
 820            src_h != plane_state->src_h) {
 821                goto out;
 822        }
 823
 824        if (fb != plane_state->fb) {
 825                drm_atomic_set_fb_for_plane(plane->state, fb);
 826                vc4_plane_async_set_fb(plane, fb);
 827        }
 828
 829        /* Set the cursor's position on the screen.  This is the
 830         * expected change from the drm_mode_cursor_universal()
 831         * helper.
 832         */
 833        plane_state->crtc_x = crtc_x;
 834        plane_state->crtc_y = crtc_y;
 835
 836        /* Allow changing the start position within the cursor BO, if
 837         * that matters.
 838         */
 839        plane_state->src_x = src_x;
 840        plane_state->src_y = src_y;
 841
 842        /* Update the display list based on the new crtc_x/y. */
 843        vc4_plane_atomic_check(plane, plane_state);
 844
 845        /* Note that we can't just call vc4_plane_write_dlist()
 846         * because that would smash the context data that the HVS is
 847         * currently using.
 848         */
 849        writel(vc4_state->dlist[vc4_state->pos0_offset],
 850               &vc4_state->hw_dlist[vc4_state->pos0_offset]);
 851        writel(vc4_state->dlist[vc4_state->pos2_offset],
 852               &vc4_state->hw_dlist[vc4_state->pos2_offset]);
 853        writel(vc4_state->dlist[vc4_state->ptr0_offset],
 854               &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
 855
 856        return 0;
 857
 858out:
 859        return drm_atomic_helper_update_plane(plane, crtc, fb,
 860                                              crtc_x, crtc_y,
 861                                              crtc_w, crtc_h,
 862                                              src_x, src_y,
 863                                              src_w, src_h,
 864                                              ctx);
 865}
 866
 867static bool vc4_format_mod_supported(struct drm_plane *plane,
 868                                     uint32_t format,
 869                                     uint64_t modifier)
 870{
 871        /* Support T_TILING for RGB formats only. */
 872        switch (format) {
 873        case DRM_FORMAT_XRGB8888:
 874        case DRM_FORMAT_ARGB8888:
 875        case DRM_FORMAT_ABGR8888:
 876        case DRM_FORMAT_XBGR8888:
 877        case DRM_FORMAT_RGB565:
 878        case DRM_FORMAT_BGR565:
 879        case DRM_FORMAT_ARGB1555:
 880        case DRM_FORMAT_XRGB1555:
 881                return true;
 882        case DRM_FORMAT_YUV422:
 883        case DRM_FORMAT_YVU422:
 884        case DRM_FORMAT_YUV420:
 885        case DRM_FORMAT_YVU420:
 886        case DRM_FORMAT_NV12:
 887        case DRM_FORMAT_NV16:
 888        default:
 889                return (modifier == DRM_FORMAT_MOD_LINEAR);
 890        }
 891}
 892
 893static const struct drm_plane_funcs vc4_plane_funcs = {
 894        .update_plane = vc4_update_plane,
 895        .disable_plane = drm_atomic_helper_disable_plane,
 896        .destroy = vc4_plane_destroy,
 897        .set_property = NULL,
 898        .reset = vc4_plane_reset,
 899        .atomic_duplicate_state = vc4_plane_duplicate_state,
 900        .atomic_destroy_state = vc4_plane_destroy_state,
 901        .format_mod_supported = vc4_format_mod_supported,
 902};
 903
 904struct drm_plane *vc4_plane_init(struct drm_device *dev,
 905                                 enum drm_plane_type type)
 906{
 907        struct drm_plane *plane = NULL;
 908        struct vc4_plane *vc4_plane;
 909        u32 formats[ARRAY_SIZE(hvs_formats)];
 910        u32 num_formats = 0;
 911        int ret = 0;
 912        unsigned i;
 913        static const uint64_t modifiers[] = {
 914                DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
 915                DRM_FORMAT_MOD_LINEAR,
 916                DRM_FORMAT_MOD_INVALID
 917        };
 918
 919        vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
 920                                 GFP_KERNEL);
 921        if (!vc4_plane)
 922                return ERR_PTR(-ENOMEM);
 923
 924        for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
 925                /* Don't allow YUV in cursor planes, since that means
 926                 * tuning on the scaler, which we don't allow for the
 927                 * cursor.
 928                 */
 929                if (type != DRM_PLANE_TYPE_CURSOR ||
 930                    hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) {
 931                        formats[num_formats++] = hvs_formats[i].drm;
 932                }
 933        }
 934        plane = &vc4_plane->base;
 935        ret = drm_universal_plane_init(dev, plane, 0,
 936                                       &vc4_plane_funcs,
 937                                       formats, num_formats,
 938                                       modifiers, type, NULL);
 939
 940        drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
 941
 942        return plane;
 943}
 944