amd-drm-next-6.6-2023-08-18:

amdgpu:
 - Panel replay fixes
 - Misc checkpatch fixes
 - SMU 13.x fixes
 - mcbp parameter handling fix for gfx9
 - RAS fixes
 - Misc code cleanups
 - SR-IOV fixes
 - Expose both current and average power via hwmon if supported
 - DP retimer fix
 - Clockgating fix
 - Subvp fixes
 - DMCUB fixes
 - Gamut remap fix
 - Misc display fixes
 - Allow users to force runtime pm when displays are attached
 - Gracefully handle more partitions than drm nodes
 - S0ix fixes
 - GC 9.4.3 fixes
 
 amdkfd:
 - TBA fix for aldebaran
 - Fix build without CONFIG_DYNAMIC_DEBUG
 - memdup cleanup
 - Fix address watch clearing
 
 radeon:
 - Misc code cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCZN/JmQAKCRC93/aFa7yZ
 2MyMAQCOXoO+UAiuxwiyYCR7MTNxueYsiE+APjWpD/r13JJk2AD+Nic8dzZV0s64
 IwAYrVsQuWL5YawLuj3uOiEshQ3oJwo=
 =cbeN
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-next-6.6-2023-08-18' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-6.6-2023-08-18:

amdgpu:
- Panel replay fixes
- Misc checkpatch fixes
- SMU 13.x fixes
- mcbp parameter handling fix for gfx9
- RAS fixes
- Misc code cleanups
- SR-IOV fixes
- Expose both current and average power via hwmon if supported
- DP retimer fix
- Clockgating fix
- Subvp fixes
- DMCUB fixes
- Gamut remap fix
- Misc display fixes
- Allow users to force runtime pm when displays are attached
- Gracefully handle more partitions than drm nodes
- S0ix fixes
- GC 9.4.3 fixes

amdkfd:
- TBA fix for aldebaran
- Fix build without CONFIG_DYNAMIC_DEBUG
- memdup cleanup
- Fix address watch clearing

radeon:
- Misc code cleanups

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

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230818195247.10981-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2023-08-21 11:26:34 +10:00
commit cacaeb27ad
120 changed files with 2365 additions and 1123 deletions

View File

@ -192,7 +192,6 @@ extern int amdgpu_emu_mode;
extern uint amdgpu_smu_memory_pool_size;
extern int amdgpu_smu_pptable_id;
extern uint amdgpu_dc_feature_mask;
extern uint amdgpu_freesync_vid_mode;
extern uint amdgpu_dc_debug_mask;
extern uint amdgpu_dc_visual_confirm;
extern uint amdgpu_dm_abm_level;

View File

@ -706,7 +706,7 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
atcs_input.size = sizeof(struct atcs_pref_req_input);
/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
atcs_input.client_id = adev->pdev->devfn | (adev->pdev->bus->number << 8);
atcs_input.client_id = pci_dev_id(adev->pdev);
atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
if (advertise)
@ -776,7 +776,7 @@ int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
atcs_input.size = sizeof(struct atcs_pwr_shift_input);
/* dGPU id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
atcs_input.dgpu_id = adev->pdev->devfn | (adev->pdev->bus->number << 8);
atcs_input.dgpu_id = pci_dev_id(adev->pdev);
atcs_input.dev_acpi_state = dev_state;
atcs_input.drv_state = drv_state;
@ -1141,7 +1141,7 @@ int amdgpu_acpi_get_tmr_info(struct amdgpu_device *adev, u64 *tmr_offset,
if (!tmr_offset || !tmr_size)
return -EINVAL;
bdf = (adev->pdev->bus->number << 8) | adev->pdev->devfn;
bdf = pci_dev_id(adev->pdev);
dev_info = amdgpu_acpi_get_dev(bdf);
if (!dev_info)
return -ENOENT;
@ -1162,7 +1162,7 @@ int amdgpu_acpi_get_mem_info(struct amdgpu_device *adev, int xcc_id,
if (!numa_info)
return -EINVAL;
bdf = (adev->pdev->bus->number << 8) | adev->pdev->devfn;
bdf = pci_dev_id(adev->pdev);
dev_info = amdgpu_acpi_get_dev(bdf);
if (!dev_info)
return -ENOENT;

View File

@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch(
return watch_address_cntl;
}
static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev,
uint32_t watch_id)
{
return 0;
}
const struct kfd2kgd_calls aldebaran_kfd2kgd = {
.program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping,
@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = {
.set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override,
.set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode,
.set_address_watch = kgd_gfx_aldebaran_set_address_watch,
.clear_address_watch = kgd_gfx_aldebaran_clear_address_watch,
.clear_address_watch = kgd_gfx_v9_clear_address_watch,
.get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times,
.build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info,
.program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,

View File

@ -39,7 +39,6 @@
#include "amdgpu_xgmi.h"
#include "kfd_priv.h"
#include "kfd_smi_events.h"
#include <drm/ttm/ttm_tt.h>
/* Userptr restore delay, just long enough to allow consecutive VM
* changes to accumulate

View File

@ -305,10 +305,16 @@ size_t amdgpu_device_aper_access(struct amdgpu_device *adev, loff_t pos,
if (write) {
memcpy_toio(addr, buf, count);
/* Make sure HDP write cache flush happens without any reordering
* after the system memory contents are sent over PCIe device
*/
mb();
amdgpu_device_flush_hdp(adev, NULL);
} else {
amdgpu_device_invalidate_hdp(adev, NULL);
/* Make sure HDP read cache is invalidated before issuing a read
* to the PCIe device
*/
mb();
memcpy_fromio(buf, addr, count);
}
@ -3487,10 +3493,11 @@ static void amdgpu_device_set_mcbp(struct amdgpu_device *adev)
{
if (amdgpu_mcbp == 1)
adev->gfx.mcbp = true;
if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 0, 0)) &&
(adev->ip_versions[GC_HWIP][0] < IP_VERSION(10, 0, 0)) &&
adev->gfx.num_gfx_rings)
else if (amdgpu_mcbp == 0)
adev->gfx.mcbp = false;
else if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 0, 0)) &&
(adev->ip_versions[GC_HWIP][0] < IP_VERSION(10, 0, 0)) &&
adev->gfx.num_gfx_rings)
adev->gfx.mcbp = true;
if (amdgpu_sriov_vf(adev))
@ -4153,6 +4160,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
cancel_delayed_work_sync(&adev->delayed_init_work);
flush_delayed_work(&adev->gfx.gfx_off_delay_work);
amdgpu_ras_suspend(adev);

View File

@ -334,14 +334,14 @@ enum AMDGPU_DOORBELL_ASSIGNMENT_LAYOUT1 {
AMDGPU_DOORBELL_LAYOUT1_sDMA_ENGINE_END = 0x19F,
/* IH: 0x1A0 ~ 0x1AF */
AMDGPU_DOORBELL_LAYOUT1_IH = 0x1A0,
/* VCN: 0x1B0 ~ 0x1D4 */
/* VCN: 0x1B0 ~ 0x1E8 */
AMDGPU_DOORBELL_LAYOUT1_VCN_START = 0x1B0,
AMDGPU_DOORBELL_LAYOUT1_VCN_END = 0x1D4,
AMDGPU_DOORBELL_LAYOUT1_VCN_END = 0x1E8,
AMDGPU_DOORBELL_LAYOUT1_FIRST_NON_CP = AMDGPU_DOORBELL_LAYOUT1_sDMA_ENGINE_START,
AMDGPU_DOORBELL_LAYOUT1_LAST_NON_CP = AMDGPU_DOORBELL_LAYOUT1_VCN_END,
AMDGPU_DOORBELL_LAYOUT1_MAX_ASSIGNMENT = 0x1D4,
AMDGPU_DOORBELL_LAYOUT1_MAX_ASSIGNMENT = 0x1E8,
AMDGPU_DOORBELL_LAYOUT1_INVALID = 0xFFFF
};

View File

@ -187,7 +187,6 @@ int amdgpu_mes_kiq;
int amdgpu_noretry = -1;
int amdgpu_force_asic_type = -1;
int amdgpu_tmz = -1; /* auto */
uint amdgpu_freesync_vid_mode;
int amdgpu_reset_method = -1; /* auto */
int amdgpu_num_kcq = -1;
int amdgpu_smartshift_bias;
@ -348,8 +347,9 @@ module_param_named(aspm, amdgpu_aspm, int, 0444);
* Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
* the dGPUs when they are idle if supported. The default is -1 (auto enable).
* Setting the value to 0 disables this functionality.
* Setting the value to -2 is auto enabled with power down when displays are attached.
*/
MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto)");
MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto, -2 = autowith displays)");
module_param_named(runpm, amdgpu_runtime_pm, int, 0444);
/**
@ -871,32 +871,6 @@ module_param_named(backlight, amdgpu_backlight, bint, 0444);
MODULE_PARM_DESC(tmz, "Enable TMZ feature (-1 = auto (default), 0 = off, 1 = on)");
module_param_named(tmz, amdgpu_tmz, int, 0444);
/**
* DOC: freesync_video (uint)
* Enable the optimization to adjust front porch timing to achieve seamless
* mode change experience when setting a freesync supported mode for which full
* modeset is not needed.
*
* The Display Core will add a set of modes derived from the base FreeSync
* video mode into the corresponding connector's mode list based on commonly
* used refresh rates and VRR range of the connected display, when users enable
* this feature. From the userspace perspective, they can see a seamless mode
* change experience when the change between different refresh rates under the
* same resolution. Additionally, userspace applications such as Video playback
* can read this modeset list and change the refresh rate based on the video
* frame rate. Finally, the userspace can also derive an appropriate mode for a
* particular refresh rate based on the FreeSync Mode and add it to the
* connector's mode list.
*
* Note: This is an experimental feature.
*
* The default value: 0 (off).
*/
MODULE_PARM_DESC(
freesync_video,
"Enable freesync modesetting optimization feature (0 = off (default), 1 = on)");
module_param_named(freesync_video, amdgpu_freesync_vid_mode, uint, 0444);
/**
* DOC: reset_method (int)
* GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco)
@ -2523,24 +2497,26 @@ static int amdgpu_runtime_idle_check_display(struct device *dev)
struct drm_connector_list_iter iter;
int ret = 0;
/* XXX: Return busy if any displays are connected to avoid
* possible display wakeups after runtime resume due to
* hotplug events in case any displays were connected while
* the GPU was in suspend. Remove this once that is fixed.
*/
mutex_lock(&drm_dev->mode_config.mutex);
drm_connector_list_iter_begin(drm_dev, &iter);
drm_for_each_connector_iter(list_connector, &iter) {
if (list_connector->status == connector_status_connected) {
ret = -EBUSY;
break;
if (amdgpu_runtime_pm != -2) {
/* XXX: Return busy if any displays are connected to avoid
* possible display wakeups after runtime resume due to
* hotplug events in case any displays were connected while
* the GPU was in suspend. Remove this once that is fixed.
*/
mutex_lock(&drm_dev->mode_config.mutex);
drm_connector_list_iter_begin(drm_dev, &iter);
drm_for_each_connector_iter(list_connector, &iter) {
if (list_connector->status == connector_status_connected) {
ret = -EBUSY;
break;
}
}
}
drm_connector_list_iter_end(&iter);
mutex_unlock(&drm_dev->mode_config.mutex);
drm_connector_list_iter_end(&iter);
mutex_unlock(&drm_dev->mode_config.mutex);
if (ret)
return ret;
if (ret)
return ret;
}
if (adev->dc_enabled) {
struct drm_crtc *crtc;

View File

@ -551,6 +551,41 @@ int amdgpu_fence_driver_sw_init(struct amdgpu_device *adev)
return 0;
}
/**
* amdgpu_fence_need_ring_interrupt_restore - helper function to check whether
* fence driver interrupts need to be restored.
*
* @ring: ring that to be checked
*
* Interrupts for rings that belong to GFX IP don't need to be restored
* when the target power state is s0ix.
*
* Return true if need to restore interrupts, false otherwise.
*/
static bool amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
bool is_gfx_power_domain = false;
switch (ring->funcs->type) {
case AMDGPU_RING_TYPE_SDMA:
/* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
if (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0))
is_gfx_power_domain = true;
break;
case AMDGPU_RING_TYPE_GFX:
case AMDGPU_RING_TYPE_COMPUTE:
case AMDGPU_RING_TYPE_KIQ:
case AMDGPU_RING_TYPE_MES:
is_gfx_power_domain = true;
break;
default:
break;
}
return !(adev->in_s0ix && is_gfx_power_domain);
}
/**
* amdgpu_fence_driver_hw_fini - tear down the fence driver
* for all possible rings.
@ -579,7 +614,8 @@ void amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev)
amdgpu_fence_driver_force_completion(ring);
if (!drm_dev_is_unplugged(adev_to_drm(adev)) &&
ring->fence_drv.irq_src)
ring->fence_drv.irq_src &&
amdgpu_fence_need_ring_interrupt_restore(ring))
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
ring->fence_drv.irq_type);
@ -655,7 +691,8 @@ void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)
continue;
/* enable the interrupt */
if (ring->fence_drv.irq_src)
if (ring->fence_drv.irq_src &&
amdgpu_fence_need_ring_interrupt_restore(ring))
amdgpu_irq_get(adev, ring->fence_drv.irq_src,
ring->fence_drv.irq_type);
}

View File

@ -700,15 +700,8 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
if (adev->gfx.gfx_off_req_count == 0 &&
!adev->gfx.gfx_off_state) {
/* If going to s2idle, no need to wait */
if (adev->in_s0ix) {
if (!amdgpu_dpm_set_powergating_by_smu(adev,
AMD_IP_BLOCK_TYPE_GFX, true))
adev->gfx.gfx_off_state = true;
} else {
schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
delay);
}
}
} else {
if (adev->gfx.gfx_off_req_count == 0) {

View File

@ -1019,7 +1019,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
case AMDGPU_INFO_SENSOR_GPU_AVG_POWER:
/* get average GPU power */
if (amdgpu_dpm_read_sensor(adev,
AMDGPU_PP_SENSOR_GPU_POWER,
AMDGPU_PP_SENSOR_GPU_AVG_POWER,
(void *)&ui32, &ui32_size)) {
return -EINVAL;
}

View File

@ -132,6 +132,7 @@ struct psp_funcs {
int (*read_usbc_pd_fw)(struct psp_context *psp, uint32_t *fw_ver);
int (*update_spirom)(struct psp_context *psp, uint64_t fw_pri_mc_addr);
int (*vbflash_stat)(struct psp_context *psp);
int (*fatal_error_recovery_quirk)(struct psp_context *psp);
};
struct ta_funcs {
@ -445,6 +446,10 @@ struct amdgpu_psp_funcs {
((psp)->funcs->vbflash_stat ? \
(psp)->funcs->vbflash_stat((psp)) : -EINVAL)
#define psp_fatal_error_recovery_quirk(psp) \
((psp)->funcs->fatal_error_recovery_quirk ? \
(psp)->funcs->fatal_error_recovery_quirk((psp)) : 0)
extern const struct amd_ip_funcs psp_ip_funcs;
extern const struct amdgpu_ip_block_version psp_v3_1_ip_block;

View File

@ -2064,6 +2064,8 @@ static void amdgpu_ras_do_recovery(struct work_struct *work)
if (ras->gpu_reset_flags & AMDGPU_RAS_GPU_RESET_MODE1_RESET) {
ras->gpu_reset_flags &= ~AMDGPU_RAS_GPU_RESET_MODE1_RESET;
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
psp_fatal_error_recovery_quirk(&adev->psp);
}
}
@ -2970,10 +2972,6 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev)
{
amdgpu_ras_check_supported(adev);
if (!adev->ras_hw_enabled)
return;
if (atomic_cmpxchg(&amdgpu_ras_in_intr, 0, 1) == 0) {
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);

View File

@ -158,6 +158,7 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 7): /* Sienna cichlid */
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 2): /* Aldebaran */
case IP_VERSION(13, 0, 6):
case IP_VERSION(13, 0, 10):
return true;
default:
@ -212,6 +213,7 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
control->i2c_address = EEPROM_I2C_MADDR_0;
return true;
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 6):
case IP_VERSION(13, 0, 10):
control->i2c_address = EEPROM_I2C_MADDR_4;
return true;

View File

