amd-drm-next-7.1-2026-03-12:

amdgpu:
 - SMU13 fix
 - SMU14 fix
 - Fixes for bring up hw testing
 - Kerneldoc fix
 - GC12 idle power fix for compute workloads
 - DCCG fixes
 - UserQ fixes
 - Move test for fbdev object to a generic helper
 - GC 12.1 updates
 - Use struct drm_edid in non-DC code
 - Include IP discovery data in devcoredump
 - SMU 13.x updates
 - Misc cleanups
 - DML 2.1 fixes
 - Enable NV12/P010 support on primary planes
 - Enable color encoding and color range on overlay planes
 - DC underflow fixes
 - HWSS fast path fixes
 - Replay fixes
 - DCN 4.2 updates
 - Support newer IP discovery tables
 - LSDMA 7.1 support
 - IH 7.1 fixes
 - SoC v1 updates
 - GC12.1 updates
 - PSP 15 updates
 - XGMI fixes
 - GPUVM locking fix
 
 amdkfd:
 - Fix missing BO unreserve in an error path
 
 radeon:
 - Move test for fbdev object to a generic helper
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCabMItwAKCRC93/aFa7yZ
 2BiwAQD3yQsA6xuspaMXduQwFE0tu6rL6bB+NSB7bfM2YYdE1AEAqi2GQPOlfohH
 DK/zb58ZPoeJfCdShPPQ85cSkPSu2wY=
 =OtzL
 -----END PGP SIGNATURE-----

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

amd-drm-next-7.1-2026-03-12:

amdgpu:
- SMU13 fix
- SMU14 fix
- Fixes for bring up hw testing
- Kerneldoc fix
- GC12 idle power fix for compute workloads
- DCCG fixes
- UserQ fixes
- Move test for fbdev object to a generic helper
- GC 12.1 updates
- Use struct drm_edid in non-DC code
- Include IP discovery data in devcoredump
- SMU 13.x updates
- Misc cleanups
- DML 2.1 fixes
- Enable NV12/P010 support on primary planes
- Enable color encoding and color range on overlay planes
- DC underflow fixes
- HWSS fast path fixes
- Replay fixes
- DCN 4.2 updates
- Support newer IP discovery tables
- LSDMA 7.1 support
- IH 7.1 fixes
- SoC v1 updates
- GC12.1 updates
- PSP 15 updates
- XGMI fixes
- GPUVM locking fix

amdkfd:
- Fix missing BO unreserve in an error path

radeon:
- Move test for fbdev object to a generic helper

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260312184425.3875669-1-alexander.deucher@amd.com
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Dave Airlie 2026-03-16 16:50:47 +10:00
commit 02e778f123
163 changed files with 3824 additions and 2528 deletions

View File

@ -86,7 +86,7 @@ amdgpu-y += \
nbio_v7_2.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o soc21.o soc24.o \
sienna_cichlid.o smu_v13_0_10.o nbio_v4_3.o hdp_v6_0.o nbio_v7_7.o hdp_v5_2.o lsdma_v6_0.o \
nbio_v7_9.o aqua_vanjaram.o nbio_v7_11.o lsdma_v7_0.o hdp_v7_0.o nbif_v6_3_1.o \
cyan_skillfish_reg_init.o soc_v1_0.o
cyan_skillfish_reg_init.o soc_v1_0.o lsdma_v7_1.o
# add DF block
amdgpu-y += \

View File

@ -246,10 +246,10 @@ amdgpu_connector_find_encoder(struct drm_connector *connector,
return NULL;
}
static struct edid *
static const struct drm_edid *
amdgpu_connector_get_hardcoded_edid(struct amdgpu_device *adev)
{
return drm_edid_duplicate(drm_edid_raw(adev->mode_info.bios_hardcoded_edid));
return drm_edid_dup(adev->mode_info.bios_hardcoded_edid);
}
static void amdgpu_connector_get_edid(struct drm_connector *connector)
@ -268,8 +268,8 @@ static void amdgpu_connector_get_edid(struct drm_connector *connector)
if ((amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
ENCODER_OBJECT_ID_NONE) &&
amdgpu_connector->ddc_bus->has_aux) {
amdgpu_connector->edid = drm_get_edid(connector,
&amdgpu_connector->ddc_bus->aux.ddc);
amdgpu_connector->edid = drm_edid_read_ddc(connector,
&amdgpu_connector->ddc_bus->aux.ddc);
} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
(connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
@ -277,14 +277,14 @@ static void amdgpu_connector_get_edid(struct drm_connector *connector)
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
amdgpu_connector->ddc_bus->has_aux)
amdgpu_connector->edid = drm_get_edid(connector,
&amdgpu_connector->ddc_bus->aux.ddc);
amdgpu_connector->edid = drm_edid_read_ddc(connector,
&amdgpu_connector->ddc_bus->aux.ddc);
else if (amdgpu_connector->ddc_bus)
amdgpu_connector->edid = drm_get_edid(connector,
&amdgpu_connector->ddc_bus->adapter);
amdgpu_connector->edid = drm_edid_read_ddc(connector,
&amdgpu_connector->ddc_bus->adapter);
} else if (amdgpu_connector->ddc_bus) {
amdgpu_connector->edid = drm_get_edid(connector,
&amdgpu_connector->ddc_bus->adapter);
amdgpu_connector->edid = drm_edid_read_ddc(connector,
&amdgpu_connector->ddc_bus->adapter);
}
if (!amdgpu_connector->edid) {
@ -292,30 +292,22 @@ static void amdgpu_connector_get_edid(struct drm_connector *connector)
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
(connector->connector_type == DRM_MODE_CONNECTOR_eDP))) {
amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev);
drm_connector_update_edid_property(connector, amdgpu_connector->edid);
drm_edid_connector_update(connector, amdgpu_connector->edid);
}
}
}
static void amdgpu_connector_free_edid(struct drm_connector *connector)
{
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
kfree(amdgpu_connector->edid);
amdgpu_connector->edid = NULL;
}
static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector)
{
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
int ret;
if (amdgpu_connector->edid) {
drm_connector_update_edid_property(connector, amdgpu_connector->edid);
ret = drm_add_edid_modes(connector, amdgpu_connector->edid);
drm_edid_connector_update(connector, amdgpu_connector->edid);
ret = drm_edid_connector_add_modes(connector);
return ret;
}
drm_connector_update_edid_property(connector, NULL);
drm_edid_connector_update(connector, NULL);
return 0;
}
@ -754,7 +746,7 @@ static void amdgpu_connector_destroy(struct drm_connector *connector)
{
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
kfree(amdgpu_connector->con_priv);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
@ -873,7 +865,7 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
dret = amdgpu_display_ddc_probe(amdgpu_connector, false);
if (dret) {
amdgpu_connector->detected_by_load = false;
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
amdgpu_connector_get_edid(connector);
if (!amdgpu_connector->edid) {
@ -883,13 +875,13 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
ret = connector_status_connected;
} else {
amdgpu_connector->use_digital =
!!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
drm_edid_is_digital(amdgpu_connector->edid);
/* some oems have boards with separate digital and analog connectors
* with a shared ddc line (often vga + hdmi)
*/
if (amdgpu_connector->use_digital && amdgpu_connector->shared_ddc) {
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
ret = connector_status_disconnected;
} else {
ret = connector_status_connected;
@ -984,7 +976,7 @@ static void amdgpu_connector_shared_ddc(enum drm_connector_status *status,
/* hpd is our only option in this case */
if (!amdgpu_display_hpd_sense(adev,
amdgpu_connector->hpd.hpd)) {
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
*status = connector_status_disconnected;
}
}
@ -1053,7 +1045,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
}
if (dret) {
amdgpu_connector->detected_by_load = false;
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
amdgpu_connector_get_edid(connector);
if (!amdgpu_connector->edid) {
@ -1063,13 +1055,13 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
broken_edid = true; /* defer use_digital to later */
} else {
amdgpu_connector->use_digital =
!!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
drm_edid_is_digital(amdgpu_connector->edid);
/* some oems have boards with separate digital and analog connectors
* with a shared ddc line (often vga + hdmi)
*/
if ((!amdgpu_connector->use_digital) && amdgpu_connector->shared_ddc) {
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
ret = connector_status_disconnected;
} else {
ret = connector_status_connected;
@ -1417,7 +1409,7 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
goto out;
}
amdgpu_connector_free_edid(connector);
drm_edid_free(amdgpu_connector->edid);
if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
(connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {

View File

@ -39,6 +39,7 @@
#include "amdgpu_reset.h"
#include "amdgpu_psp_ta.h"
#include "amdgpu_userq.h"
#if defined(CONFIG_DEBUG_FS)
@ -2156,6 +2157,53 @@ static const struct file_operations amdgpu_pt_info_fops = {
.release = single_release,
};
static int amdgpu_mqd_info_read(struct seq_file *m, void *unused)
{
struct amdgpu_usermode_queue *queue = m->private;
struct amdgpu_bo *bo;
int r;
if (!queue || !queue->mqd.obj)
return -EINVAL;
bo = amdgpu_bo_ref(queue->mqd.obj);
r = amdgpu_bo_reserve(bo, true);
if (r) {
amdgpu_bo_unref(&bo);
return -EINVAL;
}
seq_printf(m, "queue_type: %d\n", queue->queue_type);
seq_printf(m, "mqd_gpu_address: 0x%llx\n", amdgpu_bo_gpu_offset(queue->mqd.obj));
amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo);
return 0;
}
static int amdgpu_mqd_info_open(struct inode *inode, struct file *file)
{
return single_open(file, amdgpu_mqd_info_read, inode->i_private);
}
static const struct file_operations amdgpu_mqd_info_fops = {
.owner = THIS_MODULE,
.open = amdgpu_mqd_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void amdgpu_debugfs_userq_init(struct drm_file *file, struct amdgpu_usermode_queue *queue, int qid)
{
char queue_name[32];
scnprintf(queue_name, sizeof(queue_name), "queue_%d", qid);
queue->debugfs_queue = debugfs_create_dir(queue_name, file->debugfs_client);
debugfs_create_file("mqd_info", 0444, queue->debugfs_queue, queue, &amdgpu_mqd_info_fops);
}
void amdgpu_debugfs_vm_init(struct drm_file *file)
{
debugfs_create_file("vm_pagetable_info", 0444, file->debugfs_client, file,
@ -2174,4 +2222,9 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
void amdgpu_debugfs_vm_init(struct drm_file *file)
{
}
void amdgpu_debugfs_userq_init(struct drm_file *file,
struct amdgpu_usermode_queue *queue,
int qid)
{
}
#endif

View File

@ -25,6 +25,7 @@
/*
* Debugfs
*/
struct amdgpu_usermode_queue;
int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
int amdgpu_debugfs_init(struct amdgpu_device *adev);
@ -34,4 +35,7 @@ void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
void amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev);
void amdgpu_debugfs_vm_init(struct drm_file *file);
void amdgpu_debugfs_userq_init(struct drm_file *file,
struct amdgpu_usermode_queue *queue,
int qid);

View File

@ -261,6 +261,8 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
}
}
amdgpu_discovery_dump(coredump->adev, &p);
/* IP firmware information */
drm_printf(&p, "\nIP Firmwares\n");
amdgpu_devcoredump_fw_info(coredump->adev, &p);

View File

@ -1995,8 +1995,10 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
break;
default:
r = amdgpu_discovery_set_ip_blocks(adev);
if (r)
if (r) {
adev->num_ip_blocks = 0;
return r;
}
break;
}
@ -2550,6 +2552,8 @@ int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
if (!adev->ip_blocks[i].version)
continue;
/* skip CG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
@ -2589,6 +2593,8 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
if (!adev->ip_blocks[i].version)
continue;
/* skip PG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
@ -2796,6 +2802,8 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].version)
continue;
if (!adev->ip_blocks[i].version->funcs->early_fini)
continue;
@ -2873,6 +2881,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
if (!adev->ip_blocks[i].status.sw)
continue;
if (!adev->ip_blocks[i].version)
continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
amdgpu_ucode_free_bo(adev);
amdgpu_free_static_csa(&adev->virt.csa_obj);
@ -2899,6 +2909,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_blocks[i].status.late_initialized)
continue;
if (!adev->ip_blocks[i].version)
continue;
if (adev->ip_blocks[i].version->funcs->late_fini)
adev->ip_blocks[i].version->funcs->late_fini(&adev->ip_blocks[i]);
adev->ip_blocks[i].status.late_initialized = false;

View File

@ -87,6 +87,7 @@
#include "sdma_v7_1.h"
#include "lsdma_v6_0.h"
#include "lsdma_v7_0.h"
#include "lsdma_v7_1.h"
#include "vcn_v2_0.h"
#include "jpeg_v2_0.h"
#include "vcn_v3_0.h"
@ -132,6 +133,7 @@ MODULE_FIRMWARE("amdgpu/picasso_ip_discovery.bin");
MODULE_FIRMWARE("amdgpu/arcturus_ip_discovery.bin");
MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin");
/* Note: These registers are consistent across all the SOCs */
#define mmIP_DISCOVERY_VERSION 0x16A00
#define mmRCC_CONFIG_MEMSIZE 0xde3
#define mmMP0_SMN_C2PMSG_33 0x16061
@ -139,6 +141,10 @@ MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin");
#define mmMM_INDEX_HI 0x6
#define mmMM_DATA 0x1
#define mmDRIVER_SCRATCH_0 0x94
#define mmDRIVER_SCRATCH_1 0x95
#define mmDRIVER_SCRATCH_2 0x96
static const char *hw_id_names[HW_ID_MAX] = {
[MP1_HWID] = "MP1",
[MP2_HWID] = "MP2",
@ -253,39 +259,12 @@ static int hw_id_map[MAX_HWIP] = {
[ATU_HWIP] = ATU_HWID,
};
static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, uint8_t *binary)
static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev,
bool *is_tmr_in_sysmem)
{
u64 tmr_offset, tmr_size, pos;
void *discv_regn;
int ret;
ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size);
if (ret)
return ret;
pos = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET;
/* This region is read-only and reserved from system use */
discv_regn = memremap(pos, adev->discovery.size, MEMREMAP_WC);
if (discv_regn) {
memcpy(binary, discv_regn, adev->discovery.size);
memunmap(discv_regn);
return 0;
}
return -ENOENT;
}
#define IP_DISCOVERY_V2 2
#define IP_DISCOVERY_V4 4
static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
uint8_t *binary)
{
bool sz_valid = true;
uint64_t vram_size;
int i, ret = 0;
u32 msg;
u64 vram_size, tmr_offset, tmr_size;
u32 msg, tmr_offset_lo, tmr_offset_hi;
int i, ret;
if (!amdgpu_sriov_vf(adev)) {
/* It can take up to two second for IFWI init to complete on some dGPUs,
@ -305,51 +284,98 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
}
vram_size = RREG32(mmRCC_CONFIG_MEMSIZE);
if (!vram_size || vram_size == U32_MAX)
sz_valid = false;
if (vram_size == U32_MAX)
return -ENXIO;
else if (!vram_size)
*is_tmr_in_sysmem = true;
else
vram_size <<= 20;
*is_tmr_in_sysmem = false;
/*
* If in VRAM, discovery TMR is marked for reservation. If it is in system mem,
* then it is not required to be reserved.
*/
if (sz_valid) {
if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) {
/* For SRIOV VFs with dynamic critical region enabled,
* we will get the IPD binary via below call.
* If dynamic critical is disabled, fall through to normal seq.
*/
if (amdgpu_virt_get_dynamic_data_info(adev,
AMD_SRIOV_MSG_IPD_TABLE_ID, binary,
&adev->discovery.size)) {
dev_err(adev->dev,
"failed to read discovery info from dynamic critical region.");
ret = -EINVAL;
goto exit;
}
/* init the default tmr size and offset */
adev->discovery.size = DISCOVERY_TMR_SIZE;
if (vram_size)
adev->discovery.offset = (vram_size << 20) - DISCOVERY_TMR_OFFSET;
if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) {
adev->discovery.offset =
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset;
adev->discovery.size =
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10;
if (!adev->discovery.offset || !adev->discovery.size)
return -EINVAL;
} else {
tmr_size = RREG32(mmDRIVER_SCRATCH_2);
if (tmr_size) {
/* It's preferred to transition to PSP mailbox reg interface
* for both bare-metal and passthrough if available */
adev->discovery.size = (u32)tmr_size;
tmr_offset_lo = RREG32(mmDRIVER_SCRATCH_0);
tmr_offset_hi = RREG32(mmDRIVER_SCRATCH_1);
adev->discovery.offset = ((u64)le32_to_cpu(tmr_offset_hi) << 32 |
le32_to_cpu(tmr_offset_lo));
} else if (!vram_size) {
/* fall back to apci approach to query tmr offset if vram_size is 0 */
ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size);
if (ret)
return ret;
adev->discovery.size = (u32)tmr_size;
adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET;
}
}
adev->discovery.bin = kzalloc(adev->discovery.size, GFP_KERNEL);
if (!adev->discovery.bin)
return -ENOMEM;
adev->discovery.debugfs_blob.data = adev->discovery.bin;
adev->discovery.debugfs_blob.size = adev->discovery.size;
return 0;
}
static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, uint8_t *binary)
{
void *discv_regn;
/* This region is read-only and reserved from system use */
discv_regn = memremap(adev->discovery.offset, adev->discovery.size, MEMREMAP_WC);
if (discv_regn) {
memcpy(binary, discv_regn, adev->discovery.size);
memunmap(discv_regn);
return 0;
}
return -ENOENT;
}
#define IP_DISCOVERY_V2 2
#define IP_DISCOVERY_V4 4
static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
uint8_t *binary,
bool is_tmr_in_sysmem)
{
int ret = 0;
if (!is_tmr_in_sysmem) {
if (amdgpu_sriov_vf(adev) &&
amdgpu_sriov_xgmi_connected_to_cpu(adev)) {
ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary);
} else {
uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET;
amdgpu_device_vram_access(adev, pos, (uint32_t *)binary,
adev->discovery.size, false);
amdgpu_device_vram_access(adev, adev->discovery.offset,
(uint32_t *)binary,
adev->discovery.size, false);
adev->discovery.reserve_tmr = true;
}
} else {
ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary);
}
if (ret)
dev_err(adev->dev,
"failed to read discovery info from memory, vram size read: %llx",
vram_size);
exit:
return ret;
}
static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev,
uint8_t *binary,
const char *fw_name)
uint8_t *binary,
const char *fw_name)
{
const struct firmware *fw;
int r;
@ -431,14 +457,12 @@ static void amdgpu_discovery_harvest_config_quirk(struct amdgpu_device *adev)
}
static int amdgpu_discovery_verify_npsinfo(struct amdgpu_device *adev,
struct binary_header *bhdr)
struct table_info *info)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct table_info *info;
uint16_t checksum;
uint16_t offset;
info = &bhdr->table_list[NPS_INFO];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
@ -491,23 +515,125 @@ static const char *amdgpu_discovery_get_fw_name(struct amdgpu_device *adev)
}
}
static int amdgpu_discovery_get_table_info(struct amdgpu_device *adev,
struct table_info **info,
uint16_t table_id)
{
struct binary_header *bhdr =
(struct binary_header *)adev->discovery.bin;
struct binary_header_v2 *bhdrv2;
switch (bhdr->version_major) {
case 2:
bhdrv2 = (struct binary_header_v2 *)adev->discovery.bin;
*info = &bhdrv2->table_list[table_id];
break;
case 1:
*info = &bhdr->table_list[table_id];
break;
default:
dev_err(adev->dev, "Invalid ip discovery table version\n");
return -EINVAL;
}
return 0;
}
static int amdgpu_discovery_table_check(struct amdgpu_device *adev,
uint8_t *discovery_bin,
uint16_t table_id)
{
int r, act_val, exp_val, table_size;
uint16_t offset, checksum;
struct table_info *info;
bool check_table = true;
char *table_name;
r = amdgpu_discovery_get_table_info(adev, &info, table_id);
if (r)
return r;
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
switch (table_id) {
case IP_DISCOVERY:
struct ip_discovery_header *ihdr =
(struct ip_discovery_header *)(discovery_bin + offset);
act_val = le32_to_cpu(ihdr->signature);
exp_val = DISCOVERY_TABLE_SIGNATURE;
table_size = le16_to_cpu(ihdr->size);
table_name = "data table";
break;
case GC:
struct gpu_info_header *ghdr =
(struct gpu_info_header *)(discovery_bin + offset);
act_val = le32_to_cpu(ghdr->table_id);
exp_val = GC_TABLE_ID;
table_size = le16_to_cpu(ghdr->size);
table_name = "gc table";
break;
case HARVEST_INFO:
struct harvest_info_header *hhdr =
(struct harvest_info_header *)(discovery_bin + offset);
act_val = le32_to_cpu(hhdr->signature);
exp_val = HARVEST_TABLE_SIGNATURE;
table_size = sizeof(struct harvest_table);
table_name = "harvest table";
break;
case VCN_INFO:
struct vcn_info_header *vhdr =
(struct vcn_info_header *)(discovery_bin + offset);
act_val = le32_to_cpu(vhdr->table_id);
exp_val = VCN_INFO_TABLE_ID;
table_size = le32_to_cpu(vhdr->size_bytes);
table_name = "vcn table";
break;
case MALL_INFO:
struct mall_info_header *mhdr =
(struct mall_info_header *)(discovery_bin + offset);
act_val = le32_to_cpu(mhdr->table_id);
exp_val = MALL_INFO_TABLE_ID;
table_size = le32_to_cpu(mhdr->size_bytes);
table_name = "mall table";
check_table = false;
break;
default:
dev_err(adev->dev, "invalid ip discovery table id %d specified\n", table_id);
check_table = false;
break;
}
if (check_table && offset) {
if (act_val != exp_val) {
dev_err(adev->dev, "invalid ip discovery %s signature\n", table_name);
return -EINVAL;
}
if (!amdgpu_discovery_verify_checksum(adev, discovery_bin + offset,
table_size, checksum)) {
dev_err(adev->dev, "invalid ip discovery %s checksum\n", table_name);
return -EINVAL;
}
}
return 0;
}
static int amdgpu_discovery_init(struct amdgpu_device *adev)
{
struct table_info *info;
struct binary_header *bhdr;
uint8_t *discovery_bin;
const char *fw_name;
uint16_t offset;
uint16_t size;
uint16_t checksum;
uint16_t table_id;
bool is_tmr_in_sysmem;
int r;
adev->discovery.bin = kzalloc(DISCOVERY_TMR_SIZE, GFP_KERNEL);
if (!adev->discovery.bin)
return -ENOMEM;
adev->discovery.size = DISCOVERY_TMR_SIZE;
adev->discovery.debugfs_blob.data = adev->discovery.bin;
adev->discovery.debugfs_blob.size = adev->discovery.size;
r = amdgpu_discovery_get_tmr_info(adev, &is_tmr_in_sysmem);
if (r)
return r;
discovery_bin = adev->discovery.bin;
/* Read from file if it is the preferred option */
@ -520,7 +646,8 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
goto out;
} else {
drm_dbg(&adev->ddev, "use ip discovery information from memory");
r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin);
r = amdgpu_discovery_read_binary_from_mem(adev, discovery_bin,
is_tmr_in_sysmem);
if (r)
goto out;
}
@ -547,118 +674,10 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
goto out;
}
info = &bhdr->table_list[IP_DISCOVERY];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
if (offset) {
struct ip_discovery_header *ihdr =
(struct ip_discovery_header *)(discovery_bin + offset);
if (le32_to_cpu(ihdr->signature) != DISCOVERY_TABLE_SIGNATURE) {
dev_err(adev->dev, "invalid ip discovery data table signature\n");
r = -EINVAL;
for (table_id = 0; table_id <= MALL_INFO; table_id++) {
r = amdgpu_discovery_table_check(adev, discovery_bin, table_id);
if (r)
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev, discovery_bin + offset,
le16_to_cpu(ihdr->size),
checksum)) {
dev_err(adev->dev, "invalid ip discovery data table checksum\n");
r = -EINVAL;
goto out;
}
}
info = &bhdr->table_list[GC];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
if (offset) {
struct gpu_info_header *ghdr =
(struct gpu_info_header *)(discovery_bin + offset);
if (le32_to_cpu(ghdr->table_id) != GC_TABLE_ID) {
dev_err(adev->dev, "invalid ip discovery gc table id\n");
r = -EINVAL;
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev, discovery_bin + offset,
le32_to_cpu(ghdr->size),
checksum)) {
dev_err(adev->dev, "invalid gc data table checksum\n");
r = -EINVAL;
goto out;
}
}
info = &bhdr->table_list[HARVEST_INFO];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
if (offset) {
struct harvest_info_header *hhdr =
(struct harvest_info_header *)(discovery_bin + offset);
if (le32_to_cpu(hhdr->signature) != HARVEST_TABLE_SIGNATURE) {
dev_err(adev->dev, "invalid ip discovery harvest table signature\n");
r = -EINVAL;
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev,
discovery_bin + offset,
sizeof(struct harvest_table), checksum)) {
dev_err(adev->dev, "invalid harvest data table checksum\n");
r = -EINVAL;
goto out;
}
}
info = &bhdr->table_list[VCN_INFO];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
if (offset) {
struct vcn_info_header *vhdr =
(struct vcn_info_header *)(discovery_bin + offset);
if (le32_to_cpu(vhdr->table_id) != VCN_INFO_TABLE_ID) {
dev_err(adev->dev, "invalid ip discovery vcn table id\n");
r = -EINVAL;
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev,
discovery_bin + offset,
le32_to_cpu(vhdr->size_bytes), checksum)) {
dev_err(adev->dev, "invalid vcn data table checksum\n");
r = -EINVAL;
goto out;
}
}
info = &bhdr->table_list[MALL_INFO];
offset = le16_to_cpu(info->offset);
checksum = le16_to_cpu(info->checksum);
if (0 && offset) {
struct mall_info_header *mhdr =
(struct mall_info_header *)(discovery_bin + offset);
if (le32_to_cpu(mhdr->table_id) != MALL_INFO_TABLE_ID) {
dev_err(adev->dev, "invalid ip discovery mall table id\n");
r = -EINVAL;
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev,
discovery_bin + offset,
le32_to_cpu(mhdr->size_bytes), checksum)) {
dev_err(adev->dev, "invalid mall data table checksum\n");
r = -EINVAL;
goto out;
}
}
return 0;
@ -770,14 +789,15 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
uint32_t *umc_harvest_count)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct binary_header *bhdr;
struct table_info *info;
struct harvest_table *harvest_info;
u16 offset;
int i;
uint32_t umc_harvest_config = 0;
u64 umc_harvest_config = 0;
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset);
if (amdgpu_discovery_get_table_info(adev, &info, HARVEST_INFO))
return;
offset = le16_to_cpu(info->offset);
if (!offset) {
dev_err(adev->dev, "invalid harvest table offset\n");
@ -830,7 +850,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
}
}
adev->umc.active_mask = ((1 << adev->umc.node_inst_num) - 1) &
adev->umc.active_mask = ((1ULL << adev->umc.node_inst_num) - 1ULL) &
~umc_harvest_config;
}
@ -1195,13 +1215,8 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
ip_hw_instance->num_instance);
ip_hw_instance->num_base_addresses = ip->num_base_address;
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++) {
if (reg_base_64)
ip_hw_instance->base_addr[kk] =
lower_32_bits(le64_to_cpu(ip->base_address_64[kk])) & 0x3FFFFFFF;
else
ip_hw_instance->base_addr[kk] = ip->base_address[kk];
}
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++)
ip_hw_instance->base_addr[kk] = ip->base_address[kk];
kobject_init(&ip_hw_instance->kobj, &ip_hw_instance_ktype);
ip_hw_instance->kobj.kset = &ip_hw_id->hw_id_kset;
@ -1224,7 +1239,7 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev)
{
struct ip_discovery_top *ip_top = adev->discovery.ip_top;
uint8_t *discovery_bin = adev->discovery.bin;
struct binary_header *bhdr;
struct table_info *info;
struct ip_discovery_header *ihdr;
struct die_header *dhdr;
struct kset *die_kset = &ip_top->die_kset;
@ -1232,10 +1247,12 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev)
size_t ip_offset;
int ii, res;
bhdr = (struct binary_header *)discovery_bin;
res = amdgpu_discovery_get_table_info(adev, &info, IP_DISCOVERY);
if (res)
return res;
ihdr = (struct ip_discovery_header
*)(discovery_bin +
le16_to_cpu(bhdr->table_list[IP_DISCOVERY].offset));
le16_to_cpu(info->offset));
num_dies = le16_to_cpu(ihdr->num_dies);
DRM_DEBUG("number of dies: %d\n", num_dies);
@ -1379,12 +1396,54 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
kobject_put(&ip_top->kobj);
}
/* devcoredump support */
void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p)
{
struct ip_discovery_top *ip_top = adev->discovery.ip_top;
struct ip_die_entry *ip_die_entry;
struct list_head *el_die, *el_hw_id, *el_hw_inst;
struct ip_hw_id *hw_id;
struct kset *die_kset;
struct ip_hw_instance *ip_inst;
int i = 0, j;
die_kset = &ip_top->die_kset;
drm_printf(p, "\nHW IP Discovery\n");
spin_lock(&die_kset->list_lock);
list_for_each(el_die, &die_kset->list) {
drm_printf(p, "die %d\n", i++);
ip_die_entry = to_ip_die_entry(list_to_kobj(el_die));
list_for_each(el_hw_id, &ip_die_entry->ip_kset.list) {
hw_id = to_ip_hw_id(list_to_kobj(el_hw_id));
drm_printf(p, "hw_id %d %s\n", hw_id->hw_id, hw_id_names[hw_id->hw_id]);
list_for_each(el_hw_inst, &hw_id->hw_id_kset.list) {
ip_inst = to_ip_hw_instance(list_to_kobj(el_hw_inst));
drm_printf(p, "\tinstance %d\n", ip_inst->num_instance);
drm_printf(p, "\tmajor %d\n", ip_inst->major);
drm_printf(p, "\tminor %d\n", ip_inst->minor);
drm_printf(p, "\trevision %d\n", ip_inst->revision);
drm_printf(p, "\tharvest 0x%01X\n", ip_inst->harvest);
drm_printf(p, "\tnum_base_addresses %d\n",
ip_inst->num_base_addresses);
for (j = 0; j < ip_inst->num_base_addresses; j++)
drm_printf(p, "\tbase_addr[%d] 0x%08X\n",
j, ip_inst->base_addr[j]);
}
}
}
spin_unlock(&die_kset->list_lock);
}
/* ================================================== */
static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
{
uint8_t num_base_address, subrev, variant;
struct binary_header *bhdr;
struct table_info *info;
struct ip_discovery_header *ihdr;
struct die_header *dhdr;
uint8_t *discovery_bin;
@ -1409,10 +1468,12 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
adev->sdma.sdma_mask = 0;
adev->vcn.inst_mask = 0;
adev->jpeg.inst_mask = 0;
bhdr = (struct binary_header *)discovery_bin;
r = amdgpu_discovery_get_table_info(adev, &info, IP_DISCOVERY);
if (r)
return r;
ihdr = (struct ip_discovery_header
*)(discovery_bin +
le16_to_cpu(bhdr->table_list[IP_DISCOVERY].offset));
le16_to_cpu(info->offset));
num_dies = le16_to_cpu(ihdr->num_dies);
DRM_DEBUG("number of dies: %d\n", num_dies);
@ -1585,14 +1646,15 @@ static void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct ip_discovery_header *ihdr;
struct binary_header *bhdr;
struct table_info *info;
int vcn_harvest_count = 0;
int umc_harvest_count = 0;
uint16_t offset, ihdr_ver;
uint16_t ihdr_ver;
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[IP_DISCOVERY].offset);
ihdr = (struct ip_discovery_header *)(discovery_bin + offset);
if (amdgpu_discovery_get_table_info(adev, &info, IP_DISCOVERY))
return;
ihdr = (struct ip_discovery_header *)(discovery_bin +
le16_to_cpu(info->offset));
ihdr_ver = le16_to_cpu(ihdr->version);
/*
* Harvest table does not fit Navi1x and legacy GPUs,
@ -1640,7 +1702,7 @@ union gc_info {
static int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct binary_header *bhdr;
struct table_info *info;
union gc_info *gc_info;
u16 offset;
@ -1649,8 +1711,9 @@ static int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
return -EINVAL;
}
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[GC].offset);
if (amdgpu_discovery_get_table_info(adev, &info, GC))
return -EINVAL;
offset = le16_to_cpu(info->offset);
if (!offset)
return 0;
@ -1749,7 +1812,7 @@ union mall_info {
static int amdgpu_discovery_get_mall_info(struct amdgpu_device *adev)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct binary_header *bhdr;
struct table_info *info;
union mall_info *mall_info;
u32 u, mall_size_per_umc, m_s_present, half_use;
u64 mall_size;
@ -1760,8 +1823,9 @@ static int amdgpu_discovery_get_mall_info(struct amdgpu_device *adev)
return -EINVAL;
}
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[MALL_INFO].offset);
if (amdgpu_discovery_get_table_info(adev, &info, MALL_INFO))
return -EINVAL;
offset = le16_to_cpu(info->offset);
if (!offset)
return 0;
@ -1806,7 +1870,7 @@ union vcn_info {
static int amdgpu_discovery_get_vcn_info(struct amdgpu_device *adev)
{
uint8_t *discovery_bin = adev->discovery.bin;
struct binary_header *bhdr;
struct table_info *info;
union vcn_info *vcn_info;
u16 offset;
int v;
@ -1826,8 +1890,9 @@ static int amdgpu_discovery_get_vcn_info(struct amdgpu_device *adev)
return -EINVAL;
}
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[VCN_INFO].offset);
if (amdgpu_discovery_get_table_info(adev, &info, VCN_INFO))
return -EINVAL;
offset = le16_to_cpu(info->offset);
if (!offset)
return 0;
@ -1864,14 +1929,26 @@ static int amdgpu_discovery_refresh_nps_info(struct amdgpu_device *adev,
uint64_t vram_size, pos, offset;
struct nps_info_header *nhdr;
struct binary_header bhdr;
struct binary_header_v2 bhdrv2;
uint16_t checksum;
vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20;
pos = vram_size - DISCOVERY_TMR_OFFSET;
amdgpu_device_vram_access(adev, pos, &bhdr, sizeof(bhdr), false);
offset = le16_to_cpu(bhdr.table_list[NPS_INFO].offset);
checksum = le16_to_cpu(bhdr.table_list[NPS_INFO].checksum);
switch (bhdr.version_major) {
case 2:
amdgpu_device_vram_access(adev, pos, &bhdrv2, sizeof(bhdrv2), false);
offset = le16_to_cpu(bhdrv2.table_list[NPS_INFO].offset);
checksum = le16_to_cpu(bhdrv2.table_list[NPS_INFO].checksum);
break;
case 1:
offset = le16_to_cpu(bhdr.table_list[NPS_INFO].offset);
checksum = le16_to_cpu(bhdr.table_list[NPS_INFO].checksum);
break;
default:
return -EINVAL;
}
amdgpu_device_vram_access(adev, (pos + offset), nps_data,
sizeof(*nps_data), false);
@ -1894,7 +1971,7 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev,
{
uint8_t *discovery_bin = adev->discovery.bin;
struct amdgpu_gmc_memrange *mem_ranges;
struct binary_header *bhdr;
struct table_info *info;
union nps_info *nps_info;
union nps_info nps_data;
u16 offset;
@ -1915,14 +1992,15 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev,
return -EINVAL;
}
bhdr = (struct binary_header *)discovery_bin;
offset = le16_to_cpu(bhdr->table_list[NPS_INFO].offset);
if (amdgpu_discovery_get_table_info(adev, &info, NPS_INFO))
return -EINVAL;
offset = le16_to_cpu(info->offset);
if (!offset)
return -ENOENT;
/* If verification fails, return as if NPS table doesn't exist */
if (amdgpu_discovery_verify_npsinfo(adev, bhdr))
if (amdgpu_discovery_verify_npsinfo(adev, info))
return -ENOENT;
nps_info = (union nps_info *)(discovery_bin + offset);
@ -3226,6 +3304,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(7, 0, 1):
adev->lsdma.funcs = &lsdma_v7_0_funcs;
break;
case IP_VERSION(7, 1, 0):
adev->lsdma.funcs = &lsdma_v7_1_funcs;
break;
default:
break;
}

