root/drivers/gpu/drm/zte/zx_plane.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zx_vl_plane_atomic_check
  2. zx_vl_get_fmt
  3. zx_vl_set_update
  4. zx_vl_rsz_set_update
  5. zx_vl_rsz_get_fmt
  6. rsz_step_value
  7. zx_vl_rsz_setup
  8. zx_vl_plane_atomic_update
  9. zx_plane_atomic_disable
  10. zx_gl_plane_atomic_check
  11. zx_gl_get_fmt
  12. zx_gl_set_update
  13. zx_gl_rsz_set_update
  14. zx_gl_rsz_setup
  15. zx_gl_plane_atomic_update
  16. zx_plane_destroy
  17. zx_plane_set_update
  18. zx_plane_hbsc_init
  19. zx_plane_init

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

/* [<][>][^][v][top][bottom][index][help] */