@ -397,7 +397,7 @@ void amdgpu_sw_ring_ib_begin(struct amdgpu_ring *ring)
struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
WARN_ON(!ring->is_sw_ring);
if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) {
if (adev->gfx.mcbp && ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) {
if (amdgpu_mcbp_scan(mux) > 0)
amdgpu_mcbp_trigger_preempt(mux);
return;

View File

@ -49,7 +49,6 @@
#include <drm/ttm/ttm_tt.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
#include "amdgpu.h"
#include "amdgpu_object.h"
@ -2420,7 +2419,7 @@ static ssize_t amdgpu_iomem_read(struct file *f, char __user *buf,
struct page *p;
void *ptr;
bytes = bytes < size ? bytes : size;
bytes = min(bytes, size);
/* Translate the bus address to a physical address. If
* the domain is NULL it means there is no IOMMU active
@ -2475,7 +2474,7 @@ static ssize_t amdgpu_iomem_write(struct file *f, const char __user *buf,
struct page *p;
void *ptr;
bytes = bytes < size ? bytes : size;
bytes = min(bytes, size);
addr = dom ? iommu_iova_to_phys(dom, addr) : addr;

View File

@ -239,8 +239,13 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev)
for (i = 1; i < MAX_XCP; i++) {
ret = amdgpu_xcp_drm_dev_alloc(&p_ddev);
if (ret)
if (ret == -ENOSPC) {
dev_warn(adev->dev,
"Skip xcp node #%d when out of drm node resource.", i);
return 0;
} else if (ret) {
return ret;
}
/* Redirect all IOCTLs to the primary device */
adev->xcp_mgr->xcp[i].rdev = p_ddev->render->dev;
@ -328,6 +333,9 @@ int amdgpu_xcp_dev_register(struct amdgpu_device *adev,
return 0;
for (i = 1; i < MAX_XCP; i++) {
if (!adev->xcp_mgr->xcp[i].ddev)
break;
ret = drm_dev_register(adev->xcp_mgr->xcp[i].ddev, ent->driver_data);
if (ret)
return ret;
@ -345,6 +353,9 @@ void amdgpu_xcp_dev_unplug(struct amdgpu_device *adev)
return;
for (i = 1; i < MAX_XCP; i++) {
if (!adev->xcp_mgr->xcp[i].ddev)
break;
p_ddev = adev->xcp_mgr->xcp[i].ddev;
drm_dev_unplug(p_ddev);
p_ddev->render->dev = adev->xcp_mgr->xcp[i].rdev;

View File

@ -117,12 +117,15 @@ struct drm_device;
struct card_info {
struct drm_device *dev;
void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */
void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */
void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
uint32_t (* pll_read)(struct card_info *, uint32_t); /* filled by driver */
void (*reg_write)(struct card_info *info,
u32 reg, uint32_t val); /* filled by driver */
uint32_t (*reg_read)(struct card_info *info, uint32_t reg); /* filled by driver */
void (*mc_write)(struct card_info *info,
u32 reg, uint32_t val); /* filled by driver */
uint32_t (*mc_read)(struct card_info *info, uint32_t reg); /* filled by driver */
void (*pll_write)(struct card_info *info,
u32 reg, uint32_t val); /* filled by driver */
uint32_t (*pll_read)(struct card_info *info, uint32_t reg); /* filled by driver */
};
struct atom_context {
@ -152,10 +155,10 @@ struct atom_context {
extern int amdgpu_atom_debug;
struct atom_context *amdgpu_atom_parse(struct card_info *, void *);
int amdgpu_atom_execute_table(struct atom_context *, int, uint32_t *);
int amdgpu_atom_asic_init(struct atom_context *);
void amdgpu_atom_destroy(struct atom_context *);
struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios);
int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params);
int amdgpu_atom_asic_init(struct atom_context *ctx);
void amdgpu_atom_destroy(struct atom_context *ctx);
bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size,
uint8_t *frev, uint8_t *crev, uint16_t *data_start);
bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index,

View File

@ -337,13 +337,11 @@ static uint64_t gfx_v9_4_3_get_gpu_clock_counter(struct amdgpu_device *adev)
{
uint64_t clock;
amdgpu_gfx_off_ctrl(adev, false);
mutex_lock(&adev->gfx.gpu_clock_mutex);
WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_CAPTURE_GPU_CLOCK_COUNT, 1);
clock = (uint64_t)RREG32_SOC15(GC, GET_INST(GC, 0), regRLC_GPU_CLOCK_COUNT_LSB) |
((uint64_t)RREG32_SOC15(GC, GET_INST(GC, 0), regRLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
mutex_unlock(&adev->gfx.gpu_clock_mutex);
amdgpu_gfx_off_ctrl(adev, true);
return clock;
}

View File

@ -1998,6 +1998,19 @@ static int gmc_v9_0_init_mem_ranges(struct amdgpu_device *adev)
return 0;
}
static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev)
{
static const u32 regBIF_BIOS_SCRATCH_4 = 0x50;
u32 vram_info;
if (!amdgpu_sriov_vf(adev)) {
vram_info = RREG32(regBIF_BIOS_SCRATCH_4);
adev->gmc.vram_vendor = vram_info & 0xF;
}
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
}
static int gmc_v9_0_sw_init(void *handle)
{
int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits;
@ -2010,15 +2023,12 @@ static int gmc_v9_0_sw_init(void *handle)
spin_lock_init(&adev->gmc.invalidate_lock);
if (!(adev->bios) || adev->gmc.is_app_apu) {
if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3)) {
gmc_v9_4_3_init_vram_info(adev);
} else if (!adev->bios) {
if (adev->flags & AMD_IS_APU) {
if (adev->gmc.is_app_apu) {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
} else {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4;
adev->gmc.vram_width = 64 * 64;
}
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4;
adev->gmc.vram_width = 64 * 64;
} else {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;

View File

@ -26,6 +26,7 @@
#include "soc15.h"
#include "soc15d.h"
#include "jpeg_v4_0_3.h"
#include "mmsch_v4_0_3.h"
#include "vcn/vcn_4_0_3_offset.h"
#include "vcn/vcn_4_0_3_sh_mask.h"
@ -41,6 +42,7 @@ static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev);
static int jpeg_v4_0_3_set_powergating_state(void *handle,
enum amd_powergating_state state);
static void jpeg_v4_0_3_set_ras_funcs(struct amdgpu_device *adev);
static void jpeg_v4_0_3_dec_ring_set_wptr(struct amdgpu_ring *ring);
static int amdgpu_ih_srcid_jpeg[] = {
VCN_4_0__SRCID__JPEG_DECODE,
@ -109,9 +111,20 @@ static int jpeg_v4_0_3_sw_init(void *handle)
ring = &adev->jpeg.inst[i].ring_dec[j];
ring->use_doorbell = true;
ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id);
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
1 + j + 9 * jpeg_inst;
if (!amdgpu_sriov_vf(adev)) {
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
1 + j + 9 * jpeg_inst;
} else {
if (j < 4)
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
4 + j + 32 * jpeg_inst;
else
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
8 + j + 32 * jpeg_inst;
}
sprintf(ring->name, "jpeg_dec_%d.%d", adev->jpeg.inst[i].aid_id, j);
r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0,
AMDGPU_RING_PRIO_DEFAULT, NULL);
@ -160,6 +173,119 @@ static int jpeg_v4_0_3_sw_fini(void *handle)
return r;
}
static int jpeg_v4_0_3_start_sriov(struct amdgpu_device *adev)
{
struct amdgpu_ring *ring;
uint64_t ctx_addr;
uint32_t param, resp, expected;
uint32_t tmp, timeout;
struct amdgpu_mm_table *table = &adev->virt.mm_table;
uint32_t *table_loc;
uint32_t table_size;
uint32_t size, size_dw, item_offset;
uint32_t init_status;
int i, j, jpeg_inst;
struct mmsch_v4_0_cmd_direct_write
direct_wt = { {0} };
struct mmsch_v4_0_cmd_end end = { {0} };
struct mmsch_v4_0_3_init_header header;
direct_wt.cmd_header.command_type =
MMSCH_COMMAND__DIRECT_REG_WRITE;
end.cmd_header.command_type =
MMSCH_COMMAND__END;
for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) {
jpeg_inst = GET_INST(JPEG, i);
memset(&header, 0, sizeof(struct mmsch_v4_0_3_init_header));
header.version = MMSCH_VERSION;
header.total_size = sizeof(struct mmsch_v4_0_3_init_header) >> 2;
table_loc = (uint32_t *)table->cpu_addr;
table_loc += header.total_size;
item_offset = header.total_size;
for (j = 0; j < adev->jpeg.num_jpeg_rings; j++) {
ring = &adev->jpeg.inst[i].ring_dec[j];
table_size = 0;
tmp = SOC15_REG_OFFSET(JPEG, 0, regUVD_JMI0_UVD_LMI_JRBC_RB_64BIT_BAR_LOW);
MMSCH_V4_0_INSERT_DIRECT_WT(tmp, lower_32_bits(ring->gpu_addr));
tmp = SOC15_REG_OFFSET(JPEG, 0, regUVD_JMI0_UVD_LMI_JRBC_RB_64BIT_BAR_HIGH);
MMSCH_V4_0_INSERT_DIRECT_WT(tmp, upper_32_bits(ring->gpu_addr));
tmp = SOC15_REG_OFFSET(JPEG, 0, regUVD_JRBC0_UVD_JRBC_RB_SIZE);
MMSCH_V4_0_INSERT_DIRECT_WT(tmp, ring->ring_size / 4);
if (j <= 3) {
header.mjpegdec0[j].table_offset = item_offset;
header.mjpegdec0[j].init_status = 0;
header.mjpegdec0[j].table_size = table_size;
} else {
header.mjpegdec1[j - 4].table_offset = item_offset;
header.mjpegdec1[j - 4].init_status = 0;
header.mjpegdec1[j - 4].table_size = table_size;
}
header.total_size += table_size;
item_offset += table_size;
}
MMSCH_V4_0_INSERT_END();
/* send init table to MMSCH */
size = sizeof(struct mmsch_v4_0_3_init_header);
table_loc = (uint32_t *)table->cpu_addr;
memcpy((void *)table_loc, &header, size);
ctx_addr = table->gpu_addr;
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_CTX_ADDR_LO, lower_32_bits(ctx_addr));
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_CTX_ADDR_HI, upper_32_bits(ctx_addr));
tmp = RREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_VMID);
tmp &= ~MMSCH_VF_VMID__VF_CTX_VMID_MASK;
tmp |= (0 << MMSCH_VF_VMID__VF_CTX_VMID__SHIFT);
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_VMID, tmp);
size = header.total_size;
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_CTX_SIZE, size);
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_MAILBOX_RESP, 0);
param = 0x00000001;
WREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_MAILBOX_HOST, param);
tmp = 0;
timeout = 1000;
resp = 0;
expected = MMSCH_VF_MAILBOX_RESP__OK;
init_status =
((struct mmsch_v4_0_3_init_header *)(table_loc))->mjpegdec0[i].init_status;
while (resp != expected) {
resp = RREG32_SOC15(VCN, jpeg_inst, regMMSCH_VF_MAILBOX_RESP);
if (resp != 0)
break;
udelay(10);
tmp = tmp + 10;
if (tmp >= timeout) {
DRM_ERROR("failed to init MMSCH. TIME-OUT after %d usec"\
" waiting for regMMSCH_VF_MAILBOX_RESP "\
"(expected=0x%08x, readback=0x%08x)\n",
tmp, expected, resp);
return -EBUSY;
}
}
if (resp != expected && resp != MMSCH_VF_MAILBOX_RESP__INCOMPLETE &&
init_status != MMSCH_VF_ENGINE_STATUS__PASS)
DRM_ERROR("MMSCH init status is incorrect! readback=0x%08x, header init status for jpeg: %x\n",
resp, init_status);
}
return 0;
}
/**
* jpeg_v4_0_3_hw_init - start and test JPEG block
*
@ -172,31 +298,47 @@ static int jpeg_v4_0_3_hw_init(void *handle)
struct amdgpu_ring *ring;
int i, j, r, jpeg_inst;
for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
jpeg_inst = GET_INST(JPEG, i);
if (amdgpu_sriov_vf(adev)) {
r = jpeg_v4_0_3_start_sriov(adev);
if (r)
return r;
ring = adev->jpeg.inst[i].ring_dec;
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
ring = &adev->jpeg.inst[i].ring_dec[j];
ring->wptr = 0;
ring->wptr_old = 0;
jpeg_v4_0_3_dec_ring_set_wptr(ring);
ring->sched.ready = true;
}
}
} else {
for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
jpeg_inst = GET_INST(JPEG, i);
if (ring->use_doorbell)
adev->nbio.funcs->vcn_doorbell_range(
adev, ring->use_doorbell,
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * jpeg_inst,
adev->jpeg.inst[i].aid_id);
ring = adev->jpeg.inst[i].ring_dec;
for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
ring = &adev->jpeg.inst[i].ring_dec[j];
if (ring->use_doorbell)
WREG32_SOC15_OFFSET(
VCN, GET_INST(VCN, i),
regVCN_JPEG_DB_CTRL,
(ring->pipe ? (ring->pipe - 0x15) : 0),
ring->doorbell_index
adev->nbio.funcs->vcn_doorbell_range(
adev, ring->use_doorbell,
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * jpeg_inst,
adev->jpeg.inst[i].aid_id);
for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
ring = &adev->jpeg.inst[i].ring_dec[j];
if (ring->use_doorbell)
WREG32_SOC15_OFFSET(
VCN, GET_INST(VCN, i),
regVCN_JPEG_DB_CTRL,
(ring->pipe ? (ring->pipe - 0x15) : 0),
ring->doorbell_index
<< VCN_JPEG_DB_CTRL__OFFSET__SHIFT |
VCN_JPEG_DB_CTRL__EN_MASK);
r = amdgpu_ring_test_helper(ring);
if (r)
return r;
VCN_JPEG_DB_CTRL__EN_MASK);
r = amdgpu_ring_test_helper(ring);
if (r)
return r;
}
}
}
DRM_DEV_INFO(adev->dev, "JPEG decode initialized successfully.\n");

View File

@ -0,0 +1,37 @@
/*
* Copyright 2023 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 __MMSCH_V4_0_3_H__
#define __MMSCH_V4_0_3_H__
#include "amdgpu_vcn.h"
#include "mmsch_v4_0.h"
struct mmsch_v4_0_3_init_header {
uint32_t version;
uint32_t total_size;
struct mmsch_v4_0_table_info vcn0;
struct mmsch_v4_0_table_info mjpegdec0[4];
struct mmsch_v4_0_table_info mjpegdec1[4];
};
#endif

View File

@ -691,6 +691,27 @@ static int psp_v13_0_vbflash_status(struct psp_context *psp)
return RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_115);
}
static int psp_v13_0_fatal_error_recovery_quirk(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 10)) {
uint32_t reg_data;
/* MP1 fatal error: trigger PSP dram read to unhalt PSP
* during MP1 triggered sync flood.
*/
reg_data = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_67);
WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_67, reg_data + 0x10);
/* delay 1000ms for the mode1 reset for fatal error
* to be recovered back.
*/
msleep(1000);
}
return 0;
}
static const struct psp_funcs psp_v13_0_funcs = {
.init_microcode = psp_v13_0_init_microcode,
.bootloader_load_kdb = psp_v13_0_bootloader_load_kdb,
@ -710,7 +731,8 @@ static const struct psp_funcs psp_v13_0_funcs = {
.load_usbc_pd_fw = psp_v13_0_load_usbc_pd_fw,
.read_usbc_pd_fw = psp_v13_0_read_usbc_pd_fw,
.update_spirom = psp_v13_0_update_spirom,
.vbflash_stat = psp_v13_0_vbflash_status
.vbflash_stat = psp_v13_0_vbflash_status,
.fatal_error_recovery_quirk = psp_v13_0_fatal_error_recovery_quirk,
};
void psp_v13_0_set_psp_funcs(struct psp_context *psp)

View File

@ -31,6 +31,7 @@
#include "soc15d.h"
#include "soc15_hw_ip.h"
#include "vcn_v2_0.h"
#include "mmsch_v4_0_3.h"
#include "vcn/vcn_4_0_3_offset.h"
#include "vcn/vcn_4_0_3_sh_mask.h"
@ -44,6 +45,7 @@
#define VCN_VID_SOC_ADDRESS_2_0 0x1fb00
#define VCN1_VID_SOC_ADDRESS_3_0 0x48300
static int vcn_v4_0_3_start_sriov(struct amdgpu_device *adev);
static void vcn_v4_0_3_set_unified_ring_funcs(struct amdgpu_device *adev);
static void vcn_v4_0_3_set_irq_funcs(struct amdgpu_device *adev);
static int vcn_v4_0_3_set_powergating_state(void *handle,
@ -111,9 +113,16 @@ static int vcn_v4_0_3_sw_init(void *handle)
ring = &adev->vcn.inst[i].ring_enc[0];
ring->use_doorbell = true;
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * vcn_inst;
if (!amdgpu_sriov_vf(adev))
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * vcn_inst;
else
ring->doorbell_index =
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
32 * vcn_inst;
ring->vm_hub = AMDGPU_MMHUB0(adev->vcn.inst[i].aid_id);
sprintf(ring->name, "vcn_unified_%d", adev->vcn.inst[i].aid_id);
r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0,
@ -130,6 +139,12 @@ static int vcn_v4_0_3_sw_init(void *handle)
amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
}
if (amdgpu_sriov_vf(adev)) {
r = amdgpu_virt_alloc_mm_table(adev);
if (r)
return r;
}
if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
adev->vcn.pause_dpg_mode = vcn_v4_0_3_pause_dpg_mode;
@ -167,6 +182,9 @@ static int vcn_v4_0_3_sw_fini(void *handle)
drm_dev_exit(idx);
}
if (amdgpu_sriov_vf(adev))
amdgpu_virt_free_mm_table(adev);
r = amdgpu_vcn_suspend(adev);
if (r)
return r;
@ -189,33 +207,47 @@ static int vcn_v4_0_3_hw_init(void *handle)
struct amdgpu_ring *ring;
int i, r, vcn_inst;
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
vcn_inst = GET_INST(VCN, i);
ring = &adev->vcn.inst[i].ring_enc[0];
if (ring->use_doorbell) {
adev->nbio.funcs->vcn_doorbell_range(
adev, ring->use_doorbell,
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * vcn_inst,
adev->vcn.inst[i].aid_id);
WREG32_SOC15(
VCN, GET_INST(VCN, ring->me),
regVCN_RB1_DB_CTRL,
ring->doorbell_index
<< VCN_RB1_DB_CTRL__OFFSET__SHIFT |
VCN_RB1_DB_CTRL__EN_MASK);
/* Read DB_CTRL to flush the write DB_CTRL command. */
RREG32_SOC15(
VCN, GET_INST(VCN, ring->me),
regVCN_RB1_DB_CTRL);
}
r = amdgpu_ring_test_helper(ring);
if (amdgpu_sriov_vf(adev)) {
r = vcn_v4_0_3_start_sriov(adev);
if (r)
goto done;
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
ring = &adev->vcn.inst[i].ring_enc[0];
ring->wptr = 0;
ring->wptr_old = 0;
vcn_v4_0_3_unified_ring_set_wptr(ring);
ring->sched.ready = true;
}
} else {
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
vcn_inst = GET_INST(VCN, i);
ring = &adev->vcn.inst[i].ring_enc[0];
if (ring->use_doorbell) {
adev->nbio.funcs->vcn_doorbell_range(
adev, ring->use_doorbell,
(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
9 * vcn_inst,
adev->vcn.inst[i].aid_id);
WREG32_SOC15(
VCN, GET_INST(VCN, ring->me),
regVCN_RB1_DB_CTRL,
ring->doorbell_index
<< VCN_RB1_DB_CTRL__OFFSET__SHIFT |
VCN_RB1_DB_CTRL__EN_MASK);
/* Read DB_CTRL to flush the write DB_CTRL command. */
RREG32_SOC15(
VCN, GET_INST(VCN, ring->me),
regVCN_RB1_DB_CTRL);
}
r = amdgpu_ring_test_helper(ring);
if (r)
goto done;
}
}
done:
@ -813,6 +845,193 @@ static int vcn_v4_0_3_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, b
return 0;
}
static int vcn_v4_0_3_start_sriov(struct amdgpu_device *adev)
{
int i, vcn_inst;
struct amdgpu_ring *ring_enc;
uint64_t cache_addr;
uint64_t rb_enc_addr;
uint64_t ctx_addr;
uint32_t param, resp, expected;
uint32_t offset, cache_size;
uint32_t tmp, timeout;
struct amdgpu_mm_table *table = &adev->virt.mm_table;
uint32_t *table_loc;
uint32_t table_size;
uint32_t size, size_dw;
uint32_t init_status;
uint32_t enabled_vcn;
struct mmsch_v4_0_cmd_direct_write
direct_wt = { {0} };
struct mmsch_v4_0_cmd_direct_read_modify_write
direct_rd_mod_wt = { {0} };
struct mmsch_v4_0_cmd_end end = { {0} };
struct mmsch_v4_0_3_init_header header;
volatile struct amdgpu_vcn4_fw_shared *fw_shared;
volatile struct amdgpu_fw_shared_rb_setup *rb_setup;
direct_wt.cmd_header.command_type =
MMSCH_COMMAND__DIRECT_REG_WRITE;
direct_rd_mod_wt.cmd_header.command_type =
MMSCH_COMMAND__DIRECT_REG_READ_MODIFY_WRITE;
end.cmd_header.command_type = MMSCH_COMMAND__END;
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
vcn_inst = GET_INST(VCN, i);
memset(&header, 0, sizeof(struct mmsch_v4_0_3_init_header));
header.version = MMSCH_VERSION;
header.total_size = sizeof(struct mmsch_v4_0_3_init_header) >> 2;
table_loc = (uint32_t *)table->cpu_addr;
table_loc += header.total_size;
table_size = 0;
MMSCH_V4_0_INSERT_DIRECT_RD_MOD_WT(SOC15_REG_OFFSET(VCN, 0, regUVD_STATUS),
~UVD_STATUS__UVD_BUSY, UVD_STATUS__UVD_BUSY);
cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + i].tmr_mc_addr_lo);
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + i].tmr_mc_addr_hi);
offset = 0;
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_OFFSET0), 0);
} else {
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
lower_32_bits(adev->vcn.inst[i].gpu_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
upper_32_bits(adev->vcn.inst[i].gpu_addr));
offset = cache_size;
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_OFFSET0),
AMDGPU_UVD_FIRMWARE_OFFSET >> 3);
}
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_SIZE0),
cache_size);
cache_addr = adev->vcn.inst[vcn_inst].gpu_addr + offset;
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), lower_32_bits(cache_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), upper_32_bits(cache_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_OFFSET1), 0);
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_SIZE1), AMDGPU_VCN_STACK_SIZE);
cache_addr = adev->vcn.inst[vcn_inst].gpu_addr + offset +
AMDGPU_VCN_STACK_SIZE;
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), lower_32_bits(cache_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), upper_32_bits(cache_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_OFFSET2), 0);
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_CACHE_SIZE2), AMDGPU_VCN_CONTEXT_SIZE);
fw_shared = adev->vcn.inst[vcn_inst].fw_shared.cpu_addr;
rb_setup = &fw_shared->rb_setup;
ring_enc = &adev->vcn.inst[vcn_inst].ring_enc[0];
ring_enc->wptr = 0;
rb_enc_addr = ring_enc->gpu_addr;
rb_setup->is_rb_enabled_flags |= RB_ENABLED;
rb_setup->rb_addr_lo = lower_32_bits(rb_enc_addr);
rb_setup->rb_addr_hi = upper_32_bits(rb_enc_addr);
rb_setup->rb_size = ring_enc->ring_size / 4;
fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_VF_RB_SETUP_FLAG);
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_NC0_64BIT_BAR_LOW),
lower_32_bits(adev->vcn.inst[vcn_inst].fw_shared.gpu_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_LMI_VCPU_NC0_64BIT_BAR_HIGH),
upper_32_bits(adev->vcn.inst[vcn_inst].fw_shared.gpu_addr));
MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
regUVD_VCPU_NONCACHE_SIZE0),
AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn4_fw_shared)));
MMSCH_V4_0_INSERT_END();
header.vcn0.init_status = 0;
header.vcn0.table_offset = header.total_size;
header.vcn0.table_size = table_size;
header.total_size += table_size;
/* Send init table to mmsch */
size = sizeof(struct mmsch_v4_0_3_init_header);
table_loc = (uint32_t *)table->cpu_addr;
memcpy((void *)table_loc, &header, size);
ctx_addr = table->gpu_addr;
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_CTX_ADDR_LO, lower_32_bits(ctx_addr));
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_CTX_ADDR_HI, upper_32_bits(ctx_addr));
tmp = RREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_VMID);
tmp &= ~MMSCH_VF_VMID__VF_CTX_VMID_MASK;
tmp |= (0 << MMSCH_VF_VMID__VF_CTX_VMID__SHIFT);
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_VMID, tmp);
size = header.total_size;
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_CTX_SIZE, size);
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_MAILBOX_RESP, 0);
param = 0x00000001;
WREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_MAILBOX_HOST, param);
tmp = 0;
timeout = 1000;
resp = 0;
expected = MMSCH_VF_MAILBOX_RESP__OK;
while (resp != expected) {
resp = RREG32_SOC15(VCN, vcn_inst, regMMSCH_VF_MAILBOX_RESP);
if (resp != 0)
break;
udelay(10);
tmp = tmp + 10;
if (tmp >= timeout) {
DRM_ERROR("failed to init MMSCH. TIME-OUT after %d usec"\
" waiting for regMMSCH_VF_MAILBOX_RESP "\
"(expected=0x%08x, readback=0x%08x)\n",
tmp, expected, resp);
return -EBUSY;
}
}
enabled_vcn = amdgpu_vcn_is_disabled_vcn(adev, VCN_DECODE_RING, 0) ? 1 : 0;
init_status = ((struct mmsch_v4_0_3_init_header *)(table_loc))->vcn0.init_status;
if (resp != expected && resp != MMSCH_VF_MAILBOX_RESP__INCOMPLETE
&& init_status != MMSCH_VF_ENGINE_STATUS__PASS) {
DRM_ERROR("MMSCH init status is incorrect! readback=0x%08x, header init "\
"status for VCN%x: 0x%x\n", resp, enabled_vcn, init_status);
}
}
return 0;
}
/**
* vcn_v4_0_3_start - VCN start
*
@ -1317,6 +1536,15 @@ static int vcn_v4_0_3_set_powergating_state(void *handle,
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int ret;
/* for SRIOV, guest should not control VCN Power-gating
* MMSCH FW should control Power-gating and clock-gating
* guest should avoid touching CGC and PG
*/
if (amdgpu_sriov_vf(adev)) {
adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
return 0;
}
if (state == adev->vcn.cur_state)
return 0;