View File

@ -30,10 +30,12 @@
#define DISCOVERY_TMR_OFFSET (64 << 10)
struct ip_discovery_top;
struct drm_printer;
struct amdgpu_discovery_info {
struct debugfs_blob_wrapper debugfs_blob;
struct ip_discovery_top *ip_top;
uint64_t offset;
uint32_t size;
uint8_t *bin;
bool reserve_tmr;
@ -47,4 +49,6 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev,
struct amdgpu_gmc_memrange **ranges,
int *range_cnt, bool refresh);
void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p);
#endif /* __AMDGPU_DISCOVERY__ */

View File

@ -1738,21 +1738,6 @@ bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
stime, etime, mode);
}
static bool
amdgpu_display_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
{
struct drm_device *dev = adev_to_drm(adev);
struct drm_fb_helper *fb_helper = dev->fb_helper;
if (!fb_helper || !fb_helper->buffer)
return false;
if (gem_to_amdgpu_bo(fb_helper->buffer->gem) != robj)
return false;
return true;
}
int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
{
struct drm_device *dev = adev_to_drm(adev);
@ -1775,7 +1760,6 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_framebuffer *fb = crtc->primary->fb;
struct amdgpu_bo *robj;
if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) {
struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo);
@ -1790,8 +1774,9 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
if (!fb || !fb->obj[0])
continue;
robj = gem_to_amdgpu_bo(fb->obj[0]);
if (!amdgpu_display_robj_is_fb(adev, robj)) {
if (!drm_fb_helper_gem_is_fb(dev->fb_helper, fb->obj[0])) {
struct amdgpu_bo *robj = gem_to_amdgpu_bo(fb->obj[0]);
r = amdgpu_bo_reserve(robj, true);
if (r == 0) {
amdgpu_bo_unpin(robj);

View File

@ -94,6 +94,10 @@ enum amdgpu_memory_partition {
#define AMDGPU_GMC9_FAULT_SOURCE_DATA_WRITE 0x20
#define AMDGPU_GMC9_FAULT_SOURCE_DATA_EXE 0x10
#define AMDGPU_GMC121_FAULT_SOURCE_DATA_READ 0x400000
#define AMDGPU_GMC121_FAULT_SOURCE_DATA_WRITE 0x200000
#define AMDGPU_GMC121_FAULT_SOURCE_DATA_EXE 0x100000
/*
* GMC page fault information
*/

View File

@ -83,7 +83,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev)
{
struct amdgpu_device *adev = drm_to_adev(dev);
if (adev == NULL)
if (adev == NULL || !adev->num_ip_blocks)
return;
amdgpu_unregister_gpu_instance(adev);

View File

@ -159,9 +159,9 @@ struct amdgpu_mes {
int hung_queue_db_array_size;
int hung_queue_hqd_info_offset;
struct amdgpu_bo *hung_queue_db_array_gpu_obj[AMDGPU_MAX_MES_PIPES];
uint64_t hung_queue_db_array_gpu_addr[AMDGPU_MAX_MES_PIPES];
void *hung_queue_db_array_cpu_addr[AMDGPU_MAX_MES_PIPES];
struct amdgpu_bo *hung_queue_db_array_gpu_obj[AMDGPU_MAX_MES_INST_PIPES];
uint64_t hung_queue_db_array_gpu_addr[AMDGPU_MAX_MES_INST_PIPES];
void *hung_queue_db_array_cpu_addr[AMDGPU_MAX_MES_INST_PIPES];
/* cooperative dispatch */
bool enable_coop_mode;

View File

@ -368,15 +368,15 @@ struct amdgpu_mode_info {
struct drm_property *plane_ctm_property;
/**
* @shaper_lut_property: Plane property to set pre-blending shaper LUT
* that converts color content before 3D LUT. If
* plane_shaper_tf_property != Identity TF, AMD color module will
* @plane_shaper_lut_property: Plane property to set pre-blending
* shaper LUT that converts color content before 3D LUT.
* If plane_shaper_tf_property != Identity TF, AMD color module will
* combine the user LUT values with pre-defined TF into the LUT
* parameters to be programmed.
*/
struct drm_property *plane_shaper_lut_property;
/**
* @shaper_lut_size_property: Plane property for the size of
* @plane_shaper_lut_size_property: Plane property for the size of
* pre-blending shaper LUT as supported by the driver (read-only).
*/
struct drm_property *plane_shaper_lut_size_property;
@ -400,10 +400,10 @@ struct amdgpu_mode_info {
*/
struct drm_property *plane_lut3d_property;
/**
* @plane_degamma_lut_size_property: Plane property to define the max
* size of 3D LUT as supported by the driver (read-only). The max size
* is the max size of one dimension and, therefore, the max number of
* entries for 3D LUT array is the 3D LUT size cubed;
* @plane_lut3d_size_property: Plane property to define the max size
* of 3D LUT as supported by the driver (read-only). The max size is
* the max size of one dimension and, therefore, the max number of
* entries for 3D LUT array is the 3D LUT size cubed.
*/
struct drm_property *plane_lut3d_size_property;
/**
@ -624,7 +624,7 @@ struct amdgpu_connector {
bool use_digital;
/* we need to mind the EDID between detect
and get modes due to analog/digital/tvencoder */
struct edid *edid;
const struct drm_edid *edid;
void *con_priv;
bool dac_load_detect;
bool detected_by_load; /* if the connection status was determined by load */

View File

@ -3096,6 +3096,13 @@ static int psp_load_non_psp_fw(struct psp_context *psp)
*/
continue;
/* IMU ucode is part of IFWI and MP0 15.0.8 would load it */
if (amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 8) &&
(ucode->ucode_id == AMDGPU_UCODE_ID_IMU_I ||
ucode->ucode_id == AMDGPU_UCODE_ID_IMU_D))
continue;
psp_print_fw_hdr(psp, ucode);
ret = psp_execute_ip_fw_load(psp, ucode);

View File

@ -291,22 +291,22 @@ void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr)
break;
case 5:
/* rlc_hdr v2_5 */
DRM_INFO("rlc_iram_ucode_size_bytes: %u\n",
DRM_DEBUG("rlc_iram_ucode_size_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->v2_2.rlc_iram_ucode_size_bytes));
DRM_INFO("rlc_iram_ucode_offset_bytes: %u\n",
DRM_DEBUG("rlc_iram_ucode_offset_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->v2_2.rlc_iram_ucode_offset_bytes));
DRM_INFO("rlc_dram_ucode_size_bytes: %u\n",
DRM_DEBUG("rlc_dram_ucode_size_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->v2_2.rlc_dram_ucode_size_bytes));
DRM_INFO("rlc_dram_ucode_offset_bytes: %u\n",
DRM_DEBUG("rlc_dram_ucode_offset_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->v2_2.rlc_dram_ucode_offset_bytes));
/* rlc_hdr v2_5 */
DRM_INFO("rlc_1_iram_ucode_size_bytes: %u\n",
DRM_DEBUG("rlc_1_iram_ucode_size_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->rlc_1_iram_ucode_size_bytes));
DRM_INFO("rlc_1_iram_ucode_offset_bytes: %u\n",
DRM_DEBUG("rlc_1_iram_ucode_offset_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->rlc_1_iram_ucode_offset_bytes));
DRM_INFO("rlc_1_dram_ucode_size_bytes: %u\n",
DRM_DEBUG("rlc_1_dram_ucode_size_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->rlc_1_dram_ucode_size_bytes));
DRM_INFO("rlc_1_dram_ucode_offset_bytes: %u\n",
DRM_DEBUG("rlc_1_dram_ucode_offset_bytes: %u\n",
le32_to_cpu(rlc_hdr_v2_5->rlc_1_dram_ucode_offset_bytes));
break;
default:

View File

@ -709,46 +709,6 @@ static int amdgpu_userq_priority_permit(struct drm_file *filp,
return -EACCES;
}
#if defined(CONFIG_DEBUG_FS)
static int amdgpu_mqd_info_read(struct seq_file *m, void *unused)
{
struct amdgpu_usermode_queue *queue = m->private;
struct amdgpu_bo *bo;
int r;
if (!queue || !queue->mqd.obj)
return -EINVAL;
bo = amdgpu_bo_ref(queue->mqd.obj);
r = amdgpu_bo_reserve(bo, true);
if (r) {
amdgpu_bo_unref(&bo);
return -EINVAL;
}
seq_printf(m, "queue_type: %d\n", queue->queue_type);
seq_printf(m, "mqd_gpu_address: 0x%llx\n", amdgpu_bo_gpu_offset(queue->mqd.obj));
amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo);
return 0;
}
static int amdgpu_mqd_info_open(struct inode *inode, struct file *file)
{
return single_open(file, amdgpu_mqd_info_read, inode->i_private);
}
static const struct file_operations amdgpu_mqd_info_fops = {
.owner = THIS_MODULE,
.open = amdgpu_mqd_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
static int
amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
{
@ -758,7 +718,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
const struct amdgpu_userq_funcs *uq_funcs;
struct amdgpu_usermode_queue *queue;
struct amdgpu_db_info db_info;
char *queue_name;
bool skip_map_queue;
u32 qid;
uint64_t index;
@ -819,17 +778,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) ||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) {
r = -EINVAL;
kfree(queue);
goto unlock;
goto free_queue;
}
/* Convert relative doorbell offset into absolute doorbell index */
index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
if (index == (uint64_t)-EINVAL) {
drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
kfree(queue);
r = -EINVAL;
goto unlock;
goto free_queue;
}
queue->doorbell_index = index;
@ -837,42 +794,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
r = amdgpu_userq_fence_driver_alloc(adev, queue);
if (r) {
drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n");
goto unlock;
goto free_queue;
}
r = uq_funcs->mqd_create(queue, &args->in);
if (r) {
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
amdgpu_userq_fence_driver_free(queue);
kfree(queue);
goto unlock;
goto clean_fence_driver;
}
/* drop this refcount during queue destroy */
kref_init(&queue->refcount);
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
if (r) {
kfree(queue);
up_read(&adev->reset_domain->sem);
goto unlock;
}
r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL);
if (r) {
drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n");
amdgpu_userq_fence_driver_free(queue);
uq_funcs->mqd_destroy(queue);
kfree(queue);
r = -ENOMEM;
up_read(&adev->reset_domain->sem);
goto unlock;
}
up_read(&adev->reset_domain->sem);
/* don't map the queue if scheduling is halted */
if (adev->userq_halt_for_enforce_isolation &&
((queue->queue_type == AMDGPU_HW_IP_GFX) ||
@ -884,31 +814,52 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
r = amdgpu_userq_map_helper(queue);
if (r) {
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
xa_erase(&uq_mgr->userq_xa, qid);
amdgpu_userq_fence_driver_free(queue);
uq_funcs->mqd_destroy(queue);
kfree(queue);
goto unlock;
down_read(&adev->reset_domain->sem);
goto clean_mqd;
}
}
queue_name = kasprintf(GFP_KERNEL, "queue-%d", qid);
if (!queue_name) {
/* drop this refcount during queue destroy */
kref_init(&queue->refcount);
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL);
if (r) {
if (!skip_map_queue)
amdgpu_userq_unmap_helper(queue);
r = -ENOMEM;
goto unlock;
goto clean_mqd;
}
#if defined(CONFIG_DEBUG_FS)
/* Queue dentry per client to hold MQD information */
queue->debugfs_queue = debugfs_create_dir(queue_name, filp->debugfs_client);
debugfs_create_file("mqd_info", 0444, queue->debugfs_queue, queue, &amdgpu_mqd_info_fops);
#endif
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
if (r) {
xa_erase(&uq_mgr->userq_xa, qid);
if (!skip_map_queue)
amdgpu_userq_unmap_helper(queue);
goto clean_mqd;
}
up_read(&adev->reset_domain->sem);
amdgpu_debugfs_userq_init(filp, queue, qid);
amdgpu_userq_init_hang_detect_work(queue);
kfree(queue_name);
args->out.queue_id = qid;
atomic_inc(&uq_mgr->userq_count[queue->queue_type]);
mutex_unlock(&uq_mgr->userq_mutex);
return 0;
clean_mqd:
uq_funcs->mqd_destroy(queue);
up_read(&adev->reset_domain->sem);
clean_fence_driver:
amdgpu_userq_fence_driver_free(queue);
free_queue:
kfree(queue);
unlock:
mutex_unlock(&uq_mgr->userq_mutex);
@ -1089,12 +1040,12 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec,
struct amdgpu_bo *bo;
int ret;
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
while (!list_empty(&vm->invalidated)) {
bo_va = list_first_entry(&vm->invalidated,
struct amdgpu_bo_va,
base.vm_status);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
bo = bo_va->base.bo;
ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2);
@ -1111,9 +1062,9 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec,
if (ret)
return ret;
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
}
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
return 0;
}

View File

@ -162,6 +162,7 @@ enum AMDGIM_FEATURE_FLAG {
AMDGIM_FEATURE_RAS_TELEMETRY = (1 << 10),
AMDGIM_FEATURE_RAS_CPER = (1 << 11),
AMDGIM_FEATURE_XGMI_TA_EXT_PEER_LINK = (1 << 12),
AMDGIM_FEATURE_XGMI_CONNECTED_TO_CPU = (1 << 13),
};
enum AMDGIM_REG_ACCESS_FLAG {
@ -412,6 +413,9 @@ struct amdgpu_video_codec_info;
#define amdgpu_sriov_xgmi_ta_ext_peer_link_en(adev) \
((adev)->virt.gim_feature & AMDGIM_FEATURE_XGMI_TA_EXT_PEER_LINK)
#define amdgpu_sriov_xgmi_connected_to_cpu(adev) \
((adev)->virt.gim_feature & AMDGIM_FEATURE_XGMI_CONNECTED_TO_CPU)
static inline bool is_virtual_machine(void)
{
#if defined(CONFIG_X86)

View File

@ -153,12 +153,10 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo)
vm_bo->moved = true;
amdgpu_vm_assert_locked(vm);
spin_lock(&vm_bo->vm->status_lock);
if (bo->tbo.type == ttm_bo_type_kernel)
list_move(&vm_bo->vm_status, &vm->evicted);
else
list_move_tail(&vm_bo->vm_status, &vm->evicted);
spin_unlock(&vm_bo->vm->status_lock);
}
/**
* amdgpu_vm_bo_moved - vm_bo is moved
@ -171,9 +169,7 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo)
static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo)
{
amdgpu_vm_assert_locked(vm_bo->vm);
spin_lock(&vm_bo->vm->status_lock);
list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
spin_unlock(&vm_bo->vm->status_lock);
}
/**
@ -187,9 +183,7 @@ static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo)
static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
{
amdgpu_vm_assert_locked(vm_bo->vm);
spin_lock(&vm_bo->vm->status_lock);
list_move(&vm_bo->vm_status, &vm_bo->vm->idle);
spin_unlock(&vm_bo->vm->status_lock);
vm_bo->moved = false;
}
@ -203,9 +197,9 @@ static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
*/
static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo)
{
spin_lock(&vm_bo->vm->status_lock);
spin_lock(&vm_bo->vm->invalidated_lock);
list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated);
spin_unlock(&vm_bo->vm->status_lock);
spin_unlock(&vm_bo->vm->invalidated_lock);
}
/**
@ -218,10 +212,9 @@ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo)
*/
static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo)
{
amdgpu_vm_assert_locked(vm_bo->vm);
vm_bo->moved = true;
spin_lock(&vm_bo->vm->status_lock);
list_move(&vm_bo->vm_status, &vm_bo->vm->evicted_user);
spin_unlock(&vm_bo->vm->status_lock);
}
/**
@ -235,13 +228,10 @@ static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo)
static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo)
{
amdgpu_vm_assert_locked(vm_bo->vm);
if (vm_bo->bo->parent) {
spin_lock(&vm_bo->vm->status_lock);
if (vm_bo->bo->parent)
list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
spin_unlock(&vm_bo->vm->status_lock);
} else {
else
amdgpu_vm_bo_idle(vm_bo);
}
}
/**
@ -255,9 +245,7 @@ static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo)
static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo)
{
amdgpu_vm_assert_locked(vm_bo->vm);
spin_lock(&vm_bo->vm->status_lock);
list_move(&vm_bo->vm_status, &vm_bo->vm->done);
spin_unlock(&vm_bo->vm->status_lock);
}
/**
@ -271,13 +259,13 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm)
{
struct amdgpu_vm_bo_base *vm_bo, *tmp;
amdgpu_vm_assert_locked(vm);
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
list_splice_init(&vm->done, &vm->invalidated);
list_for_each_entry(vm_bo, &vm->invalidated, vm_status)
vm_bo->moved = true;
spin_unlock(&vm->invalidated_lock);
amdgpu_vm_assert_locked(vm);
list_for_each_entry_safe(vm_bo, tmp, &vm->idle, vm_status) {
struct amdgpu_bo *bo = vm_bo->bo;
@ -287,14 +275,13 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm)
else if (bo->parent)
list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
}
spin_unlock(&vm->status_lock);
}
/**
* amdgpu_vm_update_shared - helper to update shared memory stat
* @base: base structure for tracking BO usage in a VM
*
* Takes the vm status_lock and updates the shared memory stat. If the basic
* Takes the vm stats_lock and updates the shared memory stat. If the basic
* stat changed (e.g. buffer was moved) amdgpu_vm_update_stats need to be called
* as well.
*/
@ -307,7 +294,7 @@ static void amdgpu_vm_update_shared(struct amdgpu_vm_bo_base *base)
bool shared;
dma_resv_assert_held(bo->tbo.base.resv);
spin_lock(&vm->status_lock);
spin_lock(&vm->stats_lock);
shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base);
if (base->shared != shared) {
base->shared = shared;
@ -319,7 +306,7 @@ static void amdgpu_vm_update_shared(struct amdgpu_vm_bo_base *base)
vm->stats[bo_memtype].drm.private += size;
}
}
spin_unlock(&vm->status_lock);
spin_unlock(&vm->stats_lock);
}
/**
@ -344,11 +331,11 @@ void amdgpu_vm_bo_update_shared(struct amdgpu_bo *bo)
* be bo->tbo.resource
* @sign: if we should add (+1) or subtract (-1) from the stat
*
* Caller need to have the vm status_lock held. Useful for when multiple update
* Caller need to have the vm stats_lock held. Useful for when multiple update
* need to happen at the same time.
*/
static void amdgpu_vm_update_stats_locked(struct amdgpu_vm_bo_base *base,
struct ttm_resource *res, int sign)
struct ttm_resource *res, int sign)
{
struct amdgpu_vm *vm = base->vm;
struct amdgpu_bo *bo = base->bo;
@ -372,7 +359,8 @@ static void amdgpu_vm_update_stats_locked(struct amdgpu_vm_bo_base *base,
*/
if (bo->flags & AMDGPU_GEM_CREATE_DISCARDABLE)
vm->stats[res_memtype].drm.purgeable += size;
if (!(bo->preferred_domains & amdgpu_mem_type_to_domain(res_memtype)))
if (!(bo->preferred_domains &
amdgpu_mem_type_to_domain(res_memtype)))
vm->stats[bo_memtype].evicted += size;
}
}
@ -391,9 +379,9 @@ void amdgpu_vm_update_stats(struct amdgpu_vm_bo_base *base,
{
struct amdgpu_vm *vm = base->vm;
spin_lock(&vm->status_lock);
spin_lock(&vm->stats_lock);
amdgpu_vm_update_stats_locked(base, res, sign);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->stats_lock);
}
/**
@ -419,10 +407,10 @@ void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base,
base->next = bo->vm_bo;
bo->vm_bo = base;
spin_lock(&vm->status_lock);
spin_lock(&vm->stats_lock);
base->shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base);
amdgpu_vm_update_stats_locked(base, bo->tbo.resource, +1);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->stats_lock);
if (!amdgpu_vm_is_bo_always_valid(vm, bo))
return;
@ -481,25 +469,25 @@ int amdgpu_vm_lock_done_list(struct amdgpu_vm *vm, struct drm_exec *exec,
int ret;
/* We can only trust prev->next while holding the lock */
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
while (!list_is_head(prev->next, &vm->done)) {
bo_va = list_entry(prev->next, typeof(*bo_va), base.vm_status);
bo = bo_va->base.bo;
if (bo) {
amdgpu_bo_ref(bo);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 1);
amdgpu_bo_unref(&bo);
if (unlikely(ret))
return ret;
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
}
prev = prev->next;
}
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
return 0;
}
@ -595,7 +583,7 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
void *param)
{
uint64_t new_vm_generation = amdgpu_vm_generation(adev, vm);
struct amdgpu_vm_bo_base *bo_base;
struct amdgpu_vm_bo_base *bo_base, *tmp;
struct amdgpu_bo *bo;
int r;
@ -608,13 +596,7 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
return r;
}
spin_lock(&vm->status_lock);
while (!list_empty(&vm->evicted)) {
bo_base = list_first_entry(&vm->evicted,
struct amdgpu_vm_bo_base,
vm_status);
spin_unlock(&vm->status_lock);
list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) {
bo = bo_base->bo;
r = validate(param, bo);
@ -627,26 +609,21 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
vm->update_funcs->map_table(to_amdgpu_bo_vm(bo));
amdgpu_vm_bo_relocated(bo_base);
}
spin_lock(&vm->status_lock);
}
while (ticket && !list_empty(&vm->evicted_user)) {
bo_base = list_first_entry(&vm->evicted_user,
struct amdgpu_vm_bo_base,
vm_status);
spin_unlock(&vm->status_lock);
bo = bo_base->bo;
dma_resv_assert_held(bo->tbo.base.resv);
if (ticket) {
list_for_each_entry_safe(bo_base, tmp, &vm->evicted_user,
vm_status) {
bo = bo_base->bo;
dma_resv_assert_held(bo->tbo.base.resv);
r = validate(param, bo);
if (r)
return r;
r = validate(param, bo);
if (r)
return r;
amdgpu_vm_bo_invalidated(bo_base);
spin_lock(&vm->status_lock);
amdgpu_vm_bo_invalidated(bo_base);
}
}
spin_unlock(&vm->status_lock);
amdgpu_vm_eviction_lock(vm);
vm->evicting = false;
@ -675,9 +652,7 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm)
ret = !vm->evicting;
amdgpu_vm_eviction_unlock(vm);
spin_lock(&vm->status_lock);
ret &= list_empty(&vm->evicted);
spin_unlock(&vm->status_lock);
spin_lock(&vm->immediate.lock);
ret &= !vm->immediate.stopped;
@ -971,18 +946,13 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
struct amdgpu_vm *vm, bool immediate)
{
struct amdgpu_vm_update_params params;
struct amdgpu_vm_bo_base *entry;
struct amdgpu_vm_bo_base *entry, *tmp;
bool flush_tlb_needed = false;
LIST_HEAD(relocated);
int r, idx;
amdgpu_vm_assert_locked(vm);
spin_lock(&vm->status_lock);
list_splice_init(&vm->relocated, &relocated);
spin_unlock(&vm->status_lock);
if (list_empty(&relocated))
if (list_empty(&vm->relocated))
return 0;
if (!drm_dev_enter(adev_to_drm(adev), &idx))
@ -998,7 +968,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
if (r)
goto error;
list_for_each_entry(entry, &relocated, vm_status) {
list_for_each_entry(entry, &vm->relocated, vm_status) {
/* vm_flush_needed after updating moved PDEs */
flush_tlb_needed |= entry->moved;
@ -1014,9 +984,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
if (flush_tlb_needed)
atomic64_inc(&vm->tlb_seq);
while (!list_empty(&relocated)) {
entry = list_first_entry(&relocated, struct amdgpu_vm_bo_base,
vm_status);
list_for_each_entry_safe(entry, tmp, &vm->relocated, vm_status) {
amdgpu_vm_bo_idle(entry);
}
@ -1243,9 +1211,9 @@ int amdgpu_vm_update_range(struct amdgpu_device *adev, struct amdgpu_vm *vm,
void amdgpu_vm_get_memory(struct amdgpu_vm *vm,
struct amdgpu_mem_stats stats[__AMDGPU_PL_NUM])
{
spin_lock(&vm->status_lock);
spin_lock(&vm->stats_lock);
memcpy(stats, vm->stats, sizeof(*stats) * __AMDGPU_PL_NUM);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->stats_lock);
}
/**
@ -1612,29 +1580,24 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
struct ww_acquire_ctx *ticket)
{
struct amdgpu_bo_va *bo_va;
struct amdgpu_bo_va *bo_va, *tmp;
struct dma_resv *resv;
bool clear, unlock;
int r;
spin_lock(&vm->status_lock);
while (!list_empty(&vm->moved)) {
bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va,
base.vm_status);
spin_unlock(&vm->status_lock);
list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
/* Per VM BOs never need to bo cleared in the page tables */
r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
return r;
spin_lock(&vm->status_lock);
}
spin_lock(&vm->invalidated_lock);
while (!list_empty(&vm->invalidated)) {
bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
base.vm_status);
resv = bo_va->base.bo->tbo.base.resv;
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
/* Try to reserve the BO to avoid clearing its ptes */
if (!adev->debug_vm && dma_resv_trylock(resv)) {
@ -1666,9 +1629,9 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
bo_va->base.bo->tbo.resource->mem_type == TTM_PL_SYSTEM))
amdgpu_vm_bo_evicted_user(&bo_va->base);
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
}
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
return 0;
}
@ -2211,9 +2174,9 @@ void amdgpu_vm_bo_del(struct amdgpu_device *adev,
}
}
spin_lock(&vm->status_lock);
spin_lock(&vm->invalidated_lock);
list_del(&bo_va->base.vm_status);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->invalidated_lock);
list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
list_del(&mapping->list);
@ -2321,10 +2284,10 @@ void amdgpu_vm_bo_move(struct amdgpu_bo *bo, struct ttm_resource *new_mem,
for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) {
struct amdgpu_vm *vm = bo_base->vm;
spin_lock(&vm->status_lock);
spin_lock(&vm->stats_lock);
amdgpu_vm_update_stats_locked(bo_base, bo->tbo.resource, -1);
amdgpu_vm_update_stats_locked(bo_base, new_mem, +1);
spin_unlock(&vm->status_lock);
spin_unlock(&vm->stats_lock);
}
amdgpu_vm_bo_invalidate(bo, evicted);
@ -2593,11 +2556,12 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
INIT_LIST_HEAD(&vm->relocated);
INIT_LIST_HEAD(&vm->moved);
INIT_LIST_HEAD(&vm->idle);
spin_lock_init(&vm->invalidated_lock);
INIT_LIST_HEAD(&vm->invalidated);
spin_lock_init(&vm->status_lock);
INIT_LIST_HEAD(&vm->freed);
INIT_LIST_HEAD(&vm->done);
INIT_KFIFO(vm->faults);
spin_lock_init(&vm->stats_lock);
r = amdgpu_vm_init_entities(adev, vm);
if (r)
@ -3065,7 +3029,6 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m)
amdgpu_vm_assert_locked(vm);
spin_lock(&vm->status_lock);
seq_puts(m, "\tIdle BOs:\n");
list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) {
if (!bo_va->base.bo)
@ -3103,11 +3066,13 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m)
id = 0;
seq_puts(m, "\tInvalidated BOs:\n");
spin_lock(&vm->invalidated_lock);
list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) {
if (!bo_va->base.bo)
continue;
total_invalidated += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
}
spin_unlock(&vm->invalidated_lock);
total_invalidated_objs = id;
id = 0;
@ -3117,7 +3082,6 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m)
continue;
total_done += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
}
spin_unlock(&vm->status_lock);
total_done_objs = id;
seq_printf(m, "\tTotal idle size: %12lld\tobjs:\t%d\n", total_idle,

View File

@ -205,11 +205,11 @@ struct amdgpu_vm_bo_base {
/* protected by bo being reserved */
struct amdgpu_vm_bo_base *next;
/* protected by vm status_lock */
/* protected by vm reservation and invalidated_lock */
struct list_head vm_status;
/* if the bo is counted as shared in mem stats
* protected by vm status_lock */
* protected by vm BO being reserved */
bool shared;
/* protected by the BO being reserved */
@ -345,10 +345,8 @@ struct amdgpu_vm {
bool evicting;
unsigned int saved_flags;
/* Lock to protect vm_bo add/del/move on all lists of vm */
spinlock_t status_lock;
/* Memory statistics for this vm, protected by status_lock */
/* Memory statistics for this vm, protected by stats_lock */
spinlock_t stats_lock;
struct amdgpu_mem_stats stats[__AMDGPU_PL_NUM];
/*
@ -356,6 +354,8 @@ struct amdgpu_vm {
* PDs, PTs or per VM BOs. The state transits are:
*
* evicted -> relocated (PDs, PTs) or moved (per VM BOs) -> idle
*
* Lists are protected by the root PD dma_resv lock.
*/
/* Per-VM and PT BOs who needs a validation */
@ -376,7 +376,10 @@ struct amdgpu_vm {
* state transits are:
*
* evicted_user or invalidated -> done
*
* Lists are protected by the invalidated_lock.
*/
spinlock_t invalidated_lock;
/* BOs for user mode queues that need a validation */
struct list_head evicted_user;

View File

@ -544,9 +544,7 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry)
entry->bo->vm_bo = NULL;
ttm_bo_set_bulk_move(&entry->bo->tbo, NULL);
spin_lock(&entry->vm->status_lock);
list_del(&entry->vm_status);
spin_unlock(&entry->vm->status_lock);
amdgpu_bo_unref(&entry->bo);
}
@ -590,7 +588,6 @@ static void amdgpu_vm_pt_add_list(struct amdgpu_vm_update_params *params,
struct amdgpu_vm_pt_cursor seek;
struct amdgpu_vm_bo_base *entry;
spin_lock(&params->vm->status_lock);
for_each_amdgpu_vm_pt_dfs_safe(params->adev, params->vm, cursor, seek, entry) {
if (entry && entry->bo)
list_move(&entry->vm_status, &params->tlb_flush_waitlist);
@ -598,7 +595,6 @@ static void amdgpu_vm_pt_add_list(struct amdgpu_vm_update_params *params,
/* enter start node now */
list_move(&cursor->entry->vm_status, &params->tlb_flush_waitlist);
spin_unlock(&params->vm->status_lock);
}
/**

View File

@ -161,7 +161,8 @@ union amd_sriov_msg_feature_flags {
uint32_t ras_telemetry : 1;
uint32_t ras_cper : 1;
uint32_t xgmi_ta_ext_peer_link : 1;
uint32_t reserved : 19;
uint32_t xgmi_connected_to_cpu : 1;
uint32_t reserved : 18;
} flags;
uint32_t all;
};

View File

@ -1298,7 +1298,7 @@ static void dce_v10_0_audio_write_speaker_allocation(struct drm_encoder *encoder
return;
}
sad_count = drm_edid_to_speaker_allocation(amdgpu_connector->edid, &sadb);
sad_count = drm_edid_to_speaker_allocation(drm_edid_raw(amdgpu_connector->edid), &sadb);
if (sad_count < 0) {
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
sad_count = 0;
@ -1368,7 +1368,7 @@ static void dce_v10_0_audio_write_sad_regs(struct drm_encoder *encoder)
return;
}
sad_count = drm_edid_to_sad(amdgpu_connector->edid, &sads);
sad_count = drm_edid_to_sad(drm_edid_raw(amdgpu_connector->edid), &sads);
if (sad_count < 0)
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
if (sad_count <= 0)

View File

@ -1265,7 +1265,7 @@ static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
return;
}
sad_count = drm_edid_to_speaker_allocation(amdgpu_connector->edid, &sadb);
sad_count = drm_edid_to_speaker_allocation(drm_edid_raw(amdgpu_connector->edid), &sadb);
if (sad_count < 0) {
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
sad_count = 0;
@ -1346,7 +1346,7 @@ static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
return;
}
sad_count = drm_edid_to_sad(amdgpu_connector->edid, &sads);
sad_count = drm_edid_to_sad(drm_edid_raw(amdgpu_connector->edid), &sads);
if (sad_count < 0)
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
if (sad_count <= 0)

View File

@ -1271,7 +1271,7 @@ static void dce_v8_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
return;
}
sad_count = drm_edid_to_speaker_allocation(amdgpu_connector->edid, &sadb);
sad_count = drm_edid_to_speaker_allocation(drm_edid_raw(amdgpu_connector->edid), &sadb);
if (sad_count < 0) {
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
sad_count = 0;
@ -1339,7 +1339,7 @@ static void dce_v8_0_audio_write_sad_regs(struct drm_encoder *encoder)
return;
}
sad_count = drm_edid_to_sad(amdgpu_connector->edid, &sads);
sad_count = drm_edid_to_sad(drm_edid_raw(amdgpu_connector->edid), &sads);
if (sad_count < 0)
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
if (sad_count <= 0)

View File

@ -1155,11 +1155,13 @@ static int gfx_v12_1_sw_init(struct amdgpu_ip_block *ip_block)
break;
}
/* recalculate compute rings to use based on hardware configuration */
num_compute_rings = (adev->gfx.mec.num_pipe_per_mec *
adev->gfx.mec.num_queue_per_pipe) / 2;
adev->gfx.num_compute_rings = min(adev->gfx.num_compute_rings,
num_compute_rings);
if (adev->gfx.num_compute_rings) {
/* recalculate compute rings to use based on hardware configuration */
num_compute_rings = (adev->gfx.mec.num_pipe_per_mec *
adev->gfx.mec.num_queue_per_pipe) / 2;
adev->gfx.num_compute_rings = min(adev->gfx.num_compute_rings,
num_compute_rings);
}
num_xcc = NUM_XCC(adev->gfx.xcc_mask);
@ -2794,6 +2796,33 @@ static void gfx_v12_1_xcc_fini(struct amdgpu_device *adev,
gfx_v12_1_xcc_enable_gui_idle_interrupt(adev, false, xcc_id);
}
static int gfx_v12_1_set_userq_eop_interrupts(struct amdgpu_device *adev,
bool enable)
{
unsigned int irq_type;
int m, p, r;
if (adev->gfx.disable_kq) {
for (m = 0; m < adev->gfx.mec.num_mec; ++m) {
for (p = 0; p < adev->gfx.mec.num_pipe_per_mec; p++) {
irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP
+ (m * adev->gfx.mec.num_pipe_per_mec)
+ p;
if (enable)
r = amdgpu_irq_get(adev, &adev->gfx.eop_irq,
irq_type);
else
r = amdgpu_irq_put(adev, &adev->gfx.eop_irq,
irq_type);
if (r)
return r;
}
}
}
return 0;
}
static int gfx_v12_1_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
@ -2801,6 +2830,7 @@ static int gfx_v12_1_hw_fini(struct amdgpu_ip_block *ip_block)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
gfx_v12_1_set_userq_eop_interrupts(adev, false);
num_xcc = NUM_XCC(adev->gfx.xcc_mask);
for (i = 0; i < num_xcc; i++) {
@ -2868,10 +2898,26 @@ static int gfx_v12_1_early_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
switch (amdgpu_user_queue) {
case -1:
default:
adev->gfx.disable_kq = true;
adev->gfx.disable_uq = true;
break;
case 0:
adev->gfx.disable_kq = false;
adev->gfx.disable_uq = true;
break;
}
adev->gfx.funcs = &gfx_v12_1_gfx_funcs;
adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
AMDGPU_MAX_COMPUTE_RINGS);
if (adev->gfx.disable_kq)
adev->gfx.num_compute_rings = 0;
else
adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
AMDGPU_MAX_COMPUTE_RINGS);
gfx_v12_1_set_kiq_pm4_funcs(adev);
gfx_v12_1_set_ring_funcs(adev);
@ -2898,6 +2944,10 @@ static int gfx_v12_1_late_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
r = gfx_v12_1_set_userq_eop_interrupts(adev, true);
if (r)
return r;
return 0;
}
@ -3630,12 +3680,6 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev,
return -EINVAL;
switch (me_id) {
case 0:
if (pipe_id == 0)
amdgpu_fence_process(&adev->gfx.gfx_ring[0]);
else
amdgpu_fence_process(&adev->gfx.gfx_ring[1]);
break;
case 1:
case 2:
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
@ -3652,6 +3696,9 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev,
amdgpu_fence_process(ring);
}
break;
default:
dev_dbg(adev->dev, "Unexpected me %d in eop_irq\n", me_id);
break;
}
}
@ -3719,29 +3766,23 @@ static void gfx_v12_1_handle_priv_fault(struct amdgpu_device *adev,
if (xcc_id == -EINVAL)
return;
switch (me_id) {
case 0:
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
/* we only enabled 1 gfx queue per pipe for now */
if (ring->me == me_id && ring->pipe == pipe_id)
drm_sched_fault(&ring->sched);
}
break;
case 1:
case 2:
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring
if (!adev->gfx.disable_kq) {
switch (me_id) {
case 1:
case 2:
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring
[i +
xcc_id * adev->gfx.num_compute_rings];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
drm_sched_fault(&ring->sched);
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
drm_sched_fault(&ring->sched);
}
break;
default:
dev_dbg(adev->dev, "Unexpected me %d in priv_fault\n", me_id);
break;
}
break;
default:
BUG();
break;
}
}

