amd-drm-next-7.2-2026-06-03:

amdgpu:
 - BT.2020 fix for DCE
 - DC bounds checking fixes
 - SDMA 7.1 fix
 - UserQ fixes
 - SI fix
 - SMU 13 fixes
 - SMU 14 fixes
 - GC 12.1 fix
 - Userptr fix
 - GC 10.1 fix
 - GART fix for non-4K pages
 - DCN 4.x fixes
 - DCN 4.2 updates
 - More DC KUnit tests
 - PSR cleanup
 - Support for connectors without DDC pins
 - Initial DCN 4.2.1 support
 - Initial HDMI 2.1 FRL support
 - Misc bounds check fixes
 - RAS fixes
 - GC 11.5.6 support
 - SDMA 6.4.0 support
 - NBIO 7.11.5 support
 - IH 6.4.0 support
 - HDP 6.4.0 support
 - MMHUB 3.4.2 support
 - SMU 15.0.5 support
 - ATHUB 3.4.2 support
 - VPE 2.2 support
 - Devcoredump fixes
 - _PR3 fix
 
 amdkfd:
 - UAF race fix
 - Fix a potential NULL pointer dereference
 - GC 11 buffer overflow fix for SDMA
 - Profiler locking order fix
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCaiDUrgAKCRC93/aFa7yZ
 2ADAAQDmTEPxVsj/ZDw8K/Kl4GYh43TbafwN6M9oqOD2PiCd/QEAgWJLmUB/yE0p
 d0oA1awDA9jogEaTT4PE7J1VFaLwYAk=
 =tPRP
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-next-7.2-2026-06-03' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-7.2-2026-06-03:

amdgpu:
- BT.2020 fix for DCE
- DC bounds checking fixes
- SDMA 7.1 fix
- UserQ fixes
- SI fix
- SMU 13 fixes
- SMU 14 fixes
- GC 12.1 fix
- Userptr fix
- GC 10.1 fix
- GART fix for non-4K pages
- DCN 4.x fixes
- DCN 4.2 updates
- More DC KUnit tests
- PSR cleanup
- Support for connectors without DDC pins
- Initial DCN 4.2.1 support
- Initial HDMI 2.1 FRL support
- Misc bounds check fixes
- RAS fixes
- GC 11.5.6 support
- SDMA 6.4.0 support
- NBIO 7.11.5 support
- IH 6.4.0 support
- HDP 6.4.0 support
- MMHUB 3.4.2 support
- SMU 15.0.5 support
- ATHUB 3.4.2 support
- VPE 2.2 support
- Devcoredump fixes
- _PR3 fix

amdkfd:
- UAF race fix
- Fix a potential NULL pointer dereference
- GC 11 buffer overflow fix for SDMA
- Profiler locking order fix

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260604013527.2373534-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2026-06-04 12:06:36 +10:00
commit 527b3f2a48
350 changed files with 101785 additions and 817 deletions

View File

@ -553,7 +553,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT);
if (coredump->rings && coredump->rings_dw) {
for (i = 0, off = 0, idx = 0; i < adev->num_rings; i++) {
for (i = 0, off = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
ring = adev->rings[i];
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&

View File

@ -1921,6 +1921,7 @@ static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
while ((parent = pci_upstream_bridge(parent))) {
if (parent->vendor == PCI_VENDOR_ID_ATI)
continue;
break;
}
return parent;
@ -2027,7 +2028,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
adev->flags |= AMD_IS_PX;
if (!(adev->flags & AMD_IS_APU)) {
parent = pcie_find_root_port(adev->pdev);
parent = amdgpu_device_find_parent(adev);
adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
}

View File

@ -396,6 +396,26 @@ static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev,
return r;
}
if (fw->size > adev->discovery.size) {
dev_err(adev->dev,
"ip discovery firmware \"%s\" too large (%zu > %u)\n",
fw_name, fw->size, adev->discovery.size);
release_firmware(fw);
return -EINVAL;
}
/* Ensure the firmware is at least large enough to contain the
* binary header fields.
*/
if (fw->size < offsetof(struct binary_header, binary_size) +
sizeof(((struct binary_header *)0)->binary_size)) {
dev_err(adev->dev,
"ip discovery firmware \"%s\" too small (%zu)\n",
fw_name, fw->size);
release_firmware(fw);
return -EINVAL;
}
memcpy((u8 *)binary, (u8 *)fw->data, fw->size);
release_firmware(fw);
@ -820,42 +840,44 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
harvest_info = (struct harvest_table *)(discovery_bin + offset);
for (i = 0; i < 32; i++) {
if (le16_to_cpu(harvest_info->list[i].hw_id) == 0)
u16 hw_id = le16_to_cpu(harvest_info->list[i].hw_id);
u8 inst = harvest_info->list[i].number_instance;
if (hw_id == 0)
break;
switch (le16_to_cpu(harvest_info->list[i].hw_id)) {
if (inst >= 32) {
dev_warn(adev->dev,
"bogus harvest instance %u for hw_id %u\n",
inst, hw_id);
continue;
}
switch (hw_id) {
case VCN_HWID:
(*vcn_harvest_count)++;
adev->vcn.harvest_config |=
(1 << harvest_info->list[i].number_instance);
adev->jpeg.harvest_config |=
(1 << harvest_info->list[i].number_instance);
adev->vcn.harvest_config |= BIT(inst);
adev->jpeg.harvest_config |= BIT(inst);
adev->vcn.inst_mask &=
~(1U << harvest_info->list[i].number_instance);
adev->jpeg.inst_mask &=
~(1U << harvest_info->list[i].number_instance);
adev->vcn.inst_mask &= ~BIT(inst);
adev->jpeg.inst_mask &= ~BIT(inst);
break;
case DMU_HWID:
adev->harvest_ip_mask |= AMD_HARVEST_IP_DMU_MASK;
break;
case UMC_HWID:
umc_harvest_config |=
1 << (le16_to_cpu(harvest_info->list[i].number_instance));
umc_harvest_config |= BIT_ULL(inst);
(*umc_harvest_count)++;
break;
case GC_HWID:
adev->gfx.xcc_mask &=
~(1U << harvest_info->list[i].number_instance);
adev->gfx.xcc_mask &= ~BIT(inst);
break;
case SDMA0_HWID:
adev->sdma.sdma_mask &=
~(1U << harvest_info->list[i].number_instance);
adev->sdma.sdma_mask &= ~BIT(inst);
break;
#if defined(CONFIG_DRM_AMD_ISP)
case ISP_HWID:
adev->isp.harvest_config |=
~(1U << harvest_info->list[i].number_instance);
adev->isp.harvest_config |= ~BIT(inst);
break;
#endif
default:
@ -2096,6 +2118,7 @@ static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
amdgpu_device_ip_block_add(adev, &soc21_common_ip_block);
break;
case IP_VERSION(12, 0, 0):
@ -2156,6 +2179,7 @@ static int amdgpu_discovery_set_gmc_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
amdgpu_device_ip_block_add(adev, &gmc_v11_0_ip_block);
break;
case IP_VERSION(12, 0, 0):
@ -2203,6 +2227,7 @@ static int amdgpu_discovery_set_ih_ip_blocks(struct amdgpu_device *adev)
break;
case IP_VERSION(6, 1, 0):
case IP_VERSION(6, 1, 1):
case IP_VERSION(6, 4, 0):
amdgpu_device_ip_block_add(adev, &ih_v6_1_ip_block);
break;
case IP_VERSION(7, 0, 0):
@ -2344,6 +2369,7 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &smu_v14_0_ip_block);
break;
case IP_VERSION(15, 0, 0):
case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 8):
amdgpu_device_ip_block_add(adev, &smu_v15_0_ip_block);
break;
@ -2399,6 +2425,7 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 1, 0):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
/* TODO: Fix IP version. DC code expects version 4.0.1 */
if (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(4, 1, 0))
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1);
@ -2478,6 +2505,7 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
amdgpu_device_ip_block_add(adev, &gfx_v11_0_ip_block);
break;
case IP_VERSION(12, 0, 0):
@ -2538,6 +2566,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(6, 1, 2):
case IP_VERSION(6, 1, 3):
case IP_VERSION(6, 1, 4):
case IP_VERSION(6, 4, 0):
amdgpu_device_ip_block_add(adev, &sdma_v6_0_ip_block);
break;
case IP_VERSION(7, 0, 0):
@ -2689,6 +2718,7 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
amdgpu_device_ip_block_add(adev, &mes_v11_0_ip_block);
adev->enable_mes = true;
adev->enable_mes_kiq = true;
@ -2739,6 +2769,7 @@ static int amdgpu_discovery_set_vpe_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &vpe_v6_1_ip_block);
break;
case IP_VERSION(2, 0, 0):
case IP_VERSION(2, 2, 0):
amdgpu_device_ip_block_add(adev, &vpe_v2_0_ip_block);
break;
default:
@ -3095,6 +3126,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
adev->family = AMDGPU_FAMILY_GC_11_5_0;
break;
case IP_VERSION(12, 0, 0):
@ -3123,6 +3155,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
adev->flags |= AMD_IS_APU;
break;
default:
@ -3194,6 +3227,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
break;
case IP_VERSION(6, 3, 1):
case IP_VERSION(7, 11, 4):
case IP_VERSION(7, 11, 5):
adev->nbio.funcs = &nbif_v6_3_1_funcs;
adev->nbio.hdp_flush_reg = &nbif_v6_3_1_hdp_flush_reg;
break;
@ -3232,6 +3266,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(6, 0, 1):
case IP_VERSION(6, 1, 0):
case IP_VERSION(6, 1, 1):
case IP_VERSION(6, 4, 0):
adev->hdp.funcs = &hdp_v6_0_funcs;
break;
case IP_VERSION(7, 0, 0):
@ -3314,6 +3349,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
adev->smuio.funcs = &smuio_v14_0_2_funcs;
break;
case IP_VERSION(15, 0, 0):
case IP_VERSION(15, 0, 5):
adev->smuio.funcs = &smuio_v15_0_0_funcs;
break;
case IP_VERSION(15, 0, 8):

View File

@ -115,6 +115,43 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr)
}
}
/*
* IPMI FRU Product Info Area fields are TLV: one type/length byte
* (low 6 bits = data length) followed by that many data bytes. These
* helpers walk the cursor and copy a single field while bounding all
* accesses to the actual buffer length read from the EEPROM.
*/
#define FRU_FIELD_LEN(p, a) ((p)[a] & 0x3F)
/* Advance cursor past the current TLV. Returns false if no more data. */
static bool fru_pia_advance(u32 *addr, const unsigned char *pia, int len)
{
if (*addr >= (u32)len)
return false;
*addr += 1 + FRU_FIELD_LEN(pia, *addr);
return true;
}
/*
* Copy the current TLV's data into dst (NUL-terminated). Returns false if
* the TLV header or data would read past the end of pia.
*/
static bool fru_pia_copy_field(char *dst, size_t dst_size,
const unsigned char *pia, u32 addr, int len)
{
size_t fl;
if (addr + 1 >= (u32)len)
return false;
fl = min3((size_t)FRU_FIELD_LEN(pia, addr),
dst_size - 1,
(size_t)(len - addr - 1));
memcpy(dst, pia + addr + 1, fl);
dst[fl] = '\0';
return true;
}
int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
{
struct amdgpu_fru_info *fru_info;
@ -223,52 +260,46 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
* Read Manufacturer Name field whose length is [3].
*/
addr = 3;
if (addr + 1 >= len)
if (!fru_pia_copy_field(fru_info->manufacturer_name,
sizeof(fru_info->manufacturer_name),
pia, addr, len))
goto Out;
memcpy(fru_info->manufacturer_name, pia + addr + 1,
min_t(size_t, sizeof(fru_info->manufacturer_name),
pia[addr] & 0x3F));
fru_info->manufacturer_name[sizeof(fru_info->manufacturer_name) - 1] =
'\0';
/* Read Product Name field. */
addr += 1 + (pia[addr] & 0x3F);
if (addr + 1 >= len)
if (!fru_pia_advance(&addr, pia, len) ||
!fru_pia_copy_field(fru_info->product_name,
sizeof(fru_info->product_name),
pia, addr, len))
goto Out;
memcpy(fru_info->product_name, pia + addr + 1,
min_t(size_t, sizeof(fru_info->product_name), pia[addr] & 0x3F));
fru_info->product_name[sizeof(fru_info->product_name) - 1] = '\0';
/* Go to the Product Part/Model Number field. */
addr += 1 + (pia[addr] & 0x3F);
if (addr + 1 >= len)
if (!fru_pia_advance(&addr, pia, len) ||
!fru_pia_copy_field(fru_info->product_number,
sizeof(fru_info->product_number),
pia, addr, len))
goto Out;
memcpy(fru_info->product_number, pia + addr + 1,
min_t(size_t, sizeof(fru_info->product_number),
pia[addr] & 0x3F));
fru_info->product_number[sizeof(fru_info->product_number) - 1] = '\0';
/* Go to the Product Version field. */
addr += 1 + (pia[addr] & 0x3F);
/* Go to the Product Serial Number field. */
addr += 1 + (pia[addr] & 0x3F);
if (addr + 1 >= len)
/* Skip the Product Version field. */
if (!fru_pia_advance(&addr, pia, len))
goto Out;
memcpy(fru_info->serial, pia + addr + 1,
min_t(size_t, sizeof(fru_info->serial), pia[addr] & 0x3F));
fru_info->serial[sizeof(fru_info->serial) - 1] = '\0';
/* Asset Tag field */
addr += 1 + (pia[addr] & 0x3F);
/* Read the Product Serial Number field. */
if (!fru_pia_advance(&addr, pia, len) ||
!fru_pia_copy_field(fru_info->serial,
sizeof(fru_info->serial),
pia, addr, len))
goto Out;
/* Skip the Asset Tag field. */
if (!fru_pia_advance(&addr, pia, len))
goto Out;
/* FRU File Id field. This could be 'null'. */
addr += 1 + (pia[addr] & 0x3F);
if ((addr + 1 >= len) || !(pia[addr] & 0x3F))
if (!fru_pia_advance(&addr, pia, len) ||
!fru_pia_copy_field(fru_info->fru_id,
sizeof(fru_info->fru_id),
pia, addr, len))
goto Out;
memcpy(fru_info->fru_id, pia + addr + 1,
min_t(size_t, sizeof(fru_info->fru_id), pia[addr] & 0x3F));
fru_info->fru_id[sizeof(fru_info->fru_id) - 1] = '\0';
Out:
kfree(pia);

View File

@ -394,7 +394,8 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
uint64_t start_page, uint64_t num_pages,
uint64_t flags, void *dst)
{
u32 i, idx;
u32 i, j, t, idx;
u64 page_base;
/* The SYSTEM flag indicates the pages aren't in VRAM. */
WARN_ON_ONCE(flags & AMDGPU_PTE_SYSTEM);
@ -402,9 +403,12 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
if (!drm_dev_enter(adev_to_drm(adev), &idx))
return;
for (i = 0; i < num_pages; ++i) {
amdgpu_gmc_set_pte_pde(adev, dst,
start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags);
page_base = pa;
for (i = 0, t = 0; i < num_pages; i++) {
for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
amdgpu_gmc_set_pte_pde(adev, dst, start_page + t, page_base, flags);
page_base += AMDGPU_GPU_PAGE_SIZE;
}
}
drm_dev_exit(idx);

View File

@ -249,7 +249,7 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj,
drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
drm_exec_until_all_locked(&exec) {
r = drm_exec_prepare_obj(&exec, &abo->tbo.base, 1);
r = drm_exec_prepare_obj(&exec, &abo->tbo.base, TTM_NUM_MOVE_FENCES + 1);
drm_exec_retry_on_contention(&exec);
if (unlikely(r))
goto out_unlock;

View File

@ -990,10 +990,7 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
if (r)
return r;
if (amdgpu_sriov_vf(adev))
return r;
if (adev->gfx.cp_ecc_error_irq.funcs) {
if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs) {
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
if (r)
goto late_fini;
@ -1008,6 +1005,21 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
return r;
}
void amdgpu_gfx_ras_suspend(struct amdgpu_device *adev,
struct ras_common_if *ras_block)
{
if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs)
amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
}
void amdgpu_gfx_ras_fini(struct amdgpu_device *adev,
struct ras_common_if *ras_block)
{
if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs)
amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_ras_block_late_fini(adev, ras_block);
}
int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev)
{
int err = 0;
@ -1036,6 +1048,12 @@ int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev)
if (!ras->ras_block.ras_late_init)
ras->ras_block.ras_late_init = amdgpu_gfx_ras_late_init;
if (!ras->ras_block.ras_suspend)
ras->ras_block.ras_suspend = amdgpu_gfx_ras_suspend;
if (!ras->ras_block.ras_fini)
ras->ras_block.ras_fini = amdgpu_gfx_ras_fini;
/* If not defined special ras_cb function, use default ras_cb */
if (!ras->ras_block.ras_cb)
ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb;

View File

@ -615,7 +615,8 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable);
void amdgpu_gfx_off_ctrl_immediate(struct amdgpu_device *adev, bool enable);
int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value);
int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void amdgpu_gfx_ras_fini(struct amdgpu_device *adev);
void amdgpu_gfx_ras_suspend(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void amdgpu_gfx_ras_fini(struct amdgpu_device *adev, struct ras_common_if *ras_block);
int amdgpu_get_gfx_off_entrycount(struct amdgpu_device *adev, u64 *value);
int amdgpu_get_gfx_off_residency(struct amdgpu_device *adev, u32 *residency);
int amdgpu_set_gfx_off_residency(struct amdgpu_device *adev, bool value);

View File

@ -170,7 +170,7 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
/*
* The following is for PTE only. GART does not have PDEs.
*/
value = addr & 0x0000FFFFFFFFF000ULL;
value = addr & adev->gmc.pte_addr_mask;
value |= flags;
writeq(value, ptr + (gpu_page_idx * 8));
@ -976,6 +976,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
/* Don't enable it by default yet.
*/
if (amdgpu_tmz < 1) {
@ -1014,7 +1015,7 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev)
gc_ver == IP_VERSION(9, 4, 3) ||
gc_ver == IP_VERSION(9, 4, 4) ||
gc_ver == IP_VERSION(9, 5, 0) ||
gc_ver >= IP_VERSION(10, 3, 0));
gc_ver >= IP_VERSION(10, 1, 0));
/* For GFX12.1 B0, set xnack (retry) on as default */
if (gc_ver == IP_VERSION(12, 1, 0) && (adev->rev_id & 0xf) == 0x1)

View File