View File

@ -227,7 +227,6 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
queue_input.tba_addr = qpd->tba_addr;
queue_input.tma_addr = qpd->tma_addr;
queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device);
queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled;
queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled ||
kfd_dbg_has_ttmps_always_setup(q->device);
@ -2817,19 +2816,11 @@ static void copy_context_work_handler (struct work_struct *work)
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
{
size_t array_size = num_queues * sizeof(uint32_t);
uint32_t *queue_ids = NULL;
if (!usr_queue_id_array)
return NULL;
queue_ids = kzalloc(array_size, GFP_KERNEL);
if (!queue_ids)
return ERR_PTR(-ENOMEM);
if (copy_from_user(queue_ids, usr_queue_id_array, array_size))
return ERR_PTR(-EFAULT);
return queue_ids;
return memdup_user(usr_queue_id_array, array_size);
}
int resume_queues(struct kfd_process *p,

View File

@ -48,7 +48,7 @@ int pipe_priority_map[] = {
struct kfd_mem_obj *allocate_hiq_mqd(struct kfd_node *dev, struct queue_properties *q)
{
struct kfd_mem_obj *mqd_mem_obj = NULL;
struct kfd_mem_obj *mqd_mem_obj;
mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
if (!mqd_mem_obj)
@ -64,7 +64,7 @@ struct kfd_mem_obj *allocate_hiq_mqd(struct kfd_node *dev, struct queue_properti
struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_node *dev,
struct queue_properties *q)
{
struct kfd_mem_obj *mqd_mem_obj = NULL;
struct kfd_mem_obj *mqd_mem_obj;
uint64_t offset;
mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);

View File

@ -121,6 +121,7 @@ static int pm_map_process_aldebaran(struct packet_manager *pm,
packet->sh_mem_bases = qpd->sh_mem_bases;
if (qpd->tba_addr) {
packet->sq_shader_tba_lo = lower_32_bits(qpd->tba_addr >> 8);
packet->sq_shader_tba_hi = upper_32_bits(qpd->tba_addr >> 8);
packet->sq_shader_tma_lo = lower_32_bits(qpd->tma_addr >> 8);
packet->sq_shader_tma_hi = upper_32_bits(qpd->tma_addr >> 8);
}

View File

@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/sched/task.h>
#include <linux/dynamic_debug.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/drm_exec.h>
@ -48,8 +49,13 @@
* page table is updated.
*/
#define AMDGPU_SVM_RANGE_RETRY_FAULT_PENDING (2UL * NSEC_PER_MSEC)
#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
#define dynamic_svm_range_dump(svms) \
_dynamic_func_call_no_desc("svm_range_dump", svm_range_debug_dump, svms)
#else
#define dynamic_svm_range_dump(svms) \
do { if (0) svm_range_debug_dump(svms); } while (0)
#endif
/* Giant svm range split into smaller ranges based on this, it is decided using
* minimum of all dGPU/APU 1/32 VRAM size, between 2MB to 1GB and alignment to

View File

@ -1915,7 +1915,14 @@ int kfd_topology_add_device(struct kfd_node *gpu)
const char *asic_name = amdgpu_asic_name[gpu->adev->asic_type];
gpu_id = kfd_generate_gpu_id(gpu);
pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
if (gpu->xcp && !gpu->xcp->ddev) {
dev_warn(gpu->adev->dev,
"Won't add GPU (ID: 0x%x) to topology since it has no drm node assigned.",
gpu_id);
return 0;
} else {
pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
}
/* Check to see if this gpu device exists in the topology_device_list.
* If so, assign the gpu to that device,

View File

@ -6045,7 +6045,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
if (stream->link->psr_settings.psr_feature_enabled) {
if (stream->link->psr_settings.psr_feature_enabled || stream->link->replay_settings.replay_feature_enabled) {
//
// should decide stream support vsc sdp colorimetry capability
// before building vsc info packet
@ -7785,7 +7785,7 @@ static void update_freesync_state_on_stream(
aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
if (aconn && aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) {
pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
if (aconn->vsdb_info.amd_vsdb_version == 1)

View File

@ -117,7 +117,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
if (sad_count <= 0)
return result;
edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
edid_caps->audio_mode_count = min(sad_count, DC_MAX_AUDIO_DESC_COUNT);
for (i = 0; i < edid_caps->audio_mode_count; ++i) {
struct cea_sad *sad = &sads[i];

View File

@ -96,7 +96,7 @@ struct dc_bios *bios_parser_create(
struct bp_init_data *init,
enum dce_version dce_version)
{
struct bios_parser *bp = NULL;
struct bios_parser *bp;
bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
if (!bp)
@ -2576,7 +2576,7 @@ static struct integrated_info *bios_parser_create_integrated_info(
struct dc_bios *dcb)
{
struct bios_parser *bp = BP_FROM_DCB(dcb);
struct integrated_info *info = NULL;
struct integrated_info *info;
info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);

View File

@ -3086,7 +3086,7 @@ static struct integrated_info *bios_parser_create_integrated_info(
struct dc_bios *dcb)
{
struct bios_parser *bp = BP_FROM_DCB(dcb);
struct integrated_info *info = NULL;
struct integrated_info *info;
info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
@ -3675,7 +3675,7 @@ struct dc_bios *firmware_parser_create(
struct bp_init_data *init,
enum dce_version dce_version)
{
struct bios_parser *bp = NULL;
struct bios_parser *bp;
bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
if (!bp)

View File

@ -117,6 +117,7 @@ void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_m
continue;
clk_mgr->psr_allow_active_cache = edp_link->psr_settings.psr_allow_active;
dc->link_srv->edp_set_psr_allow_active(edp_link, &allow_active, false, false, NULL);
dc->link_srv->edp_set_replay_allow_active(edp_link, &allow_active, false, false, NULL);
}
}
@ -137,6 +138,8 @@ void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr)
continue;
dc->link_srv->edp_set_psr_allow_active(edp_link,
&clk_mgr->psr_allow_active_cache, false, false, NULL);
dc->link_srv->edp_set_replay_allow_active(edp_link,
&clk_mgr->psr_allow_active_cache, false, false, NULL);
}
}

View File

@ -555,6 +555,11 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
}
}
if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching)
dcn32_smu_wait_for_dmub_ack_mclk(clk_mgr, true);
else
dcn32_smu_wait_for_dmub_ack_mclk(clk_mgr, false);
/* Always update saved value, even if new value not set due to P-State switching unsupported. Also check safe_to_lower for FCLK */
if (safe_to_lower && (clk_mgr_base->clks.fclk_p_state_change_support != clk_mgr_base->clks.fclk_prev_p_state_change_support)) {
update_fclk = true;

View File

@ -139,3 +139,10 @@ unsigned int dcn32_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, ui
return response;
}
void dcn32_smu_wait_for_dmub_ack_mclk(struct clk_mgr_internal *clk_mgr, bool enable)
{
smu_print("PMFW to wait for DMCUB ack for MCLK : %d\n", enable);
dcn32_smu_send_msg_with_param(clk_mgr, 0x14, enable ? 1 : 0, NULL);
}

View File

@ -43,5 +43,6 @@ void dcn32_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr);
void dcn32_smu_send_cab_for_uclk_message(struct clk_mgr_internal *clk_mgr, unsigned int num_ways);
void dcn32_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
unsigned int dcn32_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
void dcn32_smu_wait_for_dmub_ack_mclk(struct clk_mgr_internal *clk_mgr, bool enable);
#endif /* __DCN32_CLK_MGR_SMU_MSG_H_ */

View File

@ -586,18 +586,15 @@ dc_stream_forward_crc_window(struct dc_stream_state *stream,
bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
struct crc_params *crc_window, bool enable, bool continuous)
{
int i;
struct pipe_ctx *pipe;
struct crc_params param;
struct timing_generator *tg;
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
break;
}
pipe = resource_get_otg_master_for_stream(
&dc->current_state->res_ctx, stream);
/* Stream not found */
if (i == MAX_PIPES)
if (pipe == NULL)
return false;
/* By default, capture the full frame */
@ -1064,7 +1061,7 @@ static void apply_ctx_interdependent_lock(struct dc *dc,
// Copied conditions that were previously in dce110_apply_ctx_for_surface
if (stream == pipe_ctx->stream) {
if (!pipe_ctx->top_pipe &&
if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) &&
(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
dc->hwss.pipe_control_lock(dc, pipe_ctx, lock);
}
@ -3164,7 +3161,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {
if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_ctx->stream == stream) {
if (stream_update->periodic_interrupt && dc->hwss.setup_periodic_interrupt)
dc->hwss.setup_periodic_interrupt(dc, pipe_ctx);
@ -3289,6 +3286,9 @@ static bool dc_dmub_should_send_dirty_rect_cmd(struct dc *dc, struct dc_stream_s
&& stream->ctx->dce_version >= DCN_VERSION_3_1)
return true;
if (stream->link->replay_settings.config.replay_supported)
return true;
return false;
}
@ -3443,16 +3443,9 @@ static void commit_planes_for_stream_fast(struct dc *dc,
struct pipe_ctx *top_pipe_to_program = NULL;
dc_z10_restore(dc);
for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (!pipe_ctx->top_pipe &&
!pipe_ctx->prev_odm_pipe &&
pipe_ctx->stream &&
pipe_ctx->stream == stream) {
top_pipe_to_program = pipe_ctx;
}
}
top_pipe_to_program = resource_get_otg_master_for_stream(
&context->res_ctx,
stream);
if (dc->debug.visual_confirm) {
for (i = 0; i < dc->res_pool->pipe_count; i++) {
@ -3557,16 +3550,9 @@ static void commit_planes_for_stream(struct dc *dc,
context_clock_trace(dc, context);
}
for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (!pipe_ctx->top_pipe &&
!pipe_ctx->prev_odm_pipe &&
pipe_ctx->stream &&
pipe_ctx->stream == stream) {
top_pipe_to_program = pipe_ctx;
}
}
top_pipe_to_program = resource_get_otg_master_for_stream(
&context->res_ctx,
stream);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
@ -5173,6 +5159,9 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
if (link->psr_settings.psr_feature_enabled)
return;
if (link->replay_settings.replay_feature_enabled)
return;
/*find primary pipe associated with stream*/
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];

View File

@ -45,6 +45,8 @@
#include "link/hwss/link_hwss_dio.h"
#include "link/hwss/link_hwss_dpia.h"
#include "link/hwss/link_hwss_hpo_dp.h"
#include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
#include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
@ -730,10 +732,10 @@ static inline void get_vp_scan_direction(
*flip_horz_scan_dir = !*flip_horz_scan_dir;
}
int get_num_mpc_splits(struct pipe_ctx *pipe)
int resource_get_num_mpc_splits(const struct pipe_ctx *pipe)
{
int mpc_split_count = 0;
struct pipe_ctx *other_pipe = pipe->bottom_pipe;
const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
mpc_split_count++;
@ -748,40 +750,30 @@ int get_num_mpc_splits(struct pipe_ctx *pipe)
return mpc_split_count;
}
int get_num_odm_splits(struct pipe_ctx *pipe)
int resource_get_num_odm_splits(const struct pipe_ctx *pipe)
{
int odm_split_count = 0;
struct pipe_ctx *next_pipe = NULL;
while (pipe->top_pipe)
pipe = pipe->top_pipe;
pipe = resource_get_otg_master(pipe);
next_pipe = pipe->next_odm_pipe;
while (next_pipe) {
while (pipe->next_odm_pipe) {
odm_split_count++;
next_pipe = next_pipe->next_odm_pipe;
}
pipe = pipe->prev_odm_pipe;
while (pipe) {
odm_split_count++;
pipe = pipe->prev_odm_pipe;
pipe = pipe->next_odm_pipe;
}
return odm_split_count;
}
static int get_odm_split_index(struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *split_pipe = NULL;
int index = 0;
while (pipe_ctx->top_pipe)
pipe_ctx = pipe_ctx->top_pipe;
pipe_ctx = resource_get_opp_head(pipe_ctx);
if (!pipe_ctx)
return 0;
split_pipe = pipe_ctx->prev_odm_pipe;
while (split_pipe) {
while (pipe_ctx->prev_odm_pipe) {
index++;
split_pipe = split_pipe->prev_odm_pipe;
pipe_ctx = pipe_ctx->prev_odm_pipe;
}
return index;
@ -852,7 +844,7 @@ static struct rect shift_rec(const struct rect *rec_in, int x, int y)
static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
{
const struct dc_stream_state *stream = pipe_ctx->stream;
int odm_slice_count = get_num_odm_splits(pipe_ctx) + 1;
int odm_slice_count = resource_get_num_odm_splits(pipe_ctx) + 1;
int odm_slice_idx = get_odm_split_index(pipe_ctx);
bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
int h_active = stream->timing.h_addressable +
@ -970,7 +962,7 @@ static struct rect calculate_mpc_slice_in_timing_active(
struct rect *plane_clip_rec)
{
const struct dc_stream_state *stream = pipe_ctx->stream;
int mpc_slice_count = get_num_mpc_splits(pipe_ctx) + 1;
int mpc_slice_count = resource_get_num_mpc_splits(pipe_ctx) + 1;
int mpc_slice_idx = get_mpc_split_index(pipe_ctx);
int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
struct rect mpc_rec;
@ -1563,7 +1555,7 @@ enum dc_status resource_build_scaling_params_for_context(
return DC_OK;
}
struct pipe_ctx *find_free_secondary_pipe_legacy(
struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *primary_pipe)
@ -1629,7 +1621,7 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
const struct pipe_ctx *cur_opp_head)
{
const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
struct pipe_ctx *new_sec_dpp;
struct pipe_ctx *new_pipe;
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
while (cur_sec_dpp) {
@ -1637,9 +1629,8 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
* this is to avoid MPO pipe switching to different opp blending
* tree
*/
new_sec_dpp = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
if (new_sec_dpp->plane_state == NULL &&
new_sec_dpp->stream == NULL) {
new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
free_pipe_idx = cur_sec_dpp->pipe_idx;
break;
}
@ -1655,17 +1646,15 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx(
const struct resource_pool *pool)
{
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp;
const struct pipe_ctx *new_pipe, *cur_pipe;
int i;
for (i = 0; i < pool->pipe_count; i++) {
cur_sec_dpp = &cur_res_ctx->pipe_ctx[i];
new_sec_dpp = &new_res_ctx->pipe_ctx[i];
cur_pipe = &cur_res_ctx->pipe_ctx[i];
new_pipe = &new_res_ctx->pipe_ctx[i];
if (cur_sec_dpp->plane_state == NULL &&
cur_sec_dpp->stream == NULL &&
new_sec_dpp->plane_state == NULL &&
new_sec_dpp->stream == NULL) {
if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
resource_is_pipe_type(new_pipe, FREE_PIPE)) {
free_pipe_idx = i;
break;
}
@ -1680,18 +1669,17 @@ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
const struct resource_pool *pool)
{
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp;
const struct pipe_ctx *new_pipe, *cur_pipe;
int i;
for (i = 0; i < pool->pipe_count; i++) {
cur_sec_dpp = &cur_res_ctx->pipe_ctx[i];
new_sec_dpp = &new_res_ctx->pipe_ctx[i];
cur_pipe = &cur_res_ctx->pipe_ctx[i];
new_pipe = &new_res_ctx->pipe_ctx[i];
if (cur_sec_dpp->plane_state &&
cur_sec_dpp->top_pipe &&
cur_sec_dpp->top_pipe->plane_state == cur_sec_dpp->plane_state &&
new_sec_dpp->plane_state == NULL &&
new_sec_dpp->stream == NULL) {
if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
!resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
resource_is_for_mpcc_combine(cur_pipe) &&
resource_is_pipe_type(new_pipe, FREE_PIPE)) {
free_pipe_idx = i;
break;
}
@ -1704,14 +1692,13 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
const struct resource_pool *pool)
{
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
const struct pipe_ctx *new_sec_dpp;
const struct pipe_ctx *new_pipe;
int i;
for (i = 0; i < pool->pipe_count; i++) {
new_sec_dpp = &new_res_ctx->pipe_ctx[i];
new_pipe = &new_res_ctx->pipe_ctx[i];
if (new_sec_dpp->plane_state == NULL &&
new_sec_dpp->stream == NULL) {
if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
free_pipe_idx = i;
break;
}
@ -1720,51 +1707,83 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
return free_pipe_idx;
}
/* TODO: Unify the pipe naming convention:
*
* OPP head pipe - the head pipe of an MPC blending tree with a functional OPP
* feeding to an OTG. OPP head pipe is by convention the top most pipe. i.e.
* pipe's top_pipe is NULL.
*
* OTG master pipe - the master pipe of its OPP head pipes with a functional
* OTG. It merges all its OPP head pipes pixel data from their MPCs in ODM block
* and output to backend DIG. OTG master pipe is by convention the top most pipe
* of the first odm slice. i.e. pipe's top_pipe is NULL and pipe's prev_odm_pipe
* is NULL.
*
* Secondary OPP head pipe - an OPP head pipe which is not an OTG master pipe.
* Its output feeds to another OTG master pipe. i.e pipe's top_pipe is NULL and
* pipe's prev_odm_pipe is not NULL.
*
* Secondary DPP pipe - the pipe with a functional DPP outputting to another OPP
* head pipe's MPC. Its output is a secondary layer in the OPP head's MPC
* blending tree. Secondary DPP pipe is by convention a non top most pipe. i.e
* pipe's top_pipe should be not NULL.
*
* The function below is actually getting the OTG master pipe associated with
* the stream. Name it as getting head pipe is confusing.
*/
struct pipe_ctx *resource_get_head_pipe_for_stream(
bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
{
#ifdef DBG
if (pipe_ctx->stream == NULL) {
/* a free pipe with dangling states */
ASSERT(!pipe_ctx->plane_state);
ASSERT(!pipe_ctx->prev_odm_pipe);
ASSERT(!pipe_ctx->next_odm_pipe);
ASSERT(!pipe_ctx->top_pipe);
ASSERT(!pipe_ctx->bottom_pipe);
} else if (pipe_ctx->top_pipe) {
/* a secondary DPP pipe must be signed to a plane */
ASSERT(pipe_ctx->plane_state)
}
/* Add more checks here to prevent corrupted pipe ctx. It is very hard
* to debug this issue afterwards because we can't pinpoint the code
* location causing inconsistent pipe context states.
*/
#endif
switch (type) {
case OTG_MASTER:
return !pipe_ctx->prev_odm_pipe &&
!pipe_ctx->top_pipe &&
pipe_ctx->stream;
case OPP_HEAD:
return !pipe_ctx->top_pipe && pipe_ctx->stream;
case DPP_PIPE:
return pipe_ctx->plane_state && pipe_ctx->stream;
case FREE_PIPE:
return !pipe_ctx->plane_state && !pipe_ctx->stream;
default:
return false;
}
}
bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx)
{
return resource_get_num_mpc_splits(pipe_ctx) > 0;
}
struct pipe_ctx *resource_get_otg_master_for_stream(
struct resource_context *res_ctx,
struct dc_stream_state *stream)
{
int i;
for (i = 0; i < MAX_PIPES; i++) {
if (res_ctx->pipe_ctx[i].stream == stream
&& !res_ctx->pipe_ctx[i].top_pipe
&& !res_ctx->pipe_ctx[i].prev_odm_pipe)
if (res_ctx->pipe_ctx[i].stream == stream &&
resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
return &res_ctx->pipe_ctx[i];
}
return NULL;
}
struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
while (otg_master->prev_odm_pipe)
otg_master = otg_master->prev_odm_pipe;
return otg_master;
}
struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx;
ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE));
while (opp_head->top_pipe)
opp_head = opp_head->top_pipe;
return opp_head;
}
static struct pipe_ctx *get_tail_pipe(
struct pipe_ctx *head_pipe)
{
struct pipe_ctx *tail_pipe;
tail_pipe = head_pipe->bottom_pipe;
struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe;
while (tail_pipe) {
head_pipe = tail_pipe;
@ -1906,7 +1925,7 @@ bool dc_add_plane_to_context(
goto out;
}
otg_master_pipe = resource_get_head_pipe_for_stream(
otg_master_pipe = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
if (otg_master_pipe->plane_state == NULL)
added = add_plane_to_opp_head_pipes(otg_master_pipe,
@ -2427,7 +2446,7 @@ enum dc_status dc_remove_stream_from_ctx(
{
int i;
struct dc_context *dc_ctx = dc->ctx;
struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(&new_ctx->res_ctx, stream);
struct pipe_ctx *odm_pipe;
if (!del_pipe) {
@ -3681,7 +3700,7 @@ enum dc_status resource_map_clock_resources(
{
/* acquire new resources */
const struct resource_pool *pool = dc->res_pool;
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
if (!pipe_ctx)
@ -4071,10 +4090,7 @@ void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i];
pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (!pipe_ctx_old->stream)
continue;
if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER))
continue;
if (!pipe_ctx->stream ||
@ -4198,11 +4214,13 @@ const struct link_hwss *get_link_hwss(const struct dc_link *link,
* with an hpo encoder. Or we can return a very dummy one that doesn't
* do work for all functions
*/
return get_hpo_dp_link_hwss();
return (requires_fixed_vs_pe_retimer_hpo_link_hwss(link) ?
get_hpo_fixed_vs_pe_retimer_dp_link_hwss() : get_hpo_dp_link_hwss());
else if (can_use_dpia_link_hwss(link, link_res))
return get_dpia_link_hwss();
else if (can_use_dio_link_hwss(link, link_res))
return get_dio_link_hwss();
return (requires_fixed_vs_pe_retimer_dio_link_hwss(link)) ?
get_dio_fixed_vs_pe_retimer_link_hwss() : get_dio_link_hwss();
else
return get_virtual_link_hwss();
}

View File

@ -321,7 +321,7 @@ static bool is_subvp_high_refresh_candidate(struct dc_stream_state *stream)
* remain in HW cursor mode if there's no cursor update which will
* then cause corruption.
*/
if ((refresh_rate >= 120 && refresh_rate <= 165 &&
if ((refresh_rate >= 120 && refresh_rate <= 175 &&
stream->timing.v_addressable >= 1440 &&
stream->timing.v_addressable <= 2160) &&
(dc->current_state->stream_count > 1 ||

View File

@ -47,7 +47,7 @@ struct aux_payload;
struct set_config_cmd_payload;
struct dmub_notification;
#define DC_VER "3.2.246"
#define DC_VER "3.2.247"
#define MAX_SURFACES 3
#define MAX_PLANES 6
@ -1498,6 +1498,7 @@ struct dc_link {
enum engine_id eng_id;
bool test_pattern_enabled;
enum dp_test_pattern current_test_pattern;
union compliance_test_state compliance_test_state;
void *priv;

View File

@ -31,6 +31,7 @@
#include "core_types.h"
#include "../basics/conversion.h"
#include "cursor_reg_cache.h"
#include "resource.h"
#define CTX dc_dmub_srv->ctx
#define DC_LOGGER CTX->logger
@ -356,7 +357,7 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru
for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->fpo_in_use) {
if (resource_is_pipe_type(pipe, OTG_MASTER) && pipe->stream->fpo_in_use) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
uint8_t min_refresh_in_hz = (pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000;
@ -531,7 +532,8 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
// We check for master pipe, but it shouldn't matter since we only need
// the pipe for timing info (stream should be same for any pipe splits)
if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
!resource_is_pipe_type(pipe, DPP_PIPE))
continue;
// Find the SubVP pipe
@ -728,12 +730,10 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->stream)
continue;
/* For SubVP pipe count, only count the top most (ODM / MPC) pipe
*/
if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe &&
if (resource_is_pipe_type(pipe, OTG_MASTER) &&
resource_is_pipe_type(pipe, DPP_PIPE) &&
pipe->stream->mall_stream_config.type == SUBVP_MAIN)
subvp_pipes[subvp_count++] = pipe;
}
@ -750,12 +750,14 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
* Any ODM or MPC splits being used in SubVP will be handled internally in
* populate_subvp_cmd_pipe_info
*/
if (pipe->plane_state && pipe->stream->mall_stream_config.paired_stream &&
!pipe->top_pipe && !pipe->prev_odm_pipe &&
if (resource_is_pipe_type(pipe, OTG_MASTER) &&
resource_is_pipe_type(pipe, DPP_PIPE) &&
pipe->stream->mall_stream_config.paired_stream &&
pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
} else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE &&
!pipe->top_pipe && !pipe->prev_odm_pipe) {
} else if (resource_is_pipe_type(pipe, OTG_MASTER) &&
resource_is_pipe_type(pipe, DPP_PIPE) &&
pipe->stream->mall_stream_config.type == SUBVP_NONE) {
// Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where
// we run through DML without calculating "natural" P-state support
populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
@ -897,6 +899,9 @@ static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream->ctx->dce_version >= DCN_VERSION_3_1)
return true;
if (pipe_ctx->stream->link->replay_settings.config.replay_supported)
return true;
return false;
}

View File

@ -98,6 +98,29 @@
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 5)
#define HWSEQ_PIXEL_RATE_REG_LIST_302(blk) \
SRII(PIXEL_RATE_CNTL, blk, 0), \
SRII(PIXEL_RATE_CNTL, blk, 1),\
SRII(PIXEL_RATE_CNTL, blk, 2),\
SRII(PIXEL_RATE_CNTL, blk, 3), \
SRII(PIXEL_RATE_CNTL, blk, 4)
#define HWSEQ_PHYPLL_REG_LIST_302(blk) \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4)
#define HWSEQ_PIXEL_RATE_REG_LIST_303(blk) \
SRII(PIXEL_RATE_CNTL, blk, 0), \
SRII(PIXEL_RATE_CNTL, blk, 1)
#define HWSEQ_PHYPLL_REG_LIST_303(blk) \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1)
#define HWSEQ_PHYPLL_REG_LIST_201(blk) \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1)
@ -387,7 +410,11 @@
SR(MPC_CRC_RESULT_C), \
SR(MPC_CRC_RESULT_AR), \
SR(AZALIA_AUDIO_DTO), \
SR(AZALIA_CONTROLLER_CLOCK_GATING)
SR(AZALIA_CONTROLLER_CLOCK_GATING), \
SR(HPO_TOP_CLOCK_CONTROL), \
SR(ODM_MEM_PWR_CTRL3), \
SR(DMU_MEM_PWR_CNTL), \
SR(MMHUBBUB_MEM_PWR_CNTL)
#define HWSEQ_DCN301_REG_LIST()\
SR(REFCLK_CNTL), \
@ -508,8 +535,11 @@
SR(D5VGA_CONTROL), \
SR(D6VGA_CONTROL), \
SR(DC_IP_REQUEST_CNTL), \
HWSEQ_PIXEL_RATE_REG_LIST_302(OTG), \
HWSEQ_PHYPLL_REG_LIST_302(OTG), \
SR(AZALIA_AUDIO_DTO), \
SR(AZALIA_CONTROLLER_CLOCK_GATING)
SR(AZALIA_CONTROLLER_CLOCK_GATING), \
SR(HPO_TOP_CLOCK_CONTROL)
#define HWSEQ_DCN303_REG_LIST() \
HWSEQ_DCN_REG_LIST(), \
@ -540,28 +570,6 @@
SR(AZALIA_CONTROLLER_CLOCK_GATING), \
SR(HPO_TOP_CLOCK_CONTROL)
#define HWSEQ_PIXEL_RATE_REG_LIST_302(blk) \
SRII(PIXEL_RATE_CNTL, blk, 0), \
SRII(PIXEL_RATE_CNTL, blk, 1),\
SRII(PIXEL_RATE_CNTL, blk, 2),\
SRII(PIXEL_RATE_CNTL, blk, 3), \
SRII(PIXEL_RATE_CNTL, blk, 4)
#define HWSEQ_PHYPLL_REG_LIST_302(blk) \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4)
#define HWSEQ_PIXEL_RATE_REG_LIST_303(blk) \
SRII(PIXEL_RATE_CNTL, blk, 0), \
SRII(PIXEL_RATE_CNTL, blk, 1)
#define HWSEQ_PHYPLL_REG_LIST_303(blk) \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \
SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1)
struct dce_hwseq_registers {
uint32_t DCFE_CLOCK_CONTROL[6];
uint32_t DCFEV_CLOCK_CONTROL;
@ -663,14 +671,15 @@ struct dce_hwseq_registers {
uint32_t MC_VM_XGMI_LFB_CNTL;
uint32_t AZALIA_AUDIO_DTO;
uint32_t AZALIA_CONTROLLER_CLOCK_GATING;
uint32_t HPO_TOP_CLOCK_CONTROL;
uint32_t ODM_MEM_PWR_CTRL3;
uint32_t DMU_MEM_PWR_CNTL;
uint32_t MMHUBBUB_MEM_PWR_CNTL;
uint32_t DCHUBBUB_ARB_HOSTVM_CNTL;
/* MMHUB VM */
uint32_t MC_VM_FB_LOCATION_BASE;
uint32_t MC_VM_FB_LOCATION_TOP;
uint32_t MC_VM_FB_OFFSET;
uint32_t MMHUBBUB_MEM_PWR_CNTL;
uint32_t HPO_TOP_CLOCK_CONTROL;
uint32_t ODM_MEM_PWR_CTRL3;
uint32_t DMU_MEM_PWR_CNTL;
uint32_t DCHUBBUB_ARB_HOSTVM_CNTL;
uint32_t HPO_TOP_HW_CONTROL;
};
/* set field name */
@ -915,6 +924,7 @@ struct dce_hwseq_registers {
#define HWSEQ_DCN30_MASK_SH_LIST(mask_sh)\
HWSEQ_DCN2_MASK_SH_LIST(mask_sh), \
HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \
HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh), \
HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \
HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \
HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \
@ -1012,7 +1022,8 @@ struct dce_hwseq_registers {
HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \
HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \
HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \
HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh)
HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \
HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh)
#define HWSEQ_DCN303_MASK_SH_LIST(mask_sh) \
HWSEQ_DCN_MASK_SH_LIST(mask_sh), \

View File

@ -33,7 +33,7 @@
#define MAX_PIPES 6
/**
/*
* Get Replay state from firmware.
*/
static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *state, uint8_t panel_inst)
@ -62,7 +62,7 @@ static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *s
}
}
/**
/*
* Enable/Disable Replay.
*/
static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst)
@ -112,7 +112,7 @@ static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait,
}
/**
/*
* Set REPLAY power optimization flags.
*/
static void dmub_replay_set_power_opt(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst)
@ -130,7 +130,7 @@ static void dmub_replay_set_power_opt(struct dmub_replay *dmub, unsigned int pow
dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
/**
/*
* Setup Replay by programming phy registers and sending replay hw context values to firmware.
*/
static bool dmub_replay_copy_settings(struct dmub_replay *dmub,
@ -215,7 +215,7 @@ static bool dmub_replay_copy_settings(struct dmub_replay *dmub,
return true;
}
/**
/*
* Set coasting vtotal.
*/
static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub,
@ -234,7 +234,7 @@ static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub,
dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
/**
/*
* Get Replay residency from firmware.
*/
static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst,
@ -267,7 +267,7 @@ static const struct dmub_replay_funcs replay_funcs = {
.replay_residency = dmub_replay_residency,
};
/**
/*
* Construct Replay object.
*/
static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context *ctx)
@ -276,7 +276,7 @@ static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context
replay->funcs = &replay_funcs;
}
/**
/*
* Allocate and initialize Replay object.
*/
struct dmub_replay *dmub_replay_create(struct dc_context *ctx)
@ -293,7 +293,7 @@ struct dmub_replay *dmub_replay_create(struct dc_context *ctx)
return replay;
}
/**
/*
* Deallocate Replay object.
*/
void dmub_replay_destroy(struct dmub_replay **dmub)

View File

@ -824,7 +824,7 @@ static enum dc_status build_mapped_resource(
struct dc_state *context,
struct dc_stream_state *stream)
{
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;

View File

@ -1590,6 +1590,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
*/
if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) {
pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
}
return DC_OK;
}
@ -2021,6 +2022,10 @@ static bool should_enable_fbc(struct dc *dc,
if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled)
return false;
/* Replay should not be enabled */
if (pipe_ctx->stream->link->replay_settings.replay_feature_enabled)
return false;
/* Nothing to compress */
if (!pipe_ctx->plane_state)
return false;

View File

@ -942,7 +942,7 @@ static enum dc_status build_mapped_resource(
struct dc_state *context,
struct dc_stream_state *stream)
{
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;

View File

@ -873,7 +873,7 @@ static enum dc_status build_mapped_resource(
struct dc_state *context,
struct dc_stream_state *stream)
{
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
@ -964,7 +964,7 @@ enum dc_status resource_map_phy_clock_resources(
{
/* acquire new resources */
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
if (!pipe_ctx)

View File

@ -1055,7 +1055,7 @@ static enum dc_status build_mapped_resource(
struct dc_state *context,
struct dc_stream_state *stream)
{
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
@ -1090,8 +1090,8 @@ static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer(
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
if (!head_pipe) {
ASSERT(0);

View File

@ -1638,6 +1638,7 @@ static void dcn20_update_dchubp_dpp(
if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
|| pipe_ctx->update_flags.bits.plane_changed
|| pipe_ctx->stream->update_flags.bits.gamut_remap
|| plane_state->update_flags.bits.gamut_remap_change
|| pipe_ctx->stream->update_flags.bits.out_csc) {
/* dpp/cm gamut remap*/
dc->hwss.program_gamut_remap(pipe_ctx);

View File

@ -712,7 +712,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.timing_trace = false,
.clock_trace = true,
.disable_pplib_clock_request = true,
.pipe_split_policy = MPC_SPLIT_DYNAMIC,
.pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
.force_single_disp_pipe_split = false,
.disable_dcc = DCC_ENABLE,
.vsr_support = true,
@ -1294,7 +1294,7 @@ static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx)
enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream)
{
enum dc_status status = DC_OK;
struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
@ -1948,7 +1948,7 @@ int dcn20_validate_apply_pipe_split_flags(
v->ODMCombineEnablePerState[vlevel][pipe_plane];
if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) {
if (get_num_mpc_splits(pipe) == 1) {
if (resource_get_num_mpc_splits(pipe) == 1) {
/*If need split for mpc but 2 way split already*/
if (split[i] == 4)
split[i] = 2; /* 2 -> 4 MPC */
@ -1956,7 +1956,7 @@ int dcn20_validate_apply_pipe_split_flags(
split[i] = 0; /* 2 -> 2 MPC */
else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state)
merge[i] = true; /* 2 -> 1 MPC */
} else if (get_num_mpc_splits(pipe) == 3) {
} else if (resource_get_num_mpc_splits(pipe) == 3) {
/*If need split for mpc but 4 way split already*/
if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe)
|| !pipe->bottom_pipe)) {
@ -1965,7 +1965,7 @@ int dcn20_validate_apply_pipe_split_flags(
pipe->top_pipe->plane_state == pipe->plane_state)
merge[i] = true; /* 4 -> 1 MPC */
split[i] = 0;
} else if (get_num_odm_splits(pipe)) {
} else if (resource_get_num_odm_splits(pipe)) {
/* ODM -> MPC transition */
if (pipe->prev_odm_pipe) {
split[i] = 0;
@ -1973,7 +1973,7 @@ int dcn20_validate_apply_pipe_split_flags(
}
}
} else {
if (get_num_odm_splits(pipe) == 1) {
if (resource_get_num_odm_splits(pipe) == 1) {
/*If need split for odm but 2 way split already*/
if (split[i] == 4)
split[i] = 2; /* 2 -> 4 ODM */
@ -1983,7 +1983,7 @@ int dcn20_validate_apply_pipe_split_flags(
ASSERT(0); /* NOT expected yet */
merge[i] = true; /* exit ODM */
}
} else if (get_num_odm_splits(pipe) == 3) {
} else if (resource_get_num_odm_splits(pipe) == 3) {
/*If need split for odm but 4 way split already*/
if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe)
|| !pipe->next_odm_pipe)) {
@ -1993,7 +1993,7 @@ int dcn20_validate_apply_pipe_split_flags(
merge[i] = true; /* exit ODM */
}
split[i] = 0;
} else if (get_num_mpc_splits(pipe)) {
} else if (resource_get_num_mpc_splits(pipe)) {
/* MPC -> ODM transition */
ASSERT(0); /* NOT expected yet */
if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
@ -2151,28 +2151,27 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer(
const struct dc_state *cur_ctx,
struct dc_state *new_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *opp_head_pipe)
const struct pipe_ctx *opp_head)
{
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream);
struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master);
if (!head_pipe)
ASSERT(0);
ASSERT(otg_master);
if (!idle_pipe)
if (!sec_dpp_pipe)
return NULL;
idle_pipe->stream = head_pipe->stream;
idle_pipe->stream_res.tg = head_pipe->stream_res.tg;
idle_pipe->stream_res.opp = head_pipe->stream_res.opp;
sec_dpp_pipe->stream = opp_head->stream;
sec_dpp_pipe->stream_res.tg = opp_head->stream_res.tg;
sec_dpp_pipe->stream_res.opp = opp_head->stream_res.opp;
idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx];
idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx];
idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx];
idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst;
sec_dpp_pipe->plane_res.hubp = pool->hubps[sec_dpp_pipe->pipe_idx];
sec_dpp_pipe->plane_res.ipp = pool->ipps[sec_dpp_pipe->pipe_idx];
sec_dpp_pipe->plane_res.dpp = pool->dpps[sec_dpp_pipe->pipe_idx];
sec_dpp_pipe->plane_res.mpcc_inst = pool->dpps[sec_dpp_pipe->pipe_idx]->inst;
return idle_pipe;
return sec_dpp_pipe;
}
bool dcn20_get_dcc_compression_cap(const struct dc *dc,

View File

@ -999,8 +999,8 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer(
const struct pipe_ctx *opp_head_pipe)
{
struct resource_context *res_ctx = &new_ctx->res_ctx;
struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
if (!head_pipe)
ASSERT(0);

View File

@ -461,6 +461,11 @@ void dcn30_init_hw(struct dc *dc)
REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
}
if (dc->debug.enable_mem_low_power.bits.vga) {
// Power down VGA memory
REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
}
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;

View File

@ -2063,7 +2063,8 @@ bool dcn30_validate_bandwidth(struct dc *dc,
}
DC_FP_START();
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
if (dc->res_pool->funcs->calculate_wm_and_dlg)
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
DC_FP_END();
BW_VAL_TRACE_END_WATERMARKS();

View File

@ -1018,8 +1018,8 @@ void hubbub31_init(struct hubbub *hubbub)
/*done in hwseq*/
/*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/
REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL,
DISPCLK_R_DCHUBBUB_GATE_DIS, 0,
DCFCLK_R_DCHUBBUB_GATE_DIS, 0);
DISPCLK_R_DCHUBBUB_GATE_DIS, 1,
DCFCLK_R_DCHUBBUB_GATE_DIS, 1);
}
/*

View File

@ -1781,8 +1781,8 @@ bool dcn31_validate_bandwidth(struct dc *dc,
BW_VAL_TRACE_SKIP(fast);
goto validate_out;
}
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
if (dc->res_pool->funcs->calculate_wm_and_dlg)
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
BW_VAL_TRACE_END_WATERMARKS();

View File

@ -1689,7 +1689,9 @@ static bool filter_modes_for_single_channel_workaround(struct dc *dc,
struct dc_state *context)
{
// Filter 2K@240Hz+8K@24fps above combination timing if memory only has single dimm LPDDR
if (dc->clk_mgr->bw_params->vram_type == 34 && dc->clk_mgr->bw_params->num_channels < 2) {
if (dc->clk_mgr->bw_params->vram_type == 34 &&
dc->clk_mgr->bw_params->num_channels < 2 &&
context->stream_count > 1) {
int total_phy_pix_clk = 0;
for (int i = 0; i < context->stream_count; i++)
@ -1738,8 +1740,8 @@ bool dcn314_validate_bandwidth(struct dc *dc,
BW_VAL_TRACE_SKIP(fast);
goto validate_out;
}
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
if (dc->res_pool->funcs->calculate_wm_and_dlg)
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
BW_VAL_TRACE_END_WATERMARKS();

View File

@ -955,8 +955,8 @@ void hubbub32_init(struct hubbub *hubbub)
/*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/
REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL,
DISPCLK_R_DCHUBBUB_GATE_DIS, 0,
DCFCLK_R_DCHUBBUB_GATE_DIS, 0);
DISPCLK_R_DCHUBBUB_GATE_DIS, 1,
DCFCLK_R_DCHUBBUB_GATE_DIS, 1);
}
/*
ignore the "df_pre_cstate_req" from the SDP port control.

View File

@ -567,7 +567,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
bool ret = false;
/* program OGAM or 3DLUT only for the top pipe*/
if (pipe_ctx->top_pipe == NULL) {
if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
/*program shaper and 3dlut in MPC*/
ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
@ -1202,10 +1202,10 @@ void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->top_pipe || pipe->prev_odm_pipe)
if (!resource_is_pipe_type(pipe, OTG_MASTER))
continue;
if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
&& pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg);
reset_sync_context_for_pipe(dc, context, i);
@ -1299,7 +1299,7 @@ static void apply_symclk_on_tx_off_wa(struct dc_link *link)
if (link->phy_state.symclk_ref_cnts.otg > 0) {
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) {
pipe_ctx->clock_source->funcs->program_pix_clk(
pipe_ctx->clock_source,
&pipe_ctx->stream_res.pix_clk_params,
@ -1382,7 +1382,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
{
phantom_pipe->update_flags.raw = 0;
if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
if (phantom_pipe->stream && phantom_pipe->plane_state) {
if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) {
phantom_pipe->update_flags.bits.enable = 1;
phantom_pipe->update_flags.bits.mpcc = 1;
phantom_pipe->update_flags.bits.dppclk = 1;
@ -1392,7 +1392,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
phantom_pipe->update_flags.bits.scaler = 1;
phantom_pipe->update_flags.bits.viewport = 1;
phantom_pipe->update_flags.bits.det_size = 1;
if (!phantom_pipe->top_pipe && !phantom_pipe->prev_odm_pipe) {
if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) {
phantom_pipe->update_flags.bits.odm = 1;
phantom_pipe->update_flags.bits.global_sync = 1;
}

View File

@ -1709,8 +1709,8 @@ void dcn32_retain_phantom_pipes(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->top_pipe && !pipe->prev_odm_pipe &&
pipe->plane_state && pipe->stream &&
if (resource_is_pipe_type(pipe, OTG_MASTER) &&
resource_is_pipe_type(pipe, DPP_PIPE) &&
pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
phantom_plane = pipe->plane_state;
phantom_stream = pipe->stream;

View File

@ -646,10 +646,8 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->stream)
continue;
if (pipe->plane_state && !pipe->top_pipe) {
if (resource_is_pipe_type(pipe, OPP_HEAD) &&
resource_is_pipe_type(pipe, DPP_PIPE)) {
if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
subvp_count++;
@ -706,10 +704,8 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->stream)
continue;
if (pipe->plane_state && !pipe->top_pipe) {
if (resource_is_pipe_type(pipe, OPP_HEAD) &&
resource_is_pipe_type(pipe, DPP_PIPE)) {
if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
subvp_count++;

View File

@ -3015,7 +3015,7 @@ static bool all_displays_in_sync(const struct pipe_ctx pipe[],
int i, num_active_pipes = 0;
for (i = 0; i < pipe_count; i++) {
if (!pipe[i].stream || pipe[i].top_pipe)
if (!resource_is_pipe_type(&pipe[i], OPP_HEAD))
continue;
active_pipes[num_active_pipes++] = &pipe[i];

View File

@ -1258,7 +1258,7 @@ bool dcn_validate_bandwidth(
hsplit_pipe->pipe_dlg_param.vblank_end = pipe->pipe_dlg_param.vblank_end;
} else {
/* pipe not split previously needs split */
hsplit_pipe = find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe);
hsplit_pipe = resource_find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe);
ASSERT(hsplit_pipe);
split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe);
}

View File

@ -1305,7 +1305,7 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc,
pipes[pipe_cnt].dout.is_virtual = 0;
pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
switch (get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
switch (resource_get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
case 1:
pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
break;

View File

@ -37,7 +37,7 @@
static const struct subvp_high_refresh_list subvp_high_refresh_list = {
.min_refresh = 120,
.max_refresh = 165,
.max_refresh = 175,
.res = {
{.width = 3840, .height = 2160, },
{.width = 3440, .height = 1440, },
@ -756,7 +756,7 @@ static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
// Find the minimum pipe split count for non SubVP pipes
if (pipe->stream && !pipe->top_pipe &&
if (resource_is_pipe_type(pipe, OPP_HEAD) &&
pipe->stream->mall_stream_config.type == SUBVP_NONE) {
split_cnt = 0;
while (pipe) {
@ -886,7 +886,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
// We check for master pipe, but it shouldn't matter since we only need
// the pipe for timing info (stream should be same for any pipe splits)
if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
!resource_is_pipe_type(pipe, DPP_PIPE))
continue;
// Find the SubVP pipe
@ -899,7 +900,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
drr_pipe = &context->res_ctx.pipe_ctx[i];
// We check for master pipe only
if (!drr_pipe->stream || !drr_pipe->plane_state || drr_pipe->top_pipe || drr_pipe->prev_odm_pipe)
if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
!resource_is_pipe_type(pipe, DPP_PIPE))
continue;
if (drr_pipe->stream->mall_stream_config.type == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param &&
@ -980,7 +982,8 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
// We check for master pipe, but it shouldn't matter since we only need
// the pipe for timing info (stream should be same for any pipe splits)
if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
!resource_is_pipe_type(pipe, DPP_PIPE))
continue;
if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) {
@ -1064,7 +1067,8 @@ static bool subvp_subvp_admissable(struct dc *dc,
}
if (subvp_count == 2 && ((min_refresh < 120 && max_refresh < 120) ||
(min_refresh >= 120 && max_refresh <= 165)))
(min_refresh >= subvp_high_refresh_list.min_refresh &&
max_refresh <= subvp_high_refresh_list.max_refresh)))
result = true;
return result;

View File

@ -49,6 +49,8 @@ struct dcn_hubbub_wm_set {
uint32_t dram_clk_change;
uint32_t usr_retrain;
uint32_t fclk_pstate_change;
uint32_t sr_enter_exit_Z8;
uint32_t sr_enter_Z8;
};
struct dcn_hubbub_wm {

View File

@ -179,6 +179,10 @@ struct link_service {
int (*aux_transfer_raw)(struct ddc_service *ddc,
struct aux_payload *payload,
enum aux_return_code_type *operation_result);
bool (*configure_fixed_vs_pe_retimer)(
struct ddc_service *ddc,
const uint8_t *data,
uint32_t len);
bool (*aux_transfer_with_retries_no_mutex)(struct ddc_service *ddc,
struct aux_payload *payload);
bool (*is_in_aux_transaction_mode)(struct ddc_service *ddc);

View File

@ -37,7 +37,6 @@
#define IS_PIPE_SYNCD_VALID(pipe) ((((pipe)->pipe_idx_syncd) & 0x80)?1:0)
#define GET_PIPE_SYNCD_FROM_PIPE(pipe) ((pipe)->pipe_idx_syncd & 0x7F)
#define SET_PIPE_SYNCD_TO_PIPE(pipe, pipe_syncd) ((pipe)->pipe_idx_syncd = (0x80 | pipe_syncd))
#define FREE_PIPE_INDEX_NOT_FOUND -1
enum dce_version resource_parse_asic_id(
struct hw_asic_id asic_id);
@ -143,10 +142,6 @@ struct clock_source *dc_resource_find_first_free_pll(
struct resource_context *res_ctx,
const struct resource_pool *pool);
struct pipe_ctx *resource_get_head_pipe_for_stream(
struct resource_context *res_ctx,
struct dc_stream_state *stream);
bool resource_attach_surfaces_to_context(
struct dc_plane_state *const *plane_state,
int surface_count,
@ -154,29 +149,232 @@ bool resource_attach_surfaces_to_context(
struct dc_state *context,
const struct resource_pool *pool);
struct pipe_ctx *find_free_secondary_pipe_legacy(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *primary_pipe);
#define FREE_PIPE_INDEX_NOT_FOUND -1
/*
* pipe types are identified based on MUXes in DCN front end that are capable
* of taking input from one DCN pipeline to another DCN pipeline. The name is
* in a form of XXXX_YYYY, where XXXX is the DCN front end hardware block the
* pipeline ends with and YYYY is the rendering role that the pipe is in.
*
* For instance OTG_MASTER is a pipe ending with OTG hardware block in its
* pipeline and it is in a role of a master pipe for timing generation.
*
* For quick reference a diagram of each pipe type's areas of responsibility
* for outputting timings on the screen is shown below:
*
* Timing Active for Stream 0
* __________________________________________________
* |OTG master 0 (OPP head 0)|OPP head 2 (DPP pipe 2) |
* | (DPP pipe 0)| |
* | Top Plane 0 | |
* | ______________|____ |
* | |DPP pipe 1 |DPP | |
* | | |pipe| |
* | | Bottom |3 | |
* | | Plane 1 | | |
* | | | | |
* | |______________|____| |
* | | |
* | | |
* | ODM slice 0 | ODM slice 1 |
* |_________________________|________________________|
*
* Timing Active for Stream 1
* __________________________________________________
* |OTG master 4 (OPP head 4) |
* | |
* | |
* | |
* | |
* | |
* | Blank Pixel Data |
* | (generated by DPG4) |
* | |
* | |
* | |
* | |
* | |
* |__________________________________________________|
*
* Inter-pipe Relation
* __________________________________________________
* |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
* | | plane 0 | slice 0 | |
* | 0 | -------------MPC---------ODM----------- |
* | | plane 1 | | | | |
* | 1 | ------------- | | | |
* | | plane 0 | slice 1 | | |
* | 2 | -------------MPC--------- | |
* | | plane 1 | | | |
* | 3 | ------------- | | |
* | | | blank | |
* | 4 | | ----------------------- |
* | | | | |
* | 5 | (FREE) | | |
* |________|_______________|___________|_____________|
*/
enum pipe_type {
/* free pipe - free pipe is an uninitialized pipe without a stream
* associated with it. It is a free DCN pipe resource. It can be
* acquired as any type of pipe.
*/
FREE_PIPE,
/* OTG master pipe - the master pipe of its OPP head pipes with a
* functional OTG. It merges all its OPP head pipes pixel data in ODM
* block and output to backend DIG. OTG master pipe is responsible for
* generating entire crtc timing to backend DIG. An OTG master pipe may
* or may not have a plane. If it has a plane it blends it as the left
* most MPC slice of the top most layer. If it doesn't have a plane it
* can output pixel data from its OPP head pipes' test pattern
* generators (DPG) such as solid black pixel data to blank the screen.
*/
OTG_MASTER,
/* OPP head pipe - the head pipe of an MPC blending tree with a
* functional OPP outputting to an OTG. OPP head pipe is responsible for
* processing output pixels in its own ODM slice. It may or may not have
* a plane. If it has a plane it blends it as the top most layer within
* its own ODM slice. If it doesn't have a plane it can output pixel
* data from its DPG such as solid black pixel data to blank the pixel
* data in its own ODM slice. OTG master pipe is also an OPP head pipe
* but with more responsibility.
*/
OPP_HEAD,
/* DPP pipe - the pipe with a functional DPP outputting to an OPP head
* pipe's MPC. DPP pipe is responsible for processing pixel data from
* its own MPC slice of a plane. It must be connected to an OPP head
* pipe and it must have a plane associated with it.
*/
DPP_PIPE,
};
/*
* Determine if the input pipe ctx is of a pipe type.
* return - true if pipe ctx is of the input type.
*/
bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type);
/*
* Determine if the input pipe ctx is used for rendering a plane with MPCC
* combine. MPCC combine is a hardware feature to combine multiple DPP pipes
* into a single plane. It is typically used for bypassing pipe bandwidth
* limitation for rendering a very large plane or saving power by reducing UCLK
* and DPPCLK speeds.
*
* For instance in the Inter-pipe Relation diagram shown below, both PIPE 0 and
* 1 are for MPCC combine for plane 0
*
* Inter-pipe Relation
* __________________________________________________
* |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
* | | plane 0 | | |
* | 0 | -------------MPC----------------------- |
* | | plane 0 | | | |
* | 1 | ------------- | | |
* |________|_______________|___________|_____________|
*
* return - true if pipe ctx is used for mpcc combine.
*/
bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx);
/*
* Look for a free pipe in new resource context that is used as a secondary DPP
* pipe in MPC blending tree associated with input OPP head pipe.
*
* return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
* pipe idx of the free pipe
*/
int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
const struct resource_context *cur_res_ctx,
struct resource_context *new_res_ctx,
const struct pipe_ctx *cur_opp_head);
/*
* Look for a free pipe in new resource context that is not used in current
* resource context.
*
* return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
* pipe idx of the free pipe
*/
int recource_find_free_pipe_not_used_in_cur_res_ctx(
const struct resource_context *cur_res_ctx,
struct resource_context *new_res_ctx,
const struct resource_pool *pool);
/*
* Look for a free pipe in new resource context that is used as a secondary DPP
* pipe in any MPCC combine in current resource context.
* return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
* pipe idx of the free pipe
*/
int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
const struct resource_context *cur_res_ctx,
struct resource_context *new_res_ctx,
const struct resource_pool *pool);
/*
* Look for any free pipe in new resource context.
* return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
* pipe idx of the free pipe
*/
int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
const struct resource_pool *pool);
/*
* Legacy find free secondary pipe logic deprecated for newer DCNs as it doesn't
* find the most optimal free pipe to prevent from time consuming hardware state
* transitions.
*/
struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct pipe_ctx *primary_pipe);
/*
* Get number of MPC "cuts" of the plane associated with the pipe. MPC slice
* count is equal to MPC splits + 1. For example if a plane is cut 3 times, it
* will have 4 pieces of slice.
* return - 0 if pipe is not used for a plane with MPCC combine. otherwise
* the number of MPC "cuts" for the plane.
*/
int resource_get_num_mpc_splits(const struct pipe_ctx *pipe);
/*
* Get number of ODM "cuts" of the timing associated with the pipe. ODM slice
* count is equal to ODM splits + 1. For example if a timing is cut 3 times, it
* will have 4 pieces of slice.
* return - 0 if pipe is not used for ODM combine. otherwise
* the number of ODM "cuts" for the timing.
*/
int resource_get_num_odm_splits(const struct pipe_ctx *pipe);
/*
* Get the OTG master pipe in resource context associated with the stream.
* return - NULL if not found. Otherwise the OTG master pipe associated with the
* stream.
*/
struct pipe_ctx *resource_get_otg_master_for_stream(
struct resource_context *res_ctx,
struct dc_stream_state *stream);
/*
* Get the OTG master pipe for the input pipe context.
* return - the OTG master pipe for the input pipe
* context.
*/
struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx);
/*
* Get the OPP head pipe for the input pipe context.
* return - the OPP head pipe for the input pipe
* context.
*/
struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx);
bool resource_validate_attach_surfaces(
const struct dc_validation_set set[],
int set_count,
@ -212,10 +410,6 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format);
void get_audio_check(struct audio_info *aud_modes,
struct audio_check *aud_chk);
int get_num_mpc_splits(struct pipe_ctx *pipe);
int get_num_odm_splits(struct pipe_ctx *pipe);
bool get_temp_dp_link_res(struct dc_link *link,
struct link_resource *link_res,
struct dc_link_settings *link_settings);

View File

@ -42,7 +42,8 @@ AMD_DISPLAY_FILES += $(AMD_DAL_LINK_ACCESSORIES)
###############################################################################
# hwss
###############################################################################
LINK_HWSS = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o
LINK_HWSS = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o \
link_hwss_dio_fixed_vs_pe_retimer.o link_hwss_hpo_fixed_vs_pe_retimer_dp.o
AMD_DAL_LINK_HWSS = $(addprefix $(AMDDALPATH)/dc/link/hwss/, \
$(LINK_HWSS))

View File

@ -675,7 +675,8 @@ bool dp_set_test_pattern(
if (pipes[i].stream == NULL)
continue;
if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
if (resource_is_pipe_type(&pipes[i], OTG_MASTER) &&
pipes[i].stream->link == link) {
pipe_ctx = &pipes[i];
break;
}
@ -703,6 +704,7 @@ bool dp_set_test_pattern(
/* Reset Test Pattern state */
link->test_pattern_enabled = false;
link->current_test_pattern = test_pattern;
return true;
}
@ -740,6 +742,7 @@ bool dp_set_test_pattern(
if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
/* Set Test Pattern state */
link->test_pattern_enabled = true;
link->current_test_pattern = test_pattern;
if (p_link_settings != NULL)
dpcd_set_link_settings(link,
p_link_settings);
@ -938,6 +941,7 @@ bool dp_set_test_pattern(
/* Set Test Pattern state */
link->test_pattern_enabled = true;
link->current_test_pattern = test_pattern;
}
return true;

View File

@ -166,7 +166,7 @@ void set_dio_dp_lane_settings(struct dc_link *link,
link_enc->funcs->dp_set_lane_settings(link_enc, link_settings, lane_settings);
}
static void update_dio_stream_allocation_table(struct dc_link *link,
void update_dio_stream_allocation_table(struct dc_link *link,
const struct link_resource *link_res,
const struct link_mst_stream_allocation_table *table)
{

View File

@ -55,5 +55,8 @@ void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
struct audio_output *audio_output, uint32_t audio_inst);
void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
void update_dio_stream_allocation_table(struct dc_link *link,
const struct link_resource *link_res,
const struct link_mst_stream_allocation_table *table);
#endif /* __LINK_HWSS_DIO_H__ */

View File

@ -0,0 +1,200 @@
/*
* Copyright 2023 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "link_hwss_dio.h"
#include "link_hwss_dio_fixed_vs_pe_retimer.h"
#include "link_enc_cfg.h"
uint8_t dp_dio_fixed_vs_pe_retimer_lane_cfg_to_hw_cfg(struct dc_link *link)
{
// TODO: Get USB-C cable orientation
if (link->cur_link_settings.lane_count == LANE_COUNT_FOUR)
return 0xF2;
else
return 0x12;
}
void dp_dio_fixed_vs_pe_retimer_exit_manual_automation(struct dc_link *link)
{
const uint8_t dp_type = dp_dio_fixed_vs_pe_retimer_lane_cfg_to_hw_cfg(link);
const uint8_t vendor_lttpr_exit_manual_automation_0[4] = {0x1, 0x11, 0x0, 0x06};
const uint8_t vendor_lttpr_exit_manual_automation_1[4] = {0x1, 0x50, dp_type, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_2[4] = {0x1, 0x50, 0x50, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_3[4] = {0x1, 0x51, 0x50, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_4[4] = {0x1, 0x10, 0x58, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_5[4] = {0x1, 0x10, 0x59, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_6[4] = {0x1, 0x30, 0x51, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_7[4] = {0x1, 0x30, 0x52, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_8[4] = {0x1, 0x30, 0x54, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_9[4] = {0x1, 0x30, 0x55, 0x0};
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_0[0], sizeof(vendor_lttpr_exit_manual_automation_0));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_1[0], sizeof(vendor_lttpr_exit_manual_automation_1));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_2[0], sizeof(vendor_lttpr_exit_manual_automation_2));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_3[0], sizeof(vendor_lttpr_exit_manual_automation_3));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_4[0], sizeof(vendor_lttpr_exit_manual_automation_4));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_5[0], sizeof(vendor_lttpr_exit_manual_automation_5));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_6[0], sizeof(vendor_lttpr_exit_manual_automation_6));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_7[0], sizeof(vendor_lttpr_exit_manual_automation_7));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_8[0], sizeof(vendor_lttpr_exit_manual_automation_8));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_9[0], sizeof(vendor_lttpr_exit_manual_automation_9));
}
static bool set_dio_fixed_vs_pe_retimer_dp_link_test_pattern_override(struct dc_link *link,
const struct link_resource *link_res, struct encoder_set_dp_phy_pattern_param *tp_params,
const struct link_hwss *link_hwss)
{
struct encoder_set_dp_phy_pattern_param hw_tp_params = { 0 };
const uint8_t pltpat_custom[10] = {0x1F, 0x7C, 0xF0, 0xC1, 0x07, 0x1F, 0x7C, 0xF0, 0xC1, 0x07};
const uint8_t vendor_lttpr_write_data_pg0[4] = {0x1, 0x11, 0x0, 0x0};
const uint8_t vendor_lttpr_exit_manual_automation_0[4] = {0x1, 0x11, 0x0, 0x06};
if (tp_params == NULL)
return false;
if (link->current_test_pattern >= DP_TEST_PATTERN_SQUARE_BEGIN &&
link->current_test_pattern <= DP_TEST_PATTERN_SQUARE_END) {
// Deprogram overrides from previous test pattern
dp_dio_fixed_vs_pe_retimer_exit_manual_automation(link);
}
switch (tp_params->dp_phy_pattern) {
case DP_TEST_PATTERN_80BIT_CUSTOM:
if (tp_params->custom_pattern_size == 0 || memcmp(tp_params->custom_pattern,
pltpat_custom, tp_params->custom_pattern_size) != 0)
return false;
break;
case DP_TEST_PATTERN_D102:
break;
default:
if (link->current_test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM ||
link->current_test_pattern == DP_TEST_PATTERN_D102)
// Deprogram overrides from previous test pattern
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_0[0],
sizeof(vendor_lttpr_exit_manual_automation_0));
return false;
}
hw_tp_params.dp_phy_pattern = tp_params->dp_phy_pattern;
hw_tp_params.dp_panel_mode = tp_params->dp_panel_mode;
if (link_hwss->ext.set_dp_link_test_pattern)
link_hwss->ext.set_dp_link_test_pattern(link, link_res, &hw_tp_params);
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg0[0], sizeof(vendor_lttpr_write_data_pg0));
return true;
}
static void set_dio_fixed_vs_pe_retimer_dp_link_test_pattern(struct dc_link *link,
const struct link_resource *link_res,
struct encoder_set_dp_phy_pattern_param *tp_params)
{
struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
if (!set_dio_fixed_vs_pe_retimer_dp_link_test_pattern_override(
link, link_res, tp_params, get_dio_link_hwss())) {
link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params);
}
link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
}
void enable_dio_fixed_vs_pe_retimer_program_4lane_output(struct dc_link *link)
{
const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
}
static void enable_dio_fixed_vs_pe_retimer_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal,
enum clock_source_id clock_source,
const struct dc_link_settings *link_settings)
{
if (link_settings->lane_count == LANE_COUNT_FOUR)
enable_dio_fixed_vs_pe_retimer_program_4lane_output(link);
enable_dio_dp_link_output(link, link_res, signal, clock_source, link_settings);
}
static const struct link_hwss dio_fixed_vs_pe_retimer_link_hwss = {
.setup_stream_encoder = setup_dio_stream_encoder,
.reset_stream_encoder = reset_dio_stream_encoder,
.setup_stream_attribute = setup_dio_stream_attribute,
.disable_link_output = disable_dio_link_output,
.setup_audio_output = setup_dio_audio_output,
.enable_audio_packet = enable_dio_audio_packet,
.disable_audio_packet = disable_dio_audio_packet,
.ext = {
.set_throttled_vcp_size = set_dio_throttled_vcp_size,
.enable_dp_link_output = enable_dio_fixed_vs_pe_retimer_dp_link_output,
.set_dp_link_test_pattern = set_dio_fixed_vs_pe_retimer_dp_link_test_pattern,
.set_dp_lane_settings = set_dio_dp_lane_settings,
.update_stream_allocation_table = update_dio_stream_allocation_table,
},
};
bool requires_fixed_vs_pe_retimer_dio_link_hwss(const struct dc_link *link)
{
if (!(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN))
return false;
if (!link->dpcd_caps.lttpr_caps.main_link_channel_coding.bits.DP_128b_132b_SUPPORTED)
return false;
return true;
}
const struct link_hwss *get_dio_fixed_vs_pe_retimer_link_hwss(void)
{
return &dio_fixed_vs_pe_retimer_link_hwss;
}

View File

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

View File

@ -28,7 +28,7 @@
#include "dccg.h"
#include "clk_mgr.h"
static void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
struct fixed31_32 throttled_vcp_size)
{
struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
@ -41,7 +41,7 @@ static void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
throttled_vcp_size);
}
static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
const struct dc_link_settings *link_settings,
struct fixed31_32 throttled_vcp_size)
{
@ -69,7 +69,7 @@ static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
hblank_min_symbol_width);
}
static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
{
struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc;
@ -78,14 +78,14 @@ static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst);
}
static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
{
struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
stream_enc->funcs->disable(stream_enc);
}
static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
{
struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
struct dc_stream_state *stream = pipe_ctx->stream;
@ -102,7 +102,7 @@ static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
}
static void enable_hpo_dp_link_output(struct dc_link *link,
void enable_hpo_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal,
enum clock_source_id clock_source,
@ -120,7 +120,7 @@ static void enable_hpo_dp_link_output(struct dc_link *link,
link->link_enc->hpd_source);
}
static void disable_hpo_dp_link_output(struct dc_link *link,
void disable_hpo_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal)
{
@ -154,7 +154,7 @@ static void set_hpo_dp_lane_settings(struct dc_link *link,
lane_settings[0].FFE_PRESET.raw);
}
static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
void update_hpo_dp_stream_allocation_table(struct dc_link *link,
const struct link_resource *link_res,
const struct link_mst_stream_allocation_table *table)
{
@ -163,7 +163,7 @@ static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
table);
}
static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
struct audio_output *audio_output, uint32_t audio_inst)
{
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
@ -172,13 +172,13 @@ static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
&pipe_ctx->stream->audio_info);
}
static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
{
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(
pipe_ctx->stream_res.hpo_dp_stream_enc);
}
static void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
{
if (pipe_ctx->stream_res.audio)
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(

View File

@ -28,9 +28,35 @@
#include "link_hwss.h"
#include "link.h"
void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
struct fixed31_32 throttled_vcp_size);
void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
const struct dc_link_settings *link_settings,
struct fixed31_32 throttled_vcp_size);
void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
const struct dc_link_settings *link_settings,
struct fixed31_32 throttled_vcp_size);
void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx);
void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx);
void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx);
void enable_hpo_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal,
enum clock_source_id clock_source,
const struct dc_link_settings *link_settings);
void disable_hpo_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal);
void update_hpo_dp_stream_allocation_table(struct dc_link *link,
const struct link_resource *link_res,
const struct link_mst_stream_allocation_table *table);
void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
struct audio_output *audio_output, uint32_t audio_inst);
void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx);
void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx);
const struct link_hwss *get_hpo_dp_link_hwss(void);
bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
const struct link_resource *link_res);
const struct link_hwss *get_hpo_dp_link_hwss(void);
#endif /* __LINK_HWSS_HPO_DP_H__ */

View File

@ -0,0 +1,229 @@
/*
* Copyright 2023 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "link_hwss_hpo_dp.h"
#include "link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
#include "link_hwss_dio_fixed_vs_pe_retimer.h"
static void dp_hpo_fixed_vs_pe_retimer_set_tx_ffe(struct dc_link *link,
const struct dc_lane_settings *hw_lane_settings)
{
const uint8_t vendor_ffe_preset_table[16] = {
0x01, 0x41, 0x61, 0x81,
0xB1, 0x05, 0x35, 0x65,
0x85, 0xA5, 0x09, 0x39,
0x59, 0x89, 0x0F, 0x24};
const uint8_t ffe_mask[4] = {
(hw_lane_settings[0].FFE_PRESET.settings.no_deemphasis != 0 ? 0x0F : 0xFF)
& (hw_lane_settings[0].FFE_PRESET.settings.no_preshoot != 0 ? 0xF1 : 0xFF),
(hw_lane_settings[1].FFE_PRESET.settings.no_deemphasis != 0 ? 0x0F : 0xFF)
& (hw_lane_settings[1].FFE_PRESET.settings.no_preshoot != 0 ? 0xF1 : 0xFF),
(hw_lane_settings[2].FFE_PRESET.settings.no_deemphasis != 0 ? 0x0F : 0xFF)
& (hw_lane_settings[2].FFE_PRESET.settings.no_preshoot != 0 ? 0xF1 : 0xFF),
(hw_lane_settings[3].FFE_PRESET.settings.no_deemphasis != 0 ? 0x0F : 0xFF)
& (hw_lane_settings[3].FFE_PRESET.settings.no_preshoot != 0 ? 0xF1 : 0xFF)};
const uint8_t ffe_cfg[4] = {
vendor_ffe_preset_table[hw_lane_settings[0].FFE_PRESET.settings.level] & ffe_mask[0],
vendor_ffe_preset_table[hw_lane_settings[1].FFE_PRESET.settings.level] & ffe_mask[1],
vendor_ffe_preset_table[hw_lane_settings[2].FFE_PRESET.settings.level] & ffe_mask[2],
vendor_ffe_preset_table[hw_lane_settings[3].FFE_PRESET.settings.level] & ffe_mask[3]};
const uint8_t dp_type = dp_dio_fixed_vs_pe_retimer_lane_cfg_to_hw_cfg(link);
const uint8_t vendor_lttpr_write_data_ffe1[4] = {0x01, 0x50, dp_type, 0x0F};
const uint8_t vendor_lttpr_write_data_ffe2[4] = {0x01, 0x55, dp_type, ffe_cfg[0]};
const uint8_t vendor_lttpr_write_data_ffe3[4] = {0x01, 0x56, dp_type, ffe_cfg[1]};
const uint8_t vendor_lttpr_write_data_ffe4[4] = {0x01, 0x57, dp_type, ffe_cfg[2]};
const uint8_t vendor_lttpr_write_data_ffe5[4] = {0x01, 0x58, dp_type, ffe_cfg[3]};
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_ffe1[0], sizeof(vendor_lttpr_write_data_ffe1));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_ffe2[0], sizeof(vendor_lttpr_write_data_ffe2));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_ffe3[0], sizeof(vendor_lttpr_write_data_ffe3));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_ffe4[0], sizeof(vendor_lttpr_write_data_ffe4));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_ffe5[0], sizeof(vendor_lttpr_write_data_ffe5));
}
static void dp_hpo_fixed_vs_pe_retimer_program_override_test_pattern(struct dc_link *link,
struct encoder_set_dp_phy_pattern_param *tp_params)
{
const uint8_t vendor_lttpr_write_data_pg0[4] = {0x1, 0x11, 0x0, 0x0};
const uint8_t vendor_lttpr_write_data_pg1[4] = {0x1, 0x50, 0x50, 0x0};
const uint8_t vendor_lttpr_write_data_pg2[4] = {0x1, 0x51, 0x50, 0x0};
const uint8_t vendor_lttpr_write_data_pg3[4] = {0x1, 0x10, 0x58, 0x21};
const uint8_t vendor_lttpr_write_data_pg4[4] = {0x1, 0x10, 0x59, 0x21};
const uint8_t vendor_lttpr_write_data_pg5[4] = {0x1, 0x1C, 0x58, 0x4F};
const uint8_t vendor_lttpr_write_data_pg6[4] = {0x1, 0x1C, 0x59, 0x4F};
const uint8_t vendor_lttpr_write_data_pg7[4] = {0x1, 0x30, 0x51, 0x20};
const uint8_t vendor_lttpr_write_data_pg8[4] = {0x1, 0x30, 0x52, 0x20};
const uint8_t vendor_lttpr_write_data_pg9[4] = {0x1, 0x30, 0x54, 0x20};
const uint8_t vendor_lttpr_write_data_pg10[4] = {0x1, 0x30, 0x55, 0x20};
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg0[0], sizeof(vendor_lttpr_write_data_pg0));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg1[0], sizeof(vendor_lttpr_write_data_pg1));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg2[0], sizeof(vendor_lttpr_write_data_pg2));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg3[0], sizeof(vendor_lttpr_write_data_pg3));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg4[0], sizeof(vendor_lttpr_write_data_pg4));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg5[0], sizeof(vendor_lttpr_write_data_pg5));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg6[0], sizeof(vendor_lttpr_write_data_pg6));
if (link->cur_link_settings.lane_count == LANE_COUNT_FOUR)
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg7[0], sizeof(vendor_lttpr_write_data_pg7));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg8[0], sizeof(vendor_lttpr_write_data_pg8));
if (link->cur_link_settings.lane_count == LANE_COUNT_FOUR)
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg9[0], sizeof(vendor_lttpr_write_data_pg9));
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pg10[0], sizeof(vendor_lttpr_write_data_pg10));
}
static bool dp_hpo_fixed_vs_pe_retimer_set_override_test_pattern(struct dc_link *link,
const struct link_resource *link_res, struct encoder_set_dp_phy_pattern_param *tp_params,
const struct link_hwss *link_hwss)
{
struct encoder_set_dp_phy_pattern_param hw_tp_params = { 0 };
const uint8_t vendor_lttpr_exit_manual_automation_0[4] = {0x1, 0x11, 0x0, 0x06};
if (tp_params == NULL)
return false;
if (tp_params->dp_phy_pattern < DP_TEST_PATTERN_SQUARE_BEGIN ||
tp_params->dp_phy_pattern > DP_TEST_PATTERN_SQUARE_END) {
// Deprogram overrides from previously set square wave override
if (link->current_test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM ||
link->current_test_pattern == DP_TEST_PATTERN_D102)
link->dc->link_srv->configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_exit_manual_automation_0[0],
sizeof(vendor_lttpr_exit_manual_automation_0));
else
dp_dio_fixed_vs_pe_retimer_exit_manual_automation(link);
return false;
}
hw_tp_params.dp_phy_pattern = DP_TEST_PATTERN_PRBS31;
hw_tp_params.dp_panel_mode = tp_params->dp_panel_mode;
if (link_hwss->ext.set_dp_link_test_pattern)
link_hwss->ext.set_dp_link_test_pattern(link, link_res, &hw_tp_params);
dp_hpo_fixed_vs_pe_retimer_program_override_test_pattern(link, tp_params);
dp_hpo_fixed_vs_pe_retimer_set_tx_ffe(link, &link->cur_lane_setting[0]);
return true;
}
static void set_hpo_fixed_vs_pe_retimer_dp_link_test_pattern(struct dc_link *link,
const struct link_resource *link_res,
struct encoder_set_dp_phy_pattern_param *tp_params)
{
if (!dp_hpo_fixed_vs_pe_retimer_set_override_test_pattern(
link, link_res, tp_params, get_hpo_dp_link_hwss())) {
link_res->hpo_dp_link_enc->funcs->set_link_test_pattern(
link_res->hpo_dp_link_enc, tp_params);
}
link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
}
static void set_hpo_fixed_vs_pe_retimer_dp_lane_settings(struct dc_link *link,
const struct link_resource *link_res,
const struct dc_link_settings *link_settings,
const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
{
link_res->hpo_dp_link_enc->funcs->set_ffe(
link_res->hpo_dp_link_enc,
link_settings,
lane_settings[0].FFE_PRESET.raw);
// FFE is programmed when retimer is programmed for SQ128, but explicit
// programming needed here as well in case FFE-only update is requested
if (link->current_test_pattern >= DP_TEST_PATTERN_SQUARE_BEGIN &&
link->current_test_pattern <= DP_TEST_PATTERN_SQUARE_END)
dp_hpo_fixed_vs_pe_retimer_set_tx_ffe(link, &lane_settings[0]);
}
static void enable_hpo_fixed_vs_pe_retimer_dp_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal,
enum clock_source_id clock_source,
const struct dc_link_settings *link_settings)
{
if (link_settings->lane_count == LANE_COUNT_FOUR)
enable_dio_fixed_vs_pe_retimer_program_4lane_output(link);
enable_hpo_dp_link_output(link, link_res, signal, clock_source, link_settings);
}
static const struct link_hwss hpo_fixed_vs_pe_retimer_dp_link_hwss = {
.setup_stream_encoder = setup_hpo_dp_stream_encoder,
.reset_stream_encoder = reset_hpo_dp_stream_encoder,
.setup_stream_attribute = setup_hpo_dp_stream_attribute,
.disable_link_output = disable_hpo_dp_link_output,
.setup_audio_output = setup_hpo_dp_audio_output,
.enable_audio_packet = enable_hpo_dp_audio_packet,
.disable_audio_packet = disable_hpo_dp_audio_packet,
.ext = {
.set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size,
.set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width,
.enable_dp_link_output = enable_hpo_fixed_vs_pe_retimer_dp_link_output,
.set_dp_link_test_pattern = set_hpo_fixed_vs_pe_retimer_dp_link_test_pattern,
.set_dp_lane_settings = set_hpo_fixed_vs_pe_retimer_dp_lane_settings,
.update_stream_allocation_table = update_hpo_dp_stream_allocation_table,
},
};
bool requires_fixed_vs_pe_retimer_hpo_link_hwss(const struct dc_link *link)
{
if (!(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN))
return false;
if (!link->dpcd_caps.lttpr_caps.main_link_channel_coding.bits.DP_128b_132b_SUPPORTED)
return false;
return true;
}
const struct link_hwss *get_hpo_fixed_vs_pe_retimer_dp_link_hwss(void)
{
return &hpo_fixed_vs_pe_retimer_dp_link_hwss;
}

View File

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

View File

@ -182,11 +182,8 @@ void link_resume(struct dc_link *link)
static bool is_master_pipe_for_link(const struct dc_link *link,
const struct pipe_ctx *pipe)
{
return (pipe->stream &&
pipe->stream->link &&
pipe->stream->link == link &&
pipe->top_pipe == NULL &&
pipe->prev_odm_pipe == NULL);
return resource_is_pipe_type(pipe, OTG_MASTER) &&
pipe->stream->link == link;
}
/*

View File

@ -132,6 +132,7 @@ static void construct_link_service_ddc(struct link_service *link_srv)
link_srv->destroy_ddc_service = link_destroy_ddc_service;
link_srv->query_ddc_data = link_query_ddc_data;
link_srv->aux_transfer_raw = link_aux_transfer_raw;
link_srv->configure_fixed_vs_pe_retimer = link_configure_fixed_vs_pe_retimer;
link_srv->aux_transfer_with_retries_no_mutex =
link_aux_transfer_with_retries_no_mutex;
link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode;

View File

@ -412,6 +412,88 @@ int link_aux_transfer_raw(struct ddc_service *ddc,
}
}
uint32_t link_get_fixed_vs_pe_retimer_write_address(struct dc_link *link)
{
uint32_t vendor_lttpr_write_address = 0xF004F;
uint8_t offset;
switch (link->dpcd_caps.lttpr_caps.phy_repeater_cnt) {
case 0x80: // 1 lttpr repeater
offset = 1;
break;
case 0x40: // 2 lttpr repeaters
offset = 2;
break;
case 0x20: // 3 lttpr repeaters
offset = 3;
break;
case 0x10: // 4 lttpr repeaters
offset = 4;
break;
case 0x08: // 5 lttpr repeaters
offset = 5;
break;
case 0x04: // 6 lttpr repeaters
offset = 6;
break;
case 0x02: // 7 lttpr repeaters
offset = 7;
break;
case 0x01: // 8 lttpr repeaters
offset = 8;
break;
default:
offset = 0xFF;
}
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
}
return vendor_lttpr_write_address;
}
uint32_t link_get_fixed_vs_pe_retimer_read_address(struct dc_link *link)
{
return link_get_fixed_vs_pe_retimer_write_address(link) + 4;
}
bool link_configure_fixed_vs_pe_retimer(struct ddc_service *ddc, const uint8_t *data, uint32_t length)
{
struct aux_payload write_payload = {
.i2c_over_aux = false,
.write = true,
.address = link_get_fixed_vs_pe_retimer_write_address(ddc->link),
.length = length,
.data = (uint8_t *) data,
.reply = NULL,
.mot = I2C_MOT_UNDEF,
.write_status_update = false,
.defer_delay = 0,
};
return link_aux_transfer_with_retries_no_mutex(ddc,
&write_payload);
}
bool link_query_fixed_vs_pe_retimer(struct ddc_service *ddc, uint8_t *data, uint32_t length)
{
struct aux_payload read_payload = {
.i2c_over_aux = false,
.write = false,
.address = link_get_fixed_vs_pe_retimer_read_address(ddc->link),
.length = length,
.data = data,
.reply = NULL,
.mot = I2C_MOT_UNDEF,
.write_status_update = false,
.defer_delay = 0,
};
return link_aux_transfer_with_retries_no_mutex(ddc,
&read_payload);
}
bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
struct aux_payload *payload)
{

View File

@ -72,6 +72,20 @@ bool link_query_ddc_data(
bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
struct aux_payload *payload);
bool link_configure_fixed_vs_pe_retimer(
struct ddc_service *ddc,
const uint8_t *data,
uint32_t length);
bool link_query_fixed_vs_pe_retimer(
struct ddc_service *ddc,
uint8_t *data,
uint32_t length);
uint32_t link_get_fixed_vs_pe_retimer_read_address(struct dc_link *link);
uint32_t link_get_fixed_vs_pe_retimer_write_address(struct dc_link *link);
void write_scdc_data(
struct ddc_service *ddc_service,
uint32_t pix_clk,

View File

@ -182,6 +182,68 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link)
return false;
}
static bool handle_hpd_irq_replay_sink(struct dc_link *link)
{
union dpcd_replay_configuration replay_configuration;
/*AMD Replay version reuse DP_PSR_ERROR_STATUS for REPLAY_ERROR status.*/
union psr_error_status replay_error_status;
if (!link->replay_settings.replay_feature_enabled)
return false;
dm_helpers_dp_read_dpcd(
link->ctx,
link,
DP_SINK_PR_REPLAY_STATUS,
&replay_configuration.raw,
sizeof(replay_configuration.raw));
dm_helpers_dp_read_dpcd(
link->ctx,
link,
DP_PSR_ERROR_STATUS,
&replay_error_status.raw,
sizeof(replay_error_status.raw));
link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR =
replay_error_status.bits.LINK_CRC_ERROR;
link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR =
replay_configuration.bits.DESYNC_ERROR_STATUS;
link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR =
replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS;
if (link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR ||
link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR ||
link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR) {
bool allow_active;
/* Acknowledge and clear configuration bits */
dm_helpers_dp_write_dpcd(
link->ctx,
link,
DP_SINK_PR_REPLAY_STATUS,
&replay_configuration.raw,
sizeof(replay_configuration.raw));
/* Acknowledge and clear error bits */
dm_helpers_dp_write_dpcd(
link->ctx,
link,
DP_PSR_ERROR_STATUS,/*DpcdAddress_REPLAY_Error_Status*/
&replay_error_status.raw,
sizeof(replay_error_status.raw));
/* Replay error, disable and re-enable Replay */
if (link->replay_settings.replay_allow_active) {
allow_active = false;
edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
allow_active = true;
edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
}
}
return true;
}
void dp_handle_link_loss(struct dc_link *link)
{
struct pipe_ctx *pipes[MAX_PIPES];
@ -360,6 +422,10 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
/* PSR-related error was detected and handled */
return true;
if (handle_hpd_irq_replay_sink(link))
/* Replay-related error was detected and handled */
return true;
/* If PSR-related error handled, Main link may be off,
* so do not handle as a normal sink status change interrupt.
*/

View File

@ -36,6 +36,7 @@
#include "link_dpcd.h"
#include "link_dp_phy.h"
#include "link_dp_capability.h"
#include "link_ddc.h"
#define DC_LOGGER \
link->ctx->logger
@ -46,42 +47,20 @@ void dp_fixed_vs_pe_read_lane_adjust(
{
const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
const uint8_t offset = dp_parse_lttpr_repeater_count(
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
uint32_t vendor_lttpr_write_address = 0xF004F;
uint32_t vendor_lttpr_read_address = 0xF0053;
uint8_t dprx_vs = 0;
uint8_t dprx_pe = 0;
uint8_t lane;
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
vendor_lttpr_read_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
}
/* W/A to read lane settings requested by DPRX */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_read_dpcd(
link,
vendor_lttpr_read_address,
&dprx_vs,
1);
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
core_link_read_dpcd(
link,
vendor_lttpr_read_address,
&dprx_pe,
1);
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1);
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 1);
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
@ -95,19 +74,11 @@ void dp_fixed_vs_pe_set_retimer_lane_settings(
const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
uint8_t lane_count)
{
const uint8_t offset = dp_parse_lttpr_repeater_count(
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
uint32_t vendor_lttpr_write_address = 0xF004F;
uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
uint8_t lane = 0;
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
}
for (lane = 0; lane < lane_count; lane++) {
vendor_lttpr_write_data_vs[3] |=
dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
@ -116,21 +87,14 @@ void dp_fixed_vs_pe_set_retimer_lane_settings(
}
/* Force LTTPR to output desired VS and PE */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_reset[0],
sizeof(vendor_lttpr_write_data_reset));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
}
static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
@ -241,7 +205,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
uint32_t vendor_lttpr_write_address = 0xF004F;
enum link_training_result status = LINK_TRAINING_SUCCESS;
uint8_t lane = 0;
union down_spread_ctrl downspread = {0};
@ -259,8 +222,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
}
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
if (offset == 2) {
pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
@ -271,28 +232,17 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
}
/* Vendor specific: Reset lane settings */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_reset[0],
sizeof(vendor_lttpr_write_data_reset));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
/* Vendor specific: Enable intercept */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_intercept_en[0],
sizeof(vendor_lttpr_write_data_intercept_en));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
/* 1. set link rate, lane count and spread. */
@ -344,31 +294,16 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
lt_settings->link_settings.link_spread);
if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_1[0],
sizeof(vendor_lttpr_write_data_4lane_1));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_2[0],
sizeof(vendor_lttpr_write_data_4lane_2));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_3[0],
sizeof(vendor_lttpr_write_data_4lane_3));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_4[0],
sizeof(vendor_lttpr_write_data_4lane_4));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_5[0],
sizeof(vendor_lttpr_write_data_4lane_5));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
}
/* 2. Perform link training */
@ -383,7 +318,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
union lane_align_status_updated dpcd_lane_status_updated;
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
enum dc_status dpcd_status = DC_OK;
uint8_t i = 0;
retries_cr = 0;
@ -418,18 +352,12 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
for (i = 0; i < max_vendor_dpcd_retries; i++) {
if (pre_disable_intercept_delay_ms != 0)
msleep(pre_disable_intercept_delay_ms);
dpcd_status = core_link_write_dpcd(
link,
vendor_lttpr_write_address,
if (link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_dis[0],
sizeof(vendor_lttpr_write_data_intercept_dis));
if (dpcd_status == DC_OK)
sizeof(vendor_lttpr_write_data_intercept_dis)))
break;
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_en[0],
sizeof(vendor_lttpr_write_data_intercept_en));
}
@ -445,16 +373,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
}
/* Vendor specific: Update VS and PE to DPRX requested value */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
dpcd_set_lane_settings(
link,
@ -550,16 +472,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
}
/* Vendor specific: Update VS and PE to DPRX requested value */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
/* 2. update DPCD*/
if (!retries_ch_eq)
@ -636,7 +552,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
uint32_t vendor_lttpr_write_address = 0xF004F;
enum link_training_result status = LINK_TRAINING_SUCCESS;
uint8_t lane = 0;
union down_spread_ctrl downspread = {0};
@ -654,8 +569,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
}
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
if (offset == 2) {
pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
@ -666,28 +579,16 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
}
/* Vendor specific: Reset lane settings */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_reset[0],
sizeof(vendor_lttpr_write_data_reset));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
/* Vendor specific: Enable intercept */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_intercept_en[0],
sizeof(vendor_lttpr_write_data_intercept_en));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
/* 1. set link rate, lane count and spread. */
@ -739,31 +640,16 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
lt_settings->link_settings.link_spread);
if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_1[0],
sizeof(vendor_lttpr_write_data_4lane_1));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_2[0],
sizeof(vendor_lttpr_write_data_4lane_2));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_3[0],
sizeof(vendor_lttpr_write_data_4lane_3));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_4[0],
sizeof(vendor_lttpr_write_data_4lane_4));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_4lane_5[0],
sizeof(vendor_lttpr_write_data_4lane_5));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
}
/* 2. Perform link training */
@ -778,7 +664,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
union lane_align_status_updated dpcd_lane_status_updated;
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
enum dc_status dpcd_status = DC_OK;
uint8_t i = 0;
retries_cr = 0;
@ -813,18 +698,12 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
for (i = 0; i < max_vendor_dpcd_retries; i++) {
if (pre_disable_intercept_delay_ms != 0)
msleep(pre_disable_intercept_delay_ms);
dpcd_status = core_link_write_dpcd(
link,
vendor_lttpr_write_address,
if (link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_dis[0],
sizeof(vendor_lttpr_write_data_intercept_dis));
if (dpcd_status == DC_OK)
sizeof(vendor_lttpr_write_data_intercept_dis)))
break;
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_intercept_en[0],
sizeof(vendor_lttpr_write_data_intercept_en));
}
@ -840,16 +719,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
}
/* Vendor specific: Update VS and PE to DPRX requested value */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
dpcd_set_lane_settings(
link,
@ -922,17 +795,14 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_adicora_eq1[0],
sizeof(vendor_lttpr_write_data_adicora_eq1));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_adicora_eq2[0],
sizeof(vendor_lttpr_write_data_adicora_eq2));
/* Note: also check that TPS4 is a supported feature*/
tr_pattern = lt_settings->pattern_for_eq;
@ -956,16 +826,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
}
/* Vendor specific: Update VS and PE to DPRX requested value */
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_vs[0],
sizeof(vendor_lttpr_write_data_vs));
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_pe[0],
sizeof(vendor_lttpr_write_data_pe));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
/* 2. update DPCD*/
if (!retries_ch_eq) {
@ -978,11 +842,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
lt_settings,
tr_pattern, 0);
core_link_write_dpcd(
link,
vendor_lttpr_write_address,
&vendor_lttpr_write_data_adicora_eq3[0],
sizeof(vendor_lttpr_write_data_adicora_eq3));
link_configure_fixed_vs_pe_retimer(link->ddc,
&vendor_lttpr_write_data_adicora_eq3[0],
sizeof(vendor_lttpr_write_data_adicora_eq3));
} else
dpcd_set_lane_settings(link, lt_settings, 0);