View File

@ -2355,7 +2355,7 @@ static int gfx_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++) {
ring = &adev->gfx.sw_gfx_ring[i];
ring->ring_obj = NULL;
sprintf(ring->name, amdgpu_sw_ring_name(i));
strscpy(ring->name, amdgpu_sw_ring_name(i), sizeof(ring->name));
ring->use_doorbell = true;
ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1;
ring->is_sw_ring = true;

View File

@ -121,7 +121,7 @@ static int gmc_v12_1_process_interrupt(struct amdgpu_device *adev,
if (entry->src_id == UTCL2_1_0__SRCID__RETRY) {
retry_fault = true;
write_fault = !!(entry->src_data[1] & 0x200000);
write_fault = !!(entry->src_data[1] & AMDGPU_GMC121_FAULT_SOURCE_DATA_WRITE);
}
if (entry->client_id == SOC_V1_0_IH_CLIENTID_VMC) {

View File

@ -289,6 +289,13 @@ static uint32_t ih_v7_0_setup_retry_doorbell(u32 doorbell_index)
return val;
}
#define regIH_RING1_CLIENT_CFG_INDEX_V7_1 0x122
#define regIH_RING1_CLIENT_CFG_INDEX_V7_1_BASE_IDX 0
#define regIH_RING1_CLIENT_CFG_DATA_V7_1 0x123
#define regIH_RING1_CLIENT_CFG_DATA_V7_1_BASE_IDX 0
#define regIH_CHICKEN_V7_1 0x129
#define regIH_CHICKEN_V7_1_BASE_IDX 0
/**
* ih_v7_0_irq_init - init and enable the interrupt ring
*
@ -307,6 +314,7 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev)
u32 tmp;
int ret;
int i;
u32 reg_addr;
/* disable irqs */
ret = ih_v7_0_toggle_interrupts(adev, false);
@ -318,10 +326,15 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev)
if (unlikely((adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) ||
(adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO))) {
if (ih[0]->use_bus_addr) {
ih_chicken = RREG32_SOC15(OSSSYS, 0, regIH_CHICKEN);
if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0))
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_CHICKEN_V7_1);
else
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_CHICKEN);
ih_chicken = RREG32(reg_addr);
/* The reg fields definitions are identical in ih v7_0 and ih v7_1 */
ih_chicken = REG_SET_FIELD(ih_chicken,
IH_CHICKEN, MC_SPACE_GPA_ENABLE, 1);
WREG32_SOC15(OSSSYS, 0, regIH_CHICKEN, ih_chicken);
WREG32(reg_addr, ih_chicken);
}
}
@ -358,17 +371,26 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev)
/* Redirect the interrupts to IH RB1 for dGPU */
if (adev->irq.ih1.ring_size) {
tmp = RREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX);
if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0))
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX_V7_1);
else
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX);
tmp = RREG32(reg_addr);
/* The reg fields definitions are identical in ih v7_0 and ih v7_1 */
tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_INDEX, INDEX, 0);
WREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX, tmp);
WREG32(reg_addr, tmp);
tmp = RREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA);
if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0))
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA_V7_1);
else
reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA);
tmp = RREG32(reg_addr);
/* The reg fields definitions are identical in ih v7_0 and ih v7_1 */
tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA, CLIENT_ID, 0xa);
tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA, SOURCE_ID, 0x0);
tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA,
SOURCE_ID_MATCH_ENABLE, 0x1);
WREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA, tmp);
WREG32(reg_addr, tmp);
}
pci_set_master(adev->pdev);