@ -280,6 +280,7 @@ struct amdgpu_gmc {
u64 real_vram_size;
int vram_mtrr;
u64 mc_mask;
uint64_t pte_addr_mask;
const struct firmware *fw; /* MC firmware */
uint32_t fw_version;
struct amdgpu_irq_src vm_fault;

View File

@ -203,7 +203,7 @@ int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
int r;
/* Align to TLB L2 cache entry size to work around "V bit HW bug" */
if (adev->asic_type == CHIP_TAHITI) {
if (adev->family == AMDGPU_FAMILY_SI) {
alignment = 32 * 1024 / AMDGPU_GPU_PAGE_SIZE;
num_pages = ALIGN(num_pages, alignment);
}

View File

@ -67,6 +67,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
{
struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo;
long r;
if (!mmu_notifier_range_blockable(range))
@ -77,8 +78,9 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
mmu_interval_set_seq(mni, cur_seq);
amdgpu_vm_bo_invalidate(bo, false);
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
false, MAX_SCHEDULE_TIMEOUT);
r = dma_resv_wait_timeout(vm_root->tbo.base.resv,
DMA_RESV_USAGE_BOOKKEEP, false,
MAX_SCHEDULE_TIMEOUT);
mutex_unlock(&adev->notifier_lock);
if (r <= 0)
DRM_ERROR("(%ld) failed to wait for user bo\n", r);

View File

@ -99,6 +99,7 @@ int amdgpu_mca_mp0_ras_sw_init(struct amdgpu_device *adev)
strcpy(ras->ras_block.ras_comm.name, "mca.mp0");
ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__MCA;
ras->ras_block.ras_comm.sub_block_index = AMDGPU_RAS_MCA_BLOCK__MP0;
ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
adev->mca.mp0.ras_if = &ras->ras_block.ras_comm;
@ -123,6 +124,7 @@ int amdgpu_mca_mp1_ras_sw_init(struct amdgpu_device *adev)
strcpy(ras->ras_block.ras_comm.name, "mca.mp1");
ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__MCA;
ras->ras_block.ras_comm.sub_block_index = AMDGPU_RAS_MCA_BLOCK__MP1;
ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
adev->mca.mp1.ras_if = &ras->ras_block.ras_comm;
@ -147,6 +149,7 @@ int amdgpu_mca_mpio_ras_sw_init(struct amdgpu_device *adev)
strcpy(ras->ras_block.ras_comm.name, "mca.mpio");
ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__MCA;
ras->ras_block.ras_comm.sub_block_index = AMDGPU_RAS_MCA_BLOCK__MPIO;
ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
adev->mca.mpio.ras_if = &ras->ras_block.ras_comm;

View File

@ -4651,14 +4651,17 @@ static ssize_t amdgpu_psp_vbflash_write(struct file *filp, struct kobject *kobj,
return -ENOMEM;
}
mutex_lock(&adev->psp.mutex);
/* TODO Just allocate max for now and optimize to realloc later if needed */
if (!adev->psp.vbflash_tmp_buf) {
adev->psp.vbflash_tmp_buf = kvmalloc(AMD_VBIOS_FILE_MAX_SIZE_B, GFP_KERNEL);
if (!adev->psp.vbflash_tmp_buf)
if (!adev->psp.vbflash_tmp_buf) {
mutex_unlock(&adev->psp.mutex);
return -ENOMEM;
}
}
mutex_lock(&adev->psp.mutex);
memcpy(adev->psp.vbflash_tmp_buf + pos, buffer, count);
adev->psp.vbflash_image_size += count;
mutex_unlock(&adev->psp.mutex);
@ -4723,7 +4726,7 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj,
*/
static const struct bin_attribute psp_vbflash_bin_attr = {
.attr = {.name = "psp_vbflash", .mode = 0660},
.size = 0,
.size = AMD_VBIOS_FILE_MAX_SIZE_B,
.write = amdgpu_psp_vbflash_write,
.read = amdgpu_psp_vbflash_read,
};

View File

@ -95,6 +95,9 @@ struct amdgpu_ras_block_list {
struct list_head node;
struct amdgpu_ras_block_object *ras_obj;
/* set by ras_late_init, cleared by ras_suspend/ras_fini */
bool active;
};
const char *get_ras_block_str(struct ras_common_if *ras_block)
@ -4637,10 +4640,23 @@ void amdgpu_ras_resume(struct amdgpu_device *adev)
void amdgpu_ras_suspend(struct amdgpu_device *adev)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct amdgpu_ras_block_list *node;
struct amdgpu_ras_block_object *obj;
if (!adev->ras_enabled || !con)
return;
/* run per-block ras_suspend before tearing down the RAS context */
list_for_each_entry(node, &adev->ras_list, node) {
if (!node->active)
continue;
obj = node->ras_obj;
if (obj && obj->ras_suspend)
obj->ras_suspend(adev, &obj->ras_comm);
node->active = false;
}
amdgpu_ras_disable_all_features(adev, 0);
/* Make sure all ras objects are disabled. */
if (AMDGPU_RAS_GET_FEATURES(con->features))
@ -4694,8 +4710,15 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev)
obj->ras_comm.name, r);
return r;
}
} else
amdgpu_ras_block_late_init_default(adev, &obj->ras_comm);
} else {
r = amdgpu_ras_block_late_init_default(adev, &obj->ras_comm);
if (r) {
dev_err(adev->dev, "%s failed to execute ras_block_late_init_default! ret:%d\n",
obj->ras_comm.name, r);
return r;
}
}
node->active = true;
}
amdgpu_ras_check_bad_page_status(adev);
@ -4734,11 +4757,12 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
list_for_each_entry_safe(ras_node, tmp, &adev->ras_list, node) {
if (ras_node->ras_obj) {
obj = ras_node->ras_obj;
if (amdgpu_ras_is_supported(adev, obj->ras_comm.block) &&
obj->ras_fini)
/* fall back to default cleanup if ras_suspend already ran */
if (ras_node->active && obj->ras_fini)
obj->ras_fini(adev, &obj->ras_comm);
else
amdgpu_ras_block_late_fini_default(adev, &obj->ras_comm);
ras_node->active = false;
}
/* Clear ras blocks from ras_list and free ras block list node */

View File

@ -762,6 +762,7 @@ struct amdgpu_ras_block_object {
int (*ras_block_match)(struct amdgpu_ras_block_object *block_obj,
enum amdgpu_ras_block block, uint32_t sub_block_index);
int (*ras_late_init)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void (*ras_suspend)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void (*ras_fini)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
ras_ih_cb ras_cb;
const struct amdgpu_ras_block_hw_ops *hw_ops;

View File

@ -145,12 +145,15 @@
#define RAS_RI_TO_AI(_C, _I) (((_I) + (_C)->ras_fri) % \
(_C)->ras_max_record_count)
#define RAS_NUM_RECS(_tbl_hdr) (((_tbl_hdr)->tbl_size - \
RAS_TABLE_HEADER_SIZE) / RAS_TABLE_RECORD_SIZE)
#define RAS_NUM_RECS(_tbl_hdr) \
(((_tbl_hdr)->tbl_size < RAS_TABLE_HEADER_SIZE) ? 0u : \
(((_tbl_hdr)->tbl_size - RAS_TABLE_HEADER_SIZE) / RAS_TABLE_RECORD_SIZE))
#define RAS_NUM_RECS_V2_1(_tbl_hdr) (((_tbl_hdr)->tbl_size - \
RAS_TABLE_HEADER_SIZE - \
RAS_TABLE_V2_1_INFO_SIZE) / RAS_TABLE_RECORD_SIZE)
#define RAS_NUM_RECS_V2_1(_tbl_hdr) \
(((_tbl_hdr)->tbl_size < RAS_TABLE_HEADER_SIZE + \
RAS_TABLE_V2_1_INFO_SIZE) ? 0u : \
(((_tbl_hdr)->tbl_size - RAS_TABLE_HEADER_SIZE - \
RAS_TABLE_V2_1_INFO_SIZE) / RAS_TABLE_RECORD_SIZE))
#define to_amdgpu_device(x) ((container_of(x, struct amdgpu_ras, eeprom_control))->adev)
@ -1610,11 +1613,24 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
switch (hdr->version) {
case RAS_TABLE_VER_V2_1:
case RAS_TABLE_VER_V3:
if (hdr->tbl_size < RAS_TABLE_HEADER_SIZE + RAS_TABLE_V2_1_INFO_SIZE) {
dev_err(adev->dev,
"RAS header invalid, tbl_size %u smaller than minimum %u, resetting table\n",
hdr->tbl_size,
RAS_TABLE_HEADER_SIZE + RAS_TABLE_V2_1_INFO_SIZE);
return amdgpu_ras_eeprom_reset_table(control);
}
control->ras_num_recs = RAS_NUM_RECS_V2_1(hdr);
control->ras_record_offset = RAS_RECORD_START_V2_1;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1;
break;
case RAS_TABLE_VER_V1:
if (hdr->tbl_size < RAS_TABLE_HEADER_SIZE) {
dev_err(adev->dev,
"RAS header invalid, tbl_size %u smaller than minimum %u, resetting table\n",
hdr->tbl_size, RAS_TABLE_HEADER_SIZE);
return amdgpu_ras_eeprom_reset_table(control);
}
control->ras_num_recs = RAS_NUM_RECS(hdr);
control->ras_record_offset = RAS_RECORD_START;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT;

View File

@ -484,7 +484,7 @@ bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid,
static ssize_t amdgpu_ras_cper_debugfs_read(struct file *f, char __user *buf,
size_t size, loff_t *offset)
{
const uint8_t ring_header_size = 12;
const u8 ring_header_size = 12;
struct amdgpu_ring *ring = file_inode(f)->i_private;
struct ras_cmd_cper_snapshot_req *snapshot_req __free(kfree) =
kzalloc_obj(struct ras_cmd_cper_snapshot_req);
@ -494,49 +494,103 @@ static ssize_t amdgpu_ras_cper_debugfs_read(struct file *f, char __user *buf,
kzalloc_obj(struct ras_cmd_cper_record_req);
struct ras_cmd_cper_record_rsp *record_rsp __free(kfree) =
kzalloc_obj(struct ras_cmd_cper_record_rsp);
uint8_t *ring_header __free(kfree) =
u32 *ring_header __free(kfree) =
kzalloc(ring_header_size, GFP_KERNEL);
uint32_t total_cper_num;
uint64_t start_cper_id;
char __user *data_buf = buf;
size_t data_size = size;
u32 total_cper_num;
u64 start_cper_id;
u64 cper_offset;
size_t chunk_size;
size_t total_data_size = 0;
bool read_header;
int r;
if (!snapshot_req || !snapshot_rsp || !record_req || !record_rsp ||
!ring_header)
return -ENOMEM;
if (!(*offset)) {
read_header = !(*offset);
cper_offset = read_header ? 0 : *offset - 1;
if (read_header) {
/* Need at least 12 bytes for the header on the first read */
if (size < ring_header_size)
return -EINVAL;
if (copy_to_user(buf, ring_header, ring_header_size))
return -EFAULT;
buf += ring_header_size;
size -= ring_header_size;
data_buf += ring_header_size;
data_size -= ring_header_size;
}
r = amdgpu_ras_mgr_handle_ras_cmd(ring->adev,
RAS_CMD__GET_CPER_SNAPSHOT,
snapshot_req, sizeof(struct ras_cmd_cper_snapshot_req),
snapshot_rsp, sizeof(struct ras_cmd_cper_snapshot_rsp));
if (r || !snapshot_rsp->total_cper_num)
return r;
start_cper_id = snapshot_rsp->start_cper_id;
total_cper_num = snapshot_rsp->total_cper_num;
record_req->buf_ptr = (uint64_t)(uintptr_t)buf;
record_req->buf_size = size;
record_req->cper_start_id = start_cper_id + *offset;
record_req->cper_num = total_cper_num;
r = amdgpu_ras_mgr_handle_ras_cmd(ring->adev, RAS_CMD__GET_CPER_RECORD,
record_req, sizeof(struct ras_cmd_cper_record_req),
record_rsp, sizeof(struct ras_cmd_cper_record_rsp));
if (r)
return r;
r = *offset ? record_rsp->real_data_size : record_rsp->real_data_size + ring_header_size;
(*offset) += record_rsp->real_cper_num;
if (!snapshot_rsp->total_cper_num) {
if (!read_header)
return 0;
if (copy_to_user(buf, ring_header, ring_header_size))
return -EFAULT;
*offset = 1;
return ring_header_size;
}
start_cper_id = snapshot_rsp->start_cper_id;
total_cper_num = snapshot_rsp->total_cper_num;
if (read_header && !data_size) {
if (copy_to_user(buf, ring_header, ring_header_size))
return -EFAULT;
*offset = cper_offset + 1;
return ring_header_size;
}
if (!data_size)
return 0;
while (data_size && cper_offset < total_cper_num) {
memset(record_req, 0, sizeof(*record_req));
memset(record_rsp, 0, sizeof(*record_rsp));
chunk_size = min_t(size_t, data_size, RAS_CMD_MAX_CPER_BUF_SZ);
record_req->buf_ptr = (u64)(uintptr_t)data_buf;
record_req->buf_size = chunk_size;
record_req->cper_start_id = start_cper_id + cper_offset;
record_req->cper_num = total_cper_num - cper_offset;
r = amdgpu_ras_mgr_handle_ras_cmd(ring->adev,
RAS_CMD__GET_CPER_RECORD,
record_req,
sizeof(struct ras_cmd_cper_record_req),
record_rsp,
sizeof(struct ras_cmd_cper_record_rsp));
if (r)
return r;
if (!record_rsp->real_data_size || !record_rsp->real_cper_num)
break;
if (record_rsp->real_data_size > data_size)
return -EIO;
data_buf += record_rsp->real_data_size;
data_size -= record_rsp->real_data_size;
total_data_size += record_rsp->real_data_size;
cper_offset += record_rsp->real_cper_num;
}
if (read_header) {
ring_header[1] = total_data_size >> 2;
ring_header[2] = ring_header[1];
if (copy_to_user(buf, ring_header, ring_header_size))
return -EFAULT;
}
r = read_header ? total_data_size + ring_header_size : total_data_size;
*offset = cper_offset + 1;
return r;
}

View File

@ -98,15 +98,18 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
uint32_t phy_id;
uint32_t op;
char str[64];
int ret;
long len;
ssize_t write_ret = size;
int ret, nargs;
if (*pos || size > sizeof(str) - 1)
if (*pos)
return -EINVAL;
memset(str, 0, sizeof(str));
ret = copy_from_user(str, buf, size);
if (ret)
len = strncpy_from_user(str, buf, sizeof(str));
if (len < 0)
return -EFAULT;
if (len == 0 || len >= sizeof(str))
return -EINVAL;
ret = pm_runtime_get_sync(dev->dev);
if (ret < 0) {
@ -114,10 +117,14 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
return ret;
}
if (size < 3)
sscanf(str, "%u ", &op);
if (len < 3)
nargs = sscanf(str, "%u", &op);
else
sscanf(str, "%u %u", &op, &phy_id);
nargs = sscanf(str, "%u %u", &op, &phy_id);
if (nargs < 1) {
write_ret = -EINVAL;
goto out;
}
switch (op) {
case 1:
@ -135,9 +142,10 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
mutex_unlock(&psp->securedisplay_context.mutex);
break;
case 2:
if (size < 3 || phy_id >= TA_SECUREDISPLAY_MAX_PHY) {
if (nargs < 2 || phy_id >= TA_SECUREDISPLAY_MAX_PHY) {
dev_err(adev->dev, "Invalid input: %s\n", str);
return -EINVAL;
write_ret = -EINVAL;
break;
}
mutex_lock(&psp->securedisplay_context.mutex);
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
@ -157,11 +165,14 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
break;
default:
dev_err(adev->dev, "Invalid input: %s\n", str);
write_ret = -EINVAL;
break;
}
out:
pm_runtime_put_autosuspend(dev->dev);
return size;
return write_ret;
}
static const struct file_operations amdgpu_securedisplay_debugfs_ops = {

View File

@ -173,16 +173,17 @@ void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv)
int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *va,
u64 *gpu_addr, u64 **cpu_addr)
{
unsigned long bit_pos;
unsigned long bit_pos = 0;
for (;;) {
bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem);
do {
bit_pos = find_next_zero_bit(adev->seq64.used,
adev->seq64.num_sem, bit_pos);
if (bit_pos >= adev->seq64.num_sem)
return -ENOSPC;
if (!test_and_set_bit(bit_pos, adev->seq64.used))
break;
}
bit_pos++;
} while (1);
*va = bit_pos * sizeof(u64) + amdgpu_seq64_get_va_base(adev);

View File

@ -532,10 +532,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
amdgpu_bo_unreserve(queue->db_obj.obj);
amdgpu_bo_unref(&queue->db_obj.obj);
amdgpu_bo_reserve(queue->wptr_obj.obj, true);
amdgpu_bo_unpin(queue->wptr_obj.obj);
amdgpu_bo_unreserve(queue->wptr_obj.obj);
amdgpu_bo_unref(&queue->wptr_obj.obj);
kfree(queue);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@ -887,7 +883,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
continue;
}
r = amdgpu_userq_restore_helper(queue);
r = amdgpu_userq_map_helper(queue);
if (r)
ret = r;
@ -975,7 +971,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
if (unlikely(ret))
goto unlock_all;
ret = amdgpu_vm_lock_individual(vm, &exec, 1);
ret = amdgpu_vm_lock_individual(vm, &exec, TTM_NUM_MOVE_FENCES + 1);
drm_exec_retry_on_contention(&exec);
if (unlikely(ret))
goto unlock_all;
@ -1124,7 +1120,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
/* Try to unmap all the queues in this process ctx */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
r = amdgpu_userq_preempt_helper(queue);
r = amdgpu_userq_unmap_helper(queue);
if (r)
ret = r;
}
@ -1344,8 +1340,7 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
}
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping,
uint64_t saddr)
struct amdgpu_bo_va_mapping *mapping)
{
u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
struct amdgpu_bo_va *bo_va = mapping->bo_va;
@ -1354,12 +1349,9 @@ void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
if (!ip_mask)
return;
dev_warn_once(adev->dev, "now unmapping a vital queue va:%llx\n", saddr);
/**
* The userq VA mapping reservation should include the eviction fence,
* if the eviction fence can't signal successfully during unmapping,
* then driver will warn to flag this improper unmap of the userq VA.
* Note: The eviction fence may be attached to different BOs, and this
* The userq VA mapping reservation should include the eviction fence.
* Note: The eviction fence may be attached to different BOs and this
* unmap is only for one kind of userq VAs, so at this point suppose
* the eviction fence is always unsignaled.
*/

View File

@ -182,6 +182,5 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
u64 addr, u64 expected_size, u64 *va_out);
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping,
uint64_t saddr);
struct amdgpu_bo_va_mapping *mapping);
#endif

View File

