diff options
author | Stephane Viau <sviau@codeaurora.org> | 2014-12-08 10:48:58 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2015-02-01 15:30:35 -0500 |
commit | f8d9b5156e966e701cb17c623ffd6ebe35cc3157 (patch) | |
tree | 0e33d69578018f8eb3fbda70d8e8b50ff94f05b6 | |
parent | 7ca12718b393a6b71fc62782a64737b5c9dc6d3c (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 213 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_fb.c | 2 |
2 files changed, 194 insertions, 21 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 0b2416e77d27..05cf9ab2a876 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
@@ -276,6 +276,155 @@ static void set_scanout_locked(struct drm_plane *plane, | |||
276 | plane->fb = fb; | 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 | static int mdp5_plane_mode_set(struct drm_plane *plane, | 428 | static int mdp5_plane_mode_set(struct drm_plane *plane, |
280 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | 429 | struct drm_crtc *crtc, struct drm_framebuffer *fb, |
281 | int crtc_x, int crtc_y, | 430 | int crtc_x, int crtc_y, |
@@ -285,11 +434,14 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
285 | { | 434 | { |
286 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | 435 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
287 | struct mdp5_kms *mdp5_kms = get_kms(plane); | 436 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
437 | struct device *dev = mdp5_kms->dev->dev; | ||
288 | enum mdp5_pipe pipe = mdp5_plane->pipe; | 438 | enum mdp5_pipe pipe = mdp5_plane->pipe; |
289 | const struct mdp_format *format; | 439 | const struct mdp_format *format; |
290 | uint32_t nplanes, config = 0; | 440 | uint32_t nplanes, config = 0; |
291 | uint32_t phasex_step = 0, phasey_step = 0; | 441 | /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ |
442 | uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; | ||
292 | uint32_t hdecm = 0, vdecm = 0; | 443 | uint32_t hdecm = 0, vdecm = 0; |
444 | uint32_t pix_format; | ||
293 | unsigned long flags; | 445 | unsigned long flags; |
294 | int ret; | 446 | int ret; |
295 | 447 | ||
@@ -299,6 +451,9 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
299 | if (WARN_ON(nplanes > pipe2nclients(pipe))) | 451 | if (WARN_ON(nplanes > pipe2nclients(pipe))) |
300 | return -EINVAL; | 452 | return -EINVAL; |
301 | 453 | ||
454 | format = to_mdp_format(msm_framebuffer_format(fb)); | ||
455 | pix_format = format->base.pixel_format; | ||
456 | |||
302 | /* src values are in Q16 fixed point, convert to integer: */ | 457 | /* src values are in Q16 fixed point, convert to integer: */ |
303 | src_x = src_x >> 16; | 458 | src_x = src_x >> 16; |
304 | src_y = src_y >> 16; | 459 | src_y = src_y >> 16; |
@@ -323,14 +478,28 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
323 | */ | 478 | */ |
324 | mdp5_smp_configure(mdp5_kms->smp, pipe); | 479 | mdp5_smp_configure(mdp5_kms->smp, pipe); |
325 | 480 | ||
326 | if (src_w != crtc_w) { | 481 | /* SCALE is used to both scale and up-sample chroma components */ |
327 | config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; | 482 | |
328 | /* TODO calc phasex_step, hdecm */ | 483 | if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) { |
484 | /* TODO calc hdecm */ | ||
485 | ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step); | ||
486 | if (ret) { | ||
487 | dev_err(dev, "X scaling (%d -> %d) failed: %d\n", | ||
488 | src_w, crtc_w, ret); | ||
489 | return ret; | ||
490 | } | ||
491 | config |= get_scalex_config(src_w, crtc_w); | ||
329 | } | 492 | } |
330 | 493 | ||
331 | if (src_h != crtc_h) { | 494 | if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) { |
332 | config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; | 495 | /* TODO calc vdecm */ |
333 | /* TODO calc phasey_step, vdecm */ | 496 | ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step); |
497 | if (ret) { | ||
498 | dev_err(dev, "Y scaling (%d -> %d) failed: %d\n", | ||
499 | src_h, crtc_h, ret); | ||
500 | return ret; | ||
501 | } | ||
502 | config |= get_scaley_config(src_h, crtc_h); | ||
334 | } | 503 | } |
335 | 504 | ||
336 | spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); | 505 | spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); |
@@ -355,8 +524,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
355 | MDP5_PIPE_OUT_XY_X(crtc_x) | | 524 | MDP5_PIPE_OUT_XY_X(crtc_x) | |
356 | MDP5_PIPE_OUT_XY_Y(crtc_y)); | 525 | MDP5_PIPE_OUT_XY_Y(crtc_y)); |
357 | 526 | ||
358 | format = to_mdp_format(msm_framebuffer_format(fb)); | ||
359 | |||
360 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), | 527 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), |
361 | MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | | 528 | MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | |
362 | MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | | 529 | MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | |
@@ -366,8 +533,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
366 | MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | | 533 | MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | |
367 | MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | | 534 | MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | |
368 | COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | | 535 | COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | |
369 | MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | | 536 | MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) | |
370 | MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); | 537 | MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); |
371 | 538 | ||
372 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), | 539 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), |
373 | MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | | 540 | MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | |
@@ -381,18 +548,24 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, | |||
381 | /* not using secure mode: */ | 548 | /* not using secure mode: */ |
382 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); | 549 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); |
383 | 550 | ||
384 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); | 551 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), |
385 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); | 552 | phasex_step[0]); |
553 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), | ||
554 | phasey_step[0]); | ||
555 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), | ||
556 | phasex_step[1]); | ||
557 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), | ||
558 | phasey_step[1]); | ||
386 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), | 559 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), |
387 | MDP5_PIPE_DECIMATION_VERT(vdecm) | | 560 | MDP5_PIPE_DECIMATION_VERT(vdecm) | |
388 | MDP5_PIPE_DECIMATION_HORZ(hdecm)); | 561 | MDP5_PIPE_DECIMATION_HORZ(hdecm)); |
389 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), | 562 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config); |
390 | MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | | 563 | |
391 | MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | | 564 | if (MDP_FORMAT_IS_YUV(format)) |
392 | MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | | 565 | csc_enable(mdp5_kms, pipe, |
393 | MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | | 566 | mdp_get_default_csc_cfg(CSC_YUV2RGB)); |
394 | MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | | 567 | else |
395 | MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); | 568 | csc_disable(mdp5_kms, pipe); |
396 | 569 | ||
397 | set_scanout_locked(plane, fb); | 570 | set_scanout_locked(plane, fb); |
398 | 571 | ||
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index d1a7a45091df..6b573e612f27 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c | |||
@@ -122,7 +122,7 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane) | |||
122 | struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); | 122 | struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); |
123 | if (!msm_fb->planes[plane]) | 123 | if (!msm_fb->planes[plane]) |
124 | return 0; | 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 | struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) | 128 | struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) |