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 struct drm_gem_dma_object *gem; 201 u32 dx, dy, src_x, src_y; 202 dma_addr_t dma_addr; 203 u32 ch_base; 204 int i; 205 206 ch_base = sun8i_channel_base(layer); 207 208 /* Adjust x and y to be dividable by subsampling factor */ 209 src_x = (state->src.x1 >> 16) & ~(format->hsub - 1); 210 src_y = (state->src.y1 >> 16) & ~(format->vsub - 1); 211 212 for (i = 0; i < format->num_planes; i++) { 213 /* Get the physical address of the buffer in memory */ 214 gem = drm_fb_dma_get_gem_obj(fb, i); 215 216 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); 217 218 /* Compute the start of the displayed memory */ 219 dma_addr = gem->dma_addr + fb->offsets[i]; 220 221 dx = src_x; 222 dy = src_y; 223 224 if (i > 0) { 225 dx /= format->hsub; 226 dy /= format->vsub; 227 } 228 229 /* Fixup framebuffer address for src coordinates */ 230 dma_addr += dx * format->cpp[i]; 231 dma_addr += dy * fb->pitches[i]; 232 233 /* Set the line width */ 234 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", 235 i + 1, fb->pitches[i]); 236 regmap_write(layer->regs, 237 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base, 238 layer->overlay, i), 239 fb->pitches[i]); 240 241 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n", 242 i + 1, &dma_addr); 243 244 regmap_write(layer->regs, 245 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base, 246 layer->overlay, i), 247 lower_32_bits(dma_addr)); 248 } 249 } 250 251 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, 252 struct drm_atomic_state *state) 253 { 254 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 255 plane); 256 struct sun8i_layer *layer = plane_to_sun8i_layer(plane); 257 struct drm_crtc *crtc = new_plane_state->crtc; 258 struct drm_crtc_state *crtc_state; 259 const struct drm_format_info *fmt; 260 int min_scale, max_scale, ret; 261 u32 hw_fmt; 262 263 if (!crtc) 264 return 0; 265 266 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 267 if (WARN_ON(!crtc_state)) 268 return -EINVAL; 269 270 fmt = new_plane_state->fb->format; 271 ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); 272 if (ret) { 273 DRM_DEBUG_DRIVER("Invalid plane format\n"); 274 return ret; 275 } 276 277 min_scale = DRM_PLANE_NO_SCALING; 278 max_scale = DRM_PLANE_NO_SCALING; 279 280 if (layer->cfg->scaler_mask & BIT(layer->channel)) { 281 min_scale = SUN8I_VI_SCALER_SCALE_MIN; 282 max_scale = SUN8I_VI_SCALER_SCALE_MAX; 283 } 284 285 return drm_atomic_helper_check_plane_state(new_plane_state, 286 crtc_state, 287 min_scale, max_scale, 288 true, true); 289 } 290 291 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, 292 struct drm_atomic_state *state) 293 { 294 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 295 plane); 296 struct sun8i_layer *layer = plane_to_sun8i_layer(plane); 297 298 if (!new_state->crtc || !new_state->visible) { 299 sun8i_vi_layer_disable(layer); 300 return; 301 } 302 303 sun8i_vi_layer_update_attributes(layer, plane); 304 sun8i_vi_layer_update_coord(layer, plane); 305 sun8i_csc_config(layer, new_state); 306 sun8i_vi_layer_update_buffer(layer, plane); 307 } 308 309 static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { 310 .atomic_check = sun8i_vi_layer_atomic_check, 311 .atomic_update = sun8i_vi_layer_atomic_update, 312 }; 313 314 static const struct drm_plane_funcs sun8i_vi_layer_funcs = { 315 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 316 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 317 .destroy = drm_plane_cleanup, 318 .disable_plane = drm_atomic_helper_disable_plane, 319 .reset = drm_atomic_helper_plane_reset, 320 .update_plane = drm_atomic_helper_update_plane, 321 }; 322 323 /* 324 * While DE2 VI layer supports same RGB formats as UI layer, alpha 325 * channel is ignored. This structure lists all unique variants 326 * where alpha channel is replaced with "don't care" (X) channel. 327 */ 328 static const u32 sun8i_vi_layer_formats[] = { 329 DRM_FORMAT_BGR565, 330 DRM_FORMAT_BGR888, 331 DRM_FORMAT_BGRX4444, 332 DRM_FORMAT_BGRX5551, 333 DRM_FORMAT_BGRX8888, 334 DRM_FORMAT_RGB565, 335 DRM_FORMAT_RGB888, 336 DRM_FORMAT_RGBX4444, 337 DRM_FORMAT_RGBX5551, 338 DRM_FORMAT_RGBX8888, 339 DRM_FORMAT_XBGR1555, 340 DRM_FORMAT_XBGR4444, 341 DRM_FORMAT_XBGR8888, 342 DRM_FORMAT_XRGB1555, 343 DRM_FORMAT_XRGB4444, 344 DRM_FORMAT_XRGB8888, 345 346 DRM_FORMAT_NV16, 347 DRM_FORMAT_NV12, 348 DRM_FORMAT_NV21, 349 DRM_FORMAT_NV61, 350 DRM_FORMAT_UYVY, 351 DRM_FORMAT_VYUY, 352 DRM_FORMAT_YUYV, 353 DRM_FORMAT_YVYU, 354 DRM_FORMAT_YUV411, 355 DRM_FORMAT_YUV420, 356 DRM_FORMAT_YUV422, 357 DRM_FORMAT_YVU411, 358 DRM_FORMAT_YVU420, 359 DRM_FORMAT_YVU422, 360 }; 361 362 static const u32 sun8i_vi_layer_de3_formats[] = { 363 DRM_FORMAT_ABGR1555, 364 DRM_FORMAT_ABGR2101010, 365 DRM_FORMAT_ABGR4444, 366 DRM_FORMAT_ABGR8888, 367 DRM_FORMAT_ARGB1555, 368 DRM_FORMAT_ARGB2101010, 369 DRM_FORMAT_ARGB4444, 370 DRM_FORMAT_ARGB8888, 371 DRM_FORMAT_BGR565, 372 DRM_FORMAT_BGR888, 373 DRM_FORMAT_BGRA1010102, 374 DRM_FORMAT_BGRA5551, 375 DRM_FORMAT_BGRA4444, 376 DRM_FORMAT_BGRA8888, 377 DRM_FORMAT_BGRX8888, 378 DRM_FORMAT_RGB565, 379 DRM_FORMAT_RGB888, 380 DRM_FORMAT_RGBA1010102, 381 DRM_FORMAT_RGBA4444, 382 DRM_FORMAT_RGBA5551, 383 DRM_FORMAT_RGBA8888, 384 DRM_FORMAT_RGBX8888, 385 DRM_FORMAT_XBGR8888, 386 DRM_FORMAT_XRGB8888, 387 388 DRM_FORMAT_NV16, 389 DRM_FORMAT_NV12, 390 DRM_FORMAT_NV21, 391 DRM_FORMAT_NV61, 392 DRM_FORMAT_P010, 393 DRM_FORMAT_P210, 394 DRM_FORMAT_UYVY, 395 DRM_FORMAT_VYUY, 396 DRM_FORMAT_YUYV, 397 DRM_FORMAT_YVYU, 398 DRM_FORMAT_YUV411, 399 DRM_FORMAT_YUV420, 400 DRM_FORMAT_YUV422, 401 DRM_FORMAT_YVU411, 402 DRM_FORMAT_YVU420, 403 DRM_FORMAT_YVU422, 404 }; 405 406 static const uint64_t sun8i_layer_modifiers[] = { 407 DRM_FORMAT_MOD_LINEAR, 408 DRM_FORMAT_MOD_INVALID 409 }; 410 411 struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm, 412 enum drm_plane_type type, 413 struct regmap *regs, 414 int index, int phy_index, 415 int plane_cnt, 416 const struct sun8i_layer_cfg *cfg) 417 { 418 u32 supported_encodings, supported_ranges; 419 unsigned int format_count; 420 struct sun8i_layer *layer; 421 const u32 *formats; 422 int ret; 423 424 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 425 if (!layer) 426 return ERR_PTR(-ENOMEM); 427 428 layer->type = SUN8I_LAYER_TYPE_VI; 429 layer->index = index; 430 layer->channel = phy_index; 431 layer->overlay = 0; 432 layer->regs = regs; 433 layer->cfg = cfg; 434 435 if (layer->cfg->de_type >= SUN8I_MIXER_DE3) { 436 formats = sun8i_vi_layer_de3_formats; 437 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats); 438 } else { 439 formats = sun8i_vi_layer_formats; 440 format_count = ARRAY_SIZE(sun8i_vi_layer_formats); 441 } 442 443 /* possible crtcs are set later */ 444 ret = drm_universal_plane_init(drm, &layer->plane, 0, 445 &sun8i_vi_layer_funcs, 446 formats, format_count, 447 sun8i_layer_modifiers, 448 type, NULL); 449 if (ret) { 450 dev_err(drm->dev, "Couldn't initialize layer\n"); 451 return ERR_PTR(ret); 452 } 453 454 if (layer->cfg->de2_fcc_alpha || layer->cfg->de_type >= SUN8I_MIXER_DE3) { 455 ret = drm_plane_create_alpha_property(&layer->plane); 456 if (ret) { 457 dev_err(drm->dev, "Couldn't add alpha property\n"); 458 return ERR_PTR(ret); 459 } 460 } 461 462 ret = drm_plane_create_zpos_property(&layer->plane, index, 463 0, plane_cnt - 1); 464 if (ret) { 465 dev_err(drm->dev, "Couldn't add zpos property\n"); 466 return ERR_PTR(ret); 467 } 468 469 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) | 470 BIT(DRM_COLOR_YCBCR_BT709); 471 if (layer->cfg->de_type >= SUN8I_MIXER_DE3) 472 supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020); 473 474 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | 475 BIT(DRM_COLOR_YCBCR_FULL_RANGE); 476 477 ret = drm_plane_create_color_properties(&layer->plane, 478 supported_encodings, 479 supported_ranges, 480 DRM_COLOR_YCBCR_BT709, 481 DRM_COLOR_YCBCR_LIMITED_RANGE); 482 if (ret) { 483 dev_err(drm->dev, "Couldn't add encoding and range properties!\n"); 484 return ERR_PTR(ret); 485 } 486 487 drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs); 488 489 return layer; 490 } 491