@ -283,14 +283,66 @@ unsigned int amd_sriov_msg_checksum(void *obj,
return ret;
}
#define AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_INIT_CAPACITY 512
/* Max bad page slots allowed for SRIOV*/
#define AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_MAX_CAPACITY 10665U
/**
* amdgpu_virt_ras_realloc_eh_data_space - alloc/realloc VF bad-page @data->bps and @data->bps_bo
* @adev: amdgpu device
* @data: VF RAS error-handler data
* @pages: minimum number of new slots to add beyond @data->capacity
*
* Return: 0 on success, %-ENOMEM on failure.
*/
static int amdgpu_virt_ras_realloc_eh_data_space(struct amdgpu_device *adev,
struct amdgpu_virt_ras_err_handler_data *data,
int pages)
{
struct eeprom_table_record *new_bps;
struct amdgpu_bo **new_bo;
unsigned int old_space;
unsigned int new_space;
unsigned int align_space;
old_space = (unsigned int)data->capacity;
new_space = old_space + max_t(unsigned int, (unsigned int)pages,
(unsigned int)AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_INIT_CAPACITY);
if (new_space < old_space || new_space > AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_MAX_CAPACITY)
return -ENOMEM;
align_space = ALIGN(new_space, AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_INIT_CAPACITY);
if (align_space > AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_MAX_CAPACITY)
return -ENOMEM;
new_bps = kmalloc_array(align_space, sizeof(*data->bps), GFP_KERNEL);
new_bo = kcalloc(align_space, sizeof(*data->bps_bo), GFP_KERNEL);
if (!new_bps || !new_bo) {
kfree(new_bps);
kfree(new_bo);
dev_warn_ratelimited(adev->dev,
"RAS WARN: failed to grow bad page table to %u slots\n",
align_space);
return -ENOMEM;
}
memcpy(new_bps, data->bps, data->count * sizeof(*data->bps));
memcpy(new_bo, data->bps_bo, data->count * sizeof(*data->bps_bo));
kfree(data->bps);
kfree(data->bps_bo);
data->bps = new_bps;
data->bps_bo = new_bo;
data->capacity = (int)align_space;
return 0;
}
static int amdgpu_virt_init_ras_err_handler_data(struct amdgpu_device *adev)
{
struct amdgpu_virt *virt = &adev->virt;
struct amdgpu_virt_ras_err_handler_data **data = &virt->virt_eh_data;
/* GPU will be marked bad on host if bp count more then 10,
* so alloc 512 is enough.
*/
unsigned int align_space = 512;
unsigned int align_space = AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_INIT_CAPACITY;
void *bps = NULL;
struct amdgpu_bo **bps_bo = NULL;
@ -302,12 +354,13 @@ static int amdgpu_virt_init_ras_err_handler_data(struct amdgpu_device *adev)
if (!bps)
goto bps_failure;
bps_bo = kmalloc_objs(*(*data)->bps_bo, align_space);
bps_bo = kcalloc(align_space, sizeof(*(*data)->bps_bo), GFP_KERNEL);
if (!bps_bo)
goto bps_bo_failure;
(*data)->bps = bps;
(*data)->bps_bo = bps_bo;
(*data)->capacity = align_space;
(*data)->count = 0;
(*data)->last_reserved = 0;
@ -361,17 +414,33 @@ void amdgpu_virt_release_ras_err_handler_data(struct amdgpu_device *adev)
virt->virt_eh_data = NULL;
}
static void amdgpu_virt_ras_add_bps(struct amdgpu_device *adev,
struct eeprom_table_record *bps, int pages)
static bool amdgpu_virt_ras_add_bps(struct amdgpu_device *adev,
const struct eeprom_table_record *bps, int pages)
{
struct amdgpu_virt *virt = &adev->virt;
struct amdgpu_virt_ras_err_handler_data *data = virt->virt_eh_data;
int need;
if (!data)
return;
if (!data || pages <= 0)
return false;
if (pages > AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_MAX_CAPACITY - data->count) {
dev_warn_ratelimited(adev->dev,
"RAS WARN: bad page table at capacity (count=%d pages=%d max=%u)\n",
data->count, pages,
AMDGPU_VIRT_RAS_BAD_PAGE_TABLE_MAX_CAPACITY);
return false;
}
need = data->count + pages;
if (need > data->capacity &&
amdgpu_virt_ras_realloc_eh_data_space(adev, data, need - data->capacity))
return false;
memcpy(&data->bps[data->count], bps, pages * sizeof(*data->bps));
data->count += pages;
return true;
}
static void amdgpu_virt_ras_reserve_bps(struct amdgpu_device *adev)
@ -443,20 +512,22 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev,
memset(&bp, 0, sizeof(bp));
if (bp_block_size) {
bp_cnt = bp_block_size / sizeof(uint64_t);
for (bp_idx = 0; bp_idx < bp_cnt; bp_idx++) {
retired_page = *(uint64_t *)(vram_usage_va +
bp_block_offset + bp_idx * sizeof(uint64_t));
bp.retired_page = retired_page;
if (!bp_block_size)
return;
if (amdgpu_virt_ras_check_bad_page(adev, retired_page))
continue;
bp_cnt = bp_block_size / sizeof(uint64_t);
for (bp_idx = 0; bp_idx < bp_cnt; bp_idx++) {
retired_page = *(uint64_t *)(vram_usage_va +
bp_block_offset + bp_idx * sizeof(uint64_t));
bp.retired_page = retired_page;
amdgpu_virt_ras_add_bps(adev, &bp, 1);
if (amdgpu_virt_ras_check_bad_page(adev, retired_page))
continue;
amdgpu_virt_ras_reserve_bps(adev);
}
if (!amdgpu_virt_ras_add_bps(adev, &bp, 1))
break;
amdgpu_virt_ras_reserve_bps(adev);
}
}

View File

@ -265,6 +265,8 @@ struct amdgpu_virt_ras_err_handler_data {
struct eeprom_table_record *bps;
/* point to reserved bo array */
struct amdgpu_bo **bps_bo;
/* number of slots in bps[] / bps_bo[] (always >= count) */
int capacity;
/* the count of entries */
int count;
/* last reserved entry's index + 1 */

View File

@ -484,7 +484,7 @@ int amdgpu_vm_lock_individual(struct amdgpu_vm *vm, struct drm_exec *exec,
amdgpu_bo_ref(bo);
spin_unlock(&vm->individual_lock);
ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 1);
ret = drm_exec_prepare_obj(exec, &bo->tbo.base, num_fences);
amdgpu_bo_unref(&bo);
if (unlikely(ret))
return ret;
@ -1982,7 +1982,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
* from user space.
*/
if (unlikely(bo_va->userq_va_mapped))
amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
amdgpu_userq_gem_va_unmap_validate(adev, mapping);
list_del(&mapping->list);
amdgpu_vm_it_remove(mapping, &vm->va);

View File

@ -312,6 +312,7 @@ static int vpe_early_init(struct amdgpu_ip_block *ip_block)
vpe->collaborate_mode = true;
break;
case IP_VERSION(2, 0, 0):
case IP_VERSION(2, 2, 0):
vpe_v2_0_set_funcs(vpe);
break;
default:

View File

@ -43,6 +43,7 @@ static uint32_t athub_v3_0_get_cg_cntl(struct amdgpu_device *adev)
data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1);
break;
case IP_VERSION(3, 3, 0):
case IP_VERSION(3, 4, 2):
data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_3_0);
break;
default:
@ -59,6 +60,7 @@ static void athub_v3_0_set_cg_cntl(struct amdgpu_device *adev, uint32_t data)
WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1, data);
break;
case IP_VERSION(3, 3, 0):
case IP_VERSION(3, 4, 2):
WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_3_0, data);
break;
default:
@ -112,6 +114,7 @@ int athub_v3_0_set_clockgating(struct amdgpu_device *adev,
case IP_VERSION(3, 0, 1):
case IP_VERSION(3, 0, 2):
case IP_VERSION(3, 3, 0):
case IP_VERSION(3, 4, 2):
athub_v3_0_update_medium_grain_clock_gating(adev,
state == AMD_CG_STATE_GATE);
athub_v3_0_update_medium_grain_light_sleep(adev,

View File

@ -129,6 +129,10 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_4_pfp.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_me.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_rlc.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_pfp.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_me.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_rlc.bin");
static const struct amdgpu_hwip_reg_entry gc_reg_list_11_0[] = {
SOC15_REG_ENTRY_STR(GC, 0, regGRBM_STATUS),
@ -1123,6 +1127,7 @@ static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
adev->gfx.config.max_hw_contexts = 8;
adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
@ -1606,6 +1611,7 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
adev->gfx.me.num_me = 1;
adev->gfx.me.num_pipe_per_me = 1;
adev->gfx.me.num_queue_per_pipe = 2;
@ -3078,7 +3084,8 @@ static int gfx_v11_0_wait_for_rlc_autoload_complete(struct amdgpu_device *adev)
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 1) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 2) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 3) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4))
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 6))
bootload_status = RREG32_SOC15(GC, 0,
regRLC_RLCS_BOOTLOAD_STATUS_gc_11_0_1);
else
@ -5721,6 +5728,7 @@ static void gfx_v11_cntl_power_gating(struct amdgpu_device *adev, bool enable)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
WREG32_SOC15(GC, 0, regRLC_PG_DELAY_3, RLC_PG_DELAY_3_DEFAULT_GC_11_0_1);
break;
default:
@ -5760,6 +5768,7 @@ static int gfx_v11_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
if (!enable)
amdgpu_gfx_off_ctrl(adev, false);
@ -5795,6 +5804,7 @@ static int gfx_v11_0_set_clockgating_state(struct amdgpu_ip_block *ip_block,
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
gfx_v11_0_update_gfx_clock_gating(adev,
state == AMD_CG_STATE_GATE);
break;

View File

@ -4057,8 +4057,6 @@ static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX))
amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0);

View File

@ -321,7 +321,7 @@ static void gfxhub_v11_5_0_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, GCVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
@ -449,12 +449,10 @@ static void gfxhub_v11_5_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -326,7 +326,7 @@ static void gfxhub_v12_0_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, GCVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
@ -454,12 +454,10 @@ static void gfxhub_v12_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -633,19 +633,17 @@ static void gfxhub_v12_1_xcc_set_fault_enable_default(struct amdgpu_device *adev
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
OTHER_CLIENT_ID_NO_RETRY_FAULT_INTERRUPT, value);
if (!value)
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
CRASH_ON_NO_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_LO32, tmp);
tmp = RREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32);
if (!value)
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
CRASH_ON_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32, tmp);
}

View File

@ -403,12 +403,10 @@ static void gfxhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -516,12 +516,10 @@ static void gfxhub_v1_2_xcc_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i), regVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
}

View File

@ -418,12 +418,10 @@ static void gfxhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -449,12 +449,10 @@ static void gfxhub_v2_1_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -318,7 +318,7 @@ static void gfxhub_v3_0_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, GCVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
@ -446,12 +446,10 @@ static void gfxhub_v3_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -323,7 +323,7 @@ static void gfxhub_v3_0_3_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, GCVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(GC, 0, regGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
@ -434,12 +434,10 @@ static void gfxhub_v3_0_3_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
if (!value) {
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, 1);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, 1);
}
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_NO_RETRY_FAULT, !value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}

View File

@ -843,6 +843,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
if (r) {

View File

@ -585,6 +585,7 @@ static void gmc_v11_0_set_mmhub_funcs(struct amdgpu_device *adev)
case IP_VERSION(3, 3, 1):
case IP_VERSION(3, 3, 2):
case IP_VERSION(3, 4, 0):
case IP_VERSION(3, 4, 2):
adev->mmhub.funcs = &mmhub_v3_3_funcs;
break;
default:
@ -604,6 +605,7 @@ static void gmc_v11_0_set_gfxhub_funcs(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
adev->gfxhub.funcs = &gfxhub_v11_5_0_funcs;
break;
default:
@ -778,6 +780,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask);
set_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask);
/*
@ -818,6 +821,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
if (r) {

View File

@ -811,8 +811,9 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev)
static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
{
int r, vram_width = 0, vram_type = 0, vram_vendor = 0;
int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits;
struct amdgpu_device *adev = ip_block->adev;
uint64_t pte_addr_mask = 0;
int i;
adev->mmhub.funcs->init(adev);
@ -842,6 +843,8 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* block size 512 (9bit)
*/
amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
dma_addr_bits = 44;
break;
case IP_VERSION(12, 1, 0):
bitmap_set(adev->vmhubs_mask, AMDGPU_GFXHUB(0),
@ -854,9 +857,13 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* block size 512 (9bit)
*/
amdgpu_vm_adjust_size(adev, 128 * 1024 * 1024, 9, 4, 57);
pte_addr_mask = 0x000FFFFFFFFFF000ULL; /* 52 bit PA */
dma_addr_bits = 52;
break;
default:
break;
dev_warn(adev->dev, "Unrecognized GC IP version: 0x%08x\n",
amdgpu_ip_version(adev, GC_HWIP, 0));
return -EINVAL;
}
/* This interrupt is VMC page fault.*/
@ -910,14 +917,15 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = AMDGPU_GMC_HOLE_MASK;
adev->gmc.pte_addr_mask = pte_addr_mask;
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(dma_addr_bits));
if (r) {
drm_warn(adev_to_drm(adev), "No suitable DMA available.\n");
return r;
}
adev->need_swiotlb = drm_need_swiotlb(44);
adev->need_swiotlb = drm_need_swiotlb(dma_addr_bits);
r = gmc_v12_0_mc_init(adev);
if (r)

View File

@ -830,6 +830,7 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
amdgpu_vm_adjust_size(adev, 64, 9, 1, 40);
adev->gmc.mc_mask = 0xffffffffffULL;
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL;
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {

View File

@ -1010,6 +1010,7 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {

View File

@ -1125,6 +1125,7 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {

View File

@ -1983,6 +1983,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
dma_addr_bits = amdgpu_ip_version(adev, GC_HWIP, 0) >=
IP_VERSION(9, 4, 2) ?

View File

@ -42,6 +42,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_1_imu.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_2_imu.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_3_imu.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_imu.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_imu.bin");
static int imu_v11_0_init_microcode(struct amdgpu_device *adev)
{

View File

@ -467,6 +467,11 @@ static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
kfree(queue->userq_prop);
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
&queue->mqd.cpu_ptr);
amdgpu_bo_reserve(queue->wptr_obj.obj, true);
amdgpu_bo_unpin(queue->wptr_obj.obj);
amdgpu_bo_unreserve(queue->wptr_obj.obj);
amdgpu_bo_unref(&queue->wptr_obj.obj);
}
static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)

View File

@ -58,6 +58,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_3_mes_2.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_3_mes1.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_mes_2.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_4_mes1.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_mes_2.bin");
MODULE_FIRMWARE("amdgpu/gc_11_5_6_mes1.bin");
static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block);
static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block);

View File

@ -340,7 +340,7 @@ static void mmhub_v3_0_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -333,7 +333,7 @@ static void mmhub_v3_0_1_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -339,7 +339,7 @@ static void mmhub_v3_0_2_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -451,7 +451,7 @@ static void mmhub_v3_3_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,
@ -636,6 +636,7 @@ static void mmhub_v3_3_init_client_info(struct amdgpu_device *adev)
ARRAY_SIZE(mmhub_client_ids_v3_3_1));
break;
case IP_VERSION(3, 4, 0):
case IP_VERSION(3, 4, 2):
amdgpu_mmhub_init_client_info(&adev->mmhub,
mmhub_client_ids_v3_4,
ARRAY_SIZE(mmhub_client_ids_v3_4));

View File

@ -334,7 +334,7 @@ static void mmhub_v4_1_0_setup_vmid_config(struct amdgpu_device *adev)
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, 0, regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -518,7 +518,7 @@ static void mmhub_v4_2_0_mid_setup_vmid_config(struct amdgpu_device *adev,
/* Send no-retry XNACK on fault to suppress VM fault storm. */
tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
!amdgpu_noretry);
!adev->gmc.noretry);
WREG32_SOC15_OFFSET(MMHUB, GET_INST(MMHUB, j), regMMVM_CONTEXT1_CNTL,
i * hub->ctx_distance, tmp);
WREG32_SOC15_OFFSET(MMHUB, GET_INST(MMHUB, j), regMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32,

View File

@ -57,12 +57,50 @@
#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10 0x0021
#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10_BASE_IDX 2
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5 0x8e13
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_HIGH_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5 0x8e14
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_BASE_LOW_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5 0x8e15
#define regBIF_BX_PF0_DOORBELL_SELFRING_GPA_APER_CNTL_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5 0x8e4d
#define regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5 0x8e4e
#define regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5 0xd000
#define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX0_BIF_FB_EN_nbio_7_11_5 0x8e20
#define regBIF_BX0_BIF_FB_EN_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5 0x8e11
#define regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5 0x8e12
#define regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5 0x8e26
#define regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5 0x8e27
#define regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5_BASE_IDX 5
#define regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5 0x8e17
#define regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5_BASE_IDX 5
static void nbif_v6_3_1_remap_hdp_registers(struct amdgpu_device *adev)
{
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5)) {
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL_nbio_7_11_5,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL_nbio_7_11_5,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
} else {
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_MEM_FLUSH_CNTL,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL);
WREG32_SOC15(NBIO, 0, regBIF_BX0_REMAP_HDP_REG_FLUSH_CNTL,
adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL);
}
}
static u32 nbif_v6_3_1_get_rev_id(struct amdgpu_device *adev)
@ -71,6 +109,8 @@ static u32 nbif_v6_3_1_get_rev_id(struct amdgpu_device *adev)
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4))
tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbif_4_10);
else if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_nbio_7_11_5);
else
tmp = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0);
@ -82,12 +122,21 @@ static u32 nbif_v6_3_1_get_rev_id(struct amdgpu_device *adev)
static void nbif_v6_3_1_mc_access_enable(struct amdgpu_device *adev, bool enable)
{
if (enable)
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN,
BIF_BX0_BIF_FB_EN__FB_READ_EN_MASK |
BIF_BX0_BIF_FB_EN__FB_WRITE_EN_MASK);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN, 0);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5)) {
if (enable)
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN_nbio_7_11_5,
BIF_BX0_BIF_FB_EN__FB_READ_EN_MASK |
BIF_BX0_BIF_FB_EN__FB_WRITE_EN_MASK);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN_nbio_7_11_5, 0);
} else {
if (enable)
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN,
BIF_BX0_BIF_FB_EN__FB_READ_EN_MASK |
BIF_BX0_BIF_FB_EN__FB_WRITE_EN_MASK);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN, 0);
}
}
static u32 nbif_v6_3_1_get_memsize(struct amdgpu_device *adev)
@ -100,8 +149,14 @@ static void nbif_v6_3_1_sdma_doorbell_range(struct amdgpu_device *adev,
int doorbell_index,
int doorbell_size)
{
u32 doorbell_range;
if (instance == 0) {
u32 doorbell_range = RREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
doorbell_range = RREG32_SOC15(NBIO, 0,
regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10);
else
doorbell_range = RREG32_SOC15(NBIO, 0,
regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL);
if (use_doorbell) {
doorbell_range = REG_SET_FIELD(doorbell_range,
@ -130,11 +185,10 @@ static void nbif_v6_3_1_sdma_doorbell_range(struct amdgpu_device *adev,
S2A_DOORBELL_PORT2_RANGE_SIZE,
0);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL_nbif_4_10, doorbell_range);
} else {
else
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL, doorbell_range);
}
}
}
@ -179,14 +233,15 @@ static void nbif_v6_3_1_vcn_doorbell_range(struct amdgpu_device *adev,
S2A_DOORBELL_PORT4_RANGE_SIZE,
0);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) {
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10, doorbell_range);
} else {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
WREG32_SOC15(NBIO, 0,
regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL_nbif_4_10,
doorbell_range);
else
if (instance)
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL, doorbell_range);
else
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL, doorbell_range);
}
}
static void nbif_v6_3_1_vpe_doorbell_range(struct amdgpu_device *adev,
@ -227,16 +282,18 @@ static void nbif_v6_3_1_vpe_doorbell_range(struct amdgpu_device *adev,
0);
}
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4))
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4) ||
amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5)) {
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL_nbif_4_10, doorbell_range);
else
} else {
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL, doorbell_range);
}
}
static void nbif_v6_3_1_gc_doorbell_init(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4)) {
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL_nbif_4_10, 0x30000007);
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL_nbif_4_10, 0x3000000d);
} else {
@ -278,7 +335,13 @@ nbif_v6_3_1_enable_doorbell_selfring_aperture(struct amdgpu_device *adev,
static void nbif_v6_3_1_ih_doorbell_range(struct amdgpu_device *adev,
bool use_doorbell, int doorbell_index)
{
u32 ih_doorbell_range = RREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL);
u32 ih_doorbell_range;
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
ih_doorbell_range = RREG32_SOC15(NBIO, 0,
regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10);
else
ih_doorbell_range = RREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL);
if (use_doorbell) {
ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
@ -307,11 +370,11 @@ static void nbif_v6_3_1_ih_doorbell_range(struct amdgpu_device *adev,
S2A_DOORBELL_PORT1_RANGE_SIZE,
0);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) {
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10, ih_doorbell_range);
} else {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL_nbif_4_10,
ih_doorbell_range);
else
WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL, ih_doorbell_range);
}
}
static void nbif_v6_3_1_ih_control(struct amdgpu_device *adev)
@ -319,9 +382,13 @@ static void nbif_v6_3_1_ih_control(struct amdgpu_device *adev)
u32 interrupt_cntl;
/* setup interrupt control */
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2_nbio_7_11_5,
adev->dummy_page_addr >> 8);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
interrupt_cntl = RREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL);
interrupt_cntl = RREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5);
/*
* BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
* BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
@ -333,7 +400,10 @@ static void nbif_v6_3_1_ih_control(struct amdgpu_device *adev)
interrupt_cntl = REG_SET_FIELD(interrupt_cntl, BIF_BX0_INTERRUPT_CNTL,
IH_REQ_NONSNOOP_EN, 0);
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL, interrupt_cntl);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL_nbio_7_11_5, interrupt_cntl);
else
WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL, interrupt_cntl);
}
static void
@ -356,27 +426,31 @@ nbif_v6_3_1_get_clockgating_state(struct amdgpu_device *adev,
static u32 nbif_v6_3_1_get_hdp_flush_req_offset(struct amdgpu_device *adev)
{
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_REQ);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_REQ_nbio_7_11_5);
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_REQ);
}
static u32 nbif_v6_3_1_get_hdp_flush_done_offset(struct amdgpu_device *adev)
{
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_DONE);
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_DONE_nbio_7_11_5);
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_GPU_HDP_FLUSH_DONE);
}
static u32 nbif_v6_3_1_get_pcie_index_offset(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4)) {
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX0_PCIE_INDEX);
}
else {
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_RSMU_INDEX);
}
}
static u32 nbif_v6_3_1_get_pcie_data_offset(struct amdgpu_device *adev)
{
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 4))
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) >= IP_VERSION(7, 11, 4))
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX0_PCIE_DATA);
else
return SOC15_REG_OFFSET(NBIO, 0, regBIF_BX_PF0_RSMU_DATA);
@ -546,8 +620,12 @@ static void nbif_v6_3_1_set_reg_remap(struct amdgpu_device *adev)
adev->rmmio_remap.reg_offset = MMIO_REG_HOLE_OFFSET;
adev->rmmio_remap.bus_addr = adev->rmmio_base + MMIO_REG_HOLE_OFFSET;
} else {
adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0,
regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL) << 2;
if (amdgpu_ip_version(adev, NBIO_HWIP, 0) == IP_VERSION(7, 11, 5))
adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0,
regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL_nbio_7_11_5) << 2;
else
adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0,
regBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL) << 2;
adev->rmmio_remap.bus_addr = 0;
}
}

View File

@ -55,6 +55,7 @@ MODULE_FIRMWARE("amdgpu/sdma_6_1_1.bin");
MODULE_FIRMWARE("amdgpu/sdma_6_1_2.bin");
MODULE_FIRMWARE("amdgpu/sdma_6_1_3.bin");
MODULE_FIRMWARE("amdgpu/sdma_6_1_4.bin");
MODULE_FIRMWARE("amdgpu/sdma_6_4_0.bin");
#define SDMA1_REG_OFFSET 0x600
#define SDMA0_HYP_DEC_REG_START 0x5880

View File

@ -1315,6 +1315,7 @@ static int sdma_v7_1_sw_init(struct amdgpu_ip_block *ip_block)
ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
ring->no_user_submission = adev->sdma.no_user_submission;
for (xcc_id = 0; xcc_id < fls(adev->gfx.xcc_mask); xcc_id++) {
if (adev->sdma.instance[i].xcc_id == GET_INST(GC, xcc_id))

View File

@ -833,6 +833,11 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
AMD_PG_SUPPORT_GFX_PG;
adev->external_rev_id = adev->rev_id + 0x1;
break;
case IP_VERSION(11, 5, 6):
adev->cg_flags = 0;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0xd0;
break;
default:
/* FIXME: not supported yet */
return -EINVAL;

