1 /* 2 * Copyright (C) 2014-2015 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 <drm/drm_print.h> 20 #include "mdp5_kms.h" 21 22 struct mdp5_plane { 23 struct drm_plane base; 24 25 uint32_t nformats; 26 uint32_t formats[32]; 27 }; 28 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) 29 30 static int mdp5_plane_mode_set(struct drm_plane *plane, 31 struct drm_crtc *crtc, struct drm_framebuffer *fb, 32 struct drm_rect *src, struct drm_rect *dest); 33 34 static struct mdp5_kms *get_kms(struct drm_plane *plane) 35 { 36 struct msm_drm_private *priv = plane->dev->dev_private; 37 return to_mdp5_kms(to_mdp_kms(priv->kms)); 38 } 39 40 static bool plane_enabled(struct drm_plane_state *state) 41 { 42 return state->visible; 43 } 44 45 static void mdp5_plane_destroy(struct drm_plane *plane) 46 { 47 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 48 49 drm_plane_helper_disable(plane); 50 drm_plane_cleanup(plane); 51 52 kfree(mdp5_plane); 53 } 54 55 static void mdp5_plane_install_rotation_property(struct drm_device *dev, 56 struct drm_plane *plane) 57 { 58 drm_plane_create_rotation_property(plane, 59 DRM_MODE_ROTATE_0, 60 DRM_MODE_ROTATE_0 | 61 DRM_MODE_ROTATE_180 | 62 DRM_MODE_REFLECT_X | 63 DRM_MODE_REFLECT_Y); 64 } 65 66 /* helper to install properties which are common to planes and crtcs */ 67 static void mdp5_plane_install_properties(struct drm_plane *plane, 68 struct drm_mode_object *obj) 69 { 70 struct drm_device *dev = plane->dev; 71 struct msm_drm_private *dev_priv = dev->dev_private; 72 struct drm_property *prop; 73 74 #define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \ 75 prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \ 76 if (!prop) { \ 77 prop = drm_property_##fnc(dev, 0, #name, \ 78 ##__VA_ARGS__); \ 79 if (!prop) { \ 80 dev_warn(dev->dev, \ 81 "Create property %s failed\n", \ 82 #name); \ 83 return; \ 84 } \ 85 dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \ 86 } \ 87 drm_object_attach_property(&plane->base, prop, init_val); \ 88 } while (0) 89 90 #define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \ 91 INSTALL_PROPERTY(name, NAME, init_val, \ 92 create_range, min, max) 93 94 #define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \ 95 INSTALL_PROPERTY(name, NAME, init_val, \ 96 create_enum, name##_prop_enum_list, \ 97 ARRAY_SIZE(name##_prop_enum_list)) 98 99 INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1); 100 101 mdp5_plane_install_rotation_property(dev, plane); 102 103 #undef INSTALL_RANGE_PROPERTY 104 #undef INSTALL_ENUM_PROPERTY 105 #undef INSTALL_PROPERTY 106 } 107 108 static int mdp5_plane_atomic_set_property(struct drm_plane *plane, 109 struct drm_plane_state *state, struct drm_property *property, 110 uint64_t val) 111 { 112 struct drm_device *dev = plane->dev; 113 struct mdp5_plane_state *pstate; 114 struct msm_drm_private *dev_priv = dev->dev_private; 115 int ret = 0; 116 117 pstate = to_mdp5_plane_state(state); 118 119 #define SET_PROPERTY(name, NAME, type) do { \ 120 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ 121 pstate->name = (type)val; \ 122 DBG("Set property %s %d", #name, (type)val); \ 123 goto done; \ 124 } \ 125 } while (0) 126 127 SET_PROPERTY(zpos, ZPOS, uint8_t); 128 129 dev_err(dev->dev, "Invalid property\n"); 130 ret = -EINVAL; 131 done: 132 return ret; 133 #undef SET_PROPERTY 134 } 135 136 static int mdp5_plane_atomic_get_property(struct drm_plane *plane, 137 const struct drm_plane_state *state, 138 struct drm_property *property, uint64_t *val) 139 { 140 struct drm_device *dev = plane->dev; 141 struct mdp5_plane_state *pstate; 142 struct msm_drm_private *dev_priv = dev->dev_private; 143 int ret = 0; 144 145 pstate = to_mdp5_plane_state(state); 146 147 #define GET_PROPERTY(name, NAME, type) do { \ 148 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ 149 *val = pstate->name; \ 150 DBG("Get property %s %lld", #name, *val); \ 151 goto done; \ 152 } \ 153 } while (0) 154 155 GET_PROPERTY(zpos, ZPOS, uint8_t); 156 157 dev_err(dev->dev, "Invalid property\n"); 158 ret = -EINVAL; 159 done: 160 return ret; 161 #undef SET_PROPERTY 162 } 163 164 static void 165 mdp5_plane_atomic_print_state(struct drm_printer *p, 166 const struct drm_plane_state *state) 167 { 168 struct mdp5_plane_state *pstate = to_mdp5_plane_state(state); 169 struct mdp5_kms *mdp5_kms = get_kms(state->plane); 170 171 drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ? 172 pstate->hwpipe->name : "(null)"); 173 if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT) 174 drm_printf(p, "\tright-hwpipe=%s\n", 175 pstate->r_hwpipe ? pstate->r_hwpipe->name : 176 "(null)"); 177 drm_printf(p, "\tpremultiplied=%u\n", pstate->premultiplied); 178 drm_printf(p, "\tzpos=%u\n", pstate->zpos); 179 drm_printf(p, "\talpha=%u\n", pstate->alpha); 180 drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage)); 181 } 182 183 static void mdp5_plane_reset(struct drm_plane *plane) 184 { 185 struct mdp5_plane_state *mdp5_state; 186 187 if (plane->state && plane->state->fb) 188 drm_framebuffer_unreference(plane->state->fb); 189 190 kfree(to_mdp5_plane_state(plane->state)); 191 mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL); 192 193 /* assign default blend parameters */ 194 mdp5_state->alpha = 255; 195 mdp5_state->premultiplied = 0; 196 197 if (plane->type == DRM_PLANE_TYPE_PRIMARY) 198 mdp5_state->zpos = STAGE_BASE; 199 else 200 mdp5_state->zpos = STAGE0 + drm_plane_index(plane); 201 202 mdp5_state->base.plane = plane; 203 204 plane->state = &mdp5_state->base; 205 } 206 207 static struct drm_plane_state * 208 mdp5_plane_duplicate_state(struct drm_plane *plane) 209 { 210 struct mdp5_plane_state *mdp5_state; 211 212 if (WARN_ON(!plane->state)) 213 return NULL; 214 215 mdp5_state = kmemdup(to_mdp5_plane_state(plane->state), 216 sizeof(*mdp5_state), GFP_KERNEL); 217 if (!mdp5_state) 218 return NULL; 219 220 __drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base); 221 222 return &mdp5_state->base; 223 } 224 225 static void mdp5_plane_destroy_state(struct drm_plane *plane, 226 struct drm_plane_state *state) 227 { 228 struct mdp5_plane_state *pstate = to_mdp5_plane_state(state); 229 230 if (state->fb) 231 drm_framebuffer_unreference(state->fb); 232 233 kfree(pstate); 234 } 235 236 static const struct drm_plane_funcs mdp5_plane_funcs = { 237 .update_plane = drm_atomic_helper_update_plane, 238 .disable_plane = drm_atomic_helper_disable_plane, 239 .destroy = mdp5_plane_destroy, 240 .atomic_set_property = mdp5_plane_atomic_set_property, 241 .atomic_get_property = mdp5_plane_atomic_get_property, 242 .reset = mdp5_plane_reset, 243 .atomic_duplicate_state = mdp5_plane_duplicate_state, 244 .atomic_destroy_state = mdp5_plane_destroy_state, 245 .atomic_print_state = mdp5_plane_atomic_print_state, 246 }; 247 248 static int mdp5_plane_prepare_fb(struct drm_plane *plane, 249 struct drm_plane_state *new_state) 250 { 251 struct mdp5_kms *mdp5_kms = get_kms(plane); 252 struct msm_kms *kms = &mdp5_kms->base.base; 253 struct drm_framebuffer *fb = new_state->fb; 254 255 if (!new_state->fb) 256 return 0; 257 258 DBG("%s: prepare: FB[%u]", plane->name, fb->base.id); 259 return msm_framebuffer_prepare(fb, kms->aspace); 260 } 261 262 static void mdp5_plane_cleanup_fb(struct drm_plane *plane, 263 struct drm_plane_state *old_state) 264 { 265 struct mdp5_kms *mdp5_kms = get_kms(plane); 266 struct msm_kms *kms = &mdp5_kms->base.base; 267 struct drm_framebuffer *fb = old_state->fb; 268 269 if (!fb) 270 return; 271 272 DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id); 273 msm_framebuffer_cleanup(fb, kms->aspace); 274 } 275 276 #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 277 static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, 278 struct drm_plane_state *state) 279 { 280 struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); 281 struct drm_plane *plane = state->plane; 282 struct drm_plane_state *old_state = plane->state; 283 struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg); 284 bool new_hwpipe = false; 285 bool need_right_hwpipe = false; 286 uint32_t max_width, max_height; 287 bool out_of_bounds = false; 288 uint32_t caps = 0; 289 int min_scale, max_scale; 290 int ret; 291 292 DBG("%s: check (%d -> %d)", plane->name, 293 plane_enabled(old_state), plane_enabled(state)); 294 295 max_width = config->hw->lm.max_width << 16; 296 max_height = config->hw->lm.max_height << 16; 297 298 /* Make sure source dimensions are within bounds. */ 299 if (state->src_h > max_height) 300 out_of_bounds = true; 301 302 if (state->src_w > max_width) { 303 /* If source split is supported, we can go up to 2x 304 * the max LM width, but we'd need to stage another 305 * hwpipe to the right LM. So, the drm_plane would 306 * consist of 2 hwpipes. 307 */ 308 if (config->hw->mdp.caps & MDP_CAP_SRC_SPLIT && 309 (state->src_w <= 2 * max_width)) 310 need_right_hwpipe = true; 311 else 312 out_of_bounds = true; 313 } 314 315 if (out_of_bounds) { 316 struct drm_rect src = drm_plane_state_src(state); 317 DBG("Invalid source size "DRM_RECT_FP_FMT, 318 DRM_RECT_FP_ARG(&src)); 319 return -ERANGE; 320 } 321 322 min_scale = FRAC_16_16(1, 8); 323 max_scale = FRAC_16_16(8, 1); 324 325 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 326 min_scale, max_scale, 327 true, true); 328 if (ret) 329 return ret; 330 331 if (plane_enabled(state)) { 332 unsigned int rotation; 333 const struct mdp_format *format; 334 struct mdp5_kms *mdp5_kms = get_kms(plane); 335 uint32_t blkcfg = 0; 336 337 format = to_mdp_format(msm_framebuffer_format(state->fb)); 338 if (MDP_FORMAT_IS_YUV(format)) 339 caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC; 340 341 if (((state->src_w >> 16) != state->crtc_w) || 342 ((state->src_h >> 16) != state->crtc_h)) 343 caps |= MDP_PIPE_CAP_SCALE; 344 345 rotation = drm_rotation_simplify(state->rotation, 346 DRM_MODE_ROTATE_0 | 347 DRM_MODE_REFLECT_X | 348 DRM_MODE_REFLECT_Y); 349 350 if (rotation & DRM_MODE_REFLECT_X) 351 caps |= MDP_PIPE_CAP_HFLIP; 352 353 if (rotation & DRM_MODE_REFLECT_Y) 354 caps |= MDP_PIPE_CAP_VFLIP; 355 356 if (plane->type == DRM_PLANE_TYPE_CURSOR) 357 caps |= MDP_PIPE_CAP_CURSOR; 358 359 /* (re)allocate hw pipe if we don't have one or caps-mismatch: */ 360 if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps)) 361 new_hwpipe = true; 362 363 /* 364 * (re)allocte hw pipe if we're either requesting for 2 hw pipes 365 * or we're switching from 2 hw pipes to 1 hw pipe because the 366 * new src_w can be supported by 1 hw pipe itself. 367 */ 368 if ((need_right_hwpipe && !mdp5_state->r_hwpipe) || 369 (!need_right_hwpipe && mdp5_state->r_hwpipe)) 370 new_hwpipe = true; 371 372 if (mdp5_kms->smp) { 373 const struct mdp_format *format = 374 to_mdp_format(msm_framebuffer_format(state->fb)); 375 376 blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format, 377 state->src_w >> 16, false); 378 379 if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg)) 380 new_hwpipe = true; 381 } 382 383 /* (re)assign hwpipe if needed, otherwise keep old one: */ 384 if (new_hwpipe) { 385 /* TODO maybe we want to re-assign hwpipe sometimes 386 * in cases when we no-longer need some caps to make 387 * it available for other planes? 388 */ 389 struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe; 390 struct mdp5_hw_pipe *old_right_hwpipe = 391 mdp5_state->r_hwpipe; 392 struct mdp5_hw_pipe *new_hwpipe = NULL; 393 struct mdp5_hw_pipe *new_right_hwpipe = NULL; 394 395 ret = mdp5_pipe_assign(state->state, plane, caps, 396 blkcfg, &new_hwpipe, 397 need_right_hwpipe ? 398 &new_right_hwpipe : NULL); 399 if (ret) { 400 DBG("%s: failed to assign hwpipe(s)!", 401 plane->name); 402 return ret; 403 } 404 405 mdp5_state->hwpipe = new_hwpipe; 406 if (need_right_hwpipe) 407 mdp5_state->r_hwpipe = new_right_hwpipe; 408 else 409 /* 410 * set it to NULL so that the driver knows we 411 * don't have a right hwpipe when committing a 412 * new state 413 */ 414 mdp5_state->r_hwpipe = NULL; 415 416 417 mdp5_pipe_release(state->state, old_hwpipe); 418 mdp5_pipe_release(state->state, old_right_hwpipe); 419 } 420 } else { 421 mdp5_pipe_release(state->state, mdp5_state->hwpipe); 422 mdp5_pipe_release(state->state, mdp5_state->r_hwpipe); 423 mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL; 424 } 425 426 return 0; 427 } 428 429 static int mdp5_plane_atomic_check(struct drm_plane *plane, 430 struct drm_plane_state *state) 431 { 432 struct drm_crtc *crtc; 433 struct drm_crtc_state *crtc_state; 434 435 crtc = state->crtc ? state->crtc : plane->state->crtc; 436 if (!crtc) 437 return 0; 438 439 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); 440 if (WARN_ON(!crtc_state)) 441 return -EINVAL; 442 443 return mdp5_plane_atomic_check_with_state(crtc_state, state); 444 } 445 446 static void mdp5_plane_atomic_update(struct drm_plane *plane, 447 struct drm_plane_state *old_state) 448 { 449 struct drm_plane_state *state = plane->state; 450 451 DBG("%s: update", plane->name); 452 453 if (plane_enabled(state)) { 454 int ret; 455 456 ret = mdp5_plane_mode_set(plane, 457 state->crtc, state->fb, 458 &state->src, &state->dst); 459 /* atomic_check should have ensured that this doesn't fail */ 460 WARN_ON(ret < 0); 461 } 462 } 463 464 static int mdp5_plane_atomic_async_check(struct drm_plane *plane, 465 struct drm_plane_state *state) 466 { 467 struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); 468 struct drm_crtc_state *crtc_state; 469 int min_scale, max_scale; 470 int ret; 471 472 crtc_state = drm_atomic_get_existing_crtc_state(state->state, 473 state->crtc); 474 if (WARN_ON(!crtc_state)) 475 return -EINVAL; 476 477 if (!crtc_state->active) 478 return -EINVAL; 479 480 mdp5_state = to_mdp5_plane_state(state); 481 482 /* don't use fast path if we don't have a hwpipe allocated yet */ 483 if (!mdp5_state->hwpipe) 484 return -EINVAL; 485 486 /* only allow changing of position(crtc x/y or src x/y) in fast path */ 487 if (plane->state->crtc != state->crtc || 488 plane->state->src_w != state->src_w || 489 plane->state->src_h != state->src_h || 490 plane->state->crtc_w != state->crtc_w || 491 plane->state->crtc_h != state->crtc_h || 492 !plane->state->fb || 493 plane->state->fb != state->fb) 494 return -EINVAL; 495 496 min_scale = FRAC_16_16(1, 8); 497 max_scale = FRAC_16_16(8, 1); 498 499 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 500 min_scale, max_scale, 501 true, true); 502 if (ret) 503 return ret; 504 505 /* 506 * if the visibility of the plane changes (i.e, if the cursor is 507 * clipped out completely, we can't take the async path because 508 * we need to stage/unstage the plane from the Layer Mixer(s). We 509 * also assign/unassign the hwpipe(s) tied to the plane. We avoid 510 * taking the fast path for both these reasons. 511 */ 512 if (state->visible != plane->state->visible) 513 return -EINVAL; 514 515 return 0; 516 } 517 518 static void mdp5_plane_atomic_async_update(struct drm_plane *plane, 519 struct drm_plane_state *new_state) 520 { 521 plane->state->src_x = new_state->src_x; 522 plane->state->src_y = new_state->src_y; 523 plane->state->crtc_x = new_state->crtc_x; 524 plane->state->crtc_y = new_state->crtc_y; 525 526 if (plane_enabled(new_state)) { 527 struct mdp5_ctl *ctl; 528 struct mdp5_pipeline *pipeline = 529 mdp5_crtc_get_pipeline(plane->crtc); 530 int ret; 531 532 ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb, 533 &new_state->src, &new_state->dst); 534 WARN_ON(ret < 0); 535 536 ctl = mdp5_crtc_get_ctl(new_state->crtc); 537 538 mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane), true); 539 } 540 541 *to_mdp5_plane_state(plane->state) = 542 *to_mdp5_plane_state(new_state); 543 } 544 545 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { 546 .prepare_fb = mdp5_plane_prepare_fb, 547 .cleanup_fb = mdp5_plane_cleanup_fb, 548 .atomic_check = mdp5_plane_atomic_check, 549 .atomic_update = mdp5_plane_atomic_update, 550 .atomic_async_check = mdp5_plane_atomic_async_check, 551 .atomic_async_update = mdp5_plane_atomic_async_update, 552 }; 553 554 static void set_scanout_locked(struct mdp5_kms *mdp5_kms, 555 enum mdp5_pipe pipe, 556 struct drm_framebuffer *fb) 557 { 558 struct msm_kms *kms = &mdp5_kms->base.base; 559 560 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), 561 MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | 562 MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); 563 564 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), 565 MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | 566 MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); 567 568 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), 569 msm_framebuffer_iova(fb, kms->aspace, 0)); 570 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), 571 msm_framebuffer_iova(fb, kms->aspace, 1)); 572 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), 573 msm_framebuffer_iova(fb, kms->aspace, 2)); 574 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), 575 msm_framebuffer_iova(fb, kms->aspace, 3)); 576 } 577 578 /* Note: mdp5_plane->pipe_lock must be locked */ 579 static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe) 580 { 581 uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) & 582 ~MDP5_PIPE_OP_MODE_CSC_1_EN; 583 584 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value); 585 } 586 587 /* Note: mdp5_plane->pipe_lock must be locked */ 588 static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 589 struct csc_cfg *csc) 590 { 591 uint32_t i, mode = 0; /* RGB, no CSC */ 592 uint32_t *matrix; 593 594 if (unlikely(!csc)) 595 return; 596 597 if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type)) 598 mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV); 599 if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type)) 600 mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV); 601 mode |= MDP5_PIPE_OP_MODE_CSC_1_EN; 602 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode); 603 604 matrix = csc->matrix; 605 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe), 606 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) | 607 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1])); 608 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe), 609 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) | 610 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3])); 611 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe), 612 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) | 613 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5])); 614 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe), 615 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) | 616 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7])); 617 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe), 618 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8])); 619 620 for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) { 621 uint32_t *pre_clamp = csc->pre_clamp; 622 uint32_t *post_clamp = csc->post_clamp; 623 624 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i), 625 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) | 626 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i])); 627 628 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i), 629 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) | 630 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i])); 631 632 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i), 633 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i])); 634 635 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i), 636 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i])); 637 } 638 } 639 640 #define PHASE_STEP_SHIFT 21 641 #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */ 642 643 static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) 644 { 645 uint32_t unit; 646 647 if (src == 0 || dst == 0) 648 return -EINVAL; 649 650 /* 651 * PHASE_STEP_X/Y is coded on 26 bits (25:0), 652 * where 2^21 represents the unity "1" in fixed-point hardware design. 653 * This leaves 5 bits for the integer part (downscale case): 654 * -> maximum downscale ratio = 0b1_1111 = 31 655 */ 656 if (src > (dst * DOWN_SCALE_RATIO_MAX)) 657 return -EOVERFLOW; 658 659 unit = 1 << PHASE_STEP_SHIFT; 660 *out_phase = mult_frac(unit, src, dst); 661 662 return 0; 663 } 664 665 static int calc_scalex_steps(struct drm_plane *plane, 666 uint32_t pixel_format, uint32_t src, uint32_t dest, 667 uint32_t phasex_steps[COMP_MAX]) 668 { 669 struct mdp5_kms *mdp5_kms = get_kms(plane); 670 struct device *dev = mdp5_kms->dev->dev; 671 uint32_t phasex_step; 672 unsigned int hsub; 673 int ret; 674 675 ret = calc_phase_step(src, dest, &phasex_step); 676 if (ret) { 677 dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret); 678 return ret; 679 } 680 681 hsub = drm_format_horz_chroma_subsampling(pixel_format); 682 683 phasex_steps[COMP_0] = phasex_step; 684 phasex_steps[COMP_3] = phasex_step; 685 phasex_steps[COMP_1_2] = phasex_step / hsub; 686 687 return 0; 688 } 689 690 static int calc_scaley_steps(struct drm_plane *plane, 691 uint32_t pixel_format, uint32_t src, uint32_t dest, 692 uint32_t phasey_steps[COMP_MAX]) 693 { 694 struct mdp5_kms *mdp5_kms = get_kms(plane); 695 struct device *dev = mdp5_kms->dev->dev; 696 uint32_t phasey_step; 697 unsigned int vsub; 698 int ret; 699 700 ret = calc_phase_step(src, dest, &phasey_step); 701 if (ret) { 702 dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret); 703 return ret; 704 } 705 706 vsub = drm_format_vert_chroma_subsampling(pixel_format); 707 708 phasey_steps[COMP_0] = phasey_step; 709 phasey_steps[COMP_3] = phasey_step; 710 phasey_steps[COMP_1_2] = phasey_step / vsub; 711 712 return 0; 713 } 714 715 static uint32_t get_scale_config(const struct mdp_format *format, 716 uint32_t src, uint32_t dst, bool horz) 717 { 718 bool scaling = format->is_yuv ? true : (src != dst); 719 uint32_t sub, pix_fmt = format->base.pixel_format; 720 uint32_t ya_filter, uv_filter; 721 bool yuv = format->is_yuv; 722 723 if (!scaling) 724 return 0; 725 726 if (yuv) { 727 sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) : 728 drm_format_vert_chroma_subsampling(pix_fmt); 729 uv_filter = ((src / sub) <= dst) ? 730 SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 731 } 732 ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 733 734 if (horz) 735 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | 736 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) | 737 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) | 738 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter)); 739 else 740 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | 741 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) | 742 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) | 743 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter)); 744 } 745 746 static void calc_pixel_ext(const struct mdp_format *format, 747 uint32_t src, uint32_t dst, uint32_t phase_step[2], 748 int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX], 749 bool horz) 750 { 751 bool scaling = format->is_yuv ? true : (src != dst); 752 int i; 753 754 /* 755 * Note: 756 * We assume here that: 757 * 1. PCMN filter is used for downscale 758 * 2. bilinear filter is used for upscale 759 * 3. we are in a single pipe configuration 760 */ 761 762 for (i = 0; i < COMP_MAX; i++) { 763 pix_ext_edge1[i] = 0; 764 pix_ext_edge2[i] = scaling ? 1 : 0; 765 } 766 } 767 768 static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 769 const struct mdp_format *format, 770 uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], 771 uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) 772 { 773 uint32_t pix_fmt = format->base.pixel_format; 774 uint32_t lr, tb, req; 775 int i; 776 777 for (i = 0; i < COMP_MAX; i++) { 778 uint32_t roi_w = src_w; 779 uint32_t roi_h = src_h; 780 781 if (format->is_yuv && i == COMP_1_2) { 782 roi_w /= drm_format_horz_chroma_subsampling(pix_fmt); 783 roi_h /= drm_format_vert_chroma_subsampling(pix_fmt); 784 } 785 786 lr = (pe_left[i] >= 0) ? 787 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) : 788 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]); 789 790 lr |= (pe_right[i] >= 0) ? 791 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) : 792 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]); 793 794 tb = (pe_top[i] >= 0) ? 795 MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) : 796 MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]); 797 798 tb |= (pe_bottom[i] >= 0) ? 799 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) : 800 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]); 801 802 req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w + 803 pe_left[i] + pe_right[i]); 804 805 req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h + 806 pe_top[i] + pe_bottom[i]); 807 808 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr); 809 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb); 810 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req); 811 812 DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i, 813 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT), 814 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT), 815 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF), 816 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF), 817 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT)); 818 819 DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i, 820 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT), 821 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT), 822 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF), 823 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF), 824 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM)); 825 } 826 } 827 828 struct pixel_ext { 829 int left[COMP_MAX]; 830 int right[COMP_MAX]; 831 int top[COMP_MAX]; 832 int bottom[COMP_MAX]; 833 }; 834 835 struct phase_step { 836 u32 x[COMP_MAX]; 837 u32 y[COMP_MAX]; 838 }; 839 840 static void mdp5_hwpipe_mode_set(struct mdp5_kms *mdp5_kms, 841 struct mdp5_hw_pipe *hwpipe, 842 struct drm_framebuffer *fb, 843 struct phase_step *step, 844 struct pixel_ext *pe, 845 u32 scale_config, u32 hdecm, u32 vdecm, 846 bool hflip, bool vflip, 847 int crtc_x, int crtc_y, 848 unsigned int crtc_w, unsigned int crtc_h, 849 u32 src_img_w, u32 src_img_h, 850 u32 src_x, u32 src_y, 851 u32 src_w, u32 src_h) 852 { 853 enum mdp5_pipe pipe = hwpipe->pipe; 854 bool has_pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT; 855 const struct mdp_format *format = 856 to_mdp_format(msm_framebuffer_format(fb)); 857 858 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), 859 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_img_w) | 860 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_img_h)); 861 862 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), 863 MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | 864 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); 865 866 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), 867 MDP5_PIPE_SRC_XY_X(src_x) | 868 MDP5_PIPE_SRC_XY_Y(src_y)); 869 870 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), 871 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | 872 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); 873 874 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), 875 MDP5_PIPE_OUT_XY_X(crtc_x) | 876 MDP5_PIPE_OUT_XY_Y(crtc_y)); 877 878 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), 879 MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | 880 MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | 881 MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | 882 MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | 883 COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | 884 MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | 885 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | 886 COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | 887 MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) | 888 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); 889 890 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), 891 MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | 892 MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | 893 MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | 894 MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); 895 896 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), 897 (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) | 898 (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) | 899 COND(has_pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) | 900 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); 901 902 /* not using secure mode: */ 903 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); 904 905 if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) 906 mdp5_write_pixel_ext(mdp5_kms, pipe, format, 907 src_w, pe->left, pe->right, 908 src_h, pe->top, pe->bottom); 909 910 if (hwpipe->caps & MDP_PIPE_CAP_SCALE) { 911 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), 912 step->x[COMP_0]); 913 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), 914 step->y[COMP_0]); 915 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), 916 step->x[COMP_1_2]); 917 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), 918 step->y[COMP_1_2]); 919 mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), 920 MDP5_PIPE_DECIMATION_VERT(vdecm) | 921 MDP5_PIPE_DECIMATION_HORZ(hdecm)); 922 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), 923 scale_config); 924 } 925 926 if (hwpipe->caps & MDP_PIPE_CAP_CSC) { 927 if (MDP_FORMAT_IS_YUV(format)) 928 csc_enable(mdp5_kms, pipe, 929 mdp_get_default_csc_cfg(CSC_YUV2RGB)); 930 else 931 csc_disable(mdp5_kms, pipe); 932 } 933 934 set_scanout_locked(mdp5_kms, pipe, fb); 935 } 936 937 static int mdp5_plane_mode_set(struct drm_plane *plane, 938 struct drm_crtc *crtc, struct drm_framebuffer *fb, 939 struct drm_rect *src, struct drm_rect *dest) 940 { 941 struct drm_plane_state *pstate = plane->state; 942 struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe; 943 struct mdp5_kms *mdp5_kms = get_kms(plane); 944 enum mdp5_pipe pipe = hwpipe->pipe; 945 struct mdp5_hw_pipe *right_hwpipe; 946 const struct mdp_format *format; 947 uint32_t nplanes, config = 0; 948 struct phase_step step = { { 0 } }; 949 struct pixel_ext pe = { { 0 } }; 950 uint32_t hdecm = 0, vdecm = 0; 951 uint32_t pix_format; 952 unsigned int rotation; 953 bool vflip, hflip; 954 int crtc_x, crtc_y; 955 unsigned int crtc_w, crtc_h; 956 uint32_t src_x, src_y; 957 uint32_t src_w, src_h; 958 uint32_t src_img_w, src_img_h; 959 int ret; 960 961 nplanes = fb->format->num_planes; 962 963 /* bad formats should already be rejected: */ 964 if (WARN_ON(nplanes > pipe2nclients(pipe))) 965 return -EINVAL; 966 967 format = to_mdp_format(msm_framebuffer_format(fb)); 968 pix_format = format->base.pixel_format; 969 970 src_x = src->x1; 971 src_y = src->y1; 972 src_w = drm_rect_width(src); 973 src_h = drm_rect_height(src); 974 975 crtc_x = dest->x1; 976 crtc_y = dest->y1; 977 crtc_w = drm_rect_width(dest); 978 crtc_h = drm_rect_height(dest); 979 980 /* src values are in Q16 fixed point, convert to integer: */ 981 src_x = src_x >> 16; 982 src_y = src_y >> 16; 983 src_w = src_w >> 16; 984 src_h = src_h >> 16; 985 986 src_img_w = min(fb->width, src_w); 987 src_img_h = min(fb->height, src_h); 988 989 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name, 990 fb->base.id, src_x, src_y, src_w, src_h, 991 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); 992 993 right_hwpipe = to_mdp5_plane_state(pstate)->r_hwpipe; 994 if (right_hwpipe) { 995 /* 996 * if the plane comprises of 2 hw pipes, assume that the width 997 * is split equally across them. The only parameters that varies 998 * between the 2 pipes are src_x and crtc_x 999 */ 1000 crtc_w /= 2; 1001 src_w /= 2; 1002 src_img_w /= 2; 1003 } 1004 1005 ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, step.x); 1006 if (ret) 1007 return ret; 1008 1009 ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, step.y); 1010 if (ret) 1011 return ret; 1012 1013 if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) { 1014 calc_pixel_ext(format, src_w, crtc_w, step.x, 1015 pe.left, pe.right, true); 1016 calc_pixel_ext(format, src_h, crtc_h, step.y, 1017 pe.top, pe.bottom, false); 1018 } 1019 1020 /* TODO calc hdecm, vdecm */ 1021 1022 /* SCALE is used to both scale and up-sample chroma components */ 1023 config |= get_scale_config(format, src_w, crtc_w, true); 1024 config |= get_scale_config(format, src_h, crtc_h, false); 1025 DBG("scale config = %x", config); 1026 1027 rotation = drm_rotation_simplify(pstate->rotation, 1028 DRM_MODE_ROTATE_0 | 1029 DRM_MODE_REFLECT_X | 1030 DRM_MODE_REFLECT_Y); 1031 hflip = !!(rotation & DRM_MODE_REFLECT_X); 1032 vflip = !!(rotation & DRM_MODE_REFLECT_Y); 1033 1034 mdp5_hwpipe_mode_set(mdp5_kms, hwpipe, fb, &step, &pe, 1035 config, hdecm, vdecm, hflip, vflip, 1036 crtc_x, crtc_y, crtc_w, crtc_h, 1037 src_img_w, src_img_h, 1038 src_x, src_y, src_w, src_h); 1039 if (right_hwpipe) 1040 mdp5_hwpipe_mode_set(mdp5_kms, right_hwpipe, fb, &step, &pe, 1041 config, hdecm, vdecm, hflip, vflip, 1042 crtc_x + crtc_w, crtc_y, crtc_w, crtc_h, 1043 src_img_w, src_img_h, 1044 src_x + src_w, src_y, src_w, src_h); 1045 1046 plane->fb = fb; 1047 1048 return ret; 1049 } 1050 1051 /* 1052 * Use this func and the one below only after the atomic state has been 1053 * successfully swapped 1054 */ 1055 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) 1056 { 1057 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state); 1058 1059 if (WARN_ON(!pstate->hwpipe)) 1060 return SSPP_NONE; 1061 1062 return pstate->hwpipe->pipe; 1063 } 1064 1065 enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane) 1066 { 1067 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state); 1068 1069 if (!pstate->r_hwpipe) 1070 return SSPP_NONE; 1071 1072 return pstate->r_hwpipe->pipe; 1073 } 1074 1075 uint32_t mdp5_plane_get_flush(struct drm_plane *plane) 1076 { 1077 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state); 1078 u32 mask; 1079 1080 if (WARN_ON(!pstate->hwpipe)) 1081 return 0; 1082 1083 mask = pstate->hwpipe->flush_mask; 1084 1085 if (pstate->r_hwpipe) 1086 mask |= pstate->r_hwpipe->flush_mask; 1087 1088 return mask; 1089 } 1090 1091 /* initialize plane */ 1092 struct drm_plane *mdp5_plane_init(struct drm_device *dev, 1093 enum drm_plane_type type) 1094 { 1095 struct drm_plane *plane = NULL; 1096 struct mdp5_plane *mdp5_plane; 1097 int ret; 1098 1099 mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); 1100 if (!mdp5_plane) { 1101 ret = -ENOMEM; 1102 goto fail; 1103 } 1104 1105 plane = &mdp5_plane->base; 1106 1107 mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats, 1108 ARRAY_SIZE(mdp5_plane->formats), false); 1109 1110 ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, 1111 mdp5_plane->formats, mdp5_plane->nformats, 1112 NULL, type, NULL); 1113 if (ret) 1114 goto fail; 1115 1116 drm_plane_helper_add(plane, &mdp5_plane_helper_funcs); 1117 1118 mdp5_plane_install_properties(plane, &plane->base); 1119 1120 return plane; 1121 1122 fail: 1123 if (plane) 1124 mdp5_plane_destroy(plane); 1125 1126 return ERR_PTR(ret); 1127 } 1128