2324 lines · 78.0 KB · C
RawDownload
// 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.