View File

@ -31,6 +31,7 @@
#include "vpe/vpe_2_0_0_sh_mask.h"
MODULE_FIRMWARE("amdgpu/vpe_2_0_0.bin");
MODULE_FIRMWARE("amdgpu/vpe_2_2_0.bin");
#define VPE_THREAD1_UCODE_OFFSET 0x8000

View File

@ -1706,6 +1706,7 @@ int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pc
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
/* Cacheline size not available in IP discovery for gc11.
* kfd_fill_gpu_cache_info_from_gfx_config to hard code it
*/

View File

@ -106,6 +106,7 @@ static void kfd_device_info_set_sdma_info(struct kfd_dev *kfd)
case IP_VERSION(6, 1, 2):
case IP_VERSION(6, 1, 3):
case IP_VERSION(6, 1, 4):
case IP_VERSION(6, 4, 0):
case IP_VERSION(7, 0, 0):
case IP_VERSION(7, 0, 1):
case IP_VERSION(7, 1, 0):
@ -167,6 +168,7 @@ static void kfd_device_info_set_event_interrupt_class(struct kfd_dev *kfd)
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
kfd->device_info.event_interrupt_class = &event_interrupt_class_v11;
break;
case IP_VERSION(12, 0, 0):
@ -445,6 +447,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
f2g = &gfx_v11_kfd2kgd;
break;
case IP_VERSION(11, 5, 4):
case IP_VERSION(11, 5, 6):
gfx_target_version = 110504;
f2g = &gfx_v11_kfd2kgd;
break;
@ -736,6 +739,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
int partition_mode;
int xcp_idx;
kfd->profiler_process = NULL;
mutex_init(&kfd->profiler_lock);
kfd->mec_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev,
KGD_ENGINE_MEC1);
kfd->mec2_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev,
@ -936,9 +942,6 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
svm_range_set_max_pages(kfd->adev);
kfd->profiler_process = NULL;
mutex_init(&kfd->profiler_lock);
kfd->init_complete = true;
dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor,
kfd->adev->pdev->device);

View File

@ -2669,6 +2669,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
if (pdd->qpd.is_debug)
return ret;
if (q->properties.is_being_destroyed)
return -EBUSY;
q->properties.is_being_destroyed = true;
if (pdd->process->debug_trap_enabled && q->properties.is_suspended) {
@ -2681,6 +2684,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
dqm_lock(dqm);
}
if (ret)
q->properties.is_being_destroyed = false;
return ret;
}
@ -2774,7 +2780,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
return retval;
failed_try_destroy_debugged_queue:
q->properties.is_being_destroyed = false;
dqm_unlock(dqm);
return retval;
}
@ -3478,7 +3484,7 @@ static void copy_context_work_handler(struct work_struct *work)
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
{
if (!usr_queue_id_array)
return NULL;
return num_queues ? ERR_PTR(-EINVAL) : NULL;
if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
return ERR_PTR(-EINVAL);

View File

@ -330,8 +330,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
static void restore_mqd(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *qp,
const void *mqd_src,
struct queue_properties *qp, const void *mqd_src,
const void *ctl_stack_src, const u32 ctl_stack_size)
{
uint64_t addr;
@ -347,14 +346,48 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
*gart_addr = addr;
m->cp_hqd_pq_doorbell_control =
qp->doorbell_off <<
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n",
m->cp_hqd_pq_doorbell_control);
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
qp->is_active = 0;
}
static void checkpoint_mqd_sdma(struct mqd_manager *mm,
void *mqd,
void *mqd_dst,
void *ctl_stack_dst)
{
struct v11_sdma_mqd *m;
m = get_sdma_mqd(mqd);
memcpy(mqd_dst, m, sizeof(struct v11_sdma_mqd));
}
static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *qp,
const void *mqd_src,
const void *ctl_stack_src,
const u32 ctl_stack_size)
{
uint64_t addr;
struct v11_sdma_mqd *m;
m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr;
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
m->sdmax_rlcx_doorbell_offset =
qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
*mqd = m;
if (gart_addr)
*gart_addr = addr;
qp->is_active = 0;
}
static void init_mqd_hiq(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
@ -539,8 +572,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type,
mqd->update_mqd = update_mqd_sdma;
mqd->destroy_mqd = kfd_destroy_mqd_sdma;
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->checkpoint_mqd = checkpoint_mqd;
mqd->restore_mqd = restore_mqd;
mqd->checkpoint_mqd = checkpoint_mqd_sdma;
mqd->restore_mqd = restore_mqd_sdma;
mqd->mqd_size = sizeof(struct v11_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
#if defined(CONFIG_DEBUG_FS)

View File

@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <drm/drm_drv.h>
@ -52,7 +53,7 @@ int amdgpu_xcp_drm_dev_alloc(struct drm_device **ddev)
{
struct platform_device *pdev;
struct xcp_device *pxcp_dev;
char dev_name[20];
char *dev_name;
int ret, i;
guard(mutex)(&xcp_mutex);
@ -68,8 +69,12 @@ int amdgpu_xcp_drm_dev_alloc(struct drm_device **ddev)
if (i >= MAX_XCP_PLATFORM_DEVICE)
return -ENODEV;
snprintf(dev_name, sizeof(dev_name), "amdgpu_xcp_%d", i);
dev_name = kasprintf(GFP_KERNEL, "amdgpu_xcp_%d", i);
if (!dev_name)
return -ENOMEM;
pdev = platform_device_register_simple(dev_name, -1, NULL, 0);
kfree(dev_name);
if (IS_ERR(pdev))
return PTR_ERR(pdev);

View File

@ -58,7 +58,7 @@ config DRM_AMD_SECURE_DISPLAY
config DRM_AMD_DC_KUNIT_TEST
tristate "KUnit tests for the AMD DC display driver" if !KUNIT_ALL_TESTS
depends on DRM_AMD_DC && KUNIT && DEBUG_FS
depends on DRM_AMD_DC && KUNIT && DEBUG_FS && DRM_KUNIT_TEST_HELPERS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the AMD Display Core driver.

View File

@ -63,4 +63,7 @@ endif
# KUnit tests as separate module
ifneq ($(CONFIG_DRM_AMD_DC_KUNIT_TEST),)
obj-y += $(AMDDALPATH)/amdgpu_dm/tests/
# Enable gcov for amdgpu_dm KUnit builds
GCOV_PROFILE := y
endif

View File

@ -158,6 +158,9 @@ MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB);
#define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin"
MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB);
#define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin"
MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB);
/**
* DOC: overview
*
@ -1375,6 +1378,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
case IP_VERSION(3, 5, 1):
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
hw_params.ips_sequential_ono = adev->external_rev_id > 0x10;
hw_params.lower_hbr3_phy_ssc = true;
break;
@ -1823,6 +1827,7 @@ static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
bb_size = sizeof(struct dml2_soc_bb);
break;
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
bb_size = sizeof(struct dml2_soc_bb);
break;
default:
@ -1870,6 +1875,7 @@ static enum dmub_ips_disable_type dm_get_default_ips_mode(
ret = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF;
break;
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
ret = DMUB_IPS_ENABLE;
break;
default:
@ -1946,6 +1952,40 @@ static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm)
return 0;
}
static void hdmi_frl_status_polling_work(struct work_struct *work)
{
struct amdgpu_display_manager *dm =
container_of(to_delayed_work(work), struct amdgpu_display_manager,
hdmi_frl_status_polling_work);
struct dc *dc = dm->dc;
struct dc_link *dc_link;
bool link_update = false;
for (int i = 0; i < MAX_LINKS; i++) {
dc_link = dc->links[i];
if (!dc_link || !dc_link->local_sink)
continue;
if (!dc_is_hdmi_signal(dc_link->connector_signal))
continue;
if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
continue;
link_update = dc_link_frl_poll_status_flag(dc_link);
if (link_update) {
mutex_lock(&dm->dc_lock);
dc_link_detect(dc_link, DETECT_REASON_RETRAIN);
mutex_unlock(&dm->dc_lock);
}
}
queue_delayed_work(dm->hdmi_frl_status_polling_wq,
&dm->hdmi_frl_status_polling_work,
msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms));
}
static int amdgpu_dm_init(struct amdgpu_device *adev)
{
struct dc_init_data init_data;
@ -2050,6 +2090,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;
if (amdgpu_dc_feature_mask & DC_FRL_MASK)
init_data.flags.enable_frl = true;
init_data.flags.seamless_boot_edp_requested = false;
if (amdgpu_device_seamless_boot_supported(adev)) {
@ -2217,6 +2260,14 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
dc_init_callbacks(adev->dm.dc, &init_params);
}
if (adev->dm.dc->caps.max_links > 0) {
adev->dm.hdmi_frl_status_polling_wq =
create_singlethread_workqueue("hdmi_frl_status_polling_workqueue");
if (!adev->dm.hdmi_frl_status_polling_wq)
drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n");
adev->dm.hdmi_frl_status_polling_delay_ms = 200;
INIT_DELAYED_WORK(&adev->dm.hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
}
if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
init_completion(&adev->dm.dmub_aux_transfer_done);
adev->dm.dmub_notify = kzalloc_obj(struct dmub_notification);
@ -2483,6 +2534,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 0, 1):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
return 0;
default:
break;
@ -2621,6 +2673,9 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
case IP_VERSION(4, 2, 0):
dmub_asic = DMUB_ASIC_DCN42;
break;
case IP_VERSION(4, 2, 1):
dmub_asic = DMUB_ASIC_DCN42B;
break;
default:
/* ASIC doesn't support DMUB. */
return 0;
@ -5741,6 +5796,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 0, 1):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
if (register_outbox_irq_handlers(dm->adev)) {
drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
goto fail;
@ -5766,6 +5822,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 0, 1):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
psr_feature_enabled = true;
break;
default:
@ -5784,6 +5841,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 5, 1):
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
replay_feature_enabled = true;
break;
@ -5945,6 +6003,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 0, 1):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
if (dcn10_register_irq_handlers(dm->adev)) {
drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
goto fail;
@ -6096,6 +6155,9 @@ static int dm_init_microcode(struct amdgpu_device *adev)
case IP_VERSION(4, 2, 0):
fw_name_dmub = FIRMWARE_DCN_42_DMUB;
break;
case IP_VERSION(4, 2, 1):
fw_name_dmub = FIRMWARE_DCN_42B_DMUB;
break;
default:
/* ASIC doesn't support DMUB. */
return 0;
@ -6224,6 +6286,7 @@ static int dm_early_init(struct amdgpu_ip_block *ip_block)
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 0, 1):
case IP_VERSION(4, 2, 0):
case IP_VERSION(4, 2, 1):
adev->mode_info.num_crtc = 4;
adev->mode_info.num_hpd = 4;
adev->mode_info.num_dig = 4;
@ -6918,18 +6981,26 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->v_border_bottom = 0;
/* TODO: un-hardcode */
if (drm_mode_is_420_only(info, mode_in)
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL)
&& aconnector
&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if (drm_mode_is_420_also(info, mode_in)
&& aconnector
&& aconnector->force_yuv420_output)
&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420
|| aconnector->force_yuv420_output))
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
&& aconnector
&& aconnector->force_yuv422_output)
&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422
|| aconnector->force_yuv422_output))
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL)
&& aconnector
&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR444)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
else
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
@ -6954,7 +7025,8 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
}
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL) {
err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
(struct drm_connector *)connector,
mode_in);
@ -7299,12 +7371,30 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP)) {
if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE)
dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
dsc_caps);
else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
if (aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT &&
!aconnector->dsc_settings.dsc_force_disable_passthrough &&
aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0 &&
sink->edid_caps.frl_dsc_support &&
sink->edid_caps.max_frl_rate > 0 &&
sink->edid_caps.frl_dsc_max_frl_rate > 0)
dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
else
dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
dsc_caps);
}
} else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
if (sink->edid_caps.frl_dsc_support &&
sink->edid_caps.max_frl_rate > 0 &&
sink->edid_caps.frl_dsc_max_frl_rate > 0)
dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
}
}
@ -7378,6 +7468,10 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
struct drm_connector *drm_connector = &aconnector->base;
u32 link_bandwidth_kbps;
struct dc *dc = sink->ctx->dc;
const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL;
u32 converter_bw_in_kbps;
u32 sink_bw_in_kbps;
u32 dsc_sink_bw_in_kbps;
u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
u32 dsc_max_supported_bw_in_kbps;
u32 max_dsc_target_bpp_limit_override =
@ -7416,8 +7510,18 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
} else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing,
dc_link_get_highest_encoding_format(aconnector->dc_link));
max_supported_bw_in_kbps = link_bandwidth_kbps;
dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
converter_bw_in_kbps = aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps;
sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate);
dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
if (dsc_caps->is_frl) {
max_supported_bw_in_kbps = min(link_bandwidth_kbps, converter_bw_in_kbps);
max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, sink_bw_in_kbps);
dsc_max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps);
} else {
max_supported_bw_in_kbps = link_bandwidth_kbps;
dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
}
if (timing_bw_in_kbps > max_supported_bw_in_kbps &&
max_supported_bw_in_kbps > 0 &&
@ -7430,11 +7534,41 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
dc_link_get_highest_encoding_format(aconnector->dc_link),
&stream->timing.dsc_cfg)) {
stream->timing.flags.DSC = 1;
drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from DP-HDMI PCON\n",
__func__, drm_connector->name);
drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from %s\n",
__func__, drm_connector->name,
(dsc_caps->is_frl == 1) ? "HDMI FRL RX" : "DP-HDMI PCON");
}
}
}
else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
struct dc_dsc_policy dsc_policy = {0};
frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link);
if (frl_verified_link_cap->frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE &&
aconnector->dc_link->frl_flags.force_frl_dsc) {
dc_dsc_policy_set_enable_dsc_when_not_needed(true);
dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
}
timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL);
link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link, frl_verified_link_cap->frl_link_rate);
dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
if ((timing_bw_in_kbps > link_bandwidth_kbps && dsc_sink_bw_in_kbps > 0) ||
(dsc_policy.enable_dsc_when_not_needed || dsc_options.force_dsc_when_not_needed)) {
if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
dsc_caps,
&dsc_options,
dsc_sink_bw_in_kbps,
&stream->timing,
dc_link_get_highest_encoding_format(aconnector->dc_link),
&stream->timing.dsc_cfg)) {
stream->timing.flags.DSC = 1;
drm_dbg_driver(drm_connector->dev, "%s: HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n",
__func__, drm_connector->name);
}
}
}
/* Overwrite the stream flag if DSC is enabled through debugfs */
if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE)
@ -7601,8 +7735,9 @@ create_stream_for_sink(struct drm_connector *connector,
update_stream_signal(stream, sink);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL)
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
@ -8304,6 +8439,7 @@ create_validate_stream_for_sink(struct drm_connector *connector,
if (aconnector &&
(aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL ||
aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
bpc_limit = 8;
@ -10871,6 +11007,25 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
dc_exit_ips_for_hw_access(dm->dc);
WARN_ON(!dc_commit_streams(dm->dc, &params));
bool frl_stream_found = false;
for (i = 0; i < params.stream_count; i++) {
struct dc_stream_state *stream = params.streams[i];
if (stream->signal == SIGNAL_TYPE_HDMI_FRL) {
frl_stream_found = true;
break;
}
}
if (frl_stream_found) {
if (queue_delayed_work(dm->hdmi_frl_status_polling_wq,
&dm->hdmi_frl_status_polling_work,
msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms)))
drm_dbg_kms(dev, "200ms frl status polling starts ...\n");
} else {
if (cancel_delayed_work_sync(&dm->hdmi_frl_status_polling_work))
drm_dbg_kms(dev, "200ms frl status polling stops ...\n");
}
/* Allow idle optimization when vblank count is 0 for display off */
if ((dm->active_vblank_irq_count == 0) && amdgpu_dm_is_headless(dm->adev))
dc_allow_idle_optimizations(dm->dc, true);
@ -12655,7 +12810,8 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
* as previous DCN generations, so enable native mode on DCN401/420
*/
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1) ||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0)) {
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1)) {
*cursor_mode = DM_CURSOR_NATIVE_MODE;
return 0;
}
@ -13091,9 +13247,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
continue;
/* Check if rotation or scaling is enabled on DCN401 */
if ((drm_plane_mask(crtc->cursor) & new_crtc_state->plane_mask) &&
(amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1))) {
if ((drm_plane_mask(crtc->cursor) &
new_crtc_state->plane_mask) &&
(amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1))) {
new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor);
is_rotated = new_cursor_state &&

