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 v4.2 645 lines 19 kB view raw
1/* 2 * Copyright (c) 2014 The Linux Foundation. All rights reserved. 3 * Copyright (C) 2013 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published by 8 * the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#include "mdp5_kms.h" 20 21struct mdp5_plane { 22 struct drm_plane base; 23 const char *name; 24 25 enum mdp5_pipe pipe; 26 27 spinlock_t pipe_lock; /* protect REG_MDP5_PIPE_* registers */ 28 uint32_t reg_offset; 29 30 uint32_t flush_mask; /* used to commit pipe registers */ 31 32 uint32_t nformats; 33 uint32_t formats[32]; 34}; 35#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) 36 37static int mdp5_plane_mode_set(struct drm_plane *plane, 38 struct drm_crtc *crtc, struct drm_framebuffer *fb, 39 int crtc_x, int crtc_y, 40 unsigned int crtc_w, unsigned int crtc_h, 41 uint32_t src_x, uint32_t src_y, 42 uint32_t src_w, uint32_t src_h); 43static void set_scanout_locked(struct drm_plane *plane, 44 struct drm_framebuffer *fb); 45 46static struct mdp5_kms *get_kms(struct drm_plane *plane) 47{ 48 struct msm_drm_private *priv = plane->dev->dev_private; 49 return to_mdp5_kms(to_mdp_kms(priv->kms)); 50} 51 52static bool plane_enabled(struct drm_plane_state *state) 53{ 54 return state->fb && state->crtc; 55} 56 57static void mdp5_plane_destroy(struct drm_plane *plane) 58{ 59 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 60 61 drm_plane_helper_disable(plane); 62 drm_plane_cleanup(plane); 63 64 kfree(mdp5_plane); 65} 66 67/* helper to install properties which are common to planes and crtcs */ 68void mdp5_plane_install_properties(struct drm_plane *plane, 69 struct drm_mode_object *obj) 70{ 71 // XXX 72} 73 74int mdp5_plane_set_property(struct drm_plane *plane, 75 struct drm_property *property, uint64_t val) 76{ 77 // XXX 78 return -EINVAL; 79} 80 81static void mdp5_plane_reset(struct drm_plane *plane) 82{ 83 struct mdp5_plane_state *mdp5_state; 84 85 if (plane->state && plane->state->fb) 86 drm_framebuffer_unreference(plane->state->fb); 87 88 kfree(to_mdp5_plane_state(plane->state)); 89 mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL); 90 91 if (plane->type == DRM_PLANE_TYPE_PRIMARY) { 92 mdp5_state->zpos = 0; 93 } else { 94 mdp5_state->zpos = 1 + drm_plane_index(plane); 95 } 96 mdp5_state->base.plane = plane; 97 98 plane->state = &mdp5_state->base; 99} 100 101static struct drm_plane_state * 102mdp5_plane_duplicate_state(struct drm_plane *plane) 103{ 104 struct mdp5_plane_state *mdp5_state; 105 106 if (WARN_ON(!plane->state)) 107 return NULL; 108 109 mdp5_state = kmemdup(to_mdp5_plane_state(plane->state), 110 sizeof(*mdp5_state), GFP_KERNEL); 111 112 if (mdp5_state && mdp5_state->base.fb) 113 drm_framebuffer_reference(mdp5_state->base.fb); 114 115 mdp5_state->mode_changed = false; 116 mdp5_state->pending = false; 117 118 return &mdp5_state->base; 119} 120 121static void mdp5_plane_destroy_state(struct drm_plane *plane, 122 struct drm_plane_state *state) 123{ 124 if (state->fb) 125 drm_framebuffer_unreference(state->fb); 126 127 kfree(to_mdp5_plane_state(state)); 128} 129 130static const struct drm_plane_funcs mdp5_plane_funcs = { 131 .update_plane = drm_atomic_helper_update_plane, 132 .disable_plane = drm_atomic_helper_disable_plane, 133 .destroy = mdp5_plane_destroy, 134 .set_property = mdp5_plane_set_property, 135 .reset = mdp5_plane_reset, 136 .atomic_duplicate_state = mdp5_plane_duplicate_state, 137 .atomic_destroy_state = mdp5_plane_destroy_state, 138}; 139 140static int mdp5_plane_prepare_fb(struct drm_plane *plane, 141 struct drm_framebuffer *fb, 142 const struct drm_plane_state *new_state) 143{ 144 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 145 struct mdp5_kms *mdp5_kms = get_kms(plane); 146 147 DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); 148 return msm_framebuffer_prepare(fb, mdp5_kms->id); 149} 150 151static void mdp5_plane_cleanup_fb(struct drm_plane *plane, 152 struct drm_framebuffer *fb, 153 const struct drm_plane_state *old_state) 154{ 155 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 156 struct mdp5_kms *mdp5_kms = get_kms(plane); 157 158 DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); 159 msm_framebuffer_cleanup(fb, mdp5_kms->id); 160} 161 162static int mdp5_plane_atomic_check(struct drm_plane *plane, 163 struct drm_plane_state *state) 164{ 165 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 166 struct drm_plane_state *old_state = plane->state; 167 168 DBG("%s: check (%d -> %d)", mdp5_plane->name, 169 plane_enabled(old_state), plane_enabled(state)); 170 171 if (plane_enabled(state) && plane_enabled(old_state)) { 172 /* we cannot change SMP block configuration during scanout: */ 173 bool full_modeset = false; 174 if (state->fb->pixel_format != old_state->fb->pixel_format) { 175 DBG("%s: pixel_format change!", mdp5_plane->name); 176 full_modeset = true; 177 } 178 if (state->src_w != old_state->src_w) { 179 DBG("%s: src_w change!", mdp5_plane->name); 180 full_modeset = true; 181 } 182 if (to_mdp5_plane_state(old_state)->pending) { 183 DBG("%s: still pending!", mdp5_plane->name); 184 full_modeset = true; 185 } 186 if (full_modeset) { 187 struct drm_crtc_state *crtc_state = 188 drm_atomic_get_crtc_state(state->state, state->crtc); 189 crtc_state->mode_changed = true; 190 to_mdp5_plane_state(state)->mode_changed = true; 191 } 192 } else { 193 to_mdp5_plane_state(state)->mode_changed = true; 194 } 195 196 return 0; 197} 198 199static void mdp5_plane_atomic_update(struct drm_plane *plane, 200 struct drm_plane_state *old_state) 201{ 202 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 203 struct drm_plane_state *state = plane->state; 204 205 DBG("%s: update", mdp5_plane->name); 206 207 if (!plane_enabled(state)) { 208 to_mdp5_plane_state(state)->pending = true; 209 } else if (to_mdp5_plane_state(state)->mode_changed) { 210 int ret; 211 to_mdp5_plane_state(state)->pending = true; 212 ret = mdp5_plane_mode_set(plane, 213 state->crtc, state->fb, 214 state->crtc_x, state->crtc_y, 215 state->crtc_w, state->crtc_h, 216 state->src_x, state->src_y, 217 state->src_w, state->src_h); 218 /* atomic_check should have ensured that this doesn't fail */ 219 WARN_ON(ret < 0); 220 } else { 221 unsigned long flags; 222 spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); 223 set_scanout_locked(plane, state->fb); 224 spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); 225 } 226} 227 228static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { 229 .prepare_fb = mdp5_plane_prepare_fb, 230 .cleanup_fb = mdp5_plane_cleanup_fb, 231 .atomic_check = mdp5_plane_atomic_check, 232 .atomic_update = mdp5_plane_atomic_update, 233}; 234 235static void set_scanout_locked(struct drm_plane *plane, 236 struct drm_framebuffer *fb) 237{ 238 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 239 struct mdp5_kms *mdp5_kms = get_kms(plane); 240 enum mdp5_pipe pipe = mdp5_plane->pipe; 241 242 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), 243 MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | 244 MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); 245 246 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), 247 MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | 248 MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); 249 250 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), 251 msm_framebuffer_iova(fb, mdp5_kms->id, 0)); 252 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), 253 msm_framebuffer_iova(fb, mdp5_kms->id, 1)); 254 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), 255 msm_framebuffer_iova(fb, mdp5_kms->id, 2)); 256 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), 257 msm_framebuffer_iova(fb, mdp5_kms->id, 3)); 258 259 plane->fb = fb; 260} 261 262/* Note: mdp5_plane->pipe_lock must be locked */ 263static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe) 264{ 265 uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) & 266 ~MDP5_PIPE_OP_MODE_CSC_1_EN; 267 268 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value); 269} 270 271/* Note: mdp5_plane->pipe_lock must be locked */ 272static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 273 struct csc_cfg *csc) 274{ 275 uint32_t i, mode = 0; /* RGB, no CSC */ 276 uint32_t *matrix; 277 278 if (unlikely(!csc)) 279 return; 280 281 if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type)) 282 mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV); 283 if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type)) 284 mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV); 285 mode |= MDP5_PIPE_OP_MODE_CSC_1_EN; 286 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode); 287 288 matrix = csc->matrix; 289 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe), 290 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) | 291 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1])); 292 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe), 293 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) | 294 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3])); 295 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe), 296 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) | 297 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5])); 298 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe), 299 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) | 300 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7])); 301 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe), 302 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8])); 303 304 for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) { 305 uint32_t *pre_clamp = csc->pre_clamp; 306 uint32_t *post_clamp = csc->post_clamp; 307 308 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i), 309 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) | 310 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i])); 311 312 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i), 313 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) | 314 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i])); 315 316 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i), 317 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i])); 318 319 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i), 320 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i])); 321 } 322} 323 324#define PHASE_STEP_SHIFT 21 325#define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */ 326 327static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) 328{ 329 uint32_t unit; 330 331 if (src == 0 || dst == 0) 332 return -EINVAL; 333 334 /* 335 * PHASE_STEP_X/Y is coded on 26 bits (25:0), 336 * where 2^21 represents the unity "1" in fixed-point hardware design. 337 * This leaves 5 bits for the integer part (downscale case): 338 * -> maximum downscale ratio = 0b1_1111 = 31 339 */ 340 if (src > (dst * DOWN_SCALE_RATIO_MAX)) 341 return -EOVERFLOW; 342 343 unit = 1 << PHASE_STEP_SHIFT; 344 *out_phase = mult_frac(unit, src, dst); 345 346 return 0; 347} 348 349static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, 350 uint32_t phasex_steps[2]) 351{ 352 uint32_t phasex_step; 353 unsigned int hsub; 354 int ret; 355 356 ret = calc_phase_step(src, dest, &phasex_step); 357 if (ret) 358 return ret; 359 360 hsub = drm_format_horz_chroma_subsampling(pixel_format); 361 362 phasex_steps[0] = phasex_step; 363 phasex_steps[1] = phasex_step / hsub; 364 365 return 0; 366} 367 368static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest, 369 uint32_t phasey_steps[2]) 370{ 371 uint32_t phasey_step; 372 unsigned int vsub; 373 int ret; 374 375 ret = calc_phase_step(src, dest, &phasey_step); 376 if (ret) 377 return ret; 378 379 vsub = drm_format_vert_chroma_subsampling(pixel_format); 380 381 phasey_steps[0] = phasey_step; 382 phasey_steps[1] = phasey_step / vsub; 383 384 return 0; 385} 386 387static uint32_t get_scalex_config(uint32_t src, uint32_t dest) 388{ 389 uint32_t filter; 390 391 filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 392 393 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | 394 MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) | 395 MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter) | 396 MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter); 397} 398 399static uint32_t get_scaley_config(uint32_t src, uint32_t dest) 400{ 401 uint32_t filter; 402 403 filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 404 405 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | 406 MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) | 407 MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter) | 408 MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter); 409} 410 411static int mdp5_plane_mode_set(struct drm_plane *plane, 412 struct drm_crtc *crtc, struct drm_framebuffer *fb, 413 int crtc_x, int crtc_y, 414 unsigned int crtc_w, unsigned int crtc_h, 415 uint32_t src_x, uint32_t src_y, 416 uint32_t src_w, uint32_t src_h) 417{ 418 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 419 struct mdp5_kms *mdp5_kms = get_kms(plane); 420 struct device *dev = mdp5_kms->dev->dev; 421 enum mdp5_pipe pipe = mdp5_plane->pipe; 422 const struct mdp_format *format; 423 uint32_t nplanes, config = 0; 424 /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ 425 uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; 426 uint32_t hdecm = 0, vdecm = 0; 427 uint32_t pix_format; 428 unsigned long flags; 429 int ret; 430 431 nplanes = drm_format_num_planes(fb->pixel_format); 432 433 /* bad formats should already be rejected: */ 434 if (WARN_ON(nplanes > pipe2nclients(pipe))) 435 return -EINVAL; 436 437 format = to_mdp_format(msm_framebuffer_format(fb)); 438 pix_format = format->base.pixel_format; 439 440 /* src values are in Q16 fixed point, convert to integer: */ 441 src_x = src_x >> 16; 442 src_y = src_y >> 16; 443 src_w = src_w >> 16; 444 src_h = src_h >> 16; 445 446 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, 447 fb->base.id, src_x, src_y, src_w, src_h, 448 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); 449 450 /* Request some memory from the SMP: */ 451 ret = mdp5_smp_request(mdp5_kms->smp, 452 mdp5_plane->pipe, fb->pixel_format, src_w); 453 if (ret) 454 return ret; 455 456 /* 457 * Currently we update the hw for allocations/requests immediately, 458 * but once atomic modeset/pageflip is in place, the allocation 459 * would move into atomic->check_plane_state(), while updating the 460 * hw would remain here: 461 */ 462 mdp5_smp_configure(mdp5_kms->smp, pipe); 463 464 /* SCALE is used to both scale and up-sample chroma components */ 465 466 if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) { 467 /* TODO calc hdecm */ 468 ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step); 469 if (ret) { 470 dev_err(dev, "X scaling (%d -> %d) failed: %d\n", 471 src_w, crtc_w, ret); 472 return ret; 473 } 474 config |= get_scalex_config(src_w, crtc_w); 475 } 476 477 if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) { 478 /* TODO calc vdecm */ 479 ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step); 480 if (ret) { 481 dev_err(dev, "Y scaling (%d -> %d) failed: %d\n", 482 src_h, crtc_h, ret); 483 return ret; 484 } 485 config |= get_scaley_config(src_h, crtc_h); 486 } 487 488 spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); 489 490 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), 491 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) | 492 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height)); 493 494 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), 495 MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | 496 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); 497 498 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), 499 MDP5_PIPE_SRC_XY_X(src_x) | 500 MDP5_PIPE_SRC_XY_Y(src_y)); 501 502 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), 503 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | 504 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); 505 506 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), 507 MDP5_PIPE_OUT_XY_X(crtc_x) | 508 MDP5_PIPE_OUT_XY_Y(crtc_y)); 509 510 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), 511 MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | 512 MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | 513 MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | 514 MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | 515 COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | 516 MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | 517 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | 518 COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | 519 MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) | 520 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); 521 522 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), 523 MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | 524 MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | 525 MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | 526 MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); 527 528 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), 529 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); 530 531 /* not using secure mode: */ 532 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); 533 534 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), 535 phasex_step[0]); 536 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), 537 phasey_step[0]); 538 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), 539 phasex_step[1]); 540 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), 541 phasey_step[1]); 542 mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), 543 MDP5_PIPE_DECIMATION_VERT(vdecm) | 544 MDP5_PIPE_DECIMATION_HORZ(hdecm)); 545 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config); 546 547 if (MDP_FORMAT_IS_YUV(format)) 548 csc_enable(mdp5_kms, pipe, 549 mdp_get_default_csc_cfg(CSC_YUV2RGB)); 550 else 551 csc_disable(mdp5_kms, pipe); 552 553 set_scanout_locked(plane, fb); 554 555 spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); 556 557 return ret; 558} 559 560void mdp5_plane_complete_flip(struct drm_plane *plane) 561{ 562 struct mdp5_kms *mdp5_kms = get_kms(plane); 563 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 564 enum mdp5_pipe pipe = mdp5_plane->pipe; 565 566 DBG("%s: complete flip", mdp5_plane->name); 567 568 mdp5_smp_commit(mdp5_kms->smp, pipe); 569 570 to_mdp5_plane_state(plane->state)->pending = false; 571} 572 573enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) 574{ 575 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 576 return mdp5_plane->pipe; 577} 578 579uint32_t mdp5_plane_get_flush(struct drm_plane *plane) 580{ 581 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 582 583 return mdp5_plane->flush_mask; 584} 585 586/* called after vsync in thread context */ 587void mdp5_plane_complete_commit(struct drm_plane *plane, 588 struct drm_plane_state *state) 589{ 590 struct mdp5_kms *mdp5_kms = get_kms(plane); 591 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 592 enum mdp5_pipe pipe = mdp5_plane->pipe; 593 594 if (!plane_enabled(plane->state)) { 595 DBG("%s: free SMP", mdp5_plane->name); 596 mdp5_smp_release(mdp5_kms->smp, pipe); 597 } 598} 599 600/* initialize plane */ 601struct drm_plane *mdp5_plane_init(struct drm_device *dev, 602 enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset) 603{ 604 struct drm_plane *plane = NULL; 605 struct mdp5_plane *mdp5_plane; 606 int ret; 607 enum drm_plane_type type; 608 609 mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); 610 if (!mdp5_plane) { 611 ret = -ENOMEM; 612 goto fail; 613 } 614 615 plane = &mdp5_plane->base; 616 617 mdp5_plane->pipe = pipe; 618 mdp5_plane->name = pipe2name(pipe); 619 620 mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats, 621 ARRAY_SIZE(mdp5_plane->formats)); 622 623 mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe); 624 mdp5_plane->reg_offset = reg_offset; 625 spin_lock_init(&mdp5_plane->pipe_lock); 626 627 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 628 ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, 629 mdp5_plane->formats, mdp5_plane->nformats, 630 type); 631 if (ret) 632 goto fail; 633 634 drm_plane_helper_add(plane, &mdp5_plane_helper_funcs); 635 636 mdp5_plane_install_properties(plane, &plane->base); 637 638 return plane; 639 640fail: 641 if (plane) 642 mdp5_plane_destroy(plane); 643 644 return ERR_PTR(ret); 645}