View File

@ -2144,6 +2144,10 @@ enum dmub_phy_fsm_state {
DMUB_PHY_FSM_PLL_EN,
DMUB_PHY_FSM_TX_EN,
DMUB_PHY_FSM_FAST_LP,
DMUB_PHY_FSM_P2_PLL_OFF_CPM,
DMUB_PHY_FSM_P2_PLL_OFF_PG,
DMUB_PHY_FSM_P2_PLL_OFF,
DMUB_PHY_FSM_P2_PLL_ON,
};
/**

View File

@ -149,6 +149,8 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
/* VSC packet set to 4 for PSR-SU, or 2 for PSR1 */
if (stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1)
vsc_packet_revision = vsc_packet_rev4;
else if (stream->link->replay_settings.config.replay_supported)
vsc_packet_revision = vsc_packet_rev4;
else if (stream->link->psr_settings.psr_version == DC_PSR_VERSION_1)
vsc_packet_revision = vsc_packet_rev2;
@ -536,6 +538,9 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
case FREESYNC_TYPE_PCON_IN_WHITELIST:
mod_build_adaptive_sync_infopacket_v1(info_packet);
break;
case ADAPTIVE_SYNC_TYPE_EDP:
mod_build_adaptive_sync_infopacket_v1(info_packet);
break;
case ADAPTIVE_SYNC_TYPE_NONE:
case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST:
default:

View File

@ -15805,6 +15805,11 @@
#define mmDME6_DME_MEMORY_CONTROL 0x093d
#define mmDME6_DME_MEMORY_CONTROL_BASE_IDX 3
// addressBlock: dce_dc_hpo_hpo_top_dispdec
// base address: 0x0
#define mmHPO_TOP_CLOCK_CONTROL 0x0e43
#define mmHPO_TOP_CLOCK_CONTROL_BASE_IDX 3
// base address: 0x1a698
#define mmDC_PERFMON29_PERFCOUNTER_CNTL 0x0e66
#define mmDC_PERFMON29_PERFCOUNTER_CNTL_BASE_IDX 3

View File

@ -60666,7 +60666,12 @@
#define DME6_DME_MEMORY_CONTROL__DME_MEM_PWR_STATE_MASK 0x00000300L
#define DME6_DME_MEMORY_CONTROL__DME_MEM_DEFAULT_MEM_LOW_POWER_STATE_MASK 0x00003000L
// addressBlock: dce_dc_hpo_hpo_top_dispdec
//HPO_TOP_CLOCK_CONTROL
#define HPO_TOP_CLOCK_CONTROL__HPO_HDMISTREAMCLK_GATE_DIS__SHIFT 0x9
#define HPO_TOP_CLOCK_CONTROL__HPO_HDMISTREAMCLK_GATE_DIS_MASK 0x00000200L
// addressBlock: dce_dc_hpo_hpo_dcperfmon_dc_perfmon_dispdec
//DC_PERFMON29_PERFCOUNTER_CNTL
#define DC_PERFMON29_PERFCOUNTER_CNTL__PERFCOUNTER_EVENT_SEL__SHIFT 0x0
#define DC_PERFMON29_PERFCOUNTER_CNTL__PERFCOUNTER_CVALUE_SEL__SHIFT 0x9