View File

@ -0,0 +1,99 @@
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/delay.h>
#include "amdgpu.h"
#include "lsdma_v7_1.h"
#include "amdgpu_lsdma.h"
#include "lsdma/lsdma_7_1_0_offset.h"
#include "lsdma/lsdma_7_1_0_sh_mask.h"
static int lsdma_v7_1_wait_pio_status(struct amdgpu_device *adev)
{
return amdgpu_lsdma_wait_for(adev, SOC15_REG_OFFSET(LSDMA, 0, regLSDMA_PIO_STATUS),
LSDMA_PIO_STATUS__PIO_IDLE_MASK | LSDMA_PIO_STATUS__PIO_FIFO_EMPTY_MASK,
LSDMA_PIO_STATUS__PIO_IDLE_MASK | LSDMA_PIO_STATUS__PIO_FIFO_EMPTY_MASK);
}
static int lsdma_v7_1_copy_mem(struct amdgpu_device *adev,
uint64_t src_addr,
uint64_t dst_addr,
uint64_t size)
{
int ret;
uint32_t tmp;
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_SRC_ADDR_LO, lower_32_bits(src_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_SRC_ADDR_HI, upper_32_bits(src_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_DST_ADDR_LO, lower_32_bits(dst_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_DST_ADDR_HI, upper_32_bits(dst_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_CONTROL, 0x0);
tmp = RREG32_SOC15(LSDMA, 0, regLSDMA_PIO_COMMAND);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, COUNT, size);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, RAW_WAIT, 0);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, CONSTANT_FILL, 0);
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_COMMAND, tmp);
ret = lsdma_v7_1_wait_pio_status(adev);
if (ret)
dev_err(adev->dev, "LSDMA PIO failed to copy memory!\n");
return ret;
}
static int lsdma_v7_1_fill_mem(struct amdgpu_device *adev,
uint64_t dst_addr,
uint32_t data,
uint64_t size)
{
int ret;
uint32_t tmp;
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_CONSTFILL_DATA, data);
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_DST_ADDR_LO, lower_32_bits(dst_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_DST_ADDR_HI, upper_32_bits(dst_addr));
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_CONTROL, 0x0);
tmp = RREG32_SOC15(LSDMA, 0, regLSDMA_PIO_COMMAND);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, COUNT, size);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, RAW_WAIT, 0);
tmp = REG_SET_FIELD(tmp, LSDMA_PIO_COMMAND, CONSTANT_FILL, 1);
WREG32_SOC15(LSDMA, 0, regLSDMA_PIO_COMMAND, tmp);
ret = lsdma_v7_1_wait_pio_status(adev);
if (ret)
dev_err(adev->dev, "LSDMA PIO failed to fill memory!\n");
return ret;
}
const struct amdgpu_lsdma_funcs lsdma_v7_1_funcs = {
.copy_mem = lsdma_v7_1_copy_mem,
.fill_mem = lsdma_v7_1_fill_mem,
};

View File

@ -0,0 +1,31 @@
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __LSDMA_V7_1_H__
#define __LSDMA_V7_1_H__
#include "soc15_common.h"
extern const struct amdgpu_lsdma_funcs lsdma_v7_1_funcs;
#endif /* __LSDMA_V7_1_H__ */

View File

@ -731,6 +731,9 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe)
int i;
struct amdgpu_device *adev = mes->adev;
union MESAPI_SET_HW_RESOURCES mes_set_hw_res_pkt;
uint32_t mes_rev = (pipe == AMDGPU_MES_SCHED_PIPE) ?
(mes->sched_version & AMDGPU_MES_VERSION_MASK) :
(mes->kiq_version & AMDGPU_MES_VERSION_MASK);
memset(&mes_set_hw_res_pkt, 0, sizeof(mes_set_hw_res_pkt));
@ -785,7 +788,7 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe)
* handling support, other queue will not use the oversubscribe timer.
* handling mode - 0: disabled; 1: basic version; 2: basic+ version
*/
mes_set_hw_res_pkt.oversubscription_timer = 50;
mes_set_hw_res_pkt.oversubscription_timer = mes_rev < 0x8b ? 0 : 50;
mes_set_hw_res_pkt.unmapped_doorbell_handling = 1;
if (amdgpu_mes_log_enable) {

View File

@ -1611,7 +1611,6 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[inst],
&adev->mes.eop_gpu_addr[inst],
NULL);
amdgpu_ucode_release(&adev->mes.fw[inst]);
if (adev->enable_uni_mes || pipe == AMDGPU_MES_SCHED_PIPE) {
amdgpu_bo_free_kernel(&adev->mes.ring[inst].mqd_obj,
@ -1622,6 +1621,9 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block)
}
}
for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++)
amdgpu_ucode_release(&adev->mes.fw[pipe]);
for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) {
if (!adev->enable_uni_mes) {
amdgpu_bo_free_kernel(&adev->gfx.kiq[xcc_id].ring.mqd_obj,

View File

@ -478,7 +478,7 @@ static int soc24_common_hw_init(struct amdgpu_ip_block *ip_block)
if (adev->nbio.funcs->remap_hdp_registers)
adev->nbio.funcs->remap_hdp_registers(adev);
if (adev->df.funcs->hw_init)
if (adev->df.funcs && adev->df.funcs->hw_init)
adev->df.funcs->hw_init(adev);
/* enable the doorbell aperture */

View File

@ -57,7 +57,7 @@ static void soc_v1_0_doorbell_index_init(struct amdgpu_device *adev)
adev->doorbell_index.userqueue_end = AMDGPU_SOC_V1_0_DOORBELL_USERQUEUE_END;
adev->doorbell_index.xcc_doorbell_range = AMDGPU_SOC_V1_0_DOORBELL_XCC_RANGE;
adev->doorbell_index.sdma_doorbell_range = 20;
adev->doorbell_index.sdma_doorbell_range = 14;
for (i = 0; i < adev->sdma.num_instances; i++)
adev->doorbell_index.sdma_engine[i] =
AMDGPU_SOC_V1_0_DOORBELL_sDMA_ENGINE_START +
@ -214,23 +214,35 @@ static bool soc_v1_0_need_full_reset(struct amdgpu_device *adev)
static bool soc_v1_0_need_reset_on_init(struct amdgpu_device *adev)
{
u32 sol_reg;
if (adev->flags & AMD_IS_APU)
return false;
/* Check sOS sign of life register to confirm sys driver and sOS
* are already been loaded.
*/
sol_reg = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_81);
if (sol_reg)
return true;
return false;
}
static enum amd_reset_method
soc_v1_0_asic_reset_method(struct amdgpu_device *adev)
{
if ((adev->gmc.xgmi.supported && adev->gmc.xgmi.connected_to_cpu) ||
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 8))) {
if (amdgpu_reset_method != -1)
dev_warn_once(adev->dev, "Reset override isn't supported, using Mode2 instead.\n");
return AMD_RESET_METHOD_MODE2;
}
return amdgpu_reset_method;
}
static int soc_v1_0_asic_reset(struct amdgpu_device *adev)
{
switch (soc_v1_0_asic_reset_method(adev)) {
case AMD_RESET_METHOD_MODE2:
dev_info(adev->dev, "MODE2 reset\n");
return amdgpu_dpm_mode2_reset(adev);
default:
dev_info(adev->dev, "Invalid reset method Not supported\n");
return -EOPNOTSUPP;
}
return 0;
}
@ -244,6 +256,7 @@ static const struct amdgpu_asic_funcs soc_v1_0_asic_funcs = {
.need_reset_on_init = &soc_v1_0_need_reset_on_init,
.encode_ext_smn_addressing = &soc_v1_0_encode_ext_smn_addressing,
.reset = soc_v1_0_asic_reset,
.reset_method = &soc_v1_0_asic_reset_method,
};
static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block)
@ -268,7 +281,8 @@ static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block)
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
case IP_VERSION(12, 1, 0):
adev->cg_flags = 0;
adev->cg_flags = AMD_CG_SUPPORT_GFX_CGCG |
AMD_CG_SUPPORT_GFX_CGLS;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x50;
break;
@ -809,7 +823,7 @@ int soc_v1_0_init_soc_config(struct amdgpu_device *adev)
{
int ret, i;
int xcc_inst_per_aid = 4;
uint16_t xcc_mask;
uint16_t xcc_mask, sdma_mask = 0;
xcc_mask = adev->gfx.xcc_mask;
adev->aid_mask = 0;
@ -819,10 +833,12 @@ int soc_v1_0_init_soc_config(struct amdgpu_device *adev)
}
adev->sdma.num_inst_per_xcc = 2;
adev->sdma.num_instances =
NUM_XCC(adev->gfx.xcc_mask) * adev->sdma.num_inst_per_xcc;
adev->sdma.sdma_mask =
GENMASK(adev->sdma.num_instances - 1, 0);
for_each_inst(i, adev->gfx.xcc_mask)
sdma_mask |=
GENMASK(adev->sdma.num_inst_per_xcc - 1, 0) <<
(i * adev->sdma.num_inst_per_xcc);
adev->sdma.sdma_mask = sdma_mask;
adev->sdma.num_instances = NUM_XCC(adev->sdma.sdma_mask);
ret = soc_v1_0_xcp_mgr_init(adev);
if (ret)

View File

@ -2720,7 +2720,7 @@ static int get_wave_state(struct device_queue_manager *dqm,
ctl_stack, ctl_stack_used_size, save_area_used_size);
}
static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
static int get_queue_checkpoint_info(struct device_queue_manager *dqm,
const struct queue *q,
u32 *mqd_size,
u32 *ctl_stack_size)
@ -2728,6 +2728,7 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
struct mqd_manager *mqd_mgr;
enum KFD_MQD_TYPE mqd_type =
get_mqd_type_from_queue_type(q->properties.type);
int ret = 0;
dqm_lock(dqm);
mqd_mgr = dqm->mqd_mgrs[mqd_type];
@ -2735,9 +2736,11 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
*ctl_stack_size = 0;
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info)
mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);
ret = mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);
dqm_unlock(dqm);
return ret;
}
static int checkpoint_mqd(struct device_queue_manager *dqm,

View File

@ -192,7 +192,7 @@ struct device_queue_manager_ops {
int (*reset_queues)(struct device_queue_manager *dqm,
uint16_t pasid);
void (*get_queue_checkpoint_info)(struct device_queue_manager *dqm,
int (*get_queue_checkpoint_info)(struct device_queue_manager *dqm,
const struct queue *q, u32 *mqd_size,
u32 *ctl_stack_size);

View File

@ -102,7 +102,8 @@ struct mqd_manager {
u32 *ctl_stack_used_size,
u32 *save_area_used_size);
void (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, uint32_t *ctl_stack_size);
int (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd,
uint32_t *ctl_stack_size);
void (*checkpoint_mqd)(struct mqd_manager *mm,
void *mqd,

View File

@ -385,11 +385,14 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
return 0;
}
static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
{
struct v9_mqd *m = get_mqd(mqd);
*ctl_stack_size = m->cp_hqd_cntl_stack_size * NUM_XCC(mm->dev->xcc_mask);
if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size))
return -EINVAL;
return 0;
}
static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)

View File

@ -274,10 +274,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
return 0;
}
static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
{
/* Control stack is stored in user mode */
*ctl_stack_size = 0;
return 0;
}
static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)

View File

@ -585,7 +585,7 @@ static void kfd_procfs_add_sysfs_stats(struct kfd_process *p)
ret = kobject_init_and_add(pdd->kobj_stats,
&procfs_stats_type,
p->kobj,
stats_dir_filename);
"%s", stats_dir_filename);
if (ret) {
pr_warn("Creating KFD proc/stats_%s folder failed",
@ -632,7 +632,7 @@ static void kfd_procfs_add_sysfs_counters(struct kfd_process *p)
return;
ret = kobject_init_and_add(kobj_counters, &sysfs_counters_type,
p->kobj, counters_dir_filename);
p->kobj, "%s", counters_dir_filename);
if (ret) {
pr_warn("Creating KFD proc/%s folder failed",
counters_dir_filename);

View File

@ -593,6 +593,7 @@ int pqm_update_queue_properties(struct process_queue_manager *pqm,
p->queue_size)) {
pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n",
p->queue_address, p->queue_size);
amdgpu_bo_unreserve(vm->root.bo);
return -EFAULT;
}
@ -1069,6 +1070,7 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm,
uint32_t *ctl_stack_size)
{
struct process_queue_node *pqn;
int ret;
pqn = get_queue_by_qid(pqm, qid);
if (!pqn) {
@ -1081,9 +1083,14 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm,
return -EOPNOTSUPP;
}
pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm,
ret = pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm,
pqn->q, mqd_size,
ctl_stack_size);
if (ret) {
pr_debug("amdkfd: Overflow while computing stack size for queue %d\n", qid);
return ret;
}
return 0;
}

View File

@ -2473,6 +2473,8 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_7_SCRATCH_MEM
DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_IB_MEM
DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_SHARED_STATE
DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_LSDMA_BUFFER
DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_CURSOR_OFFLOAD
};
int r;

View File

