Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/meson: plane: add support for AFBC mode for OSD1 plane

This adds all the OSD configuration plumbing to support the AFBC decoders
path to display of the OSD1 plane.

The Amlogic GXM and G12A AFBC decoders are integrated very differently.

The Amlogic GXM has a direct output path to the OSD1 VIU pixel input,
because the GXM AFBC decoder seem to be a custom IP developed by Amlogic.

On the other side, the Amlogic G12A AFBC decoder seems to be an external
IP that emit pixels on an AXI master hooked to a "Mali Unpack" block
feeding the OSD1 VIU pixel input.
This uses a weird "0x1000000" internal HW physical address on both
sides to transfer the pixels.

For Amlogic GXM, the supported pixel formats are the same as the normal
linear OSD1 mode.

On the other side, Amlogic added support for all AFBC v1.2 formats for
the G12A AFBC integration.

For simplicity, we stick to the already supported formats for now.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191021091509.3864-7-narmstrong@baylibre.com

+203 -31
+2
drivers/gpu/drm/meson/meson_crtc.c
··· 281 281 if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { 282 282 writel_relaxed(priv->viu.osd1_ctrl_stat, 283 283 priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); 284 + writel_relaxed(priv->viu.osd1_ctrl_stat2, 285 + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 284 286 writel_relaxed(priv->viu.osd1_blk0_cfg[0], 285 287 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); 286 288 writel_relaxed(priv->viu.osd1_blk0_cfg[1],
+4
drivers/gpu/drm/meson/meson_drv.h
··· 53 53 bool osd1_enabled; 54 54 bool osd1_interlace; 55 55 bool osd1_commit; 56 + bool osd1_afbcd; 56 57 uint32_t osd1_ctrl_stat; 58 + uint32_t osd1_ctrl_stat2; 57 59 uint32_t osd1_blk0_cfg[5]; 60 + uint32_t osd1_blk1_cfg4; 61 + uint32_t osd1_blk2_cfg4; 58 62 uint32_t osd1_addr; 59 63 uint32_t osd1_stride; 60 64 uint32_t osd1_height;
+197 -31
drivers/gpu/drm/meson/meson_plane.c
··· 23 23 #include "meson_plane.h" 24 24 #include "meson_registers.h" 25 25 #include "meson_viu.h" 26 + #include "meson_osd_afbcd.h" 26 27 27 28 /* OSD_SCI_WH_M1 */ 28 29 #define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) ··· 93 92 false, true); 94 93 } 95 94 95 + #define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | \ 96 + AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | \ 97 + AFBC_FORMAT_MOD_YTR | \ 98 + AFBC_FORMAT_MOD_SPARSE | \ 99 + AFBC_FORMAT_MOD_SPLIT) 100 + 96 101 /* Takes a fixed 16.16 number and converts it to integer. */ 97 102 static inline int64_t fixed16_to_int(int64_t value) 98 103 { 99 104 return value >> 16; 105 + } 106 + 107 + static u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv) 108 + { 109 + u32 line_stride = 0; 110 + 111 + switch (priv->afbcd.format) { 112 + case DRM_FORMAT_RGB565: 113 + line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7; 114 + break; 115 + case DRM_FORMAT_RGB888: 116 + case DRM_FORMAT_XRGB8888: 117 + case DRM_FORMAT_ARGB8888: 118 + case DRM_FORMAT_XBGR8888: 119 + case DRM_FORMAT_ABGR8888: 120 + line_stride = ((priv->viu.osd1_width << 5) + 127) >> 7; 121 + break; 122 + } 123 + 124 + return ((line_stride + 1) >> 1) << 1; 100 125 } 101 126 102 127 static void meson_plane_atomic_update(struct drm_plane *plane, ··· 153 126 */ 154 127 spin_lock_irqsave(&priv->drm->event_lock, flags); 155 128 129 + /* Check if AFBC decoder is required for this buffer */ 130 + if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || 131 + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) && 132 + fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) 133 + priv->viu.osd1_afbcd = true; 134 + else 135 + priv->viu.osd1_afbcd = false; 136 + 156 137 /* Enable OSD and BLK0, set max global alpha */ 157 138 priv->viu.osd1_ctrl_stat = OSD_ENABLE | 158 139 (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | 159 140 OSD_BLK0_ENABLE; 160 141 142 + priv->viu.osd1_ctrl_stat2 = readl(priv->io_base + 143 + _REG(VIU_OSD1_CTRL_STAT2)); 144 + 161 145 canvas_id_osd1 = priv->canvas_id_osd1; 162 146 163 147 /* Set up BLK0 to point to the right canvas */ 164 - priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | 165 - OSD_ENDIANNESS_LE); 148 + priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL; 149 + 150 + if (priv->viu.osd1_afbcd) { 151 + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 152 + /* This is the internal decoding memory address */ 153 + priv->viu.osd1_blk1_cfg4 = MESON_G12A_AFBCD_OUT_ADDR; 154 + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_BE; 155 + priv->viu.osd1_ctrl_stat2 |= OSD_PENDING_STAT_CLEAN; 156 + priv->viu.osd1_ctrl_stat |= VIU_OSD1_CFG_SYN_EN; 157 + } 158 + 159 + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { 160 + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; 161 + priv->viu.osd1_ctrl_stat2 |= OSD_DPATH_MALI_AFBCD; 162 + } 163 + } else { 164 + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; 165 + 166 + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) 167 + priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD; 168 + } 166 169 167 170 /* On GXBB, Use the old non-HDR RGB2YUV converter */ 168 171 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) 169 172 priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; 170 173 174 + if (priv->viu.osd1_afbcd && 175 + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 176 + priv->viu.osd1_blk0_cfg[0] |= OSD_MALI_SRC_EN | 177 + priv->afbcd.ops->fmt_to_blk_mode(fb->modifier, 178 + fb->format->format); 179 + } else { 180 + switch (fb->format->format) { 181 + case DRM_FORMAT_XRGB8888: 182 + case DRM_FORMAT_ARGB8888: 183 + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 184 + OSD_COLOR_MATRIX_32_ARGB; 185 + break; 186 + case DRM_FORMAT_XBGR8888: 187 + case DRM_FORMAT_ABGR8888: 188 + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 189 + OSD_COLOR_MATRIX_32_ABGR; 190 + break; 191 + case DRM_FORMAT_RGB888: 192 + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | 193 + OSD_COLOR_MATRIX_24_RGB; 194 + break; 195 + case DRM_FORMAT_RGB565: 196 + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | 197 + OSD_COLOR_MATRIX_16_RGB565; 198 + break; 199 + }; 200 + } 201 + 171 202 switch (fb->format->format) { 172 203 case DRM_FORMAT_XRGB8888: 173 - /* For XRGB, replace the pixel's alpha by 0xFF */ 174 - writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, 175 - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 176 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 177 - OSD_COLOR_MATRIX_32_ARGB; 178 - break; 179 204 case DRM_FORMAT_XBGR8888: 180 205 /* For XRGB, replace the pixel's alpha by 0xFF */ 181 - writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, 182 - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 183 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 184 - OSD_COLOR_MATRIX_32_ABGR; 206 + priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN; 185 207 break; 186 208 case DRM_FORMAT_ARGB8888: 187 - /* For ARGB, use the pixel's alpha */ 188 - writel_bits_relaxed(OSD_REPLACE_EN, 0, 189 - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 190 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 191 - OSD_COLOR_MATRIX_32_ARGB; 192 - break; 193 209 case DRM_FORMAT_ABGR8888: 194 210 /* For ARGB, use the pixel's alpha */ 195 - writel_bits_relaxed(OSD_REPLACE_EN, 0, 196 - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 197 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 198 - OSD_COLOR_MATRIX_32_ABGR; 199 - break; 200 - case DRM_FORMAT_RGB888: 201 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | 202 - OSD_COLOR_MATRIX_24_RGB; 203 - break; 204 - case DRM_FORMAT_RGB565: 205 - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | 206 - OSD_COLOR_MATRIX_16_RGB565; 211 + priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN; 207 212 break; 208 213 }; 209 214 ··· 366 307 priv->viu.osd1_height = fb->height; 367 308 priv->viu.osd1_width = fb->width; 368 309 310 + if (priv->viu.osd1_afbcd) { 311 + priv->afbcd.modifier = fb->modifier; 312 + priv->afbcd.format = fb->format->format; 313 + 314 + /* Calculate decoder write stride */ 315 + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 316 + priv->viu.osd1_blk2_cfg4 = 317 + meson_g12a_afbcd_line_stride(priv); 318 + } 319 + 369 320 if (!meson_plane->enabled) { 370 321 /* Reset OSD1 before enabling it on GXL+ SoCs */ 371 322 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || ··· 396 327 struct meson_plane *meson_plane = to_meson_plane(plane); 397 328 struct meson_drm *priv = meson_plane->priv; 398 329 330 + if (priv->afbcd.ops) { 331 + priv->afbcd.ops->reset(priv); 332 + priv->afbcd.ops->disable(priv); 333 + } 334 + 399 335 /* Disable OSD1 */ 400 336 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 401 337 writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, ··· 420 346 .prepare_fb = drm_gem_fb_prepare_fb, 421 347 }; 422 348 349 + static bool meson_plane_format_mod_supported(struct drm_plane *plane, 350 + u32 format, u64 modifier) 351 + { 352 + struct meson_plane *meson_plane = to_meson_plane(plane); 353 + struct meson_drm *priv = meson_plane->priv; 354 + int i; 355 + 356 + if (modifier == DRM_FORMAT_MOD_INVALID) 357 + return false; 358 + 359 + if (modifier == DRM_FORMAT_MOD_LINEAR) 360 + return true; 361 + 362 + if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) && 363 + !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 364 + return false; 365 + 366 + if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) 367 + return false; 368 + 369 + for (i = 0 ; i < plane->modifier_count ; ++i) 370 + if (plane->modifiers[i] == modifier) 371 + break; 372 + 373 + if (i == plane->modifier_count) { 374 + DRM_DEBUG_KMS("Unsupported modifier\n"); 375 + return false; 376 + } 377 + 378 + if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt) 379 + return priv->afbcd.ops->supported_fmt(modifier, format); 380 + 381 + DRM_DEBUG_KMS("AFBC Unsupported\n"); 382 + return false; 383 + } 384 + 423 385 static const struct drm_plane_funcs meson_plane_funcs = { 424 386 .update_plane = drm_atomic_helper_update_plane, 425 387 .disable_plane = drm_atomic_helper_disable_plane, ··· 463 353 .reset = drm_atomic_helper_plane_reset, 464 354 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 465 355 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 356 + .format_mod_supported = meson_plane_format_mod_supported, 466 357 }; 467 358 468 359 static const uint32_t supported_drm_formats[] = { ··· 475 364 DRM_FORMAT_RGB565, 476 365 }; 477 366 367 + static const uint64_t format_modifiers_afbc_gxm[] = { 368 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 369 + AFBC_FORMAT_MOD_SPARSE | 370 + AFBC_FORMAT_MOD_YTR), 371 + /* SPLIT mandates SPARSE, RGB modes mandates YTR */ 372 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 373 + AFBC_FORMAT_MOD_YTR | 374 + AFBC_FORMAT_MOD_SPARSE | 375 + AFBC_FORMAT_MOD_SPLIT), 376 + DRM_FORMAT_MOD_LINEAR, 377 + DRM_FORMAT_MOD_INVALID, 378 + }; 379 + 380 + static const uint64_t format_modifiers_afbc_g12a[] = { 381 + /* 382 + * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED) 383 + * - SPLIT is mandatory for performances reasons when in 16x16 384 + * block size 385 + * - 32x8 block size + SPLIT is mandatory with 4K frame size 386 + * for performances reasons 387 + */ 388 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 389 + AFBC_FORMAT_MOD_SPARSE | 390 + AFBC_FORMAT_MOD_SPLIT), 391 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 392 + AFBC_FORMAT_MOD_YTR | 393 + AFBC_FORMAT_MOD_SPARSE | 394 + AFBC_FORMAT_MOD_SPLIT), 395 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 396 + AFBC_FORMAT_MOD_SPARSE), 397 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 398 + AFBC_FORMAT_MOD_YTR | 399 + AFBC_FORMAT_MOD_SPARSE), 400 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 401 + AFBC_FORMAT_MOD_SPARSE | 402 + AFBC_FORMAT_MOD_SPLIT), 403 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 404 + AFBC_FORMAT_MOD_YTR | 405 + AFBC_FORMAT_MOD_SPARSE | 406 + AFBC_FORMAT_MOD_SPLIT), 407 + DRM_FORMAT_MOD_LINEAR, 408 + DRM_FORMAT_MOD_INVALID, 409 + }; 410 + 411 + static const uint64_t format_modifiers_default[] = { 412 + DRM_FORMAT_MOD_LINEAR, 413 + DRM_FORMAT_MOD_INVALID, 414 + }; 415 + 478 416 int meson_plane_create(struct meson_drm *priv) 479 417 { 480 418 struct meson_plane *meson_plane; 481 419 struct drm_plane *plane; 420 + const uint64_t *format_modifiers = format_modifiers_default; 482 421 483 422 meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane), 484 423 GFP_KERNEL); ··· 538 377 meson_plane->priv = priv; 539 378 plane = &meson_plane->base; 540 379 380 + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) 381 + format_modifiers = format_modifiers_afbc_gxm; 382 + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 383 + format_modifiers = format_modifiers_afbc_g12a; 384 + 541 385 drm_universal_plane_init(priv->drm, plane, 0xFF, 542 386 &meson_plane_funcs, 543 387 supported_drm_formats, 544 388 ARRAY_SIZE(supported_drm_formats), 545 - NULL, 389 + format_modifiers, 546 390 DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); 547 391 548 392 drm_plane_helper_add(plane, &meson_plane_helper_funcs);