0001
0002
0003
0004
0005
0006
0007
0008 #include <drm/drm_atomic.h>
0009 #include <drm/drm_blend.h>
0010 #include <drm/drm_damage_helper.h>
0011 #include <drm/drm_fourcc.h>
0012 #include <drm/drm_framebuffer.h>
0013 #include <drm/drm_gem_atomic_helper.h>
0014 #include <drm/drm_print.h>
0015
0016 #include "mdp5_kms.h"
0017
0018 struct mdp5_plane {
0019 struct drm_plane base;
0020
0021 uint32_t nformats;
0022 uint32_t formats[32];
0023 };
0024 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
0025
0026 static int mdp5_plane_mode_set(struct drm_plane *plane,
0027 struct drm_crtc *crtc, struct drm_framebuffer *fb,
0028 struct drm_rect *src, struct drm_rect *dest);
0029
0030 static struct mdp5_kms *get_kms(struct drm_plane *plane)
0031 {
0032 struct msm_drm_private *priv = plane->dev->dev_private;
0033 return to_mdp5_kms(to_mdp_kms(priv->kms));
0034 }
0035
0036 static bool plane_enabled(struct drm_plane_state *state)
0037 {
0038 return state->visible;
0039 }
0040
0041 static void mdp5_plane_destroy(struct drm_plane *plane)
0042 {
0043 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
0044
0045 drm_plane_cleanup(plane);
0046
0047 kfree(mdp5_plane);
0048 }
0049
0050
0051 static void mdp5_plane_install_properties(struct drm_plane *plane,
0052 struct drm_mode_object *obj)
0053 {
0054 unsigned int zpos;
0055
0056 drm_plane_create_rotation_property(plane,
0057 DRM_MODE_ROTATE_0,
0058 DRM_MODE_ROTATE_0 |
0059 DRM_MODE_ROTATE_180 |
0060 DRM_MODE_REFLECT_X |
0061 DRM_MODE_REFLECT_Y);
0062 drm_plane_create_alpha_property(plane);
0063 drm_plane_create_blend_mode_property(plane,
0064 BIT(DRM_MODE_BLEND_PIXEL_NONE) |
0065 BIT(DRM_MODE_BLEND_PREMULTI) |
0066 BIT(DRM_MODE_BLEND_COVERAGE));
0067
0068 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
0069 zpos = STAGE_BASE;
0070 else
0071 zpos = STAGE0 + drm_plane_index(plane);
0072 drm_plane_create_zpos_property(plane, zpos, 1, 255);
0073 }
0074
0075 static void
0076 mdp5_plane_atomic_print_state(struct drm_printer *p,
0077 const struct drm_plane_state *state)
0078 {
0079 struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
0080 struct mdp5_kms *mdp5_kms = get_kms(state->plane);
0081
0082 drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ?
0083 pstate->hwpipe->name : "(null)");
0084 if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
0085 drm_printf(p, "\tright-hwpipe=%s\n",
0086 pstate->r_hwpipe ? pstate->r_hwpipe->name :
0087 "(null)");
0088 drm_printf(p, "\tblend_mode=%u\n", pstate->base.pixel_blend_mode);
0089 drm_printf(p, "\tzpos=%u\n", pstate->base.zpos);
0090 drm_printf(p, "\tnormalized_zpos=%u\n", pstate->base.normalized_zpos);
0091 drm_printf(p, "\talpha=%u\n", pstate->base.alpha);
0092 drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
0093 }
0094
0095 static void mdp5_plane_reset(struct drm_plane *plane)
0096 {
0097 struct mdp5_plane_state *mdp5_state;
0098
0099 if (plane->state)
0100 __drm_atomic_helper_plane_destroy_state(plane->state);
0101
0102 kfree(to_mdp5_plane_state(plane->state));
0103 plane->state = NULL;
0104 mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
0105 if (!mdp5_state)
0106 return;
0107 __drm_atomic_helper_plane_reset(plane, &mdp5_state->base);
0108 }
0109
0110 static struct drm_plane_state *
0111 mdp5_plane_duplicate_state(struct drm_plane *plane)
0112 {
0113 struct mdp5_plane_state *mdp5_state;
0114
0115 if (WARN_ON(!plane->state))
0116 return NULL;
0117
0118 mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
0119 sizeof(*mdp5_state), GFP_KERNEL);
0120 if (!mdp5_state)
0121 return NULL;
0122
0123 __drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
0124
0125 return &mdp5_state->base;
0126 }
0127
0128 static void mdp5_plane_destroy_state(struct drm_plane *plane,
0129 struct drm_plane_state *state)
0130 {
0131 struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
0132
0133 if (state->fb)
0134 drm_framebuffer_put(state->fb);
0135
0136 kfree(pstate);
0137 }
0138
0139 static const struct drm_plane_funcs mdp5_plane_funcs = {
0140 .update_plane = drm_atomic_helper_update_plane,
0141 .disable_plane = drm_atomic_helper_disable_plane,
0142 .destroy = mdp5_plane_destroy,
0143 .reset = mdp5_plane_reset,
0144 .atomic_duplicate_state = mdp5_plane_duplicate_state,
0145 .atomic_destroy_state = mdp5_plane_destroy_state,
0146 .atomic_print_state = mdp5_plane_atomic_print_state,
0147 };
0148
0149 static int mdp5_plane_prepare_fb(struct drm_plane *plane,
0150 struct drm_plane_state *new_state)
0151 {
0152 struct msm_drm_private *priv = plane->dev->dev_private;
0153 struct msm_kms *kms = priv->kms;
0154 bool needs_dirtyfb = to_mdp5_plane_state(new_state)->needs_dirtyfb;
0155
0156 if (!new_state->fb)
0157 return 0;
0158
0159 drm_gem_plane_helper_prepare_fb(plane, new_state);
0160
0161 return msm_framebuffer_prepare(new_state->fb, kms->aspace, needs_dirtyfb);
0162 }
0163
0164 static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
0165 struct drm_plane_state *old_state)
0166 {
0167 struct mdp5_kms *mdp5_kms = get_kms(plane);
0168 struct msm_kms *kms = &mdp5_kms->base.base;
0169 struct drm_framebuffer *fb = old_state->fb;
0170 bool needed_dirtyfb = to_mdp5_plane_state(old_state)->needs_dirtyfb;
0171
0172 if (!fb)
0173 return;
0174
0175 DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id);
0176 msm_framebuffer_cleanup(fb, kms->aspace, needed_dirtyfb);
0177 }
0178
0179 static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
0180 struct drm_plane_state *state)
0181 {
0182 struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
0183 struct drm_plane *plane = state->plane;
0184 struct drm_plane_state *old_state = plane->state;
0185 struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
0186 bool new_hwpipe = false;
0187 bool need_right_hwpipe = false;
0188 uint32_t max_width, max_height;
0189 bool out_of_bounds = false;
0190 uint32_t caps = 0;
0191 int min_scale, max_scale;
0192 int ret;
0193
0194 DBG("%s: check (%d -> %d)", plane->name,
0195 plane_enabled(old_state), plane_enabled(state));
0196
0197 max_width = config->hw->lm.max_width << 16;
0198 max_height = config->hw->lm.max_height << 16;
0199
0200
0201 if (state->src_h > max_height)
0202 out_of_bounds = true;
0203
0204 if (state->src_w > max_width) {
0205
0206
0207
0208
0209
0210 if (config->hw->mdp.caps & MDP_CAP_SRC_SPLIT &&
0211 (state->src_w <= 2 * max_width))
0212 need_right_hwpipe = true;
0213 else
0214 out_of_bounds = true;
0215 }
0216
0217 if (out_of_bounds) {
0218 struct drm_rect src = drm_plane_state_src(state);
0219 DBG("Invalid source size "DRM_RECT_FP_FMT,
0220 DRM_RECT_FP_ARG(&src));
0221 return -ERANGE;
0222 }
0223
0224 min_scale = FRAC_16_16(1, 8);
0225 max_scale = FRAC_16_16(8, 1);
0226
0227 ret = drm_atomic_helper_check_plane_state(state, crtc_state,
0228 min_scale, max_scale,
0229 true, true);
0230 if (ret)
0231 return ret;
0232
0233 if (plane_enabled(state)) {
0234 unsigned int rotation;
0235 const struct mdp_format *format;
0236 struct mdp5_kms *mdp5_kms = get_kms(plane);
0237 uint32_t blkcfg = 0;
0238
0239 format = to_mdp_format(msm_framebuffer_format(state->fb));
0240 if (MDP_FORMAT_IS_YUV(format))
0241 caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
0242
0243 if (((state->src_w >> 16) != state->crtc_w) ||
0244 ((state->src_h >> 16) != state->crtc_h))
0245 caps |= MDP_PIPE_CAP_SCALE;
0246
0247 rotation = drm_rotation_simplify(state->rotation,
0248 DRM_MODE_ROTATE_0 |
0249 DRM_MODE_REFLECT_X |
0250 DRM_MODE_REFLECT_Y);
0251
0252 if (rotation & DRM_MODE_REFLECT_X)
0253 caps |= MDP_PIPE_CAP_HFLIP;
0254
0255 if (rotation & DRM_MODE_REFLECT_Y)
0256 caps |= MDP_PIPE_CAP_VFLIP;
0257
0258 if (plane->type == DRM_PLANE_TYPE_CURSOR)
0259 caps |= MDP_PIPE_CAP_CURSOR;
0260
0261
0262 if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
0263 new_hwpipe = true;
0264
0265
0266
0267
0268
0269
0270 if ((need_right_hwpipe && !mdp5_state->r_hwpipe) ||
0271 (!need_right_hwpipe && mdp5_state->r_hwpipe))
0272 new_hwpipe = true;
0273
0274 if (mdp5_kms->smp) {
0275 const struct mdp_format *format =
0276 to_mdp_format(msm_framebuffer_format(state->fb));
0277
0278 blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
0279 state->src_w >> 16, false);
0280
0281 if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
0282 new_hwpipe = true;
0283 }
0284
0285
0286 if (new_hwpipe) {
0287
0288
0289
0290
0291 struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
0292 struct mdp5_hw_pipe *old_right_hwpipe =
0293 mdp5_state->r_hwpipe;
0294 struct mdp5_hw_pipe *new_hwpipe = NULL;
0295 struct mdp5_hw_pipe *new_right_hwpipe = NULL;
0296
0297 ret = mdp5_pipe_assign(state->state, plane, caps,
0298 blkcfg, &new_hwpipe,
0299 need_right_hwpipe ?
0300 &new_right_hwpipe : NULL);
0301 if (ret) {
0302 DBG("%s: failed to assign hwpipe(s)!",
0303 plane->name);
0304 return ret;
0305 }
0306
0307 mdp5_state->hwpipe = new_hwpipe;
0308 if (need_right_hwpipe)
0309 mdp5_state->r_hwpipe = new_right_hwpipe;
0310 else
0311
0312
0313
0314
0315
0316 mdp5_state->r_hwpipe = NULL;
0317
0318
0319 ret = mdp5_pipe_release(state->state, old_hwpipe);
0320 if (ret)
0321 return ret;
0322
0323 ret = mdp5_pipe_release(state->state, old_right_hwpipe);
0324 if (ret)
0325 return ret;
0326
0327 }
0328 } else {
0329 ret = mdp5_pipe_release(state->state, mdp5_state->hwpipe);
0330 if (ret)
0331 return ret;
0332
0333 ret = mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
0334 if (ret)
0335 return ret;
0336
0337 mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
0338 }
0339
0340 return 0;
0341 }
0342
0343 static int mdp5_plane_atomic_check(struct drm_plane *plane,
0344 struct drm_atomic_state *state)
0345 {
0346 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
0347 plane);
0348 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0349 plane);
0350 struct drm_crtc *crtc;
0351 struct drm_crtc_state *crtc_state;
0352
0353 crtc = new_plane_state->crtc ? new_plane_state->crtc : old_plane_state->crtc;
0354 if (!crtc)
0355 return 0;
0356
0357 crtc_state = drm_atomic_get_existing_crtc_state(state,
0358 crtc);
0359 if (WARN_ON(!crtc_state))
0360 return -EINVAL;
0361
0362 return mdp5_plane_atomic_check_with_state(crtc_state, new_plane_state);
0363 }
0364
0365 static void mdp5_plane_atomic_update(struct drm_plane *plane,
0366 struct drm_atomic_state *state)
0367 {
0368 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0369 plane);
0370
0371 DBG("%s: update", plane->name);
0372
0373 if (plane_enabled(new_state)) {
0374 int ret;
0375
0376 ret = mdp5_plane_mode_set(plane,
0377 new_state->crtc, new_state->fb,
0378 &new_state->src, &new_state->dst);
0379
0380 WARN_ON(ret < 0);
0381 }
0382 }
0383
0384 static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
0385 struct drm_atomic_state *state)
0386 {
0387 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0388 plane);
0389 struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(new_plane_state);
0390 struct drm_crtc_state *crtc_state;
0391 int min_scale, max_scale;
0392 int ret;
0393
0394 crtc_state = drm_atomic_get_existing_crtc_state(state,
0395 new_plane_state->crtc);
0396 if (WARN_ON(!crtc_state))
0397 return -EINVAL;
0398
0399 if (!crtc_state->active)
0400 return -EINVAL;
0401
0402
0403 if (!mdp5_state->hwpipe)
0404 return -EINVAL;
0405
0406
0407 if (plane->state->crtc != new_plane_state->crtc ||
0408 plane->state->src_w != new_plane_state->src_w ||
0409 plane->state->src_h != new_plane_state->src_h ||
0410 plane->state->crtc_w != new_plane_state->crtc_w ||
0411 plane->state->crtc_h != new_plane_state->crtc_h ||
0412 !plane->state->fb ||
0413 plane->state->fb != new_plane_state->fb)
0414 return -EINVAL;
0415
0416 min_scale = FRAC_16_16(1, 8);
0417 max_scale = FRAC_16_16(8, 1);
0418
0419 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
0420 min_scale, max_scale,
0421 true, true);
0422 if (ret)
0423 return ret;
0424
0425
0426
0427
0428
0429
0430
0431
0432 if (new_plane_state->visible != plane->state->visible)
0433 return -EINVAL;
0434
0435 return 0;
0436 }
0437
0438 static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
0439 struct drm_atomic_state *state)
0440 {
0441 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0442 plane);
0443 struct drm_framebuffer *old_fb = plane->state->fb;
0444
0445 plane->state->src_x = new_state->src_x;
0446 plane->state->src_y = new_state->src_y;
0447 plane->state->crtc_x = new_state->crtc_x;
0448 plane->state->crtc_y = new_state->crtc_y;
0449
0450 if (plane_enabled(new_state)) {
0451 struct mdp5_ctl *ctl;
0452 struct mdp5_pipeline *pipeline =
0453 mdp5_crtc_get_pipeline(new_state->crtc);
0454 int ret;
0455
0456 ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb,
0457 &new_state->src, &new_state->dst);
0458 WARN_ON(ret < 0);
0459
0460 ctl = mdp5_crtc_get_ctl(new_state->crtc);
0461
0462 mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane), true);
0463 }
0464
0465 *to_mdp5_plane_state(plane->state) =
0466 *to_mdp5_plane_state(new_state);
0467
0468 new_state->fb = old_fb;
0469 }
0470
0471 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
0472 .prepare_fb = mdp5_plane_prepare_fb,
0473 .cleanup_fb = mdp5_plane_cleanup_fb,
0474 .atomic_check = mdp5_plane_atomic_check,
0475 .atomic_update = mdp5_plane_atomic_update,
0476 .atomic_async_check = mdp5_plane_atomic_async_check,
0477 .atomic_async_update = mdp5_plane_atomic_async_update,
0478 };
0479
0480 static void set_scanout_locked(struct mdp5_kms *mdp5_kms,
0481 enum mdp5_pipe pipe,
0482 struct drm_framebuffer *fb)
0483 {
0484 struct msm_kms *kms = &mdp5_kms->base.base;
0485
0486 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
0487 MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
0488 MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
0489
0490 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
0491 MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
0492 MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
0493
0494 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
0495 msm_framebuffer_iova(fb, kms->aspace, 0));
0496 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
0497 msm_framebuffer_iova(fb, kms->aspace, 1));
0498 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
0499 msm_framebuffer_iova(fb, kms->aspace, 2));
0500 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
0501 msm_framebuffer_iova(fb, kms->aspace, 3));
0502 }
0503
0504
0505 static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
0506 {
0507 uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
0508 ~MDP5_PIPE_OP_MODE_CSC_1_EN;
0509
0510 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
0511 }
0512
0513
0514 static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
0515 struct csc_cfg *csc)
0516 {
0517 uint32_t i, mode = 0;
0518 uint32_t *matrix;
0519
0520 if (unlikely(!csc))
0521 return;
0522
0523 if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
0524 mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
0525 if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
0526 mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
0527 mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
0528 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
0529
0530 matrix = csc->matrix;
0531 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
0532 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
0533 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
0534 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
0535 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
0536 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
0537 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
0538 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
0539 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
0540 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
0541 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
0542 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
0543 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
0544 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
0545
0546 for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
0547 uint32_t *pre_clamp = csc->pre_clamp;
0548 uint32_t *post_clamp = csc->post_clamp;
0549
0550 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
0551 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
0552 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
0553
0554 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
0555 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
0556 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
0557
0558 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
0559 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
0560
0561 mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
0562 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
0563 }
0564 }
0565
0566 #define PHASE_STEP_SHIFT 21
0567 #define DOWN_SCALE_RATIO_MAX 32
0568
0569 static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
0570 {
0571 uint32_t unit;
0572
0573 if (src == 0 || dst == 0)
0574 return -EINVAL;
0575
0576
0577
0578
0579
0580
0581
0582 if (src > (dst * DOWN_SCALE_RATIO_MAX))
0583 return -EOVERFLOW;
0584
0585 unit = 1 << PHASE_STEP_SHIFT;
0586 *out_phase = mult_frac(unit, src, dst);
0587
0588 return 0;
0589 }
0590
0591 static int calc_scalex_steps(struct drm_plane *plane,
0592 uint32_t pixel_format, uint32_t src, uint32_t dest,
0593 uint32_t phasex_steps[COMP_MAX])
0594 {
0595 const struct drm_format_info *info = drm_format_info(pixel_format);
0596 struct mdp5_kms *mdp5_kms = get_kms(plane);
0597 struct device *dev = mdp5_kms->dev->dev;
0598 uint32_t phasex_step;
0599 int ret;
0600
0601 ret = calc_phase_step(src, dest, &phasex_step);
0602 if (ret) {
0603 DRM_DEV_ERROR(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
0604 return ret;
0605 }
0606
0607 phasex_steps[COMP_0] = phasex_step;
0608 phasex_steps[COMP_3] = phasex_step;
0609 phasex_steps[COMP_1_2] = phasex_step / info->hsub;
0610
0611 return 0;
0612 }
0613
0614 static int calc_scaley_steps(struct drm_plane *plane,
0615 uint32_t pixel_format, uint32_t src, uint32_t dest,
0616 uint32_t phasey_steps[COMP_MAX])
0617 {
0618 const struct drm_format_info *info = drm_format_info(pixel_format);
0619 struct mdp5_kms *mdp5_kms = get_kms(plane);
0620 struct device *dev = mdp5_kms->dev->dev;
0621 uint32_t phasey_step;
0622 int ret;
0623
0624 ret = calc_phase_step(src, dest, &phasey_step);
0625 if (ret) {
0626 DRM_DEV_ERROR(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
0627 return ret;
0628 }
0629
0630 phasey_steps[COMP_0] = phasey_step;
0631 phasey_steps[COMP_3] = phasey_step;
0632 phasey_steps[COMP_1_2] = phasey_step / info->vsub;
0633
0634 return 0;
0635 }
0636
0637 static uint32_t get_scale_config(const struct mdp_format *format,
0638 uint32_t src, uint32_t dst, bool horz)
0639 {
0640 const struct drm_format_info *info = drm_format_info(format->base.pixel_format);
0641 bool scaling = format->is_yuv ? true : (src != dst);
0642 uint32_t sub;
0643 uint32_t ya_filter, uv_filter;
0644 bool yuv = format->is_yuv;
0645
0646 if (!scaling)
0647 return 0;
0648
0649 if (yuv) {
0650 sub = horz ? info->hsub : info->vsub;
0651 uv_filter = ((src / sub) <= dst) ?
0652 SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
0653 }
0654 ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
0655
0656 if (horz)
0657 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
0658 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
0659 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
0660 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
0661 else
0662 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
0663 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
0664 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
0665 COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
0666 }
0667
0668 static void calc_pixel_ext(const struct mdp_format *format,
0669 uint32_t src, uint32_t dst, uint32_t phase_step[2],
0670 int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
0671 bool horz)
0672 {
0673 bool scaling = format->is_yuv ? true : (src != dst);
0674 int i;
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 for (i = 0; i < COMP_MAX; i++) {
0685 pix_ext_edge1[i] = 0;
0686 pix_ext_edge2[i] = scaling ? 1 : 0;
0687 }
0688 }
0689
0690 static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
0691 const struct mdp_format *format,
0692 uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
0693 uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
0694 {
0695 const struct drm_format_info *info = drm_format_info(format->base.pixel_format);
0696 uint32_t lr, tb, req;
0697 int i;
0698
0699 for (i = 0; i < COMP_MAX; i++) {
0700 uint32_t roi_w = src_w;
0701 uint32_t roi_h = src_h;
0702
0703 if (format->is_yuv && i == COMP_1_2) {
0704 roi_w /= info->hsub;
0705 roi_h /= info->vsub;
0706 }
0707
0708 lr = (pe_left[i] >= 0) ?
0709 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
0710 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
0711
0712 lr |= (pe_right[i] >= 0) ?
0713 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
0714 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
0715
0716 tb = (pe_top[i] >= 0) ?
0717 MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
0718 MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
0719
0720 tb |= (pe_bottom[i] >= 0) ?
0721 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
0722 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
0723
0724 req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
0725 pe_left[i] + pe_right[i]);
0726
0727 req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
0728 pe_top[i] + pe_bottom[i]);
0729
0730 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
0731 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
0732 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
0733
0734 DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
0735 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
0736 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
0737 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
0738 FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
0739 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
0740
0741 DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
0742 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
0743 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
0744 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
0745 FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
0746 FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
0747 }
0748 }
0749
0750 struct pixel_ext {
0751 int left[COMP_MAX];
0752 int right[COMP_MAX];
0753 int top[COMP_MAX];
0754 int bottom[COMP_MAX];
0755 };
0756
0757 struct phase_step {
0758 u32 x[COMP_MAX];
0759 u32 y[COMP_MAX];
0760 };
0761
0762 static void mdp5_hwpipe_mode_set(struct mdp5_kms *mdp5_kms,
0763 struct mdp5_hw_pipe *hwpipe,
0764 struct drm_framebuffer *fb,
0765 struct phase_step *step,
0766 struct pixel_ext *pe,
0767 u32 scale_config, u32 hdecm, u32 vdecm,
0768 bool hflip, bool vflip,
0769 int crtc_x, int crtc_y,
0770 unsigned int crtc_w, unsigned int crtc_h,
0771 u32 src_img_w, u32 src_img_h,
0772 u32 src_x, u32 src_y,
0773 u32 src_w, u32 src_h)
0774 {
0775 enum mdp5_pipe pipe = hwpipe->pipe;
0776 bool has_pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
0777 const struct mdp_format *format =
0778 to_mdp_format(msm_framebuffer_format(fb));
0779
0780 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
0781 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_img_w) |
0782 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_img_h));
0783
0784 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
0785 MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
0786 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
0787
0788 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
0789 MDP5_PIPE_SRC_XY_X(src_x) |
0790 MDP5_PIPE_SRC_XY_Y(src_y));
0791
0792 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
0793 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
0794 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
0795
0796 mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
0797 MDP5_PIPE_OUT_XY_X(crtc_x) |
0798 MDP5_PIPE_OUT_XY_Y(crtc_y));
0799
0800 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
0801 MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
0802 MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
0803 MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
0804 MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
0805 COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
0806 MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
0807 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
0808 COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
0809 MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
0810 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
0811
0812 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
0813 MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
0814 MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
0815 MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
0816 MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
0817
0818 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
0819 (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
0820 (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
0821 COND(has_pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
0822 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
0823
0824
0825 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
0826
0827 if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
0828 mdp5_write_pixel_ext(mdp5_kms, pipe, format,
0829 src_w, pe->left, pe->right,
0830 src_h, pe->top, pe->bottom);
0831
0832 if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
0833 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
0834 step->x[COMP_0]);
0835 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
0836 step->y[COMP_0]);
0837 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
0838 step->x[COMP_1_2]);
0839 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
0840 step->y[COMP_1_2]);
0841 mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
0842 MDP5_PIPE_DECIMATION_VERT(vdecm) |
0843 MDP5_PIPE_DECIMATION_HORZ(hdecm));
0844 mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
0845 scale_config);
0846 }
0847
0848 if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
0849 if (MDP_FORMAT_IS_YUV(format))
0850 csc_enable(mdp5_kms, pipe,
0851 mdp_get_default_csc_cfg(CSC_YUV2RGB));
0852 else
0853 csc_disable(mdp5_kms, pipe);
0854 }
0855
0856 set_scanout_locked(mdp5_kms, pipe, fb);
0857 }
0858
0859 static int mdp5_plane_mode_set(struct drm_plane *plane,
0860 struct drm_crtc *crtc, struct drm_framebuffer *fb,
0861 struct drm_rect *src, struct drm_rect *dest)
0862 {
0863 struct drm_plane_state *pstate = plane->state;
0864 struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
0865 struct mdp5_kms *mdp5_kms = get_kms(plane);
0866 enum mdp5_pipe pipe = hwpipe->pipe;
0867 struct mdp5_hw_pipe *right_hwpipe;
0868 const struct mdp_format *format;
0869 uint32_t nplanes, config = 0;
0870 struct phase_step step = { { 0 } };
0871 struct pixel_ext pe = { { 0 } };
0872 uint32_t hdecm = 0, vdecm = 0;
0873 uint32_t pix_format;
0874 unsigned int rotation;
0875 bool vflip, hflip;
0876 int crtc_x, crtc_y;
0877 unsigned int crtc_w, crtc_h;
0878 uint32_t src_x, src_y;
0879 uint32_t src_w, src_h;
0880 uint32_t src_img_w, src_img_h;
0881 int ret;
0882
0883 nplanes = fb->format->num_planes;
0884
0885
0886 if (WARN_ON(nplanes > pipe2nclients(pipe)))
0887 return -EINVAL;
0888
0889 format = to_mdp_format(msm_framebuffer_format(fb));
0890 pix_format = format->base.pixel_format;
0891
0892 src_x = src->x1;
0893 src_y = src->y1;
0894 src_w = drm_rect_width(src);
0895 src_h = drm_rect_height(src);
0896
0897 crtc_x = dest->x1;
0898 crtc_y = dest->y1;
0899 crtc_w = drm_rect_width(dest);
0900 crtc_h = drm_rect_height(dest);
0901
0902
0903 src_x = src_x >> 16;
0904 src_y = src_y >> 16;
0905 src_w = src_w >> 16;
0906 src_h = src_h >> 16;
0907
0908 src_img_w = min(fb->width, src_w);
0909 src_img_h = min(fb->height, src_h);
0910
0911 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name,
0912 fb->base.id, src_x, src_y, src_w, src_h,
0913 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
0914
0915 right_hwpipe = to_mdp5_plane_state(pstate)->r_hwpipe;
0916 if (right_hwpipe) {
0917
0918
0919
0920
0921
0922 crtc_w /= 2;
0923 src_w /= 2;
0924 src_img_w /= 2;
0925 }
0926
0927 ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, step.x);
0928 if (ret)
0929 return ret;
0930
0931 ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, step.y);
0932 if (ret)
0933 return ret;
0934
0935 if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
0936 calc_pixel_ext(format, src_w, crtc_w, step.x,
0937 pe.left, pe.right, true);
0938 calc_pixel_ext(format, src_h, crtc_h, step.y,
0939 pe.top, pe.bottom, false);
0940 }
0941
0942
0943
0944
0945 config |= get_scale_config(format, src_w, crtc_w, true);
0946 config |= get_scale_config(format, src_h, crtc_h, false);
0947 DBG("scale config = %x", config);
0948
0949 rotation = drm_rotation_simplify(pstate->rotation,
0950 DRM_MODE_ROTATE_0 |
0951 DRM_MODE_REFLECT_X |
0952 DRM_MODE_REFLECT_Y);
0953 hflip = !!(rotation & DRM_MODE_REFLECT_X);
0954 vflip = !!(rotation & DRM_MODE_REFLECT_Y);
0955
0956 mdp5_hwpipe_mode_set(mdp5_kms, hwpipe, fb, &step, &pe,
0957 config, hdecm, vdecm, hflip, vflip,
0958 crtc_x, crtc_y, crtc_w, crtc_h,
0959 src_img_w, src_img_h,
0960 src_x, src_y, src_w, src_h);
0961 if (right_hwpipe)
0962 mdp5_hwpipe_mode_set(mdp5_kms, right_hwpipe, fb, &step, &pe,
0963 config, hdecm, vdecm, hflip, vflip,
0964 crtc_x + crtc_w, crtc_y, crtc_w, crtc_h,
0965 src_img_w, src_img_h,
0966 src_x + src_w, src_y, src_w, src_h);
0967
0968 return ret;
0969 }
0970
0971
0972
0973
0974
0975 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
0976 {
0977 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
0978
0979 if (WARN_ON(!pstate->hwpipe))
0980 return SSPP_NONE;
0981
0982 return pstate->hwpipe->pipe;
0983 }
0984
0985 enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane)
0986 {
0987 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
0988
0989 if (!pstate->r_hwpipe)
0990 return SSPP_NONE;
0991
0992 return pstate->r_hwpipe->pipe;
0993 }
0994
0995 uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
0996 {
0997 struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
0998 u32 mask;
0999
1000 if (WARN_ON(!pstate->hwpipe))
1001 return 0;
1002
1003 mask = pstate->hwpipe->flush_mask;
1004
1005 if (pstate->r_hwpipe)
1006 mask |= pstate->r_hwpipe->flush_mask;
1007
1008 return mask;
1009 }
1010
1011
1012 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
1013 enum drm_plane_type type)
1014 {
1015 struct drm_plane *plane = NULL;
1016 struct mdp5_plane *mdp5_plane;
1017 int ret;
1018
1019 mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
1020 if (!mdp5_plane) {
1021 ret = -ENOMEM;
1022 goto fail;
1023 }
1024
1025 plane = &mdp5_plane->base;
1026
1027 mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
1028 ARRAY_SIZE(mdp5_plane->formats), false);
1029
1030 ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
1031 mdp5_plane->formats, mdp5_plane->nformats,
1032 NULL, type, NULL);
1033 if (ret)
1034 goto fail;
1035
1036 drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
1037
1038 mdp5_plane_install_properties(plane, &plane->base);
1039
1040 drm_plane_enable_fb_damage_clips(plane);
1041
1042 return plane;
1043
1044 fail:
1045 if (plane)
1046 mdp5_plane_destroy(plane);
1047
1048 return ERR_PTR(ret);
1049 }