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

drm/msm/mdp5: add NV12 support for MDP5

This change adds the NV12 format support for public planes.

Signed-off-by: Stephane Viau <sviau@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Stephane Viau and committed by
Rob Clark
f8d9b515 7ca12718

+194 -21
+193 -20
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
··· 276 276 plane->fb = fb; 277 277 } 278 278 279 + /* Note: mdp5_plane->pipe_lock must be locked */ 280 + static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe) 281 + { 282 + uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) & 283 + ~MDP5_PIPE_OP_MODE_CSC_1_EN; 284 + 285 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value); 286 + } 287 + 288 + /* Note: mdp5_plane->pipe_lock must be locked */ 289 + static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 290 + struct csc_cfg *csc) 291 + { 292 + uint32_t i, mode = 0; /* RGB, no CSC */ 293 + uint32_t *matrix; 294 + 295 + if (unlikely(!csc)) 296 + return; 297 + 298 + if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type)) 299 + mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV); 300 + if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type)) 301 + mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV); 302 + mode |= MDP5_PIPE_OP_MODE_CSC_1_EN; 303 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode); 304 + 305 + matrix = csc->matrix; 306 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe), 307 + MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) | 308 + MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1])); 309 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe), 310 + MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) | 311 + MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3])); 312 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe), 313 + MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) | 314 + MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5])); 315 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe), 316 + MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) | 317 + MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7])); 318 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe), 319 + MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8])); 320 + 321 + for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) { 322 + uint32_t *pre_clamp = csc->pre_clamp; 323 + uint32_t *post_clamp = csc->post_clamp; 324 + 325 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i), 326 + MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) | 327 + MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i])); 328 + 329 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i), 330 + MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) | 331 + MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i])); 332 + 333 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i), 334 + MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i])); 335 + 336 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i), 337 + MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i])); 338 + } 339 + } 340 + 341 + #define PHASE_STEP_SHIFT 21 342 + #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */ 343 + 344 + static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) 345 + { 346 + uint32_t unit; 347 + 348 + if (src == 0 || dst == 0) 349 + return -EINVAL; 350 + 351 + /* 352 + * PHASE_STEP_X/Y is coded on 26 bits (25:0), 353 + * where 2^21 represents the unity "1" in fixed-point hardware design. 354 + * This leaves 5 bits for the integer part (downscale case): 355 + * -> maximum downscale ratio = 0b1_1111 = 31 356 + */ 357 + if (src > (dst * DOWN_SCALE_RATIO_MAX)) 358 + return -EOVERFLOW; 359 + 360 + unit = 1 << PHASE_STEP_SHIFT; 361 + *out_phase = mult_frac(unit, src, dst); 362 + 363 + return 0; 364 + } 365 + 366 + static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, 367 + uint32_t phasex_steps[2]) 368 + { 369 + uint32_t phasex_step; 370 + unsigned int hsub; 371 + int ret; 372 + 373 + ret = calc_phase_step(src, dest, &phasex_step); 374 + if (ret) 375 + return ret; 376 + 377 + hsub = drm_format_horz_chroma_subsampling(pixel_format); 378 + 379 + phasex_steps[0] = phasex_step; 380 + phasex_steps[1] = phasex_step / hsub; 381 + 382 + return 0; 383 + } 384 + 385 + static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, 386 + uint32_t phasey_steps[2]) 387 + { 388 + uint32_t phasey_step; 389 + unsigned int vsub; 390 + int ret; 391 + 392 + ret = calc_phase_step(src, dest, &phasey_step); 393 + if (ret) 394 + return ret; 395 + 396 + vsub = drm_format_vert_chroma_subsampling(pixel_format); 397 + 398 + phasey_steps[0] = phasey_step; 399 + phasey_steps[1] = phasey_step / vsub; 400 + 401 + return 0; 402 + } 403 + 404 + static uint32_t get_scalex_config(uint32_t src, uint32_t dest) 405 + { 406 + uint32_t filter; 407 + 408 + filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 409 + 410 + return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | 411 + MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) | 412 + MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter) | 413 + MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter); 414 + } 415 + 416 + static uint32_t get_scaley_config(uint32_t src, uint32_t dest) 417 + { 418 + uint32_t filter; 419 + 420 + filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 421 + 422 + return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | 423 + MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) | 424 + MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter) | 425 + MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter); 426 + } 427 + 279 428 static int mdp5_plane_mode_set(struct drm_plane *plane, 280 429 struct drm_crtc *crtc, struct drm_framebuffer *fb, 281 430 int crtc_x, int crtc_y, ··· 434 285 { 435 286 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 436 287 struct mdp5_kms *mdp5_kms = get_kms(plane); 288 + struct device *dev = mdp5_kms->dev->dev; 437 289 enum mdp5_pipe pipe = mdp5_plane->pipe; 438 290 const struct mdp_format *format; 439 291 uint32_t nplanes, config = 0; 440 - uint32_t phasex_step = 0, phasey_step = 0; 292 + /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ 293 + uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; 441 294 uint32_t hdecm = 0, vdecm = 0; 295 + uint32_t pix_format; 442 296 unsigned long flags; 443 297 int ret; 444 298 ··· 450 298 /* bad formats should already be rejected: */ 451 299 if (WARN_ON(nplanes > pipe2nclients(pipe))) 452 300 return -EINVAL; 301 + 302 + format = to_mdp_format(msm_framebuffer_format(fb)); 303 + pix_format = format->base.pixel_format; 453 304 454 305 /* src values are in Q16 fixed point, convert to integer: */ 455 306 src_x = src_x >> 16; ··· 478 323 */ 479 324 mdp5_smp_configure(mdp5_kms->smp, pipe); 480 325 481 - if (src_w != crtc_w) { 482 - config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; 483 - /* TODO calc phasex_step, hdecm */ 326 + /* SCALE is used to both scale and up-sample chroma components */ 327 + 328 + if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) { 329 + /* TODO calc hdecm */ 330 + ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step); 331 + if (ret) { 332 + dev_err(dev, "X scaling (%d -> %d) failed: %d\n", 333 + src_w, crtc_w, ret); 334 + return ret; 335 + } 336 + config |= get_scalex_config(src_w, crtc_w); 484 337 } 485 338 486 - if (src_h != crtc_h) { 487 - config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; 488 - /* TODO calc phasey_step, vdecm */ 339 + if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) { 340 + /* TODO calc vdecm */ 341 + ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step); 342 + if (ret) { 343 + dev_err(dev, "Y scaling (%d -> %d) failed: %d\n", 344 + src_h, crtc_h, ret); 345 + return ret; 346 + } 347 + config |= get_scaley_config(src_h, crtc_h); 489 348 } 490 349 491 350 spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); ··· 524 355 MDP5_PIPE_OUT_XY_X(crtc_x) | 525 356 MDP5_PIPE_OUT_XY_Y(crtc_y)); 526 357 527 - format = to_mdp_format(msm_framebuffer_format(fb)); 528 - 529 358 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), 530 359 MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | 531 360 MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | ··· 533 366 MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | 534 367 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | 535 368 COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | 536 - MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | 537 - MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); 369 + MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) | 370 + MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); 538 371 539 372 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), 540 373 MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | ··· 548 381 /* not using secure mode: */ 549 382 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); 550 383 551 - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); 552 - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); 384 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), 385 + phasex_step[0]); 386 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), 387 + phasey_step[0]); 388 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), 389 + phasex_step[1]); 390 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), 391 + phasey_step[1]); 553 392 mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), 554 393 MDP5_PIPE_DECIMATION_VERT(vdecm) | 555 394 MDP5_PIPE_DECIMATION_HORZ(hdecm)); 556 - mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), 557 - MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | 558 - MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | 559 - MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | 560 - MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | 561 - MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | 562 - MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); 395 + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config); 396 + 397 + if (MDP_FORMAT_IS_YUV(format)) 398 + csc_enable(mdp5_kms, pipe, 399 + mdp_get_default_csc_cfg(CSC_YUV2RGB)); 400 + else 401 + csc_disable(mdp5_kms, pipe); 563 402 564 403 set_scanout_locked(plane, fb); 565 404
+1 -1
drivers/gpu/drm/msm/msm_fb.c
··· 122 122 struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); 123 123 if (!msm_fb->planes[plane]) 124 124 return 0; 125 - return msm_gem_iova(msm_fb->planes[plane], id); 125 + return msm_gem_iova(msm_fb->planes[plane], id) + fb->offsets[plane]; 126 126 } 127 127 128 128 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)