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