@ -62,6 +62,9 @@ static const uint32_t rgb_formats[] = {
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_RGB565,
DRM_FORMAT_NV21,
DRM_FORMAT_NV12,
DRM_FORMAT_P010
};
static const uint32_t overlay_formats[] = {
@ -1908,7 +1911,8 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
drm_plane_create_zpos_immutable_property(plane, 255);
}
if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
if ((plane->type == DRM_PLANE_TYPE_PRIMARY ||
plane->type == DRM_PLANE_TYPE_OVERLAY) &&
plane_cap &&
(plane_cap->pixel_format_support.nv12 ||
plane_cap->pixel_format_support.p010)) {

View File

@ -794,13 +794,11 @@ static enum bp_result bios_parser_external_encoder_control(
static enum bp_result bios_parser_dac_load_detection(
struct dc_bios *dcb,
enum engine_id engine_id,
struct graphics_object_id ext_enc_id)
enum engine_id engine_id)
{
struct bios_parser *bp = BP_FROM_DCB(dcb);
struct dc_context *ctx = dcb->ctx;
struct bp_load_detection_parameters bp_params = {0};
struct bp_external_encoder_control ext_cntl = {0};
enum bp_result bp_result = BP_RESULT_UNSUPPORTED;
uint32_t bios_0_scratch;
uint32_t device_id_mask = 0;
@ -826,13 +824,6 @@ static enum bp_result bios_parser_dac_load_detection(
bp_params.engine_id = engine_id;
bp_result = bp->cmd_tbl.dac_load_detection(bp, &bp_params);
} else if (ext_enc_id.id) {
if (!bp->cmd_tbl.external_encoder_control)
return BP_RESULT_UNSUPPORTED;
ext_cntl.action = EXTERNAL_ENCODER_CONTROL_DAC_LOAD_DETECT;
ext_cntl.encoder_id = ext_enc_id;
bp_result = bp->cmd_tbl.external_encoder_control(bp, &ext_cntl);
}
if (bp_result != BP_RESULT_OK)

View File

@ -48,6 +48,7 @@
#include "dcn32/dcn32_clk_mgr.h"
#include "dcn35/dcn35_clk_mgr.h"
#include "dcn401/dcn401_clk_mgr.h"
#include "dcn42/dcn42_clk_mgr.h"
int clk_mgr_helper_get_active_display_cnt(
struct dc *dc,
@ -362,6 +363,18 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
return &clk_mgr->base;
}
break;
case AMDGPU_FAMILY_GC_11_5_4: {
struct clk_mgr_dcn42 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);
if (clk_mgr == NULL) {
BREAK_TO_DEBUGGER();
return NULL;
}
dcn42_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base.base;
}
break;
#endif /* CONFIG_DRM_AMD_DC_FP */
default:
ASSERT(0); /* Unknown Asic */
@ -419,6 +432,9 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
case AMDGPU_FAMILY_GC_12_0_0:
dcn401_clk_mgr_destroy(clk_mgr);
break;
case AMDGPU_FAMILY_GC_11_5_4:
dcn42_clk_mgr_destroy(clk_mgr);
break;
default:
break;

View File

@ -547,6 +547,7 @@ void dcn3_clk_mgr_construct(
/* in case we don't get a value from the register, use default */
if (clk_mgr->base.dentist_vco_freq_khz == 0)
clk_mgr->base.dentist_vco_freq_khz = 3650000;
/* Convert dprefclk units from MHz to KHz */
/* Value already divided by 10, some resolution lost */

View File

@ -31,59 +31,19 @@
#include "link_service.h"
#include "logger_types.h"
#include "clk/clk_15_0_0_offset.h"
#include "clk/clk_15_0_0_sh_mask.h"
#include "dcn/dcn_4_2_0_offset.h"
#include "dcn/dcn_4_2_0_sh_mask.h"
#undef DC_LOGGER
#define DC_LOGGER \
clk_mgr->base.base.ctx->logger
#define DCN_BASE__INST0_SEG1 0x000000C0
#define regCLK8_CLK2_BYPASS_CNTL 0x4c2a
#define regCLK8_CLK2_BYPASS_CNTL_BASE_IDX 0
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL__SHIFT 0x0
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV__SHIFT 0x10
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK 0x00000007L
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV_MASK 0x000F0000L
#define regDENTIST_DISPCLK_CNTL 0x0064
#define regDENTIST_DISPCLK_CNTL_BASE_IDX 1
// DENTIST_DISPCLK_CNTL
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_WDIVIDER__SHIFT 0x0
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_RDIVIDER__SHIFT 0x8
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_CHG_DONE__SHIFT 0x13
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_CHG_DONE__SHIFT 0x14
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_WDIVIDER__SHIFT 0x18
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_WDIVIDER_MASK 0x0000007FL
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_RDIVIDER_MASK 0x00007F00L
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_CHG_DONE_MASK 0x00080000L
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_CHG_DONE_MASK 0x00100000L
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_WDIVIDER_MASK 0x7F000000L
#define mmDENTIST_DISPCLK_CNTL 0x0124
#define mmCLK8_CLK_TICK_CNT_CONFIG_REG 0x1B851
#define mmCLK8_CLK0_CURRENT_CNT 0x1B853
#define mmCLK8_CLK1_CURRENT_CNT 0x1B854
#define mmCLK8_CLK2_CURRENT_CNT 0x1B855
#define mmCLK8_CLK3_CURRENT_CNT 0x1B856
#define mmCLK8_CLK4_CURRENT_CNT 0x1B857
#define mmCLK8_CLK0_BYPASS_CNTL 0x1B81A
#define mmCLK8_CLK1_BYPASS_CNTL 0x1B822
#define mmCLK8_CLK2_BYPASS_CNTL 0x1B82A
#define mmCLK8_CLK3_BYPASS_CNTL 0x1B832
#define mmCLK8_CLK4_BYPASS_CNTL 0x1B83A
#define mmCLK8_CLK0_DS_CNTL 0x1B814
#define mmCLK8_CLK1_DS_CNTL 0x1B81C
#define mmCLK8_CLK2_DS_CNTL 0x1B824
#define mmCLK8_CLK3_DS_CNTL 0x1B82C
#define mmCLK8_CLK4_DS_CNTL 0x1B834
dc_logger
#define DC_LOGGER_INIT(logger) \
struct dal_logger *dc_logger = logger
#define DCN42_CLKIP_REFCLK 48000
#undef FN
#define FN(reg_name, field_name) \
@ -92,16 +52,25 @@
#define REG(reg) \
(clk_mgr->regs->reg)
// for DCN register access
#define DCN_BASE__INST0_SEG0 0x00000012
#define DCN_BASE__INST0_SEG1 0x000000C0
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
#define SR(reg_name)\
.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
reg ## reg_name
#define SR(reg_name) \
.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
#define CLK_SR_DCN42(reg_name)\
.reg_name = mm ## reg_name
// for CLKIP register access
#define CLK_BASE__INST0_SEG0 0x00016C00
#define CLK_BASE_INNER(seg) \
CLK_BASE__INST0_SEG ## seg
#define CLK_SR_DCN42(reg_name) \
.reg_name = CLK_BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
static const struct clk_mgr_registers clk_mgr_regs_dcn42 = {
CLK_REG_LIST_DCN42()
@ -115,26 +84,21 @@ static const struct clk_mgr_mask clk_mgr_mask_dcn42 = {
CLK_COMMON_MASK_SH_LIST_DCN42(_MASK)
};
#define TO_CLK_MGR_DCN42(clk_mgr_int)\
container_of(clk_mgr_int, struct clk_mgr_dcn42, base)
int dcn42_get_active_display_cnt_wa(
struct dc *dc,
struct dc_state *context,
int *all_active_disps)
bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context)
{
int i, display_count = 0;
bool tmds_present = false;
int i, active_count = 0;
for (i = 0; i < context->stream_count; i++) {
const struct dc_stream_state *stream = context->streams[i];
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
tmds_present = true;
/* Checking stream / link detection ensuring that PHY is active*/
if (dc_is_hdmi_signal(stream->signal) ||
dc_is_dvi_signal(stream->signal) ||
(dc_is_dp_signal(stream->signal) && !stream->dpms_off))
active_count++;
}
for (i = 0; i < dc->link_count; i++) {
@ -143,15 +107,53 @@ int dcn42_get_active_display_cnt_wa(
/* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc))
display_count++;
active_count++;
}
if (all_active_disps != NULL)
*all_active_disps = display_count;
/* WA for hang on HDMI after display off back on*/
if (display_count == 0 && tmds_present)
display_count = 1;
return display_count;
return active_count > 0;
}
static uint32_t dcn42_get_clock_freq_from_clkip(struct clk_mgr *clk_mgr_base, enum clock_type clock)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
uint64_t clock_freq_mhz = 0;
uint32_t timer_threshold = 0;
// always safer to read the timer threshold instead of using cached value
REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &timer_threshold);
if (timer_threshold == 0) {
BREAK_TO_DEBUGGER();
return 0;
}
switch (clock) {
case clock_type_dispclk:
clock_freq_mhz = REG_READ(CLK8_CLK0_CURRENT_CNT);
break;
case clock_type_dppclk:
clock_freq_mhz = REG_READ(CLK8_CLK1_CURRENT_CNT);
break;
case clock_type_dprefclk:
clock_freq_mhz = REG_READ(CLK8_CLK2_CURRENT_CNT);
break;
case clock_type_dcfclk:
clock_freq_mhz = REG_READ(CLK8_CLK3_CURRENT_CNT);
break;
case clock_type_dtbclk:
clock_freq_mhz = REG_READ(CLK8_CLK4_CURRENT_CNT);
break;
default:
break;
}
clock_freq_mhz *= DCN42_CLKIP_REFCLK;
clock_freq_mhz = div_u64(clock_freq_mhz, timer_threshold);
// there are no DCN clocks over 0xFFFFFFFF MHz
ASSERT(clock_freq_mhz <= 0xFFFFFFFF);
return (uint32_t)clock_freq_mhz;
}
void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
@ -213,22 +215,18 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
struct dc *dc = clk_mgr_base->ctx->dc;
int display_count = 0;
bool update_dppclk = false;
bool update_dispclk = false;
bool dpp_clock_lowered = false;
int all_active_disps = 0;
bool has_active_display;
if (dc->work_arounds.skip_clock_update)
return;
display_count = dcn42_get_active_display_cnt_wa(dc, context, &all_active_disps);
has_active_display = dcn42_has_active_display(dc, context);
/*dml21 issue*/
ASSERT(new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz > 590000); //remove this section if assert is hit
if (new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz < 590000)
new_clocks->ref_dtbclk_khz = 600000;
/*
* if it is safe to lower, but we are already in the lower state, we don't have to do anything
* also if safe to lower is false, we just go in the higher state
@ -248,7 +246,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
/* check that we're not already in lower */
if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
/* if we can go lower, go lower */
if (display_count == 0)
if (has_active_display == false)
clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
}
} else {
@ -262,9 +260,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
dcn42_smu_set_dtbclk(clk_mgr, true);
if (clk_mgr_base->boot_snapshot.timer_threhold)
actual_dtbclk = REG_READ(CLK8_CLK4_CURRENT_CNT) / (clk_mgr_base->boot_snapshot.timer_threhold / 48000);
actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
if (actual_dtbclk > 590000) {
clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
@ -308,7 +304,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
}
if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
(new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) {
(new_clocks->dispclk_khz > 0 || (safe_to_lower && has_active_display == false))) {
int requested_dispclk_khz = new_clocks->dispclk_khz;
dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true);
@ -386,34 +382,27 @@ bool dcn42_are_clock_states_equal(struct dc_clocks *a,
static void dcn42_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
uint32_t ratio = 1;
internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD = REG_READ(CLK8_CLK_TICK_CNT_CONFIG_REG) & 0xFFFFFF;
ratio = internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD / 48000;
ASSERT(ratio != 0);
if (ratio) {
// read dcf deep sleep divider
internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
// read dispclk
internal->CLK8_CLK0_CURRENT_CNT = REG_READ(CLK8_CLK0_CURRENT_CNT) / ratio;
internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
// read dppclk
internal->CLK8_CLK1_CURRENT_CNT = REG_READ(CLK8_CLK1_CURRENT_CNT) / ratio;
internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
// read dprefclk
internal->CLK8_CLK2_CURRENT_CNT = REG_READ(CLK8_CLK2_CURRENT_CNT) / ratio;
internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
// read dcfclk
internal->CLK8_CLK3_CURRENT_CNT = REG_READ(CLK8_CLK3_CURRENT_CNT) / ratio;
internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
// read dtbclk
internal->CLK8_CLK4_CURRENT_CNT = REG_READ(CLK8_CLK4_CURRENT_CNT) / ratio;
internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
}
REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD);
// read dcf deep sleep divider
internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
// read dispclk
internal->CLK8_CLK0_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dispclk);
internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
// read dppclk
internal->CLK8_CLK1_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dppclk);
internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
// read dprefclk
internal->CLK8_CLK2_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dprefclk);
internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
// read dcfclk
internal->CLK8_CLK3_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dcfclk);
internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
// read dtbclk
internal->CLK8_CLK4_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
}
static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
@ -422,8 +411,11 @@ static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs
struct dcn42_clk_internal internal = {0};
char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};
DC_LOGGER_INIT(clk_mgr->base.base.ctx->logger);
(void)dc_logger;
dcn42_dump_clk_registers_internal(&internal, &clk_mgr->base.base);
regs_and_bypass->timer_threhold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
regs_and_bypass->dcfclk = internal.CLK8_CLK3_CURRENT_CNT / 10;
regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK3_DS_CNTL / 10;
regs_and_bypass->dcf_deep_sleep_allow = internal.CLK8_CLK3_DS_CNTL & 0x10; /*bit 4: CLK0_ALLOW_DS*/
@ -432,18 +424,10 @@ static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs
regs_and_bypass->dppclk = internal.CLK8_CLK1_CURRENT_CNT / 10;
regs_and_bypass->dtbclk = internal.CLK8_CLK4_CURRENT_CNT / 10;
regs_and_bypass->dppclk_bypass = internal.CLK8_CLK1_BYPASS_CNTL & 0x0007;
if (regs_and_bypass->dppclk_bypass > 4)
regs_and_bypass->dppclk_bypass = 0;
regs_and_bypass->dcfclk_bypass = internal.CLK8_CLK3_BYPASS_CNTL & 0x0007;
if (regs_and_bypass->dcfclk_bypass > 4)
regs_and_bypass->dcfclk_bypass = 0;
regs_and_bypass->dispclk_bypass = internal.CLK8_CLK0_BYPASS_CNTL & 0x0007;
if (regs_and_bypass->dispclk_bypass > 4)
regs_and_bypass->dispclk_bypass = 0;
regs_and_bypass->dprefclk_bypass = internal.CLK8_CLK2_BYPASS_CNTL & 0x0007;
if (regs_and_bypass->dprefclk_bypass > 4)
regs_and_bypass->dprefclk_bypass = 0;
regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL);
regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL);
regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL);
regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL);
if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
@ -467,7 +451,6 @@ static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs
// REGISTER VALUES
DC_LOG_SMU("reg_name,value,clk_type\n");
DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n",
internal.CLK8_CLK3_CURRENT_CNT);
@ -588,6 +571,9 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 };
DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
(void)dc_logger;
init_clk_states(clk_mgr_base);
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
@ -597,6 +583,7 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
else
clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz;
DC_LOG_SMU("dp_dto_source_clock %d, dprefclk %d\n", clk_mgr_base->dp_dto_source_clock_in_khz, clk_mgr_base->dprefclk_khz);
dcn42_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr);
clk_mgr_base->clks.ref_dtbclk_khz = clk_mgr_base->boot_snapshot.dtbclk * 10;
@ -605,6 +592,12 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
clk_mgr_base->clks.dtbclk_en = true;
}
if (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels != 0) {
/*skip to get clock table and notify pmfw watermark range again*/
DC_LOG_SMU("skip to get dpm_clks from pmfw from resume and acr\n");
return;
}
smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem(
clk_mgr_base->ctx,
DC_MEM_ALLOC_TYPE_GART,
@ -711,10 +704,9 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
/* DTBCLK*/
clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = clk_mgr_base->clks.ref_dtbclk_khz / 1000;
clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1;
/* Refresh bounding box */
clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
}
}
if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
@ -826,7 +818,6 @@ static void dcn42_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr)
}
}
/* Exposed for dcn42b reuse */
void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table)
{
int i, num_valid_sets;
@ -885,18 +876,42 @@ void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_
void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
{
int i = 0;
struct dcn42_watermarks *table = NULL;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
struct clk_mgr_dcn42 *clk_mgr_dcn42 = TO_CLK_MGR_DCN42(clk_mgr);
struct dcn42_watermarks *table = clk_mgr_dcn42->smu_wm_set.wm_set;
if (!clk_mgr->smu_ver)
return;
/*send once already skip*/
if (clk_mgr_base->bw_params->wm_table.entries[WM_A].valid == true)
return;
clk_mgr_dcn42->smu_wm_set.wm_set = (struct dcn42_watermarks *)dm_helpers_allocate_gpu_mem(
clk_mgr->base.ctx,
DC_MEM_ALLOC_TYPE_GART,
sizeof(struct dcn42_watermarks),
&clk_mgr_dcn42->smu_wm_set.mc_address.quad_part);
ASSERT(clk_mgr_dcn42->smu_wm_set.wm_set);
table = clk_mgr_dcn42->smu_wm_set.wm_set;
if (!table || clk_mgr_dcn42->smu_wm_set.mc_address.quad_part == 0)
return;
memset(table, 0, sizeof(*table));
/*same as previous asic, set wm valid before building watermark ranges*/
for (i = 0; i < WM_SET_COUNT; i++) {
clk_mgr_base->bw_params->wm_table.entries[i].wm_inst = i;
if (i >= clk_mgr_base->bw_params->clk_table.num_entries) {
clk_mgr_base->bw_params->wm_table.entries[i].valid = false;
continue;
}
clk_mgr_base->bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
clk_mgr_base->bw_params->wm_table.entries[i].valid = true;
}
/* build watermark_range will check this valid range*/
dcn42_build_watermark_ranges(clk_mgr_base->bw_params, table);
dcn42_smu_set_dram_addr_high(clk_mgr,
@ -904,18 +919,21 @@ void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
dcn42_smu_set_dram_addr_low(clk_mgr,
clk_mgr_dcn42->smu_wm_set.mc_address.low_part);
dcn42_smu_transfer_wm_table_dram_2_smu(clk_mgr);
if (clk_mgr_dcn42->smu_wm_set.wm_set && clk_mgr_dcn42->smu_wm_set.mc_address.quad_part != 0)
dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
clk_mgr_dcn42->smu_wm_set.wm_set);
}
void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base)
{
int display_count;
struct dc *dc = clk_mgr_base->ctx->dc;
struct dc_state *context = dc->current_state;
if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
display_count = dcn42_get_active_display_cnt_wa(dc, context, NULL);
/* if we can go lower, go lower */
if (display_count == 0)
if (dcn42_has_active_display(dc, context) == false)
clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
}
@ -1096,14 +1114,7 @@ void dcn42_clk_mgr_construct(
clk_mgr->base.dprefclk_ss_divider = 1000;
clk_mgr->base.ss_on_dprefclk = false;
clk_mgr->base.dfs_ref_freq_khz = 48000; /*sync with pmfw*/
clk_mgr->smu_wm_set.wm_set = (struct dcn42_watermarks *)dm_helpers_allocate_gpu_mem(
clk_mgr->base.base.ctx,
DC_MEM_ALLOC_TYPE_GART,
sizeof(struct dcn42_watermarks),
&clk_mgr->smu_wm_set.mc_address.quad_part);
ASSERT(clk_mgr->smu_wm_set.wm_set);
clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
/* Changed from DCN3.2_clock_frequency doc to match
* dcn32_dump_clk_registers from 4 * dentist_vco_freq_khz /
@ -1112,6 +1123,9 @@ void dcn42_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = 600000;
clk_mgr->base.smu_present = false;
clk_mgr->base.smu_ver = dcn42_smu_get_pmfw_version(&clk_mgr->base);
if (clk_mgr->base.smu_ver && clk_mgr->base.smu_ver != -1)
clk_mgr->base.smu_present = true;
if (ctx->dc_bios->integrated_info) {
clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq;
@ -1122,7 +1136,9 @@ void dcn42_clk_mgr_construct(
dcn42_bw_params.wm_table = ddr5_wm_table;
dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type;
dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4;
dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 4;
dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 1;
clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base);
clk_mgr->base.base.clks.ref_dtbclk_khz = dcn42_smu_get_dtbclk(&clk_mgr->base);
}
/* in case we don't get a value from the BIOS, use default */
if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
@ -1131,9 +1147,6 @@ void dcn42_clk_mgr_construct(
/* Saved clocks configured at boot for debug purposes */
dcn42_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);
if (clk_mgr->base.smu_present)
clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base);
clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
dce_clock_read_ss_info(&clk_mgr->base);
/*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/

View File

@ -59,7 +59,6 @@ void dcn42_clk_mgr_construct(struct dc_context *ctx,
void dcn42_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int);
/* Exposed for dcn42b reuse */
void dcn42_init_single_clock(unsigned int *entry_0,
uint32_t *smu_entry_0,
uint8_t num_levels);
@ -76,4 +75,5 @@ int dcn42_get_active_display_cnt_wa(struct dc *dc, struct dc_state *context, int
void dcn42_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, struct dc_state *context, bool safe_to_lower);
void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, struct dc_state *context, int ref_dtbclk_khz);
bool dcn42_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base);
bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context);
#endif //__DCN42_CLK_MGR_H__

View File

