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