View File

@ -704,6 +704,14 @@ struct amdgpu_display_manager {
struct completion replied;
char reply_data[0x40]; // Cannot include dmub_cmd here
} fused_io[8];
/**
* @hdmi_frl_status_polling_work:
*
* workqueue for 200ms frl status polling
*/
struct workqueue_struct *hdmi_frl_status_polling_wq;
struct delayed_work hdmi_frl_status_polling_work;
unsigned int hdmi_frl_status_polling_delay_ms;
/**
* @dm_boot_time_crc_info:
@ -840,6 +848,7 @@ struct amdgpu_dm_connector {
bool fake_enable;
bool force_yuv420_output;
bool force_yuv422_output;
uint8_t force_yuv_pixel_format;
struct dsc_preferred_settings dsc_settings;
struct psr_caps psr_caps;
union dp_downstream_port_present mst_downstream_port_present;
@ -850,6 +859,8 @@ struct amdgpu_dm_connector {
bool disallow_edp_enter_psr;
bool disallow_edp_enter_replay;
union dwnstream_portxcaps mst_downstream_port_caps;
/* Record progress status of mst*/
uint8_t mst_status;
@ -1105,7 +1116,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
void amdgpu_dm_update_connector_after_detect(
struct amdgpu_dm_connector *aconnector);
void populate_hdmi_info_from_connector(struct drm_hdmi_info *info,
void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *info,
struct dc_edid_caps *edid_caps);
extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;

View File

@ -759,8 +759,23 @@ static int __set_output_tf_32(struct dc_transfer_func *func,
return res ? 0 : -ENOMEM;
}
STATIC_IFN_KUNIT void __set_tf_bypass(struct dc_transfer_func *tf)
{
tf->type = TF_TYPE_BYPASS;
tf->tf = TRANSFER_FUNCTION_LINEAR;
}
EXPORT_IF_KUNIT(__set_tf_bypass);
static int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
STATIC_IFN_KUNIT void __set_tf_distributed_points(struct dc_transfer_func *tf,
enum dc_transfer_func_predefined predefined_tf)
{
tf->type = TF_TYPE_DISTRIBUTED_POINTS;
tf->tf = predefined_tf;
tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
}
EXPORT_IF_KUNIT(__set_tf_distributed_points);
STATIC_IFN_KUNIT int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
const struct drm_color_lut *regamma_lut,
uint32_t regamma_size, bool has_rom,
enum dc_transfer_func_predefined tf)
@ -779,22 +794,19 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
* pre-defined TF and the custom LUT values into the LUT that's
* actually programmed.
*/
out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
out_tf->tf = tf;
out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
__set_tf_distributed_points(out_tf, tf);
ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom);
} else {
/*
* No CRTC RGM means we can just put the block into bypass
* since we don't have any plane level adjustments using it.
*/
out_tf->type = TF_TYPE_BYPASS;
out_tf->tf = TRANSFER_FUNCTION_LINEAR;
__set_tf_bypass(out_tf);
}
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_atomic_regamma);
/**
* __set_input_tf - calculates the input transfer function based on expected
@ -1044,9 +1056,9 @@ EXPORT_IF_KUNIT(__drm_3dlut32_to_dc_3dlut);
* Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
* on DCN accordingly.
*/
static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut)
STATIC_IFN_KUNIT void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut)
{
if (!drm_lut3d_size) {
lut->state.bits.initialized = 0;
@ -1062,8 +1074,9 @@ static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
MAX_COLOR_3DLUT_BITDEPTH);
}
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_lut3d);
static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
STATIC_IFN_KUNIT int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t shaper_size,
@ -1076,20 +1089,17 @@ static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
* If user shaper LUT is set, we assume a linear color space
* (linearized by degamma 1D LUT or not).
*/
func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
func_shaper->tf = tf;
func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
__set_tf_distributed_points(func_shaper, tf);
ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom);
} else {
func_shaper->type = TF_TYPE_BYPASS;
func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
__set_tf_bypass(func_shaper);
}
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_shaper_lut);
static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
STATIC_IFN_KUNIT int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t blend_size,
@ -1105,18 +1115,15 @@ static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
* module to fill the parameters that will be translated to HW
* points.
*/
func_blend->type = TF_TYPE_DISTRIBUTED_POINTS;
func_blend->tf = tf;
func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
__set_tf_distributed_points(func_blend, tf);
ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size);
} else {
func_blend->type = TF_TYPE_BYPASS;
func_blend->tf = TRANSFER_FUNCTION_LINEAR;
__set_tf_bypass(func_blend);
}
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_blend_lut);
/**
* amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
@ -1198,6 +1205,7 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_verify_lut_sizes);
/**
* amdgpu_dm_check_crtc_color_mgmt: Check if DRM color props are programmable by DC.
@ -1493,7 +1501,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state,
return 0;
}
static int
STATIC_IFN_KUNIT int
__set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct drm_colorop_state *colorop_state)
{
@ -1508,8 +1516,7 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
return -EINVAL;
if (colorop_state->bypass) {
tf->type = TF_TYPE_BYPASS;
tf->tf = TRANSFER_FUNCTION_LINEAR;
__set_tf_bypass(tf);
return 0;
}
@ -1520,6 +1527,7 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
return 0;
}
EXPORT_IF_KUNIT(__set_colorop_in_tf_1d_curve);
static int
__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
@ -1705,9 +1713,9 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
* Returns:
* 0 on success. -EINVAL if drm_lut3d_size is zero.
*/
static int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut)
STATIC_IFN_KUNIT int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut)
{
if (!drm_lut3d_size) {
lut->state.bits.initialized = 0;
@ -1724,6 +1732,7 @@ static int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
return 0;
}
EXPORT_IF_KUNIT(__set_colorop_3dlut);
static int
__set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,

View File

@ -36,11 +36,14 @@ struct drm_color_lut;
struct drm_color_lut32;
struct drm_color_ctm;
struct drm_color_ctm_3x4;
struct drm_colorop_state;
struct drm_property_blob;
struct dc_gamma;
struct dc_rgb;
struct dc_plane_state;
struct fixed31_32;
struct tetrahedral_params;
struct dc_transfer_func;
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
/*
@ -84,6 +87,32 @@ void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
struct tetrahedral_params *params,
bool use_tetrahedral_9,
int bit_depth);
struct dc_3dlut;
void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut);
int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut);
void __set_tf_bypass(struct dc_transfer_func *tf);
void __set_tf_distributed_points(struct dc_transfer_func *tf,
enum dc_transfer_func_predefined predefined_tf);
int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
const struct drm_color_lut *regamma_lut,
uint32_t regamma_size, bool has_rom,
enum dc_transfer_func_predefined tf);
int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t shaper_size,
struct dc_transfer_func *func_shaper);
int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t blend_size,
struct dc_transfer_func *func_blend);
int __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct drm_colorop_state *colorop_state);
#endif
#endif /* __AMDGPU_DM_COLOR_H__ */

View File

@ -63,12 +63,11 @@ static const struct drm_colorop_funcs dm_colorop_funcs = {
.destroy = drm_colorop_destroy,
};
int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list)
STATIC_IFN_KUNIT int
amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane,
bool hw_3d_lut, struct drm_prop_enum_list *list)
{
struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
struct drm_device *dev = plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
int i = 0;
@ -124,7 +123,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
i++;
if (has_3dlut) {
if (hw_3d_lut) {
/* 1D curve - SHAPER TF */
ops[i] = kzalloc_obj(*ops[0]);
if (!ops[i]) {
@ -219,9 +218,20 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
cleanup:
if (ret == -ENOMEM)
drm_err(plane->dev, "KMS: Failed to allocate colorop\n");
drm_err(dev, "KMS: Failed to allocate colorop\n");
drm_colorop_pipeline_destroy(dev);
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_build_default_pipeline);
int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list)
{
struct drm_device *dev = plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
bool hw_3d_lut = adev->dm.dc->caps.color.dpp.hw_3d_lut ||
adev->dm.dc->caps.color.mpc.preblend;
return amdgpu_dm_build_default_pipeline(dev, plane, hw_3d_lut, list);
}

View File

@ -33,4 +33,9 @@ extern const u64 amdgpu_dm_supported_blnd_tfs;
int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
int amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane,
bool hw_3d_lut, struct drm_prop_enum_list *list);
#endif
#endif /* __AMDGPU_DM_COLOROP_H__*/

View File

@ -1345,8 +1345,13 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b
if (size == 0)
return 0;
if (!connector->base.state || !connector->base.state->crtc)
return -ENODEV;
acrtc_state = to_dm_crtc_state(connector->base.state->crtc->state);
write_size = min_t(size_t, size, sizeof(data));
r = copy_from_user(data, buf, write_size);
write_size -= r;
@ -3137,6 +3142,7 @@ static int force_yuv420_output_set(void *data, u64 val)
struct amdgpu_dm_connector *connector = data;
connector->force_yuv420_output = (bool)val;
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR420;
return 0;
}
@ -3156,6 +3162,31 @@ static int force_yuv420_output_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv420_output_fops, force_yuv420_output_get,
force_yuv420_output_set, "%llu\n");
static int force_yuv422_output_set(void *data, u64 val)
{
struct amdgpu_dm_connector *connector = data;
connector->force_yuv422_output = (bool)val;
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR422;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv422_output_fops, NULL,
force_yuv422_output_set, "%llu\n");
static int force_yuv444_output_set(void *data, u64 val)
{
struct amdgpu_dm_connector *connector = data;
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR444;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv444_output_fops, NULL,
force_yuv444_output_set, "%llu\n");
/*
* Read Replay state
*/
@ -3605,6 +3636,8 @@ static const struct {
const struct file_operations *fops;
} connector_debugfs_entries[] = {
{"force_yuv420_output", &force_yuv420_output_fops},
{"force_yuv422_output", &force_yuv422_output_fops},
{"force_yuv444_output", &force_yuv444_output_fops},
{"trigger_hotplug", &trigger_hotplug_debugfs_fops},
{"internal_display", &internal_display_fops},
{"odm_combine_segments", &odm_combine_segments_fops}

View File

@ -581,6 +581,8 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
link->dp.mst_enabled = config->mst_enabled;
link->dp.dp2_enabled = config->dp2_enabled;
link->dp.usb4_enabled = config->usb4_enabled;
if (aconnector->dc_sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
link->hdmi.frl_enabled = config->frl_enabled;
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
link->adjust.auth_delay = 2;
link->adjust.retry_limit = MAX_NUM_OF_ATTEMPTS;

View File

@ -178,8 +178,15 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
if (edid_caps->edid_hdmi)
populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps);
if (edid_caps->edid_hdmi) {
populate_hdmi_info_from_connector(link->dc->config.enable_frl, &connector->display_info.hdmi, edid_caps);
drm_dbg_driver(connector->dev, "%s: HDMI_FRL [%s] max_frl_rate %d\n", __func__, connector->name, edid_caps->max_frl_rate);
if (edid_caps->frl_dsc_support)
drm_dbg_driver(connector->dev, "%s: HDMI_FRL_DSC [%s] frl_dsc_10bpc %d, frl_dsc_12bpc %d, frl_dsc_all_bpp %d, frl_dsc_native_420 %d, frl_dsc_max_slices %d, frl_dsc_max_frl_rate %d, frl_dsc_total_chunk_kbytes %d\n",
__func__, connector->name, edid_caps->frl_dsc_10bpc, edid_caps->frl_dsc_12bpc, \
edid_caps->frl_dsc_all_bpp, edid_caps->frl_dsc_native_420, edid_caps->frl_dsc_max_slices, \
edid_caps->frl_dsc_max_frl_rate, edid_caps->frl_dsc_total_chunk_kbytes);
}
apply_edid_quirks(dev, edid_buf, edid_caps);
@ -1071,9 +1078,70 @@ dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_conn
return edid;
}
void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
static uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane)
{
uint8_t max_frl_rate;
if ((max_lanes == 3) && (max_rate_per_lane == 3))
max_frl_rate = 1;
else if ((max_lanes == 3) && (max_rate_per_lane == 6))
max_frl_rate = 2;
else if ((max_lanes == 4) && (max_rate_per_lane == 6))
max_frl_rate = 3;
else if ((max_lanes == 4) && (max_rate_per_lane == 8))
max_frl_rate = 4;
else if ((max_lanes == 4) && (max_rate_per_lane == 10))
max_frl_rate = 5;
else if ((max_lanes == 4) && (max_rate_per_lane == 12))
max_frl_rate = 6;
else
max_frl_rate = 0;
return max_frl_rate;
}
static uint8_t get_dsc_max_slices(uint8_t max_slices, int clk_per_slice)
{
uint8_t dsc_max_slices;
if ((max_slices == 1) && (clk_per_slice == 340))
dsc_max_slices = 1;
else if ((max_slices == 2) && (clk_per_slice == 340))
dsc_max_slices = 2;
else if ((max_slices == 4) && (clk_per_slice == 340))
dsc_max_slices = 3;
else if ((max_slices == 8) && (clk_per_slice == 340))
dsc_max_slices = 4;
else if ((max_slices == 8) && (clk_per_slice == 400))
dsc_max_slices = 5;
else if ((max_slices == 12) && (clk_per_slice == 400))
dsc_max_slices = 6;
else if ((max_slices == 16) && (clk_per_slice == 400))
dsc_max_slices = 7;
else
dsc_max_slices = 0;
return dsc_max_slices;
}
void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
{
edid_caps->scdc_present = hdmi->scdc.supported;
if (enable_frl) {
edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes, hdmi->max_frl_rate_per_lane);
edid_caps->frl_dsc_support = hdmi->dsc_cap.v_1p2;
if (edid_caps->frl_dsc_support) {
if (hdmi->dsc_cap.bpc_supported == 10)
edid_caps->frl_dsc_10bpc = true;
else if (hdmi->dsc_cap.bpc_supported == 12)
edid_caps->frl_dsc_12bpc = true;
edid_caps->frl_dsc_all_bpp = hdmi->dsc_cap.all_bpp;
edid_caps->frl_dsc_native_420 = hdmi->dsc_cap.native_420;
edid_caps->frl_dsc_max_slices = get_dsc_max_slices(hdmi->dsc_cap.max_slices, hdmi->dsc_cap.clk_per_slice);
edid_caps->frl_dsc_max_frl_rate = get_max_frl_rate(hdmi->dsc_cap.max_lanes, hdmi->dsc_cap.max_frl_rate_per_lane);
edid_caps->frl_dsc_total_chunk_kbytes = hdmi->dsc_cap.total_chunk_kbytes;
}
}
}
enum dc_edid_status dm_helpers_read_local_edid(

View File

@ -230,7 +230,8 @@ EXPORT_IF_KUNIT(dm_ism_get_idle_allow_delay);
* dm_ism_insert_record - Insert a record into the circular history buffer
* @ism: ISM instance
*/
static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
STATIC_IFN_KUNIT
void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
{
struct amdgpu_dm_ism_record *record;
@ -245,15 +246,19 @@ static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
record->duration_ns =
record->timestamp_ns - ism->last_idle_timestamp_ns;
}
EXPORT_IF_KUNIT(dm_ism_insert_record);
static void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism)
STATIC_IFN_KUNIT
void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism)
{
ism->last_idle_timestamp_ns = ktime_get_ns();
}
EXPORT_IF_KUNIT(dm_ism_set_last_idle_ts);
static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
STATIC_IFN_KUNIT
bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event)
{
enum amdgpu_dm_ism_state next_state;
@ -268,6 +273,7 @@ static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
return gotNextState;
}
EXPORT_IF_KUNIT(dm_ism_trigger_event);
static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism,
@ -326,15 +332,36 @@ static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism,
}
}
STATIC_IFN_KUNIT
enum amdgpu_dm_ism_event dm_ism_dispatch_next_event(
enum amdgpu_dm_ism_state current_state,
uint64_t delay_ns,
uint64_t sso_delay_ns)
{
switch (current_state) {
case DM_ISM_STATE_HYSTERESIS_WAITING:
if (delay_ns == 0)
return DM_ISM_EVENT_IMMEDIATE;
break;
case DM_ISM_STATE_OPTIMIZED_IDLE:
if (sso_delay_ns == 0)
return DM_ISM_EVENT_IMMEDIATE;
break;
case DM_ISM_STATE_TIMER_ABORTED:
return DM_ISM_EVENT_IMMEDIATE;
default:
break;
}
return DM_ISM_NUM_EVENTS;
}
EXPORT_IF_KUNIT(dm_ism_dispatch_next_event);
static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
struct amdgpu_dm_ism *ism,
struct dm_crtc_state *acrtc_state,
enum amdgpu_dm_ism_event event)
struct dm_crtc_state *acrtc_state)
{
enum amdgpu_dm_ism_event ret = event;
const struct amdgpu_dm_ism_config *config = &ism->config;
uint64_t delay_ns, sso_delay_ns;
uint64_t delay_ns = 0, sso_delay_ns = 0;
switch (ism->previous_state) {
case DM_ISM_STATE_HYSTERESIS_WAITING:
@ -368,30 +395,15 @@ static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
switch (ism->current_state) {
case DM_ISM_STATE_HYSTERESIS_WAITING:
dm_ism_set_last_idle_ts(ism);
/* CRTC can be disabled; allow immediate idle */
if (!acrtc_state->stream) {
ret = DM_ISM_EVENT_IMMEDIATE;
break;
}
delay_ns = dm_ism_get_idle_allow_delay(ism,
acrtc_state->stream);
if (delay_ns == 0) {
ret = DM_ISM_EVENT_IMMEDIATE;
break;
}
delay_ns = dm_ism_get_idle_allow_delay(ism, acrtc_state->stream);
/* Schedule worker */
mod_delayed_work(system_dfl_wq, &ism->delayed_work,
nsecs_to_jiffies(delay_ns));
if (delay_ns > 0)
mod_delayed_work(system_dfl_wq, &ism->delayed_work,
nsecs_to_jiffies(delay_ns));
break;
case DM_ISM_STATE_OPTIMIZED_IDLE:
sso_delay_ns = dm_ism_get_sso_delay(ism, acrtc_state->stream);
if (sso_delay_ns == 0)
ret = DM_ISM_EVENT_IMMEDIATE;
else if (config->sso_num_frames < config->filter_num_frames) {
if (sso_delay_ns > 0) {
/*
* If sso_num_frames is less than hysteresis frames, it
* indicates that allowing idle here, then disallowing
@ -399,13 +411,10 @@ static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
* have a negative power impact. Skip idle allow here,
* and let the sso_delayed_work handle it.
*/
mod_delayed_work(system_dfl_wq,
&ism->sso_delayed_work,
nsecs_to_jiffies(sso_delay_ns));
} else {
/* Enable idle optimization without SSO */
dm_ism_commit_idle_optimization_state(
ism, acrtc_state->stream, false, false);
if (config->sso_num_frames >= config->filter_num_frames)
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
false, false);
mod_delayed_work(system_dfl_wq,
&ism->sso_delayed_work,
nsecs_to_jiffies(sso_delay_ns));
@ -420,13 +429,12 @@ static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
dm_ism_insert_record(ism);
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
true, false);
ret = DM_ISM_EVENT_IMMEDIATE;
break;
default:
break;
}
return ret;
return dm_ism_dispatch_next_event(ism->current_state, delay_ns, sso_delay_ns);
}
static char *dm_ism_events_str[DM_ISM_NUM_EVENTS] = {
@ -481,8 +489,7 @@ void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
dm_ism_states_str[ism->previous_state],
dm_ism_states_str[ism->current_state],
dm_ism_events_str[event]);
next_event = dm_ism_dispatch_power_state(
ism, acrtc_state, next_event);
next_event = dm_ism_dispatch_power_state(ism, acrtc_state);
} else {
trace_amdgpu_dm_ism_event(
acrtc->crtc_id,
@ -633,6 +640,7 @@ void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
INIT_DELAYED_WORK(&ism->delayed_work, dm_ism_delayed_work_func);
INIT_DELAYED_WORK(&ism->sso_delayed_work, dm_ism_sso_delayed_work_func);
}
EXPORT_IF_KUNIT(amdgpu_dm_ism_init);
void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism)
@ -640,3 +648,4 @@ void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism)
cancel_delayed_work_sync(&ism->sso_delayed_work);
cancel_delayed_work_sync(&ism->delayed_work);
}
EXPORT_IF_KUNIT(amdgpu_dm_ism_fini);

