1985 lines · 65.4 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 "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);} 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) {		*global_alpha = true;		*global_alpha_value = plane_state->alpha >> 8;	}} static 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;} static bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier){	return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);} static 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);} static void amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(struct dc_tiling_info *tiling_info,							     uint64_t tiling_flags){	/* Fill GFX8 params */	if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {		unsigned int bankw, bankh, mtaspect, tile_split, num_banks; 		bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);		bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);		mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);		tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);		num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS); 		tiling_info->gfxversion = DcGfxVersion8;		/* XXX fix me for VI */		tiling_info->gfx8.num_banks = num_banks;		tiling_info->gfx8.array_mode =				DC_ARRAY_2D_TILED_THIN1;		tiling_info->gfx8.tile_split = tile_split;		tiling_info->gfx8.bank_width = bankw;		tiling_info->gfx8.bank_height = bankh;		tiling_info->gfx8.tile_aspect = mtaspect;		tiling_info->gfx8.tile_mode =				DC_ADDR_SURF_MICRO_TILING_DISPLAY;	} else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)			== DC_ARRAY_1D_TILED_THIN1) {		tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;	} 	tiling_info->gfx8.pipe_config =			AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);} static 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;} static 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. */	}} static 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 &&	    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;} static int amdgpu_dm_plane_fill_gfx9_plane_attributes_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: %d\n", ret); 	return ret;} static int amdgpu_dm_plane_fill_gfx12_plane_attributes_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 error: %d\n", ret); 	return ret;} 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));} static void amdgpu_dm_plane_add_gfx9_modifiers(const struct amdgpu_device *adev,					       uint64_t **mods,					       uint64_t *size,					       uint64_t *capacity){	int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);	int pipe_xor_bits = min(8, pipes +				ilog2(adev->gfx.config.gb_addr_config_fields.num_se));	int bank_xor_bits = min(8 - pipe_xor_bits,				ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));	int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +		 ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);  	if (adev->family == AMDGPU_FAMILY_RV) {		/* Raven2 and later */		bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81; 		/*		 * No _D DCC swizzles yet because we only allow 32bpp, which		 * doesn't support _D on DCN		 */ 		if (has_constant_encode) {			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_GFX9) |						     AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |						     AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |						     AMD_FMT_MOD_SET(DCC, 1) |						     AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |						     AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |						     AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));		} 		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_GFX9) |					     AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |					     AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |					     AMD_FMT_MOD_SET(DCC, 1) |					     AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |					     AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |					     AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0)); 		if (has_constant_encode) {			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_GFX9) |						     AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |						     AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |						     AMD_FMT_MOD_SET(DCC, 1) |

Lines 1–500 of 1985.