/* * This 4-entry look-up-table is used to determine the full 8-bit alpha value * for formats with 1- or 2-bit alpha channels. * We set it to give 100%/0% opacity for 1-bit formats and 100%/66%/33%/0% * opacity for 2-bit formats.
*/ #define MALIDP_ALPHA_LUT 0xffaa5500
/* page sizes the MMU prefetcher can support */ #define MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES (SZ_4K | SZ_64K) #define MALIDP_MMU_PREFETCH_FULL_PGSIZES (SZ_1M | SZ_2M)
/* readahead for partial-frame prefetch */ #define MALIDP_MMU_PREFETCH_READAHEAD 8
/* * Replicate what the default ->reset hook does: free the state pointer and * allocate a new empty object. We just need enough space to store * a malidp_plane_state instead of a drm_plane_state.
*/ staticvoid malidp_plane_reset(struct drm_plane *plane)
{ struct malidp_plane_state *state = to_malidp_plane_state(plane->state);
if (state)
__drm_atomic_helper_plane_destroy_state(&state->base);
kfree(state);
plane->state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL); if (state)
__drm_atomic_helper_plane_reset(plane, &state->base);
}
if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID)) returnfalse;
/* Some pixel formats are supported without any modifier */ if (modifier == DRM_FORMAT_MOD_LINEAR) { /* * However these pixel formats need to be supported with * modifiers only
*/ return !malidp_hw_format_is_afbc_only(format);
}
if (!fourcc_mod_is_vendor(modifier, ARM)) {
DRM_DEBUG_KMS("Unknown modifier (not Arm)\n"); returnfalse;
}
if (modifier &
~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
DRM_DEBUG_KMS("Unsupported modifiers\n"); returnfalse;
}
modifiers = malidp_format_modifiers;
/* SPLIT buffers must use SPARSE layout */ if (WARN_ON_ONCE((modifier & AFBC_SPLIT) && !(modifier & AFBC_SPARSE))) returnfalse;
/* CBR only applies to YUV formats, where YTR should be always 0 */ if (WARN_ON_ONCE((modifier & AFBC_CBR) && (modifier & AFBC_YTR))) returnfalse;
while (*modifiers != DRM_FORMAT_MOD_INVALID) { if (*modifiers == modifier) break;
modifiers++;
}
/* return false, if the modifier was not found */ if (*modifiers == DRM_FORMAT_MOD_INVALID) {
DRM_DEBUG_KMS("Unsupported modifier\n"); returnfalse;
}
info = drm_format_info(format);
if (info->num_planes != 1) {
DRM_DEBUG_KMS("AFBC buffers expect one plane\n"); returnfalse;
}
if (malidp_hw_format_is_linear_only(format) == true) {
DRM_DEBUG_KMS("Given format (0x%x) is supported is linear mode only\n",
format); returnfalse;
}
/* * RGB formats need to provide YTR modifier and YUV formats should not * provide YTR modifier.
*/ if (!(info->is_yuv) != !!(modifier & AFBC_FORMAT_MOD_YTR)) {
DRM_DEBUG_KMS("AFBC_FORMAT_MOD_YTR is %s for %s formats\n",
info->is_yuv ? "disallowed" : "mandatory",
info->is_yuv ? "YUV" : "RGB"); returnfalse;
}
if (modifier & AFBC_SPLIT) { if (!info->is_yuv) { if (info->cpp[0] <= 2) {
DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n"); returnfalse;
}
}
if ((info->hsub != 1) || (info->vsub != 1)) { if (!(format == DRM_FORMAT_YUV420_10BIT &&
(map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) {
DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n"); returnfalse;
}
}
}
if (modifier & AFBC_CBR) { if ((info->hsub == 1) || (info->vsub == 1)) {
DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n"); returnfalse;
}
}
returntrue;
}
staticbool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
u32 format, u64 modifier)
{ return malidp_format_mod_supported(plane->dev, format, modifier);
}
mmu_dom = iommu_get_domain_for_dev(mp->base.dev->dev); if (mmu_dom) return mmu_dom->pgsize_bitmap;
return 0;
}
/* * Check if the framebuffer is entirely made up of pages at least pgsize in * size. Only a heuristic: assumes that each scatterlist entry has been aligned * to the largest page size smaller than its length and that the MMU maps to * the largest page size possible.
*/ staticbool malidp_check_pages_threshold(struct malidp_plane_state *ms,
u32 pgsize)
{ int i;
for (i = 0; i < ms->n_planes; i++) { struct drm_gem_object *obj; struct drm_gem_dma_object *dma_obj; struct sg_table *sgt; struct scatterlist *sgl;
if (dma_obj->sgt)
sgt = dma_obj->sgt; else
sgt = obj->funcs->get_sg_table(obj);
if (IS_ERR(sgt)) returnfalse;
sgl = sgt->sgl;
while (sgl) { if (sgl->length < pgsize) { if (!dma_obj->sgt)
kfree(sgt); returnfalse;
}
sgl = sg_next(sgl);
} if (!dma_obj->sgt)
kfree(sgt);
}
returntrue;
}
/* * Check if it is possible to enable partial-frame MMU prefetch given the * current format, AFBC state and rotation.
*/ staticbool malidp_partial_prefetch_supported(u32 format, u64 modifier, unsignedint rotation)
{ bool afbc, sparse;
/* rotation and horizontal flip not supported for partial prefetch */ if (rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X)) returnfalse;
switch (format) { case DRM_FORMAT_ARGB2101010: case DRM_FORMAT_RGBA1010102: case DRM_FORMAT_BGRA1010102: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_RGBA8888: case DRM_FORMAT_BGRA8888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: case DRM_FORMAT_RGBX8888: case DRM_FORMAT_BGRX8888: case DRM_FORMAT_RGB888: case DRM_FORMAT_RGBA5551: case DRM_FORMAT_RGB565: /* always supported */ returntrue;
case DRM_FORMAT_ABGR2101010: case DRM_FORMAT_ABGR8888: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_BGR565: /* supported, but if AFBC then must be sparse mode */ return (!afbc) || (afbc && sparse);
case DRM_FORMAT_BGR888: /* supported, but not for AFBC */ return !afbc;
case DRM_FORMAT_YUYV: case DRM_FORMAT_UYVY: case DRM_FORMAT_NV12: case DRM_FORMAT_YUV420: /* not supported */ returnfalse;
default: returnfalse;
}
}
/* * Select the preferred MMU prefetch mode. Full-frame prefetch is preferred as * long as the framebuffer is all large pages. Otherwise partial-frame prefetch * is selected as long as it is supported for the current format. The selected * page size for prefetch is returned in pgsize_bitmap.
*/ staticenum mmu_prefetch_mode malidp_mmu_prefetch_select_mode
(struct malidp_plane_state *ms, u32 *pgsize_bitmap)
{
u32 pgsizes;
/* get the full-frame prefetch page size(s) supported by the MMU */
pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_FULL_PGSIZES;
while (pgsizes) {
u32 largest_pgsize = 1 << __fls(pgsizes);
if (malidp_check_pages_threshold(ms, largest_pgsize)) {
*pgsize_bitmap = largest_pgsize; return MALIDP_PREFETCH_MODE_FULL;
}
pgsizes -= largest_pgsize;
}
/* get the partial-frame prefetch page size(s) supported by the MMU */
pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES;
if (malidp_partial_prefetch_supported(ms->base.fb->format->format,
ms->base.fb->modifier,
ms->base.rotation)) { /* partial prefetch using the smallest page size */
*pgsize_bitmap = 1 << __ffs(pgsizes); return MALIDP_PREFETCH_MODE_PARTIAL;
}
*pgsize_bitmap = 0; return MALIDP_PREFETCH_MODE_NONE;
}
/* get the page sizes supported by the MMU */
ms->mmu_prefetch_pgsize = malidp_get_pgsize_bitmap(mp);
ms->mmu_prefetch_mode =
malidp_mmu_prefetch_select_mode(ms, &ms->mmu_prefetch_pgsize);
}
/* * DP550/650 video layers can accept 3 plane formats only if * fb->pitches[1] == fb->pitches[2] since they don't have a * third plane stride register.
*/ if (ms->n_planes == 3 &&
!(mp->hwdev->hw->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) &&
(new_plane_state->fb->pitches[1] != new_plane_state->fb->pitches[2])) return -EINVAL;
ret = malidp_se_check_scaling(mp, new_plane_state); if (ret) return ret;
/* validate the rotation constraints for each layer */ if (new_plane_state->rotation != DRM_MODE_ROTATE_0) { if (mp->layer->rot == ROTATE_NONE) return -EINVAL; if ((mp->layer->rot == ROTATE_COMPRESSED) && !(fb->modifier)) return -EINVAL; /* * packed RGB888 / BGR888 can't be rotated or flipped * unless they are stored in a compressed way
*/ if ((fb->format->format == DRM_FORMAT_RGB888 ||
fb->format->format == DRM_FORMAT_BGR888) && !(fb->modifier)) return -EINVAL;
}
/* SMART layer does not support AFBC */ if (mp->layer->id == DE_SMART && fb->modifier) {
DRM_ERROR("AFBC framebuffer not supported in SMART layer"); return -EINVAL;
}
ms->rotmem_size = 0; if (new_plane_state->rotation & MALIDP_ROTATED_MASK) { int val;
val = mp->hwdev->hw->rotmem_required(mp->hwdev, new_plane_state->crtc_w,
new_plane_state->crtc_h,
fb->format->format,
!!(fb->modifier)); if (val < 0) return val;
/* * The drm convention for pitch is that it needs to cover width * cpp, * but our hardware wants the pitch/stride to cover all rows included * in a tile.
*/ for (i = 0; i < num_strides; ++i) { unsignedint block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
/* * drm_fb_dma_get_gem_addr() alters the physical base address of the * framebuffer as per the plane's src_x, src_y co-ordinates (ie to * take care of source cropping). * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H * and _AD_CROP_V registers.
*/ if (!afbc) {
dma_addr = drm_fb_dma_get_gem_addr(fb, plane->state,
plane_index);
} else { struct drm_gem_dma_object *obj;
obj = drm_fb_dma_get_gem_obj(fb, plane_index);
if (WARN_ON(!obj)) return;
dma_addr = obj->dma_addr;
}
if (mp->layer->id == DE_SMART) { /* * Enable the first rectangle in the SMART layer to be * able to use it as a drm plane.
*/
malidp_hw_write(mp->hwdev, 1,
mp->layer->base + MALIDP550_LS_ENABLE);
malidp_hw_write(mp->hwdev,
LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
}
malidp_de_set_plane_afbc(plane);
/* first clear the rotation bits */
val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
val &= ~LAYER_ROT_MASK;
/* setup the rotation and axis flip bits */ if (new_state->rotation & DRM_MODE_ROTATE_MASK)
val |= ilog2(plane->state->rotation & DRM_MODE_ROTATE_MASK) <<
LAYER_ROT_OFFSET; if (new_state->rotation & DRM_MODE_REFLECT_X)
val |= LAYER_H_FLIP; if (new_state->rotation & DRM_MODE_REFLECT_Y)
val |= LAYER_V_FLIP;
val &= ~(LAYER_COMP_MASK | LAYER_PMUL_ENABLE | LAYER_ALPHA(0xff));
if (new_state->alpha != DRM_BLEND_ALPHA_OPAQUE) {
val |= LAYER_COMP_PLANE;
} elseif (new_state->fb->format->has_alpha) { /* We only care about blend mode if the format has alpha */ switch (pixel_alpha) { case DRM_MODE_BLEND_PREMULTI:
val |= LAYER_COMP_PIXEL | LAYER_PMUL_ENABLE; break; case DRM_MODE_BLEND_COVERAGE:
val |= LAYER_COMP_PIXEL; break;
}
}
val |= LAYER_ALPHA(plane_alpha);
val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK); if (new_state->crtc) { struct malidp_crtc_state *m =
to_malidp_crtc_state(new_state->crtc->state);
if (m->scaler_config.scale_enable &&
m->scaler_config.plane_src_id == mp->layer->id)
val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE);
}
/* set the 'enable layer' bit */
val |= LAYER_ENABLE;
if (!(map->features & MALIDP_DEVICE_AFBC_SUPPORT_SPLIT)) { /* * Since our hardware does not support SPLIT, so build the list * of supported modifiers excluding SPLIT ones.
*/ while (*modifiers != DRM_FORMAT_MOD_INVALID) { if (!(*modifiers & AFBC_SPLIT))
supported_modifiers[j++] = *modifiers;
formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL); if (!formats) {
ret = -ENOMEM; goto cleanup;
}
for (i = 0; i < map->n_layers; i++) {
u8 id = map->layers[i].id;
/* build the list of DRM supported formats based on the map */ for (n = 0, j = 0; j < map->n_pixel_formats; j++) { if ((map->pixel_formats[j].layer & id) == id)
formats[n++] = map->pixel_formats[j].format;
}
plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
DRM_PLANE_TYPE_OVERLAY;
/* * All the layers except smart layer supports AFBC modifiers.
*/
plane = drmm_universal_plane_alloc(drm, struct malidp_plane, base,
crtcs, &malidp_de_plane_funcs, formats, n,
(id == DE_SMART) ? linear_only_modifiers :
modifiers, plane_type, NULL); if (IS_ERR(plane)) {
ret = PTR_ERR(plane); goto cleanup;
}
/* Attach the YUV->RGB property only to video layers */ if (id & (DE_VIDEO1 | DE_VIDEO2)) { /* default encoding for YUV->RGB is BT601 NARROW */ enum drm_color_encoding enc = DRM_COLOR_YCBCR_BT601; enum drm_color_range range = DRM_COLOR_YCBCR_LIMITED_RANGE;
ret = drm_plane_create_color_properties(&plane->base,
BIT(DRM_COLOR_YCBCR_BT601) | \
BIT(DRM_COLOR_YCBCR_BT709) | \
BIT(DRM_COLOR_YCBCR_BT2020),
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
enc, range); if (!ret) /* program the HW registers */
malidp_de_set_color_encoding(plane, enc, range); else
DRM_WARN("Failed to create video layer %d color properties\n", id);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.