View File

@ -14205,6 +14205,10 @@
// addressBlock: dce_dc_hpo_hpo_top_dispdec
// base address: 0x0
#define mmHPO_TOP_CLOCK_CONTROL 0x0e43
#define mmHPO_TOP_CLOCK_CONTROL_BASE_IDX 3
// base address: 0x1a698
#define mmDC_PERFMON26_PERFCOUNTER_CNTL 0x0e66

View File

@ -52401,7 +52401,10 @@
#define DC_PERFMON25_PERFMON_LOW__PERFMON_LOW__SHIFT 0x0
#define DC_PERFMON25_PERFMON_LOW__PERFMON_LOW_MASK 0xFFFFFFFFL
// addressBlock: dce_dc_hpo_hpo_top_dispdec
//HPO_TOP_CLOCK_CONTROL
#define HPO_TOP_CLOCK_CONTROL__HPO_HDMISTREAMCLK_GATE_DIS__SHIFT 0x9
#define HPO_TOP_CLOCK_CONTROL__HPO_HDMISTREAMCLK_GATE_DIS_MASK 0x00000200L
// addressBlock: dce_dc_hpo_hpo_dcperfmon_dc_perfmon_dispdec
//DC_PERFMON26_PERFCOUNTER_CNTL

View File

@ -132,7 +132,8 @@ enum amd_pp_sensors {
AMDGPU_PP_SENSOR_MEM_TEMP,
AMDGPU_PP_SENSOR_VCE_POWER,
AMDGPU_PP_SENSOR_UVD_POWER,
AMDGPU_PP_SENSOR_GPU_POWER,
AMDGPU_PP_SENSOR_GPU_AVG_POWER,
AMDGPU_PP_SENSOR_GPU_INPUT_POWER,
AMDGPU_PP_SENSOR_SS_APU_SHARE,
AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK,

View File

@ -1467,6 +1467,32 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
return -EINVAL;
}
static unsigned int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev,
enum amd_pp_sensors sensor,
void *query)
{
int r, size = sizeof(uint32_t);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
/* get the sensor value */
r = amdgpu_dpm_read_sensor(adev, sensor, query, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
/**
* DOC: gpu_busy_percent
*
@ -1481,26 +1507,10 @@ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
int r, value, size = sizeof(value);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(ddev->dev);
if (r < 0) {
pm_runtime_put_autosuspend(ddev->dev);
return r;
}
/* read the IP busy sensor */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD,
(void *)&value, &size);
pm_runtime_mark_last_busy(ddev->dev);
pm_runtime_put_autosuspend(ddev->dev);
unsigned int value;
int r;
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value);
if (r)
return r;
@ -1521,26 +1531,10 @@ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
int r, value, size = sizeof(value);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(ddev->dev);
if (r < 0) {
pm_runtime_put_autosuspend(ddev->dev);
return r;
}
/* read the IP busy sensor */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MEM_LOAD,
(void *)&value, &size);
pm_runtime_mark_last_busy(ddev->dev);
pm_runtime_put_autosuspend(ddev->dev);
unsigned int value;
int r;
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value);
if (r)
return r;
@ -1814,45 +1808,15 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
return size;
}
static int amdgpu_device_read_powershift(struct amdgpu_device *adev,
uint32_t *ss_power, bool dgpu_share)
{
struct drm_device *ddev = adev_to_drm(adev);
uint32_t size;
int r = 0;
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(ddev->dev);
if (r < 0) {
pm_runtime_put_autosuspend(ddev->dev);
return r;
}
if (dgpu_share)
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
(void *)ss_power, &size);
else
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE,
(void *)ss_power, &size);
pm_runtime_mark_last_busy(ddev->dev);
pm_runtime_put_autosuspend(ddev->dev);
return r;
}
static int amdgpu_show_powershift_percent(struct device *dev,
char *buf, bool dgpu_share)
char *buf, enum amd_pp_sensors sensor)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
uint32_t ss_power;
int r = 0, i;
r = amdgpu_device_read_powershift(adev, &ss_power, dgpu_share);
r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power);
if (r == -EOPNOTSUPP) {
/* sensor not available on dGPU, try to read from APU */
adev = NULL;
@ -1865,14 +1829,15 @@ static int amdgpu_show_powershift_percent(struct device *dev,
}
mutex_unlock(&mgpu_info.mutex);
if (adev)
r = amdgpu_device_read_powershift(adev, &ss_power, dgpu_share);
r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power);
}
if (!r)
r = sysfs_emit(buf, "%u%%\n", ss_power);
if (r)
return r;
return r;
return sysfs_emit(buf, "%u%%\n", ss_power);
}
/**
* DOC: smartshift_apu_power
*
@ -1886,7 +1851,7 @@ static int amdgpu_show_powershift_percent(struct device *dev,
static ssize_t amdgpu_get_smartshift_apu_power(struct device *dev, struct device_attribute *attr,
char *buf)
{
return amdgpu_show_powershift_percent(dev, buf, false);
return amdgpu_show_powershift_percent(dev, buf, AMDGPU_PP_SENSOR_SS_APU_SHARE);
}
/**
@ -1902,7 +1867,7 @@ static ssize_t amdgpu_get_smartshift_apu_power(struct device *dev, struct device
static ssize_t amdgpu_get_smartshift_dgpu_power(struct device *dev, struct device_attribute *attr,
char *buf)
{
return amdgpu_show_powershift_percent(dev, buf, true);
return amdgpu_show_powershift_percent(dev, buf, AMDGPU_PP_SENSOR_SS_DGPU_SHARE);
}
/**
@ -1965,7 +1930,6 @@ static ssize_t amdgpu_set_smartshift_bias(struct device *dev,
return r;
}
static int ss_power_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr,
uint32_t mask, enum amdgpu_device_attr_states *states)
{
@ -1978,15 +1942,15 @@ static int ss_power_attr_update(struct amdgpu_device *adev, struct amdgpu_device
static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr,
uint32_t mask, enum amdgpu_device_attr_states *states)
{
uint32_t ss_power, size;
uint32_t ss_power;
if (!amdgpu_device_supports_smart_shift(adev_to_drm(adev)))
*states = ATTR_STATE_UNSUPPORTED;
else if (amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE,
(void *)&ss_power, &size))
else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE,
(void *)&ss_power))
*states = ATTR_STATE_UNSUPPORTED;
else if (amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
(void *)&ss_power, &size))
else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE,
(void *)&ss_power))
*states = ATTR_STATE_UNSUPPORTED;
return 0;
@ -2095,7 +2059,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
gc_ver == IP_VERSION(10, 1, 2) ||
gc_ver == IP_VERSION(11, 0, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3)))
gc_ver == IP_VERSION(11, 0, 3) ||
gc_ver == IP_VERSION(9, 4, 3)))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_vclk1)) {
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
@ -2109,7 +2074,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
gc_ver == IP_VERSION(10, 1, 2) ||
gc_ver == IP_VERSION(11, 0, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3)))
gc_ver == IP_VERSION(11, 0, 3) ||
gc_ver == IP_VERSION(9, 4, 3)))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_dclk1)) {
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
@ -2269,46 +2235,32 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
int channel = to_sensor_dev_attr(attr)->index;
int r, temp = 0, size = sizeof(temp);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
int r, temp = 0;
if (channel >= PP_TEMP_MAX)
return -EINVAL;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
switch (channel) {
case PP_TEMP_JUNCTION:
/* get current junction temperature */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP,
(void *)&temp, &size);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP,
(void *)&temp);
break;
case PP_TEMP_EDGE:
/* get current edge temperature */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_EDGE_TEMP,
(void *)&temp, &size);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_EDGE_TEMP,
(void *)&temp);
break;
case PP_TEMP_MEM:
/* get current memory temperature */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MEM_TEMP,
(void *)&temp, &size);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_TEMP,
(void *)&temp);
break;
default:
r = -EINVAL;
break;
}
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
if (r)
return r;
@ -2592,25 +2544,10 @@ static ssize_t amdgpu_hwmon_get_fan1_min(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
u32 min_rpm = 0;
u32 size = sizeof(min_rpm);
int r;
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM,
(void *)&min_rpm, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM,
(void *)&min_rpm);
if (r)
return r;
@ -2624,25 +2561,10 @@ static ssize_t amdgpu_hwmon_get_fan1_max(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
u32 max_rpm = 0;
u32 size = sizeof(max_rpm);
int r;
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM,
(void *)&max_rpm, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM,
(void *)&max_rpm);
if (r)
return r;
@ -2804,26 +2726,11 @@ static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
u32 vddgfx;
int r, size = sizeof(vddgfx);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
int r;
/* get the voltage */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX,
(void *)&vddgfx, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDGFX,
(void *)&vddgfx);
if (r)
return r;
@ -2843,30 +2750,15 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
u32 vddnb;
int r, size = sizeof(vddnb);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
int r;
/* only APUs have vddnb */
if (!(adev->flags & AMD_IS_APU))
return -EINVAL;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
/* get the voltage */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB,
(void *)&vddnb, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDNB,
(void *)&vddnb);
if (r)
return r;
@ -2880,40 +2772,48 @@ static ssize_t amdgpu_hwmon_show_vddnb_label(struct device *dev,
return sysfs_emit(buf, "vddnb\n");
}
static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
struct device_attribute *attr,
char *buf)
static unsigned int amdgpu_hwmon_get_power(struct device *dev,
enum amd_pp_sensors sensor)
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
unsigned int uw;
u32 query = 0;
int r, size = sizeof(u32);
unsigned uw;
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
/* get the voltage */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER,
(void *)&query, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
int r;
r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&query);
if (r)
return r;
/* convert to microwatts */
uw = (query >> 8) * 1000000 + (query & 0xff) * 1000;
return sysfs_emit(buf, "%u\n", uw);
return uw;
}
static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
struct device_attribute *attr,
char *buf)
{
unsigned int val;
val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_AVG_POWER);
if (val < 0)
return val;
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t amdgpu_hwmon_show_power_input(struct device *dev,
struct device_attribute *attr,
char *buf)
{
unsigned int val;
val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER);
if (val < 0)
return val;
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev,
@ -3048,26 +2948,11 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
uint32_t sclk;
int r, size = sizeof(sclk);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
int r;
/* get the sclk */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
(void *)&sclk, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
(void *)&sclk);
if (r)
return r;
@ -3087,26 +2972,11 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev,
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
uint32_t mclk;
int r, size = sizeof(mclk);
if (amdgpu_in_reset(adev))
return -EPERM;
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
int r;
/* get the sclk */
r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
(void *)&mclk, &size);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
(void *)&mclk);
if (r)
return r;
@ -3166,6 +3036,8 @@ static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev,
*
* - power1_average: average power used by the SoC in microWatts. On APUs this includes the CPU.
*
* - power1_input: instantaneous power used by the SoC in microWatts. On APUs this includes the CPU.
*
* - power1_cap_min: minimum cap supported in microWatts
*
* - power1_cap_max: maximum cap supported in microWatts
@ -3234,6 +3106,7 @@ static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NU
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, amdgpu_hwmon_show_power_input, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0);
static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);
@ -3280,6 +3153,7 @@ static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_label.dev_attr.attr,
&sensor_dev_attr_power1_average.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_power1_cap_max.dev_attr.attr,
&sensor_dev_attr_power1_cap_min.dev_attr.attr,
&sensor_dev_attr_power1_cap.dev_attr.attr,
@ -3305,6 +3179,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
struct amdgpu_device *adev = dev_get_drvdata(dev);
umode_t effective_mode = attr->mode;
uint32_t gc_ver = adev->ip_versions[GC_HWIP][0];
uint32_t tmp;
/* under multi-vf mode, the hwmon attributes are all not supported */
if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
@ -3390,6 +3265,14 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
(attr == &sensor_dev_attr_power1_average.dev_attr.attr))
return 0;
/* not all products support both average and instantaneous */
if (attr == &sensor_dev_attr_power1_average.dev_attr.attr &&
amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&tmp) == -EOPNOTSUPP)
return 0;
if (attr == &sensor_dev_attr_power1_input.dev_attr.attr &&
amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&tmp) == -EOPNOTSUPP)
return 0;
/* hide max/min values if we can't both query and manage the fan */
if (((amdgpu_dpm_set_fan_speed_pwm(adev, U32_MAX) == -EOPNOTSUPP) &&
(amdgpu_dpm_get_fan_speed_pwm(adev, NULL) == -EOPNOTSUPP) &&
@ -3586,7 +3469,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size))
seq_printf(m, "\t%u mV (VDDNB)\n", value);
size = sizeof(uint32_t);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, (void *)&query, &size))
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size))
seq_printf(m, "\t%u.%u W (average GPU)\n", query >> 8, query & 0xff);
size = sizeof(value);
seq_printf(m, "\n");

