1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_damage_helper.h> 9 #include <drm/drm_fourcc.h> 10 #include <drm/drm_framebuffer.h> 11 #include <drm/drm_gem_atomic_helper.h> 12 13 #include "mdp4_kms.h" 14 15 #define DOWN_SCALE_MAX 8 16 #define UP_SCALE_MAX 8 17 18 struct mdp4_plane { 19 struct drm_plane base; 20 const char *name; 21 22 enum mdp4_pipe pipe; 23 }; 24 #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base) 25 26 /* MDP format helper functions */ 27 static inline 28 enum mdp4_frame_format mdp4_get_frame_format(struct drm_framebuffer *fb) 29 { 30 bool is_tile = false; 31 32 if (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE) 33 is_tile = true; 34 35 if (fb->format->format == DRM_FORMAT_NV12 && is_tile) 36 return FRAME_TILE_YCBCR_420; 37 38 return FRAME_LINEAR; 39 } 40 41 static void mdp4_plane_set_scanout(struct drm_plane *plane, 42 struct drm_framebuffer *fb); 43 static int mdp4_plane_mode_set(struct drm_plane *plane, 44 struct drm_crtc *crtc, struct drm_framebuffer *fb, 45 int crtc_x, int crtc_y, 46 unsigned int crtc_w, unsigned int crtc_h, 47 uint32_t src_x, uint32_t src_y, 48 uint32_t src_w, uint32_t src_h); 49 50 static struct mdp4_kms *get_kms(struct drm_plane *plane) 51 { 52 struct msm_drm_private *priv = plane->dev->dev_private; 53 return to_mdp4_kms(to_mdp_kms(priv->kms)); 54 } 55 56 /* helper to install properties which are common to planes and crtcs */ 57 static void mdp4_plane_install_properties(struct drm_plane *plane, 58 struct drm_mode_object *obj) 59 { 60 // XXX 61 } 62 63 static int mdp4_plane_set_property(struct drm_plane *plane, 64 struct drm_property *property, uint64_t val) 65 { 66 // XXX 67 return -EINVAL; 68 } 69 70 static const struct drm_plane_funcs mdp4_plane_funcs = { 71 .update_plane = drm_atomic_helper_update_plane, 72 .disable_plane = drm_atomic_helper_disable_plane, 73 .set_property = mdp4_plane_set_property, 74 .reset = drm_atomic_helper_plane_reset, 75 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 76 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 77 }; 78 79 static int mdp4_plane_prepare_fb(struct drm_plane *plane, 80 struct drm_plane_state *new_state) 81 { 82 if (!new_state->fb) 83 return 0; 84 85 drm_gem_plane_helper_prepare_fb(plane, new_state); 86 87 return msm_framebuffer_prepare(new_state->fb, false); 88 } 89 90 static void mdp4_plane_cleanup_fb(struct drm_plane *plane, 91 struct drm_plane_state *old_state) 92 { 93 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); 94 struct drm_framebuffer *fb = old_state->fb; 95 96 if (!fb) 97 return; 98 99 DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id); 100 msm_framebuffer_cleanup(fb, false); 101 } 102 103 104 static int mdp4_plane_atomic_check(struct drm_plane *plane, 105 struct drm_atomic_state *state) 106 { 107 return 0; 108 } 109 110 static void mdp4_plane_atomic_update(struct drm_plane *plane, 111 struct drm_atomic_state *state) 112 { 113 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 114 plane); 115 int ret; 116 117 ret = mdp4_plane_mode_set(plane, 118 new_state->crtc, new_state->fb, 119 new_state->crtc_x, new_state->crtc_y, 120 new_state->crtc_w, new_state->crtc_h, 121 new_state->src_x, new_state->src_y, 122 new_state->src_w, new_state->src_h); 123 /* atomic_check should have ensured that this doesn't fail */ 124 WARN_ON(ret < 0); 125 } 126 127 static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs = { 128 .prepare_fb = mdp4_plane_prepare_fb, 129 .cleanup_fb = mdp4_plane_cleanup_fb, 130 .atomic_check = mdp4_plane_atomic_check, 131 .atomic_update = mdp4_plane_atomic_update, 132 }; 133 134 static void mdp4_plane_set_scanout(struct drm_plane *plane, 135 struct drm_framebuffer *fb) 136 { 137 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); 138 struct mdp4_kms *mdp4_kms = get_kms(plane); 139 enum mdp4_pipe pipe = mdp4_plane->pipe; 140 141 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe), 142 MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | 143 MDP4_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); 144 145 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_B(pipe), 146 MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | 147 MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); 148 149 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), 150 msm_framebuffer_iova(fb, 0)); 151 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe), 152 msm_framebuffer_iova(fb, 1)); 153 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe), 154 msm_framebuffer_iova(fb, 2)); 155 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe), 156 msm_framebuffer_iova(fb, 3)); 157 } 158 159 static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms, 160 enum mdp4_pipe pipe, struct csc_cfg *csc) 161 { 162 int i; 163 164 for (i = 0; i < ARRAY_SIZE(csc->matrix); i++) { 165 mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_MV(pipe, i), 166 csc->matrix[i]); 167 } 168 169 for (i = 0; i < ARRAY_SIZE(csc->post_bias) ; i++) { 170 mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_BV(pipe, i), 171 csc->pre_bias[i]); 172 173 mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_BV(pipe, i), 174 csc->post_bias[i]); 175 } 176 177 for (i = 0; i < ARRAY_SIZE(csc->post_clamp) ; i++) { 178 mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_LV(pipe, i), 179 csc->pre_clamp[i]); 180 181 mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_LV(pipe, i), 182 csc->post_clamp[i]); 183 } 184 } 185 186 #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 187 188 static int mdp4_plane_mode_set(struct drm_plane *plane, 189 struct drm_crtc *crtc, struct drm_framebuffer *fb, 190 int crtc_x, int crtc_y, 191 unsigned int crtc_w, unsigned int crtc_h, 192 uint32_t src_x, uint32_t src_y, 193 uint32_t src_w, uint32_t src_h) 194 { 195 struct drm_device *dev = plane->dev; 196 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); 197 struct mdp4_kms *mdp4_kms = get_kms(plane); 198 enum mdp4_pipe pipe = mdp4_plane->pipe; 199 const struct msm_format *format; 200 uint32_t op_mode = 0; 201 uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; 202 uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; 203 enum mdp4_frame_format frame_type; 204 205 if (!(crtc && fb)) { 206 DBG("%s: disabled!", mdp4_plane->name); 207 return 0; 208 } 209 210 frame_type = mdp4_get_frame_format(fb); 211 212 /* src values are in Q16 fixed point, convert to integer: */ 213 src_x = src_x >> 16; 214 src_y = src_y >> 16; 215 src_w = src_w >> 16; 216 src_h = src_h >> 16; 217 218 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name, 219 fb->base.id, src_x, src_y, src_w, src_h, 220 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); 221 222 format = msm_framebuffer_format(fb); 223 224 if (src_w > (crtc_w * DOWN_SCALE_MAX)) { 225 DRM_DEV_ERROR(dev->dev, "Width down scaling exceeds limits!\n"); 226 return -ERANGE; 227 } 228 229 if (src_h > (crtc_h * DOWN_SCALE_MAX)) { 230 DRM_DEV_ERROR(dev->dev, "Height down scaling exceeds limits!\n"); 231 return -ERANGE; 232 } 233 234 if (crtc_w > (src_w * UP_SCALE_MAX)) { 235 DRM_DEV_ERROR(dev->dev, "Width up scaling exceeds limits!\n"); 236 return -ERANGE; 237 } 238 239 if (crtc_h > (src_h * UP_SCALE_MAX)) { 240 DRM_DEV_ERROR(dev->dev, "Height up scaling exceeds limits!\n"); 241 return -ERANGE; 242 } 243 244 if (src_w != crtc_w) { 245 uint32_t sel_unit = SCALE_FIR; 246 op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; 247 248 if (MSM_FORMAT_IS_YUV(format)) { 249 if (crtc_w > src_w) 250 sel_unit = SCALE_PIXEL_RPT; 251 else if (crtc_w <= (src_w / 4)) 252 sel_unit = SCALE_MN_PHASE; 253 254 op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit); 255 phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, 256 src_w, crtc_w); 257 } 258 } 259 260 if (src_h != crtc_h) { 261 uint32_t sel_unit = SCALE_FIR; 262 op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; 263 264 if (MSM_FORMAT_IS_YUV(format)) { 265 266 if (crtc_h > src_h) 267 sel_unit = SCALE_PIXEL_RPT; 268 else if (crtc_h <= (src_h / 4)) 269 sel_unit = SCALE_MN_PHASE; 270 271 op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit); 272 phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, 273 src_h, crtc_h); 274 } 275 } 276 277 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), 278 MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | 279 MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); 280 281 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), 282 MDP4_PIPE_SRC_XY_X(src_x) | 283 MDP4_PIPE_SRC_XY_Y(src_y)); 284 285 mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), 286 MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | 287 MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); 288 289 mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), 290 MDP4_PIPE_DST_XY_X(crtc_x) | 291 MDP4_PIPE_DST_XY_Y(crtc_y)); 292 293 mdp4_plane_set_scanout(plane, fb); 294 295 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), 296 MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | 297 MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r_cr) | 298 MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g_y) | 299 MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b_cb) | 300 COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | 301 MDP4_PIPE_SRC_FORMAT_CPP(format->bpp - 1) | 302 MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | 303 MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) | 304 MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) | 305 MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) | 306 COND(format->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT, 307 MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); 308 309 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), 310 MDP4_PIPE_SRC_UNPACK_ELEM0(format->element[0]) | 311 MDP4_PIPE_SRC_UNPACK_ELEM1(format->element[1]) | 312 MDP4_PIPE_SRC_UNPACK_ELEM2(format->element[2]) | 313 MDP4_PIPE_SRC_UNPACK_ELEM3(format->element[3])); 314 315 if (MSM_FORMAT_IS_YUV(format)) { 316 struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB); 317 318 op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR; 319 op_mode |= MDP4_PIPE_OP_MODE_CSC_EN; 320 mdp4_write_csc_config(mdp4_kms, pipe, csc); 321 } 322 323 mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); 324 mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); 325 mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); 326 327 if (frame_type != FRAME_LINEAR) 328 mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe), 329 MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) | 330 MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h)); 331 332 return 0; 333 } 334 335 static const char *pipe_names[] = { 336 "VG1", "VG2", 337 "RGB1", "RGB2", "RGB3", 338 "VG3", "VG4", 339 }; 340 341 enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane) 342 { 343 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); 344 return mdp4_plane->pipe; 345 } 346 347 static const uint64_t supported_format_modifiers[] = { 348 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 349 DRM_FORMAT_MOD_LINEAR, 350 DRM_FORMAT_MOD_INVALID 351 }; 352 353 static const uint32_t mdp4_rgb_formats[] = { 354 DRM_FORMAT_ARGB8888, 355 DRM_FORMAT_ABGR8888, 356 DRM_FORMAT_RGBA8888, 357 DRM_FORMAT_BGRA8888, 358 DRM_FORMAT_XRGB8888, 359 DRM_FORMAT_XBGR8888, 360 DRM_FORMAT_RGBX8888, 361 DRM_FORMAT_BGRX8888, 362 DRM_FORMAT_RGB888, 363 DRM_FORMAT_BGR888, 364 DRM_FORMAT_RGB565, 365 DRM_FORMAT_BGR565, 366 }; 367 368 static const uint32_t mdp4_rgb_yuv_formats[] = { 369 DRM_FORMAT_ARGB8888, 370 DRM_FORMAT_ABGR8888, 371 DRM_FORMAT_RGBA8888, 372 DRM_FORMAT_BGRA8888, 373 DRM_FORMAT_XRGB8888, 374 DRM_FORMAT_XBGR8888, 375 DRM_FORMAT_RGBX8888, 376 DRM_FORMAT_BGRX8888, 377 DRM_FORMAT_RGB888, 378 DRM_FORMAT_BGR888, 379 DRM_FORMAT_RGB565, 380 DRM_FORMAT_BGR565, 381 382 DRM_FORMAT_NV12, 383 DRM_FORMAT_NV21, 384 DRM_FORMAT_NV16, 385 DRM_FORMAT_NV61, 386 DRM_FORMAT_VYUY, 387 DRM_FORMAT_UYVY, 388 DRM_FORMAT_YUYV, 389 DRM_FORMAT_YVYU, 390 DRM_FORMAT_YUV420, 391 DRM_FORMAT_YVU420, 392 }; 393 394 /* initialize plane */ 395 struct drm_plane *mdp4_plane_init(struct drm_device *dev, 396 enum mdp4_pipe pipe_id, bool private_plane) 397 { 398 struct drm_plane *plane = NULL; 399 struct mdp4_plane *mdp4_plane; 400 enum drm_plane_type type; 401 uint32_t pipe_caps; 402 const uint32_t *formats; 403 size_t nformats; 404 405 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 406 407 pipe_caps = mdp4_pipe_caps(pipe_id); 408 if (pipe_supports_yuv(pipe_caps)) { 409 formats = mdp4_rgb_yuv_formats; 410 nformats = ARRAY_SIZE(mdp4_rgb_yuv_formats); 411 } else { 412 formats = mdp4_rgb_formats; 413 nformats = ARRAY_SIZE(mdp4_rgb_formats); 414 } 415 416 mdp4_plane = drmm_universal_plane_alloc(dev, struct mdp4_plane, base, 417 0xff, &mdp4_plane_funcs, 418 formats, nformats, 419 supported_format_modifiers, 420 type, NULL); 421 if (IS_ERR(mdp4_plane)) 422 return ERR_CAST(mdp4_plane); 423 424 plane = &mdp4_plane->base; 425 426 mdp4_plane->pipe = pipe_id; 427 mdp4_plane->name = pipe_names[pipe_id]; 428 429 drm_plane_helper_add(plane, &mdp4_plane_helper_funcs); 430 431 mdp4_plane_install_properties(plane, &plane->base); 432 433 drm_plane_enable_fb_damage_clips(plane); 434 435 return plane; 436 } 437