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