View File

@ -157,6 +157,13 @@ uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
const struct dc_stream_state *stream);
uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
const struct dc_stream_state *stream);
void dm_ism_insert_record(struct amdgpu_dm_ism *ism);
void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism);
bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event);
enum amdgpu_dm_ism_event dm_ism_dispatch_next_event(enum amdgpu_dm_ism_state current_state,
uint64_t delay_ns,
uint64_t sso_delay_ns);
#endif
#endif

View File

@ -1174,6 +1174,77 @@ static int try_disable_dsc(struct drm_atomic_commit *state,
return 0;
}
static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
{
unsigned int max_conv_bw_in_kbps = 0;
unsigned int max_sink_bw_in_kbps = 0;
unsigned int dsc_max_sink_bw_in_kbps = 0;
if (aconnector->dc_link->dc->caps.dp_hdmi21_pcon_support &&
aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE == DOWN_STREAM_DETAILED_HDMI) {
max_conv_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
aconnector->dc_link->dc,
aconnector->mst_downstream_port_caps.bytes.byte2.bits.MAX_ENCODED_LINK_BW_SUPPORT);
if (aconnector->dc_sink->edid_caps.max_frl_rate && max_conv_bw_in_kbps) {
max_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
aconnector->dc_link->dc,
aconnector->dc_sink->edid_caps.max_frl_rate);
dsc_max_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
aconnector->dc_link->dc,
aconnector->dc_sink->edid_caps.frl_dsc_max_frl_rate);
*bw_in_kbps = min(max_conv_bw_in_kbps, max_sink_bw_in_kbps);
*dsc_bw_in_kbps = min(*bw_in_kbps, dsc_max_sink_bw_in_kbps);
}
}
return *bw_in_kbps > 0; // Frl endpoint is detected
}
static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream,
struct dc_dsc_policy *dsc_policy,
struct dsc_mst_fairness_params *params,
uint32_t frl_conv_dsc_bw_in_kbps)
{
uint32_t min_bpp_x16, max_bpp_x16;
struct dc_dsc_config_options dsc_options = {0};
min_bpp_x16 = dsc_policy->min_target_bpp * 16;
max_bpp_x16 = dsc_policy->max_target_bpp * 16;
dc_dsc_get_default_config_option(stream->sink->ctx->dc, &dsc_options);
dsc_options.max_target_bpp_limit_override_x16 =
stream->sink->edid_caps.panel_patch.max_dsc_target_bpp_limit * 16;
if (dc_dsc_compute_config(
stream->sink->ctx->dc->res_pool->dscs[0],
&stream->sink->dsc_caps.dsc_dec_caps,
&dsc_options,
frl_conv_dsc_bw_in_kbps,
&stream->timing,
dc_link_get_highest_encoding_format(aconnector->dc_link),
&stream->timing.dsc_cfg)) {
// The timing can enable dsc
if (stream->sink->dsc_caps.dsc_dec_caps.is_vic_all_bpp && min_bpp_x16 <= stream->timing.dsc_cfg.bits_per_pixel) {
// with all supported bpp within the range limit
params->bw_range.max_target_bpp_x16 = min(stream->timing.dsc_cfg.bits_per_pixel, dsc_policy->max_target_bpp * 16);
params->bw_range.min_target_bpp_x16 = min_bpp_x16;
params->bw_range.max_kbps = (params->bw_range.max_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
params->bw_range.min_kbps = (params->bw_range.min_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
} else if (!stream->sink->dsc_caps.dsc_dec_caps.is_vic_all_bpp &&
min_bpp_x16 <= stream->timing.dsc_cfg.bits_per_pixel &&
max_bpp_x16 >= stream->timing.dsc_cfg.bits_per_pixel) {
// with selected bpp only within the range limit
params->bw_range.max_target_bpp_x16 = stream->timing.dsc_cfg.bits_per_pixel;
params->bw_range.max_kbps = (params->bw_range.max_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
params->bw_range.min_target_bpp_x16 = params->bw_range.max_target_bpp_x16;
params->bw_range.min_kbps = params->bw_range.max_kbps;
}
}
}
static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
{
int i;
@ -1199,6 +1270,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
bool debugfs_overwrite = false;
uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
struct drm_connector_state *new_conn_state;
bool is_frl_endpoint_present;
uint32_t frl_conv_bw_in_kbps, frl_conv_dsc_bw_in_kbps;
memset(params, 0, sizeof(params));
@ -1244,6 +1317,12 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps);
if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported &&
is_frl_endpoint_present &&
frl_conv_dsc_bw_in_kbps &&
stream->sink->dsc_caps.dsc_dec_caps.is_frl)
build_frl_mst_dsc_params(aconnector, stream, &dsc_policy, &params[count], frl_conv_dsc_bw_in_kbps);
if (!dc_dsc_compute_bandwidth_range(
stream->sink->ctx->dc->res_pool->dscs[0],
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,

View File

@ -25,6 +25,7 @@
*/
#include "amdgpu_dm_psr.h"
#include "amdgpu.h"
#include "dc_dmub_srv.h"
#include "dc.h"
#include "amdgpu_dm.h"
@ -122,7 +123,7 @@ bool amdgpu_dm_set_psr_caps(struct dc_link *link, struct amdgpu_dm_connector *ac
return false;
/*disable allow psr/psrsu/replay on eDP1*/
if (dc_get_edp_link_panel_inst(link->ctx->dc, link, &panel_inst) && panel_inst == 1)
if (dc_get_edp_link_panel_inst(dc, link, &panel_inst) && panel_inst == 1)
return false;
if (link_supports_psrsu(link))
@ -144,22 +145,17 @@ bool amdgpu_dm_set_psr_caps(struct dc_link *link, struct amdgpu_dm_connector *ac
bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm)
{
unsigned int i;
bool allow_active = false;
for (i = 0; i < dm->dc->current_state->stream_count ; i++) {
struct dc_link *link;
struct dc_stream_state *stream = dm->dc->current_state->streams[i];
for (i = 0; i < dm->dc->current_state->stream_count; i++) {
const struct dc_link *link = dm->dc->current_state->streams[i]->link;
link = stream->link;
if (!link)
continue;
if (link->psr_settings.psr_feature_enabled &&
link->psr_settings.psr_allow_active) {
allow_active = true;
break;
}
if (link->psr_settings.psr_feature_enabled && link->psr_settings.psr_allow_active)
return true;
}
return allow_active;
return false;
}
/*
@ -193,3 +189,4 @@ bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm, struct dc_stream
return mod_power_set_psr_event(dm->power_module, stream,
set_event, event, wait_for_disable);
}
EXPORT_IF_KUNIT(amdgpu_dm_psr_set_event);

View File

@ -27,10 +27,12 @@
#ifndef AMDGPU_DM_AMDGPU_DM_PSR_H_
#define AMDGPU_DM_AMDGPU_DM_PSR_H_
#include "amdgpu.h"
#include "dc.h"
#include "modules/inc/mod_power.h"
struct amdgpu_display_manager;
struct amdgpu_dm_connector;
/* the number of pageflips before enabling psr */
#define AMDGPU_DM_PSR_ENTRY_DELAY 5

View File

@ -6,9 +6,17 @@ CONFIG_DRM_AMD_DC=y
CONFIG_DEBUG_FS=y
CONFIG_DRM_AMD_DC_KUNIT_TEST=y
CONFIG_FW_LOADER=y
CONFIG_DRM_KUNIT_TEST=y
CONFIG_DRM_KUNIT_TEST_HELPERS=y
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_TTM=y
CONFIG_HWMON=y
CONFIG_I2C=y
CONFIG_POWER_SUPPLY=y
CONFIG_CRC16=y
# GCOV Coverage - see tools/testing/kunit/configs/coverage_uml.config
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_GCOV=y

View File

@ -991,6 +991,542 @@ static void dm_test_3dlut32_to_dc_3dlut_green_blue(struct kunit *test)
drm_color_lut32_extract(600000, 12));
}
/* ---- Tests for amdgpu_dm_verify_lut_sizes ---- */
/**
* dm_test_make_lut_blob - Allocate a fake drm_property_blob for testing
* @test: KUnit test context
* @num_entries: number of LUT entries the blob will report
*
* Allocates a fake blob whose drm_color_lut_size() returns exactly
* @num_entries. The data pointer is non-NULL so that
* __extract_blob_lut() returns a non-NULL lut pointer and the size
* check inside amdgpu_dm_verify_lut_sizes() is actually exercised.
*
* Return: pointer to the allocated blob
*/
static struct drm_property_blob *
dm_test_make_lut_blob(struct kunit *test, uint32_t num_entries)
{
struct drm_property_blob *blob;
blob = kunit_kzalloc(test, sizeof(*blob), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, blob);
blob->length = num_entries * sizeof(struct drm_color_lut);
blob->data = kunit_kcalloc(test, num_entries,
sizeof(struct drm_color_lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, blob->data);
return blob;
}
/**
* dm_test_verify_lut_sizes_null_luts - Both LUTs absent: must succeed
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_null_luts(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
/* degamma_lut and gamma_lut are NULL (zeroed allocation) */
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), 0);
}
/**
* dm_test_verify_lut_sizes_valid_degamma - Degamma LUT with the correct atomic size: must succeed
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_valid_degamma(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->degamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), 0);
}
/**
* dm_test_verify_lut_sizes_invalid_degamma - Degamma LUT with a wrong size: must return -EINVAL
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_invalid_degamma(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
/* Use an arbitrary size that is neither atomic nor legacy */
state->degamma_lut = dm_test_make_lut_blob(test, 128);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), -EINVAL);
}
/**
* dm_test_verify_lut_sizes_valid_gamma_atomic - Gamma LUT with correct atomic size: must succeed
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_valid_gamma_atomic(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->gamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), 0);
}
/**
* dm_test_verify_lut_sizes_valid_gamma_legacy - Gamma LUT with legacy 256-entry size: must succeed
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_valid_gamma_legacy(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->gamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LEGACY_LUT_ENTRIES);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), 0);
}
/**
* dm_test_verify_lut_sizes_invalid_gamma - Size is neither atomic nor legacy: must return -EINVAL
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_invalid_gamma(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->gamma_lut = dm_test_make_lut_blob(test, 128);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), -EINVAL);
}
/**
* dm_test_verify_lut_sizes_both_valid - Both LUTs set to valid sizes: must succeed
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_both_valid(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->degamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
state->gamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), 0);
}
/**
* dm_test_verify_lut_sizes_invalid_degamma_valid_gamma - Bad degamma overrides valid gamma: -EINVAL
* @test: KUnit test context
*/
static void dm_test_verify_lut_sizes_invalid_degamma_valid_gamma(struct kunit *test)
{
struct drm_crtc_state *state;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
state->degamma_lut = dm_test_make_lut_blob(test, 128);
state->gamma_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut_sizes(state), -EINVAL);
}
/* ---- Tests for amdgpu_dm_atomic_lut3d ---- */
/**
* dm_test_atomic_lut3d_zero_size - Zero LUT size: initialized must be cleared, no LUT data written
* @test: KUnit test context
*/
static void dm_test_atomic_lut3d_zero_size(struct kunit *test)
{
struct dc_3dlut *lut;
u32 initialized;
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
/* Pre-set initialized so we can confirm it is cleared */
lut->state.bits.initialized = 1;
amdgpu_dm_atomic_lut3d(NULL, 0, lut);
/* Copy bit-field: typeof cannot be applied to a bit-field */
initialized = lut->state.bits.initialized;
KUNIT_EXPECT_EQ(test, initialized, 0U);
}
/**
* dm_test_atomic_lut3d_nonzero_state_bits - Non-zero size: state bits and mode flags must be set
* @test: KUnit test context
*/
static void dm_test_atomic_lut3d_nonzero_state_bits(struct kunit *test)
{
const uint32_t lut3d_size = 5;
struct drm_color_lut *lut_data;
struct dc_3dlut *lut;
u32 initialized;
lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut_data);
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, lut);
/* Copy bit-field: typeof cannot be applied to a bit-field */
initialized = lut->state.bits.initialized;
KUNIT_EXPECT_EQ(test, initialized, 1U);
KUNIT_EXPECT_FALSE(test, lut->lut_3d.use_tetrahedral_9);
KUNIT_EXPECT_TRUE(test, lut->lut_3d.use_12bits);
}
/**
* dm_test_atomic_lut3d_data_forwarded - Non-zero size: LUT data forwarded to tetrahedral_17
* @test: KUnit test context
*/
static void dm_test_atomic_lut3d_data_forwarded(struct kunit *test)
{
const uint32_t lut3d_size = 5;
struct drm_color_lut *lut_data;
struct dc_3dlut *lut;
lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut_data);
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
lut_data[0].red = 0xFFFF;
lut_data[0].green = 0x8000;
lut_data[0].blue = 0x4000;
amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, lut);
/*
* use_tetrahedral_9 == false data goes into tetrahedral_17.
* lut[0] maps to lut0[0] (first element of the first group).
*/
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].red,
drm_color_lut_extract(0xFFFF, MAX_COLOR_3DLUT_BITDEPTH));
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].green,
drm_color_lut_extract(0x8000, MAX_COLOR_3DLUT_BITDEPTH));
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].blue,
drm_color_lut_extract(0x4000, MAX_COLOR_3DLUT_BITDEPTH));
}
/* ---- Tests for __set_colorop_3dlut ---- */
/**
* dm_test_set_colorop_3dlut_zero_size - Zero LUT size: must return -EINVAL and clear initialized
* @test: KUnit test context
*/
static void dm_test_set_colorop_3dlut_zero_size(struct kunit *test)
{
struct dc_3dlut *lut;
u32 initialized;
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
lut->state.bits.initialized = 1;
KUNIT_EXPECT_EQ(test, __set_colorop_3dlut(NULL, 0, lut), -EINVAL);
/* Copy bit-field: typeof cannot be applied to a bit-field */
initialized = lut->state.bits.initialized;
KUNIT_EXPECT_EQ(test, initialized, 0U);
}
/**
* dm_test_set_colorop_3dlut_nonzero_state_bits - Non-zero size: must return 0 and set state bits
* @test: KUnit test context
*/
static void dm_test_set_colorop_3dlut_nonzero_state_bits(struct kunit *test)
{
const uint32_t lut3d_size = 5;
struct drm_color_lut32 *lut_data;
struct dc_3dlut *lut;
u32 initialized;
lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut_data);
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
KUNIT_EXPECT_EQ(test, __set_colorop_3dlut(lut_data, lut3d_size, lut), 0);
/* Copy bit-field: typeof cannot be applied to a bit-field */
initialized = lut->state.bits.initialized;
KUNIT_EXPECT_EQ(test, initialized, 1U);
KUNIT_EXPECT_FALSE(test, lut->lut_3d.use_tetrahedral_9);
KUNIT_EXPECT_TRUE(test, lut->lut_3d.use_12bits);
}
/**
* dm_test_set_colorop_3dlut_data_forwarded - Non-zero size: 32-bit data forwarded to tetrahedral_17
* @test: KUnit test context
*/
static void dm_test_set_colorop_3dlut_data_forwarded(struct kunit *test)
{
const uint32_t lut3d_size = 5;
struct drm_color_lut32 *lut_data;
struct dc_3dlut *lut;
lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut_data);
lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, lut);
lut_data[0].red = 0xFFFFFFFF;
lut_data[0].green = 0x80000000;
lut_data[0].blue = 0x40000000;
KUNIT_EXPECT_EQ(test, __set_colorop_3dlut(lut_data, lut3d_size, lut), 0);
/*
* use_tetrahedral_9 == false data goes into tetrahedral_17.
* lut[0] maps to lut0[0]. Bit depth used by __set_colorop_3dlut is 12.
*/
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].red,
drm_color_lut32_extract(0xFFFFFFFF, 12));
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].green,
drm_color_lut32_extract(0x80000000, 12));
KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].blue,
drm_color_lut32_extract(0x40000000, 12));
}
/**
* dm_test_set_tf_bypass - __set_tf_bypass: sets TF_TYPE_BYPASS and TRANSFER_FUNCTION_LINEAR
* @test: KUnit test context
*/
static void dm_test_set_tf_bypass(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
tf->type = TF_TYPE_DISTRIBUTED_POINTS;
tf->tf = TRANSFER_FUNCTION_SRGB;
__set_tf_bypass(tf);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_set_tf_distributed_points_srgb - __set_tf_distributed_points: sRGB predefined TF
* @test: KUnit test context
*/
static void dm_test_set_tf_distributed_points_srgb(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
__set_tf_distributed_points(tf, TRANSFER_FUNCTION_SRGB);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_DISTRIBUTED_POINTS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_SRGB);
KUNIT_EXPECT_EQ(test, tf->sdr_ref_white_level, 80U);
}
/**
* dm_test_set_tf_distributed_points_pq - __set_tf_distributed_points: PQ predefined TF
* @test: KUnit test context
*/
static void dm_test_set_tf_distributed_points_pq(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
__set_tf_distributed_points(tf, TRANSFER_FUNCTION_PQ);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_DISTRIBUTED_POINTS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_PQ);
KUNIT_EXPECT_EQ(test, tf->sdr_ref_white_level, 80U);
}
/**
* dm_test_set_atomic_regamma_bypass - No LUT and linear TF: must take bypass path
* @test: KUnit test context
*/
static void dm_test_set_atomic_regamma_bypass(struct kunit *test)
{
struct dc_transfer_func *out_tf;
out_tf = kunit_kzalloc(test, sizeof(*out_tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, out_tf);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_set_atomic_regamma(out_tf, NULL, 0, false,
TRANSFER_FUNCTION_LINEAR),
0);
KUNIT_EXPECT_EQ(test, (int)out_tf->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)out_tf->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_atomic_shaper_lut_bypass - No LUT and linear TF: must take bypass path
* @test: KUnit test context
*/
static void dm_test_atomic_shaper_lut_bypass(struct kunit *test)
{
struct dc_transfer_func *func_shaper;
func_shaper = kunit_kzalloc(test, sizeof(*func_shaper), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, func_shaper);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_atomic_shaper_lut(NULL, false,
TRANSFER_FUNCTION_LINEAR,
0, func_shaper),
0);
KUNIT_EXPECT_EQ(test, (int)func_shaper->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)func_shaper->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_atomic_blend_lut_bypass - amdgpu_dm_atomic_blend_lut bypass: no LUT, linear TF -> bypass
* @test: KUnit test context
*/
static void dm_test_atomic_blend_lut_bypass(struct kunit *test)
{
struct dc_transfer_func *func_blend;
func_blend = kunit_kzalloc(test, sizeof(*func_blend), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, func_blend);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_atomic_blend_lut(NULL, false,
TRANSFER_FUNCTION_LINEAR,
0, func_blend),
0);
KUNIT_EXPECT_EQ(test, (int)func_blend->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)func_blend->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/* ---- Tests for __set_colorop_in_tf_1d_curve ---- */
/**
* dm_test_set_colorop_in_tf_1d_curve_invalid_type - Non-1D colorop type must be rejected
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_invalid_type(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_3D_LUT;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_EOTF;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
-EINVAL);
}
/**
* dm_test_set_colorop_in_tf_1d_curve_unsupported_curve - Unsupported 1D curve type must be rejected
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_unsupported_curve(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_1D_CURVE;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_COUNT;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
-EINVAL);
}
/**
* dm_test_set_colorop_in_tf_1d_curve_bypass - Bypass mode forces linear bypass transfer function
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_bypass(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_1D_CURVE;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_EOTF;
colorop_state->bypass = true;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
0);
KUNIT_EXPECT_EQ(test,
(int)dc_plane_state->in_transfer_func.type,
(int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test,
(int)dc_plane_state->in_transfer_func.tf,
(int)TRANSFER_FUNCTION_LINEAR);
}
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@ -1056,6 +1592,38 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_3dlut32_to_dc_3dlut_distribution),
KUNIT_CASE(dm_test_3dlut32_to_dc_3dlut_tetrahedral_17),
KUNIT_CASE(dm_test_3dlut32_to_dc_3dlut_green_blue),
/* amdgpu_dm_verify_lut_sizes */
KUNIT_CASE(dm_test_verify_lut_sizes_null_luts),
KUNIT_CASE(dm_test_verify_lut_sizes_valid_degamma),
KUNIT_CASE(dm_test_verify_lut_sizes_invalid_degamma),
KUNIT_CASE(dm_test_verify_lut_sizes_valid_gamma_atomic),
KUNIT_CASE(dm_test_verify_lut_sizes_valid_gamma_legacy),
KUNIT_CASE(dm_test_verify_lut_sizes_invalid_gamma),
KUNIT_CASE(dm_test_verify_lut_sizes_both_valid),
KUNIT_CASE(dm_test_verify_lut_sizes_invalid_degamma_valid_gamma),
/* amdgpu_dm_atomic_lut3d */
KUNIT_CASE(dm_test_atomic_lut3d_zero_size),
KUNIT_CASE(dm_test_atomic_lut3d_nonzero_state_bits),
KUNIT_CASE(dm_test_atomic_lut3d_data_forwarded),
/* __set_colorop_3dlut */
KUNIT_CASE(dm_test_set_colorop_3dlut_zero_size),
KUNIT_CASE(dm_test_set_colorop_3dlut_nonzero_state_bits),
KUNIT_CASE(dm_test_set_colorop_3dlut_data_forwarded),
/* __set_tf_bypass */
KUNIT_CASE(dm_test_set_tf_bypass),
/* __set_tf_distributed_points */
KUNIT_CASE(dm_test_set_tf_distributed_points_srgb),
KUNIT_CASE(dm_test_set_tf_distributed_points_pq),
/* amdgpu_dm_set_atomic_regamma */
KUNIT_CASE(dm_test_set_atomic_regamma_bypass),
/* amdgpu_dm_atomic_shaper_lut */
KUNIT_CASE(dm_test_atomic_shaper_lut_bypass),
/* amdgpu_dm_atomic_blend_lut */
KUNIT_CASE(dm_test_atomic_blend_lut_bypass),
/* __set_colorop_in_tf_1d_curve */
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_invalid_type),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_unsupported_curve),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_bypass),
{}
};