@ -2895,16 +2895,27 @@ static struct surface_update_descriptor det_surface_update(
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
if (u->blend_tf || (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
if (u->cm || (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
update_flags->bits.gamma_change = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
if (u->lut3d_func || u->func_shaper) {
if (u->cm && (u->cm->flags.bits.lut3d_enable || u->surface->cm.flags.bits.lut3d_enable)) {
update_flags->bits.lut_3d = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
if (u->cm && u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable &&
u->cm->flags.bits.lut3d_enable && u->surface->cm.flags.bits.lut3d_enable) {
/* Toggling 3DLUT loading between DMA and Host is illegal */
BREAK_TO_DEBUGGER();
}
if (u->cm && u->cm->flags.bits.lut3d_enable && !u->cm->flags.bits.lut3d_dma_enable) {
/* Host loading 3DLUT requires full update but only stream lock */
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
}
if (u->hdr_mult.value)
if (u->hdr_mult.value != u->surface->hdr_mult.value) {
// TODO: Should be fast?
@ -2919,24 +2930,15 @@ static struct surface_update_descriptor det_surface_update(
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
}
if (u->cm2_params) {
if (u->cm2_params->component_settings.shaper_3dlut_setting != u->surface->mcm_shaper_3dlut_setting
|| u->cm2_params->component_settings.lut1d_enable != u->surface->mcm_lut1d_enable
|| u->cm2_params->cm2_luts.lut3d_data.lut3d_src != u->surface->mcm_luts.lut3d_data.lut3d_src) {
update_flags->bits.mcm_transfer_function_enable_change = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
}
if (u->cm_hist_control) {
update_flags->bits.cm_hist_change = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
if (update_flags->bits.lut_3d &&
u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
}
if (check_config->enable_legacy_fast_update &&
(update_flags->bits.gamma_change ||
update_flags->bits.gamut_remap_change ||
update_flags->bits.input_csc_change ||
update_flags->bits.cm_hist_change ||
update_flags->bits.coeff_reduction_change)) {
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
}
@ -3168,6 +3170,11 @@ static void copy_surface_update_to_plane(
surface->gamma_correction.type =
srf_update->gamma->type;
}
if (srf_update->cm_hist_control) {
memcpy(&surface->cm_hist_control,
srf_update->cm_hist_control,
sizeof(surface->cm_hist_control));
}
if (srf_update->in_transfer_func) {
surface->in_transfer_func.sdr_ref_white_level =
@ -3181,24 +3188,12 @@ static void copy_surface_update_to_plane(
sizeof(struct dc_transfer_func_distributed_points));
}
if (srf_update->cm2_params) {
surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting;
surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable;
surface->mcm_luts = srf_update->cm2_params->cm2_luts;
/* Shaper, 3DLUT, 1DLUT */
if (srf_update->cm) {
memcpy(&surface->cm, srf_update->cm,
sizeof(surface->cm));
}
if (srf_update->func_shaper) {
memcpy(&surface->in_shaper_func, srf_update->func_shaper,
sizeof(surface->in_shaper_func));
if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER)
surface->mcm_luts.shaper = &surface->in_shaper_func;
}
if (srf_update->lut3d_func)
memcpy(&surface->lut3d_func, srf_update->lut3d_func,
sizeof(surface->lut3d_func));
if (srf_update->hdr_mult.value)
surface->hdr_mult =
srf_update->hdr_mult;
@ -3207,17 +3202,6 @@ static void copy_surface_update_to_plane(
surface->sdr_white_level_nits =
srf_update->sdr_white_level_nits;
if (srf_update->blend_tf) {
memcpy(&surface->blend_tf, srf_update->blend_tf,
sizeof(surface->blend_tf));
if (surface->mcm_lut1d_enable)
surface->mcm_luts.lut1d_func = &surface->blend_tf;
}
if (srf_update->cm2_params || srf_update->blend_tf)
surface->lut_bank_a = !surface->lut_bank_a;
if (srf_update->input_csc_color_matrix)
surface->input_csc_color_matrix =
*srf_update->input_csc_color_matrix;
@ -4501,11 +4485,9 @@ static void commit_planes_for_stream(struct dc *dc,
if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
continue;
if (srf_updates[i].cm2_params &&
srf_updates[i].cm2_params->cm2_luts.lut3d_data.lut3d_src ==
DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM &&
srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting ==
DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT &&
if (srf_updates[i].cm &&
srf_updates[i].cm->flags.bits.lut3d_enable &&
srf_updates[i].cm->flags.bits.lut3d_dma_enable &&
dc->hwss.trigger_3dlut_dma_load)
dc->hwss.trigger_3dlut_dma_load(dc, pipe_ctx);
@ -5073,6 +5055,7 @@ void populate_fast_updates(struct dc_fast_update *fast_update,
fast_update[i].input_csc_color_matrix = srf_updates[i].input_csc_color_matrix;
fast_update[i].coeff_reduction_factor = srf_updates[i].coeff_reduction_factor;
fast_update[i].cursor_csc_color_matrix = srf_updates[i].cursor_csc_color_matrix;
fast_update[i].cm_hist_control = srf_updates[i].cm_hist_control;
}
}
@ -5090,6 +5073,7 @@ static bool fast_updates_exist(const struct dc_fast_update *fast_update, int sur
fast_update[i].gamut_remap_matrix ||
fast_update[i].input_csc_color_matrix ||
fast_update[i].cursor_csc_color_matrix ||
fast_update[i].cm_hist_control ||
fast_update[i].coeff_reduction_factor)
return true;
}
@ -5110,6 +5094,7 @@ bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_
fast_update[i].gamma ||
fast_update[i].gamut_remap_matrix ||
fast_update[i].coeff_reduction_factor ||
fast_update[i].cm_hist_control ||
fast_update[i].cursor_csc_color_matrix)
return true;
}
@ -5151,6 +5136,12 @@ static bool full_update_required(
const struct dc_stream_update *stream_update,
const struct dc_stream_state *stream)
{
const union dc_plane_cm_flags blend_only_flags = {
.bits = {
.blend_enable = 1,
}
};
if (full_update_required_weak(dc, srf_updates, surface_count, stream_update, stream))
return true;
@ -5163,14 +5154,12 @@ static bool full_update_required(
(srf_updates[i].sdr_white_level_nits &&
srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) ||
srf_updates[i].in_transfer_func ||
srf_updates[i].func_shaper ||
srf_updates[i].lut3d_func ||
srf_updates[i].surface->force_full_update ||
(srf_updates[i].flip_addr &&
srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface) ||
(srf_updates[i].cm2_params &&
(srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting != srf_updates[i].surface->mcm_shaper_3dlut_setting ||
srf_updates[i].cm2_params->component_settings.lut1d_enable != srf_updates[i].surface->mcm_lut1d_enable))))
(srf_updates[i].cm &&
((srf_updates[i].cm->flags.all != blend_only_flags.all && srf_updates[i].cm->flags.all != 0) ||
(srf_updates[i].surface->cm.flags.all != blend_only_flags.all && srf_updates[i].surface->cm.flags.all != 0)))))
return true;
}
@ -5945,6 +5934,7 @@ bool dc_is_dmub_outbox_supported(struct dc *dc)
case AMDGPU_FAMILY_GC_11_0_1:
case AMDGPU_FAMILY_GC_11_5_0:
case AMDGPU_FAMILY_GC_11_5_4:
if (!dc->debug.dpia_debug.bits.disable_dpia)
return true;
break;
@ -6897,7 +6887,7 @@ bool dc_capture_register_software_state(struct dc *dc, struct dc_register_softwa
struct dc_plane_state *plane_state = pipe_ctx->plane_state;
/* MPCC blending tree and mode control - capture actual blend configuration */
state->mpc.mpcc_mode[i] = (plane_state->blend_tf.type != TF_TYPE_BYPASS) ? 1 : 0;
state->mpc.mpcc_mode[i] = (plane_state->cm.blend_func.type != TF_TYPE_BYPASS) ? 1 : 0;
state->mpc.mpcc_alpha_blend_mode[i] = plane_state->per_pixel_alpha ? 1 : 0;
state->mpc.mpcc_alpha_multiplied_mode[i] = plane_state->pre_multiplied_alpha ? 1 : 0;
state->mpc.mpcc_blnd_active_overlap_only[i] = 0; /* Default - no overlap restriction */
@ -7295,6 +7285,23 @@ static bool update_planes_and_stream_prepare_v3(
ASSERT(scratch->flow == UPDATE_V3_FLOW_INVALID);
dc_exit_ips_for_hw_access(scratch->dc);
/* HWSS path determination needs to be done prior to updating the surface and stream states. */
struct dc_fast_update fast_update[MAX_SURFACES] = { 0 };
populate_fast_updates(fast_update,
scratch->surface_updates,
scratch->surface_count,
scratch->stream_update);
const bool is_hwss_fast_path_only =
fast_update_only(scratch->dc,
fast_update,
scratch->surface_updates,
scratch->surface_count,
scratch->stream_update,
scratch->stream) &&
!scratch->dc->check_config.enable_legacy_fast_update;
if (!update_planes_and_stream_state(
scratch->dc,
scratch->surface_updates,
@ -7310,26 +7317,7 @@ static bool update_planes_and_stream_prepare_v3(
if (scratch->new_context == scratch->dc->current_state) {
ASSERT(scratch->update_type < UPDATE_TYPE_FULL);
// TODO: Do we need this to be alive in execute?
struct dc_fast_update fast_update[MAX_SURFACES] = { 0 };
populate_fast_updates(
fast_update,
scratch->surface_updates,
scratch->surface_count,
scratch->stream_update
);
const bool fast = fast_update_only(
scratch->dc,
fast_update,
scratch->surface_updates,
scratch->surface_count,
scratch->stream_update,
scratch->stream
)
// TODO: Can this be used to skip `populate_fast_updates`?
&& !scratch->dc->check_config.enable_legacy_fast_update;
scratch->flow = fast
scratch->flow = is_hwss_fast_path_only
? UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST
: UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL;
return true;

View File

@ -2431,7 +2431,6 @@ static void resource_log_pipe_for_stream(struct dc *dc, struct dc_state *state,
int slice_idx, dpp_idx, plane_idx, slice_count, dpp_count;
bool is_primary;
DC_LOGGER_INIT(dc->ctx->logger);
slice_count = resource_get_opp_heads_for_otg_master(otg_master,
&state->res_ctx, opp_heads);

View File

@ -33,6 +33,7 @@
#include "dc_dmub_srv.h"
#include "dc_state_priv.h"
#include "dc_stream_priv.h"
#include "dce/dmub_hw_lock_mgr.h"
#define DC_LOGGER dc->ctx->logger
#ifndef MIN
@ -171,10 +172,12 @@ struct dc_stream_state *dc_create_stream_for_sink(
goto fail;
stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC);
if (stream == NULL)
goto fail;
stream->update_scratch = kzalloc((int32_t) dc_update_scratch_space_size(), GFP_ATOMIC);
if (stream->update_scratch == NULL)
goto fail;
@ -245,7 +248,6 @@ const struct dc_stream_status *dc_stream_get_status_const(
const struct dc_stream_state *stream)
{
struct dc *dc = stream->ctx->dc;
return dc_state_get_stream_status(dc->current_state, stream);
}
@ -257,6 +259,7 @@ void program_cursor_attributes(
struct resource_context *res_ctx;
struct pipe_ctx *pipe_to_program = NULL;
bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
bool unlock_dmub = false;
if (!stream)
return;
@ -275,6 +278,12 @@ void program_cursor_attributes(
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
} else {
if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream &&
should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) {
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true);
unlock_dmub = true;
}
dc->hwss.cursor_lock(dc, pipe_to_program, true);
if (pipe_to_program->next_odm_pipe)
dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
@ -297,6 +306,9 @@ void program_cursor_attributes(
dc->hwss.cursor_lock(dc, pipe_to_program, false);
if (pipe_to_program->next_odm_pipe)
dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
if (unlock_dmub)
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false);
}
}
}
@ -404,6 +416,7 @@ void program_cursor_position(
struct resource_context *res_ctx;
struct pipe_ctx *pipe_to_program = NULL;
bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
bool unlock_dmub = false;
if (!stream)
return;
@ -423,10 +436,16 @@ void program_cursor_position(
if (!pipe_to_program) {
pipe_to_program = pipe_ctx;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update)
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
else
} else {
if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream &&
should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) {
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true);
unlock_dmub = true;
}
dc->hwss.cursor_lock(dc, pipe_to_program, true);
}
}
dc->hwss.set_cursor_position(pipe_ctx);
@ -438,10 +457,14 @@ void program_cursor_position(
}
if (pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update)
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
else
} else {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
if (unlock_dmub)
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false);
}
}
}
@ -523,8 +546,10 @@ bool dc_stream_program_cursor_position(
struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
/* trigger event on first pipe with current stream */
if (stream == pipe_ctx->stream) {
pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg);
if (stream == pipe_ctx->stream &&
pipe_ctx->stream_res.tg->funcs->program_manual_trigger) {
pipe_ctx->stream_res.tg->funcs->program_manual_trigger(
pipe_ctx->stream_res.tg);
break;
}
}
@ -984,7 +1009,6 @@ void dc_stream_release_3dlut_for_stream(
if (rmcm_3dlut) {
rmcm_3dlut->isInUse = false;
rmcm_3dlut->stream = NULL;
rmcm_3dlut->protection_bits = 0;
}
}
@ -996,7 +1020,6 @@ void dc_stream_init_rmcm_3dlut(struct dc *dc)
for (int i = 0; i < num_rmcm; i++) {
dc->res_pool->rmcm_3dlut[i].isInUse = false;
dc->res_pool->rmcm_3dlut[i].stream = NULL;
dc->res_pool->rmcm_3dlut[i].protection_bits = 0;
}
}

View File

@ -139,6 +139,9 @@ const struct dc_plane_status *dc_plane_get_status(
if (pipe_ctx->plane_state && flags.bits.address)
pipe_ctx->plane_state->status.is_flip_pending = false;
if (pipe_ctx->plane_state && flags.bits.histogram)
memset(&pipe_ctx->plane_state->status.cm_hist, 0,
sizeof(pipe_ctx->plane_state->status.cm_hist));
break;
}
@ -154,6 +157,12 @@ const struct dc_plane_status *dc_plane_get_status(
if (flags.bits.address)
dc->hwss.update_pending_status(pipe_ctx);
if (flags.bits.histogram) {
struct dpp *dpp = pipe_ctx->plane_res.dpp;
if (dpp && dpp->funcs->dpp_cm_hist_read)
dpp->funcs->dpp_cm_hist_read(dpp, &pipe_ctx->plane_state->status.cm_hist);
}
}
return plane_status;

View File

@ -63,7 +63,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
#define DC_VER "3.2.372"
#define DC_VER "3.2.373"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
@ -1404,15 +1404,50 @@ struct lut_mem_mapping {
struct dc_rmcm_3dlut {
bool isInUse;
const struct dc_stream_state *stream;
uint8_t protection_bits;
};
struct dc_3dlut {
struct kref refcount;
struct tetrahedral_params lut_3d;
struct fixed31_32 hdr_multiplier;
union dc_3dlut_state state;
};
/* 3DLUT DMA (Fast Load) params */
struct dc_3dlut_dma {
struct dc_plane_address addr;
enum dc_cm_lut_swizzle swizzle;
enum dc_cm_lut_pixel_format format;
uint16_t bias; /* FP1.5.10 */
uint16_t scale; /* FP1.5.10 */
enum dc_cm_lut_size size;
};
/* color manager */
union dc_plane_cm_flags {
unsigned int all;
struct {
unsigned int shaper_enable : 1;
unsigned int lut3d_enable : 1;
unsigned int blend_enable : 1;
/* whether legacy (lut3d_func) or DMA is valid */
unsigned int lut3d_dma_enable : 1;
/* RMCM lut to be used instead of MCM */
unsigned int rmcm_enable : 1;
unsigned int reserved: 27;
} bits;
};
struct dc_plane_cm {
struct kref refcount;
struct dc_transfer_func shaper_func;
union {
struct dc_3dlut lut3d_func;
struct dc_3dlut_dma lut3d_dma;
};
struct dc_transfer_func blend_func;
union dc_plane_cm_flags flags;
};
/*
* This structure is filled in by dc_surface_get_status and contains
* the last requested address and the currently active address so the called
@ -1490,14 +1525,18 @@ struct dc_plane_state {
struct fixed31_32 hdr_mult;
struct colorspace_transform gamut_remap_matrix;
// TODO: No longer used, remove
struct dc_hdr_static_metadata hdr_static_ctx;
enum dc_color_space color_space;
bool lut_bank_a;
struct dc_hdr_static_metadata hdr_static_ctx;
struct dc_3dlut lut3d_func;
struct dc_transfer_func in_shaper_func;
struct dc_transfer_func blend_tf;
enum dc_cm2_shaper_3dlut_setting mcm_shaper_3dlut_setting;
bool mcm_lut1d_enable;
struct dc_cm2_func_luts mcm_luts;
enum mpcc_movable_cm_location mcm_location;
struct dc_plane_cm cm;
struct dc_transfer_func *gamcor_tf;
enum surface_pixel_format format;
@ -1534,11 +1573,6 @@ struct dc_plane_state {
bool is_statically_allocated;
enum chroma_cositing cositing;
enum dc_cm2_shaper_3dlut_setting mcm_shaper_3dlut_setting;
bool mcm_lut1d_enable;
struct dc_cm2_func_luts mcm_luts;
bool lut_bank_a;
enum mpcc_movable_cm_location mcm_location;
struct dc_csc_transform cursor_csc_color_matrix;
bool adaptive_sharpness_en;
int adaptive_sharpness_policy;
@ -1884,6 +1918,7 @@ struct dc_surface_update {
* change cm2_params.cm2_luts: Fast update
*/
const struct dc_cm2_parameters *cm2_params;
const struct dc_plane_cm *cm;
const struct dc_csc_transform *cursor_csc_color_matrix;
unsigned int sdr_white_level_nits;
struct dc_bias_and_scale bias_and_scale;
@ -1928,6 +1963,10 @@ struct dc_3dlut *dc_create_3dlut_func(void);
void dc_3dlut_func_release(struct dc_3dlut *lut);
void dc_3dlut_func_retain(struct dc_3dlut *lut);
struct dc_plane_cm *dc_plane_cm_create(void);
void dc_plane_cm_release(struct dc_plane_cm *cm);
void dc_plane_cm_retain(struct dc_plane_cm *cm);
void dc_post_update_surfaces_to_stream(
struct dc *dc);

View File

@ -102,8 +102,7 @@ struct dc_vbios_funcs {
struct bp_external_encoder_control *cntl);
enum bp_result (*dac_load_detection)(
struct dc_bios *bios,
enum engine_id engine_id,
struct graphics_object_id ext_enc_id);
enum engine_id engine_id);
enum bp_result (*transmitter_control)(
struct dc_bios *bios,
struct bp_transmitter_control *cntl);

View File

@ -1374,7 +1374,7 @@ union dpcd_replay_configuration {
unsigned char DESYNC_ERROR_STATUS : 1;
unsigned char SINK_DEVICE_REPLAY_STATUS : 3;
unsigned char SINK_FRAME_LOCKED : 2;
unsigned char RESERVED : 1;
unsigned char FRAME_SKIPPING_ERROR_STATUS : 1;
} bits;
unsigned char raw;
};

View File

@ -31,6 +31,7 @@
union dc_plane_status_update_flags {
struct {
uint32_t address : 1;
uint32_t histogram : 1;
} bits;
uint32_t raw;
};

View File

@ -89,6 +89,7 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
spl_in->callbacks = dcn32_spl_callbacks;
break;
case DCN_VERSION_4_01:
case DCN_VERSION_4_2:
spl_in->callbacks = dcn401_spl_callbacks;
break;
default:

View File

@ -23,8 +23,8 @@
#include "amdgpu_dm_trace.h"
#define TRACE_DC_PIPE_STATE(pipe_ctx, index, max_pipes) \
for (index = 0; index < max_pipes; ++index) { \
#define TRACE_DC_PIPE_STATE(pipe_ctx, max_pipes) \
for (int index = 0; index < max_pipes; ++index) { \
struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[index]; \
if (pipe_ctx->plane_state) \
trace_amdgpu_dm_dc_pipe_state(pipe_ctx->pipe_idx, pipe_ctx->plane_state, \

View File

@ -1194,6 +1194,8 @@ struct replay_config {
union replay_optimization replay_optimization;
/* Replay sub feature Frame Skipping is supported */
bool frame_skip_supported;
/* Replay Received Frame Skipping Error HPD. */
bool received_frame_skipping_error_hpd;
};
/* Replay feature flags*/
@ -1481,4 +1483,28 @@ struct dc_validation_dpia_set {
uint32_t required_bw;
};
enum dc_cm_lut_swizzle {
CM_LUT_3D_SWIZZLE_LINEAR_RGB,
CM_LUT_3D_SWIZZLE_LINEAR_BGR,
CM_LUT_1D_PACKED_LINEAR
};
enum dc_cm_lut_pixel_format {
CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB,
CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12MSB,
CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB,
CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12LSB,
CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10,
CM_LUT_PIXEL_FORMAT_BGRA16161616_FLOAT_FP1_5_10
};
enum dc_cm_lut_size {
CM_LUT_SIZE_NONE,
CM_LUT_SIZE_999,
CM_LUT_SIZE_171717,
CM_LUT_SIZE_333333,
CM_LUT_SIZE_454545,
CM_LUT_SIZE_656565,
};
#endif /* DC_TYPES_H_ */

View File

@ -38,7 +38,11 @@
DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0),\
DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1),\
SR(DISPCLK_FREQ_CHANGE_CNTL),\
SR(DC_MEM_GLOBAL_PWR_REQ_CNTL)
SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
SR(MICROSECOND_TIME_BASE_DIV),\
SR(MILLISECOND_TIME_BASE_DIV),\
SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2)
#define DCCG_REG_LIST_DCN2() \
DCCG_COMMON_REG_LIST_DCN_BASE(),\
@ -370,7 +374,8 @@
type OTG1_DROP_PIXEL;\
type OTG2_DROP_PIXEL;\
type OTG3_ADD_PIXEL;\
type OTG3_DROP_PIXEL;
type OTG3_DROP_PIXEL;\
type RESYNC_FIFO_LEVEL_ADJUST_EN;
struct dccg_shift {
DCCG_REG_FIELD_LIST(uint8_t)

View File

@ -96,6 +96,25 @@ static void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl
dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;
}
/*
* On DCN21 S0i3 resume, BIOS programs MICROSECOND_TIME_BASE_DIV to
* 0x00120464 as a marker that golden init has already been done.
* dcn21_s0i3_golden_init_wa() reads this marker later in bios_golden_init()
* to decide whether to skip golden init.
*
* dccg2_init() unconditionally overwrites MICROSECOND_TIME_BASE_DIV to
* 0x00120264, destroying the marker before it can be read.
*
* Guard the call: if the S0i3 marker is present, skip dccg2_init() so the
* WA can function correctly. bios_golden_init() will handle init in that case.
*/
static void dccg21_init(struct dccg *dccg)
{
if (dccg2_is_s0i3_golden_init_wa_done(dccg))
return;
dccg2_init(dccg);
}
static const struct dccg_funcs dccg21_funcs = {
.update_dpp_dto = dccg21_update_dpp_dto,
@ -103,7 +122,7 @@ static const struct dccg_funcs dccg21_funcs = {
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
.otg_add_pixel = dccg2_otg_add_pixel,
.otg_drop_pixel = dccg2_otg_drop_pixel,
.dccg_init = dccg2_init,
.dccg_init = dccg21_init,
.refclk_setup = dccg2_refclk_setup, /* Deprecated - for backward compatibility only */
.allow_clock_gating = dccg2_allow_clock_gating,
.enable_memory_low_power = dccg2_enable_memory_low_power,

View File

@ -34,7 +34,13 @@
DCCG_SRII(DTO_PARAM, DPPCLK, 1),\
DCCG_SRII(DTO_PARAM, DPPCLK, 2),\
DCCG_SRII(DTO_PARAM, DPPCLK, 3),\
SR(REFCLK_CNTL)
SR(REFCLK_CNTL),\
SR(DISPCLK_FREQ_CHANGE_CNTL),\
SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
SR(MICROSECOND_TIME_BASE_DIV),\
SR(MILLISECOND_TIME_BASE_DIV),\
SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2)
#define DCCG_MASK_SH_LIST_DCN301(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\

View File

@ -64,9 +64,12 @@
SR(DSCCLK1_DTO_PARAM),\
SR(DSCCLK2_DTO_PARAM),\
SR(DSCCLK_DTO_CTRL),\
SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2),\
SR(DCCG_GATE_DISABLE_CNTL3),\
SR(HDMISTREAMCLK0_DTO_PARAM)
SR(HDMISTREAMCLK0_DTO_PARAM),\
SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
SR(MICROSECOND_TIME_BASE_DIV)
#define DCCG_MASK_SH_LIST_DCN31(mask_sh) \

View File

@ -70,11 +70,14 @@
SR(DSCCLK2_DTO_PARAM),\
SR(DSCCLK3_DTO_PARAM),\
SR(DSCCLK_DTO_CTRL),\
SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2),\
SR(DCCG_GATE_DISABLE_CNTL3),\
SR(HDMISTREAMCLK0_DTO_PARAM),\
SR(OTG_PIXEL_RATE_DIV),\
SR(DTBCLK_P_CNTL)
SR(DTBCLK_P_CNTL),\
SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
SR(MICROSECOND_TIME_BASE_DIV)
#define DCCG_MASK_SH_LIST_DCN314_COMMON(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\

View File

@ -827,6 +827,16 @@ void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint3
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, 1);
break;
case 4:
if (dccg_dcn->dccg_mask->SYMCLKE_FE_ROOT_GATE_DISABLE) {
REG_UPDATE_2(SYMCLKE_CLOCK_ENABLE,
SYMCLKE_FE_EN, 1,
SYMCLKE_FE_SRC_SEL, link_enc_inst);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_FE_ROOT_GATE_DISABLE, 1);
}
break;
default:
return;
}
}
@ -855,6 +865,16 @@ void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint
SYMCLKD_FE_EN, 0,
SYMCLKD_FE_SRC_SEL, 0);
break;
case 4:
if (dccg_dcn->dccg_mask->SYMCLKE_FE_ROOT_GATE_DISABLE) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_FE_ROOT_GATE_DISABLE, 0);
REG_UPDATE_2(SYMCLKE_CLOCK_ENABLE,
SYMCLKE_FE_EN, 0,
SYMCLKE_FE_SRC_SEL, 0);
}
break;
default:
return;
}
}

View File

