Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.12-rc5 528 lines 14 kB view raw
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_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 || WARN_ON(!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 78static 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 101static 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 108static inline void zx_vl_rsz_set_update(struct zx_plane *zplane) 109{ 110 zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1); 111} 112 113static 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 132static 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 147static 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 181static 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 259static 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 271static 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 277static 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 || WARN_ON(!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 306static 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 326static 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 333static inline void zx_gl_rsz_set_update(struct zx_plane *zplane) 334{ 335 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); 336} 337 338static 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 349static 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 435static 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 441static const struct drm_plane_funcs zx_plane_funcs = { 442 .update_plane = drm_atomic_helper_update_plane, 443 .disable_plane = drm_atomic_helper_disable_plane, 444 .destroy = drm_plane_cleanup, 445 .reset = drm_atomic_helper_plane_reset, 446 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 447 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 448}; 449 450void zx_plane_set_update(struct drm_plane *plane) 451{ 452 struct zx_plane *zplane = to_zx_plane(plane); 453 454 /* Do nothing if the plane is not enabled */ 455 if (!plane->state->crtc) 456 return; 457 458 switch (plane->type) { 459 case DRM_PLANE_TYPE_PRIMARY: 460 zx_gl_rsz_set_update(zplane); 461 zx_gl_set_update(zplane); 462 break; 463 case DRM_PLANE_TYPE_OVERLAY: 464 zx_vl_rsz_set_update(zplane); 465 zx_vl_set_update(zplane); 466 break; 467 default: 468 WARN_ONCE(1, "unsupported plane type %d\n", plane->type); 469 } 470} 471 472static void zx_plane_hbsc_init(struct zx_plane *zplane) 473{ 474 void __iomem *hbsc = zplane->hbsc; 475 476 /* 477 * Initialize HBSC block with a sane configuration per recommedation 478 * from ZTE BSP code. 479 */ 480 zx_writel(hbsc + HBSC_SATURATION, 0x200); 481 zx_writel(hbsc + HBSC_HUE, 0x0); 482 zx_writel(hbsc + HBSC_BRIGHT, 0x0); 483 zx_writel(hbsc + HBSC_CONTRAST, 0x200); 484 485 zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40); 486 zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40); 487 zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40); 488} 489 490int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane, 491 enum drm_plane_type type) 492{ 493 const struct drm_plane_helper_funcs *helper; 494 struct drm_plane *plane = &zplane->plane; 495 struct device *dev = zplane->dev; 496 const uint32_t *formats; 497 unsigned int format_count; 498 int ret; 499 500 zx_plane_hbsc_init(zplane); 501 502 switch (type) { 503 case DRM_PLANE_TYPE_PRIMARY: 504 helper = &zx_gl_plane_helper_funcs; 505 formats = gl_formats; 506 format_count = ARRAY_SIZE(gl_formats); 507 break; 508 case DRM_PLANE_TYPE_OVERLAY: 509 helper = &zx_vl_plane_helper_funcs; 510 formats = vl_formats; 511 format_count = ARRAY_SIZE(vl_formats); 512 break; 513 default: 514 return -ENODEV; 515 } 516 517 ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK, 518 &zx_plane_funcs, formats, format_count, 519 NULL, type, NULL); 520 if (ret) { 521 DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret); 522 return ret; 523 } 524 525 drm_plane_helper_add(plane, helper); 526 527 return 0; 528}