// SPDX-License-Identifier: MIT/* * Copyright 2022-2026 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD * */ #include <drm/drm_atomic_helper.h>#include <drm/drm_blend.h>#include "drm/drm_framebuffer.h"#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_plane_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_fourcc.h> #include "amdgpu.h"#include "dal_asic_id.h"#include "amdgpu_display.h"#include "amdgpu_dm_trace.h"#include "amdgpu_dm_plane.h"#include "dm_helpers.h"#include "amdgpu_dm_colorop.h"#include "gc/gc_11_0_0_offset.h"#include "gc/gc_11_0_0_sh_mask.h" /* * TODO: these are currently initialized to rgb formats only. * For future use cases we should either initialize them dynamically based on * plane capabilities, or initialize this array to all formats, so internal drm * check will succeed, and let DC implement proper check */static const uint32_t rgb_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, DRM_FORMAT_XRGB16161616, DRM_FORMAT_XBGR16161616, DRM_FORMAT_ARGB16161616, DRM_FORMAT_ABGR16161616, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565,}; static const uint32_t overlay_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565, DRM_FORMAT_NV21, DRM_FORMAT_NV12, DRM_FORMAT_P010}; static const uint32_t video_formats[] = { DRM_FORMAT_NV21, DRM_FORMAT_NV12, DRM_FORMAT_P010}; static const u32 cursor_formats[] = { DRM_FORMAT_ARGB8888}; enum dm_micro_swizzle { MICRO_SWIZZLE_Z = 0, MICRO_SWIZZLE_S = 1, MICRO_SWIZZLE_D = 2, MICRO_SWIZZLE_R = 3}; const struct drm_format_info *amdgpu_dm_plane_get_format_info(u32 pixel_format, u64 modifier){ return amdgpu_lookup_format_info(pixel_format, modifier);}EXPORT_IF_KUNIT(amdgpu_dm_plane_get_format_info); void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state *plane_state, bool *per_pixel_alpha, bool *pre_multiplied_alpha, bool *global_alpha, int *global_alpha_value){ *per_pixel_alpha = false; *pre_multiplied_alpha = true; *global_alpha = false; *global_alpha_value = 0xff; if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI || plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) { static const uint32_t alpha_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ARGB16161616, DRM_FORMAT_ABGR16161616, DRM_FORMAT_ARGB16161616F, }; uint32_t format = plane_state->fb->format->format; unsigned int i; for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) { if (format == alpha_formats[i]) { *per_pixel_alpha = true; break; } } if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) *pre_multiplied_alpha = false; } if (plane_state->alpha < 0xffff) { struct amdgpu_device *adev = drm_to_adev(plane_state->plane->dev); *global_alpha = true; /* * DCN 4.2 uses a 12-bit MPCC_GLOBAL_ALPHA field, while * other ASICs use an 8-bit field. The DRM plane alpha is * 16-bit, so scale it down to the width the hardware expects. */ if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) || amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0)) *global_alpha_value = plane_state->alpha >> 4; else *global_alpha_value = plane_state->alpha >> 8; }}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_blending_from_plane_state); STATIC_IFN_KUNIT void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod){ if (!*mods) return; if (*cap - *size < 1) { uint64_t new_cap = *cap * 2; uint64_t *new_mods = kmalloc_array(new_cap, sizeof(uint64_t), GFP_KERNEL); if (!new_mods) { kfree(*mods); *mods = NULL; return; } memcpy(new_mods, *mods, sizeof(uint64_t) * *size); kfree(*mods); *mods = new_mods; *cap = new_cap; } (*mods)[*size] = mod; *size += 1;}EXPORT_IF_KUNIT(amdgpu_dm_plane_add_modifier); STATIC_IFN_KUNIT void amdgpu_dm_plane_add_modifier_dedup(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod){ uint64_t i; if (!*mods) return; for (i = 0; i < *size; ++i) if ((*mods)[i] == mod) return; amdgpu_dm_plane_add_modifier(mods, size, cap, mod);}EXPORT_IF_KUNIT(amdgpu_dm_plane_add_modifier_dedup); STATIC_IFN_KUNIT bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier){ return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);}EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_has_dcc); STATIC_IFN_KUNIT unsigned int amdgpu_dm_plane_modifier_gfx9_swizzle_mode(uint64_t modifier){ if (modifier == DRM_FORMAT_MOD_LINEAR) return 0; return AMD_FMT_MOD_GET(TILE, modifier);}EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_gfx9_swizzle_mode); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier( struct dc_tiling_info *tiling_info, uint64_t modifier){ if (modifier == DRM_FORMAT_MOD_LINEAR) { tiling_info->gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL; tiling_info->gfxversion = DcGfxVersion8; return 0; } if (!IS_AMD_FMT_MOD(modifier)) return -EINVAL; if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) != AMD_FMT_MOD_TILE_VER_GFX6) return -EINVAL; tiling_info->gfx8.array_mode = AMD_FMT_MOD_GET(TILE, modifier); tiling_info->gfxversion = DcGfxVersion8; tiling_info->gfx8.tile_mode = AMD_FMT_MOD_GET(MICROTILE, modifier); if (AMD_FMT_MOD_GET(TILE, modifier) < AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1) return 0; tiling_info->gfx8.pipe_config = AMD_FMT_MOD_GET(PIPE_CONFIG, modifier); tiling_info->gfx8.tile_split = AMD_FMT_MOD_GET(TILE_SPLIT, modifier); tiling_info->gfx8.bank_width = AMD_FMT_MOD_GET(BANK_WIDTH, modifier); tiling_info->gfx8.bank_height = AMD_FMT_MOD_GET(BANK_HEIGHT, modifier); tiling_info->gfx8.tile_aspect = AMD_FMT_MOD_GET(MACRO_TILE_ASPECT, modifier); tiling_info->gfx8.num_banks = AMD_FMT_MOD_GET(NUM_BANKS, modifier); return 0;}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier); STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, struct dc_tiling_info *tiling_info){ /* Fill GFX9 params */ tiling_info->gfx9.num_pipes = adev->gfx.config.gb_addr_config_fields.num_pipes; tiling_info->gfx9.num_banks = adev->gfx.config.gb_addr_config_fields.num_banks; tiling_info->gfx9.pipe_interleave = adev->gfx.config.gb_addr_config_fields.pipe_interleave_size; tiling_info->gfx9.num_shader_engines = adev->gfx.config.gb_addr_config_fields.num_se; tiling_info->gfx9.max_compressed_frags = adev->gfx.config.gb_addr_config_fields.max_compress_frags; tiling_info->gfx9.num_rb_per_se = adev->gfx.config.gb_addr_config_fields.num_rb_per_se; tiling_info->gfx9.shaderEnable = 1; if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0)) tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_device); STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, struct dc_tiling_info *tiling_info, uint64_t modifier){ unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier); unsigned int pipes_log2; pipes_log2 = min(5u, mod_pipe_xor_bits); amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, tiling_info); if (!IS_AMD_FMT_MOD(modifier)) return; tiling_info->gfx9.num_pipes = 1u << pipes_log2; tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2); if (adev->family >= AMDGPU_FAMILY_NV) { tiling_info->gfx9.num_pkrs = 1u << pkrs_log2; } else { tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits; /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */ }}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier); STATIC_IFN_KUNIT int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct dc_tiling_info *tiling_info, const struct dc_plane_dcc_param *dcc, const struct dc_plane_address *address, const struct plane_size *plane_size){ struct dc *dc = adev->dm.dc; struct dc_dcc_surface_param input; struct dc_surface_dcc_cap output; memset(&input, 0, sizeof(input)); memset(&output, 0, sizeof(output)); if (!dcc->enable) return 0; if (adev->family != AMDGPU_FAMILY_GC_12_0_0 && adev->family != AMDGPU_FAMILY_GC_13_0_1 && format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) return -EINVAL; if (!dc->cap_funcs.get_dcc_compression_cap) return -EINVAL; input.format = format; input.surface_size.width = plane_size->surface_size.width; input.surface_size.height = plane_size->surface_size.height; input.swizzle_mode = tiling_info->gfx9.swizzle; if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180) input.scan = SCAN_DIRECTION_HORIZONTAL; else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270) input.scan = SCAN_DIRECTION_VERTICAL; if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output)) return -EINVAL; if (!output.capable) return -EINVAL; if (dcc->independent_64b_blks == 0 && output.grph.rgb.independent_64b_blks != 0) return -EINVAL; return 0;}EXPORT_IF_KUNIT(amdgpu_dm_plane_validate_dcc); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct plane_size *plane_size, struct dc_tiling_info *tiling_info, struct dc_plane_dcc_param *dcc, struct dc_plane_address *address){ const uint64_t modifier = afb->base.modifier; int ret = 0; amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier); tiling_info->gfx9.swizzle = amdgpu_dm_plane_modifier_gfx9_swizzle_mode(modifier); tiling_info->gfxversion = DcGfxVersion9; if (amdgpu_dm_plane_modifier_has_dcc(modifier)) { uint64_t dcc_address = afb->address + afb->base.offsets[1]; bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier); bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier); dcc->enable = 1; dcc->meta_pitch = afb->base.pitches[1]; dcc->independent_64b_blks = independent_64b_blks; if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { if (independent_64b_blks && independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl; else if (independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_128b; else if (independent_64b_blks && !independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } else { if (independent_64b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } address->grph.meta_addr.low_part = lower_32_bits(dcc_address); address->grph.meta_addr.high_part = upper_32_bits(dcc_address); } ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size); if (ret) drm_dbg_kms(adev_to_drm(adev), "amdgpu_dm_plane_validate_dcc: returned error: %pe\n", ERR_PTR(ret)); return ret;}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct plane_size *plane_size, struct dc_tiling_info *tiling_info, struct dc_plane_dcc_param *dcc, struct dc_plane_address *address){ const uint64_t modifier = afb->base.modifier; int ret = 0; /* TODO: Most of this function shouldn't be needed on GFX12. */ amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, tiling_info); tiling_info->gfx9.swizzle = amdgpu_dm_plane_modifier_gfx9_swizzle_mode(modifier); tiling_info->gfxversion = DcGfxAddr3; if (amdgpu_dm_plane_modifier_has_dcc(modifier)) { int max_compressed_block = AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); dcc->enable = 1; dcc->independent_64b_blks = max_compressed_block == 0; if (max_compressed_block == 0) dcc->dcc_ind_blk = hubp_ind_block_64b; else if (max_compressed_block == 1) dcc->dcc_ind_blk = hubp_ind_block_128b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } /* TODO: This seems wrong because there is no DCC plane on GFX12. */ ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size); if (ret) drm_dbg_kms(adev_to_drm(adev), "amdgpu_dm_plane_validate_dcc: returned: %pe\n", ERR_PTR(ret)); return ret;}EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers); static void amdgpu_dm_plane_add_gfx10_1_modifiers(const struct amdgpu_device *adev, uint64_t **mods, uint64_t *size, uint64_t *capacity){ int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | AMD_FMT_MOD_SET(DCC, 1) | AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | AMD_FMT_MOD_SET(DCC, 1) | AMD_FMT_MOD_SET(DCC_RETILE, 1) | AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); /* Only supported for 64bpp, will be filtered in amdgpu_dm_plane_format_mod_supported */ amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));} /** * amdgpu_dm_plane_get_gfx6_tile_idx() - Get tile mode index on GFX6-8 * * @adev: amdgpu_device pointer * @bpp: bits per pixel in the image * @arr: array mode (aka. tile mode) of the image layout * * Select which tiling mode from the table is suitable for the given bits per pixel * using the given array mode, assuming the displayable micro tile mode is used. *Lines 1–500 of 2324. Load more
// SPDX-License-Identifier: MIT /* * Copyright 2022-2026 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD * */ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include "drm/drm_framebuffer.h" #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_fourcc.h> #include "amdgpu.h" #include "dal_asic_id.h" #include "amdgpu_display.h" #include "amdgpu_dm_trace.h" #include "amdgpu_dm_plane.h" #include "dm_helpers.h" #include "amdgpu_dm_colorop.h" #include "gc/gc_11_0_0_offset.h" #include "gc/gc_11_0_0_sh_mask.h" /* * TODO: these are currently initialized to rgb formats only. * For future use cases we should either initialize them dynamically based on * plane capabilities, or initialize this array to all formats, so internal drm * check will succeed, and let DC implement proper check */ static const uint32_t rgb_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, DRM_FORMAT_XRGB16161616, DRM_FORMAT_XBGR16161616, DRM_FORMAT_ARGB16161616, DRM_FORMAT_ABGR16161616, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565, }; static const uint32_t overlay_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565, DRM_FORMAT_NV21, DRM_FORMAT_NV12, DRM_FORMAT_P010 }; static const uint32_t video_formats[] = { DRM_FORMAT_NV21, DRM_FORMAT_NV12, DRM_FORMAT_P010 }; static const u32 cursor_formats[] = { DRM_FORMAT_ARGB8888 }; enum dm_micro_swizzle { MICRO_SWIZZLE_Z = 0, MICRO_SWIZZLE_S = 1, MICRO_SWIZZLE_D = 2, MICRO_SWIZZLE_R = 3 }; const struct drm_format_info *amdgpu_dm_plane_get_format_info(u32 pixel_format, u64 modifier) { return amdgpu_lookup_format_info(pixel_format, modifier); } EXPORT_IF_KUNIT(amdgpu_dm_plane_get_format_info); void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state *plane_state, bool *per_pixel_alpha, bool *pre_multiplied_alpha, bool *global_alpha, int *global_alpha_value) { *per_pixel_alpha = false; *pre_multiplied_alpha = true; *global_alpha = false; *global_alpha_value = 0xff; if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI || plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) { static const uint32_t alpha_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_RGBA8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ARGB16161616, DRM_FORMAT_ABGR16161616, DRM_FORMAT_ARGB16161616F, }; uint32_t format = plane_state->fb->format->format; unsigned int i; for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) { if (format == alpha_formats[i]) { *per_pixel_alpha = true; break; } } if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) *pre_multiplied_alpha = false; } if (plane_state->alpha < 0xffff) { struct amdgpu_device *adev = drm_to_adev(plane_state->plane->dev); *global_alpha = true; /* * DCN 4.2 uses a 12-bit MPCC_GLOBAL_ALPHA field, while * other ASICs use an 8-bit field. The DRM plane alpha is * 16-bit, so scale it down to the width the hardware expects. */ if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) || amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0)) *global_alpha_value = plane_state->alpha >> 4; else *global_alpha_value = plane_state->alpha >> 8; } } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_blending_from_plane_state); STATIC_IFN_KUNIT void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod) { if (!*mods) return; if (*cap - *size < 1) { uint64_t new_cap = *cap * 2; uint64_t *new_mods = kmalloc_array(new_cap, sizeof(uint64_t), GFP_KERNEL); if (!new_mods) { kfree(*mods); *mods = NULL; return; } memcpy(new_mods, *mods, sizeof(uint64_t) * *size); kfree(*mods); *mods = new_mods; *cap = new_cap; } (*mods)[*size] = mod; *size += 1; } EXPORT_IF_KUNIT(amdgpu_dm_plane_add_modifier); STATIC_IFN_KUNIT void amdgpu_dm_plane_add_modifier_dedup(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod) { uint64_t i; if (!*mods) return; for (i = 0; i < *size; ++i) if ((*mods)[i] == mod) return; amdgpu_dm_plane_add_modifier(mods, size, cap, mod); } EXPORT_IF_KUNIT(amdgpu_dm_plane_add_modifier_dedup); STATIC_IFN_KUNIT bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier) { return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier); } EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_has_dcc); STATIC_IFN_KUNIT unsigned int amdgpu_dm_plane_modifier_gfx9_swizzle_mode(uint64_t modifier) { if (modifier == DRM_FORMAT_MOD_LINEAR) return 0; return AMD_FMT_MOD_GET(TILE, modifier); } EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_gfx9_swizzle_mode); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier( struct dc_tiling_info *tiling_info, uint64_t modifier) { if (modifier == DRM_FORMAT_MOD_LINEAR) { tiling_info->gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL; tiling_info->gfxversion = DcGfxVersion8; return 0; } if (!IS_AMD_FMT_MOD(modifier)) return -EINVAL; if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) != AMD_FMT_MOD_TILE_VER_GFX6) return -EINVAL; tiling_info->gfx8.array_mode = AMD_FMT_MOD_GET(TILE, modifier); tiling_info->gfxversion = DcGfxVersion8; tiling_info->gfx8.tile_mode = AMD_FMT_MOD_GET(MICROTILE, modifier); if (AMD_FMT_MOD_GET(TILE, modifier) < AMD_FMT_MOD_TILE_GFX6_2D_TILED_THIN1) return 0; tiling_info->gfx8.pipe_config = AMD_FMT_MOD_GET(PIPE_CONFIG, modifier); tiling_info->gfx8.tile_split = AMD_FMT_MOD_GET(TILE_SPLIT, modifier); tiling_info->gfx8.bank_width = AMD_FMT_MOD_GET(BANK_WIDTH, modifier); tiling_info->gfx8.bank_height = AMD_FMT_MOD_GET(BANK_HEIGHT, modifier); tiling_info->gfx8.tile_aspect = AMD_FMT_MOD_GET(MACRO_TILE_ASPECT, modifier); tiling_info->gfx8.num_banks = AMD_FMT_MOD_GET(NUM_BANKS, modifier); return 0; } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx6_tiling_info_from_modifier); STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, struct dc_tiling_info *tiling_info) { /* Fill GFX9 params */ tiling_info->gfx9.num_pipes = adev->gfx.config.gb_addr_config_fields.num_pipes; tiling_info->gfx9.num_banks = adev->gfx.config.gb_addr_config_fields.num_banks; tiling_info->gfx9.pipe_interleave = adev->gfx.config.gb_addr_config_fields.pipe_interleave_size; tiling_info->gfx9.num_shader_engines = adev->gfx.config.gb_addr_config_fields.num_se; tiling_info->gfx9.max_compressed_frags = adev->gfx.config.gb_addr_config_fields.max_compress_frags; tiling_info->gfx9.num_rb_per_se = adev->gfx.config.gb_addr_config_fields.num_rb_per_se; tiling_info->gfx9.shaderEnable = 1; if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0)) tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_device); STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, struct dc_tiling_info *tiling_info, uint64_t modifier) { unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier); unsigned int pipes_log2; pipes_log2 = min(5u, mod_pipe_xor_bits); amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, tiling_info); if (!IS_AMD_FMT_MOD(modifier)) return; tiling_info->gfx9.num_pipes = 1u << pipes_log2; tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2); if (adev->family >= AMDGPU_FAMILY_NV) { tiling_info->gfx9.num_pkrs = 1u << pkrs_log2; } else { tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits; /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */ } } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier); STATIC_IFN_KUNIT int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct dc_tiling_info *tiling_info, const struct dc_plane_dcc_param *dcc, const struct dc_plane_address *address, const struct plane_size *plane_size) { struct dc *dc = adev->dm.dc; struct dc_dcc_surface_param input; struct dc_surface_dcc_cap output; memset(&input, 0, sizeof(input)); memset(&output, 0, sizeof(output)); if (!dcc->enable) return 0; if (adev->family != AMDGPU_FAMILY_GC_12_0_0 && adev->family != AMDGPU_FAMILY_GC_13_0_1 && format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) return -EINVAL; if (!dc->cap_funcs.get_dcc_compression_cap) return -EINVAL; input.format = format; input.surface_size.width = plane_size->surface_size.width; input.surface_size.height = plane_size->surface_size.height; input.swizzle_mode = tiling_info->gfx9.swizzle; if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180) input.scan = SCAN_DIRECTION_HORIZONTAL; else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270) input.scan = SCAN_DIRECTION_VERTICAL; if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output)) return -EINVAL; if (!output.capable) return -EINVAL; if (dcc->independent_64b_blks == 0 && output.grph.rgb.independent_64b_blks != 0) return -EINVAL; return 0; } EXPORT_IF_KUNIT(amdgpu_dm_plane_validate_dcc); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct plane_size *plane_size, struct dc_tiling_info *tiling_info, struct dc_plane_dcc_param *dcc, struct dc_plane_address *address) { const uint64_t modifier = afb->base.modifier; int ret = 0; amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier); tiling_info->gfx9.swizzle = amdgpu_dm_plane_modifier_gfx9_swizzle_mode(modifier); tiling_info->gfxversion = DcGfxVersion9; if (amdgpu_dm_plane_modifier_has_dcc(modifier)) { uint64_t dcc_address = afb->address + afb->base.offsets[1]; bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier); bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier); dcc->enable = 1; dcc->meta_pitch = afb->base.pitches[1]; dcc->independent_64b_blks = independent_64b_blks; if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { if (independent_64b_blks && independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl; else if (independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_128b; else if (independent_64b_blks && !independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } else { if (independent_64b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } address->grph.meta_addr.low_part = lower_32_bits(dcc_address); address->grph.meta_addr.high_part = upper_32_bits(dcc_address); } ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size); if (ret) drm_dbg_kms(adev_to_drm(adev), "amdgpu_dm_plane_validate_dcc: returned error: %pe\n", ERR_PTR(ret)); return ret; } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_attrs_from_modifiers); STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, const struct plane_size *plane_size, struct dc_tiling_info *tiling_info, struct dc_plane_dcc_param *dcc, struct dc_plane_address *address) { const uint64_t modifier = afb->base.modifier; int ret = 0; /* TODO: Most of this function shouldn't be needed on GFX12. */ amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, tiling_info); tiling_info->gfx9.swizzle = amdgpu_dm_plane_modifier_gfx9_swizzle_mode(modifier); tiling_info->gfxversion = DcGfxAddr3; if (amdgpu_dm_plane_modifier_has_dcc(modifier)) { int max_compressed_block = AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); dcc->enable = 1; dcc->independent_64b_blks = max_compressed_block == 0; if (max_compressed_block == 0) dcc->dcc_ind_blk = hubp_ind_block_64b; else if (max_compressed_block == 1) dcc->dcc_ind_blk = hubp_ind_block_128b; else dcc->dcc_ind_blk = hubp_ind_block_unconstrained; } /* TODO: This seems wrong because there is no DCC plane on GFX12. */ ret = amdgpu_dm_plane_validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size); if (ret) drm_dbg_kms(adev_to_drm(adev), "amdgpu_dm_plane_validate_dcc: returned: %pe\n", ERR_PTR(ret)); return ret; } EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers); static void amdgpu_dm_plane_add_gfx10_1_modifiers(const struct amdgpu_device *adev, uint64_t **mods, uint64_t *size, uint64_t *capacity) { int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | AMD_FMT_MOD_SET(DCC, 1) | AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | AMD_FMT_MOD_SET(DCC, 1) | AMD_FMT_MOD_SET(DCC_RETILE, 1) | AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) | AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) | AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits)); /* Only supported for 64bpp, will be filtered in amdgpu_dm_plane_format_mod_supported */ amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); amdgpu_dm_plane_add_modifier(mods, size, capacity, AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) | AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); } /** * amdgpu_dm_plane_get_gfx6_tile_idx() - Get tile mode index on GFX6-8 * * @adev: amdgpu_device pointer * @bpp: bits per pixel in the image * @arr: array mode (aka. tile mode) of the image layout * * Select which tiling mode from the table is suitable for the given bits per pixel * using the given array mode, assuming the displayable micro tile mode is used. *