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