linux/drivers/gpu/drm/zte/zx_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2016 Linaro Ltd.
   4 * Copyright 2016 ZTE Corporation.
   5 */
   6
   7#include <drm/drm_atomic.h>
   8#include <drm/drm_atomic_helper.h>
   9#include <drm/drm_fb_cma_helper.h>
  10#include <drm/drm_fourcc.h>
  11#include <drm/drm_gem_cma_helper.h>
  12#include <drm/drm_modeset_helper_vtables.h>
  13#include <drm/drm_plane_helper.h>
  14
  15#include "zx_common_regs.h"
  16#include "zx_drm_drv.h"
  17#include "zx_plane.h"
  18#include "zx_plane_regs.h"
  19#include "zx_vou.h"
  20
  21static const uint32_t gl_formats[] = {
  22        DRM_FORMAT_ARGB8888,
  23        DRM_FORMAT_XRGB8888,
  24        DRM_FORMAT_RGB888,
  25        DRM_FORMAT_RGB565,
  26        DRM_FORMAT_ARGB1555,
  27        DRM_FORMAT_ARGB4444,
  28};
  29
  30static const uint32_t vl_formats[] = {
  31        DRM_FORMAT_NV12,        /* Semi-planar YUV420 */
  32        DRM_FORMAT_YUV420,      /* Planar YUV420 */
  33        DRM_FORMAT_YUYV,        /* Packed YUV422 */
  34        DRM_FORMAT_YVYU,
  35        DRM_FORMAT_UYVY,
  36        DRM_FORMAT_VYUY,
  37        DRM_FORMAT_YUV444,      /* YUV444 8bit */
  38        /*
  39         * TODO: add formats below that HW supports:
  40         *  - YUV420 P010
  41         *  - YUV420 Hantro
  42         *  - YUV444 10bit
  43         */
  44};
  45
  46#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
  47
  48static int zx_vl_plane_atomic_check(struct drm_plane *plane,
  49                                    struct drm_atomic_state *state)
  50{
  51        struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
  52                                                                             plane);
  53        struct drm_framebuffer *fb = plane_state->fb;
  54        struct drm_crtc *crtc = plane_state->crtc;
  55        struct drm_crtc_state *crtc_state;
  56        int min_scale = FRAC_16_16(1, 8);
  57        int max_scale = FRAC_16_16(8, 1);
  58
  59        if (!crtc || WARN_ON(!fb))
  60                return 0;
  61
  62        crtc_state = drm_atomic_get_existing_crtc_state(state,
  63                                                        crtc);
  64        if (WARN_ON(!crtc_state))
  65                return -EINVAL;
  66
  67        /* nothing to check when disabling or disabled */
  68        if (!crtc_state->enable)
  69                return 0;
  70
  71        /* plane must be enabled */
  72        if (!plane_state->crtc)
  73                return -EINVAL;
  74
  75        return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
  76                                                   min_scale, max_scale,
  77                                                   true, true);
  78}
  79
  80static int zx_vl_get_fmt(uint32_t format)
  81{
  82        switch (format) {
  83        case DRM_FORMAT_NV12:
  84                return VL_FMT_YUV420;
  85        case DRM_FORMAT_YUV420:
  86                return VL_YUV420_PLANAR | VL_FMT_YUV420;
  87        case DRM_FORMAT_YUYV:
  88                return VL_YUV422_YUYV | VL_FMT_YUV422;
  89        case DRM_FORMAT_YVYU:
  90                return VL_YUV422_YVYU | VL_FMT_YUV422;
  91        case DRM_FORMAT_UYVY:
  92                return VL_YUV422_UYVY | VL_FMT_YUV422;
  93        case DRM_FORMAT_VYUY:
  94                return VL_YUV422_VYUY | VL_FMT_YUV422;
  95        case DRM_FORMAT_YUV444:
  96                return VL_FMT_YUV444_8BIT;
  97        default:
  98                WARN_ONCE(1, "invalid pixel format %d\n", format);
  99                return -EINVAL;
 100        }
 101}
 102
 103static inline void zx_vl_set_update(struct zx_plane *zplane)
 104{
 105        void __iomem *layer = zplane->layer;
 106
 107        zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
 108}
 109
 110static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
 111{
 112        zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
 113}
 114
 115static int zx_vl_rsz_get_fmt(uint32_t format)
 116{
 117        switch (format) {
 118        case DRM_FORMAT_NV12:
 119        case DRM_FORMAT_YUV420:
 120                return RSZ_VL_FMT_YCBCR420;
 121        case DRM_FORMAT_YUYV:
 122        case DRM_FORMAT_YVYU:
 123        case DRM_FORMAT_UYVY:
 124        case DRM_FORMAT_VYUY:
 125                return RSZ_VL_FMT_YCBCR422;
 126        case DRM_FORMAT_YUV444:
 127                return RSZ_VL_FMT_YCBCR444;
 128        default:
 129                WARN_ONCE(1, "invalid pixel format %d\n", format);
 130                return -EINVAL;
 131        }
 132}
 133
 134static inline u32 rsz_step_value(u32 src, u32 dst)
 135{
 136        u32 val = 0;
 137
 138        if (src == dst)
 139                val = 0;
 140        else if (src < dst)
 141                val = RSZ_PARA_STEP((src << 16) / dst);
 142        else if (src > dst)
 143                val = RSZ_DATA_STEP(src / dst) |
 144                      RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
 145
 146        return val;
 147}
 148
 149static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
 150                            u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
 151{
 152        void __iomem *rsz = zplane->rsz;
 153        u32 src_chroma_w = src_w;
 154        u32 src_chroma_h = src_h;
 155        int fmt;
 156
 157        /* Set up source and destination resolution */
 158        zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
 159        zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
 160
 161        /* Configure data format for VL RSZ */
 162        fmt = zx_vl_rsz_get_fmt(format);
 163        if (fmt >= 0)
 164                zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
 165
 166        /* Calculate Chroma height and width */
 167        if (fmt == RSZ_VL_FMT_YCBCR420) {
 168                src_chroma_w = src_w >> 1;
 169                src_chroma_h = src_h >> 1;
 170        } else if (fmt == RSZ_VL_FMT_YCBCR422) {
 171                src_chroma_w = src_w >> 1;
 172        }
 173
 174        /* Set up Luma and Chroma step registers */
 175        zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
 176        zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
 177        zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
 178        zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
 179
 180        zx_vl_rsz_set_update(zplane);
 181}
 182
 183static void zx_vl_plane_atomic_update(struct drm_plane *plane,
 184                                      struct drm_atomic_state *state)
 185{
 186        struct zx_plane *zplane = to_zx_plane(plane);
 187        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 188                                                                           plane);
 189        struct drm_framebuffer *fb = new_state->fb;
 190        struct drm_rect *src = &new_state->src;
 191        struct drm_rect *dst = &new_state->dst;
 192        struct drm_gem_cma_object *cma_obj;
 193        void __iomem *layer = zplane->layer;
 194        void __iomem *hbsc = zplane->hbsc;
 195        void __iomem *paddr_reg;
 196        dma_addr_t paddr;
 197        u32 src_x, src_y, src_w, src_h;
 198        u32 dst_x, dst_y, dst_w, dst_h;
 199        uint32_t format;
 200        int fmt;
 201        int i;
 202
 203        if (!fb)
 204                return;
 205
 206        format = fb->format->format;
 207
 208        src_x = src->x1 >> 16;
 209        src_y = src->y1 >> 16;
 210        src_w = drm_rect_width(src) >> 16;
 211        src_h = drm_rect_height(src) >> 16;
 212
 213        dst_x = dst->x1;
 214        dst_y = dst->y1;
 215        dst_w = drm_rect_width(dst);
 216        dst_h = drm_rect_height(dst);
 217
 218        /* Set up data address registers for Y, Cb and Cr planes */
 219        paddr_reg = layer + VL_Y;
 220        for (i = 0; i < fb->format->num_planes; i++) {
 221                cma_obj = drm_fb_cma_get_gem_obj(fb, i);
 222                paddr = cma_obj->paddr + fb->offsets[i];
 223                paddr += src_y * fb->pitches[i];
 224                paddr += src_x * fb->format->cpp[i];
 225                zx_writel(paddr_reg, paddr);
 226                paddr_reg += 4;
 227        }
 228
 229        /* Set up source height/width register */
 230        zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
 231
 232        /* Set up start position register */
 233        zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
 234
 235        /* Set up end position register */
 236        zx_writel(layer + VL_POS_END,
 237                  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
 238
 239        /* Strides of Cb and Cr planes should be identical */
 240        zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
 241                  CHROMA_STRIDE(fb->pitches[1]));
 242
 243        /* Set up video layer data format */
 244        fmt = zx_vl_get_fmt(format);
 245        if (fmt >= 0)
 246                zx_writel(layer + VL_CTRL1, fmt);
 247
 248        /* Always use scaler since it exists (set for not bypass) */
 249        zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
 250                       VL_SCALER_BYPASS_MODE);
 251
 252        zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
 253
 254        /* Enable HBSC block */
 255        zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
 256
 257        zx_vou_layer_enable(plane);
 258
 259        zx_vl_set_update(zplane);
 260}
 261
 262static void zx_plane_atomic_disable(struct drm_plane *plane,
 263                                    struct drm_atomic_state *state)
 264{
 265        struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
 266                                                                           plane);
 267        struct zx_plane *zplane = to_zx_plane(plane);
 268        void __iomem *hbsc = zplane->hbsc;
 269
 270        zx_vou_layer_disable(plane, old_state);
 271
 272        /* Disable HBSC block */
 273        zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
 274}
 275
 276static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
 277        .atomic_check = zx_vl_plane_atomic_check,
 278        .atomic_update = zx_vl_plane_atomic_update,
 279        .atomic_disable = zx_plane_atomic_disable,
 280};
 281
 282static int zx_gl_plane_atomic_check(struct drm_plane *plane,
 283                                    struct drm_atomic_state *state)
 284{
 285        struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
 286                                                                             plane);
 287        struct drm_framebuffer *fb = plane_state->fb;
 288        struct drm_crtc *crtc = plane_state->crtc;
 289        struct drm_crtc_state *crtc_state;
 290
 291        if (!crtc || WARN_ON(!fb))
 292                return 0;
 293
 294        crtc_state = drm_atomic_get_existing_crtc_state(state,
 295                                                        crtc);
 296        if (WARN_ON(!crtc_state))
 297                return -EINVAL;
 298
 299        /* nothing to check when disabling or disabled */
 300        if (!crtc_state->enable)
 301                return 0;
 302
 303        /* plane must be enabled */
 304        if (!plane_state->crtc)
 305                return -EINVAL;
 306
 307        return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
 308                                                   DRM_PLANE_HELPER_NO_SCALING,
 309                                                   DRM_PLANE_HELPER_NO_SCALING,
 310                                                   false, true);
 311}
 312
 313static int zx_gl_get_fmt(uint32_t format)
 314{
 315        switch (format) {
 316        case DRM_FORMAT_ARGB8888:
 317        case DRM_FORMAT_XRGB8888:
 318                return GL_FMT_ARGB8888;
 319        case DRM_FORMAT_RGB888:
 320                return GL_FMT_RGB888;
 321        case DRM_FORMAT_RGB565:
 322                return GL_FMT_RGB565;
 323        case DRM_FORMAT_ARGB1555:
 324                return GL_FMT_ARGB1555;
 325        case DRM_FORMAT_ARGB4444:
 326                return GL_FMT_ARGB4444;
 327        default:
 328                WARN_ONCE(1, "invalid pixel format %d\n", format);
 329                return -EINVAL;
 330        }
 331}
 332
 333static inline void zx_gl_set_update(struct zx_plane *zplane)
 334{
 335        void __iomem *layer = zplane->layer;
 336
 337        zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
 338}
 339
 340static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
 341{
 342        zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
 343}
 344
 345static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
 346                            u32 dst_w, u32 dst_h)
 347{
 348        void __iomem *rsz = zplane->rsz;
 349
 350        zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
 351        zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
 352
 353        zx_gl_rsz_set_update(zplane);
 354}
 355
 356static void zx_gl_plane_atomic_update(struct drm_plane *plane,
 357                                      struct drm_atomic_state *state)
 358{
 359        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 360                                                                           plane);
 361        struct zx_plane *zplane = to_zx_plane(plane);
 362        struct drm_framebuffer *fb = new_state->fb;
 363        struct drm_gem_cma_object *cma_obj;
 364        void __iomem *layer = zplane->layer;
 365        void __iomem *csc = zplane->csc;
 366        void __iomem *hbsc = zplane->hbsc;
 367        u32 src_x, src_y, src_w, src_h;
 368        u32 dst_x, dst_y, dst_w, dst_h;
 369        unsigned int bpp;
 370        uint32_t format;
 371        dma_addr_t paddr;
 372        u32 stride;
 373        int fmt;
 374
 375        if (!fb)
 376                return;
 377
 378        format = fb->format->format;
 379        stride = fb->pitches[0];
 380
 381        src_x = new_state->src_x >> 16;
 382        src_y = new_state->src_y >> 16;
 383        src_w = new_state->src_w >> 16;
 384        src_h = new_state->src_h >> 16;
 385
 386        dst_x = new_state->crtc_x;
 387        dst_y = new_state->crtc_y;
 388        dst_w = new_state->crtc_w;
 389        dst_h = new_state->crtc_h;
 390
 391        bpp = fb->format->cpp[0];
 392
 393        cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
 394        paddr = cma_obj->paddr + fb->offsets[0];
 395        paddr += src_y * stride + src_x * bpp / 8;
 396        zx_writel(layer + GL_ADDR, paddr);
 397
 398        /* Set up source height/width register */
 399        zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
 400
 401        /* Set up start position register */
 402        zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
 403
 404        /* Set up end position register */
 405        zx_writel(layer + GL_POS_END,
 406                  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
 407
 408        /* Set up stride register */
 409        zx_writel(layer + GL_STRIDE, stride & 0xffff);
 410
 411        /* Set up graphic layer data format */
 412        fmt = zx_gl_get_fmt(format);
 413        if (fmt >= 0)
 414                zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
 415                               fmt << GL_DATA_FMT_SHIFT);
 416
 417        /* Initialize global alpha with a sane value */
 418        zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
 419                       0xff << GL_GLOBAL_ALPHA_SHIFT);
 420
 421        /* Setup CSC for the GL */
 422        if (dst_h > 720)
 423                zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
 424                               CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
 425        else
 426                zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
 427                               CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
 428        zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
 429
 430        /* Always use scaler since it exists (set for not bypass) */
 431        zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
 432                       GL_SCALER_BYPASS_MODE);
 433
 434        zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
 435
 436        /* Enable HBSC block */
 437        zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
 438
 439        zx_vou_layer_enable(plane);
 440
 441        zx_gl_set_update(zplane);
 442}
 443
 444static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
 445        .atomic_check = zx_gl_plane_atomic_check,
 446        .atomic_update = zx_gl_plane_atomic_update,
 447        .atomic_disable = zx_plane_atomic_disable,
 448};
 449
 450static const struct drm_plane_funcs zx_plane_funcs = {
 451        .update_plane = drm_atomic_helper_update_plane,
 452        .disable_plane = drm_atomic_helper_disable_plane,
 453        .destroy = drm_plane_cleanup,
 454        .reset = drm_atomic_helper_plane_reset,
 455        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 456        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 457};
 458
 459void zx_plane_set_update(struct drm_plane *plane)
 460{
 461        struct zx_plane *zplane = to_zx_plane(plane);
 462
 463        /* Do nothing if the plane is not enabled */
 464        if (!plane->state->crtc)
 465                return;
 466
 467        switch (plane->type) {
 468        case DRM_PLANE_TYPE_PRIMARY:
 469                zx_gl_rsz_set_update(zplane);
 470                zx_gl_set_update(zplane);
 471                break;
 472        case DRM_PLANE_TYPE_OVERLAY:
 473                zx_vl_rsz_set_update(zplane);
 474                zx_vl_set_update(zplane);
 475                break;
 476        default:
 477                WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
 478        }
 479}
 480
 481static void zx_plane_hbsc_init(struct zx_plane *zplane)
 482{
 483        void __iomem *hbsc = zplane->hbsc;
 484
 485        /*
 486         *  Initialize HBSC block with a sane configuration per recommedation
 487         *  from ZTE BSP code.
 488         */
 489        zx_writel(hbsc + HBSC_SATURATION, 0x200);
 490        zx_writel(hbsc + HBSC_HUE, 0x0);
 491        zx_writel(hbsc + HBSC_BRIGHT, 0x0);
 492        zx_writel(hbsc + HBSC_CONTRAST, 0x200);
 493
 494        zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
 495        zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
 496        zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
 497}
 498
 499int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
 500                  enum drm_plane_type type)
 501{
 502        const struct drm_plane_helper_funcs *helper;
 503        struct drm_plane *plane = &zplane->plane;
 504        struct device *dev = zplane->dev;
 505        const uint32_t *formats;
 506        unsigned int format_count;
 507        int ret;
 508
 509        zx_plane_hbsc_init(zplane);
 510
 511        switch (type) {
 512        case DRM_PLANE_TYPE_PRIMARY:
 513                helper = &zx_gl_plane_helper_funcs;
 514                formats = gl_formats;
 515                format_count = ARRAY_SIZE(gl_formats);
 516                break;
 517        case DRM_PLANE_TYPE_OVERLAY:
 518                helper = &zx_vl_plane_helper_funcs;
 519                formats = vl_formats;
 520                format_count = ARRAY_SIZE(vl_formats);
 521                break;
 522        default:
 523                return -ENODEV;
 524        }
 525
 526        ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
 527                                       &zx_plane_funcs, formats, format_count,
 528                                       NULL, type, NULL);
 529        if (ret) {
 530                DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
 531                return ret;
 532        }
 533
 534        drm_plane_helper_add(plane, helper);
 535
 536        return 0;
 537}
 538