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 "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 uint32_t caps; 30 31 uint32_t flush_mask; /* used to commit pipe registers */ 32 33 uint32_t nformats; 34 uint32_t formats[32]; 35}; 36#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) 37 38static int mdp5_plane_mode_set(struct drm_plane *plane, 39 struct drm_crtc *crtc, struct drm_framebuffer *fb, 40 int crtc_x, int crtc_y, 41 unsigned int crtc_w, unsigned int crtc_h, 42 uint32_t src_x, uint32_t src_y, 43 uint32_t src_w, uint32_t src_h); 44 45static void set_scanout_locked(struct drm_plane *plane, 46 struct drm_framebuffer *fb); 47 48static struct mdp5_kms *get_kms(struct drm_plane *plane) 49{ 50 struct msm_drm_private *priv = plane->dev->dev_private; 51 return to_mdp5_kms(to_mdp_kms(priv->kms)); 52} 53 54static bool plane_enabled(struct drm_plane_state *state) 55{ 56 return state->fb && state->crtc; 57} 58 59static void mdp5_plane_destroy(struct drm_plane *plane) 60{ 61 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 62 63 drm_plane_helper_disable(plane); 64 drm_plane_cleanup(plane); 65 66 kfree(mdp5_plane); 67} 68 69static void mdp5_plane_install_rotation_property(struct drm_device *dev, 70 struct drm_plane *plane) 71{ 72 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 73 74 if (!(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP) && 75 !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) 76 return; 77 78 if (!dev->mode_config.rotation_property) 79 dev->mode_config.rotation_property = 80 drm_mode_create_rotation_property(dev, 81 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y)); 82 83 if (dev->mode_config.rotation_property) 84 drm_object_attach_property(&plane->base, 85 dev->mode_config.rotation_property, 86 0); 87} 88 89/* helper to install properties which are common to planes and crtcs */ 90static void mdp5_plane_install_properties(struct drm_plane *plane, 91 struct drm_mode_object *obj) 92{ 93 struct drm_device *dev = plane->dev; 94 struct msm_drm_private *dev_priv = dev->dev_private; 95 struct drm_property *prop; 96 97#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \ 98 prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \ 99 if (!prop) { \ 100 prop = drm_property_##fnc(dev, 0, #name, \ 101 ##__VA_ARGS__); \ 102 if (!prop) { \ 103 dev_warn(dev->dev, \ 104 "Create property %s failed\n", \ 105 #name); \ 106 return; \ 107 } \ 108 dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \ 109 } \ 110 drm_object_attach_property(&plane->base, prop, init_val); \ 111 } while (0) 112 113#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \ 114 INSTALL_PROPERTY(name, NAME, init_val, \ 115 create_range, min, max) 116 117#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \ 118 INSTALL_PROPERTY(name, NAME, init_val, \ 119 create_enum, name##_prop_enum_list, \ 120 ARRAY_SIZE(name##_prop_enum_list)) 121 122 INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1); 123 124 mdp5_plane_install_rotation_property(dev, plane); 125 126#undef INSTALL_RANGE_PROPERTY 127#undef INSTALL_ENUM_PROPERTY 128#undef INSTALL_PROPERTY 129} 130 131static int mdp5_plane_atomic_set_property(struct drm_plane *plane, 132 struct drm_plane_state *state, struct drm_property *property, 133 uint64_t val) 134{ 135 struct drm_device *dev = plane->dev; 136 struct mdp5_plane_state *pstate; 137 struct msm_drm_private *dev_priv = dev->dev_private; 138 int ret = 0; 139 140 pstate = to_mdp5_plane_state(state); 141 142#define SET_PROPERTY(name, NAME, type) do { \ 143 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ 144 pstate->name = (type)val; \ 145 DBG("Set property %s %d", #name, (type)val); \ 146 goto done; \ 147 } \ 148 } while (0) 149 150 SET_PROPERTY(zpos, ZPOS, uint8_t); 151 152 dev_err(dev->dev, "Invalid property\n"); 153 ret = -EINVAL; 154done: 155 return ret; 156#undef SET_PROPERTY 157} 158 159static int mdp5_plane_atomic_get_property(struct drm_plane *plane, 160 const struct drm_plane_state *state, 161 struct drm_property *property, uint64_t *val) 162{ 163 struct drm_device *dev = plane->dev; 164 struct mdp5_plane_state *pstate; 165 struct msm_drm_private *dev_priv = dev->dev_private; 166 int ret = 0; 167 168 pstate = to_mdp5_plane_state(state); 169 170#define GET_PROPERTY(name, NAME, type) do { \ 171 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ 172 *val = pstate->name; \ 173 DBG("Get property %s %lld", #name, *val); \ 174 goto done; \ 175 } \ 176 } while (0) 177 178 GET_PROPERTY(zpos, ZPOS, uint8_t); 179 180 dev_err(dev->dev, "Invalid property\n"); 181 ret = -EINVAL; 182done: 183 return ret; 184#undef SET_PROPERTY 185} 186 187static void mdp5_plane_reset(struct drm_plane *plane) 188{ 189 struct mdp5_plane_state *mdp5_state; 190 191 if (plane->state && plane->state->fb) 192 drm_framebuffer_unreference(plane->state->fb); 193 194 kfree(to_mdp5_plane_state(plane->state)); 195 mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL); 196 197 /* assign default blend parameters */ 198 mdp5_state->alpha = 255; 199 mdp5_state->premultiplied = 0; 200 201 if (plane->type == DRM_PLANE_TYPE_PRIMARY) 202 mdp5_state->zpos = STAGE_BASE; 203 else 204 mdp5_state->zpos = STAGE0 + drm_plane_index(plane); 205 206 mdp5_state->base.plane = plane; 207 208 plane->state = &mdp5_state->base; 209} 210 211static struct drm_plane_state * 212mdp5_plane_duplicate_state(struct drm_plane *plane) 213{ 214 struct mdp5_plane_state *mdp5_state; 215 216 if (WARN_ON(!plane->state)) 217 return NULL; 218 219 mdp5_state = kmemdup(to_mdp5_plane_state(plane->state), 220 sizeof(*mdp5_state), GFP_KERNEL); 221 222 if (mdp5_state && mdp5_state->base.fb) 223 drm_framebuffer_reference(mdp5_state->base.fb); 224 225 mdp5_state->mode_changed = false; 226 mdp5_state->pending = false; 227 228 return &mdp5_state->base; 229} 230 231static void mdp5_plane_destroy_state(struct drm_plane *plane, 232 struct drm_plane_state *state) 233{ 234 if (state->fb) 235 drm_framebuffer_unreference(state->fb); 236 237 kfree(to_mdp5_plane_state(state)); 238} 239 240static const struct drm_plane_funcs mdp5_plane_funcs = { 241 .update_plane = drm_atomic_helper_update_plane, 242 .disable_plane = drm_atomic_helper_disable_plane, 243 .destroy = mdp5_plane_destroy, 244 .set_property = drm_atomic_helper_plane_set_property, 245 .atomic_set_property = mdp5_plane_atomic_set_property, 246 .atomic_get_property = mdp5_plane_atomic_get_property, 247 .reset = mdp5_plane_reset, 248 .atomic_duplicate_state = mdp5_plane_duplicate_state, 249 .atomic_destroy_state = mdp5_plane_destroy_state, 250}; 251 252static int mdp5_plane_prepare_fb(struct drm_plane *plane, 253 const struct drm_plane_state *new_state) 254{ 255 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 256 struct mdp5_kms *mdp5_kms = get_kms(plane); 257 struct drm_framebuffer *fb = new_state->fb; 258 259 if (!new_state->fb) 260 return 0; 261 262 DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); 263 return msm_framebuffer_prepare(fb, mdp5_kms->id); 264} 265 266static void mdp5_plane_cleanup_fb(struct drm_plane *plane, 267 const struct drm_plane_state *old_state) 268{ 269 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 270 struct mdp5_kms *mdp5_kms = get_kms(plane); 271 struct drm_framebuffer *fb = old_state->fb; 272 273 if (!fb) 274 return; 275 276 DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); 277 msm_framebuffer_cleanup(fb, mdp5_kms->id); 278} 279 280static int mdp5_plane_atomic_check(struct drm_plane *plane, 281 struct drm_plane_state *state) 282{ 283 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 284 struct drm_plane_state *old_state = plane->state; 285 const struct mdp_format *format; 286 bool vflip, hflip; 287 288 DBG("%s: check (%d -> %d)", mdp5_plane->name, 289 plane_enabled(old_state), plane_enabled(state)); 290 291 if (plane_enabled(state)) { 292 format = to_mdp_format(msm_framebuffer_format(state->fb)); 293 if (MDP_FORMAT_IS_YUV(format) && 294 !pipe_supports_yuv(mdp5_plane->caps)) { 295 dev_err(plane->dev->dev, 296 "Pipe doesn't support YUV\n"); 297 298 return -EINVAL; 299 } 300 301 if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) && 302 (((state->src_w >> 16) != state->crtc_w) || 303 ((state->src_h >> 16) != state->crtc_h))) { 304 dev_err(plane->dev->dev, 305 "Pipe doesn't support scaling (%dx%d -> %dx%d)\n", 306 state->src_w >> 16, state->src_h >> 16, 307 state->crtc_w, state->crtc_h); 308 309 return -EINVAL; 310 } 311 312 hflip = !!(state->rotation & BIT(DRM_REFLECT_X)); 313 vflip = !!(state->rotation & BIT(DRM_REFLECT_Y)); 314 if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) || 315 (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) { 316 dev_err(plane->dev->dev, 317 "Pipe doesn't support flip\n"); 318 319 return -EINVAL; 320 } 321 } 322 323 if (plane_enabled(state) && plane_enabled(old_state)) { 324 /* we cannot change SMP block configuration during scanout: */ 325 bool full_modeset = false; 326 if (state->fb->pixel_format != old_state->fb->pixel_format) { 327 DBG("%s: pixel_format change!", mdp5_plane->name); 328 full_modeset = true; 329 } 330 if (state->src_w != old_state->src_w) { 331 DBG("%s: src_w change!", mdp5_plane->name); 332 full_modeset = true; 333 } 334 if (to_mdp5_plane_state(old_state)->pending) { 335 DBG("%s: still pending!", mdp5_plane->name); 336 full_modeset = true; 337 } 338 if (full_modeset) { 339 struct drm_crtc_state *crtc_state = 340 drm_atomic_get_crtc_state(state->state, state->crtc); 341 crtc_state->mode_changed = true; 342 to_mdp5_plane_state(state)->mode_changed = true; 343 } 344 } else { 345 to_mdp5_plane_state(state)->mode_changed = true; 346 } 347 348 return 0; 349} 350 351static void mdp5_plane_atomic_update(struct drm_plane *plane, 352 struct drm_plane_state *old_state) 353{ 354 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 355 struct drm_plane_state *state = plane->state; 356 357 DBG("%s: update", mdp5_plane->name); 358 359 if (!plane_enabled(state)) { 360 to_mdp5_plane_state(state)->pending = true; 361 } else if (to_mdp5_plane_state(state)->mode_changed) { 362 int ret; 363 to_mdp5_plane_state(state)->pending = true; 364 ret = mdp5_plane_mode_set(plane, 365 state->crtc, state->fb, 366 state->crtc_x, state->crtc_y, 367 state->crtc_w, state->crtc_h, 368 state->src_x, state->src_y, 369 state->src_w, state->src_h); 370 /* atomic_check should have ensured that this doesn't fail */ 371 WARN_ON(ret < 0); 372 } else { 373 unsigned long flags; 374 spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); 375 set_scanout_locked(plane, state->fb); 376 spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); 377 } 378} 379 380static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { 381 .prepare_fb = mdp5_plane_prepare_fb, 382 .cleanup_fb = mdp5_plane_cleanup_fb, 383 .atomic_check = mdp5_plane_atomic_check, 384 .atomic_update = mdp5_plane_atomic_update, 385}; 386 387static void set_scanout_locked(struct drm_plane *plane, 388 struct drm_framebuffer *fb) 389{ 390 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 391 struct mdp5_kms *mdp5_kms = get_kms(plane); 392 enum mdp5_pipe pipe = mdp5_plane->pipe; 393 394 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), 395 MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | 396 MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); 397 398 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), 399 MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | 400 MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); 401 402 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), 403 msm_framebuffer_iova(fb, mdp5_kms->id, 0)); 404 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), 405 msm_framebuffer_iova(fb, mdp5_kms->id, 1)); 406 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), 407 msm_framebuffer_iova(fb, mdp5_kms->id, 2)); 408 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), 409 msm_framebuffer_iova(fb, mdp5_kms->id, 3)); 410 411 plane->fb = fb; 412} 413 414/* Note: mdp5_plane->pipe_lock must be locked */ 415static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe) 416{ 417 uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) & 418 ~MDP5_PIPE_OP_MODE_CSC_1_EN; 419 420 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value); 421} 422 423/* Note: mdp5_plane->pipe_lock must be locked */ 424static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 425 struct csc_cfg *csc) 426{ 427 uint32_t i, mode = 0; /* RGB, no CSC */ 428 uint32_t *matrix; 429 430 if (unlikely(!csc)) 431 return; 432 433 if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type)) 434 mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV); 435 if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type)) 436 mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV); 437 mode |= MDP5_PIPE_OP_MODE_CSC_1_EN; 438 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode); 439 440 matrix = csc->matrix; 441 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe), 442 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) | 443 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1])); 444 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe), 445 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) | 446 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3])); 447 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe), 448 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) | 449 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5])); 450 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe), 451 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) | 452 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7])); 453 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe), 454 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8])); 455 456 for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) { 457 uint32_t *pre_clamp = csc->pre_clamp; 458 uint32_t *post_clamp = csc->post_clamp; 459 460 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i), 461 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) | 462 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i])); 463 464 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i), 465 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) | 466 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i])); 467 468 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i), 469 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i])); 470 471 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i), 472 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i])); 473 } 474} 475 476#define PHASE_STEP_SHIFT 21 477#define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */ 478 479static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) 480{ 481 uint32_t unit; 482 483 if (src == 0 || dst == 0) 484 return -EINVAL; 485 486 /* 487 * PHASE_STEP_X/Y is coded on 26 bits (25:0), 488 * where 2^21 represents the unity "1" in fixed-point hardware design. 489 * This leaves 5 bits for the integer part (downscale case): 490 * -> maximum downscale ratio = 0b1_1111 = 31 491 */ 492 if (src > (dst * DOWN_SCALE_RATIO_MAX)) 493 return -EOVERFLOW; 494 495 unit = 1 << PHASE_STEP_SHIFT; 496 *out_phase = mult_frac(unit, src, dst); 497 498 return 0; 499} 500 501static int calc_scalex_steps(struct drm_plane *plane, 502 uint32_t pixel_format, uint32_t src, uint32_t dest, 503 uint32_t phasex_steps[COMP_MAX]) 504{ 505 struct mdp5_kms *mdp5_kms = get_kms(plane); 506 struct device *dev = mdp5_kms->dev->dev; 507 uint32_t phasex_step; 508 unsigned int hsub; 509 int ret; 510 511 ret = calc_phase_step(src, dest, &phasex_step); 512 if (ret) { 513 dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret); 514 return ret; 515 } 516 517 hsub = drm_format_horz_chroma_subsampling(pixel_format); 518 519 phasex_steps[COMP_0] = phasex_step; 520 phasex_steps[COMP_3] = phasex_step; 521 phasex_steps[COMP_1_2] = phasex_step / hsub; 522 523 return 0; 524} 525 526static int calc_scaley_steps(struct drm_plane *plane, 527 uint32_t pixel_format, uint32_t src, uint32_t dest, 528 uint32_t phasey_steps[COMP_MAX]) 529{ 530 struct mdp5_kms *mdp5_kms = get_kms(plane); 531 struct device *dev = mdp5_kms->dev->dev; 532 uint32_t phasey_step; 533 unsigned int vsub; 534 int ret; 535 536 ret = calc_phase_step(src, dest, &phasey_step); 537 if (ret) { 538 dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret); 539 return ret; 540 } 541 542 vsub = drm_format_vert_chroma_subsampling(pixel_format); 543 544 phasey_steps[COMP_0] = phasey_step; 545 phasey_steps[COMP_3] = phasey_step; 546 phasey_steps[COMP_1_2] = phasey_step / vsub; 547 548 return 0; 549} 550 551static uint32_t get_scale_config(const struct mdp_format *format, 552 uint32_t src, uint32_t dst, bool horz) 553{ 554 bool scaling = format->is_yuv ? true : (src != dst); 555 uint32_t sub, pix_fmt = format->base.pixel_format; 556 uint32_t ya_filter, uv_filter; 557 bool yuv = format->is_yuv; 558 559 if (!scaling) 560 return 0; 561 562 if (yuv) { 563 sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) : 564 drm_format_vert_chroma_subsampling(pix_fmt); 565 uv_filter = ((src / sub) <= dst) ? 566 SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 567 } 568 ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; 569 570 if (horz) 571 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | 572 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) | 573 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) | 574 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter)); 575 else 576 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | 577 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) | 578 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) | 579 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter)); 580} 581 582static void calc_pixel_ext(const struct mdp_format *format, 583 uint32_t src, uint32_t dst, uint32_t phase_step[2], 584 int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX], 585 bool horz) 586{ 587 bool scaling = format->is_yuv ? true : (src != dst); 588 int i; 589 590 /* 591 * Note: 592 * We assume here that: 593 * 1. PCMN filter is used for downscale 594 * 2. bilinear filter is used for upscale 595 * 3. we are in a single pipe configuration 596 */ 597 598 for (i = 0; i < COMP_MAX; i++) { 599 pix_ext_edge1[i] = 0; 600 pix_ext_edge2[i] = scaling ? 1 : 0; 601 } 602} 603 604static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, 605 const struct mdp_format *format, 606 uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], 607 uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) 608{ 609 uint32_t pix_fmt = format->base.pixel_format; 610 uint32_t lr, tb, req; 611 int i; 612 613 for (i = 0; i < COMP_MAX; i++) { 614 uint32_t roi_w = src_w; 615 uint32_t roi_h = src_h; 616 617 if (format->is_yuv && i == COMP_1_2) { 618 roi_w /= drm_format_horz_chroma_subsampling(pix_fmt); 619 roi_h /= drm_format_vert_chroma_subsampling(pix_fmt); 620 } 621 622 lr = (pe_left[i] >= 0) ? 623 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) : 624 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]); 625 626 lr |= (pe_right[i] >= 0) ? 627 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) : 628 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]); 629 630 tb = (pe_top[i] >= 0) ? 631 MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) : 632 MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]); 633 634 tb |= (pe_bottom[i] >= 0) ? 635 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) : 636 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]); 637 638 req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w + 639 pe_left[i] + pe_right[i]); 640 641 req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h + 642 pe_top[i] + pe_bottom[i]); 643 644 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr); 645 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb); 646 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req); 647 648 DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i, 649 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT), 650 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT), 651 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF), 652 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF), 653 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT)); 654 655 DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i, 656 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT), 657 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT), 658 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF), 659 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF), 660 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM)); 661 } 662} 663 664 665static int mdp5_plane_mode_set(struct drm_plane *plane, 666 struct drm_crtc *crtc, struct drm_framebuffer *fb, 667 int crtc_x, int crtc_y, 668 unsigned int crtc_w, unsigned int crtc_h, 669 uint32_t src_x, uint32_t src_y, 670 uint32_t src_w, uint32_t src_h) 671{ 672 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 673 struct drm_plane_state *pstate = plane->state; 674 struct mdp5_kms *mdp5_kms = get_kms(plane); 675 enum mdp5_pipe pipe = mdp5_plane->pipe; 676 const struct mdp_format *format; 677 uint32_t nplanes, config = 0; 678 uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,}; 679 bool pe = mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT; 680 int pe_left[COMP_MAX], pe_right[COMP_MAX]; 681 int pe_top[COMP_MAX], pe_bottom[COMP_MAX]; 682 uint32_t hdecm = 0, vdecm = 0; 683 uint32_t pix_format; 684 bool vflip, hflip; 685 unsigned long flags; 686 int ret; 687 688 nplanes = drm_format_num_planes(fb->pixel_format); 689 690 /* bad formats should already be rejected: */ 691 if (WARN_ON(nplanes > pipe2nclients(pipe))) 692 return -EINVAL; 693 694 format = to_mdp_format(msm_framebuffer_format(fb)); 695 pix_format = format->base.pixel_format; 696 697 /* src values are in Q16 fixed point, convert to integer: */ 698 src_x = src_x >> 16; 699 src_y = src_y >> 16; 700 src_w = src_w >> 16; 701 src_h = src_h >> 16; 702 703 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, 704 fb->base.id, src_x, src_y, src_w, src_h, 705 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); 706 707 /* Request some memory from the SMP: */ 708 if (mdp5_kms->smp) { 709 ret = mdp5_smp_request(mdp5_kms->smp, 710 mdp5_plane->pipe, format, src_w, false); 711 if (ret) 712 return ret; 713 } 714 715 /* 716 * Currently we update the hw for allocations/requests immediately, 717 * but once atomic modeset/pageflip is in place, the allocation 718 * would move into atomic->check_plane_state(), while updating the 719 * hw would remain here: 720 */ 721 if (mdp5_kms->smp) 722 mdp5_smp_configure(mdp5_kms->smp, pipe); 723 724 ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step); 725 if (ret) 726 return ret; 727 728 ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, phasey_step); 729 if (ret) 730 return ret; 731 732 if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) { 733 calc_pixel_ext(format, src_w, crtc_w, phasex_step, 734 pe_left, pe_right, true); 735 calc_pixel_ext(format, src_h, crtc_h, phasey_step, 736 pe_top, pe_bottom, false); 737 } 738 739 /* TODO calc hdecm, vdecm */ 740 741 /* SCALE is used to both scale and up-sample chroma components */ 742 config |= get_scale_config(format, src_w, crtc_w, true); 743 config |= get_scale_config(format, src_h, crtc_h, false); 744 DBG("scale config = %x", config); 745 746 hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X)); 747 vflip = !!(pstate->rotation & BIT(DRM_REFLECT_Y)); 748 749 spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); 750 751 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), 752 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) | 753 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height)); 754 755 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), 756 MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | 757 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); 758 759 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), 760 MDP5_PIPE_SRC_XY_X(src_x) | 761 MDP5_PIPE_SRC_XY_Y(src_y)); 762 763 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), 764 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | 765 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); 766 767 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), 768 MDP5_PIPE_OUT_XY_X(crtc_x) | 769 MDP5_PIPE_OUT_XY_Y(crtc_y)); 770 771 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), 772 MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | 773 MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | 774 MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | 775 MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | 776 COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | 777 MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | 778 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | 779 COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | 780 MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) | 781 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample)); 782 783 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), 784 MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | 785 MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | 786 MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | 787 MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); 788 789 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), 790 (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) | 791 (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) | 792 COND(pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) | 793 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); 794 795 /* not using secure mode: */ 796 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); 797 798 if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) 799 mdp5_write_pixel_ext(mdp5_kms, pipe, format, 800 src_w, pe_left, pe_right, 801 src_h, pe_top, pe_bottom); 802 803 if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) { 804 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), 805 phasex_step[COMP_0]); 806 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), 807 phasey_step[COMP_0]); 808 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), 809 phasex_step[COMP_1_2]); 810 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), 811 phasey_step[COMP_1_2]); 812 mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), 813 MDP5_PIPE_DECIMATION_VERT(vdecm) | 814 MDP5_PIPE_DECIMATION_HORZ(hdecm)); 815 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config); 816 } 817 818 if (mdp5_plane->caps & MDP_PIPE_CAP_CSC) { 819 if (MDP_FORMAT_IS_YUV(format)) 820 csc_enable(mdp5_kms, pipe, 821 mdp_get_default_csc_cfg(CSC_YUV2RGB)); 822 else 823 csc_disable(mdp5_kms, pipe); 824 } 825 826 set_scanout_locked(plane, fb); 827 828 spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); 829 830 return ret; 831} 832 833void mdp5_plane_complete_flip(struct drm_plane *plane) 834{ 835 struct mdp5_kms *mdp5_kms = get_kms(plane); 836 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 837 enum mdp5_pipe pipe = mdp5_plane->pipe; 838 839 DBG("%s: complete flip", mdp5_plane->name); 840 841 if (mdp5_kms->smp) 842 mdp5_smp_commit(mdp5_kms->smp, pipe); 843 844 to_mdp5_plane_state(plane->state)->pending = false; 845} 846 847enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) 848{ 849 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 850 return mdp5_plane->pipe; 851} 852 853uint32_t mdp5_plane_get_flush(struct drm_plane *plane) 854{ 855 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 856 857 return mdp5_plane->flush_mask; 858} 859 860/* called after vsync in thread context */ 861void mdp5_plane_complete_commit(struct drm_plane *plane, 862 struct drm_plane_state *state) 863{ 864 struct mdp5_kms *mdp5_kms = get_kms(plane); 865 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 866 enum mdp5_pipe pipe = mdp5_plane->pipe; 867 868 if (!plane_enabled(plane->state) && mdp5_kms->smp) { 869 DBG("%s: free SMP", mdp5_plane->name); 870 mdp5_smp_release(mdp5_kms->smp, pipe); 871 } 872} 873 874/* initialize plane */ 875struct drm_plane *mdp5_plane_init(struct drm_device *dev, 876 enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset, 877 uint32_t caps) 878{ 879 struct drm_plane *plane = NULL; 880 struct mdp5_plane *mdp5_plane; 881 int ret; 882 enum drm_plane_type type; 883 884 mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); 885 if (!mdp5_plane) { 886 ret = -ENOMEM; 887 goto fail; 888 } 889 890 plane = &mdp5_plane->base; 891 892 mdp5_plane->pipe = pipe; 893 mdp5_plane->name = pipe2name(pipe); 894 mdp5_plane->caps = caps; 895 896 mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats, 897 ARRAY_SIZE(mdp5_plane->formats), 898 !pipe_supports_yuv(mdp5_plane->caps)); 899 900 mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe); 901 mdp5_plane->reg_offset = reg_offset; 902 spin_lock_init(&mdp5_plane->pipe_lock); 903 904 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 905 ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, 906 mdp5_plane->formats, mdp5_plane->nformats, 907 type); 908 if (ret) 909 goto fail; 910 911 drm_plane_helper_add(plane, &mdp5_plane_helper_funcs); 912 913 mdp5_plane_install_properties(plane, &plane->base); 914 915 return plane; 916 917fail: 918 if (plane) 919 mdp5_plane_destroy(plane); 920 921 return ERR_PTR(ret); 922} 923