1732 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2015 Broadcom4 */5 6/**7 * DOC: VC4 plane module8 *9 * Each DRM plane is a layer of pixels being scanned out by the HVS.10 *11 * At atomic modeset check time, we compute the HVS display element12 * state that would be necessary for displaying the plane (giving us a13 * chance to figure out if a plane configuration is invalid), then at14 * atomic flush time the CRTC will ask us to write our element state15 * into the region of the HVS that it has allocated for us.16 */17 18#include <drm/drm_atomic.h>19#include <drm/drm_atomic_helper.h>20#include <drm/drm_atomic_uapi.h>21#include <drm/drm_blend.h>22#include <drm/drm_drv.h>23#include <drm/drm_fb_dma_helper.h>24#include <drm/drm_fourcc.h>25#include <drm/drm_framebuffer.h>26#include <drm/drm_gem_atomic_helper.h>27 28#include "uapi/drm/vc4_drm.h"29 30#include "vc4_drv.h"31#include "vc4_regs.h"32 33static const struct hvs_format {34 u32 drm; /* DRM_FORMAT_* */35 u32 hvs; /* HVS_FORMAT_* */36 u32 pixel_order;37 u32 pixel_order_hvs5;38 bool hvs5_only;39} hvs_formats[] = {40 {41 .drm = DRM_FORMAT_XRGB8888,42 .hvs = HVS_PIXEL_FORMAT_RGBA8888,43 .pixel_order = HVS_PIXEL_ORDER_ABGR,44 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,45 },46 {47 .drm = DRM_FORMAT_ARGB8888,48 .hvs = HVS_PIXEL_FORMAT_RGBA8888,49 .pixel_order = HVS_PIXEL_ORDER_ABGR,50 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,51 },52 {53 .drm = DRM_FORMAT_ABGR8888,54 .hvs = HVS_PIXEL_FORMAT_RGBA8888,55 .pixel_order = HVS_PIXEL_ORDER_ARGB,56 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,57 },58 {59 .drm = DRM_FORMAT_XBGR8888,60 .hvs = HVS_PIXEL_FORMAT_RGBA8888,61 .pixel_order = HVS_PIXEL_ORDER_ARGB,62 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,63 },64 {65 .drm = DRM_FORMAT_RGB565,66 .hvs = HVS_PIXEL_FORMAT_RGB565,67 .pixel_order = HVS_PIXEL_ORDER_XRGB,68 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,69 },70 {71 .drm = DRM_FORMAT_BGR565,72 .hvs = HVS_PIXEL_FORMAT_RGB565,73 .pixel_order = HVS_PIXEL_ORDER_XBGR,74 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,75 },76 {77 .drm = DRM_FORMAT_ARGB1555,78 .hvs = HVS_PIXEL_FORMAT_RGBA5551,79 .pixel_order = HVS_PIXEL_ORDER_ABGR,80 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,81 },82 {83 .drm = DRM_FORMAT_XRGB1555,84 .hvs = HVS_PIXEL_FORMAT_RGBA5551,85 .pixel_order = HVS_PIXEL_ORDER_ABGR,86 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,87 },88 {89 .drm = DRM_FORMAT_RGB888,90 .hvs = HVS_PIXEL_FORMAT_RGB888,91 .pixel_order = HVS_PIXEL_ORDER_XRGB,92 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,93 },94 {95 .drm = DRM_FORMAT_BGR888,96 .hvs = HVS_PIXEL_FORMAT_RGB888,97 .pixel_order = HVS_PIXEL_ORDER_XBGR,98 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,99 },100 {101 .drm = DRM_FORMAT_YUV422,102 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,103 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,104 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,105 },106 {107 .drm = DRM_FORMAT_YVU422,108 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,109 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,110 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,111 },112 {113 .drm = DRM_FORMAT_YUV420,114 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,115 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,116 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,117 },118 {119 .drm = DRM_FORMAT_YVU420,120 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,121 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,122 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,123 },124 {125 .drm = DRM_FORMAT_NV12,126 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,127 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,128 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,129 },130 {131 .drm = DRM_FORMAT_NV21,132 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,133 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,134 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,135 },136 {137 .drm = DRM_FORMAT_NV16,138 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,139 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,140 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,141 },142 {143 .drm = DRM_FORMAT_NV61,144 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,145 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,146 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,147 },148 {149 .drm = DRM_FORMAT_P030,150 .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,151 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,152 .hvs5_only = true,153 },154 {155 .drm = DRM_FORMAT_XRGB2101010,156 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,157 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,158 .hvs5_only = true,159 },160 {161 .drm = DRM_FORMAT_ARGB2101010,162 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,163 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,164 .hvs5_only = true,165 },166 {167 .drm = DRM_FORMAT_ABGR2101010,168 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,169 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,170 .hvs5_only = true,171 },172 {173 .drm = DRM_FORMAT_XBGR2101010,174 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,175 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,176 .hvs5_only = true,177 },178 {179 .drm = DRM_FORMAT_RGB332,180 .hvs = HVS_PIXEL_FORMAT_RGB332,181 .pixel_order = HVS_PIXEL_ORDER_ARGB,182 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,183 },184 {185 .drm = DRM_FORMAT_BGR233,186 .hvs = HVS_PIXEL_FORMAT_RGB332,187 .pixel_order = HVS_PIXEL_ORDER_ABGR,188 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,189 },190 {191 .drm = DRM_FORMAT_XRGB4444,192 .hvs = HVS_PIXEL_FORMAT_RGBA4444,193 .pixel_order = HVS_PIXEL_ORDER_ABGR,194 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,195 },196 {197 .drm = DRM_FORMAT_ARGB4444,198 .hvs = HVS_PIXEL_FORMAT_RGBA4444,199 .pixel_order = HVS_PIXEL_ORDER_ABGR,200 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,201 },202 {203 .drm = DRM_FORMAT_XBGR4444,204 .hvs = HVS_PIXEL_FORMAT_RGBA4444,205 .pixel_order = HVS_PIXEL_ORDER_ARGB,206 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,207 },208 {209 .drm = DRM_FORMAT_ABGR4444,210 .hvs = HVS_PIXEL_FORMAT_RGBA4444,211 .pixel_order = HVS_PIXEL_ORDER_ARGB,212 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,213 },214 {215 .drm = DRM_FORMAT_BGRX4444,216 .hvs = HVS_PIXEL_FORMAT_RGBA4444,217 .pixel_order = HVS_PIXEL_ORDER_RGBA,218 .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,219 },220 {221 .drm = DRM_FORMAT_BGRA4444,222 .hvs = HVS_PIXEL_FORMAT_RGBA4444,223 .pixel_order = HVS_PIXEL_ORDER_RGBA,224 .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,225 },226 {227 .drm = DRM_FORMAT_RGBX4444,228 .hvs = HVS_PIXEL_FORMAT_RGBA4444,229 .pixel_order = HVS_PIXEL_ORDER_BGRA,230 .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,231 },232 {233 .drm = DRM_FORMAT_RGBA4444,234 .hvs = HVS_PIXEL_FORMAT_RGBA4444,235 .pixel_order = HVS_PIXEL_ORDER_BGRA,236 .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,237 },238};239 240static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)241{242 unsigned i;243 244 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {245 if (hvs_formats[i].drm == drm_format)246 return &hvs_formats[i];247 }248 249 return NULL;250}251 252static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)253{254 if (dst == src)255 return VC4_SCALING_NONE;256 if (3 * dst >= 2 * src)257 return VC4_SCALING_PPF;258 else259 return VC4_SCALING_TPZ;260}261 262static bool plane_enabled(struct drm_plane_state *state)263{264 return state->fb && !WARN_ON(!state->crtc);265}266 267static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)268{269 struct vc4_plane_state *vc4_state;270 271 if (WARN_ON(!plane->state))272 return NULL;273 274 vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);275 if (!vc4_state)276 return NULL;277 278 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));279 vc4_state->dlist_initialized = 0;280 281 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);282 283 if (vc4_state->dlist) {284 vc4_state->dlist = kmemdup(vc4_state->dlist,285 vc4_state->dlist_count * 4,286 GFP_KERNEL);287 if (!vc4_state->dlist) {288 kfree(vc4_state);289 return NULL;290 }291 vc4_state->dlist_size = vc4_state->dlist_count;292 }293 294 return &vc4_state->base;295}296 297static void vc4_plane_destroy_state(struct drm_plane *plane,298 struct drm_plane_state *state)299{300 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);301 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);302 303 if (drm_mm_node_allocated(&vc4_state->lbm)) {304 unsigned long irqflags;305 306 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);307 drm_mm_remove_node(&vc4_state->lbm);308 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);309 }310 311 kfree(vc4_state->dlist);312 __drm_atomic_helper_plane_destroy_state(&vc4_state->base);313 kfree(state);314}315 316/* Called during init to allocate the plane's atomic state. */317static void vc4_plane_reset(struct drm_plane *plane)318{319 struct vc4_plane_state *vc4_state;320 321 WARN_ON(plane->state);322 323 vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);324 if (!vc4_state)325 return;326 327 __drm_atomic_helper_plane_reset(plane, &vc4_state->base);328}329 330static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state)331{332 if (vc4_state->dlist_count == vc4_state->dlist_size) {333 u32 new_size = max(4u, vc4_state->dlist_count * 2);334 u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL);335 336 if (!new_dlist)337 return;338 memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4);339 340 kfree(vc4_state->dlist);341 vc4_state->dlist = new_dlist;342 vc4_state->dlist_size = new_size;343 }344 345 vc4_state->dlist_count++;346}347 348static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)349{350 unsigned int idx = vc4_state->dlist_count;351 352 vc4_dlist_counter_increment(vc4_state);353 vc4_state->dlist[idx] = val;354}355 356/* Returns the scl0/scl1 field based on whether the dimensions need to357 * be up/down/non-scaled.358 *359 * This is a replication of a table from the spec.360 */361static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)362{363 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);364 365 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {366 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:367 return SCALER_CTL0_SCL_H_PPF_V_PPF;368 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:369 return SCALER_CTL0_SCL_H_TPZ_V_PPF;370 case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:371 return SCALER_CTL0_SCL_H_PPF_V_TPZ;372 case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:373 return SCALER_CTL0_SCL_H_TPZ_V_TPZ;374 case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:375 return SCALER_CTL0_SCL_H_PPF_V_NONE;376 case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:377 return SCALER_CTL0_SCL_H_NONE_V_PPF;378 case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:379 return SCALER_CTL0_SCL_H_NONE_V_TPZ;380 case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:381 return SCALER_CTL0_SCL_H_TPZ_V_NONE;382 default:383 case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:384 /* The unity case is independently handled by385 * SCALER_CTL0_UNITY.386 */387 return 0;388 }389}390 391static int vc4_plane_margins_adj(struct drm_plane_state *pstate)392{393 struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);394 unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;395 struct drm_crtc_state *crtc_state;396 397 crtc_state = drm_atomic_get_new_crtc_state(pstate->state,398 pstate->crtc);399 400 vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);401 if (!left && !right && !top && !bottom)402 return 0;403 404 if (left + right >= crtc_state->mode.hdisplay ||405 top + bottom >= crtc_state->mode.vdisplay)406 return -EINVAL;407 408 adjhdisplay = crtc_state->mode.hdisplay - (left + right);409 vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *410 adjhdisplay,411 crtc_state->mode.hdisplay);412 vc4_pstate->crtc_x += left;413 if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)414 vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;415 416 adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);417 vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *418 adjvdisplay,419 crtc_state->mode.vdisplay);420 vc4_pstate->crtc_y += top;421 if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)422 vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;423 424 vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *425 adjhdisplay,426 crtc_state->mode.hdisplay);427 vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *428 adjvdisplay,429 crtc_state->mode.vdisplay);430 431 if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)432 return -EINVAL;433 434 return 0;435}436 437static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)438{439 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);440 struct drm_framebuffer *fb = state->fb;441 struct drm_gem_dma_object *bo;442 int num_planes = fb->format->num_planes;443 struct drm_crtc_state *crtc_state;444 u32 h_subsample = fb->format->hsub;445 u32 v_subsample = fb->format->vsub;446 int i, ret;447 448 crtc_state = drm_atomic_get_existing_crtc_state(state->state,449 state->crtc);450 if (!crtc_state) {451 DRM_DEBUG_KMS("Invalid crtc state\n");452 return -EINVAL;453 }454 455 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,456 INT_MAX, true, true);457 if (ret)458 return ret;459 460 for (i = 0; i < num_planes; i++) {461 bo = drm_fb_dma_get_gem_obj(fb, i);462 vc4_state->offsets[i] = bo->dma_addr + fb->offsets[i];463 }464 465 /*466 * We don't support subpixel source positioning for scaling,467 * but fractional coordinates can be generated by clipping468 * so just round for now469 */470 vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1 << 16);471 vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1 << 16);472 vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x;473 vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y;474 475 vc4_state->crtc_x = state->dst.x1;476 vc4_state->crtc_y = state->dst.y1;477 vc4_state->crtc_w = state->dst.x2 - state->dst.x1;478 vc4_state->crtc_h = state->dst.y2 - state->dst.y1;479 480 ret = vc4_plane_margins_adj(state);481 if (ret)482 return ret;483 484 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],485 vc4_state->crtc_w);486 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],487 vc4_state->crtc_h);488 489 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&490 vc4_state->y_scaling[0] == VC4_SCALING_NONE);491 492 if (num_planes > 1) {493 vc4_state->is_yuv = true;494 495 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;496 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;497 498 vc4_state->x_scaling[1] =499 vc4_get_scaling_mode(vc4_state->src_w[1],500 vc4_state->crtc_w);501 vc4_state->y_scaling[1] =502 vc4_get_scaling_mode(vc4_state->src_h[1],503 vc4_state->crtc_h);504 505 /* YUV conversion requires that horizontal scaling be enabled506 * on the UV plane even if vc4_get_scaling_mode() returned507 * VC4_SCALING_NONE (which can happen when the down-scaling508 * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this509 * case.510 */511 if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)512 vc4_state->x_scaling[1] = VC4_SCALING_PPF;513 } else {514 vc4_state->is_yuv = false;515 vc4_state->x_scaling[1] = VC4_SCALING_NONE;516 vc4_state->y_scaling[1] = VC4_SCALING_NONE;517 }518 519 return 0;520}521 522static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)523{524 u32 scale, recip;525 526 scale = (1 << 16) * src / dst;527 528 /* The specs note that while the reciprocal would be defined529 * as (1<<32)/scale, ~0 is close enough.530 */531 recip = ~0 / scale;532 533 vc4_dlist_write(vc4_state,534 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |535 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));536 vc4_dlist_write(vc4_state,537 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));538}539 540static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)541{542 u32 scale = (1 << 16) * src / dst;543 544 vc4_dlist_write(vc4_state,545 SCALER_PPF_AGC |546 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |547 VC4_SET_FIELD(0, SCALER_PPF_IPHASE));548}549 550static u32 vc4_lbm_size(struct drm_plane_state *state)551{552 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);553 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);554 u32 pix_per_line;555 u32 lbm;556 557 /* LBM is not needed when there's no vertical scaling. */558 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&559 vc4_state->y_scaling[1] == VC4_SCALING_NONE)560 return 0;561 562 /*563 * This can be further optimized in the RGB/YUV444 case if the PPF564 * decimation factor is between 0.5 and 1.0 by using crtc_w.565 *566 * It's not an issue though, since in that case since src_w[0] is going567 * to be greater than or equal to crtc_w.568 */569 if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)570 pix_per_line = vc4_state->crtc_w;571 else572 pix_per_line = vc4_state->src_w[0];573 574 if (!vc4_state->is_yuv) {575 if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)576 lbm = pix_per_line * 8;577 else {578 /* In special cases, this multiplier might be 12. */579 lbm = pix_per_line * 16;580 }581 } else {582 /* There are cases for this going down to a multiplier583 * of 2, but according to the firmware source, the584 * table in the docs is somewhat wrong.585 */586 lbm = pix_per_line * 16;587 }588 589 /* Align it to 64 or 128 (hvs5) bytes */590 lbm = roundup(lbm, vc4->is_vc5 ? 128 : 64);591 592 /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */593 lbm /= vc4->is_vc5 ? 4 : 2;594 595 return lbm;596}597 598static void vc4_write_scaling_parameters(struct drm_plane_state *state,599 int channel)600{601 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);602 603 /* Ch0 H-PPF Word 0: Scaling Parameters */604 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {605 vc4_write_ppf(vc4_state,606 vc4_state->src_w[channel], vc4_state->crtc_w);607 }608 609 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */610 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {611 vc4_write_ppf(vc4_state,612 vc4_state->src_h[channel], vc4_state->crtc_h);613 vc4_dlist_write(vc4_state, 0xc0c0c0c0);614 }615 616 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */617 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {618 vc4_write_tpz(vc4_state,619 vc4_state->src_w[channel], vc4_state->crtc_w);620 }621 622 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */623 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {624 vc4_write_tpz(vc4_state,625 vc4_state->src_h[channel], vc4_state->crtc_h);626 vc4_dlist_write(vc4_state, 0xc0c0c0c0);627 }628}629 630static void vc4_plane_calc_load(struct drm_plane_state *state)631{632 unsigned int hvs_load_shift, vrefresh, i;633 struct drm_framebuffer *fb = state->fb;634 struct vc4_plane_state *vc4_state;635 struct drm_crtc_state *crtc_state;636 unsigned int vscale_factor;637 638 vc4_state = to_vc4_plane_state(state);639 crtc_state = drm_atomic_get_existing_crtc_state(state->state,640 state->crtc);641 vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode);642 643 /* The HVS is able to process 2 pixels/cycle when scaling the source,644 * 4 pixels/cycle otherwise.645 * Alpha blending step seems to be pipelined and it's always operating646 * at 4 pixels/cycle, so the limiting aspect here seems to be the647 * scaler block.648 * HVS load is expressed in clk-cycles/sec (AKA Hz).649 */650 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||651 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||652 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||653 vc4_state->y_scaling[1] != VC4_SCALING_NONE)654 hvs_load_shift = 1;655 else656 hvs_load_shift = 2;657 658 vc4_state->membus_load = 0;659 vc4_state->hvs_load = 0;660 for (i = 0; i < fb->format->num_planes; i++) {661 /* Even if the bandwidth/plane required for a single frame is662 *663 * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh664 *665 * when downscaling, we have to read more pixels per line in666 * the time frame reserved for a single line, so the bandwidth667 * demand can be punctually higher. To account for that, we668 * calculate the down-scaling factor and multiply the plane669 * load by this number. We're likely over-estimating the read670 * demand, but that's better than under-estimating it.671 */672 vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i],673 vc4_state->crtc_h);674 vc4_state->membus_load += vc4_state->src_w[i] *675 vc4_state->src_h[i] * vscale_factor *676 fb->format->cpp[i];677 vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w;678 }679 680 vc4_state->hvs_load *= vrefresh;681 vc4_state->hvs_load >>= hvs_load_shift;682 vc4_state->membus_load *= vrefresh;683}684 685static int vc4_plane_allocate_lbm(struct drm_plane_state *state)686{687 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);688 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);689 unsigned long irqflags;690 u32 lbm_size;691 692 lbm_size = vc4_lbm_size(state);693 if (!lbm_size)694 return 0;695 696 if (WARN_ON(!vc4_state->lbm_offset))697 return -EINVAL;698 699 /* Allocate the LBM memory that the HVS will use for temporary700 * storage due to our scaling/format conversion.701 */702 if (!drm_mm_node_allocated(&vc4_state->lbm)) {703 int ret;704 705 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);706 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,707 &vc4_state->lbm,708 lbm_size,709 vc4->is_vc5 ? 64 : 32,710 0, 0);711 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);712 713 if (ret)714 return ret;715 } else {716 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);717 }718 719 vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;720 721 return 0;722}723 724/*725 * The colorspace conversion matrices are held in 3 entries in the dlist.726 * Create an array of them, with entries for each full and limited mode, and727 * each supported colorspace.728 */729static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {730 {731 /* Limited range */732 {733 /* BT601 */734 SCALER_CSC0_ITR_R_601_5,735 SCALER_CSC1_ITR_R_601_5,736 SCALER_CSC2_ITR_R_601_5,737 }, {738 /* BT709 */739 SCALER_CSC0_ITR_R_709_3,740 SCALER_CSC1_ITR_R_709_3,741 SCALER_CSC2_ITR_R_709_3,742 }, {743 /* BT2020 */744 SCALER_CSC0_ITR_R_2020,745 SCALER_CSC1_ITR_R_2020,746 SCALER_CSC2_ITR_R_2020,747 }748 }, {749 /* Full range */750 {751 /* JFIF */752 SCALER_CSC0_JPEG_JFIF,753 SCALER_CSC1_JPEG_JFIF,754 SCALER_CSC2_JPEG_JFIF,755 }, {756 /* BT709 */757 SCALER_CSC0_ITR_R_709_3_FR,758 SCALER_CSC1_ITR_R_709_3_FR,759 SCALER_CSC2_ITR_R_709_3_FR,760 }, {761 /* BT2020 */762 SCALER_CSC0_ITR_R_2020_FR,763 SCALER_CSC1_ITR_R_2020_FR,764 SCALER_CSC2_ITR_R_2020_FR,765 }766 }767};768 769static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state)770{771 if (!state->fb->format->has_alpha)772 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,773 SCALER_POS2_ALPHA_MODE);774 775 switch (state->pixel_blend_mode) {776 case DRM_MODE_BLEND_PIXEL_NONE:777 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,778 SCALER_POS2_ALPHA_MODE);779 default:780 case DRM_MODE_BLEND_PREMULTI:781 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,782 SCALER_POS2_ALPHA_MODE) |783 SCALER_POS2_ALPHA_PREMULT;784 case DRM_MODE_BLEND_COVERAGE:785 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,786 SCALER_POS2_ALPHA_MODE);787 }788}789 790static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state)791{792 if (!state->fb->format->has_alpha)793 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,794 SCALER5_CTL2_ALPHA_MODE);795 796 switch (state->pixel_blend_mode) {797 case DRM_MODE_BLEND_PIXEL_NONE:798 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,799 SCALER5_CTL2_ALPHA_MODE);800 default:801 case DRM_MODE_BLEND_PREMULTI:802 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,803 SCALER5_CTL2_ALPHA_MODE) |804 SCALER5_CTL2_ALPHA_PREMULT;805 case DRM_MODE_BLEND_COVERAGE:806 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,807 SCALER5_CTL2_ALPHA_MODE);808 }809}810 811/* Writes out a full display list for an active plane to the plane's812 * private dlist state.813 */814static int vc4_plane_mode_set(struct drm_plane *plane,815 struct drm_plane_state *state)816{817 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);818 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);819 struct drm_framebuffer *fb = state->fb;820 u32 ctl0_offset = vc4_state->dlist_count;821 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);822 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);823 int num_planes = fb->format->num_planes;824 u32 h_subsample = fb->format->hsub;825 u32 v_subsample = fb->format->vsub;826 bool mix_plane_alpha;827 bool covers_screen;828 u32 scl0, scl1, pitch0;829 u32 tiling, src_y;830 u32 hvs_format = format->hvs;831 unsigned int rotation;832 int ret, i;833 834 if (vc4_state->dlist_initialized)835 return 0;836 837 ret = vc4_plane_setup_clipping_and_scaling(state);838 if (ret)839 return ret;840 841 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB842 * and 4:4:4, scl1 should be set to scl0 so both channels of843 * the scaler do the same thing. For YUV, the Y plane needs844 * to be put in channel 1 and Cb/Cr in channel 0, so we swap845 * the scl fields here.846 */847 if (num_planes == 1) {848 scl0 = vc4_get_scl_field(state, 0);849 scl1 = scl0;850 } else {851 scl0 = vc4_get_scl_field(state, 1);852 scl1 = vc4_get_scl_field(state, 0);853 }854 855 rotation = drm_rotation_simplify(state->rotation,856 DRM_MODE_ROTATE_0 |857 DRM_MODE_REFLECT_X |858 DRM_MODE_REFLECT_Y);859 860 /* We must point to the last line when Y reflection is enabled. */861 src_y = vc4_state->src_y;862 if (rotation & DRM_MODE_REFLECT_Y)863 src_y += vc4_state->src_h[0] - 1;864 865 switch (base_format_mod) {866 case DRM_FORMAT_MOD_LINEAR:867 tiling = SCALER_CTL0_TILING_LINEAR;868 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);869 870 /* Adjust the base pointer to the first pixel to be scanned871 * out.872 */873 for (i = 0; i < num_planes; i++) {874 vc4_state->offsets[i] += src_y /875 (i ? v_subsample : 1) *876 fb->pitches[i];877 878 vc4_state->offsets[i] += vc4_state->src_x /879 (i ? h_subsample : 1) *880 fb->format->cpp[i];881 }882 883 break;884 885 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {886 u32 tile_size_shift = 12; /* T tiles are 4kb */887 /* Whole-tile offsets, mostly for setting the pitch. */888 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;889 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */890 u32 tile_w_mask = (1 << tile_w_shift) - 1;891 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice892 * the height (in pixels) of a 4k tile.893 */894 u32 tile_h_mask = (2 << tile_h_shift) - 1;895 /* For T-tiled, the FB pitch is "how many bytes from one row to896 * the next, such that897 *898 * pitch * tile_h == tile_size * tiles_per_row899 */900 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);901 u32 tiles_l = vc4_state->src_x >> tile_w_shift;902 u32 tiles_r = tiles_w - tiles_l;903 u32 tiles_t = src_y >> tile_h_shift;904 /* Intra-tile offsets, which modify the base address (the905 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that906 * base address).907 */908 u32 tile_y = (src_y >> 4) & 1;909 u32 subtile_y = (src_y >> 2) & 3;910 u32 utile_y = src_y & 3;911 u32 x_off = vc4_state->src_x & tile_w_mask;912 u32 y_off = src_y & tile_h_mask;913 914 /* When Y reflection is requested we must set the915 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines916 * after the initial one should be fetched in descending order,917 * which makes sense since we start from the last line and go918 * backward.919 * Don't know why we need y_off = max_y_off - y_off, but it's920 * definitely required (I guess it's also related to the "going921 * backward" situation).922 */923 if (rotation & DRM_MODE_REFLECT_Y) {924 y_off = tile_h_mask - y_off;925 pitch0 = SCALER_PITCH0_TILE_LINE_DIR;926 } else {927 pitch0 = 0;928 }929 930 tiling = SCALER_CTL0_TILING_256B_OR_T;931 pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |932 VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |933 VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |934 VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));935 vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);936 vc4_state->offsets[0] += subtile_y << 8;937 vc4_state->offsets[0] += utile_y << 4;938 939 /* Rows of tiles alternate left-to-right and right-to-left. */940 if (tiles_t & 1) {941 pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;942 vc4_state->offsets[0] += (tiles_w - tiles_l) <<943 tile_size_shift;944 vc4_state->offsets[0] -= (1 + !tile_y) << 10;945 } else {946 vc4_state->offsets[0] += tiles_l << tile_size_shift;947 vc4_state->offsets[0] += tile_y << 10;948 }949 950 break;951 }952 953 case DRM_FORMAT_MOD_BROADCOM_SAND64:954 case DRM_FORMAT_MOD_BROADCOM_SAND128:955 case DRM_FORMAT_MOD_BROADCOM_SAND256: {956 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);957 958 if (param > SCALER_TILE_HEIGHT_MASK) {959 DRM_DEBUG_KMS("SAND height too large (%d)\n",960 param);961 return -EINVAL;962 }963 964 if (fb->format->format == DRM_FORMAT_P030) {965 hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;966 tiling = SCALER_CTL0_TILING_128B;967 } else {968 hvs_format = HVS_PIXEL_FORMAT_H264;969 970 switch (base_format_mod) {971 case DRM_FORMAT_MOD_BROADCOM_SAND64:972 tiling = SCALER_CTL0_TILING_64B;973 break;974 case DRM_FORMAT_MOD_BROADCOM_SAND128:975 tiling = SCALER_CTL0_TILING_128B;976 break;977 case DRM_FORMAT_MOD_BROADCOM_SAND256:978 tiling = SCALER_CTL0_TILING_256B_OR_T;979 break;980 default:981 return -EINVAL;982 }983 }984 985 /* Adjust the base pointer to the first pixel to be scanned986 * out.987 *988 * For P030, y_ptr [31:4] is the 128bit word for the start pixel989 * y_ptr [3:0] is the pixel (0-11) contained within that 128bit990 * word that should be taken as the first pixel.991 * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the992 * element within the 128bit word, eg for pixel 3 the value993 * should be 6.994 */995 for (i = 0; i < num_planes; i++) {996 u32 tile_w, tile, x_off, pix_per_tile;997 998 if (fb->format->format == DRM_FORMAT_P030) {999 /*1000 * Spec says: bits [31:4] of the given address1001 * should point to the 128-bit word containing1002 * the desired starting pixel, and bits[3:0]1003 * should be between 0 and 11, indicating which1004 * of the 12-pixels in that 128-bit word is the1005 * first pixel to be used1006 */1007 u32 remaining_pixels = vc4_state->src_x % 96;1008 u32 aligned = remaining_pixels / 12;1009 u32 last_bits = remaining_pixels % 12;1010 1011 x_off = aligned * 16 + last_bits;1012 tile_w = 128;1013 pix_per_tile = 96;1014 } else {1015 switch (base_format_mod) {1016 case DRM_FORMAT_MOD_BROADCOM_SAND64:1017 tile_w = 64;1018 break;1019 case DRM_FORMAT_MOD_BROADCOM_SAND128:1020 tile_w = 128;1021 break;1022 case DRM_FORMAT_MOD_BROADCOM_SAND256:1023 tile_w = 256;1024 break;1025 default:1026 return -EINVAL;1027 }1028 pix_per_tile = tile_w / fb->format->cpp[0];1029 x_off = (vc4_state->src_x % pix_per_tile) /1030 (i ? h_subsample : 1) *1031 fb->format->cpp[i];1032 }1033 1034 tile = vc4_state->src_x / pix_per_tile;1035 1036 vc4_state->offsets[i] += param * tile_w * tile;1037 vc4_state->offsets[i] += src_y /1038 (i ? v_subsample : 1) *1039 tile_w;1040 vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);1041 }1042 1043 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);1044 break;1045 }1046 1047 default:1048 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",1049 (long long)fb->modifier);1050 return -EINVAL;1051 }1052 1053 /* Don't waste cycles mixing with plane alpha if the set alpha1054 * is opaque or there is no per-pixel alpha information.1055 * In any case we use the alpha property value as the fixed alpha.1056 */1057 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&1058 fb->format->has_alpha;1059 1060 if (!vc4->is_vc5) {1061 /* Control word */1062 vc4_dlist_write(vc4_state,1063 SCALER_CTL0_VALID |1064 (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |1065 (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |1066 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |1067 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |1068 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |1069 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |1070 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |1071 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |1072 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));1073 1074 /* Position Word 0: Image Positions and Alpha Value */1075 vc4_state->pos0_offset = vc4_state->dlist_count;1076 vc4_dlist_write(vc4_state,1077 VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |1078 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |1079 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));1080 1081 /* Position Word 1: Scaled Image Dimensions. */1082 if (!vc4_state->is_unity) {1083 vc4_dlist_write(vc4_state,1084 VC4_SET_FIELD(vc4_state->crtc_w,1085 SCALER_POS1_SCL_WIDTH) |1086 VC4_SET_FIELD(vc4_state->crtc_h,1087 SCALER_POS1_SCL_HEIGHT));1088 }1089 1090 /* Position Word 2: Source Image Size, Alpha */1091 vc4_state->pos2_offset = vc4_state->dlist_count;1092 vc4_dlist_write(vc4_state,1093 (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |1094 vc4_hvs4_get_alpha_blend_mode(state) |1095 VC4_SET_FIELD(vc4_state->src_w[0],1096 SCALER_POS2_WIDTH) |1097 VC4_SET_FIELD(vc4_state->src_h[0],1098 SCALER_POS2_HEIGHT));1099 1100 /* Position Word 3: Context. Written by the HVS. */1101 vc4_dlist_write(vc4_state, 0xc0c0c0c0);1102 1103 } else {1104 /* Control word */1105 vc4_dlist_write(vc4_state,1106 SCALER_CTL0_VALID |1107 (format->pixel_order_hvs5 << SCALER_CTL0_ORDER_SHIFT) |1108 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |1109 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |1110 (vc4_state->is_unity ?1111 SCALER5_CTL0_UNITY : 0) |1112 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |1113 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |1114 SCALER5_CTL0_ALPHA_EXPAND |1115 SCALER5_CTL0_RGB_EXPAND);1116 1117 /* Position Word 0: Image Positions and Alpha Value */1118 vc4_state->pos0_offset = vc4_state->dlist_count;1119 vc4_dlist_write(vc4_state,1120 (rotation & DRM_MODE_REFLECT_Y ?1121 SCALER5_POS0_VFLIP : 0) |1122 VC4_SET_FIELD(vc4_state->crtc_x,1123 SCALER_POS0_START_X) |1124 (rotation & DRM_MODE_REFLECT_X ?1125 SCALER5_POS0_HFLIP : 0) |1126 VC4_SET_FIELD(vc4_state->crtc_y,1127 SCALER5_POS0_START_Y)1128 );1129 1130 /* Control Word 2 */1131 vc4_dlist_write(vc4_state,1132 VC4_SET_FIELD(state->alpha >> 4,1133 SCALER5_CTL2_ALPHA) |1134 vc4_hvs5_get_alpha_blend_mode(state) |1135 (mix_plane_alpha ?1136 SCALER5_CTL2_ALPHA_MIX : 0)1137 );1138 1139 /* Position Word 1: Scaled Image Dimensions. */1140 if (!vc4_state->is_unity) {1141 vc4_dlist_write(vc4_state,1142 VC4_SET_FIELD(vc4_state->crtc_w,1143 SCALER5_POS1_SCL_WIDTH) |1144 VC4_SET_FIELD(vc4_state->crtc_h,1145 SCALER5_POS1_SCL_HEIGHT));1146 }1147 1148 /* Position Word 2: Source Image Size */1149 vc4_state->pos2_offset = vc4_state->dlist_count;1150 vc4_dlist_write(vc4_state,1151 VC4_SET_FIELD(vc4_state->src_w[0],1152 SCALER5_POS2_WIDTH) |1153 VC4_SET_FIELD(vc4_state->src_h[0],1154 SCALER5_POS2_HEIGHT));1155 1156 /* Position Word 3: Context. Written by the HVS. */1157 vc4_dlist_write(vc4_state, 0xc0c0c0c0);1158 }1159 1160 1161 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers1162 *1163 * The pointers may be any byte address.1164 */1165 vc4_state->ptr0_offset = vc4_state->dlist_count;1166 for (i = 0; i < num_planes; i++)1167 vc4_dlist_write(vc4_state, vc4_state->offsets[i]);1168 1169 /* Pointer Context Word 0/1/2: Written by the HVS */1170 for (i = 0; i < num_planes; i++)1171 vc4_dlist_write(vc4_state, 0xc0c0c0c0);1172 1173 /* Pitch word 0 */1174 vc4_dlist_write(vc4_state, pitch0);1175 1176 /* Pitch word 1/2 */1177 for (i = 1; i < num_planes; i++) {1178 if (hvs_format != HVS_PIXEL_FORMAT_H264 &&1179 hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {1180 vc4_dlist_write(vc4_state,1181 VC4_SET_FIELD(fb->pitches[i],1182 SCALER_SRC_PITCH));1183 } else {1184 vc4_dlist_write(vc4_state, pitch0);1185 }1186 }1187 1188 /* Colorspace conversion words */1189 if (vc4_state->is_yuv) {1190 enum drm_color_encoding color_encoding = state->color_encoding;1191 enum drm_color_range color_range = state->color_range;1192 const u32 *ccm;1193 1194 if (color_encoding >= DRM_COLOR_ENCODING_MAX)1195 color_encoding = DRM_COLOR_YCBCR_BT601;1196 if (color_range >= DRM_COLOR_RANGE_MAX)1197 color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;1198 1199 ccm = colorspace_coeffs[color_range][color_encoding];1200 1201 vc4_dlist_write(vc4_state, ccm[0]);1202 vc4_dlist_write(vc4_state, ccm[1]);1203 vc4_dlist_write(vc4_state, ccm[2]);1204 }1205 1206 vc4_state->lbm_offset = 0;1207 1208 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||1209 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||1210 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||1211 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {1212 /* Reserve a slot for the LBM Base Address. The real value will1213 * be set when calling vc4_plane_allocate_lbm().1214 */1215 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||1216 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {1217 vc4_state->lbm_offset = vc4_state->dlist_count;1218 vc4_dlist_counter_increment(vc4_state);1219 }1220 1221 if (num_planes > 1) {1222 /* Emit Cb/Cr as channel 0 and Y as channel1223 * 1. This matches how we set up scl0/scl11224 * above.1225 */1226 vc4_write_scaling_parameters(state, 1);1227 }1228 vc4_write_scaling_parameters(state, 0);1229 1230 /* If any PPF setup was done, then all the kernel1231 * pointers get uploaded.1232 */1233 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||1234 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||1235 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||1236 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {1237 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,1238 SCALER_PPF_KERNEL_OFFSET);1239 1240 /* HPPF plane 0 */1241 vc4_dlist_write(vc4_state, kernel);1242 /* VPPF plane 0 */1243 vc4_dlist_write(vc4_state, kernel);1244 /* HPPF plane 1 */1245 vc4_dlist_write(vc4_state, kernel);1246 /* VPPF plane 1 */1247 vc4_dlist_write(vc4_state, kernel);1248 }1249 }1250 1251 vc4_state->dlist[ctl0_offset] |=1252 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);1253 1254 /* crtc_* are already clipped coordinates. */1255 covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&1256 vc4_state->crtc_w == state->crtc->mode.hdisplay &&1257 vc4_state->crtc_h == state->crtc->mode.vdisplay;1258 /* Background fill might be necessary when the plane has per-pixel1259 * alpha content or a non-opaque plane alpha and could blend from the1260 * background or does not cover the entire screen.1261 */1262 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||1263 state->alpha != DRM_BLEND_ALPHA_OPAQUE;1264 1265 /* Flag the dlist as initialized to avoid checking it twice in case1266 * the async update check already called vc4_plane_mode_set() and1267 * decided to fallback to sync update because async update was not1268 * possible.1269 */1270 vc4_state->dlist_initialized = 1;1271 1272 vc4_plane_calc_load(state);1273 1274 return 0;1275}1276 1277/* If a modeset involves changing the setup of a plane, the atomic1278 * infrastructure will call this to validate a proposed plane setup.1279 * However, if a plane isn't getting updated, this (and the1280 * corresponding vc4_plane_atomic_update) won't get called. Thus, we1281 * compute the dlist here and have all active plane dlists get updated1282 * in the CRTC's flush.1283 */1284static int vc4_plane_atomic_check(struct drm_plane *plane,1285 struct drm_atomic_state *state)1286{1287 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,1288 plane);1289 struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state);1290 int ret;1291 1292 vc4_state->dlist_count = 0;1293 1294 if (!plane_enabled(new_plane_state))1295 return 0;1296 1297 ret = vc4_plane_mode_set(plane, new_plane_state);1298 if (ret)1299 return ret;1300 1301 return vc4_plane_allocate_lbm(new_plane_state);1302}1303 1304static void vc4_plane_atomic_update(struct drm_plane *plane,1305 struct drm_atomic_state *state)1306{1307 /* No contents here. Since we don't know where in the CRTC's1308 * dlist we should be stored, our dlist is uploaded to the1309 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush1310 * time.1311 */1312}1313 1314u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)1315{1316 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);1317 int i;1318 int idx;1319 1320 if (!drm_dev_enter(plane->dev, &idx))1321 goto out;1322 1323 vc4_state->hw_dlist = dlist;1324 1325 /* Can't memcpy_toio() because it needs to be 32-bit writes. */1326 for (i = 0; i < vc4_state->dlist_count; i++)1327 writel(vc4_state->dlist[i], &dlist[i]);1328 1329 drm_dev_exit(idx);1330 1331out:1332 return vc4_state->dlist_count;1333}1334 1335u32 vc4_plane_dlist_size(const struct drm_plane_state *state)1336{1337 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);1338 1339 return vc4_state->dlist_count;1340}1341 1342/* Updates the plane to immediately (well, once the FIFO needs1343 * refilling) scan out from at a new framebuffer.1344 */1345void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)1346{1347 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);1348 struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0);1349 uint32_t addr;1350 int idx;1351 1352 if (!drm_dev_enter(plane->dev, &idx))1353 return;1354 1355 /* We're skipping the address adjustment for negative origin,1356 * because this is only called on the primary plane.1357 */1358 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);1359 addr = bo->dma_addr + fb->offsets[0];1360 1361 /* Write the new address into the hardware immediately. The1362 * scanout will start from this address as soon as the FIFO1363 * needs to refill with pixels.1364 */1365 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);1366 1367 /* Also update the CPU-side dlist copy, so that any later1368 * atomic updates that don't do a new modeset on our plane1369 * also use our updated address.1370 */1371 vc4_state->dlist[vc4_state->ptr0_offset] = addr;1372 1373 drm_dev_exit(idx);1374}1375 1376static void vc4_plane_atomic_async_update(struct drm_plane *plane,1377 struct drm_atomic_state *state)1378{1379 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,1380 plane);1381 struct vc4_plane_state *vc4_state, *new_vc4_state;1382 int idx;1383 1384 if (!drm_dev_enter(plane->dev, &idx))1385 return;1386 1387 swap(plane->state->fb, new_plane_state->fb);1388 plane->state->crtc_x = new_plane_state->crtc_x;1389 plane->state->crtc_y = new_plane_state->crtc_y;1390 plane->state->crtc_w = new_plane_state->crtc_w;1391 plane->state->crtc_h = new_plane_state->crtc_h;1392 plane->state->src_x = new_plane_state->src_x;1393 plane->state->src_y = new_plane_state->src_y;1394 plane->state->src_w = new_plane_state->src_w;1395 plane->state->src_h = new_plane_state->src_h;1396 plane->state->alpha = new_plane_state->alpha;1397 plane->state->pixel_blend_mode = new_plane_state->pixel_blend_mode;1398 plane->state->rotation = new_plane_state->rotation;1399 plane->state->zpos = new_plane_state->zpos;1400 plane->state->normalized_zpos = new_plane_state->normalized_zpos;1401 plane->state->color_encoding = new_plane_state->color_encoding;1402 plane->state->color_range = new_plane_state->color_range;1403 plane->state->src = new_plane_state->src;1404 plane->state->dst = new_plane_state->dst;1405 plane->state->visible = new_plane_state->visible;1406 1407 new_vc4_state = to_vc4_plane_state(new_plane_state);1408 vc4_state = to_vc4_plane_state(plane->state);1409 1410 vc4_state->crtc_x = new_vc4_state->crtc_x;1411 vc4_state->crtc_y = new_vc4_state->crtc_y;1412 vc4_state->crtc_h = new_vc4_state->crtc_h;1413 vc4_state->crtc_w = new_vc4_state->crtc_w;1414 vc4_state->src_x = new_vc4_state->src_x;1415 vc4_state->src_y = new_vc4_state->src_y;1416 memcpy(vc4_state->src_w, new_vc4_state->src_w,1417 sizeof(vc4_state->src_w));1418 memcpy(vc4_state->src_h, new_vc4_state->src_h,1419 sizeof(vc4_state->src_h));1420 memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,1421 sizeof(vc4_state->x_scaling));1422 memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,1423 sizeof(vc4_state->y_scaling));1424 vc4_state->is_unity = new_vc4_state->is_unity;1425 vc4_state->is_yuv = new_vc4_state->is_yuv;1426 memcpy(vc4_state->offsets, new_vc4_state->offsets,1427 sizeof(vc4_state->offsets));1428 vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;1429 1430 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */1431 vc4_state->dlist[vc4_state->pos0_offset] =1432 new_vc4_state->dlist[vc4_state->pos0_offset];1433 vc4_state->dlist[vc4_state->pos2_offset] =1434 new_vc4_state->dlist[vc4_state->pos2_offset];1435 vc4_state->dlist[vc4_state->ptr0_offset] =1436 new_vc4_state->dlist[vc4_state->ptr0_offset];1437 1438 /* Note that we can't just call vc4_plane_write_dlist()1439 * because that would smash the context data that the HVS is1440 * currently using.1441 */1442 writel(vc4_state->dlist[vc4_state->pos0_offset],1443 &vc4_state->hw_dlist[vc4_state->pos0_offset]);1444 writel(vc4_state->dlist[vc4_state->pos2_offset],1445 &vc4_state->hw_dlist[vc4_state->pos2_offset]);1446 writel(vc4_state->dlist[vc4_state->ptr0_offset],1447 &vc4_state->hw_dlist[vc4_state->ptr0_offset]);1448 1449 drm_dev_exit(idx);1450}1451 1452static int vc4_plane_atomic_async_check(struct drm_plane *plane,1453 struct drm_atomic_state *state)1454{1455 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,1456 plane);1457 struct vc4_plane_state *old_vc4_state, *new_vc4_state;1458 int ret;1459 u32 i;1460 1461 ret = vc4_plane_mode_set(plane, new_plane_state);1462 if (ret)1463 return ret;1464 1465 old_vc4_state = to_vc4_plane_state(plane->state);1466 new_vc4_state = to_vc4_plane_state(new_plane_state);1467 1468 if (!new_vc4_state->hw_dlist)1469 return -EINVAL;1470 1471 if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||1472 old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||1473 old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||1474 old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset ||1475 vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state))1476 return -EINVAL;1477 1478 /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update1479 * if anything else has changed, fallback to a sync update.1480 */1481 for (i = 0; i < new_vc4_state->dlist_count; i++) {1482 if (i == new_vc4_state->pos0_offset ||1483 i == new_vc4_state->pos2_offset ||1484 i == new_vc4_state->ptr0_offset ||1485 (new_vc4_state->lbm_offset &&1486 i == new_vc4_state->lbm_offset))1487 continue;1488 1489 if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])1490 return -EINVAL;1491 }1492 1493 return 0;1494}1495 1496static int vc4_prepare_fb(struct drm_plane *plane,1497 struct drm_plane_state *state)1498{1499 struct vc4_bo *bo;1500 int ret;1501 1502 if (!state->fb)1503 return 0;1504 1505 bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);1506 1507 ret = drm_gem_plane_helper_prepare_fb(plane, state);1508 if (ret)1509 return ret;1510 1511 return vc4_bo_inc_usecnt(bo);1512}1513 1514static void vc4_cleanup_fb(struct drm_plane *plane,1515 struct drm_plane_state *state)1516{1517 struct vc4_bo *bo;1518 1519 if (!state->fb)1520 return;1521 1522 bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);1523 vc4_bo_dec_usecnt(bo);1524}1525 1526static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {1527 .atomic_check = vc4_plane_atomic_check,1528 .atomic_update = vc4_plane_atomic_update,1529 .prepare_fb = vc4_prepare_fb,1530 .cleanup_fb = vc4_cleanup_fb,1531 .atomic_async_check = vc4_plane_atomic_async_check,1532 .atomic_async_update = vc4_plane_atomic_async_update,1533};1534 1535static const struct drm_plane_helper_funcs vc5_plane_helper_funcs = {1536 .atomic_check = vc4_plane_atomic_check,1537 .atomic_update = vc4_plane_atomic_update,1538 .atomic_async_check = vc4_plane_atomic_async_check,1539 .atomic_async_update = vc4_plane_atomic_async_update,1540};1541 1542static bool vc4_format_mod_supported(struct drm_plane *plane,1543 uint32_t format,1544 uint64_t modifier)1545{1546 /* Support T_TILING for RGB formats only. */1547 switch (format) {1548 case DRM_FORMAT_XRGB8888:1549 case DRM_FORMAT_ARGB8888:1550 case DRM_FORMAT_ABGR8888:1551 case DRM_FORMAT_XBGR8888:1552 case DRM_FORMAT_RGB565:1553 case DRM_FORMAT_BGR565:1554 case DRM_FORMAT_ARGB1555:1555 case DRM_FORMAT_XRGB1555:1556 switch (fourcc_mod_broadcom_mod(modifier)) {1557 case DRM_FORMAT_MOD_LINEAR:1558 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:1559 return true;1560 default:1561 return false;1562 }1563 case DRM_FORMAT_NV12:1564 case DRM_FORMAT_NV21:1565 switch (fourcc_mod_broadcom_mod(modifier)) {1566 case DRM_FORMAT_MOD_LINEAR:1567 case DRM_FORMAT_MOD_BROADCOM_SAND64:1568 case DRM_FORMAT_MOD_BROADCOM_SAND128:1569 case DRM_FORMAT_MOD_BROADCOM_SAND256:1570 return true;1571 default:1572 return false;1573 }1574 case DRM_FORMAT_P030:1575 switch (fourcc_mod_broadcom_mod(modifier)) {1576 case DRM_FORMAT_MOD_BROADCOM_SAND128:1577 return true;1578 default:1579 return false;1580 }1581 case DRM_FORMAT_RGBX1010102:1582 case DRM_FORMAT_BGRX1010102:1583 case DRM_FORMAT_RGBA1010102:1584 case DRM_FORMAT_BGRA1010102:1585 case DRM_FORMAT_XRGB4444:1586 case DRM_FORMAT_ARGB4444:1587 case DRM_FORMAT_XBGR4444:1588 case DRM_FORMAT_ABGR4444:1589 case DRM_FORMAT_RGBX4444:1590 case DRM_FORMAT_RGBA4444:1591 case DRM_FORMAT_BGRX4444:1592 case DRM_FORMAT_BGRA4444:1593 case DRM_FORMAT_RGB332:1594 case DRM_FORMAT_BGR233:1595 case DRM_FORMAT_YUV422:1596 case DRM_FORMAT_YVU422:1597 case DRM_FORMAT_YUV420:1598 case DRM_FORMAT_YVU420:1599 case DRM_FORMAT_NV16:1600 case DRM_FORMAT_NV61:1601 default:1602 return (modifier == DRM_FORMAT_MOD_LINEAR);1603 }1604}1605 1606static const struct drm_plane_funcs vc4_plane_funcs = {1607 .update_plane = drm_atomic_helper_update_plane,1608 .disable_plane = drm_atomic_helper_disable_plane,1609 .reset = vc4_plane_reset,1610 .atomic_duplicate_state = vc4_plane_duplicate_state,1611 .atomic_destroy_state = vc4_plane_destroy_state,1612 .format_mod_supported = vc4_format_mod_supported,1613};1614 1615struct drm_plane *vc4_plane_init(struct drm_device *dev,1616 enum drm_plane_type type,1617 uint32_t possible_crtcs)1618{1619 struct vc4_dev *vc4 = to_vc4_dev(dev);1620 struct drm_plane *plane;1621 struct vc4_plane *vc4_plane;1622 u32 formats[ARRAY_SIZE(hvs_formats)];1623 int num_formats = 0;1624 unsigned i;1625 static const uint64_t modifiers[] = {1626 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,1627 DRM_FORMAT_MOD_BROADCOM_SAND128,1628 DRM_FORMAT_MOD_BROADCOM_SAND64,1629 DRM_FORMAT_MOD_BROADCOM_SAND256,1630 DRM_FORMAT_MOD_LINEAR,1631 DRM_FORMAT_MOD_INVALID1632 };1633 1634 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {1635 if (!hvs_formats[i].hvs5_only || vc4->is_vc5) {1636 formats[num_formats] = hvs_formats[i].drm;1637 num_formats++;1638 }1639 }1640 1641 vc4_plane = drmm_universal_plane_alloc(dev, struct vc4_plane, base,1642 possible_crtcs,1643 &vc4_plane_funcs,1644 formats, num_formats,1645 modifiers, type, NULL);1646 if (IS_ERR(vc4_plane))1647 return ERR_CAST(vc4_plane);1648 plane = &vc4_plane->base;1649 1650 if (vc4->is_vc5)1651 drm_plane_helper_add(plane, &vc5_plane_helper_funcs);1652 else1653 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);1654 1655 drm_plane_create_alpha_property(plane);1656 drm_plane_create_blend_mode_property(plane,1657 BIT(DRM_MODE_BLEND_PIXEL_NONE) |1658 BIT(DRM_MODE_BLEND_PREMULTI) |1659 BIT(DRM_MODE_BLEND_COVERAGE));1660 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,1661 DRM_MODE_ROTATE_0 |1662 DRM_MODE_ROTATE_180 |1663 DRM_MODE_REFLECT_X |1664 DRM_MODE_REFLECT_Y);1665 1666 drm_plane_create_color_properties(plane,1667 BIT(DRM_COLOR_YCBCR_BT601) |1668 BIT(DRM_COLOR_YCBCR_BT709) |1669 BIT(DRM_COLOR_YCBCR_BT2020),1670 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |1671 BIT(DRM_COLOR_YCBCR_FULL_RANGE),1672 DRM_COLOR_YCBCR_BT709,1673 DRM_COLOR_YCBCR_LIMITED_RANGE);1674 1675 if (type == DRM_PLANE_TYPE_PRIMARY)1676 drm_plane_create_zpos_immutable_property(plane, 0);1677 1678 return plane;1679}1680 1681#define VC4_NUM_OVERLAY_PLANES 161682 1683int vc4_plane_create_additional_planes(struct drm_device *drm)1684{1685 struct drm_plane *cursor_plane;1686 struct drm_crtc *crtc;1687 unsigned int i;1688 1689 /* Set up some arbitrary number of planes. We're not limited1690 * by a set number of physical registers, just the space in1691 * the HVS (16k) and how small an plane can be (28 bytes).1692 * However, each plane we set up takes up some memory, and1693 * increases the cost of looping over planes, which atomic1694 * modesetting does quite a bit. As a result, we pick a1695 * modest number of planes to expose, that should hopefully1696 * still cover any sane usecase.1697 */1698 for (i = 0; i < VC4_NUM_OVERLAY_PLANES; i++) {1699 struct drm_plane *plane =1700 vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,1701 GENMASK(drm->mode_config.num_crtc - 1, 0));1702 1703 if (IS_ERR(plane))1704 continue;1705 1706 /* Create zpos property. Max of all the overlays + 1 primary +1707 * 1 cursor plane on a crtc.1708 */1709 drm_plane_create_zpos_property(plane, i + 1, 1,1710 VC4_NUM_OVERLAY_PLANES + 1);1711 }1712 1713 drm_for_each_crtc(crtc, drm) {1714 /* Set up the legacy cursor after overlay initialization,1715 * since the zpos fallback is that planes are rendered by plane1716 * ID order, and that then puts the cursor on top.1717 */1718 cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR,1719 drm_crtc_mask(crtc));1720 if (!IS_ERR(cursor_plane)) {1721 crtc->cursor = cursor_plane;1722 1723 drm_plane_create_zpos_property(cursor_plane,1724 VC4_NUM_OVERLAY_PLANES + 1,1725 1,1726 VC4_NUM_OVERLAY_PLANES + 1);1727 }1728 }1729 1730 return 0;1731}1732