View File

@ -7,6 +7,7 @@
#include <kunit/test.h>
#include <drm/drm_colorop.h>
#include <drm/drm_kunit_helpers.h>
#include "amdgpu_dm_colorop.h"
@ -30,10 +31,10 @@ static void dm_test_supported_degam_tfs_has_bt2020_inv_oetf(struct kunit *test)
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF));
}
static void dm_test_supported_degam_tfs_has_gamma22_inv(struct kunit *test)
static void dm_test_supported_degam_tfs_has_gamma22(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_degam_tfs &
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV));
BIT(DRM_COLOROP_1D_CURVE_GAMMA22));
}
static void dm_test_supported_degam_tfs_no_extra_bits(struct kunit *test)
@ -41,7 +42,7 @@ static void dm_test_supported_degam_tfs_no_extra_bits(struct kunit *test)
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_degam_tfs, expected);
}
@ -66,10 +67,10 @@ static void dm_test_supported_shaper_tfs_has_bt2020_oetf(struct kunit *test)
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF));
}
static void dm_test_supported_shaper_tfs_has_gamma22(struct kunit *test)
static void dm_test_supported_shaper_tfs_has_gamma22_inv(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_shaper_tfs &
BIT(DRM_COLOROP_1D_CURVE_GAMMA22));
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV));
}
static void dm_test_supported_shaper_tfs_no_extra_bits(struct kunit *test)
@ -77,7 +78,7 @@ static void dm_test_supported_shaper_tfs_no_extra_bits(struct kunit *test)
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) |
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_shaper_tfs, expected);
}
@ -102,10 +103,10 @@ static void dm_test_supported_blnd_tfs_has_bt2020_inv_oetf(struct kunit *test)
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF));
}
static void dm_test_supported_blnd_tfs_has_gamma22_inv(struct kunit *test)
static void dm_test_supported_blnd_tfs_has_gamma22(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_blnd_tfs &
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV));
BIT(DRM_COLOROP_1D_CURVE_GAMMA22));
}
static void dm_test_supported_blnd_tfs_no_extra_bits(struct kunit *test)
@ -113,7 +114,7 @@ static void dm_test_supported_blnd_tfs_no_extra_bits(struct kunit *test)
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_blnd_tfs, expected);
}
@ -125,27 +126,104 @@ static void dm_test_degam_and_blnd_tfs_match(struct kunit *test)
amdgpu_dm_supported_blnd_tfs);
}
/* Tests for amdgpu_dm_initialize_default_pipeline */
static void kunit_colorop_pipeline_destroy(void *drm)
{
drm_colorop_pipeline_destroy((struct drm_device *)drm);
}
/**
* dm_test_initialize_default_pipeline() - Verify amdgpu_dm_build_default_pipeline()
* produces the expected colorop chain with all ops bypassable.
* @test: KUnit test context.
*/
static void dm_test_initialize_default_pipeline(struct kunit *test)
{
static const enum drm_colorop_type expected[] = {
DRM_COLOROP_1D_CURVE, /* degam TF */
DRM_COLOROP_MULTIPLIER,
DRM_COLOROP_CTM_3X4,
DRM_COLOROP_1D_CURVE, /* shaper TF */
DRM_COLOROP_1D_LUT, /* shaper LUT */
DRM_COLOROP_3D_LUT,
DRM_COLOROP_1D_CURVE, /* blnd TF */
DRM_COLOROP_1D_LUT, /* blnd LUT */
};
struct device *dev;
struct drm_device *drm;
struct drm_plane *plane;
struct drm_prop_enum_list list = {};
struct drm_colorop *op, *first = NULL;
int i = 0;
int ret;
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
/*
* Allocate a plain drm_device (not an amdgpu_device) sufficient
* because amdgpu_dm_build_default_pipeline() only needs the DRM
* mode-config infrastructure, not the amdgpu device wrapper.
*/
drm = __drm_kunit_helper_alloc_drm_device(test, dev,
sizeof(*drm), 0, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
plane = drm_kunit_helper_create_primary_plane(test, drm,
NULL, NULL, NULL, 0, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
/*
* Destroy the pipeline before the DRM device is cleaned up so
* that the colorop objects (kzalloc'd inside the function) are
* freed while the device is still valid.
*/
kunit_add_action(test, kunit_colorop_pipeline_destroy, drm);
ret = amdgpu_dm_build_default_pipeline(drm, plane, true, &list);
KUNIT_ASSERT_EQ(test, ret, 0);
kfree(list.name);
drm_for_each_colorop(op, drm) {
if (op->base.id == (uint32_t)list.type) {
first = op;
break;
}
}
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, first);
for (op = first; op; op = op->next, i++) {
KUNIT_ASSERT_LT(test, i, (int)ARRAY_SIZE(expected));
KUNIT_EXPECT_EQ(test, op->type, expected[i]);
KUNIT_EXPECT_NOT_NULL(test, op->bypass_property);
}
KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(expected));
}
static struct kunit_case dm_colorop_test_cases[] = {
/* degam TFs */
KUNIT_CASE(dm_test_supported_degam_tfs_has_srgb_eotf),
KUNIT_CASE(dm_test_supported_degam_tfs_has_pq125_eotf),
KUNIT_CASE(dm_test_supported_degam_tfs_has_bt2020_inv_oetf),
KUNIT_CASE(dm_test_supported_degam_tfs_has_gamma22_inv),
KUNIT_CASE(dm_test_supported_degam_tfs_has_gamma22),
KUNIT_CASE(dm_test_supported_degam_tfs_no_extra_bits),
/* shaper TFs */
KUNIT_CASE(dm_test_supported_shaper_tfs_has_srgb_inv_eotf),
KUNIT_CASE(dm_test_supported_shaper_tfs_has_pq125_inv_eotf),
KUNIT_CASE(dm_test_supported_shaper_tfs_has_bt2020_oetf),
KUNIT_CASE(dm_test_supported_shaper_tfs_has_gamma22),
KUNIT_CASE(dm_test_supported_shaper_tfs_has_gamma22_inv),
KUNIT_CASE(dm_test_supported_shaper_tfs_no_extra_bits),
/* blnd TFs */
KUNIT_CASE(dm_test_supported_blnd_tfs_has_srgb_eotf),
KUNIT_CASE(dm_test_supported_blnd_tfs_has_pq125_eotf),
KUNIT_CASE(dm_test_supported_blnd_tfs_has_bt2020_inv_oetf),
KUNIT_CASE(dm_test_supported_blnd_tfs_has_gamma22_inv),
KUNIT_CASE(dm_test_supported_blnd_tfs_has_gamma22),
KUNIT_CASE(dm_test_supported_blnd_tfs_no_extra_bits),
/* cross-check */
KUNIT_CASE(dm_test_degam_and_blnd_tfs_match),
/* amdgpu_dm_initialize_default_pipeline */
KUNIT_CASE(dm_test_initialize_default_pipeline),
{}
};

View File

@ -579,6 +579,288 @@ static void dm_test_ism_idle_delay_mixed_durations(struct kunit *test)
(uint64_t)0);
}
/**
* dm_test_ism_idle_delay_entry_count_exceeds_history_size - entry_count > history_size sets delay
* @test: KUnit test context
*/
static void dm_test_ism_idle_delay_entry_count_exceeds_history_size(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
struct dc_stream_state *stream = alloc_test_stream(test);
uint64_t one_frame_ns, expected;
/*
* filter_entry_count (5) > filter_history_size (3), so history_size
* is determined by filter_entry_count via max(). All 5 records are
* short idles, triggering the delay.
*/
stream->timing.v_total = 1125;
stream->timing.h_total = 2200;
stream->timing.pix_clk_100hz = 1485000;
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
1485000);
ism->config.filter_num_frames = 5;
ism->config.filter_entry_count = 5;
ism->config.filter_history_size = 3;
ism->config.activation_num_delay_frames = 10;
ism->config.filter_old_history_threshold = 0;
for (int i = 0; i < 5; i++) {
ism->records[i].duration_ns = one_frame_ns;
ism->records[i].timestamp_ns = 0;
}
ism->next_record_idx = 5;
expected = 10 * one_frame_ns;
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream), expected);
}
/* ===== Tests for amdgpu_dm_ism_init ===== */
/**
* dm_test_ism_init_sets_initial_state - all ISM fields initialized to expected values
* @test: KUnit test context
*/
static void dm_test_ism_init_sets_initial_state(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
struct amdgpu_dm_ism_config config = {
.filter_num_frames = 5,
.filter_entry_count = 3,
.activation_num_delay_frames = 10,
.filter_history_size = 8,
.filter_old_history_threshold = 20,
.sso_num_frames = 2,
};
amdgpu_dm_ism_init(ism, &config);
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 0);
KUNIT_EXPECT_EQ(test, ism->last_idle_timestamp_ns, (uint64_t)0);
KUNIT_EXPECT_EQ(test, ism->config.filter_num_frames,
config.filter_num_frames);
KUNIT_EXPECT_EQ(test, ism->config.filter_entry_count,
config.filter_entry_count);
KUNIT_EXPECT_EQ(test, ism->config.activation_num_delay_frames,
config.activation_num_delay_frames);
KUNIT_EXPECT_EQ(test, ism->config.sso_num_frames, config.sso_num_frames);
}
/* ===== Tests for amdgpu_dm_ism_fini ===== */
/**
* dm_test_ism_fini_after_init - fini cancels never-scheduled work without error
* @test: KUnit test context
*/
static void dm_test_ism_fini_after_init(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
struct amdgpu_dm_ism_config config = {
.filter_num_frames = 5,
.filter_entry_count = 3,
.activation_num_delay_frames = 10,
.sso_num_frames = 2,
};
amdgpu_dm_ism_init(ism, &config);
/* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
amdgpu_dm_ism_fini(ism);
/* FSM state is untouched by fini */
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
}
/* ===== Tests for dm_ism_set_last_idle_ts ===== */
/**
* dm_test_ism_set_last_idle_ts_updates_timestamp - last_idle_timestamp_ns updated to current time
* @test: KUnit test context
*/
static void dm_test_ism_set_last_idle_ts_updates_timestamp(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
uint64_t before;
ism->last_idle_timestamp_ns = 0;
before = ktime_get_ns();
dm_ism_set_last_idle_ts(ism);
KUNIT_EXPECT_GE(test, ism->last_idle_timestamp_ns, before);
}
/* ===== Tests for dm_ism_insert_record ===== */
/**
* dm_test_ism_insert_record_basic - record inserted with correct index and duration
* @test: KUnit test context
*/
static void dm_test_ism_insert_record_basic(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
ism->last_idle_timestamp_ns = 0;
ism->next_record_idx = 0;
dm_ism_insert_record(ism);
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 1);
KUNIT_EXPECT_GT(test, ism->records[0].timestamp_ns, (uint64_t)0);
/* duration = timestamp - last_idle_timestamp_ns (0) */
KUNIT_EXPECT_EQ(test, ism->records[0].duration_ns,
ism->records[0].timestamp_ns);
}
/**
* dm_test_ism_insert_record_wraps_around - out-of-bounds index wraps to slot 0
* @test: KUnit test context
*/
static void dm_test_ism_insert_record_wraps_around(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
ism->last_idle_timestamp_ns = 0;
/* Out-of-bounds index triggers reset to 0 */
ism->next_record_idx = AMDGPU_DM_IDLE_HIST_LEN;
dm_ism_insert_record(ism);
KUNIT_EXPECT_EQ(test, ism->next_record_idx, 1);
KUNIT_EXPECT_GT(test, ism->records[0].timestamp_ns, (uint64_t)0);
}
/* ===== Tests for dm_ism_trigger_event ===== */
/**
* dm_test_ism_trigger_event_valid_transition - valid event advances current and previous state
* @test: KUnit test context
*/
static void dm_test_ism_trigger_event_valid_transition(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
bool ok;
ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING;
ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING;
ok = dm_ism_trigger_event(ism, DM_ISM_EVENT_ENTER_IDLE_REQUESTED);
KUNIT_EXPECT_TRUE(test, ok);
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
(int)DM_ISM_STATE_HYSTERESIS_WAITING);
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
}
/**
* dm_test_ism_trigger_event_invalid_transition - invalid event leaves state unchanged
* @test: KUnit test context
*/
static void dm_test_ism_trigger_event_invalid_transition(struct kunit *test)
{
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
bool ok;
ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING;
ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING;
/* EXIT_IDLE_REQUESTED is not valid from FULL_POWER_RUNNING */
ok = dm_ism_trigger_event(ism, DM_ISM_EVENT_EXIT_IDLE_REQUESTED);
KUNIT_EXPECT_FALSE(test, ok);
/* State must remain unchanged on invalid transition */
KUNIT_EXPECT_EQ(test, (int)ism->current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
KUNIT_EXPECT_EQ(test, (int)ism->previous_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
}
/* ===== Tests for dm_ism_dispatch_next_event ===== */
/**
* dm_test_dispatch_next_event_hyst_wait_no_delay - zero delay_ns: IMMEDIATE in HYSTERESIS_WAITING
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_hyst_wait_no_delay(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_HYSTERESIS_WAITING,
0, 0);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_EVENT_IMMEDIATE);
}
/**
* dm_test_dispatch_next_event_hyst_wait_with_delay - delay_ns > 0, no IMMEDIATE event returned
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_hyst_wait_with_delay(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_HYSTERESIS_WAITING,
1000000, 0);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_NUM_EVENTS);
}
/**
* dm_test_dispatch_next_event_opt_idle_no_sso_delay - sso_delay_ns == 0 triggers IMMEDIATE event
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_opt_idle_no_sso_delay(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_OPTIMIZED_IDLE,
0, 0);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_EVENT_IMMEDIATE);
}
/**
* dm_test_dispatch_next_event_opt_idle_with_sso_delay - sso_delay_ns > 0, SSO timer, no IMMEDIATE
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_opt_idle_with_sso_delay(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_OPTIMIZED_IDLE,
0, 1000000);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_NUM_EVENTS);
}
/**
* dm_test_dispatch_next_event_timer_aborted - TIMER_ABORTED always returns IMMEDIATE
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_timer_aborted(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_TIMER_ABORTED,
0, 0);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_EVENT_IMMEDIATE);
}
/**
* dm_test_dispatch_next_event_no_action_state - other states return DM_ISM_NUM_EVENTS
* @test: KUnit test context
*/
static void dm_test_dispatch_next_event_no_action_state(struct kunit *test)
{
enum amdgpu_dm_ism_event result;
result = dm_ism_dispatch_next_event(DM_ISM_STATE_FULL_POWER_RUNNING,
0, 0);
KUNIT_EXPECT_EQ(test, (int)result, (int)DM_ISM_NUM_EVENTS);
}
static struct kunit_case dm_ism_test_cases[] = {
/* dm_ism_next_state — FULL_POWER_RUNNING */
KUNIT_CASE(dm_test_ism_next_state_running_enter_idle),
@ -621,6 +903,26 @@ static struct kunit_case dm_ism_test_cases[] = {
KUNIT_CASE(dm_test_ism_idle_delay_wraps_around_buffer),
KUNIT_CASE(dm_test_ism_idle_delay_old_history_cutoff),
KUNIT_CASE(dm_test_ism_idle_delay_mixed_durations),
KUNIT_CASE(dm_test_ism_idle_delay_entry_count_exceeds_history_size),
/* amdgpu_dm_ism_init */
KUNIT_CASE(dm_test_ism_init_sets_initial_state),
/* amdgpu_dm_ism_fini */
KUNIT_CASE(dm_test_ism_fini_after_init),
/* dm_ism_set_last_idle_ts */
KUNIT_CASE(dm_test_ism_set_last_idle_ts_updates_timestamp),
/* dm_ism_insert_record */
KUNIT_CASE(dm_test_ism_insert_record_basic),
KUNIT_CASE(dm_test_ism_insert_record_wraps_around),
/* dm_ism_trigger_event */
KUNIT_CASE(dm_test_ism_trigger_event_valid_transition),
KUNIT_CASE(dm_test_ism_trigger_event_invalid_transition),
/* dm_ism_dispatch_next_event */
KUNIT_CASE(dm_test_dispatch_next_event_hyst_wait_no_delay),
KUNIT_CASE(dm_test_dispatch_next_event_hyst_wait_with_delay),
KUNIT_CASE(dm_test_dispatch_next_event_opt_idle_no_sso_delay),
KUNIT_CASE(dm_test_dispatch_next_event_opt_idle_with_sso_delay),
KUNIT_CASE(dm_test_dispatch_next_event_timer_aborted),
KUNIT_CASE(dm_test_dispatch_next_event_no_action_state),
{}
};

View File

@ -7,11 +7,7 @@
#include <kunit/test.h>
#include "dc.h"
/* Extern declaration for the function under test */
extern void amdgpu_dm_psr_fill_caps(struct dc_link *link,
struct psr_caps *caps);
#include "amdgpu_dm_psr.h"
/*
* Helper: allocate and zero-initialise a dc_link sufficient for
@ -227,6 +223,43 @@ static void dm_test_psr_fill_caps_power_opts_z10_always_set(struct kunit *test)
}
/* End of tests for amdgpu_dm_psr_fill_caps() */
/* Tests for amdgpu_dm_psr_set_event() — early-exit validation guards */
static void dm_test_psr_set_event_null_stream(struct kunit *test)
{
/* NULL stream → immediate false, dm is not accessed */
KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_set_event(NULL, NULL, true, psr_event_vsync, false));
}
static void dm_test_psr_set_event_null_link(struct kunit *test)
{
struct dc_stream_state *stream;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, stream);
/* stream->link remains NULL from kzalloc */
KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_set_event(NULL, stream, true, psr_event_vsync, false));
}
static void dm_test_psr_set_event_psr_not_enabled(struct kunit *test)
{
struct dc_stream_state *stream;
struct dc_link *link;
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, stream);
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, link);
stream->link = link;
/* link->psr_settings.psr_feature_enabled remains false from kzalloc */
KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_set_event(NULL, stream, true, psr_event_vsync, false));
}
/* End of tests for amdgpu_dm_psr_set_event() */
static struct kunit_case dm_psr_test_cases[] = {
KUNIT_CASE(dm_test_psr_fill_caps_version_1),
KUNIT_CASE(dm_test_psr_fill_caps_version_su1),
@ -240,6 +273,9 @@ static struct kunit_case dm_psr_test_cases[] = {
KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields_unset),
KUNIT_CASE(dm_test_psr_fill_caps_rate_control_always_zero),
KUNIT_CASE(dm_test_psr_fill_caps_power_opts_z10_always_set),
KUNIT_CASE(dm_test_psr_set_event_null_stream),
KUNIT_CASE(dm_test_psr_set_event_null_link),
KUNIT_CASE(dm_test_psr_set_event_psr_not_enabled),
{}
};

