1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net> 4 */ 5 6 #include <drm/drm_atomic.h> 7 #include <drm/drm_atomic_helper.h> 8 #include <drm/drm_blend.h> 9 #include <drm/drm_crtc.h> 10 #include <drm/drm_fb_dma_helper.h> 11 #include <drm/drm_framebuffer.h> 12 #include <drm/drm_gem_atomic_helper.h> 13 #include <drm/drm_gem_dma_helper.h> 14 #include <drm/drm_print.h> 15 #include <drm/drm_probe_helper.h> 16 17 #include "sun4i_crtc.h" 18 #include "sun8i_csc.h" 19 #include "sun8i_mixer.h" 20 #include "sun8i_vi_layer.h" 21 #include "sun8i_vi_scaler.h" 22 23 static void sun8i_vi_layer_disable(struct sun8i_layer *layer) 24 { 25 u32 ch_base = sun8i_channel_base(layer); 26 27 regmap_write(layer->regs, 28 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), 0); 29 } 30 31 static void sun8i_vi_layer_update_attributes(struct sun8i_layer *layer, 32 struct drm_plane *plane) 33 { 34 struct drm_plane_state *state = plane->state; 35 const struct drm_format_info *fmt; 36 u32 val, ch_base, hw_fmt; 37 38 ch_base = sun8i_channel_base(layer); 39 fmt = state->fb->format; 40 sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); 41 42 val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET; 43 if (!fmt->is_yuv) 44 val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE; 45 val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN; 46 if (layer->cfg->de_type >= SUN8I_MIXER_DE3) { 47 val |= SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(state->alpha >> 8); 48 val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ? 49 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_PIXEL : 50 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_COMBINED; 51 } 52 53 regmap_write(layer->regs, 54 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), val); 55 56 if (layer->cfg->de2_fcc_alpha) { 57 regmap_write(layer->regs, 58 SUN8I_MIXER_FCC_GLOBAL_ALPHA_REG, 59 SUN8I_MIXER_FCC_GLOBAL_ALPHA(state->alpha >> 8)); 60 } 61 } 62 63 static void sun8i_vi_layer_update_coord(struct sun8i_layer *layer, 64 struct drm_plane *plane) 65 { 66 struct drm_plane_state *state = plane->state; 67 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(state->crtc); 68 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(scrtc->engine); 69 const struct drm_format_info *format = state->fb->format; 70 u32 src_w, src_h, dst_w, dst_h; 71 u32 outsize, insize; 72 u32 hphase, vphase; 73 u32 hn = 0, hm = 0; 74 u32 vn = 0, vm = 0; 75 bool subsampled; 76 u32 ch_base; 77 78 DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n", 79 layer->channel, layer->overlay); 80 81 ch_base = sun8i_channel_base(layer); 82 83 src_w = drm_rect_width(&state->src) >> 16; 84 src_h = drm_rect_height(&state->src) >> 16; 85 dst_w = drm_rect_width(&state->dst); 86 dst_h = drm_rect_height(&state->dst); 87 88 hphase = state->src.x1 & 0xffff; 89 vphase = state->src.y1 & 0xffff; 90 91 /* make coordinates dividable by subsampling factor */ 92 if (format->hsub > 1) { 93 int mask, remainder; 94 95 mask = format->hsub - 1; 96 remainder = (state->src.x1 >> 16) & mask; 97 src_w = (src_w + remainder) & ~mask; 98 hphase += remainder << 16; 99 } 100 101 if (format->vsub > 1) { 102 int mask, remainder; 103 104 mask = format->vsub - 1; 105 remainder = (state->src.y1 >> 16) & mask; 106 src_h = (src_h + remainder) & ~mask; 107 vphase += remainder << 16; 108 } 109 110 insize = SUN8I_MIXER_SIZE(src_w, src_h); 111 outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); 112 113 /* Set height and width */ 114 DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", 115 (state->src.x1 >> 16) & ~(format->hsub - 1), 116 (state->src.y1 >> 16) & ~(format->vsub - 1)); 117 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 118 regmap_write(layer->regs, 119 SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, layer->overlay), 120 insize); 121 regmap_write(layer->regs, 122 SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base), 123 insize); 124 125 /* 126 * Scaler must be enabled for subsampled formats, so it scales 127 * chroma to same size as luma. 128 */ 129 subsampled = format->hsub > 1 || format->vsub > 1; 130 131 if (insize != outsize || subsampled || hphase || vphase) { 132 unsigned int scanline, required; 133 struct drm_display_mode *mode; 134 u32 hscale, vscale, fps; 135 u64 ability; 136 137 DRM_DEBUG_DRIVER("HW scaling is enabled\n"); 138 139 mode = &plane->state->crtc->state->mode; 140 fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal); 141 ability = clk_get_rate(mixer->mod_clk); 142 /* BSP algorithm assumes 80% efficiency of VI scaler unit */ 143 ability *= 80; 144 do_div(ability, mode->vdisplay * fps * max(src_w, dst_w)); 145 146 required = src_h * 100 / dst_h; 147 148 if (ability < required) { 149 DRM_DEBUG_DRIVER("Using vertical coarse scaling\n"); 150 vm = src_h; 151 vn = (u32)ability * dst_h / 100; 152 src_h = vn; 153 } 154 155 /* it seems that every RGB scaler has buffer for 2048 pixels */ 156 scanline = subsampled ? layer->cfg->scanline_yuv : 2048; 157 158 if (src_w > scanline) { 159 DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n"); 160 hm = src_w; 161 hn = scanline; 162 src_w = hn; 163 } 164 165 hscale = (src_w << 16) / dst_w; 166 vscale = (src_h << 16) / dst_h; 167 168 sun8i_vi_scaler_setup(layer, src_w, src_h, dst_w, dst_h, 169 hscale, vscale, hphase, vphase, format); 170 sun8i_vi_scaler_enable(layer, true); 171 } else { 172 DRM_DEBUG_DRIVER("HW scaling is not needed\n"); 173 sun8i_vi_scaler_enable(layer, false); 174 } 175 176 regmap_write(layer->regs, 177 SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base), 178 SUN8I_MIXER_CHAN_VI_DS_N(hn) | 179 SUN8I_MIXER_CHAN_VI_DS_M(hm)); 180 regmap_write(layer->regs, 181 SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base), 182 SUN8I_MIXER_CHAN_VI_DS_N(hn) | 183 SUN8I_MIXER_CHAN_VI_DS_M(hm)); 184 regmap_write(layer->regs, 185 SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base), 186 SUN8I_MIXER_CHAN_VI_DS_N(vn) | 187 SUN8I_MIXER_CHAN_VI_DS_M(vm)); 188 regmap_write(layer->regs, 189 SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base), 190 SUN8I_MIXER_CHAN_VI_DS_N(vn) | 191 SUN8I_MIXER_CHAN_VI_DS_M(vm)); 192 } 193 194 static void sun8i_vi_layer_update_buffer(struct sun8i_layer *layer, 195 struct drm_plane *plane) 196 { 197 struct drm_plane_state *state = plane->state; 198 struct drm_framebuffer *fb = state->fb; 199 const struct drm_format_info *format = fb->format; 200 dma_addr_t dma_addr; 201 u32 ch_base; 202 int i; 203 204 ch_base = sun8i_channel_base(layer); 205 206 for (i = 0; i < format->num_planes; i++) { 207 /* Get the start of the displayed memory */ 208 dma_addr = drm_fb_dma_get_gem_addr(fb, state, i); 209 210 /* Set the line width */ 211 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", 212 i + 1, fb->pitches[i]); 213 regmap_write(layer->regs, 214 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base, 215 layer->overlay, i), 216 fb->pitches[i]); 217 218 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n", 219 i + 1, &dma_addr); 220 221 regmap_write(layer->regs, 222 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base, 223 layer->overlay, i), 224 lower_32_bits(dma_addr)); 225 } 226 } 227 228 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, 229 struct drm_atomic_state *state) 230 { 231 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 232 plane); 233 struct sun8i_layer *layer = plane_to_sun8i_layer(plane); 234 struct drm_crtc *crtc = new_plane_state->crtc; 235 struct drm_crtc_state *crtc_state; 236 const struct drm_format_info *fmt; 237 int min_scale, max_scale, ret; 238 u32 hw_fmt; 239 240 if (!crtc) 241 return 0; 242 243 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 244 if (WARN_ON(!crtc_state)) 245 return -EINVAL; 246 247 fmt = new_plane_state->fb->format; 248 ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); 249 if (ret) { 250 DRM_DEBUG_DRIVER("Invalid plane format\n"); 251 return ret; 252 } 253 254 min_scale = DRM_PLANE_NO_SCALING; 255 max_scale = DRM_PLANE_NO_SCALING; 256 257 if (layer->cfg->scaler_mask & BIT(layer->channel)) { 258 min_scale = SUN8I_VI_SCALER_SCALE_MIN; 259 max_scale = SUN8I_VI_SCALER_SCALE_MAX; 260 } 261 262 return drm_atomic_helper_check_plane_state(new_plane_state, 263 crtc_state, 264 min_scale, max_scale, 265 true, true); 266 } 267 268 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, 269 struct drm_atomic_state *state) 270 { 271 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 272 plane); 273 struct sun8i_layer *layer = plane_to_sun8i_layer(plane); 274 275 if (!new_state->crtc || !new_state->visible) { 276 sun8i_vi_layer_disable(layer); 277 return; 278 } 279 280 sun8i_vi_layer_update_attributes(layer, plane); 281 sun8i_vi_layer_update_coord(layer, plane); 282 sun8i_csc_config(layer, new_state); 283 sun8i_vi_layer_update_buffer(layer, plane); 284 } 285 286 static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { 287 .atomic_check = sun8i_vi_layer_atomic_check, 288 .atomic_update = sun8i_vi_layer_atomic_update, 289 }; 290 291 static const struct drm_plane_funcs sun8i_vi_layer_funcs = { 292 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 293 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 294 .destroy = drm_plane_cleanup, 295 .disable_plane = drm_atomic_helper_disable_plane, 296 .reset = drm_atomic_helper_plane_reset, 297 .update_plane = drm_atomic_helper_update_plane, 298 }; 299 300 /* 301 * While DE2 VI layer supports same RGB formats as UI layer, alpha 302 * channel is ignored. This structure lists all unique variants 303 * where alpha channel is replaced with "don't care" (X) channel. 304 */ 305 static const u32 sun8i_vi_layer_formats[] = { 306 DRM_FORMAT_BGR565, 307 DRM_FORMAT_BGR888, 308 DRM_FORMAT_BGRX4444, 309 DRM_FORMAT_BGRX5551, 310 DRM_FORMAT_BGRX8888, 311 DRM_FORMAT_RGB565, 312 DRM_FORMAT_RGB888, 313 DRM_FORMAT_RGBX4444, 314 DRM_FORMAT_RGBX5551, 315 DRM_FORMAT_RGBX8888, 316 DRM_FORMAT_XBGR1555, 317 DRM_FORMAT_XBGR4444, 318 DRM_FORMAT_XBGR8888, 319 DRM_FORMAT_XRGB1555, 320 DRM_FORMAT_XRGB4444, 321 DRM_FORMAT_XRGB8888, 322 323 DRM_FORMAT_NV16, 324 DRM_FORMAT_NV12, 325 DRM_FORMAT_NV21, 326 DRM_FORMAT_NV61, 327 DRM_FORMAT_UYVY, 328 DRM_FORMAT_VYUY, 329 DRM_FORMAT_YUYV, 330 DRM_FORMAT_YVYU, 331 DRM_FORMAT_YUV411, 332 DRM_FORMAT_YUV420, 333 DRM_FORMAT_YUV422, 334 DRM_FORMAT_YVU411, 335 DRM_FORMAT_YVU420, 336 DRM_FORMAT_YVU422, 337 }; 338 339 static const u32 sun8i_vi_layer_de3_formats[] = { 340 DRM_FORMAT_ABGR1555, 341 DRM_FORMAT_ABGR2101010, 342 DRM_FORMAT_ABGR4444, 343 DRM_FORMAT_ABGR8888, 344 DRM_FORMAT_ARGB1555, 345 DRM_FORMAT_ARGB2101010, 346 DRM_FORMAT_ARGB4444, 347 DRM_FORMAT_ARGB8888, 348 DRM_FORMAT_BGR565, 349 DRM_FORMAT_BGR888, 350 DRM_FORMAT_BGRA1010102, 351 DRM_FORMAT_BGRA5551, 352 DRM_FORMAT_BGRA4444, 353 DRM_FORMAT_BGRA8888, 354 DRM_FORMAT_BGRX8888, 355 DRM_FORMAT_RGB565, 356 DRM_FORMAT_RGB888, 357 DRM_FORMAT_RGBA1010102, 358 DRM_FORMAT_RGBA4444, 359 DRM_FORMAT_RGBA5551, 360 DRM_FORMAT_RGBA8888, 361 DRM_FORMAT_RGBX8888, 362 DRM_FORMAT_XBGR8888, 363 DRM_FORMAT_XRGB8888, 364 365 DRM_FORMAT_NV16, 366 DRM_FORMAT_NV12, 367 DRM_FORMAT_NV21, 368 DRM_FORMAT_NV61, 369 DRM_FORMAT_P010, 370 DRM_FORMAT_P210, 371 DRM_FORMAT_UYVY, 372 DRM_FORMAT_VYUY, 373 DRM_FORMAT_YUYV, 374 DRM_FORMAT_YVYU, 375 DRM_FORMAT_YUV411, 376 DRM_FORMAT_YUV420, 377 DRM_FORMAT_YUV422, 378 DRM_FORMAT_YVU411, 379 DRM_FORMAT_YVU420, 380 DRM_FORMAT_YVU422, 381 }; 382 383 static const uint64_t sun8i_layer_modifiers[] = { 384 DRM_FORMAT_MOD_LINEAR, 385 DRM_FORMAT_MOD_INVALID 386 }; 387 388 struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm, 389 enum drm_plane_type type, 390 struct regmap *regs, 391 int index, int phy_index, 392 int plane_cnt, 393 const struct sun8i_layer_cfg *cfg) 394 { 395 u32 supported_encodings, supported_ranges; 396 unsigned int format_count; 397 struct sun8i_layer *layer; 398 const u32 *formats; 399 int ret; 400 401 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 402 if (!layer) 403 return ERR_PTR(-ENOMEM); 404 405 layer->type = SUN8I_LAYER_TYPE_VI; 406 layer->index = index; 407 layer->channel = phy_index; 408 layer->overlay = 0; 409 layer->regs = regs; 410 layer->cfg = cfg; 411 412 if (layer->cfg->de_type >= SUN8I_MIXER_DE3) { 413 formats = sun8i_vi_layer_de3_formats; 414 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats); 415 } else { 416 formats = sun8i_vi_layer_formats; 417 format_count = ARRAY_SIZE(sun8i_vi_layer_formats); 418 } 419 420 /* possible crtcs are set later */ 421 ret = drm_universal_plane_init(drm, &layer->plane, 0, 422 &sun8i_vi_layer_funcs, 423 formats, format_count, 424 sun8i_layer_modifiers, 425 type, NULL); 426 if (ret) { 427 dev_err(drm->dev, "Couldn't initialize layer\n"); 428 return ERR_PTR(ret); 429 } 430 431 if (layer->cfg->de2_fcc_alpha || layer->cfg->de_type >= SUN8I_MIXER_DE3) { 432 ret = drm_plane_create_alpha_property(&layer->plane); 433 if (ret) { 434 dev_err(drm->dev, "Couldn't add alpha property\n"); 435 return ERR_PTR(ret); 436 } 437 } 438 439 ret = drm_plane_create_zpos_property(&layer->plane, index, 440 0, plane_cnt - 1); 441 if (ret) { 442 dev_err(drm->dev, "Couldn't add zpos property\n"); 443 return ERR_PTR(ret); 444 } 445 446 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) | 447 BIT(DRM_COLOR_YCBCR_BT709); 448 if (layer->cfg->de_type >= SUN8I_MIXER_DE3) 449 supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020); 450 451 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | 452 BIT(DRM_COLOR_YCBCR_FULL_RANGE); 453 454 ret = drm_plane_create_color_properties(&layer->plane, 455 supported_encodings, 456 supported_ranges, 457 DRM_COLOR_YCBCR_BT709, 458 DRM_COLOR_YCBCR_LIMITED_RANGE); 459 if (ret) { 460 dev_err(drm->dev, "Couldn't add encoding and range properties!\n"); 461 return ERR_PTR(ret); 462 } 463 464 drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs); 465 466 return layer; 467 } 468