@ -180,6 +180,61 @@ void dccg42_set_physymclk(
}
}
void dccg42_set_pixel_rate_div(
struct dccg *dccg,
uint32_t otg_inst,
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
uint32_t dp_dto_int;
uint32_t reg_val;
// only 2 and 4 are valid on dcn401
if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
return;
}
dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
if (tmds_div == cur_tmds_div)
return;
// encode enum to register value
reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
switch (otg_inst) {
case 0:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 1:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 2:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 3:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
void dccg42_trigger_dio_fifo_resync(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 1);
REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 0);
REG_WAIT(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, 1, 50, 2000);
}
static void dccg42_init(struct dccg *dccg)
{
int otg_inst;
@ -240,9 +295,9 @@ static const struct dccg_funcs dccg42_funcs = {
.otg_drop_pixel = dccg42_otg_drop_pixel,
.disable_dsc = dccg35_disable_dscclk,
.enable_dsc = dccg35_enable_dscclk,
.set_pixel_rate_div = dccg401_set_pixel_rate_div,
.set_pixel_rate_div = dccg42_set_pixel_rate_div,
.get_pixel_rate_div = dccg401_get_pixel_rate_div,
.trigger_dio_fifo_resync = dccg35_trigger_dio_fifo_resync,
.trigger_dio_fifo_resync = dccg42_trigger_dio_fifo_resync,
.set_dp_dto = dccg401_set_dp_dto,
.enable_symclk_se = dccg35_enable_symclk_se,
.disable_symclk_se = dccg35_disable_symclk_se,

View File

@ -238,7 +238,8 @@
DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_CLOCK_ENABLE, mask_sh),\
DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_EN, mask_sh),\
DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh)
DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh),\
DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, mask_sh)
void dccg42_otg_add_pixel(struct dccg *dccg,
@ -254,6 +255,14 @@ void dccg42_set_physymclk(
enum physymclk_clock_source clk_src,
bool force_enable);
void dccg42_set_pixel_rate_div(
struct dccg *dccg,
uint32_t otg_inst,
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused);
void dccg42_trigger_dio_fifo_resync(struct dccg *dccg);
struct dccg *dccg42_create(
struct dc_context *ctx,
const struct dccg_registers *regs,

View File

@ -28,6 +28,14 @@
#include "dc_types.h"
#include "core_types.h"
static bool dmub_hw_lock_has_inbox0_lock(const struct dc *dc)
{
return dc->ctx && dc->ctx->dmub_srv &&
dc->hwss.dmub_hw_control_lock &&
dc->hwss.dmub_hw_control_lock_fast &&
dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support;
}
void dmub_hw_lock_mgr_cmd(struct dc_dmub_srv *dmub_srv,
bool lock,
union dmub_hw_lock_flags *hw_locks,
@ -105,5 +113,13 @@ bool should_use_dmub_inbox1_lock(const struct dc *dc, const struct dc_link *link
if (dc->ctx->dce_version >= DCN_VERSION_4_01)
return false;
if (dmub_hw_lock_has_inbox0_lock(dc))
return false;
return dmub_hw_lock_mgr_does_link_require_lock(dc, link);
}
bool should_use_dmub_inbox0_lock_for_link(const struct dc *dc, const struct dc_link *link)
{
return dmub_hw_lock_has_inbox0_lock(dc) && dmub_hw_lock_mgr_does_link_require_lock(dc, link);
}

View File

@ -46,7 +46,38 @@ void dmub_hw_lock_mgr_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
* Return: true if the inbox1 lock should be used, false otherwise
*/
bool should_use_dmub_inbox1_lock(const struct dc *dc, const struct dc_link *link);
/**
* dmub_hw_lock_mgr_does_link_require_lock() - Returns true if the link has a feature that needs the HW lock.
*
* @dc: Pointer to DC object
* @link: The link to check
*
* Return: true if the link has a feature that needs the HW lock, false otherwise
*/
bool dmub_hw_lock_mgr_does_link_require_lock(const struct dc *dc, const struct dc_link *link);
/**
* dmub_hw_lock_mgr_does_context_require_lock() - Returns true if the context has any stream that needs the HW lock.
*
* @dc: Pointer to DC object
* @context: The context to check
*
* Return: true if the context has any stream that needs the HW lock, false otherwise
*/
bool dmub_hw_lock_mgr_does_context_require_lock(const struct dc *dc, const struct dc_state *context);
/**
* should_use_dmub_inbox0_lock_for_link() - Checks if the inbox0 interlock with DMU should be used.
*
* Is not functionally equivalent to inbox1 as DMUB will not own programming of the relevant locking
* registers.
*
* @dc: pointer to DC object
* @link: optional pointer to the link object to check for enabled link features
*
* Return: true if the inbox0 lock should be used, false otherwise
*/
bool should_use_dmub_inbox0_lock_for_link(const struct dc *dc, const struct dc_link *link);
#endif /*_DMUB_HW_LOCK_MGR_H_ */

View File

@ -90,6 +90,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.o := $(dml2
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_ccflags)
@ -107,6 +108,7 @@ CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.o := $(d
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_rcflags)
@ -124,6 +126,7 @@ DML21 += src/dml2_core/dml2_core_dcn4_calcs.o
DML21 += src/dml2_dpmm/dml2_dpmm_dcn4.o
DML21 += src/dml2_dpmm/dml2_dpmm_factory.o
DML21 += src/dml2_mcg/dml2_mcg_dcn4.o
DML21 += src/dml2_mcg/dml2_mcg_dcn42.o
DML21 += src/dml2_mcg/dml2_mcg_factory.o
DML21 += src/dml2_pmo/dml2_pmo_dcn3.o
DML21 += src/dml2_pmo/dml2_pmo_factory.o

View File

@ -4089,8 +4089,8 @@ static void CalculateSwathAndDETConfiguration(struct display_mode_lib_scratch_st
dml_uint_t MaximumSwathHeightC[__DML_NUM_PLANES__];
dml_uint_t RoundedUpMaxSwathSizeBytesY[__DML_NUM_PLANES__];
dml_uint_t RoundedUpMaxSwathSizeBytesC[__DML_NUM_PLANES__];
dml_uint_t RoundedUpSwathSizeBytesY[__DML_NUM_PLANES__];
dml_uint_t RoundedUpSwathSizeBytesC[__DML_NUM_PLANES__];
dml_uint_t RoundedUpSwathSizeBytesY[__DML_NUM_PLANES__] = { 0 };
dml_uint_t RoundedUpSwathSizeBytesC[__DML_NUM_PLANES__] = { 0 };
dml_uint_t SwathWidthSingleDPP[__DML_NUM_PLANES__];
dml_uint_t SwathWidthSingleDPPChroma[__DML_NUM_PLANES__];

View File

@ -45,6 +45,9 @@ static enum dml2_project_id dml21_dcn_revision_to_dml2_project_id(enum dce_versi
case DCN_VERSION_4_01:
project_id = dml2_project_dcn4x_stage2_auto_drr_svp;
break;
case DCN_VERSION_4_2:
project_id = dml2_project_dcn42;
break;
default:
project_id = dml2_project_invalid;
DC_ERR("unsupported dcn version for DML21!");
@ -598,29 +601,31 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm
plane->composition.viewport.stationary = false;
if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
if (plane_state->cm.flags.bits.lut3d_dma_enable) {
plane->tdlut.setup_for_tdlut = true;
switch (plane_state->mcm_luts.lut3d_data.gpu_mem_params.layout) {
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
switch (plane_state->cm.lut3d_dma.swizzle) {
case CM_LUT_3D_SWIZZLE_LINEAR_RGB:
case CM_LUT_3D_SWIZZLE_LINEAR_BGR:
plane->tdlut.tdlut_addressing_mode = dml2_tdlut_sw_linear;
break;
case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
case CM_LUT_1D_PACKED_LINEAR:
default:
plane->tdlut.tdlut_addressing_mode = dml2_tdlut_simple_linear;
break;
}
switch (plane_state->mcm_luts.lut3d_data.gpu_mem_params.size) {
case DC_CM2_GPU_MEM_SIZE_171717:
plane->tdlut.tdlut_width_mode = dml2_tdlut_width_17_cube;
switch (plane_state->cm.lut3d_dma.size) {
case CM_LUT_SIZE_333333:
plane->tdlut.tdlut_width_mode = dml2_tdlut_width_33_cube;
break;
case DC_CM2_GPU_MEM_SIZE_TRANSFORMED:
case CM_LUT_SIZE_171717:
default:
//plane->tdlut.tdlut_width_mode = dml2_tdlut_width_flatten; // dml2_tdlut_width_flatten undefined
plane->tdlut.tdlut_width_mode = dml2_tdlut_width_17_cube;
break;
}
}
plane->tdlut.setup_for_tdlut |= dml_ctx->config.force_tdlut_enable;
plane->dynamic_meta_data.enable = false;
@ -824,6 +829,9 @@ void dml21_copy_clocks_to_dc_state(struct dml2_context *in_ctx, struct dc_state
context->bw_ctx.bw.dcn.clk.subvp_prefetch_fclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.svp_prefetch_no_throttle.fclk_khz;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.base_efficiency = in_ctx->v21.mode_programming.programming->stutter.base_percent_efficiency;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.low_power_efficiency = in_ctx->v21.mode_programming.programming->stutter.low_power_percent_efficiency;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.z8_stutter_efficiency = in_ctx->v21.mode_programming.programming->informative.power_management.z8.stutter_efficiency;
context->bw_ctx.bw.dcn.clk.stutter_efficiency.z8_stutter_period = in_ctx->v21.mode_programming.programming->informative.power_management.z8.stutter_period;
context->bw_ctx.bw.dcn.clk.zstate_support = in_ctx->v21.mode_programming.programming->z8_stutter.supported_in_blank; /*ignore meets_eco since it is not used*/
}
static struct dml2_dchub_watermark_regs *wm_set_index_to_dc_wm_set(union dcn_watermark_set *watermarks, const enum dml2_dchub_watermark_reg_set_index wm_index)
@ -931,3 +939,31 @@ void dml21_set_dc_p_state_type(
}
}
void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_state *context)
{
unsigned int lowest_dpm_state_index = 0;
struct dc_clocks *min_clocks = &context->bw_ctx.bw.dcn.clk;
min_clocks->dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->dcfclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dcfclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->dramclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.uclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->fclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.fclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->idle_dramclk_khz = 0;
min_clocks->idle_fclk_khz = 0;
min_clocks->dcfclk_deep_sleep_khz = 0;
min_clocks->fclk_p_state_change_support = true;
min_clocks->p_state_change_support = true;
min_clocks->dtbclk_en = false;
min_clocks->ref_dtbclk_khz = 0;
min_clocks->socclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.socclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->subvp_prefetch_dramclk_khz = 0;
min_clocks->subvp_prefetch_fclk_khz = 0;
min_clocks->phyclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.phyclk.clk_values_khz[lowest_dpm_state_index];
min_clocks->stutter_efficiency.base_efficiency = 1;
min_clocks->stutter_efficiency.low_power_efficiency = 1;
min_clocks->stutter_efficiency.z8_stutter_efficiency = 1;
min_clocks->stutter_efficiency.z8_stutter_period = 100000;
min_clocks->zstate_support = DCN_ZSTATE_SUPPORT_ALLOW;
}

View File

@ -25,4 +25,5 @@ void dml21_map_hw_resources(struct dml2_context *dml_ctx);
void dml21_get_pipe_mcache_config(struct dc_state *context, struct pipe_ctx *pipe_ctx, struct dml2_per_plane_programming *pln_prog, struct dml2_pipe_configuration_descriptor *mcache_pipe_config);
void dml21_set_dc_p_state_type(struct pipe_ctx *pipe_ctx, struct dml2_per_stream_programming *stream_programming, bool sub_vp_enabled);
unsigned int map_plane_to_dml21_display_cfg(const struct dml2_context *dml_ctx, unsigned int stream_id, const struct dc_plane_state *plane, const struct dc_state *context);
void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_state *context);
#endif

View File

@ -374,6 +374,7 @@ void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *c
dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, dc->current_state);
}
static unsigned int dml21_build_fams2_stream_programming_v2(const struct dc *dc,
struct dc_state *context,
struct dml2_context *dml_ctx)

View File

@ -9,16 +9,21 @@
#include "dml21_utils.h"
#include "dml21_translation_helper.h"
#include "dml2_dc_resource_mgmt.h"
#include "dc_fpu.h"
#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
#endif // !DC_RUN_WITH_PREEMPTION_ENABLED
#define INVALID -1
static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
{
*dml_ctx = vzalloc(sizeof(struct dml2_context));
DC_RUN_WITH_PREEMPTION_ENABLED(*dml_ctx = vzalloc(sizeof(struct dml2_context)));
if (!(*dml_ctx))
return false;
(*dml_ctx)->v21.dml_init.dml2_instance = vzalloc(sizeof(struct dml2_instance));
DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.dml_init.dml2_instance = vzalloc(sizeof(struct dml2_instance)));
if (!((*dml_ctx)->v21.dml_init.dml2_instance))
return false;
@ -28,7 +33,7 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
(*dml_ctx)->v21.mode_support.display_config = &(*dml_ctx)->v21.display_config;
(*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config;
(*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming));
DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming)));
if (!((*dml_ctx)->v21.mode_programming.programming))
return false;
@ -70,8 +75,9 @@ static void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, con
bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
{
/* Allocate memory for initializing DML21 instance */
if (!dml21_allocate_memory(dml_ctx))
if (!dml21_allocate_memory(dml_ctx)) {
return false;
}
dml21_init(in_dc, *dml_ctx, config);
@ -215,6 +221,7 @@ static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_s
return true;
if (context->stream_count == 0) {
dml21_init_min_clocks_for_dc_state(dml_ctx, context);
dml21_build_fams2_programming(in_dc, context, dml_ctx);
return true;
}

View File

@ -0,0 +1,263 @@
/* SPDX-License-Identifier: MIT */
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML_DML_DCN42_SOC_BB__
#define __DML_DML_DCN42_SOC_BB__
#include "dml_top_soc_parameter_types.h"
static const struct dml2_soc_qos_parameters dml_dcn42_variant_a_soc_qos_params = {
.derate_table = {
.system_active_urgent = {
.dram_derate_percent_pixel = 65,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 60,
.fclk_derate_percent = 80,
.dcfclk_derate_percent = 80,
},
.system_active_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
.dcn_mall_prefetch_urgent = {
.dram_derate_percent_pixel = 65,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 60,
.fclk_derate_percent = 80,
.dcfclk_derate_percent = 80,
},
.dcn_mall_prefetch_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
.system_idle_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
},
.writeback = {
.base_latency_us = 12,
.scaling_factor_us = 0,
.scaling_factor_mhz = 0,
},
.qos_params = {
.dcn32x = {
.loaded_round_trip_latency_fclk_cycles = 106,
.urgent_latency_us = {
.base_latency_us = 4,
.base_latency_pixel_vm_us = 4,
.base_latency_vm_us = 4,
.scaling_factor_fclk_us = 0,
.scaling_factor_mhz = 0,
},
.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
},
},
.qos_type = dml2_qos_param_type_dcn3,
};
static const struct dml2_soc_bb dml2_socbb_dcn42 = {
.clk_table = {
.wck_ratio = {
.clk_values_khz = {2},
},
.uclk = {
.clk_values_khz = {400000},
.num_clk_values = 1,
},
.fclk = {
.clk_values_khz = {400000},
.num_clk_values = 1,
},
.dcfclk = {
.clk_values_khz = {200000},
.num_clk_values = 1,
},
.dispclk = {
.clk_values_khz = {1500000},
.num_clk_values = 1,
},
.dppclk = {
.clk_values_khz = {1500000},
.num_clk_values = 1,
},
.dtbclk = {
.clk_values_khz = {600000},
.num_clk_values = 1,
},
.phyclk = {
.clk_values_khz = {810000},
.num_clk_values = 1,
},
.socclk = {
.clk_values_khz = {600000},
.num_clk_values = 1,
},
.dscclk = {
.clk_values_khz = {500000},
.num_clk_values = 1,
},
.phyclk_d18 = {
.clk_values_khz = {667000},
.num_clk_values = 1,
},
.phyclk_d32 = {
.clk_values_khz = {625000},
.num_clk_values = 1,
},
.dram_config = {
.channel_width_bytes = 4,
.channel_count = 4,
.alt_clock_bw_conversion = true,
},
},
.qos_parameters = {
.derate_table = {
.system_active_urgent = {
.dram_derate_percent_pixel = 65,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 60,
.fclk_derate_percent = 80,
.dcfclk_derate_percent = 80,
},
.system_active_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
.dcn_mall_prefetch_urgent = {
.dram_derate_percent_pixel = 65,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 60,
.fclk_derate_percent = 80,
.dcfclk_derate_percent = 80,
},
.dcn_mall_prefetch_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
.system_idle_average = {
.dram_derate_percent_pixel = 30,
.dram_derate_percent_vm = 30,
.dram_derate_percent_pixel_and_vm = 30,
.fclk_derate_percent = 60,
.dcfclk_derate_percent = 60,
},
},
.writeback = {
.base_latency_us = 12,
.scaling_factor_us = 0,
.scaling_factor_mhz = 0,
},
.qos_params = {
.dcn32x = {
.loaded_round_trip_latency_fclk_cycles = 106,
.urgent_latency_us = {
.base_latency_us = 4,
.base_latency_pixel_vm_us = 4,
.base_latency_vm_us = 4,
.scaling_factor_fclk_us = 0,
.scaling_factor_mhz = 0,
},
.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
},
},
.qos_type = dml2_qos_param_type_dcn3,
},
.power_management_parameters = {
.dram_clk_change_blackout_us = 29,
.fclk_change_blackout_us = 0,
.g7_ppt_blackout_us = 0,
.stutter_enter_plus_exit_latency_us = 11,
.stutter_exit_latency_us = 9,
.z8_stutter_enter_plus_exit_latency_us = 300,
.z8_stutter_exit_latency_us = 200,
},
.vmin_limit = {
.dispclk_khz = 632 * 1000,
},
.dprefclk_mhz = 600,
.xtalclk_mhz = 24,
.pcie_refclk_mhz = 100,
.dchub_refclk_mhz = 50,
.mall_allocated_for_dcn_mbytes = 64,
.max_outstanding_reqs = 256,
.fabric_datapath_to_dcn_data_return_bytes = 32,
.return_bus_width_bytes = 64,
.hostvm_min_page_size_kbytes = 4,
.gpuvm_min_page_size_kbytes = 256,
.gpuvm_max_page_table_levels = 1,
.hostvm_max_non_cached_page_table_levels = 2,
.phy_downspread_percent = 0.38,
.dcn_downspread_percent = 0.38,
.dispclk_dppclk_vco_speed_mhz = 3000,
.do_urgent_latency_adjustment = 0,
.mem_word_bytes = 32,
.num_dcc_mcaches = 8,
.mcache_size_bytes = 2048,
.mcache_line_size_bytes = 32,
.max_fclk_for_uclk_dpm_khz = 2200 * 1000,
};
static const struct dml2_ip_capabilities dml2_dcn42_max_ip_caps = {
.pipe_count = 4,
.otg_count = 4,
.num_dsc = 4,
.max_num_dp2p0_streams = 4,
.max_num_hdmi_frl_outputs = 1,
.max_num_dp2p0_outputs = 4,
.rob_buffer_size_kbytes = 64,
.config_return_buffer_size_in_kbytes = 1792,
.config_return_buffer_segment_size_in_kbytes = 64,
.meta_fifo_size_in_kentries = 32,
.compressed_buffer_segment_size_in_kbytes = 64,
.cursor_buffer_size = 24,
.max_flip_time_us = 110,
.max_flip_time_lines = 50,
.hostvm_mode = 0,
.subvp_drr_scheduling_margin_us = 100,
.subvp_prefetch_end_to_mall_start_us = 15,
.subvp_fw_processing_delay = 15,
.max_vactive_det_fill_delay_us = 400,
.fams2 = {
.max_allow_delay_us = 100 * 1000,
.scheduling_delay_us = 550,
.vertical_interrupt_ack_delay_us = 40,
.allow_programming_delay_us = 18,
.min_allow_width_us = 20,
.subvp_df_throttle_delay_us = 100,
.subvp_programming_delay_us = 200,
.subvp_prefetch_to_mall_delay_us = 18,
.drr_programming_delay_us = 35,
.lock_timeout_us = 5000,
.recovery_timeout_us = 5000,
.flip_programming_delay_us = 300,
},
};
#endif

View File

@ -27,6 +27,19 @@ enum dml2_swizzle_mode {
dml2_gfx11_sw_256kb_d_x,
dml2_gfx11_sw_256kb_r_x,
dml2_sw_linear_256b, // GFX10 SW_LINEAR only accepts 256 byte aligned pitch
dml2_gfx10_sw_64kb_r_x,
dml2_gfx102_sw_64kb_s,
dml2_gfx102_sw_64kb_s_t,
dml2_gfx102_sw_64kb_s_x,
dml2_gfx102_sw_64kb_r_x,
dml2_linear_64elements, // GFX7 LINEAR_ALIGNED accepts pitch alignment of the maximum of 64 elements or 256 bytes
dml2_gfx7_1d_thin,
dml2_gfx7_2d_thin_gen_zero,
dml2_gfx7_2d_thin_gen_one,
dml2_gfx7_2d_thin_arlene,
dml2_gfx7_2d_thin_anubis
};
enum dml2_source_format_class {

View File

@ -19,6 +19,8 @@ enum dml2_project_id {
dml2_project_dcn4x_stage1,
dml2_project_dcn4x_stage2,
dml2_project_dcn4x_stage2_auto_drr_svp,
dml2_project_dcn40,
dml2_project_dcn42,
};
enum dml2_pstate_change_support {
@ -79,6 +81,7 @@ struct dml2_options {
struct dml2_pmo_options pmo_options;
};
struct dml2_initialize_instance_in_out {
struct dml2_instance *dml2_instance;
struct dml2_options options;

View File

@ -78,6 +78,86 @@ struct dml2_core_ip_params core_dcn4_ip_caps_base = {
.subvp_swath_height_margin_lines = 16,
};
struct dml2_core_ip_params core_dcn42_ip_caps_base = {
.vblank_nom_default_us = 668,
.remote_iommu_outstanding_translations = 256,
.rob_buffer_size_kbytes = 64,
.config_return_buffer_size_in_kbytes = 1792,
.config_return_buffer_segment_size_in_kbytes = 64,
.compressed_buffer_segment_size_in_kbytes = 64,
.dpte_buffer_size_in_pte_reqs_luma = 68,
.dpte_buffer_size_in_pte_reqs_chroma = 36,
.pixel_chunk_size_kbytes = 8,
.alpha_pixel_chunk_size_kbytes = 4,
.min_pixel_chunk_size_bytes = 1024,
.writeback_chunk_size_kbytes = 8,
.line_buffer_size_bits = 1171920,
.max_line_buffer_lines = 32,
.writeback_interface_buffer_size_kbytes = 90,
//Number of pipes after DCN Pipe harvesting
.max_num_dpp = 4,
.max_num_otg = 4,
.max_num_opp = 4,
.max_num_wb = 1,
.max_dchub_pscl_bw_pix_per_clk = 4,
.max_pscl_lb_bw_pix_per_clk = 2,
.max_lb_vscl_bw_pix_per_clk = 4,
.max_vscl_hscl_bw_pix_per_clk = 4,
.max_hscl_ratio = 6,
.max_vscl_ratio = 6,
.max_hscl_taps = 8,
.max_vscl_taps = 8,
.dispclk_ramp_margin_percent = 1,
.dppclk_delay_subtotal = 47,
.dppclk_delay_scl = 50,
.dppclk_delay_scl_lb_only = 16,
.dppclk_delay_cnvc_formatter = 28,
.dppclk_delay_cnvc_cursor = 6,
.cursor_buffer_size = 42,
.cursor_chunk_size = 2,
.dispclk_delay_subtotal = 125,
.max_inter_dcn_tile_repeaters = 8,
.writeback_max_hscl_ratio = 1,
.writeback_max_vscl_ratio = 1,
.writeback_min_hscl_ratio = 1,
.writeback_min_vscl_ratio = 1,
.writeback_max_hscl_taps = 1,
.writeback_max_vscl_taps = 1,
.writeback_line_buffer_buffer_size = 0,
.num_dsc = 4,
.maximum_dsc_bits_per_component = 12,
.maximum_pixels_per_line_per_dsc_unit = 5760,
.dsc422_native_support = true,
.dcc_supported = true,
.ptoi_supported = false,
.cursor_64bpp_support = true,
.dynamic_metadata_vm_enabled = false,
.max_num_hdmi_frl_outputs = 0,
.max_num_dp2p0_outputs = 2,
.max_num_dp2p0_streams = 4,
.imall_supported = 1,
.max_flip_time_us = 110,
.max_flip_time_lines = 50,
.words_per_channel = 16,
.subvp_fw_processing_delay_us = 15,
.subvp_pstate_allow_width_us = 20,
.subvp_swath_height_margin_lines = 16,
.dcn_mrq_present = 1,
.zero_size_buffer_entries = 512,
.compbuf_reserved_space_zs = 64,
.dcc_meta_buffer_size_bytes = 6272,
.meta_chunk_size_kbytes = 2,
.min_meta_chunk_size_bytes = 256,
.dchub_arb_to_ret_delay = 102,
.hostvm_mode = 1,
};
static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params)
{
ip_caps->pipe_count = ip_params->max_num_dpp;
@ -153,6 +233,37 @@ bool core_dcn4_initialize(struct dml2_core_initialize_in_out *in_out)
return true;
}
bool core_dcn42_initialize(struct dml2_core_initialize_in_out *in_out)
{
struct dml2_core_instance *core = in_out->instance;
if (!in_out->minimum_clock_table)
return false;
else
core->minimum_clock_table = in_out->minimum_clock_table;
if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) {
memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size);
// FIXME_STAGE2:
// DV still uses stage1 ip_param_st for each variant, need to patch the ip_caps with ip_param info
// Should move DV to use ip_caps but need move more overrides to ip_caps
patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb);
core->clean_me_up.mode_lib.ip.subvp_pstate_allow_width_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
core->clean_me_up.mode_lib.ip.subvp_fw_processing_delay_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us;
core->clean_me_up.mode_lib.ip.subvp_swath_height_margin_lines = core_dcn4_ip_caps_base.subvp_swath_height_margin_lines;
} else {
memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn42_ip_caps_base, sizeof(struct dml2_core_ip_params));
patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps);
core->clean_me_up.mode_lib.ip.imall_supported = false;
}
memcpy(&core->clean_me_up.mode_lib.soc, in_out->soc_bb, sizeof(struct dml2_soc_bb));
memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
return true;
}
static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters *phantom, const struct dml2_stream_parameters *main,
const struct dml2_implicit_svp_meta *meta)
{

View File

@ -5,6 +5,7 @@
#ifndef __DML2_CORE_DCN4_H__
#define __DML2_CORE_DCN4_H__
bool core_dcn4_initialize(struct dml2_core_initialize_in_out *in_out);
bool core_dcn42_initialize(struct dml2_core_initialize_in_out *in_out);
bool core_dcn4_mode_support(struct dml2_core_mode_support_in_out *in_out);
bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out);
bool core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out *in_out);