View File

@ -289,8 +289,8 @@ bool dal_vector_reserve(struct vector *vector, uint32_t capacity)
if (capacity <= vector->capacity)
return true;
new_container = krealloc(vector->container,
capacity * vector->struct_size, GFP_KERNEL);
new_container = krealloc_array(vector->container,
capacity, vector->struct_size, GFP_KERNEL);
if (new_container) {
vector->container = new_container;

View File

@ -222,6 +222,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
ATOM_COMMON_RECORD_HEADER *header;
ATOM_I2C_RECORD *record;
struct bios_parser *bp = BP_FROM_DCB(dcb);
int i;
if (!info)
return BP_RESULT_BADINPUT;
@ -234,7 +235,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@ -293,11 +294,12 @@ static enum bp_result bios_parser_get_device_tag_record(
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
int i;
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@ -966,6 +968,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -975,7 +978,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@ -1670,6 +1673,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -1679,7 +1683,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@ -2733,6 +2737,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
{
(void)i;
unsigned int j;
unsigned int n;
struct bios_parser *bp;
ATOM_BRACKET_LAYOUT_RECORD *record;
ATOM_COMMON_RECORD_HEADER *record_header;
@ -2742,7 +2747,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
record = NULL;
record_header = NULL;
for (;;) {
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
if (record_header == NULL) {

View File

@ -396,6 +396,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
struct atom_i2c_record *record;
struct atom_i2c_record dummy_record = {0};
struct bios_parser *bp = BP_FROM_DCB(dcb);
int i;
if (!info)
return BP_RESULT_BADINPUT;
@ -429,7 +430,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
break;
}
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -534,6 +535,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -542,7 +544,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -611,6 +613,7 @@ static struct atom_hpd_int_record *get_hpd_record(
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -620,7 +623,7 @@ static struct atom_hpd_int_record *get_hpd_record(
offset = le16_to_cpu(object->disp_recordoffset)
+ bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -701,8 +704,10 @@ static enum bp_result bios_parser_get_gpio_pin_info(
info->offset_en = info->offset + 1;
info->offset_mask = info->offset - 1;
info->mask = (uint32_t) (1 <<
header->gpio_pin[i].gpio_bitshift);
if (header->gpio_pin[i].gpio_bitshift >= 32)
return BP_RESULT_BADBIOSTABLE;
info->mask = 1u << header->gpio_pin[i].gpio_bitshift;
info->mask_y = info->mask + 2;
info->mask_en = info->mask + 1;
info->mask_mask = info->mask - 1;
@ -713,6 +718,69 @@ static enum bp_result bios_parser_get_gpio_pin_info(
return BP_RESULT_NORECORD;
}
static enum bp_result bios_parser_get_connector_aux_info(struct dc_bios *dcb,
struct graphics_object_id id,
struct graphics_object_i2c_info *info)
{
uint32_t offset;
struct atom_display_object_path_v2 *object;
struct atom_display_object_path_v3 *object_path_v3;
struct atom_common_record_header *header;
struct atom_i2c_record *record;
struct bios_parser *bp = BP_FROM_DCB(dcb);
if (!info)
return BP_RESULT_BADINPUT;
switch (bp->object_info_tbl.revision.minor) {
case 4:
default:
object = get_bios_object(bp, id);
if (!object)
return BP_RESULT_BADINPUT;
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
break;
case 5:
object_path_v3 = get_bios_object_from_path_v3(bp, id);
if (!object_path_v3)
return BP_RESULT_BADINPUT;
offset = object_path_v3->disp_recordoffset + bp->object_info_tbl_offset;
break;
}
for (;;) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
return BP_RESULT_BADBIOSTABLE;
if (header->record_type == LAST_RECORD_TYPE ||
!header->record_size)
break;
if (header->record_type == ATOM_I2C_RECORD_TYPE
&& sizeof(struct atom_i2c_record) <=
header->record_size) {
/* get_connector_aux_info - which aux instance is used it is based
* on record->i2c_id field only, does not need GPIO DDC
*/
record = (struct atom_i2c_record *)header;
info->i2c_line = record->i2c_id & I2C_HW_LANE_MUX;
return BP_RESULT_OK;
}
offset += header->record_size;
}
return BP_RESULT_NORECORD;
}
static struct device_id device_type_from_device_id(uint16_t device_id)
{
@ -2135,6 +2203,12 @@ static enum bp_result get_firmware_info_v3_5(
return BP_RESULT_OK;
}
/* TODO: Remove this temp define after atomfirmware.h is updated */
#define ATOM_ENCODER_CAP_RECORD_HDMI_FRL_TEMP 0x200
#define ATOM_ENCODER_CAP_RECORD_HDMI_FRL_8GbEn_TEMP 0x400 // HDMI FRL 8Gb support
#define ATOM_ENCODER_CAP_RECORD_HDMI_FRL_10GbEn_TEMP 0x800 // HDMI FRL 10Gb support
#define ATOM_ENCODER_CAP_RECORD_HDMI_FRL_12GbEn_TEMP 0x1000 // HDMI FRL 12Gb support
static enum bp_result bios_parser_get_encoder_cap_info(
struct dc_bios *dcb,
struct graphics_object_id object_id,
@ -2182,6 +2256,15 @@ static enum bp_result bios_parser_get_encoder_cap_info(
info->DP_IS_USB_C = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_USB_C_TYPE) ? 1 : 0;
DC_LOG_BIOS("\t info->DP_IS_USB_C %d", info->DP_IS_USB_C);
info->IS_HDMI_FRL_CAPABLE = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI_FRL_TEMP) ? 1 : 0;
info->FRL_8G_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI_FRL_8GbEn_TEMP) ? 1 : 0;
info->FRL_10G_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI_FRL_10GbEn_TEMP) ? 1 : 0;
info->FRL_12G_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI_FRL_12GbEn_TEMP) ? 1 : 0;
DC_LOG_BIOS("\t info->IS_HDMI_FRL_CAPABLE %d\n", info->IS_HDMI_FRL_CAPABLE);
return BP_RESULT_OK;
}
@ -2193,6 +2276,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -2201,7 +2285,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
offset = object->encoder_recordoffset + bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -2230,6 +2314,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -2238,7 +2323,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -2266,6 +2351,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -2274,7 +2360,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -2341,6 +2427,9 @@ static enum bp_result bios_parser_get_disp_connector_caps_info(
? 1 : 0;
info->INTERNAL_DISPLAY_BL = (record_path_v3->connector_caps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL)
? 1 : 0;
// All aux transactions for this connector should rely only on aux instance, not on ddc instance
info->NO_DDC_PIN = (record_path_v3->connector_caps & ATOM_CONNECTOR_CAP_DP_PLUS_PLUS_TYPE2_ONLY) ? 1 : 0;
break;
}
@ -2352,6 +2441,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
{
struct atom_common_record_header *header;
uint32_t offset;
int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@ -2360,7 +2450,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
for (;;) {
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@ -2410,6 +2500,12 @@ static enum bp_result bios_parser_get_connector_speed_cap_info(
info->DP_UHBR10_EN = (record->connector_max_speed >= 10000) ? 1 : 0;
info->DP_UHBR13_5_EN = (record->connector_max_speed >= 13500) ? 1 : 0;
info->DP_UHBR20_EN = (record->connector_max_speed >= 20000) ? 1 : 0;
info->FRL_8G_EN = (record->connector_max_speed >= 8000) ? 1 : 0;
info->FRL_10G_EN = (record->connector_max_speed >= 10000) ? 1 : 0;
info->FRL_12G_EN = (record->connector_max_speed >= 12000) ? 1 : 0;
info->FRL_16G_EN = (record->connector_max_speed >= 16000) ? 1 : 0;
info->FRL_20G_EN = (record->connector_max_speed >= 20000) ? 1 : 0;
info->FRL_24G_EN = (record->connector_max_speed >= 24000) ? 1 : 0;
return BP_RESULT_OK;
}
@ -2600,14 +2696,16 @@ static enum bp_result get_integrated_info_v11(
info_v11->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v11->dp0_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp0_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2616,14 +2714,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v11->dp1_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp1_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2632,14 +2732,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v11->dp2_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp2_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2648,14 +2750,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v11->dp3_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp3_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2796,14 +2900,16 @@ static enum bp_result get_integrated_info_v2_1(
info->ext_disp_conn_info.checksum =
info_v2_1->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr;
info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum;
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum;
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2811,14 +2917,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr;
info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum;
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum;
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2826,14 +2934,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr;
info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum;
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum;
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2841,14 +2951,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr;
info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum;
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum;
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -3228,6 +3340,7 @@ static enum bp_result update_slot_layout_info(
{
unsigned int record_offset;
unsigned int j;
unsigned int n;
struct atom_display_object_path_v2 *object;
struct atom_bracket_layout_record *record;
struct atom_common_record_header *record_header;
@ -3249,7 +3362,7 @@ static enum bp_result update_slot_layout_info(
(object->disp_recordoffset) +
(unsigned int)(bp->object_info_tbl_offset);
for (;;) {
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = (struct atom_common_record_header *)
GET_IMAGE(struct atom_common_record_header,
@ -3343,6 +3456,7 @@ static enum bp_result update_slot_layout_info_v2(
struct slot_layout_info *slot_layout_info)
{
unsigned int record_offset;
unsigned int n;
struct atom_display_object_path_v3 *object;
struct atom_bracket_layout_record_v2 *record;
struct atom_common_record_header *record_header;
@ -3365,7 +3479,7 @@ static enum bp_result update_slot_layout_info_v2(
(object->disp_recordoffset) +
(unsigned int)(bp->object_info_tbl_offset);
for (;;) {
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = (struct atom_common_record_header *)
GET_IMAGE(struct atom_common_record_header,
@ -3690,6 +3804,7 @@ static const struct dc_vbios_funcs vbios_funcs = {
.get_lttpr_interop = bios_parser_get_lttpr_interop,
.get_connector_speed_cap_info = bios_parser_get_connector_speed_cap_info,
.get_connector_aux_info = bios_parser_get_connector_aux_info,
};
static bool bios_parser2_construct(

View File

@ -37,4 +37,9 @@ void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
/* Upper bound on the number of records in a VBIOS record chain. Prevents
* unbounded looping if the VBIOS image is malformed and lacks a terminator.
*/
#define BIOS_MAX_NUM_RECORD 256
#endif

View File

@ -371,6 +371,10 @@ static enum bp_result transmitter_control_v1_7(
if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||
cntl->action == TRANSMITTER_CONTROL_ACTIAVATE ||
cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) {
if (dc_is_hdmi_frl_signal(cntl->signal))
DC_LOG_BIOS("%s:dig_v1_7.symclk_units.symclk_Hz = %d\n",
__func__, dig_v1_7.symclk_units.symclk_Hz);
else
DC_LOG_BIOS("%s:dig_v1_7.symclk_units.symclk_10khz = %d\n",
__func__, dig_v1_7.symclk_units.symclk_10khz);
}
@ -395,6 +399,8 @@ static enum bp_result transmitter_control_v1_7(
process_phy_transition_init_params.sym_clock_10khz = dig_v1_7.symclk_units.symclk_10khz;
process_phy_transition_init_params.display_port_link_rate = link->cur_link_settings.link_rate;
process_phy_transition_init_params.transition_bitmask = link->phy_transition_bitmask;
process_phy_transition_init_params.hdmi_frl_num_lanes = link->frl_link_settings.frl_num_lanes;
process_phy_transition_init_params.hdmi_frl_link_rate = link->frl_link_settings.frl_link_rate;
}
dig_v1_7.skip_phy_ssc_reduction = link->wa_flags.skip_phy_ssc_reduction;
}

View File

@ -85,6 +85,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
case DCN_VERSION_3_6:
case DCN_VERSION_4_01:
case DCN_VERSION_4_2:
case DCN_VERSION_4_2B:
*h = dal_cmd_tbl_helper_dce112_get_table2();
return true;

View File

@ -49,6 +49,9 @@ static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
case SIGNAL_TYPE_HDMI_TYPE_A:
atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI;
break;
case SIGNAL_TYPE_HDMI_FRL:
atom_dig_mode = 4;
break;
case SIGNAL_TYPE_DISPLAY_PORT_MST:
atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST;
break;

View File

@ -47,6 +47,9 @@ static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
case SIGNAL_TYPE_HDMI_TYPE_A:
atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI;
break;
case SIGNAL_TYPE_HDMI_FRL:
atom_dig_mode = 4;
break;
case SIGNAL_TYPE_DISPLAY_PORT_MST:
atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST;
break;

View File

@ -185,4 +185,14 @@ CLK_MGR_DCN42 = dcn42_smu.o dcn42_clk_mgr.o
AMD_DAL_CLK_MGR_DCN42 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn42/,$(CLK_MGR_DCN42))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN42)
###############################################################################
# DCN42B
###############################################################################
CLK_MGR_DCN42B = dcn42b_clk_mgr.o
AMD_DAL_CLK_MGR_DCN42B = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn42b/,$(CLK_MGR_DCN42B))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN42B)
endif

View File

@ -49,6 +49,7 @@
#include "dcn35/dcn35_clk_mgr.h"
#include "dcn401/dcn401_clk_mgr.h"
#include "dcn42/dcn42_clk_mgr.h"
#include "dcn42b/dcn42b_clk_mgr.h"
int clk_mgr_helper_get_active_display_cnt(
struct dc *dc,
@ -338,6 +339,16 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
break;
case AMDGPU_FAMILY_GC_11_5_0: {
if (ctx->dce_version == DCN_VERSION_4_2B) {
struct clk_mgr_dcn42 *clk_mgr = kzalloc_obj(*clk_mgr);
if (clk_mgr == NULL) {
BREAK_TO_DEBUGGER();
return NULL;
}
dcn42b_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base.base;
}
struct clk_mgr_dcn35 *clk_mgr = kzalloc_obj(*clk_mgr);
if (clk_mgr == NULL) {
@ -428,6 +439,10 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
break;
case AMDGPU_FAMILY_GC_11_5_0:
if (clk_mgr_base->ctx->dce_version == DCN_VERSION_4_2B) {
dcn42_clk_mgr_destroy(clk_mgr);
break;
}
dcn35_clk_mgr_destroy(clk_mgr);
break;
case AMDGPU_FAMILY_GC_12_0_0:

View File

@ -93,6 +93,9 @@ static int dcn31_get_active_display_cnt_wa(
if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
display_count++;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}
for (i = 0; i < dc->link_count; i++) {

View File

@ -127,6 +127,9 @@ static int dcn314_get_active_display_cnt_wa(
if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
display_count++;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}
for (i = 0; i < dc->link_count; i++) {

View File

@ -69,6 +69,9 @@ static int dcn315_get_active_display_cnt_wa(
stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
tmds_present = true;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}
for (i = 0; i < dc->link_count; i++) {

View File

@ -81,6 +81,9 @@ static int dcn316_get_active_display_cnt_wa(
stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
tmds_present = true;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}
for (i = 0; i < dc->link_count; i++) {

View File

@ -283,6 +283,18 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
if (pipe_ctx->stream_res.audio != NULL)
dto_params.req_audio_dtbclk_khz = 24000;
}
if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
dc_is_dvi_signal(pipe_ctx->stream->signal))
dto_params.is_hdmi = true;
dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
}

Some files were not shown because too many files have changed in this diff Show More