View File

@ -4039,7 +4039,7 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx,
*((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
*size = 4;
return 0;
case AMDGPU_PP_SENSOR_GPU_POWER:
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
return smu7_get_gpu_power(hwmgr, (uint32_t *)value);
case AMDGPU_PP_SENSOR_VDDGFX:
if ((data->vr_config & VRCONF_VDDGFX_MASK) ==

View File

@ -3966,7 +3966,7 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx,
*((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_POWER:
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
ret = vega10_get_gpu_power(hwmgr, (uint32_t *)value);
break;
case AMDGPU_PP_SENSOR_VDDGFX:

View File

@ -1529,7 +1529,7 @@ static int vega12_read_sensor(struct pp_hwmgr *hwmgr, int idx,
*((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_POWER:
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
ret = vega12_get_gpu_power(hwmgr, (uint32_t *)value);
if (!ret)
*size = 4;

View File

@ -2129,7 +2129,7 @@ static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr,
return ret;
}
static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int idx,
uint32_t *query)
{
int ret = 0;
@ -2140,10 +2140,17 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
return ret;
/* For the 40.46 release, they changed the value name */
if (hwmgr->smu_version == 0x282e00)
*query = metrics_table.AverageSocketPower << 8;
else
switch (idx) {
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
if (hwmgr->smu_version == 0x282e00)
*query = metrics_table.AverageSocketPower << 8;
else
ret = -EOPNOTSUPP;
break;
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
*query = metrics_table.CurrSocketPower << 8;
break;
}
return ret;
}
@ -2253,9 +2260,10 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
*((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_POWER:
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
*size = 16;
ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value);
ret = vega20_get_gpu_power(hwmgr, idx, (uint32_t *)value);
break;
case AMDGPU_PP_SENSOR_VDDGFX:
val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) &

View File

@ -200,29 +200,25 @@ struct smu_power_state {
struct smu_hw_power_state hardware;
};
enum smu_power_src_type
{
enum smu_power_src_type {
SMU_POWER_SOURCE_AC,
SMU_POWER_SOURCE_DC,
SMU_POWER_SOURCE_COUNT,
};
enum smu_ppt_limit_type
{
enum smu_ppt_limit_type {
SMU_DEFAULT_PPT_LIMIT = 0,
SMU_FAST_PPT_LIMIT,
};
enum smu_ppt_limit_level
{
enum smu_ppt_limit_level {
SMU_PPT_LIMIT_MIN = -1,
SMU_PPT_LIMIT_CURRENT,
SMU_PPT_LIMIT_DEFAULT,
SMU_PPT_LIMIT_MAX,
};
enum smu_memory_pool_size
{
enum smu_memory_pool_size {
SMU_MEMORY_POOL_SIZE_ZERO = 0,
SMU_MEMORY_POOL_SIZE_256_MB = 0x10000000,
SMU_MEMORY_POOL_SIZE_512_MB = 0x20000000,
@ -282,8 +278,7 @@ struct smu_clock_info {
uint32_t max_bus_bandwidth;
};
struct smu_bios_boot_up_values
{
struct smu_bios_boot_up_values {
uint32_t revision;
uint32_t gfxclk;
uint32_t uclk;
@ -305,8 +300,7 @@ struct smu_bios_boot_up_values
uint32_t firmware_caps;
};
enum smu_table_id
{
enum smu_table_id {
SMU_TABLE_PPTABLE = 0,
SMU_TABLE_WATERMARKS,
SMU_TABLE_CUSTOM_DPM,
@ -326,8 +320,7 @@ enum smu_table_id
SMU_TABLE_COUNT,
};
struct smu_table_context
{
struct smu_table_context {
void *power_play_table;
uint32_t power_play_table_size;
void *hardcode_pptable;
@ -390,8 +383,7 @@ struct smu_power_context {
};
#define SMU_FEATURE_MAX (64)
struct smu_feature
{
struct smu_feature {
uint32_t feature_num;
DECLARE_BITMAP(supported, SMU_FEATURE_MAX);
DECLARE_BITMAP(allowed, SMU_FEATURE_MAX);
@ -416,21 +408,18 @@ struct mclock_latency_table {
struct mclk_latency_entries entries[MAX_REGULAR_DPM_NUM];
};
enum smu_reset_mode
{
enum smu_reset_mode {
SMU_RESET_MODE_0,
SMU_RESET_MODE_1,
SMU_RESET_MODE_2,
};
enum smu_baco_state
{
enum smu_baco_state {
SMU_BACO_STATE_ENTER = 0,
SMU_BACO_STATE_EXIT,
};
struct smu_baco_context
{
struct smu_baco_context {
uint32_t state;
bool platform_support;
bool maco_support;
@ -478,8 +467,7 @@ struct stb_context {
#define WORKLOAD_POLICY_MAX 7
struct smu_context
{
struct smu_context {
struct amdgpu_device *adev;
struct amdgpu_irq_src irq_source;
@ -1398,6 +1386,7 @@ typedef enum {
METRICS_PCIE_RATE,
METRICS_PCIE_WIDTH,
METRICS_CURR_FANPWM,
METRICS_CURR_SOCKETPOWER,
} MetricsMember_t;
enum smu_cmn2asic_mapping_type {

View File

@ -23,7 +23,7 @@
#ifndef __SMU13_DRIVER_IF_V13_0_5_H__
#define __SMU13_DRIVER_IF_V13_0_5_H__
#define SMU13_0_5_DRIVER_IF_VERSION 4
#define SMU13_0_5_DRIVER_IF_VERSION 5
// Throttler Status Bitmask
#define THROTTLER_STATUS_BIT_SPL 0
@ -103,7 +103,6 @@ typedef struct {
uint16_t ThrottlerStatus;
uint16_t CurrentSocketPower; //[mW]
uint16_t spare1;
} SmuMetrics_t;
//Freq in MHz

View File

@ -64,7 +64,6 @@
#define LINK_SPEED_MAX 3
static const __maybe_unused uint16_t link_width[] = {0, 1, 2, 4, 8, 12, 16};
static const __maybe_unused uint16_t link_speed[] = {25, 50, 80, 160};
static const
struct smu_temperature_range __maybe_unused smu11_thermal_policy[] = {

View File

@ -101,8 +101,7 @@ enum SMU_11_0_ODSETTING_ID {
};
#define SMU_11_0_MAX_ODSETTING 32 //Maximum Number of ODSettings
struct smu_11_0_overdrive_table
{
struct smu_11_0_overdrive_table {
uint8_t revision; //Revision = SMU_11_0_PP_OVERDRIVE_VERSION
uint8_t reserve[3]; //Zero filled field reserved for future use
uint32_t feature_count; //Total number of supported features
@ -127,8 +126,7 @@ enum SMU_11_0_PPCLOCK_ID {
};
#define SMU_11_0_MAX_PPCLOCK 16 //Maximum Number of PP Clocks
struct smu_11_0_power_saving_clock_table
{
struct smu_11_0_power_saving_clock_table {
uint8_t revision; //Revision = SMU_11_0_PP_POWERSAVINGCLOCK_VERSION
uint8_t reserve[3]; //Zero filled field reserved for future use
uint32_t count; //power_saving_clock_count = SMU_11_0_PPCLOCK_COUNT
@ -136,8 +134,7 @@ struct smu_11_0_power_saving_clock_table
uint32_t min[SMU_11_0_MAX_PPCLOCK]; //PowerSavingClock Mode Clock Minimum array In MHz
};
struct smu_11_0_powerplay_table
{
struct smu_11_0_powerplay_table {
struct atom_common_table_header header;
uint8_t table_revision;
uint16_t table_size; //Driver portion table size. The offset to smc_pptable including header size
@ -145,14 +142,14 @@ struct smu_11_0_powerplay_table
uint32_t golden_revision;
uint16_t format_id;
uint32_t platform_caps; //POWERPLAYABLE::ulPlatformCaps
uint8_t thermal_controller_type; //one of SMU_11_0_PP_THERMALCONTROLLER
uint16_t small_power_limit1;
uint16_t small_power_limit2;
uint16_t boost_power_limit;
uint16_t od_turbo_power_limit; //Power limit setting for Turbo mode in Performance UI Tuning.
uint16_t od_power_save_power_limit; //Power limit setting for PowerSave/Optimal mode in Performance UI Tuning.
uint16_t od_turbo_power_limit; //Power limit setting for Turbo mode in Performance UI Tuning.
uint16_t od_power_save_power_limit; //Power limit setting for PowerSave/Optimal mode in Performance UI Tuning.
uint16_t software_shutdown_temp;
uint16_t reserve[6]; //Zero filled field reserved for future use

View File

@ -1130,7 +1130,7 @@ static int arcturus_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_POWER:
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
ret = arcturus_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
(uint32_t *)data);
@ -1169,6 +1169,7 @@ static int arcturus_read_sensor(struct smu_context *smu,
ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
default:
ret = -EOPNOTSUPP;
break;

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