View File

@ -21,6 +21,7 @@ bool dml2_core_create(enum dml2_project_id project_id, struct dml2_core_instance
case dml2_project_dcn4x_stage1:
result = false;
break;
case dml2_project_dcn40:
case dml2_project_dcn4x_stage2:
case dml2_project_dcn4x_stage2_auto_drr_svp:
out->initialize = &core_dcn4_initialize;
@ -30,6 +31,14 @@ bool dml2_core_create(enum dml2_project_id project_id, struct dml2_core_instance
out->calculate_mcache_allocation = &core_dcn4_calculate_mcache_allocation;
result = true;
break;
case dml2_project_dcn42:
out->initialize = &core_dcn42_initialize;
out->mode_support = &core_dcn4_mode_support;
out->mode_programming = &core_dcn4_mode_programming;
out->populate_informative = &core_dcn4_populate_informative;
out->calculate_mcache_allocation = &core_dcn4_calculate_mcache_allocation;
result = true;
break;
case dml2_project_invalid:
default:
break;

View File

@ -428,6 +428,9 @@ bool dml2_core_utils_is_phantom_pipe(const struct dml2_plane_parameters *plane_c
unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel)
{
if (dml2_core_utils_get_gfx_version(sw_mode) == 10 || dml2_core_utils_get_gfx_version(sw_mode) == 7) {
return dml2_core_utils_get_tile_block_size_bytes_backcompat(sw_mode, byte_per_pixel);
}
if (sw_mode == dml2_sw_linear)
return 256;
@ -459,14 +462,56 @@ unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw
};
}
unsigned int dml2_core_utils_get_tile_block_size_bytes_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel)
{
if (sw_mode == dml2_sw_linear_256b)
return 256;
else if (sw_mode == dml2_gfx10_sw_64kb_r_x)
return 65536;
else if (sw_mode == dml2_gfx102_sw_64kb_s)
return 65536;
else if (sw_mode == dml2_gfx102_sw_64kb_s_t)
return 65536;
else if (sw_mode == dml2_gfx102_sw_64kb_s_x)
return 65536;
else if (sw_mode == dml2_gfx102_sw_64kb_r_x)
return 65536;
else if (sw_mode == dml2_linear_64elements)
return 256;
else if (sw_mode == dml2_gfx7_1d_thin)
return 256;
else if (sw_mode == dml2_gfx7_2d_thin_gen_zero)
return (128 * 64 * byte_per_pixel);
else if (sw_mode == dml2_gfx7_2d_thin_gen_one)
return (128 * 128 * byte_per_pixel);
else if (sw_mode == dml2_gfx7_2d_thin_arlene)
return (64 * 32 * byte_per_pixel);
else if (sw_mode == dml2_gfx7_2d_thin_anubis)
return (128 * 128 * byte_per_pixel);
else {
DML_ASSERT(0);
return 256;
};
}
bool dml2_core_utils_get_segment_horizontal_contiguous(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel)
{
return (byte_per_pixel != 2);
if (dml2_core_utils_get_gfx_version(sw_mode) == 10 || dml2_core_utils_get_gfx_version(sw_mode) == 7) {
return dml2_core_utils_get_segment_horizontal_contiguous_backcompat(sw_mode, byte_per_pixel);
} else {
return (byte_per_pixel != 2);
}
}
bool dml2_core_utils_get_segment_horizontal_contiguous_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel)
{
return !((byte_per_pixel == 4) &&
((sw_mode == dml2_gfx10_sw_64kb_r_x) || (sw_mode == dml2_gfx102_sw_64kb_s) || (sw_mode == dml2_gfx102_sw_64kb_s_t) || (sw_mode == dml2_gfx102_sw_64kb_s_x)));
}
bool dml2_core_utils_is_linear(enum dml2_swizzle_mode sw_mode)
{
return sw_mode == dml2_sw_linear;
return (sw_mode == dml2_sw_linear || sw_mode == dml2_sw_linear_256b || sw_mode == dml2_linear_64elements);
};
@ -499,6 +544,20 @@ int unsigned dml2_core_utils_get_gfx_version(enum dml2_swizzle_mode sw_mode)
sw_mode == dml2_gfx11_sw_256kb_d_x ||
sw_mode == dml2_gfx11_sw_256kb_r_x)
version = 11;
else if (sw_mode == dml2_sw_linear_256b ||
sw_mode == dml2_gfx10_sw_64kb_r_x ||
sw_mode == dml2_gfx102_sw_64kb_s ||
sw_mode == dml2_gfx102_sw_64kb_s_t ||
sw_mode == dml2_gfx102_sw_64kb_s_x ||
sw_mode == dml2_gfx102_sw_64kb_r_x)
version = 10;
else if (sw_mode == dml2_linear_64elements ||
sw_mode == dml2_gfx7_1d_thin ||
sw_mode == dml2_gfx7_2d_thin_gen_zero ||
sw_mode == dml2_gfx7_2d_thin_gen_one ||
sw_mode == dml2_gfx7_2d_thin_arlene ||
sw_mode == dml2_gfx7_2d_thin_anubis)
version = 7;
else {
DML_LOG_VERBOSE("ERROR: Invalid sw_mode setting! val=%u\n", sw_mode);
DML_ASSERT(0);

View File

@ -22,6 +22,8 @@ void dml2_core_utils_pipe_plane_mapping(const struct core_display_cfg_support_in
bool dml2_core_utils_is_phantom_pipe(const struct dml2_plane_parameters *plane_cfg);
unsigned int dml2_core_utils_get_tile_block_size_bytes(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel);
bool dml2_core_utils_get_segment_horizontal_contiguous(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel);
unsigned int dml2_core_utils_get_tile_block_size_bytes_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel);
bool dml2_core_utils_get_segment_horizontal_contiguous_backcompat(enum dml2_swizzle_mode sw_mode, unsigned int byte_per_pixel);
bool dml2_core_utils_is_vertical_rotation(enum dml2_rotation_angle Scan);
bool dml2_core_utils_is_linear(enum dml2_swizzle_mode sw_mode);
int unsigned dml2_core_utils_get_gfx_version(enum dml2_swizzle_mode sw_mode);

View File

@ -802,3 +802,36 @@ bool dpmm_dcn4_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_
return true;
}
bool dpmm_dcn42_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out)
{
const struct dml2_display_cfg *display_cfg = &in_out->display_cfg->display_config;
const struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->core->clean_me_up.mode_lib;
struct dml2_dchub_global_register_set *dchubbub_regs = &in_out->programming->global_regs;
double refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : mode_lib->soc.dchub_refclk_mhz;
/* set A */
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_enter = (int unsigned)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_exit = (int unsigned)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_enter_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_exit_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].urgent = (int unsigned)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].usr = (int unsigned)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].refcyc_per_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].refcyc_per_meta_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_flip = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_nom = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidth * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_mall = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthMALL * 1000);
/* set B */
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B] = dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A];
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_C] = dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A];
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_D] = dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A];
dchubbub_regs->num_watermark_sets = 4;
return true;
}

View File

@ -10,5 +10,6 @@
bool dpmm_dcn3_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out);
bool dpmm_dcn4_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out);
bool dpmm_dcn4_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out);
bool dpmm_dcn42_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out);
#endif

View File

@ -31,6 +31,7 @@ bool dml2_dpmm_create(enum dml2_project_id project_id, struct dml2_dpmm_instance
out->map_watermarks = &dummy_map_watermarks;
result = true;
break;
case dml2_project_dcn40:
case dml2_project_dcn4x_stage2:
out->map_mode_to_soc_dpm = &dpmm_dcn3_map_mode_to_soc_dpm;
out->map_watermarks = &dummy_map_watermarks;
@ -41,6 +42,11 @@ bool dml2_dpmm_create(enum dml2_project_id project_id, struct dml2_dpmm_instance
out->map_watermarks = &dpmm_dcn4_map_watermarks;
result = true;
break;
case dml2_project_dcn42:
out->map_mode_to_soc_dpm = &dpmm_dcn4_map_mode_to_soc_dpm;
out->map_watermarks = &dpmm_dcn42_map_watermarks;
result = true;
break;
case dml2_project_invalid:
default:
break;

View File

@ -10,4 +10,4 @@
bool mcg_dcn4_build_min_clock_table(struct dml2_mcg_build_min_clock_table_params_in_out *in_out);
bool mcg_dcn4_unit_test(void);
#endif
#endif

View File

@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#include "dml2_mcg_dcn42.h"
#include "dml_top_soc_parameter_types.h"
static unsigned long long uclk_to_dram_bw_kbps(unsigned long uclk_khz, const struct dml2_dram_params *dram_config, unsigned long wck_ratio)
{
unsigned long long bw_kbps = 0;
bw_kbps = (unsigned long long) uclk_khz * dram_config->channel_count * dram_config->channel_width_bytes * wck_ratio * 2;
return bw_kbps;
}
static bool build_min_clk_table_coarse_grained(const struct dml2_soc_bb *soc_bb, struct dml2_mcg_min_clock_table *min_table)
{
int i;
for (i = 0; i < soc_bb->clk_table.fclk.num_clk_values; i++) {
if (i < soc_bb->clk_table.uclk.num_clk_values) {
min_table->dram_bw_table.entries[i].pre_derate_dram_bw_kbps =
uclk_to_dram_bw_kbps(soc_bb->clk_table.uclk.clk_values_khz[i], &soc_bb->clk_table.dram_config, soc_bb->clk_table.wck_ratio.clk_values_khz[i]);
min_table->dram_bw_table.entries[i].min_uclk_khz = soc_bb->clk_table.uclk.clk_values_khz[i];
} else {
min_table->dram_bw_table.entries[i].pre_derate_dram_bw_kbps = min_table->dram_bw_table.entries[soc_bb->clk_table.uclk.num_clk_values - 1].pre_derate_dram_bw_kbps;
min_table->dram_bw_table.entries[i].min_uclk_khz = soc_bb->clk_table.uclk.clk_values_khz[soc_bb->clk_table.uclk.num_clk_values - 1];
}
min_table->dram_bw_table.entries[i].min_dcfclk_khz = soc_bb->clk_table.dcfclk.clk_values_khz[i];
min_table->dram_bw_table.entries[i].min_fclk_khz = soc_bb->clk_table.fclk.clk_values_khz[i];
}
min_table->dram_bw_table.num_entries = soc_bb->clk_table.fclk.num_clk_values;
return true;
}
static bool build_min_clock_table(const struct dml2_soc_bb *soc_bb, struct dml2_mcg_min_clock_table *min_table)
{
bool result;
if (!soc_bb || !min_table)
return false;
if (soc_bb->clk_table.uclk.num_clk_values > DML_MCG_MAX_CLK_TABLE_SIZE)
return false;
min_table->fixed_clocks_khz.amclk = 0;
min_table->fixed_clocks_khz.dprefclk = soc_bb->dprefclk_mhz * 1000;
min_table->fixed_clocks_khz.pcierefclk = soc_bb->pcie_refclk_mhz * 1000;
min_table->fixed_clocks_khz.dchubrefclk = soc_bb->dchub_refclk_mhz * 1000;
min_table->fixed_clocks_khz.xtalclk = soc_bb->xtalclk_mhz * 1000;
min_table->max_clocks_khz.dispclk = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1];
min_table->max_clocks_khz.dppclk = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1];
min_table->max_clocks_khz.dscclk = soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1];
min_table->max_clocks_khz.dtbclk = soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1];
min_table->max_clocks_khz.phyclk = soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1];
min_table->max_ss_clocks_khz.dispclk = (unsigned int)((double)min_table->max_clocks_khz.dispclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0));
min_table->max_ss_clocks_khz.dppclk = (unsigned int)((double)min_table->max_clocks_khz.dppclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0));
min_table->max_ss_clocks_khz.dtbclk = (unsigned int)((double)min_table->max_clocks_khz.dtbclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0));
min_table->max_clocks_khz.dcfclk = soc_bb->clk_table.dcfclk.clk_values_khz[soc_bb->clk_table.dcfclk.num_clk_values - 1];
min_table->max_clocks_khz.fclk = soc_bb->clk_table.fclk.clk_values_khz[soc_bb->clk_table.fclk.num_clk_values - 1];
result = build_min_clk_table_coarse_grained(soc_bb, min_table);
return result;
}
bool mcg_dcn42_build_min_clock_table(struct dml2_mcg_build_min_clock_table_params_in_out *in_out)
{
return build_min_clock_table(in_out->soc_bb, in_out->min_clk_table);
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: MIT */
//
// Copyright 2026 Advanced Micro Devices, Inc.
#ifndef __DML2_MCG_DCN42_H__
#define __DML2_MCG_DCN42_H__
#include "dml2_internal_shared_types.h"
bool mcg_dcn42_build_min_clock_table(struct dml2_mcg_build_min_clock_table_params_in_out *in_out);
#endif

View File

@ -4,6 +4,7 @@
#include "dml2_mcg_factory.h"
#include "dml2_mcg_dcn4.h"
#include "dml2_mcg_dcn42.h"
#include "dml2_external_lib_deps.h"
static bool dummy_build_min_clock_table(struct dml2_mcg_build_min_clock_table_params_in_out *in_out)
@ -25,11 +26,16 @@ bool dml2_mcg_create(enum dml2_project_id project_id, struct dml2_mcg_instance *
out->build_min_clock_table = &dummy_build_min_clock_table;
result = true;
break;
case dml2_project_dcn40:
case dml2_project_dcn4x_stage2:
case dml2_project_dcn4x_stage2_auto_drr_svp:
out->build_min_clock_table = &mcg_dcn4_build_min_clock_table;
result = true;
break;
case dml2_project_dcn42:
out->build_min_clock_table = &mcg_dcn42_build_min_clock_table;
result = true;
break;
case dml2_project_invalid:
default:
break;

View File

@ -23,6 +23,7 @@ static const struct dml2_pmo_pstate_strategy base_strategy_list_1_display[] = {
.allow_state_increase = true,
},
// Then VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
@ -53,6 +54,7 @@ static const struct dml2_pmo_pstate_strategy base_strategy_list_2_display[] = {
.allow_state_increase = true,
},
// Then VActive + VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
@ -113,6 +115,7 @@ static const struct dml2_pmo_pstate_strategy base_strategy_list_3_display[] = {
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na },
@ -149,6 +152,7 @@ static const struct dml2_pmo_pstate_strategy base_strategy_list_4_display[] = {
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank },
@ -1651,6 +1655,7 @@ static bool validate_pstate_support_strategy_cofunctionality(struct dml2_pmo_ins
if (svp_count > 0 && (pmo->options->disable_svp || !all_timings_support_svp(pmo, display_cfg, svp_stream_mask)))
return false;
return is_config_schedulable(pmo, display_cfg, pstate_strategy);
}
@ -1980,6 +1985,7 @@ static void reset_display_configuration(struct display_configuation_with_meta *d
}
}
static void setup_planes_for_drr_by_mask(struct display_configuation_with_meta *display_config,
struct dml2_pmo_instance *pmo,
int plane_mask)

View File

@ -3,8 +3,8 @@
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_pmo_factory.h"
#include "dml2_pmo_dcn4_fams2.h"
#include "dml2_pmo_dcn3.h"
#include "dml2_pmo_dcn4_fams2.h"
#include "dml2_external_lib_deps.h"
static bool dummy_init_for_stutter(struct dml2_pmo_init_for_stutter_in_out *in_out)
@ -37,6 +37,7 @@ bool dml2_pmo_create(enum dml2_project_id project_id, struct dml2_pmo_instance *
out->optimize_dcc_mcache = pmo_dcn4_fams2_optimize_dcc_mcache;
result = true;
break;
case dml2_project_dcn40:
case dml2_project_dcn4x_stage2:
out->initialize = pmo_dcn3_initialize;
@ -56,6 +57,7 @@ bool dml2_pmo_create(enum dml2_project_id project_id, struct dml2_pmo_instance *
result = true;
break;
case dml2_project_dcn42:
case dml2_project_dcn4x_stage2_auto_drr_svp:
out->initialize = pmo_dcn4_fams2_initialize;

View File

@ -10,4 +10,4 @@
bool dml2_pmo_create(enum dml2_project_id project_id, struct dml2_pmo_instance *out);
#endif
#endif

View File

@ -17,6 +17,8 @@ bool dml2_initialize_instance(struct dml2_initialize_instance_in_out *in_out)
case dml2_project_dcn4x_stage1:
case dml2_project_dcn4x_stage2:
case dml2_project_dcn4x_stage2_auto_drr_svp:
case dml2_project_dcn40:
case dml2_project_dcn42:
return dml2_top_soc15_initialize_instance(in_out);
case dml2_project_invalid:
default:

View File

@ -3,7 +3,6 @@
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_top_legacy.h"
#include "dml2_top_soc15.h"
#include "dml2_core_factory.h"
#include "dml2_pmo_factory.h"
#include "display_mode_core_structs.h"

View File

@ -410,6 +410,7 @@ struct dml2_core_mode_support_in_out {
} legacy;
};
struct dml2_core_mode_programming_in_out {
/*
* Inputs
@ -501,6 +502,7 @@ struct dml2_core_instance {
bool (*populate_informative)(struct dml2_core_populate_informative_in_out *in_out);
bool (*calculate_mcache_allocation)(struct dml2_calculate_mcache_allocation_in_out *in_out);
struct {
struct dml2_core_internal_display_mode_lib mode_lib;
} clean_me_up;
@ -753,6 +755,7 @@ struct dml2_pmo_instance {
bool (*test_for_stutter)(struct dml2_pmo_test_for_stutter_in_out *in_out);
bool (*optimize_for_stutter)(struct dml2_pmo_optimize_for_stutter_in_out *in_out);
struct dml2_pmo_init_data init_data;
struct dml2_pmo_scratch scratch;
};

View File

@ -357,7 +357,7 @@ static bool enough_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *st
*/
static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *context)
{
struct pipe_ctx *subvp_pipes[2];
struct pipe_ctx *subvp_pipes[2] = { NULL, NULL };
struct dc_stream_state *phantom = NULL;
uint32_t microschedule_lines = 0;
uint32_t index = 0;
@ -369,6 +369,9 @@ static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *c
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
uint32_t time_us = 0;
if (pipe == NULL || pipe->stream == NULL)
continue;
/* Loop to calculate the maximum microschedule time between the two SubVP pipes,
* and also to store the two main SubVP pipe pointers in subvp_pipes[2].
*/
@ -386,14 +389,19 @@ static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *c
if (time_us > max_microschedule_us)
max_microschedule_us = time_us;
subvp_pipes[index] = pipe;
index++;
if (index < 2)
subvp_pipes[index++] = pipe;
// Maximum 2 SubVP pipes
if (index == 2)
break;
}
}
/* Minimal guard to avoid C6001 before subvp_pipes[0]/[1] dereference */
if (index < 2 || !subvp_pipes[0] || !subvp_pipes[1])
return false;
vactive1_us = ((subvp_pipes[0]->stream->timing.v_addressable * subvp_pipes[0]->stream->timing.h_total) /
(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
vactive2_us = ((subvp_pipes[1]->stream->timing.v_addressable * subvp_pipes[1]->stream->timing.h_total) /
@ -459,6 +467,11 @@ bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context
break;
}
if (pipe == NULL || pipe->stream == NULL) {
// Defensive: should never happen, try to catch in debug
ASSERT(0);
return false;
}
phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream);
main_timing = &pipe->stream->timing;
phantom_timing = &phantom_stream->timing;
@ -549,6 +562,13 @@ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state *
if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
subvp_pipe = pipe;
}
if (subvp_pipe == NULL) {
// Defensive: should never happen, catch in debug
ASSERT(0);
return false;
}
// Use ignore_msa_timing_param flag to identify as DRR
if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
// SUBVP + DRR case
@ -753,6 +773,12 @@ static void enable_phantom_plane(struct dml2_context *ctx,
return;
}
/* Minimal NULL guard for C6011 */
if (!phantom_plane) {
ASSERT(0);
continue;
}
memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address));
memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality,
sizeof(phantom_plane->scaling_quality));
@ -880,6 +906,11 @@ bool dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context *ctx, struct dc_s
if (ctx->config.svp_pstate.force_disable_subvp)
return false;
if (!state) {
ASSERT(0);
return false;
}
if (!all_pipes_have_stream_and_plane(ctx, state))
return false;
@ -898,6 +929,10 @@ bool dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context *ctx, struct dc_s
}
if (enough_pipes_for_subvp(ctx, state) && assign_subvp_pipe(ctx, state, &dc_pipe_idx)) {
if (state->res_ctx.pipe_ctx[dc_pipe_idx].stream == NULL) {
ASSERT(0);
return false;
}
dml_pipe_idx = dml2_helper_find_dml_pipe_idx_by_stream_id(ctx, state->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id);
svp_height = mode_support_info->SubViewportLinesNeededInMALL[dml_pipe_idx];
vstartup = dml_get_vstartup_calculated(&ctx->v20.dml_core_ctx, dml_pipe_idx);

View File

@ -84,8 +84,9 @@ static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_op
bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
{
// TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete.
if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version >= DCN_VERSION_4_01))
if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version >= DCN_VERSION_4_01)) {
return dml21_create(in_dc, dml2, config);
}
// Allocate Mode Lib Ctx
*dml2 = dml2_allocate_memory();

View File

@ -172,10 +172,14 @@ bool dpp1_get_optimal_number_of_taps(
scl_data->taps.h_taps_c = in_taps->h_taps_c;
if (!dpp->ctx->dc->debug.always_scale) {
if (IDENTITY_RATIO(scl_data->ratios.horz))
if (IDENTITY_RATIO(scl_data->ratios.horz)) {
scl_data->taps.h_taps = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert))
scl_data->taps.h_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.vert)) {
scl_data->taps.v_taps = 1;
scl_data->taps.v_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.horz_c))
scl_data->taps.h_taps_c = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert_c))

View File

@ -524,10 +524,14 @@ bool dpp3_get_optimal_number_of_taps(
scl_data->taps.v_taps_c = max_taps_c;
if (!dpp->ctx->dc->debug.always_scale) {
if (IDENTITY_RATIO(scl_data->ratios.horz))
if (IDENTITY_RATIO(scl_data->ratios.horz)) {
scl_data->taps.h_taps = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert))
scl_data->taps.h_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.vert)) {
scl_data->taps.v_taps = 1;
scl_data->taps.v_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.horz_c))
scl_data->taps.h_taps_c = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert_c))

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