| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2015 Broadcom |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | 4 | */ |
|---|
| 8 | 5 | |
|---|
| 9 | 6 | /** |
|---|
| .. | .. |
|---|
| 20 | 17 | |
|---|
| 21 | 18 | #include <drm/drm_atomic.h> |
|---|
| 22 | 19 | #include <drm/drm_atomic_helper.h> |
|---|
| 20 | +#include <drm/drm_atomic_uapi.h> |
|---|
| 23 | 21 | #include <drm/drm_fb_cma_helper.h> |
|---|
| 22 | +#include <drm/drm_fourcc.h> |
|---|
| 23 | +#include <drm/drm_gem_framebuffer_helper.h> |
|---|
| 24 | 24 | #include <drm/drm_plane_helper.h> |
|---|
| 25 | 25 | |
|---|
| 26 | 26 | #include "uapi/drm/vc4_drm.h" |
|---|
| 27 | + |
|---|
| 27 | 28 | #include "vc4_drv.h" |
|---|
| 28 | 29 | #include "vc4_regs.h" |
|---|
| 29 | 30 | |
|---|
| .. | .. |
|---|
| 31 | 32 | u32 drm; /* DRM_FORMAT_* */ |
|---|
| 32 | 33 | u32 hvs; /* HVS_FORMAT_* */ |
|---|
| 33 | 34 | u32 pixel_order; |
|---|
| 35 | + u32 pixel_order_hvs5; |
|---|
| 34 | 36 | } hvs_formats[] = { |
|---|
| 35 | 37 | { |
|---|
| 36 | | - .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 38 | + .drm = DRM_FORMAT_XRGB8888, |
|---|
| 39 | + .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 37 | 40 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
|---|
| 41 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, |
|---|
| 38 | 42 | }, |
|---|
| 39 | 43 | { |
|---|
| 40 | | - .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 44 | + .drm = DRM_FORMAT_ARGB8888, |
|---|
| 45 | + .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 41 | 46 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
|---|
| 47 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, |
|---|
| 42 | 48 | }, |
|---|
| 43 | 49 | { |
|---|
| 44 | | - .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 50 | + .drm = DRM_FORMAT_ABGR8888, |
|---|
| 51 | + .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 45 | 52 | .pixel_order = HVS_PIXEL_ORDER_ARGB, |
|---|
| 53 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, |
|---|
| 46 | 54 | }, |
|---|
| 47 | 55 | { |
|---|
| 48 | | - .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 56 | + .drm = DRM_FORMAT_XBGR8888, |
|---|
| 57 | + .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
|---|
| 49 | 58 | .pixel_order = HVS_PIXEL_ORDER_ARGB, |
|---|
| 59 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, |
|---|
| 50 | 60 | }, |
|---|
| 51 | 61 | { |
|---|
| 52 | | - .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, |
|---|
| 62 | + .drm = DRM_FORMAT_RGB565, |
|---|
| 63 | + .hvs = HVS_PIXEL_FORMAT_RGB565, |
|---|
| 53 | 64 | .pixel_order = HVS_PIXEL_ORDER_XRGB, |
|---|
| 54 | 65 | }, |
|---|
| 55 | 66 | { |
|---|
| 56 | | - .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, |
|---|
| 67 | + .drm = DRM_FORMAT_BGR565, |
|---|
| 68 | + .hvs = HVS_PIXEL_FORMAT_RGB565, |
|---|
| 57 | 69 | .pixel_order = HVS_PIXEL_ORDER_XBGR, |
|---|
| 58 | 70 | }, |
|---|
| 59 | 71 | { |
|---|
| 60 | | - .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
|---|
| 72 | + .drm = DRM_FORMAT_ARGB1555, |
|---|
| 73 | + .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
|---|
| 61 | 74 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
|---|
| 75 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, |
|---|
| 62 | 76 | }, |
|---|
| 63 | 77 | { |
|---|
| 64 | | - .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
|---|
| 78 | + .drm = DRM_FORMAT_XRGB1555, |
|---|
| 79 | + .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
|---|
| 65 | 80 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
|---|
| 81 | + .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, |
|---|
| 66 | 82 | }, |
|---|
| 67 | 83 | { |
|---|
| 68 | | - .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, |
|---|
| 84 | + .drm = DRM_FORMAT_RGB888, |
|---|
| 85 | + .hvs = HVS_PIXEL_FORMAT_RGB888, |
|---|
| 69 | 86 | .pixel_order = HVS_PIXEL_ORDER_XRGB, |
|---|
| 70 | 87 | }, |
|---|
| 71 | 88 | { |
|---|
| 72 | | - .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, |
|---|
| 89 | + .drm = DRM_FORMAT_BGR888, |
|---|
| 90 | + .hvs = HVS_PIXEL_FORMAT_RGB888, |
|---|
| 73 | 91 | .pixel_order = HVS_PIXEL_ORDER_XBGR, |
|---|
| 74 | 92 | }, |
|---|
| 75 | 93 | { |
|---|
| .. | .. |
|---|
| 128 | 146 | |
|---|
| 129 | 147 | static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) |
|---|
| 130 | 148 | { |
|---|
| 131 | | - if (dst > src) |
|---|
| 132 | | - return VC4_SCALING_PPF; |
|---|
| 133 | | - else if (dst < src) |
|---|
| 134 | | - return VC4_SCALING_TPZ; |
|---|
| 135 | | - else |
|---|
| 149 | + if (dst == src) |
|---|
| 136 | 150 | return VC4_SCALING_NONE; |
|---|
| 151 | + if (3 * dst >= 2 * src) |
|---|
| 152 | + return VC4_SCALING_PPF; |
|---|
| 153 | + else |
|---|
| 154 | + return VC4_SCALING_TPZ; |
|---|
| 137 | 155 | } |
|---|
| 138 | 156 | |
|---|
| 139 | 157 | static bool plane_enabled(struct drm_plane_state *state) |
|---|
| 140 | 158 | { |
|---|
| 141 | | - return state->fb && state->crtc; |
|---|
| 159 | + return state->fb && !WARN_ON(!state->crtc); |
|---|
| 142 | 160 | } |
|---|
| 143 | 161 | |
|---|
| 144 | 162 | static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) |
|---|
| .. | .. |
|---|
| 153 | 171 | return NULL; |
|---|
| 154 | 172 | |
|---|
| 155 | 173 | memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); |
|---|
| 174 | + vc4_state->dlist_initialized = 0; |
|---|
| 156 | 175 | |
|---|
| 157 | 176 | __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); |
|---|
| 158 | 177 | |
|---|
| .. | .. |
|---|
| 176 | 195 | struct vc4_dev *vc4 = to_vc4_dev(plane->dev); |
|---|
| 177 | 196 | struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); |
|---|
| 178 | 197 | |
|---|
| 179 | | - if (vc4_state->lbm.allocated) { |
|---|
| 198 | + if (drm_mm_node_allocated(&vc4_state->lbm)) { |
|---|
| 180 | 199 | unsigned long irqflags; |
|---|
| 181 | 200 | |
|---|
| 182 | 201 | spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); |
|---|
| .. | .. |
|---|
| 200 | 219 | if (!vc4_state) |
|---|
| 201 | 220 | return; |
|---|
| 202 | 221 | |
|---|
| 203 | | - plane->state = &vc4_state->base; |
|---|
| 204 | | - plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE; |
|---|
| 205 | | - vc4_state->base.plane = plane; |
|---|
| 222 | + __drm_atomic_helper_plane_reset(plane, &vc4_state->base); |
|---|
| 206 | 223 | } |
|---|
| 207 | 224 | |
|---|
| 208 | | -static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) |
|---|
| 225 | +static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state) |
|---|
| 209 | 226 | { |
|---|
| 210 | 227 | if (vc4_state->dlist_count == vc4_state->dlist_size) { |
|---|
| 211 | 228 | u32 new_size = max(4u, vc4_state->dlist_count * 2); |
|---|
| .. | .. |
|---|
| 220 | 237 | vc4_state->dlist_size = new_size; |
|---|
| 221 | 238 | } |
|---|
| 222 | 239 | |
|---|
| 223 | | - vc4_state->dlist[vc4_state->dlist_count++] = val; |
|---|
| 240 | + vc4_state->dlist_count++; |
|---|
| 241 | +} |
|---|
| 242 | + |
|---|
| 243 | +static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) |
|---|
| 244 | +{ |
|---|
| 245 | + unsigned int idx = vc4_state->dlist_count; |
|---|
| 246 | + |
|---|
| 247 | + vc4_dlist_counter_increment(vc4_state); |
|---|
| 248 | + vc4_state->dlist[idx] = val; |
|---|
| 224 | 249 | } |
|---|
| 225 | 250 | |
|---|
| 226 | 251 | /* Returns the scl0/scl1 field based on whether the dimensions need to |
|---|
| .. | .. |
|---|
| 258 | 283 | } |
|---|
| 259 | 284 | } |
|---|
| 260 | 285 | |
|---|
| 286 | +static int vc4_plane_margins_adj(struct drm_plane_state *pstate) |
|---|
| 287 | +{ |
|---|
| 288 | + struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate); |
|---|
| 289 | + unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay; |
|---|
| 290 | + struct drm_crtc_state *crtc_state; |
|---|
| 291 | + |
|---|
| 292 | + crtc_state = drm_atomic_get_new_crtc_state(pstate->state, |
|---|
| 293 | + pstate->crtc); |
|---|
| 294 | + |
|---|
| 295 | + vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom); |
|---|
| 296 | + if (!left && !right && !top && !bottom) |
|---|
| 297 | + return 0; |
|---|
| 298 | + |
|---|
| 299 | + if (left + right >= crtc_state->mode.hdisplay || |
|---|
| 300 | + top + bottom >= crtc_state->mode.vdisplay) |
|---|
| 301 | + return -EINVAL; |
|---|
| 302 | + |
|---|
| 303 | + adjhdisplay = crtc_state->mode.hdisplay - (left + right); |
|---|
| 304 | + vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x * |
|---|
| 305 | + adjhdisplay, |
|---|
| 306 | + crtc_state->mode.hdisplay); |
|---|
| 307 | + vc4_pstate->crtc_x += left; |
|---|
| 308 | + if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right) |
|---|
| 309 | + vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right; |
|---|
| 310 | + |
|---|
| 311 | + adjvdisplay = crtc_state->mode.vdisplay - (top + bottom); |
|---|
| 312 | + vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y * |
|---|
| 313 | + adjvdisplay, |
|---|
| 314 | + crtc_state->mode.vdisplay); |
|---|
| 315 | + vc4_pstate->crtc_y += top; |
|---|
| 316 | + if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom) |
|---|
| 317 | + vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom; |
|---|
| 318 | + |
|---|
| 319 | + vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w * |
|---|
| 320 | + adjhdisplay, |
|---|
| 321 | + crtc_state->mode.hdisplay); |
|---|
| 322 | + vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h * |
|---|
| 323 | + adjvdisplay, |
|---|
| 324 | + crtc_state->mode.vdisplay); |
|---|
| 325 | + |
|---|
| 326 | + if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h) |
|---|
| 327 | + return -EINVAL; |
|---|
| 328 | + |
|---|
| 329 | + return 0; |
|---|
| 330 | +} |
|---|
| 331 | + |
|---|
| 261 | 332 | static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) |
|---|
| 262 | 333 | { |
|---|
| 263 | | - struct drm_plane *plane = state->plane; |
|---|
| 264 | 334 | struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); |
|---|
| 265 | 335 | struct drm_framebuffer *fb = state->fb; |
|---|
| 266 | 336 | struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); |
|---|
| 267 | | - u32 subpixel_src_mask = (1 << 16) - 1; |
|---|
| 268 | | - u32 format = fb->format->format; |
|---|
| 269 | 337 | int num_planes = fb->format->num_planes; |
|---|
| 270 | | - u32 h_subsample = 1; |
|---|
| 271 | | - u32 v_subsample = 1; |
|---|
| 272 | | - int i; |
|---|
| 338 | + struct drm_crtc_state *crtc_state; |
|---|
| 339 | + u32 h_subsample = fb->format->hsub; |
|---|
| 340 | + u32 v_subsample = fb->format->vsub; |
|---|
| 341 | + int i, ret; |
|---|
| 342 | + |
|---|
| 343 | + crtc_state = drm_atomic_get_existing_crtc_state(state->state, |
|---|
| 344 | + state->crtc); |
|---|
| 345 | + if (!crtc_state) { |
|---|
| 346 | + DRM_DEBUG_KMS("Invalid crtc state\n"); |
|---|
| 347 | + return -EINVAL; |
|---|
| 348 | + } |
|---|
| 349 | + |
|---|
| 350 | + ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1, |
|---|
| 351 | + INT_MAX, true, true); |
|---|
| 352 | + if (ret) |
|---|
| 353 | + return ret; |
|---|
| 273 | 354 | |
|---|
| 274 | 355 | for (i = 0; i < num_planes; i++) |
|---|
| 275 | 356 | vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; |
|---|
| 276 | 357 | |
|---|
| 277 | | - /* We don't support subpixel source positioning for scaling. */ |
|---|
| 278 | | - if ((state->src_x & subpixel_src_mask) || |
|---|
| 279 | | - (state->src_y & subpixel_src_mask) || |
|---|
| 280 | | - (state->src_w & subpixel_src_mask) || |
|---|
| 281 | | - (state->src_h & subpixel_src_mask)) { |
|---|
| 282 | | - return -EINVAL; |
|---|
| 283 | | - } |
|---|
| 358 | + /* |
|---|
| 359 | + * We don't support subpixel source positioning for scaling, |
|---|
| 360 | + * but fractional coordinates can be generated by clipping |
|---|
| 361 | + * so just round for now |
|---|
| 362 | + */ |
|---|
| 363 | + vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1 << 16); |
|---|
| 364 | + vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1 << 16); |
|---|
| 365 | + vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x; |
|---|
| 366 | + vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y; |
|---|
| 284 | 367 | |
|---|
| 285 | | - vc4_state->src_x = state->src_x >> 16; |
|---|
| 286 | | - vc4_state->src_y = state->src_y >> 16; |
|---|
| 287 | | - vc4_state->src_w[0] = state->src_w >> 16; |
|---|
| 288 | | - vc4_state->src_h[0] = state->src_h >> 16; |
|---|
| 368 | + vc4_state->crtc_x = state->dst.x1; |
|---|
| 369 | + vc4_state->crtc_y = state->dst.y1; |
|---|
| 370 | + vc4_state->crtc_w = state->dst.x2 - state->dst.x1; |
|---|
| 371 | + vc4_state->crtc_h = state->dst.y2 - state->dst.y1; |
|---|
| 289 | 372 | |
|---|
| 290 | | - vc4_state->crtc_x = state->crtc_x; |
|---|
| 291 | | - vc4_state->crtc_y = state->crtc_y; |
|---|
| 292 | | - vc4_state->crtc_w = state->crtc_w; |
|---|
| 293 | | - vc4_state->crtc_h = state->crtc_h; |
|---|
| 373 | + ret = vc4_plane_margins_adj(state); |
|---|
| 374 | + if (ret) |
|---|
| 375 | + return ret; |
|---|
| 294 | 376 | |
|---|
| 295 | 377 | vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], |
|---|
| 296 | 378 | vc4_state->crtc_w); |
|---|
| .. | .. |
|---|
| 303 | 385 | if (num_planes > 1) { |
|---|
| 304 | 386 | vc4_state->is_yuv = true; |
|---|
| 305 | 387 | |
|---|
| 306 | | - h_subsample = drm_format_horz_chroma_subsampling(format); |
|---|
| 307 | | - v_subsample = drm_format_vert_chroma_subsampling(format); |
|---|
| 308 | 388 | vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample; |
|---|
| 309 | 389 | vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample; |
|---|
| 310 | 390 | |
|---|
| .. | .. |
|---|
| 327 | 407 | vc4_state->is_yuv = false; |
|---|
| 328 | 408 | vc4_state->x_scaling[1] = VC4_SCALING_NONE; |
|---|
| 329 | 409 | vc4_state->y_scaling[1] = VC4_SCALING_NONE; |
|---|
| 330 | | - } |
|---|
| 331 | | - |
|---|
| 332 | | - /* No configuring scaling on the cursor plane, since it gets |
|---|
| 333 | | - non-vblank-synced updates, and scaling requires requires |
|---|
| 334 | | - LBM changes which have to be vblank-synced. |
|---|
| 335 | | - */ |
|---|
| 336 | | - if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity) |
|---|
| 337 | | - return -EINVAL; |
|---|
| 338 | | - |
|---|
| 339 | | - /* Clamp the on-screen start x/y to 0. The hardware doesn't |
|---|
| 340 | | - * support negative y, and negative x wastes bandwidth. |
|---|
| 341 | | - */ |
|---|
| 342 | | - if (vc4_state->crtc_x < 0) { |
|---|
| 343 | | - for (i = 0; i < num_planes; i++) { |
|---|
| 344 | | - u32 cpp = fb->format->cpp[i]; |
|---|
| 345 | | - u32 subs = ((i == 0) ? 1 : h_subsample); |
|---|
| 346 | | - |
|---|
| 347 | | - vc4_state->offsets[i] += (cpp * |
|---|
| 348 | | - (-vc4_state->crtc_x) / subs); |
|---|
| 349 | | - } |
|---|
| 350 | | - vc4_state->src_w[0] += vc4_state->crtc_x; |
|---|
| 351 | | - vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample; |
|---|
| 352 | | - vc4_state->crtc_x = 0; |
|---|
| 353 | | - } |
|---|
| 354 | | - |
|---|
| 355 | | - if (vc4_state->crtc_y < 0) { |
|---|
| 356 | | - for (i = 0; i < num_planes; i++) { |
|---|
| 357 | | - u32 subs = ((i == 0) ? 1 : v_subsample); |
|---|
| 358 | | - |
|---|
| 359 | | - vc4_state->offsets[i] += (fb->pitches[i] * |
|---|
| 360 | | - (-vc4_state->crtc_y) / subs); |
|---|
| 361 | | - } |
|---|
| 362 | | - vc4_state->src_h[0] += vc4_state->crtc_y; |
|---|
| 363 | | - vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample; |
|---|
| 364 | | - vc4_state->crtc_y = 0; |
|---|
| 365 | 410 | } |
|---|
| 366 | 411 | |
|---|
| 367 | 412 | return 0; |
|---|
| .. | .. |
|---|
| 398 | 443 | static u32 vc4_lbm_size(struct drm_plane_state *state) |
|---|
| 399 | 444 | { |
|---|
| 400 | 445 | struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); |
|---|
| 401 | | - /* This is the worst case number. One of the two sizes will |
|---|
| 402 | | - * be used depending on the scaling configuration. |
|---|
| 403 | | - */ |
|---|
| 404 | | - u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); |
|---|
| 446 | + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); |
|---|
| 447 | + u32 pix_per_line; |
|---|
| 405 | 448 | u32 lbm; |
|---|
| 406 | 449 | |
|---|
| 450 | + /* LBM is not needed when there's no vertical scaling. */ |
|---|
| 451 | + if (vc4_state->y_scaling[0] == VC4_SCALING_NONE && |
|---|
| 452 | + vc4_state->y_scaling[1] == VC4_SCALING_NONE) |
|---|
| 453 | + return 0; |
|---|
| 454 | + |
|---|
| 455 | + /* |
|---|
| 456 | + * This can be further optimized in the RGB/YUV444 case if the PPF |
|---|
| 457 | + * decimation factor is between 0.5 and 1.0 by using crtc_w. |
|---|
| 458 | + * |
|---|
| 459 | + * It's not an issue though, since in that case since src_w[0] is going |
|---|
| 460 | + * to be greater than or equal to crtc_w. |
|---|
| 461 | + */ |
|---|
| 462 | + if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ) |
|---|
| 463 | + pix_per_line = vc4_state->crtc_w; |
|---|
| 464 | + else |
|---|
| 465 | + pix_per_line = vc4_state->src_w[0]; |
|---|
| 466 | + |
|---|
| 407 | 467 | if (!vc4_state->is_yuv) { |
|---|
| 408 | | - if (vc4_state->is_unity) |
|---|
| 409 | | - return 0; |
|---|
| 410 | | - else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) |
|---|
| 468 | + if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) |
|---|
| 411 | 469 | lbm = pix_per_line * 8; |
|---|
| 412 | 470 | else { |
|---|
| 413 | 471 | /* In special cases, this multiplier might be 12. */ |
|---|
| .. | .. |
|---|
| 421 | 479 | lbm = pix_per_line * 16; |
|---|
| 422 | 480 | } |
|---|
| 423 | 481 | |
|---|
| 424 | | - lbm = roundup(lbm, 32); |
|---|
| 482 | + /* Align it to 64 or 128 (hvs5) bytes */ |
|---|
| 483 | + lbm = roundup(lbm, vc4->hvs->hvs5 ? 128 : 64); |
|---|
| 484 | + |
|---|
| 485 | + /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */ |
|---|
| 486 | + lbm /= vc4->hvs->hvs5 ? 4 : 2; |
|---|
| 425 | 487 | |
|---|
| 426 | 488 | return lbm; |
|---|
| 427 | 489 | } |
|---|
| .. | .. |
|---|
| 458 | 520 | } |
|---|
| 459 | 521 | } |
|---|
| 460 | 522 | |
|---|
| 523 | +static void vc4_plane_calc_load(struct drm_plane_state *state) |
|---|
| 524 | +{ |
|---|
| 525 | + unsigned int hvs_load_shift, vrefresh, i; |
|---|
| 526 | + struct drm_framebuffer *fb = state->fb; |
|---|
| 527 | + struct vc4_plane_state *vc4_state; |
|---|
| 528 | + struct drm_crtc_state *crtc_state; |
|---|
| 529 | + unsigned int vscale_factor; |
|---|
| 530 | + struct vc4_dev *vc4; |
|---|
| 531 | + |
|---|
| 532 | + vc4 = to_vc4_dev(state->plane->dev); |
|---|
| 533 | + if (!vc4->load_tracker_available) |
|---|
| 534 | + return; |
|---|
| 535 | + |
|---|
| 536 | + vc4_state = to_vc4_plane_state(state); |
|---|
| 537 | + crtc_state = drm_atomic_get_existing_crtc_state(state->state, |
|---|
| 538 | + state->crtc); |
|---|
| 539 | + vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode); |
|---|
| 540 | + |
|---|
| 541 | + /* The HVS is able to process 2 pixels/cycle when scaling the source, |
|---|
| 542 | + * 4 pixels/cycle otherwise. |
|---|
| 543 | + * Alpha blending step seems to be pipelined and it's always operating |
|---|
| 544 | + * at 4 pixels/cycle, so the limiting aspect here seems to be the |
|---|
| 545 | + * scaler block. |
|---|
| 546 | + * HVS load is expressed in clk-cycles/sec (AKA Hz). |
|---|
| 547 | + */ |
|---|
| 548 | + if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || |
|---|
| 549 | + vc4_state->x_scaling[1] != VC4_SCALING_NONE || |
|---|
| 550 | + vc4_state->y_scaling[0] != VC4_SCALING_NONE || |
|---|
| 551 | + vc4_state->y_scaling[1] != VC4_SCALING_NONE) |
|---|
| 552 | + hvs_load_shift = 1; |
|---|
| 553 | + else |
|---|
| 554 | + hvs_load_shift = 2; |
|---|
| 555 | + |
|---|
| 556 | + vc4_state->membus_load = 0; |
|---|
| 557 | + vc4_state->hvs_load = 0; |
|---|
| 558 | + for (i = 0; i < fb->format->num_planes; i++) { |
|---|
| 559 | + /* Even if the bandwidth/plane required for a single frame is |
|---|
| 560 | + * |
|---|
| 561 | + * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh |
|---|
| 562 | + * |
|---|
| 563 | + * when downscaling, we have to read more pixels per line in |
|---|
| 564 | + * the time frame reserved for a single line, so the bandwidth |
|---|
| 565 | + * demand can be punctually higher. To account for that, we |
|---|
| 566 | + * calculate the down-scaling factor and multiply the plane |
|---|
| 567 | + * load by this number. We're likely over-estimating the read |
|---|
| 568 | + * demand, but that's better than under-estimating it. |
|---|
| 569 | + */ |
|---|
| 570 | + vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i], |
|---|
| 571 | + vc4_state->crtc_h); |
|---|
| 572 | + vc4_state->membus_load += vc4_state->src_w[i] * |
|---|
| 573 | + vc4_state->src_h[i] * vscale_factor * |
|---|
| 574 | + fb->format->cpp[i]; |
|---|
| 575 | + vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w; |
|---|
| 576 | + } |
|---|
| 577 | + |
|---|
| 578 | + vc4_state->hvs_load *= vrefresh; |
|---|
| 579 | + vc4_state->hvs_load >>= hvs_load_shift; |
|---|
| 580 | + vc4_state->membus_load *= vrefresh; |
|---|
| 581 | +} |
|---|
| 582 | + |
|---|
| 583 | +static int vc4_plane_allocate_lbm(struct drm_plane_state *state) |
|---|
| 584 | +{ |
|---|
| 585 | + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); |
|---|
| 586 | + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); |
|---|
| 587 | + unsigned long irqflags; |
|---|
| 588 | + u32 lbm_size; |
|---|
| 589 | + |
|---|
| 590 | + lbm_size = vc4_lbm_size(state); |
|---|
| 591 | + if (!lbm_size) |
|---|
| 592 | + return 0; |
|---|
| 593 | + |
|---|
| 594 | + if (WARN_ON(!vc4_state->lbm_offset)) |
|---|
| 595 | + return -EINVAL; |
|---|
| 596 | + |
|---|
| 597 | + /* Allocate the LBM memory that the HVS will use for temporary |
|---|
| 598 | + * storage due to our scaling/format conversion. |
|---|
| 599 | + */ |
|---|
| 600 | + if (!drm_mm_node_allocated(&vc4_state->lbm)) { |
|---|
| 601 | + int ret; |
|---|
| 602 | + |
|---|
| 603 | + spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); |
|---|
| 604 | + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, |
|---|
| 605 | + &vc4_state->lbm, |
|---|
| 606 | + lbm_size, |
|---|
| 607 | + vc4->hvs->hvs5 ? 64 : 32, |
|---|
| 608 | + 0, 0); |
|---|
| 609 | + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); |
|---|
| 610 | + |
|---|
| 611 | + if (ret) |
|---|
| 612 | + return ret; |
|---|
| 613 | + } else { |
|---|
| 614 | + WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); |
|---|
| 615 | + } |
|---|
| 616 | + |
|---|
| 617 | + vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; |
|---|
| 618 | + |
|---|
| 619 | + return 0; |
|---|
| 620 | +} |
|---|
| 621 | + |
|---|
| 461 | 622 | /* Writes out a full display list for an active plane to the plane's |
|---|
| 462 | 623 | * private dlist state. |
|---|
| 463 | 624 | */ |
|---|
| .. | .. |
|---|
| 470 | 631 | u32 ctl0_offset = vc4_state->dlist_count; |
|---|
| 471 | 632 | const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); |
|---|
| 472 | 633 | u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); |
|---|
| 473 | | - int num_planes = drm_format_num_planes(format->drm); |
|---|
| 634 | + int num_planes = fb->format->num_planes; |
|---|
| 635 | + u32 h_subsample = fb->format->hsub; |
|---|
| 636 | + u32 v_subsample = fb->format->vsub; |
|---|
| 474 | 637 | bool mix_plane_alpha; |
|---|
| 475 | 638 | bool covers_screen; |
|---|
| 476 | 639 | u32 scl0, scl1, pitch0; |
|---|
| 477 | | - u32 lbm_size, tiling; |
|---|
| 478 | | - unsigned long irqflags; |
|---|
| 640 | + u32 tiling, src_y; |
|---|
| 479 | 641 | u32 hvs_format = format->hvs; |
|---|
| 642 | + unsigned int rotation; |
|---|
| 480 | 643 | int ret, i; |
|---|
| 481 | 644 | |
|---|
| 645 | + if (vc4_state->dlist_initialized) |
|---|
| 646 | + return 0; |
|---|
| 647 | + |
|---|
| 482 | 648 | ret = vc4_plane_setup_clipping_and_scaling(state); |
|---|
| 483 | | - if (ret) |
|---|
| 484 | | - return ret; |
|---|
| 485 | | - |
|---|
| 486 | | - /* Allocate the LBM memory that the HVS will use for temporary |
|---|
| 487 | | - * storage due to our scaling/format conversion. |
|---|
| 488 | | - */ |
|---|
| 489 | | - lbm_size = vc4_lbm_size(state); |
|---|
| 490 | | - if (lbm_size) { |
|---|
| 491 | | - if (!vc4_state->lbm.allocated) { |
|---|
| 492 | | - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); |
|---|
| 493 | | - ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, |
|---|
| 494 | | - &vc4_state->lbm, |
|---|
| 495 | | - lbm_size, 32, 0, 0); |
|---|
| 496 | | - spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); |
|---|
| 497 | | - } else { |
|---|
| 498 | | - WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); |
|---|
| 499 | | - } |
|---|
| 500 | | - } |
|---|
| 501 | | - |
|---|
| 502 | 649 | if (ret) |
|---|
| 503 | 650 | return ret; |
|---|
| 504 | 651 | |
|---|
| .. | .. |
|---|
| 516 | 663 | scl1 = vc4_get_scl_field(state, 0); |
|---|
| 517 | 664 | } |
|---|
| 518 | 665 | |
|---|
| 666 | + rotation = drm_rotation_simplify(state->rotation, |
|---|
| 667 | + DRM_MODE_ROTATE_0 | |
|---|
| 668 | + DRM_MODE_REFLECT_X | |
|---|
| 669 | + DRM_MODE_REFLECT_Y); |
|---|
| 670 | + |
|---|
| 671 | + /* We must point to the last line when Y reflection is enabled. */ |
|---|
| 672 | + src_y = vc4_state->src_y; |
|---|
| 673 | + if (rotation & DRM_MODE_REFLECT_Y) |
|---|
| 674 | + src_y += vc4_state->src_h[0] - 1; |
|---|
| 675 | + |
|---|
| 519 | 676 | switch (base_format_mod) { |
|---|
| 520 | 677 | case DRM_FORMAT_MOD_LINEAR: |
|---|
| 521 | 678 | tiling = SCALER_CTL0_TILING_LINEAR; |
|---|
| 522 | 679 | pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); |
|---|
| 680 | + |
|---|
| 681 | + /* Adjust the base pointer to the first pixel to be scanned |
|---|
| 682 | + * out. |
|---|
| 683 | + */ |
|---|
| 684 | + for (i = 0; i < num_planes; i++) { |
|---|
| 685 | + vc4_state->offsets[i] += src_y / |
|---|
| 686 | + (i ? v_subsample : 1) * |
|---|
| 687 | + fb->pitches[i]; |
|---|
| 688 | + |
|---|
| 689 | + vc4_state->offsets[i] += vc4_state->src_x / |
|---|
| 690 | + (i ? h_subsample : 1) * |
|---|
| 691 | + fb->format->cpp[i]; |
|---|
| 692 | + } |
|---|
| 693 | + |
|---|
| 523 | 694 | break; |
|---|
| 524 | 695 | |
|---|
| 525 | 696 | case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: { |
|---|
| 526 | | - /* For T-tiled, the FB pitch is "how many bytes from |
|---|
| 527 | | - * one row to the next, such that pitch * tile_h == |
|---|
| 528 | | - * tile_size * tiles_per_row." |
|---|
| 529 | | - */ |
|---|
| 530 | 697 | u32 tile_size_shift = 12; /* T tiles are 4kb */ |
|---|
| 698 | + /* Whole-tile offsets, mostly for setting the pitch. */ |
|---|
| 699 | + u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5; |
|---|
| 531 | 700 | u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */ |
|---|
| 701 | + u32 tile_w_mask = (1 << tile_w_shift) - 1; |
|---|
| 702 | + /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice |
|---|
| 703 | + * the height (in pixels) of a 4k tile. |
|---|
| 704 | + */ |
|---|
| 705 | + u32 tile_h_mask = (2 << tile_h_shift) - 1; |
|---|
| 706 | + /* For T-tiled, the FB pitch is "how many bytes from one row to |
|---|
| 707 | + * the next, such that |
|---|
| 708 | + * |
|---|
| 709 | + * pitch * tile_h == tile_size * tiles_per_row |
|---|
| 710 | + */ |
|---|
| 532 | 711 | u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); |
|---|
| 712 | + u32 tiles_l = vc4_state->src_x >> tile_w_shift; |
|---|
| 713 | + u32 tiles_r = tiles_w - tiles_l; |
|---|
| 714 | + u32 tiles_t = src_y >> tile_h_shift; |
|---|
| 715 | + /* Intra-tile offsets, which modify the base address (the |
|---|
| 716 | + * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that |
|---|
| 717 | + * base address). |
|---|
| 718 | + */ |
|---|
| 719 | + u32 tile_y = (src_y >> 4) & 1; |
|---|
| 720 | + u32 subtile_y = (src_y >> 2) & 3; |
|---|
| 721 | + u32 utile_y = src_y & 3; |
|---|
| 722 | + u32 x_off = vc4_state->src_x & tile_w_mask; |
|---|
| 723 | + u32 y_off = src_y & tile_h_mask; |
|---|
| 724 | + |
|---|
| 725 | + /* When Y reflection is requested we must set the |
|---|
| 726 | + * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines |
|---|
| 727 | + * after the initial one should be fetched in descending order, |
|---|
| 728 | + * which makes sense since we start from the last line and go |
|---|
| 729 | + * backward. |
|---|
| 730 | + * Don't know why we need y_off = max_y_off - y_off, but it's |
|---|
| 731 | + * definitely required (I guess it's also related to the "going |
|---|
| 732 | + * backward" situation). |
|---|
| 733 | + */ |
|---|
| 734 | + if (rotation & DRM_MODE_REFLECT_Y) { |
|---|
| 735 | + y_off = tile_h_mask - y_off; |
|---|
| 736 | + pitch0 = SCALER_PITCH0_TILE_LINE_DIR; |
|---|
| 737 | + } else { |
|---|
| 738 | + pitch0 = 0; |
|---|
| 739 | + } |
|---|
| 533 | 740 | |
|---|
| 534 | 741 | tiling = SCALER_CTL0_TILING_256B_OR_T; |
|---|
| 742 | + pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | |
|---|
| 743 | + VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | |
|---|
| 744 | + VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | |
|---|
| 745 | + VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); |
|---|
| 746 | + vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift); |
|---|
| 747 | + vc4_state->offsets[0] += subtile_y << 8; |
|---|
| 748 | + vc4_state->offsets[0] += utile_y << 4; |
|---|
| 535 | 749 | |
|---|
| 536 | | - pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) | |
|---|
| 537 | | - VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) | |
|---|
| 538 | | - VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R)); |
|---|
| 750 | + /* Rows of tiles alternate left-to-right and right-to-left. */ |
|---|
| 751 | + if (tiles_t & 1) { |
|---|
| 752 | + pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; |
|---|
| 753 | + vc4_state->offsets[0] += (tiles_w - tiles_l) << |
|---|
| 754 | + tile_size_shift; |
|---|
| 755 | + vc4_state->offsets[0] -= (1 + !tile_y) << 10; |
|---|
| 756 | + } else { |
|---|
| 757 | + vc4_state->offsets[0] += tiles_l << tile_size_shift; |
|---|
| 758 | + vc4_state->offsets[0] += tile_y << 10; |
|---|
| 759 | + } |
|---|
| 760 | + |
|---|
| 539 | 761 | break; |
|---|
| 540 | 762 | } |
|---|
| 541 | 763 | |
|---|
| .. | .. |
|---|
| 543 | 765 | case DRM_FORMAT_MOD_BROADCOM_SAND128: |
|---|
| 544 | 766 | case DRM_FORMAT_MOD_BROADCOM_SAND256: { |
|---|
| 545 | 767 | uint32_t param = fourcc_mod_broadcom_param(fb->modifier); |
|---|
| 768 | + u32 tile_w, tile, x_off, pix_per_tile; |
|---|
| 546 | 769 | |
|---|
| 547 | | - /* Column-based NV12 or RGBA. |
|---|
| 548 | | - */ |
|---|
| 549 | | - if (fb->format->num_planes > 1) { |
|---|
| 550 | | - if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) { |
|---|
| 551 | | - DRM_DEBUG_KMS("SAND format only valid for NV12/21"); |
|---|
| 552 | | - return -EINVAL; |
|---|
| 553 | | - } |
|---|
| 554 | | - hvs_format = HVS_PIXEL_FORMAT_H264; |
|---|
| 555 | | - } else { |
|---|
| 556 | | - if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) { |
|---|
| 557 | | - DRM_DEBUG_KMS("SAND256 format only valid for H.264"); |
|---|
| 558 | | - return -EINVAL; |
|---|
| 559 | | - } |
|---|
| 560 | | - } |
|---|
| 770 | + hvs_format = HVS_PIXEL_FORMAT_H264; |
|---|
| 561 | 771 | |
|---|
| 562 | 772 | switch (base_format_mod) { |
|---|
| 563 | 773 | case DRM_FORMAT_MOD_BROADCOM_SAND64: |
|---|
| 564 | 774 | tiling = SCALER_CTL0_TILING_64B; |
|---|
| 775 | + tile_w = 64; |
|---|
| 565 | 776 | break; |
|---|
| 566 | 777 | case DRM_FORMAT_MOD_BROADCOM_SAND128: |
|---|
| 567 | 778 | tiling = SCALER_CTL0_TILING_128B; |
|---|
| 779 | + tile_w = 128; |
|---|
| 568 | 780 | break; |
|---|
| 569 | 781 | case DRM_FORMAT_MOD_BROADCOM_SAND256: |
|---|
| 570 | 782 | tiling = SCALER_CTL0_TILING_256B_OR_T; |
|---|
| 783 | + tile_w = 256; |
|---|
| 571 | 784 | break; |
|---|
| 572 | 785 | default: |
|---|
| 573 | 786 | break; |
|---|
| .. | .. |
|---|
| 576 | 789 | if (param > SCALER_TILE_HEIGHT_MASK) { |
|---|
| 577 | 790 | DRM_DEBUG_KMS("SAND height too large (%d)\n", param); |
|---|
| 578 | 791 | return -EINVAL; |
|---|
| 792 | + } |
|---|
| 793 | + |
|---|
| 794 | + pix_per_tile = tile_w / fb->format->cpp[0]; |
|---|
| 795 | + tile = vc4_state->src_x / pix_per_tile; |
|---|
| 796 | + x_off = vc4_state->src_x % pix_per_tile; |
|---|
| 797 | + |
|---|
| 798 | + /* Adjust the base pointer to the first pixel to be scanned |
|---|
| 799 | + * out. |
|---|
| 800 | + */ |
|---|
| 801 | + for (i = 0; i < num_planes; i++) { |
|---|
| 802 | + vc4_state->offsets[i] += param * tile_w * tile; |
|---|
| 803 | + vc4_state->offsets[i] += src_y / |
|---|
| 804 | + (i ? v_subsample : 1) * |
|---|
| 805 | + tile_w; |
|---|
| 806 | + vc4_state->offsets[i] += x_off / |
|---|
| 807 | + (i ? h_subsample : 1) * |
|---|
| 808 | + fb->format->cpp[i]; |
|---|
| 579 | 809 | } |
|---|
| 580 | 810 | |
|---|
| 581 | 811 | pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); |
|---|
| .. | .. |
|---|
| 588 | 818 | return -EINVAL; |
|---|
| 589 | 819 | } |
|---|
| 590 | 820 | |
|---|
| 591 | | - /* Control word */ |
|---|
| 592 | | - vc4_dlist_write(vc4_state, |
|---|
| 593 | | - SCALER_CTL0_VALID | |
|---|
| 594 | | - VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | |
|---|
| 595 | | - (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | |
|---|
| 596 | | - (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | |
|---|
| 597 | | - VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | |
|---|
| 598 | | - (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | |
|---|
| 599 | | - VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | |
|---|
| 600 | | - VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); |
|---|
| 601 | | - |
|---|
| 602 | | - /* Position Word 0: Image Positions and Alpha Value */ |
|---|
| 603 | | - vc4_state->pos0_offset = vc4_state->dlist_count; |
|---|
| 604 | | - vc4_dlist_write(vc4_state, |
|---|
| 605 | | - VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | |
|---|
| 606 | | - VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | |
|---|
| 607 | | - VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); |
|---|
| 608 | | - |
|---|
| 609 | | - /* Position Word 1: Scaled Image Dimensions. */ |
|---|
| 610 | | - if (!vc4_state->is_unity) { |
|---|
| 611 | | - vc4_dlist_write(vc4_state, |
|---|
| 612 | | - VC4_SET_FIELD(vc4_state->crtc_w, |
|---|
| 613 | | - SCALER_POS1_SCL_WIDTH) | |
|---|
| 614 | | - VC4_SET_FIELD(vc4_state->crtc_h, |
|---|
| 615 | | - SCALER_POS1_SCL_HEIGHT)); |
|---|
| 616 | | - } |
|---|
| 617 | | - |
|---|
| 618 | 821 | /* Don't waste cycles mixing with plane alpha if the set alpha |
|---|
| 619 | 822 | * is opaque or there is no per-pixel alpha information. |
|---|
| 620 | 823 | * In any case we use the alpha property value as the fixed alpha. |
|---|
| .. | .. |
|---|
| 622 | 825 | mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && |
|---|
| 623 | 826 | fb->format->has_alpha; |
|---|
| 624 | 827 | |
|---|
| 625 | | - /* Position Word 2: Source Image Size, Alpha */ |
|---|
| 626 | | - vc4_state->pos2_offset = vc4_state->dlist_count; |
|---|
| 627 | | - vc4_dlist_write(vc4_state, |
|---|
| 628 | | - VC4_SET_FIELD(fb->format->has_alpha ? |
|---|
| 629 | | - SCALER_POS2_ALPHA_MODE_PIPELINE : |
|---|
| 630 | | - SCALER_POS2_ALPHA_MODE_FIXED, |
|---|
| 631 | | - SCALER_POS2_ALPHA_MODE) | |
|---|
| 632 | | - (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | |
|---|
| 633 | | - (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | |
|---|
| 634 | | - VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | |
|---|
| 635 | | - VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); |
|---|
| 828 | + if (!vc4->hvs->hvs5) { |
|---|
| 829 | + /* Control word */ |
|---|
| 830 | + vc4_dlist_write(vc4_state, |
|---|
| 831 | + SCALER_CTL0_VALID | |
|---|
| 832 | + (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) | |
|---|
| 833 | + (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) | |
|---|
| 834 | + VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | |
|---|
| 835 | + (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | |
|---|
| 836 | + (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | |
|---|
| 837 | + VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | |
|---|
| 838 | + (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | |
|---|
| 839 | + VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | |
|---|
| 840 | + VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); |
|---|
| 636 | 841 | |
|---|
| 637 | | - /* Position Word 3: Context. Written by the HVS. */ |
|---|
| 638 | | - vc4_dlist_write(vc4_state, 0xc0c0c0c0); |
|---|
| 842 | + /* Position Word 0: Image Positions and Alpha Value */ |
|---|
| 843 | + vc4_state->pos0_offset = vc4_state->dlist_count; |
|---|
| 844 | + vc4_dlist_write(vc4_state, |
|---|
| 845 | + VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | |
|---|
| 846 | + VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | |
|---|
| 847 | + VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); |
|---|
| 848 | + |
|---|
| 849 | + /* Position Word 1: Scaled Image Dimensions. */ |
|---|
| 850 | + if (!vc4_state->is_unity) { |
|---|
| 851 | + vc4_dlist_write(vc4_state, |
|---|
| 852 | + VC4_SET_FIELD(vc4_state->crtc_w, |
|---|
| 853 | + SCALER_POS1_SCL_WIDTH) | |
|---|
| 854 | + VC4_SET_FIELD(vc4_state->crtc_h, |
|---|
| 855 | + SCALER_POS1_SCL_HEIGHT)); |
|---|
| 856 | + } |
|---|
| 857 | + |
|---|
| 858 | + /* Position Word 2: Source Image Size, Alpha */ |
|---|
| 859 | + vc4_state->pos2_offset = vc4_state->dlist_count; |
|---|
| 860 | + vc4_dlist_write(vc4_state, |
|---|
| 861 | + VC4_SET_FIELD(fb->format->has_alpha ? |
|---|
| 862 | + SCALER_POS2_ALPHA_MODE_PIPELINE : |
|---|
| 863 | + SCALER_POS2_ALPHA_MODE_FIXED, |
|---|
| 864 | + SCALER_POS2_ALPHA_MODE) | |
|---|
| 865 | + (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | |
|---|
| 866 | + (fb->format->has_alpha ? |
|---|
| 867 | + SCALER_POS2_ALPHA_PREMULT : 0) | |
|---|
| 868 | + VC4_SET_FIELD(vc4_state->src_w[0], |
|---|
| 869 | + SCALER_POS2_WIDTH) | |
|---|
| 870 | + VC4_SET_FIELD(vc4_state->src_h[0], |
|---|
| 871 | + SCALER_POS2_HEIGHT)); |
|---|
| 872 | + |
|---|
| 873 | + /* Position Word 3: Context. Written by the HVS. */ |
|---|
| 874 | + vc4_dlist_write(vc4_state, 0xc0c0c0c0); |
|---|
| 875 | + |
|---|
| 876 | + } else { |
|---|
| 877 | + u32 hvs_pixel_order = format->pixel_order; |
|---|
| 878 | + |
|---|
| 879 | + if (format->pixel_order_hvs5) |
|---|
| 880 | + hvs_pixel_order = format->pixel_order_hvs5; |
|---|
| 881 | + |
|---|
| 882 | + /* Control word */ |
|---|
| 883 | + vc4_dlist_write(vc4_state, |
|---|
| 884 | + SCALER_CTL0_VALID | |
|---|
| 885 | + (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) | |
|---|
| 886 | + (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | |
|---|
| 887 | + VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | |
|---|
| 888 | + (vc4_state->is_unity ? |
|---|
| 889 | + SCALER5_CTL0_UNITY : 0) | |
|---|
| 890 | + VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | |
|---|
| 891 | + VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) | |
|---|
| 892 | + SCALER5_CTL0_ALPHA_EXPAND | |
|---|
| 893 | + SCALER5_CTL0_RGB_EXPAND); |
|---|
| 894 | + |
|---|
| 895 | + /* Position Word 0: Image Positions and Alpha Value */ |
|---|
| 896 | + vc4_state->pos0_offset = vc4_state->dlist_count; |
|---|
| 897 | + vc4_dlist_write(vc4_state, |
|---|
| 898 | + (rotation & DRM_MODE_REFLECT_Y ? |
|---|
| 899 | + SCALER5_POS0_VFLIP : 0) | |
|---|
| 900 | + VC4_SET_FIELD(vc4_state->crtc_x, |
|---|
| 901 | + SCALER_POS0_START_X) | |
|---|
| 902 | + (rotation & DRM_MODE_REFLECT_X ? |
|---|
| 903 | + SCALER5_POS0_HFLIP : 0) | |
|---|
| 904 | + VC4_SET_FIELD(vc4_state->crtc_y, |
|---|
| 905 | + SCALER5_POS0_START_Y) |
|---|
| 906 | + ); |
|---|
| 907 | + |
|---|
| 908 | + /* Control Word 2 */ |
|---|
| 909 | + vc4_dlist_write(vc4_state, |
|---|
| 910 | + VC4_SET_FIELD(state->alpha >> 4, |
|---|
| 911 | + SCALER5_CTL2_ALPHA) | |
|---|
| 912 | + (fb->format->has_alpha ? |
|---|
| 913 | + SCALER5_CTL2_ALPHA_PREMULT : 0) | |
|---|
| 914 | + (mix_plane_alpha ? |
|---|
| 915 | + SCALER5_CTL2_ALPHA_MIX : 0) | |
|---|
| 916 | + VC4_SET_FIELD(fb->format->has_alpha ? |
|---|
| 917 | + SCALER5_CTL2_ALPHA_MODE_PIPELINE : |
|---|
| 918 | + SCALER5_CTL2_ALPHA_MODE_FIXED, |
|---|
| 919 | + SCALER5_CTL2_ALPHA_MODE) |
|---|
| 920 | + ); |
|---|
| 921 | + |
|---|
| 922 | + /* Position Word 1: Scaled Image Dimensions. */ |
|---|
| 923 | + if (!vc4_state->is_unity) { |
|---|
| 924 | + vc4_dlist_write(vc4_state, |
|---|
| 925 | + VC4_SET_FIELD(vc4_state->crtc_w, |
|---|
| 926 | + SCALER5_POS1_SCL_WIDTH) | |
|---|
| 927 | + VC4_SET_FIELD(vc4_state->crtc_h, |
|---|
| 928 | + SCALER5_POS1_SCL_HEIGHT)); |
|---|
| 929 | + } |
|---|
| 930 | + |
|---|
| 931 | + /* Position Word 2: Source Image Size */ |
|---|
| 932 | + vc4_state->pos2_offset = vc4_state->dlist_count; |
|---|
| 933 | + vc4_dlist_write(vc4_state, |
|---|
| 934 | + VC4_SET_FIELD(vc4_state->src_w[0], |
|---|
| 935 | + SCALER5_POS2_WIDTH) | |
|---|
| 936 | + VC4_SET_FIELD(vc4_state->src_h[0], |
|---|
| 937 | + SCALER5_POS2_HEIGHT)); |
|---|
| 938 | + |
|---|
| 939 | + /* Position Word 3: Context. Written by the HVS. */ |
|---|
| 940 | + vc4_dlist_write(vc4_state, 0xc0c0c0c0); |
|---|
| 941 | + } |
|---|
| 639 | 942 | |
|---|
| 640 | 943 | |
|---|
| 641 | 944 | /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers |
|---|
| .. | .. |
|---|
| 671 | 974 | vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); |
|---|
| 672 | 975 | } |
|---|
| 673 | 976 | |
|---|
| 977 | + vc4_state->lbm_offset = 0; |
|---|
| 978 | + |
|---|
| 674 | 979 | if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || |
|---|
| 675 | 980 | vc4_state->x_scaling[1] != VC4_SCALING_NONE || |
|---|
| 676 | 981 | vc4_state->y_scaling[0] != VC4_SCALING_NONE || |
|---|
| 677 | 982 | vc4_state->y_scaling[1] != VC4_SCALING_NONE) { |
|---|
| 678 | | - /* LBM Base Address. */ |
|---|
| 983 | + /* Reserve a slot for the LBM Base Address. The real value will |
|---|
| 984 | + * be set when calling vc4_plane_allocate_lbm(). |
|---|
| 985 | + */ |
|---|
| 679 | 986 | if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || |
|---|
| 680 | 987 | vc4_state->y_scaling[1] != VC4_SCALING_NONE) { |
|---|
| 681 | | - vc4_dlist_write(vc4_state, vc4_state->lbm.start); |
|---|
| 988 | + vc4_state->lbm_offset = vc4_state->dlist_count; |
|---|
| 989 | + vc4_dlist_counter_increment(vc4_state); |
|---|
| 682 | 990 | } |
|---|
| 683 | 991 | |
|---|
| 684 | 992 | if (num_planes > 1) { |
|---|
| .. | .. |
|---|
| 725 | 1033 | vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || |
|---|
| 726 | 1034 | state->alpha != DRM_BLEND_ALPHA_OPAQUE; |
|---|
| 727 | 1035 | |
|---|
| 1036 | + /* Flag the dlist as initialized to avoid checking it twice in case |
|---|
| 1037 | + * the async update check already called vc4_plane_mode_set() and |
|---|
| 1038 | + * decided to fallback to sync update because async update was not |
|---|
| 1039 | + * possible. |
|---|
| 1040 | + */ |
|---|
| 1041 | + vc4_state->dlist_initialized = 1; |
|---|
| 1042 | + |
|---|
| 1043 | + vc4_plane_calc_load(state); |
|---|
| 1044 | + |
|---|
| 728 | 1045 | return 0; |
|---|
| 729 | 1046 | } |
|---|
| 730 | 1047 | |
|---|
| .. | .. |
|---|
| 739 | 1056 | struct drm_plane_state *state) |
|---|
| 740 | 1057 | { |
|---|
| 741 | 1058 | struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); |
|---|
| 1059 | + int ret; |
|---|
| 742 | 1060 | |
|---|
| 743 | 1061 | vc4_state->dlist_count = 0; |
|---|
| 744 | 1062 | |
|---|
| 745 | | - if (plane_enabled(state)) |
|---|
| 746 | | - return vc4_plane_mode_set(plane, state); |
|---|
| 747 | | - else |
|---|
| 1063 | + if (!plane_enabled(state)) |
|---|
| 748 | 1064 | return 0; |
|---|
| 1065 | + |
|---|
| 1066 | + ret = vc4_plane_mode_set(plane, state); |
|---|
| 1067 | + if (ret) |
|---|
| 1068 | + return ret; |
|---|
| 1069 | + |
|---|
| 1070 | + return vc4_plane_allocate_lbm(state); |
|---|
| 749 | 1071 | } |
|---|
| 750 | 1072 | |
|---|
| 751 | 1073 | static void vc4_plane_atomic_update(struct drm_plane *plane, |
|---|
| .. | .. |
|---|
| 811 | 1133 | static void vc4_plane_atomic_async_update(struct drm_plane *plane, |
|---|
| 812 | 1134 | struct drm_plane_state *state) |
|---|
| 813 | 1135 | { |
|---|
| 814 | | - struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); |
|---|
| 815 | | - |
|---|
| 816 | | - if (plane->state->fb != state->fb) { |
|---|
| 817 | | - vc4_plane_async_set_fb(plane, state->fb); |
|---|
| 818 | | - drm_atomic_set_fb_for_plane(plane->state, state->fb); |
|---|
| 819 | | - } |
|---|
| 1136 | + struct vc4_plane_state *vc4_state, *new_vc4_state; |
|---|
| 820 | 1137 | |
|---|
| 821 | 1138 | swap(plane->state->fb, state->fb); |
|---|
| 822 | | - /* Set the cursor's position on the screen. This is the |
|---|
| 823 | | - * expected change from the drm_mode_cursor_universal() |
|---|
| 824 | | - * helper. |
|---|
| 825 | | - */ |
|---|
| 826 | 1139 | plane->state->crtc_x = state->crtc_x; |
|---|
| 827 | 1140 | plane->state->crtc_y = state->crtc_y; |
|---|
| 828 | | - |
|---|
| 829 | | - /* Allow changing the start position within the cursor BO, if |
|---|
| 830 | | - * that matters. |
|---|
| 831 | | - */ |
|---|
| 1141 | + plane->state->crtc_w = state->crtc_w; |
|---|
| 1142 | + plane->state->crtc_h = state->crtc_h; |
|---|
| 832 | 1143 | plane->state->src_x = state->src_x; |
|---|
| 833 | 1144 | plane->state->src_y = state->src_y; |
|---|
| 1145 | + plane->state->src_w = state->src_w; |
|---|
| 1146 | + plane->state->src_h = state->src_h; |
|---|
| 1147 | + plane->state->src_h = state->src_h; |
|---|
| 1148 | + plane->state->alpha = state->alpha; |
|---|
| 1149 | + plane->state->pixel_blend_mode = state->pixel_blend_mode; |
|---|
| 1150 | + plane->state->rotation = state->rotation; |
|---|
| 1151 | + plane->state->zpos = state->zpos; |
|---|
| 1152 | + plane->state->normalized_zpos = state->normalized_zpos; |
|---|
| 1153 | + plane->state->color_encoding = state->color_encoding; |
|---|
| 1154 | + plane->state->color_range = state->color_range; |
|---|
| 1155 | + plane->state->src = state->src; |
|---|
| 1156 | + plane->state->dst = state->dst; |
|---|
| 1157 | + plane->state->visible = state->visible; |
|---|
| 834 | 1158 | |
|---|
| 835 | | - /* Update the display list based on the new crtc_x/y. */ |
|---|
| 836 | | - vc4_plane_atomic_check(plane, plane->state); |
|---|
| 1159 | + new_vc4_state = to_vc4_plane_state(state); |
|---|
| 1160 | + vc4_state = to_vc4_plane_state(plane->state); |
|---|
| 1161 | + |
|---|
| 1162 | + vc4_state->crtc_x = new_vc4_state->crtc_x; |
|---|
| 1163 | + vc4_state->crtc_y = new_vc4_state->crtc_y; |
|---|
| 1164 | + vc4_state->crtc_h = new_vc4_state->crtc_h; |
|---|
| 1165 | + vc4_state->crtc_w = new_vc4_state->crtc_w; |
|---|
| 1166 | + vc4_state->src_x = new_vc4_state->src_x; |
|---|
| 1167 | + vc4_state->src_y = new_vc4_state->src_y; |
|---|
| 1168 | + memcpy(vc4_state->src_w, new_vc4_state->src_w, |
|---|
| 1169 | + sizeof(vc4_state->src_w)); |
|---|
| 1170 | + memcpy(vc4_state->src_h, new_vc4_state->src_h, |
|---|
| 1171 | + sizeof(vc4_state->src_h)); |
|---|
| 1172 | + memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling, |
|---|
| 1173 | + sizeof(vc4_state->x_scaling)); |
|---|
| 1174 | + memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling, |
|---|
| 1175 | + sizeof(vc4_state->y_scaling)); |
|---|
| 1176 | + vc4_state->is_unity = new_vc4_state->is_unity; |
|---|
| 1177 | + vc4_state->is_yuv = new_vc4_state->is_yuv; |
|---|
| 1178 | + memcpy(vc4_state->offsets, new_vc4_state->offsets, |
|---|
| 1179 | + sizeof(vc4_state->offsets)); |
|---|
| 1180 | + vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; |
|---|
| 1181 | + |
|---|
| 1182 | + /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ |
|---|
| 1183 | + vc4_state->dlist[vc4_state->pos0_offset] = |
|---|
| 1184 | + new_vc4_state->dlist[vc4_state->pos0_offset]; |
|---|
| 1185 | + vc4_state->dlist[vc4_state->pos2_offset] = |
|---|
| 1186 | + new_vc4_state->dlist[vc4_state->pos2_offset]; |
|---|
| 1187 | + vc4_state->dlist[vc4_state->ptr0_offset] = |
|---|
| 1188 | + new_vc4_state->dlist[vc4_state->ptr0_offset]; |
|---|
| 837 | 1189 | |
|---|
| 838 | 1190 | /* Note that we can't just call vc4_plane_write_dlist() |
|---|
| 839 | 1191 | * because that would smash the context data that the HVS is |
|---|
| .. | .. |
|---|
| 850 | 1202 | static int vc4_plane_atomic_async_check(struct drm_plane *plane, |
|---|
| 851 | 1203 | struct drm_plane_state *state) |
|---|
| 852 | 1204 | { |
|---|
| 853 | | - /* No configuring new scaling in the fast path. */ |
|---|
| 854 | | - if (plane->state->crtc_w != state->crtc_w || |
|---|
| 855 | | - plane->state->crtc_h != state->crtc_h || |
|---|
| 856 | | - plane->state->src_w != state->src_w || |
|---|
| 857 | | - plane->state->src_h != state->src_h) |
|---|
| 1205 | + struct vc4_plane_state *old_vc4_state, *new_vc4_state; |
|---|
| 1206 | + int ret; |
|---|
| 1207 | + u32 i; |
|---|
| 1208 | + |
|---|
| 1209 | + ret = vc4_plane_mode_set(plane, state); |
|---|
| 1210 | + if (ret) |
|---|
| 1211 | + return ret; |
|---|
| 1212 | + |
|---|
| 1213 | + old_vc4_state = to_vc4_plane_state(plane->state); |
|---|
| 1214 | + new_vc4_state = to_vc4_plane_state(state); |
|---|
| 1215 | + if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || |
|---|
| 1216 | + old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || |
|---|
| 1217 | + old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || |
|---|
| 1218 | + old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || |
|---|
| 1219 | + vc4_lbm_size(plane->state) != vc4_lbm_size(state)) |
|---|
| 858 | 1220 | return -EINVAL; |
|---|
| 1221 | + |
|---|
| 1222 | + /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update |
|---|
| 1223 | + * if anything else has changed, fallback to a sync update. |
|---|
| 1224 | + */ |
|---|
| 1225 | + for (i = 0; i < new_vc4_state->dlist_count; i++) { |
|---|
| 1226 | + if (i == new_vc4_state->pos0_offset || |
|---|
| 1227 | + i == new_vc4_state->pos2_offset || |
|---|
| 1228 | + i == new_vc4_state->ptr0_offset || |
|---|
| 1229 | + (new_vc4_state->lbm_offset && |
|---|
| 1230 | + i == new_vc4_state->lbm_offset)) |
|---|
| 1231 | + continue; |
|---|
| 1232 | + |
|---|
| 1233 | + if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i]) |
|---|
| 1234 | + return -EINVAL; |
|---|
| 1235 | + } |
|---|
| 859 | 1236 | |
|---|
| 860 | 1237 | return 0; |
|---|
| 861 | 1238 | } |
|---|
| .. | .. |
|---|
| 864 | 1241 | struct drm_plane_state *state) |
|---|
| 865 | 1242 | { |
|---|
| 866 | 1243 | struct vc4_bo *bo; |
|---|
| 867 | | - struct dma_fence *fence; |
|---|
| 868 | 1244 | int ret; |
|---|
| 869 | 1245 | |
|---|
| 870 | 1246 | if (!state->fb) |
|---|
| .. | .. |
|---|
| 872 | 1248 | |
|---|
| 873 | 1249 | bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); |
|---|
| 874 | 1250 | |
|---|
| 875 | | - fence = reservation_object_get_excl_rcu(bo->resv); |
|---|
| 876 | | - drm_atomic_set_fence_for_plane(state, fence); |
|---|
| 1251 | + drm_gem_fb_prepare_fb(plane, state); |
|---|
| 877 | 1252 | |
|---|
| 878 | 1253 | if (plane->state->fb == state->fb) |
|---|
| 879 | 1254 | return 0; |
|---|
| .. | .. |
|---|
| 908 | 1283 | |
|---|
| 909 | 1284 | static void vc4_plane_destroy(struct drm_plane *plane) |
|---|
| 910 | 1285 | { |
|---|
| 911 | | - drm_plane_helper_disable(plane, NULL); |
|---|
| 912 | 1286 | drm_plane_cleanup(plane); |
|---|
| 913 | 1287 | } |
|---|
| 914 | 1288 | |
|---|
| .. | .. |
|---|
| 929 | 1303 | switch (fourcc_mod_broadcom_mod(modifier)) { |
|---|
| 930 | 1304 | case DRM_FORMAT_MOD_LINEAR: |
|---|
| 931 | 1305 | case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: |
|---|
| 932 | | - case DRM_FORMAT_MOD_BROADCOM_SAND64: |
|---|
| 933 | | - case DRM_FORMAT_MOD_BROADCOM_SAND128: |
|---|
| 934 | 1306 | return true; |
|---|
| 935 | 1307 | default: |
|---|
| 936 | 1308 | return false; |
|---|
| .. | .. |
|---|
| 946 | 1318 | default: |
|---|
| 947 | 1319 | return false; |
|---|
| 948 | 1320 | } |
|---|
| 1321 | + case DRM_FORMAT_RGBX1010102: |
|---|
| 1322 | + case DRM_FORMAT_BGRX1010102: |
|---|
| 1323 | + case DRM_FORMAT_RGBA1010102: |
|---|
| 1324 | + case DRM_FORMAT_BGRA1010102: |
|---|
| 949 | 1325 | case DRM_FORMAT_YUV422: |
|---|
| 950 | 1326 | case DRM_FORMAT_YVU422: |
|---|
| 951 | 1327 | case DRM_FORMAT_YUV420: |
|---|
| .. | .. |
|---|
| 974 | 1350 | struct drm_plane *plane = NULL; |
|---|
| 975 | 1351 | struct vc4_plane *vc4_plane; |
|---|
| 976 | 1352 | u32 formats[ARRAY_SIZE(hvs_formats)]; |
|---|
| 977 | | - u32 num_formats = 0; |
|---|
| 978 | 1353 | int ret = 0; |
|---|
| 979 | 1354 | unsigned i; |
|---|
| 980 | 1355 | static const uint64_t modifiers[] = { |
|---|
| .. | .. |
|---|
| 991 | 1366 | if (!vc4_plane) |
|---|
| 992 | 1367 | return ERR_PTR(-ENOMEM); |
|---|
| 993 | 1368 | |
|---|
| 994 | | - for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { |
|---|
| 995 | | - /* Don't allow YUV in cursor planes, since that means |
|---|
| 996 | | - * tuning on the scaler, which we don't allow for the |
|---|
| 997 | | - * cursor. |
|---|
| 998 | | - */ |
|---|
| 999 | | - if (type != DRM_PLANE_TYPE_CURSOR || |
|---|
| 1000 | | - hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { |
|---|
| 1001 | | - formats[num_formats++] = hvs_formats[i].drm; |
|---|
| 1002 | | - } |
|---|
| 1003 | | - } |
|---|
| 1369 | + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) |
|---|
| 1370 | + formats[i] = hvs_formats[i].drm; |
|---|
| 1371 | + |
|---|
| 1004 | 1372 | plane = &vc4_plane->base; |
|---|
| 1005 | 1373 | ret = drm_universal_plane_init(dev, plane, 0, |
|---|
| 1006 | 1374 | &vc4_plane_funcs, |
|---|
| 1007 | | - formats, num_formats, |
|---|
| 1375 | + formats, ARRAY_SIZE(formats), |
|---|
| 1008 | 1376 | modifiers, type, NULL); |
|---|
| 1377 | + if (ret) |
|---|
| 1378 | + return ERR_PTR(ret); |
|---|
| 1009 | 1379 | |
|---|
| 1010 | 1380 | drm_plane_helper_add(plane, &vc4_plane_helper_funcs); |
|---|
| 1011 | 1381 | |
|---|
| 1012 | 1382 | drm_plane_create_alpha_property(plane); |
|---|
| 1383 | + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, |
|---|
| 1384 | + DRM_MODE_ROTATE_0 | |
|---|
| 1385 | + DRM_MODE_ROTATE_180 | |
|---|
| 1386 | + DRM_MODE_REFLECT_X | |
|---|
| 1387 | + DRM_MODE_REFLECT_Y); |
|---|
| 1013 | 1388 | |
|---|
| 1014 | 1389 | return plane; |
|---|
| 1015 | 1390 | } |
|---|
| 1391 | + |
|---|
| 1392 | +int vc4_plane_create_additional_planes(struct drm_device *drm) |
|---|
| 1393 | +{ |
|---|
| 1394 | + struct drm_plane *cursor_plane; |
|---|
| 1395 | + struct drm_crtc *crtc; |
|---|
| 1396 | + unsigned int i; |
|---|
| 1397 | + |
|---|
| 1398 | + /* Set up some arbitrary number of planes. We're not limited |
|---|
| 1399 | + * by a set number of physical registers, just the space in |
|---|
| 1400 | + * the HVS (16k) and how small an plane can be (28 bytes). |
|---|
| 1401 | + * However, each plane we set up takes up some memory, and |
|---|
| 1402 | + * increases the cost of looping over planes, which atomic |
|---|
| 1403 | + * modesetting does quite a bit. As a result, we pick a |
|---|
| 1404 | + * modest number of planes to expose, that should hopefully |
|---|
| 1405 | + * still cover any sane usecase. |
|---|
| 1406 | + */ |
|---|
| 1407 | + for (i = 0; i < 16; i++) { |
|---|
| 1408 | + struct drm_plane *plane = |
|---|
| 1409 | + vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); |
|---|
| 1410 | + |
|---|
| 1411 | + if (IS_ERR(plane)) |
|---|
| 1412 | + continue; |
|---|
| 1413 | + |
|---|
| 1414 | + plane->possible_crtcs = |
|---|
| 1415 | + GENMASK(drm->mode_config.num_crtc - 1, 0); |
|---|
| 1416 | + } |
|---|
| 1417 | + |
|---|
| 1418 | + drm_for_each_crtc(crtc, drm) { |
|---|
| 1419 | + /* Set up the legacy cursor after overlay initialization, |
|---|
| 1420 | + * since we overlay planes on the CRTC in the order they were |
|---|
| 1421 | + * initialized. |
|---|
| 1422 | + */ |
|---|
| 1423 | + cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); |
|---|
| 1424 | + if (!IS_ERR(cursor_plane)) { |
|---|
| 1425 | + cursor_plane->possible_crtcs = drm_crtc_mask(crtc); |
|---|
| 1426 | + crtc->cursor = cursor_plane; |
|---|
| 1427 | + } |
|---|
| 1428 | + } |
|---|
| 1429 | + |
|---|
| 1430 | + return 0; |
|---|
| 1431 | +} |
|---|