Merge branch 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux into drm-next
Last set of radeon and amdgpu changes for 4.9. This is mostly just the powerplay cleanup for dGPUs. Beyond that, just misc code cleanups and bug fixes. * 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux: (49 commits) drm/amd/amdgpu: Clean up afmt allocation in DCEv6. (v2) drm/amd/amdgpu: Remove division from vblank_wait drm/radeon/atif: Send a hotplug event when we get dgpu display request drm/radeon/atpx: check for ATIF dGPU wake for display events support drm/amdgpu/atif: Send a hotplug event when we get dgpu display request drm/amdgpu/atpx: check for ATIF dGPU wake for display events support drm/amdgpu: bump version for new vce packet support drm/amdgpu/vce: allow the clock table packet drm/amdgpu:cleanup virt related define drm/amdgpu: use powerplay module for dgpu in Vi. drm/amdgpu: set gfx clock gating for tonga/polaris. drm/amdgpu: set system clock gating for tonga/polaris. drm/amd/powerplay: export function to help to set cg by smu. drm/amdgpu: avoid out of bounds access on array interrupt_status_offsets drm/amdgpu: mark symbols static where possible drm/amdgpu: remove unused functions drm/amd/powerplay: Replace per-asic print_performance with generic drm/radeon: narrow asic_init for virtualization drm/amdgpu:add fw version entry to info drm/amdgpu:determine if vPost is needed indeed ...
This commit is contained in:
commit
9f4ef05bcd
|
@ -52,10 +52,7 @@ amdgpu-y += \
|
|||
amdgpu-y += \
|
||||
amdgpu_dpm.o \
|
||||
amdgpu_powerplay.o \
|
||||
cz_smc.o cz_dpm.o \
|
||||
tonga_smc.o tonga_dpm.o \
|
||||
fiji_smc.o fiji_dpm.o \
|
||||
iceland_smc.o iceland_dpm.o
|
||||
cz_smc.o cz_dpm.o
|
||||
|
||||
# add DCE block
|
||||
amdgpu-y += \
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "amdgpu_acp.h"
|
||||
|
||||
#include "gpu_scheduler.h"
|
||||
#include "amdgpu_virt.h"
|
||||
|
||||
/*
|
||||
* Modules parameters.
|
||||
|
@ -1827,6 +1828,7 @@ struct amdgpu_asic_funcs {
|
|||
bool (*read_disabled_bios)(struct amdgpu_device *adev);
|
||||
bool (*read_bios_from_rom)(struct amdgpu_device *adev,
|
||||
u8 *bios, u32 length_bytes);
|
||||
void (*detect_hw_virtualization) (struct amdgpu_device *adev);
|
||||
int (*read_register)(struct amdgpu_device *adev, u32 se_num,
|
||||
u32 sh_num, u32 reg_offset, u32 *value);
|
||||
void (*set_vga_state)(struct amdgpu_device *adev, bool state);
|
||||
|
@ -1836,8 +1838,6 @@ struct amdgpu_asic_funcs {
|
|||
/* MM block clocks */
|
||||
int (*set_uvd_clocks)(struct amdgpu_device *adev, u32 vclk, u32 dclk);
|
||||
int (*set_vce_clocks)(struct amdgpu_device *adev, u32 evclk, u32 ecclk);
|
||||
/* query virtual capabilities */
|
||||
u32 (*get_virtual_caps)(struct amdgpu_device *adev);
|
||||
/* static power management */
|
||||
int (*get_pcie_lanes)(struct amdgpu_device *adev);
|
||||
void (*set_pcie_lanes)(struct amdgpu_device *adev, int lanes);
|
||||
|
@ -1933,16 +1933,6 @@ struct amdgpu_atcs {
|
|||
struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev);
|
||||
void amdgpu_cgs_destroy_device(struct cgs_device *cgs_device);
|
||||
|
||||
|
||||
/* GPU virtualization */
|
||||
#define AMDGPU_VIRT_CAPS_SRIOV_EN (1 << 0)
|
||||
#define AMDGPU_VIRT_CAPS_IS_VF (1 << 1)
|
||||
struct amdgpu_virtualization {
|
||||
bool supports_sr_iov;
|
||||
bool is_virtual;
|
||||
u32 caps;
|
||||
};
|
||||
|
||||
/*
|
||||
* Core structure, functions and helpers.
|
||||
*/
|
||||
|
@ -2260,12 +2250,12 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
|||
#define amdgpu_asic_get_xclk(adev) (adev)->asic_funcs->get_xclk((adev))
|
||||
#define amdgpu_asic_set_uvd_clocks(adev, v, d) (adev)->asic_funcs->set_uvd_clocks((adev), (v), (d))
|
||||
#define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
|
||||
#define amdgpu_asic_get_virtual_caps(adev) ((adev)->asic_funcs->get_virtual_caps((adev)))
|
||||
#define amdgpu_get_pcie_lanes(adev) (adev)->asic_funcs->get_pcie_lanes((adev))
|
||||
#define amdgpu_set_pcie_lanes(adev, l) (adev)->asic_funcs->set_pcie_lanes((adev), (l))
|
||||
#define amdgpu_asic_get_gpu_clock_counter(adev) (adev)->asic_funcs->get_gpu_clock_counter((adev))
|
||||
#define amdgpu_asic_read_disabled_bios(adev) (adev)->asic_funcs->read_disabled_bios((adev))
|
||||
#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
|
||||
#define amdgpu_asic_detect_hw_virtualization(adev) (adev)->asic_funcs->detect_hw_virtualization((adev))
|
||||
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
|
||||
#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
|
||||
#define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
|
||||
|
@ -2323,6 +2313,11 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
|||
#define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
|
||||
#define amdgpu_gfx_select_se_sh(adev, se, sh, instance) (adev)->gfx.funcs->select_se_sh((adev), (se), (sh), (instance))
|
||||
|
||||
#define amdgpu_dpm_read_sensor(adev, idx, value) \
|
||||
((adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, (idx), (value)) : \
|
||||
-EINVAL)
|
||||
|
||||
#define amdgpu_dpm_get_temperature(adev) \
|
||||
((adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle) : \
|
||||
|
@ -2374,11 +2369,6 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
|||
(adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g)) : \
|
||||
(adev)->pm.funcs->powergate_vce((adev), (g)))
|
||||
|
||||
#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) \
|
||||
((adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->print_current_performance_level((adev)->powerplay.pp_handle, (m)) : \
|
||||
(adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m)))
|
||||
|
||||
#define amdgpu_dpm_get_current_power_state(adev) \
|
||||
(adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)
|
||||
|
||||
|
@ -2460,11 +2450,13 @@ void amdgpu_register_atpx_handler(void);
|
|||
void amdgpu_unregister_atpx_handler(void);
|
||||
bool amdgpu_has_atpx_dgpu_power_cntl(void);
|
||||
bool amdgpu_is_atpx_hybrid(void);
|
||||
bool amdgpu_atpx_dgpu_req_power_for_displays(void);
|
||||
#else
|
||||
static inline void amdgpu_register_atpx_handler(void) {}
|
||||
static inline void amdgpu_unregister_atpx_handler(void) {}
|
||||
static inline bool amdgpu_has_atpx_dgpu_power_cntl(void) { return false; }
|
||||
static inline bool amdgpu_is_atpx_hybrid(void) { return false; }
|
||||
static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <acpi/video.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
@ -333,6 +334,16 @@ int amdgpu_atif_handler(struct amdgpu_device *adev,
|
|||
#endif
|
||||
}
|
||||
}
|
||||
if (req.pending & ATIF_DGPU_DISPLAY_EVENT) {
|
||||
if ((adev->flags & AMD_IS_PX) &&
|
||||
amdgpu_atpx_dgpu_req_power_for_displays()) {
|
||||
pm_runtime_get_sync(adev->ddev->dev);
|
||||
/* Just fire off a uevent and let userspace tell us what to do */
|
||||
drm_helper_hpd_irq_event(adev->ddev);
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
}
|
||||
}
|
||||
/* TODO: check other events */
|
||||
|
||||
/* We've handled the event, stop the notifier chain. The ACPI interface
|
||||
|
|
|
@ -143,14 +143,6 @@ int amdgpu_amdkfd_resume(struct amdgpu_device *rdev)
|
|||
return r;
|
||||
}
|
||||
|
||||
u32 pool_to_domain(enum kgd_memory_pool p)
|
||||
{
|
||||
switch (p) {
|
||||
case KGD_POOL_FRAMEBUFFER: return AMDGPU_GEM_DOMAIN_VRAM;
|
||||
default: return AMDGPU_GEM_DOMAIN_GTT;
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
|
||||
void **mem_obj, uint64_t *gpu_addr,
|
||||
void **cpu_ptr)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct amdgpu_atpx {
|
|||
acpi_handle handle;
|
||||
struct amdgpu_atpx_functions functions;
|
||||
bool is_hybrid;
|
||||
bool dgpu_req_power_for_displays;
|
||||
};
|
||||
|
||||
static struct amdgpu_atpx_priv {
|
||||
|
@ -73,6 +74,10 @@ bool amdgpu_is_atpx_hybrid(void) {
|
|||
return amdgpu_atpx_priv.atpx.is_hybrid;
|
||||
}
|
||||
|
||||
bool amdgpu_atpx_dgpu_req_power_for_displays(void) {
|
||||
return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_atpx_call - call an ATPX method
|
||||
*
|
||||
|
@ -213,6 +218,10 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
|
|||
atpx->is_hybrid = true;
|
||||
}
|
||||
|
||||
atpx->dgpu_req_power_for_displays = false;
|
||||
if (valid_bits & ATPX_DGPU_REQ_POWER_FOR_DISPLAYS)
|
||||
atpx->dgpu_req_power_for_displays = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -711,6 +711,47 @@ static int amdgpu_cgs_rel_firmware(struct cgs_device *cgs_device, enum cgs_ucode
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
|
||||
enum cgs_ucode_id type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint16_t fw_version;
|
||||
|
||||
switch (type) {
|
||||
case CGS_UCODE_ID_SDMA0:
|
||||
fw_version = adev->sdma.instance[0].fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_SDMA1:
|
||||
fw_version = adev->sdma.instance[1].fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_CE:
|
||||
fw_version = adev->gfx.ce_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_PFP:
|
||||
fw_version = adev->gfx.pfp_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_ME:
|
||||
fw_version = adev->gfx.me_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_MEC:
|
||||
fw_version = adev->gfx.mec_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_MEC_JT1:
|
||||
fw_version = adev->gfx.mec_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_MEC_JT2:
|
||||
fw_version = adev->gfx.mec_fw_version;
|
||||
break;
|
||||
case CGS_UCODE_ID_RLC_G:
|
||||
fw_version = adev->gfx.rlc_fw_version;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("firmware type %d do not have version\n", type);
|
||||
fw_version = 0;
|
||||
}
|
||||
return fw_version;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
|
||||
enum cgs_ucode_id type,
|
||||
struct cgs_firmware_info *info)
|
||||
|
@ -741,6 +782,7 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
|
|||
info->mc_addr = gpu_addr;
|
||||
info->image_size = data_size;
|
||||
info->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
info->fw_version = amdgpu_get_firmware_version(cgs_device, type);
|
||||
info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version);
|
||||
} else {
|
||||
char fw_name[30] = {0};
|
||||
|
|
|
@ -1545,7 +1545,8 @@ static int amdgpu_connector_virtual_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
int amdgpu_connector_virtual_dpms(struct drm_connector *connector, int mode)
|
||||
static int
|
||||
amdgpu_connector_virtual_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1557,7 +1558,8 @@ amdgpu_connector_virtual_detect(struct drm_connector *connector, bool force)
|
|||
return connector_status_connected;
|
||||
}
|
||||
|
||||
int amdgpu_connector_virtual_set_property(struct drm_connector *connector,
|
||||
static int
|
||||
amdgpu_connector_virtual_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "vi.h"
|
||||
#include "bif/bif_4_1_d.h"
|
||||
#include <linux/pci.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
|
||||
static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev);
|
||||
|
@ -110,7 +111,7 @@ void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
|
|||
bool always_indirect)
|
||||
{
|
||||
trace_amdgpu_mm_wreg(adev->pdev->device, reg, v);
|
||||
|
||||
|
||||
if ((reg * 4) < adev->rmmio_size && !always_indirect)
|
||||
writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
|
||||
else {
|
||||
|
@ -651,6 +652,46 @@ bool amdgpu_card_posted(struct amdgpu_device *adev)
|
|||
|
||||
}
|
||||
|
||||
static bool amdgpu_vpost_needed(struct amdgpu_device *adev)
|
||||
{
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return false;
|
||||
|
||||
if (amdgpu_passthrough(adev)) {
|
||||
/* for FIJI: In whole GPU pass-through virtualization case
|
||||
* old smc fw won't clear some registers (e.g. MEM_SIZE, BIOS_SCRATCH)
|
||||
* so amdgpu_card_posted return false and driver will incorrectly skip vPost.
|
||||
* but if we force vPost do in pass-through case, the driver reload will hang.
|
||||
* whether doing vPost depends on amdgpu_card_posted if smc version is above
|
||||
* 00160e00 for FIJI.
|
||||
*/
|
||||
if (adev->asic_type == CHIP_FIJI) {
|
||||
int err;
|
||||
uint32_t fw_ver;
|
||||
err = request_firmware(&adev->pm.fw, "amdgpu/fiji_smc.bin", adev->dev);
|
||||
/* force vPost if error occured */
|
||||
if (err)
|
||||
return true;
|
||||
|
||||
fw_ver = *((uint32_t *)adev->pm.fw->data + 69);
|
||||
if (fw_ver >= 0x00160e00)
|
||||
return !amdgpu_card_posted(adev);
|
||||
}
|
||||
} else {
|
||||
/* in bare-metal case, amdgpu_card_posted return false
|
||||
* after system reboot/boot, and return true if driver
|
||||
* reloaded.
|
||||
* we shouldn't do vPost after driver reload otherwise GPU
|
||||
* could hang.
|
||||
*/
|
||||
if (amdgpu_card_posted(adev))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we assume vPost is neede for all other cases */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dummy_page_init - init dummy page used by the driver
|
||||
*
|
||||
|
@ -1485,13 +1526,10 @@ static int amdgpu_resume(struct amdgpu_device *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool amdgpu_device_is_virtual(void)
|
||||
static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
return boot_cpu_has(X86_FEATURE_HYPERVISOR);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
if (amdgpu_atombios_has_gpu_virtualization_table(adev))
|
||||
adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1648,25 +1686,24 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
/* See if the asic supports SR-IOV */
|
||||
adev->virtualization.supports_sr_iov =
|
||||
amdgpu_atombios_has_gpu_virtualization_table(adev);
|
||||
|
||||
/* Check if we are executing in a virtualized environment */
|
||||
adev->virtualization.is_virtual = amdgpu_device_is_virtual();
|
||||
adev->virtualization.caps = amdgpu_asic_get_virtual_caps(adev);
|
||||
/* detect if we are with an SRIOV vbios */
|
||||
amdgpu_device_detect_sriov_bios(adev);
|
||||
|
||||
/* Post card if necessary */
|
||||
if (!amdgpu_card_posted(adev) ||
|
||||
(adev->virtualization.is_virtual &&
|
||||
!(adev->virtualization.caps & AMDGPU_VIRT_CAPS_SRIOV_EN))) {
|
||||
if (amdgpu_vpost_needed(adev)) {
|
||||
if (!adev->bios) {
|
||||
dev_err(adev->dev, "Card not posted and no BIOS - ignoring\n");
|
||||
dev_err(adev->dev, "no vBIOS found\n");
|
||||
r = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
DRM_INFO("GPU not posted. posting now...\n");
|
||||
amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
DRM_INFO("GPU posting now...\n");
|
||||
r = amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "gpu post error!\n");
|
||||
goto failed;
|
||||
}
|
||||
} else {
|
||||
DRM_INFO("GPU post is not needed\n");
|
||||
}
|
||||
|
||||
/* Initialize clocks */
|
||||
|
@ -1842,8 +1879,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
|
|||
|
||||
adev = dev->dev_private;
|
||||
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
|
||||
dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
@ -1928,8 +1964,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
|
|||
struct drm_crtc *crtc;
|
||||
int r;
|
||||
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
|
||||
dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
if (fbcon)
|
||||
|
@ -2043,7 +2078,7 @@ static bool amdgpu_check_soft_reset(struct amdgpu_device *adev)
|
|||
return asic_hang;
|
||||
}
|
||||
|
||||
int amdgpu_pre_soft_reset(struct amdgpu_device *adev)
|
||||
static int amdgpu_pre_soft_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r = 0;
|
||||
|
||||
|
@ -2714,7 +2749,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
|
|||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
config = kmalloc(256 * sizeof(*config), GFP_KERNEL);
|
||||
config = kmalloc_array(256, sizeof(*config), GFP_KERNEL);
|
||||
if (!config)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2773,6 +2808,29 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
|
|||
return result;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
|
||||
size_t size, loff_t *pos)
|
||||
{
|
||||
struct amdgpu_device *adev = f->f_inode->i_private;
|
||||
int idx, r;
|
||||
int32_t value;
|
||||
|
||||
if (size != 4 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
/* convert offset to sensor number */
|
||||
idx = *pos >> 2;
|
||||
|
||||
if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor)
|
||||
r = adev->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, idx, &value);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (!r)
|
||||
r = put_user(value, (int32_t *)buf);
|
||||
|
||||
return !r ? 4 : r;
|
||||
}
|
||||
|
||||
static const struct file_operations amdgpu_debugfs_regs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -2805,12 +2863,19 @@ static const struct file_operations amdgpu_debugfs_gca_config_fops = {
|
|||
.llseek = default_llseek
|
||||
};
|
||||
|
||||
static const struct file_operations amdgpu_debugfs_sensors_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = amdgpu_debugfs_sensor_read,
|
||||
.llseek = default_llseek
|
||||
};
|
||||
|
||||
static const struct file_operations *debugfs_regs[] = {
|
||||
&amdgpu_debugfs_regs_fops,
|
||||
&amdgpu_debugfs_regs_didt_fops,
|
||||
&amdgpu_debugfs_regs_pcie_fops,
|
||||
&amdgpu_debugfs_regs_smc_fops,
|
||||
&amdgpu_debugfs_gca_config_fops,
|
||||
&amdgpu_debugfs_sensors_fops,
|
||||
};
|
||||
|
||||
static const char *debugfs_regs_names[] = {
|
||||
|
@ -2819,6 +2884,7 @@ static const char *debugfs_regs_names[] = {
|
|||
"amdgpu_regs_pcie",
|
||||
"amdgpu_regs_smc",
|
||||
"amdgpu_gca_config",
|
||||
"amdgpu_sensors",
|
||||
};
|
||||
|
||||
static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
|
||||
|
|
|
@ -56,9 +56,10 @@
|
|||
* - 3.4.0 - Add AMDGPU_INFO_NUM_EVICTIONS.
|
||||
* - 3.5.0 - Add support for new UVD_NO_OP register.
|
||||
* - 3.6.0 - kmd involves use CONTEXT_CONTROL in ring buffer.
|
||||
* - 3.7.0 - Add support for VCE clock list packet
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 6
|
||||
#define KMS_DRIVER_MINOR 7
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
int amdgpu_vram_limit = 0;
|
||||
|
@ -485,7 +486,7 @@ amdgpu_pci_shutdown(struct pci_dev *pdev)
|
|||
/* if we are running in a VM, make sure the device
|
||||
* torn down properly on reboot/shutdown
|
||||
*/
|
||||
if (adev->virtualization.is_virtual)
|
||||
if (amdgpu_passthrough(adev))
|
||||
amdgpu_pci_remove(pdev);
|
||||
}
|
||||
|
||||
|
|
|
@ -1322,6 +1322,64 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
|
|||
*/
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *adev)
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
/* sanity check PP is enabled */
|
||||
if (!(adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->read_sensor))
|
||||
return -EINVAL;
|
||||
|
||||
/* GPU Clocks */
|
||||
seq_printf(m, "GFX Clocks and Power:\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, &value))
|
||||
seq_printf(m, "\t%u MHz (MCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, &value))
|
||||
seq_printf(m, "\t%u MHz (SCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, &value))
|
||||
seq_printf(m, "\t%u mV (VDDGFX)\n", value);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, &value))
|
||||
seq_printf(m, "\t%u mV (VDDNB)\n", value);
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* GPU Temp */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, &value))
|
||||
seq_printf(m, "GPU Temperature: %u C\n", value/1000);
|
||||
|
||||
/* GPU Load */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value))
|
||||
seq_printf(m, "GPU Load: %u %%\n", value);
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* UVD clocks */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, &value)) {
|
||||
if (!value) {
|
||||
seq_printf(m, "UVD: Disabled\n");
|
||||
} else {
|
||||
seq_printf(m, "UVD: Enabled\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, &value))
|
||||
seq_printf(m, "\t%u MHz (DCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, &value))
|
||||
seq_printf(m, "\t%u MHz (VCLK)\n", value/100);
|
||||
}
|
||||
}
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* VCE clocks */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, &value)) {
|
||||
if (!value) {
|
||||
seq_printf(m, "VCE: Disabled\n");
|
||||
} else {
|
||||
seq_printf(m, "VCE: Enabled\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, &value))
|
||||
seq_printf(m, "\t%u MHz (ECCLK)\n", value/100);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
|
@ -1337,11 +1395,11 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
|
|||
(ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
|
||||
seq_printf(m, "PX asic powered off\n");
|
||||
} else if (adev->pp_enabled) {
|
||||
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
||||
return amdgpu_debugfs_pm_info_pp(m, adev);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->pm.funcs->debugfs_print_current_performance_level)
|
||||
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
||||
adev->pm.funcs->debugfs_print_current_performance_level(adev, m);
|
||||
else
|
||||
seq_printf(m, "Debugfs support not implemented for this asic\n");
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
|
|
@ -80,15 +80,6 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev)
|
|||
amd_pp->ip_funcs = &kv_dpm_ip_funcs;
|
||||
break;
|
||||
#endif
|
||||
case CHIP_TOPAZ:
|
||||
amd_pp->ip_funcs = &iceland_dpm_ip_funcs;
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
amd_pp->ip_funcs = &tonga_dpm_ip_funcs;
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
amd_pp->ip_funcs = &fiji_dpm_ip_funcs;
|
||||
break;
|
||||
case CHIP_CARRIZO:
|
||||
case CHIP_STONEY:
|
||||
amd_pp->ip_funcs = &cz_dpm_ip_funcs;
|
||||
|
@ -110,11 +101,11 @@ static int amdgpu_pp_early_init(void *handle)
|
|||
switch (adev->asic_type) {
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS10:
|
||||
adev->pp_enabled = true;
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
case CHIP_FIJI:
|
||||
case CHIP_TOPAZ:
|
||||
adev->pp_enabled = true;
|
||||
break;
|
||||
case CHIP_CARRIZO:
|
||||
case CHIP_STONEY:
|
||||
adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true;
|
||||
|
|
|
@ -691,6 +691,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
|
|||
case 0x04000008: /* rdo */
|
||||
case 0x04000009: /* vui */
|
||||
case 0x05000002: /* auxiliary buffer */
|
||||
case 0x05000009: /* clock table */
|
||||
break;
|
||||
|
||||
case 0x03000001: /* encode */
|
||||
|
|
|
@ -19,22 +19,39 @@
|
|||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Monk.liu@amd.com
|
||||
*/
|
||||
#ifndef AMDGPU_VIRT_H
|
||||
#define AMDGPU_VIRT_H
|
||||
|
||||
#ifndef _POLARIS10_CLOCK_POWER_GATING_H_
|
||||
#define _POLARIS10_CLOCK_POWER_GATING_H_
|
||||
#define AMDGPU_SRIOV_CAPS_SRIOV_VBIOS (1 << 0) /* vBIOS is sr-iov ready */
|
||||
#define AMDGPU_SRIOV_CAPS_ENABLE_IOV (1 << 1) /* sr-iov is enabled on this GPU */
|
||||
#define AMDGPU_SRIOV_CAPS_IS_VF (1 << 2) /* this GPU is a virtual function */
|
||||
#define AMDGPU_PASSTHROUGH_MODE (1 << 3) /* thw whole GPU is pass through for VM */
|
||||
/* GPU virtualization */
|
||||
struct amdgpu_virtualization {
|
||||
uint32_t virtual_caps;
|
||||
};
|
||||
|
||||
#include "polaris10_hwmgr.h"
|
||||
#include "pp_asicblocks.h"
|
||||
#define amdgpu_sriov_enabled(adev) \
|
||||
((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
|
||||
|
||||
int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
const uint32_t *msg_id);
|
||||
int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable);
|
||||
#define amdgpu_sriov_vf(adev) \
|
||||
((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_IS_VF)
|
||||
|
||||
#endif /* _POLARIS10_CLOCK_POWER_GATING_H_ */
|
||||
#define amdgpu_sriov_bios(adev) \
|
||||
((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS)
|
||||
|
||||
#define amdgpu_passthrough(adev) \
|
||||
((adev)->virtualization.virtual_caps & AMDGPU_PASSTHROUGH_MODE)
|
||||
|
||||
static inline bool is_virtual_machine(void)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
return boot_cpu_has(X86_FEATURE_HYPERVISOR);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -963,12 +963,6 @@ static bool cik_read_bios_from_rom(struct amdgpu_device *adev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static u32 cik_get_virtual_caps(struct amdgpu_device *adev)
|
||||
{
|
||||
/* CIK does not support SR-IOV */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
|
||||
{mmGRBM_STATUS, false},
|
||||
{mmGB_ADDR_CONFIG, false},
|
||||
|
@ -1641,6 +1635,12 @@ static uint32_t cik_get_rev_id(struct amdgpu_device *adev)
|
|||
>> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
|
||||
}
|
||||
|
||||
static void cik_detect_hw_virtualization(struct amdgpu_device *adev)
|
||||
{
|
||||
if (is_virtual_machine()) /* passthrough mode */
|
||||
adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
|
||||
}
|
||||
|
||||
static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
|
||||
{
|
||||
/* ORDER MATTERS! */
|
||||
|
@ -2384,13 +2384,13 @@ static const struct amdgpu_asic_funcs cik_asic_funcs =
|
|||
{
|
||||
.read_disabled_bios = &cik_read_disabled_bios,
|
||||
.read_bios_from_rom = &cik_read_bios_from_rom,
|
||||
.detect_hw_virtualization = cik_detect_hw_virtualization,
|
||||
.read_register = &cik_read_register,
|
||||
.reset = &cik_asic_reset,
|
||||
.set_vga_state = &cik_vga_set_state,
|
||||
.get_xclk = &cik_get_xclk,
|
||||
.set_uvd_clocks = &cik_set_uvd_clocks,
|
||||
.set_vce_clocks = &cik_set_vce_clocks,
|
||||
.get_virtual_caps = &cik_get_virtual_caps,
|
||||
};
|
||||
|
||||
static int cik_common_early_init(void *handle)
|
||||
|
|
|
@ -562,4 +562,40 @@ enum {
|
|||
MTYPE_NONCACHED = 3
|
||||
};
|
||||
|
||||
/* mmPA_SC_RASTER_CONFIG mask */
|
||||
#define RB_MAP_PKR0(x) ((x) << 0)
|
||||
#define RB_MAP_PKR0_MASK (0x3 << 0)
|
||||
#define RB_MAP_PKR1(x) ((x) << 2)
|
||||
#define RB_MAP_PKR1_MASK (0x3 << 2)
|
||||
#define RB_XSEL2(x) ((x) << 4)
|
||||
#define RB_XSEL2_MASK (0x3 << 4)
|
||||
#define RB_XSEL (1 << 6)
|
||||
#define RB_YSEL (1 << 7)
|
||||
#define PKR_MAP(x) ((x) << 8)
|
||||
#define PKR_MAP_MASK (0x3 << 8)
|
||||
#define PKR_XSEL(x) ((x) << 10)
|
||||
#define PKR_XSEL_MASK (0x3 << 10)
|
||||
#define PKR_YSEL(x) ((x) << 12)
|
||||
#define PKR_YSEL_MASK (0x3 << 12)
|
||||
#define SC_MAP(x) ((x) << 16)
|
||||
#define SC_MAP_MASK (0x3 << 16)
|
||||
#define SC_XSEL(x) ((x) << 18)
|
||||
#define SC_XSEL_MASK (0x3 << 18)
|
||||
#define SC_YSEL(x) ((x) << 20)
|
||||
#define SC_YSEL_MASK (0x3 << 20)
|
||||
#define SE_MAP(x) ((x) << 24)
|
||||
#define SE_MAP_MASK (0x3 << 24)
|
||||
#define SE_XSEL(x) ((x) << 26)
|
||||
#define SE_XSEL_MASK (0x3 << 26)
|
||||
#define SE_YSEL(x) ((x) << 28)
|
||||
#define SE_YSEL_MASK (0x3 << 28)
|
||||
|
||||
/* mmPA_SC_RASTER_CONFIG_1 mask */
|
||||
#define SE_PAIR_MAP(x) ((x) << 0)
|
||||
#define SE_PAIR_MAP_MASK (0x3 << 0)
|
||||
#define SE_PAIR_XSEL(x) ((x) << 2)
|
||||
#define SE_PAIR_XSEL_MASK (0x3 << 2)
|
||||
#define SE_PAIR_YSEL(x) ((x) << 4)
|
||||
#define SE_PAIR_YSEL_MASK (0x3 << 4)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -101,13 +101,6 @@ int cz_send_msg_to_smc(struct amdgpu_device *adev, u16 msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cz_send_msg_to_smc_with_parameter_async(struct amdgpu_device *adev,
|
||||
u16 msg, u32 parameter)
|
||||
{
|
||||
WREG32(mmSMU_MP1_SRBM2P_ARG_0, parameter);
|
||||
return cz_send_msg_to_smc_async(adev, msg);
|
||||
}
|
||||
|
||||
int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
u16 msg, u32 parameter)
|
||||
{
|
||||
|
|
|
@ -221,7 +221,7 @@ static bool dce_v10_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
|
|||
*/
|
||||
static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
||||
{
|
||||
unsigned i = 0;
|
||||
unsigned i = 100;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc)
|
||||
return;
|
||||
|
@ -233,14 +233,16 @@ static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
|||
* wait for another frame.
|
||||
*/
|
||||
while (dce_v10_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v10_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!dce_v10_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v10_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ static bool dce_v6_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
|
|||
*/
|
||||
static void dce_v6_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
||||
{
|
||||
unsigned i = 0;
|
||||
unsigned i = 100;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc)
|
||||
return;
|
||||
|
@ -158,14 +158,16 @@ static void dce_v6_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
|||
* wait for another frame.
|
||||
*/
|
||||
while (dce_v6_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v6_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!dce_v6_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v6_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
|
@ -185,7 +187,7 @@ static void dce_v6_0_pageflip_interrupt_init(struct amdgpu_device *adev)
|
|||
unsigned i;
|
||||
|
||||
/* Enable pflip interrupts */
|
||||
for (i = 0; i <= adev->mode_info.num_crtc; i++)
|
||||
for (i = 0; i < adev->mode_info.num_crtc; i++)
|
||||
amdgpu_irq_get(adev, &adev->pageflip_irq, i);
|
||||
}
|
||||
|
||||
|
@ -194,7 +196,7 @@ static void dce_v6_0_pageflip_interrupt_fini(struct amdgpu_device *adev)
|
|||
unsigned i;
|
||||
|
||||
/* Disable pflip interrupts */
|
||||
for (i = 0; i <= adev->mode_info.num_crtc; i++)
|
||||
for (i = 0; i < adev->mode_info.num_crtc; i++)
|
||||
amdgpu_irq_put(adev, &adev->pageflip_irq, i);
|
||||
}
|
||||
|
||||
|
@ -1420,21 +1422,29 @@ static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
|
|||
enable ? "En" : "Dis", dig->afmt->offset, amdgpu_encoder->encoder_id);
|
||||
}
|
||||
|
||||
static void dce_v6_0_afmt_init(struct amdgpu_device *adev)
|
||||
static int dce_v6_0_afmt_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < adev->mode_info.num_dig; i++)
|
||||
adev->mode_info.afmt[i] = NULL;
|
||||
|
||||
/* DCE8 has audio blocks tied to DIG encoders */
|
||||
/* DCE6 has audio blocks tied to DIG encoders */
|
||||
for (i = 0; i < adev->mode_info.num_dig; i++) {
|
||||
adev->mode_info.afmt[i] = kzalloc(sizeof(struct amdgpu_afmt), GFP_KERNEL);
|
||||
if (adev->mode_info.afmt[i]) {
|
||||
adev->mode_info.afmt[i]->offset = dig_offsets[i];
|
||||
adev->mode_info.afmt[i]->id = i;
|
||||
} else {
|
||||
for (j = 0; j < i; j++) {
|
||||
kfree(adev->mode_info.afmt[j]);
|
||||
adev->mode_info.afmt[j] = NULL;
|
||||
}
|
||||
DRM_ERROR("Out of memory allocating afmt table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dce_v6_0_afmt_fini(struct amdgpu_device *adev)
|
||||
|
@ -2397,7 +2407,9 @@ static int dce_v6_0_sw_init(void *handle)
|
|||
return -EINVAL;
|
||||
|
||||
/* setup afmt */
|
||||
dce_v6_0_afmt_init(adev);
|
||||
r = dce_v6_0_afmt_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dce_v6_0_audio_init(adev);
|
||||
if (r)
|
||||
|
@ -2782,7 +2794,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev,
|
|||
uint32_t disp_int, mask, int_control, tmp;
|
||||
unsigned hpd;
|
||||
|
||||
if (entry->src_data > 6) {
|
||||
if (entry->src_data >= adev->mode_info.num_hpd) {
|
||||
DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ static bool dce_v8_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
|
|||
*/
|
||||
static void dce_v8_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
||||
{
|
||||
unsigned i = 0;
|
||||
unsigned i = 100;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc)
|
||||
return;
|
||||
|
@ -182,14 +182,16 @@ static void dce_v8_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
|||
* wait for another frame.
|
||||
*/
|
||||
while (dce_v8_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v8_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!dce_v8_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v8_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ static bool dce_virtual_is_display_hung(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
void dce_virtual_stop_mc_access(struct amdgpu_device *adev,
|
||||
static void dce_virtual_stop_mc_access(struct amdgpu_device *adev,
|
||||
struct amdgpu_mode_mc_save *save)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
|
@ -127,13 +127,13 @@ void dce_virtual_stop_mc_access(struct amdgpu_device *adev,
|
|||
|
||||
return;
|
||||
}
|
||||
void dce_virtual_resume_mc_access(struct amdgpu_device *adev,
|
||||
static void dce_virtual_resume_mc_access(struct amdgpu_device *adev,
|
||||
struct amdgpu_mode_mc_save *save)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void dce_virtual_set_vga_render_state(struct amdgpu_device *adev,
|
||||
static void dce_virtual_set_vga_render_state(struct amdgpu_device *adev,
|
||||
bool render)
|
||||
{
|
||||
return;
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_smum.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
|
||||
|
||||
static void fiji_dpm_set_funcs(struct amdgpu_device *adev);
|
||||
|
||||
static int fiji_dpm_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_set_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_init_microcode(struct amdgpu_device *adev)
|
||||
{
|
||||
char fw_name[30] = "amdgpu/fiji_smc.bin";
|
||||
int err;
|
||||
|
||||
err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = amdgpu_ucode_validate(adev->pm.fw);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fiji_dpm_sw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
ret = fiji_dpm_init_microcode(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_sw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_hw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
ret = fiji_smu_init(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = fiji_smu_start(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
adev->firmware.smu_load = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int fiji_dpm_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
fiji_smu_fini(adev);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_suspend(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_resume(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_hw_init(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs fiji_dpm_ip_funcs = {
|
||||
.name = "fiji_dpm",
|
||||
.early_init = fiji_dpm_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = fiji_dpm_sw_init,
|
||||
.sw_fini = fiji_dpm_sw_fini,
|
||||
.hw_init = fiji_dpm_hw_init,
|
||||
.hw_fini = fiji_dpm_hw_fini,
|
||||
.suspend = fiji_dpm_suspend,
|
||||
.resume = fiji_dpm_resume,
|
||||
.is_idle = NULL,
|
||||
.wait_for_idle = NULL,
|
||||
.soft_reset = NULL,
|
||||
.set_clockgating_state = fiji_dpm_set_clockgating_state,
|
||||
.set_powergating_state = fiji_dpm_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_dpm_funcs fiji_dpm_funcs = {
|
||||
.get_temperature = NULL,
|
||||
.pre_set_power_state = NULL,
|
||||
.set_power_state = NULL,
|
||||
.post_set_power_state = NULL,
|
||||
.display_configuration_changed = NULL,
|
||||
.get_sclk = NULL,
|
||||
.get_mclk = NULL,
|
||||
.print_power_state = NULL,
|
||||
.debugfs_print_current_performance_level = NULL,
|
||||
.force_performance_level = NULL,
|
||||
.vblank_too_short = NULL,
|
||||
.powergate_uvd = NULL,
|
||||
};
|
||||
|
||||
static void fiji_dpm_set_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
if (NULL == adev->pm.funcs)
|
||||
adev->pm.funcs = &fiji_dpm_funcs;
|
||||
}
|
|
@ -1,863 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "fiji_smum.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
|
||||
#define FIJI_SMC_SIZE 0x20000
|
||||
|
||||
static int fiji_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (smc_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_address + 3) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
WREG32(mmSMC_IND_INDEX_0, smc_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t data, orig_data;
|
||||
int result = 0;
|
||||
uint32_t extra_shift;
|
||||
unsigned long flags;
|
||||
|
||||
if (smc_start_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_start_address + byte_count) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first */
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
/* Now write odd bytes left, do a read modify write cycle */
|
||||
data = 0;
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
orig_data = RREG32(mmSMC_IND_DATA_0);
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
data = (data << 8) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
data |= (orig_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_program_jump_on_start(struct amdgpu_device *adev)
|
||||
{
|
||||
static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
|
||||
fiji_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool fiji_is_smc_ram_running(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
|
||||
|
||||
return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
static int wait_smu_response(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32(mmSMC_RESP_0);
|
||||
if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, 0x20000);
|
||||
WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg,
|
||||
uint32_t parameter)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return fiji_send_msg_to_smc(adev, msg);
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_with_parameter_without_waiting(
|
||||
struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg, uint32_t parameter)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return fiji_send_msg_to_smc_without_waiting(adev, msg);
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int fiji_wait_for_smc_inactive(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fiji_smu_upload_firmware_image(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
uint32_t ucode_size;
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
uint32_t val;
|
||||
uint32_t byte_count;
|
||||
uint32_t *data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!adev->pm.fw)
|
||||
return -EINVAL;
|
||||
|
||||
/* Skip SMC ucode loading on SR-IOV capable boards.
|
||||
* vbios does this for us in asic_init in that case.
|
||||
*/
|
||||
if (adev->virtualization.supports_sr_iov)
|
||||
return 0;
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
|
||||
amdgpu_ucode_print_smc_hdr(&hdr->header);
|
||||
|
||||
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
|
||||
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
|
||||
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
|
||||
src = (const uint8_t *)
|
||||
(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
|
||||
if (ucode_size & 3) {
|
||||
DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ucode_size > FIJI_SMC_SIZE) {
|
||||
DRM_ERROR("SMC address is beyond the SMC RAM area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
byte_count = ucode_size;
|
||||
data = (uint32_t *)src;
|
||||
for (; byte_count >= 4; data++, byte_count -= 4)
|
||||
WREG32(mmSMC_IND_DATA_0, data[0]);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int fiji_read_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t *value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = fiji_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
*value = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_write_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = fiji_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
WREG32(mmSMC_IND_DATA_0, value);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_smu_stop_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum AMDGPU_UCODE_ID fiji_convert_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
return AMDGPU_UCODE_ID_SDMA0;
|
||||
case UCODE_ID_SDMA1:
|
||||
return AMDGPU_UCODE_ID_SDMA1;
|
||||
case UCODE_ID_CP_CE:
|
||||
return AMDGPU_UCODE_ID_CP_CE;
|
||||
case UCODE_ID_CP_PFP:
|
||||
return AMDGPU_UCODE_ID_CP_PFP;
|
||||
case UCODE_ID_CP_ME:
|
||||
return AMDGPU_UCODE_ID_CP_ME;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
return AMDGPU_UCODE_ID_CP_MEC1;
|
||||
case UCODE_ID_RLC_G:
|
||||
return AMDGPU_UCODE_ID_RLC_G;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return AMDGPU_UCODE_ID_MAXIMUM;
|
||||
}
|
||||
}
|
||||
|
||||
static int fiji_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
enum AMDGPU_UCODE_ID id = fiji_convert_fw_type(fw_type);
|
||||
struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
|
||||
const struct gfx_firmware_header_v1_0 *header = NULL;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t data_size;
|
||||
|
||||
if (ucode->fw == NULL)
|
||||
return -EINVAL;
|
||||
gpu_addr = ucode->mc_addr;
|
||||
header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
data_size = le32_to_cpu(header->header.ucode_size_bytes);
|
||||
|
||||
if ((fw_type == UCODE_ID_CP_MEC_JT1) ||
|
||||
(fw_type == UCODE_ID_CP_MEC_JT2)) {
|
||||
gpu_addr += le32_to_cpu(header->jt_offset) << 2;
|
||||
data_size = le32_to_cpu(header->jt_size) << 2;
|
||||
}
|
||||
|
||||
entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = upper_32_bits(gpu_addr);
|
||||
entry->image_addr_low = lower_32_bits(gpu_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = data_size;
|
||||
entry->num_register_entries = 0;
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_request_load_fw(struct amdgpu_device *adev)
|
||||
{
|
||||
struct fiji_smu_private_data *private = (struct fiji_smu_private_data *)adev->smu.priv;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
uint32_t fw_to_load;
|
||||
|
||||
WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0);
|
||||
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high);
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low);
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)private->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
if (!adev->firmware.smu_load)
|
||||
return 0;
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for RLC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for CE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for PFP\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for ME\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK |
|
||||
UCODE_ID_SDMA0_MASK |
|
||||
UCODE_ID_SDMA1_MASK |
|
||||
UCODE_ID_CP_CE_MASK |
|
||||
UCODE_ID_CP_ME_MASK |
|
||||
UCODE_ID_CP_PFP_MASK |
|
||||
UCODE_ID_CP_MEC_MASK;
|
||||
|
||||
if (fiji_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
|
||||
DRM_ERROR("Fail to request SMU load ucode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t fiji_smu_get_mask_for_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case AMDGPU_UCODE_ID_SDMA0:
|
||||
return UCODE_ID_SDMA0_MASK;
|
||||
case AMDGPU_UCODE_ID_SDMA1:
|
||||
return UCODE_ID_SDMA1_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_CE:
|
||||
return UCODE_ID_CP_CE_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_PFP:
|
||||
return UCODE_ID_CP_PFP_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_ME:
|
||||
return UCODE_ID_CP_ME_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC1:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC2:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_RLC_G:
|
||||
return UCODE_ID_RLC_G_MASK;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int fiji_smu_check_fw_load_finish(struct amdgpu_device *adev,
|
||||
uint32_t fw_type)
|
||||
{
|
||||
uint32_t fw_mask = fiji_smu_get_mask_for_fw_type(fw_type);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_start_in_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = fiji_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Clear status */
|
||||
WREG32_SMC(ixSMU_STATUS, 0);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Set SMU Auto Start */
|
||||
val = RREG32_SMC(ixSMU_INPUT_DATA);
|
||||
val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1);
|
||||
WREG32_SMC(ixSMU_INPUT_DATA, val);
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Interrupt is not enabled by firmware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Call Test SMU message with 0x20000 offset
|
||||
* to trigger SMU start
|
||||
*/
|
||||
fiji_send_msg_to_smc_offset(adev);
|
||||
DRM_INFO("[FM]try triger smu start\n");
|
||||
/* Wait for done bit to be set */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMU start\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check pass/failed indicator */
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) {
|
||||
DRM_ERROR("SMU Firmware start failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
DRM_INFO("[FM]smu started\n");
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMU firmware initialization failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
DRM_INFO("[FM]smu initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_start_in_non_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, result;
|
||||
uint32_t val;
|
||||
|
||||
/* wait for smc boot up */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done);
|
||||
if (val)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMC boot sequence is not completed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = fiji_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Set smc instruct start point at 0x0 */
|
||||
fiji_program_jump_on_start(adev);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMC firmware initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_smu_start(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
|
||||
if (!fiji_is_smc_ram_running(adev)) {
|
||||
val = RREG32_SMC(ixSMU_FIRMWARE);
|
||||
if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) {
|
||||
DRM_INFO("[FM]start smu in nonprotection mode\n");
|
||||
result = fiji_smu_start_in_non_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
DRM_INFO("[FM]start smu in protection mode\n");
|
||||
result = fiji_smu_start_in_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return fiji_smu_request_load_fw(adev);
|
||||
}
|
||||
|
||||
static const struct amdgpu_smumgr_funcs fiji_smumgr_funcs = {
|
||||
.check_fw_load_finish = fiji_smu_check_fw_load_finish,
|
||||
.request_smu_load_fw = NULL,
|
||||
.request_smu_specific_fw = NULL,
|
||||
};
|
||||
|
||||
int fiji_smu_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct fiji_smu_private_data *private;
|
||||
uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
uint32_t smu_internal_buffer_size = 200*4096;
|
||||
struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
|
||||
struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
|
||||
uint64_t mc_addr;
|
||||
void *toc_buf_ptr;
|
||||
void *smu_buf_ptr;
|
||||
int ret;
|
||||
|
||||
private = kzalloc(sizeof(struct fiji_smu_private_data), GFP_KERNEL);
|
||||
if (NULL == private)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate firmware buffers */
|
||||
if (adev->firmware.smu_load)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
adev->smu.priv = private;
|
||||
adev->smu.fw_flags = 0;
|
||||
|
||||
/* Allocate FW image data structure and header buffer */
|
||||
ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
|
||||
NULL, NULL, toc_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for TOC buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate buffer for SMU internal buffer */
|
||||
ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
|
||||
NULL, NULL, smu_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Retrieve GPU address for header buffer and internal buffer */
|
||||
ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
private->header_addr_low = lower_32_bits(mc_addr);
|
||||
private->header_addr_high = upper_32_bits(mc_addr);
|
||||
private->header = toc_buf_ptr;
|
||||
|
||||
ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
private->smu_buffer_addr_low = lower_32_bits(mc_addr);
|
||||
private->smu_buffer_addr_high = upper_32_bits(mc_addr);
|
||||
|
||||
adev->smu.smumgr_funcs = &fiji_smumgr_funcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_smu_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
kfree(adev->smu.priv);
|
||||
adev->smu.priv = NULL;
|
||||
if (adev->firmware.fw_buf)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -931,6 +931,123 @@ static u32 gfx_v6_0_get_rb_disabled(struct amdgpu_device *adev,
|
|||
return data & mask;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_raster_config(struct amdgpu_device *adev, u32 *rconf)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_TAHITI:
|
||||
case CHIP_PITCAIRN:
|
||||
*rconf |= RB_XSEL2(2) | RB_XSEL | PKR_MAP(2) | PKR_YSEL(1) |
|
||||
SE_MAP(2) | SE_XSEL(2) | SE_YSEL(2);
|
||||
break;
|
||||
case CHIP_VERDE:
|
||||
*rconf |= RB_XSEL | PKR_MAP(2) | PKR_YSEL(1);
|
||||
break;
|
||||
case CHIP_OLAND:
|
||||
*rconf |= RB_YSEL;
|
||||
break;
|
||||
case CHIP_HAINAN:
|
||||
*rconf |= 0x0;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_v6_0_write_harvested_raster_configs(struct amdgpu_device *adev,
|
||||
u32 raster_config, unsigned rb_mask,
|
||||
unsigned num_rb)
|
||||
{
|
||||
unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
|
||||
unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
|
||||
unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
|
||||
unsigned rb_per_se = num_rb / num_se;
|
||||
unsigned se_mask[4];
|
||||
unsigned se;
|
||||
|
||||
se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
|
||||
se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
|
||||
se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
|
||||
se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
|
||||
|
||||
WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
|
||||
WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
|
||||
WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
|
||||
|
||||
for (se = 0; se < num_se; se++) {
|
||||
unsigned raster_config_se = raster_config;
|
||||
unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
|
||||
unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
|
||||
int idx = (se / 2) * 2;
|
||||
|
||||
if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
|
||||
raster_config_se &= ~SE_MAP_MASK;
|
||||
|
||||
if (!se_mask[idx]) {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
pkr0_mask &= rb_mask;
|
||||
pkr1_mask &= rb_mask;
|
||||
if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
|
||||
raster_config_se &= ~PKR_MAP_MASK;
|
||||
|
||||
if (!pkr0_mask) {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se >= 2) {
|
||||
unsigned rb0_mask = 1 << (se * rb_per_se);
|
||||
unsigned rb1_mask = rb0_mask << 1;
|
||||
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR0_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se > 2) {
|
||||
rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
|
||||
rb1_mask = rb0_mask << 1;
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR1_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on SI */
|
||||
gfx_v6_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
|
||||
WREG32(PA_SC_RASTER_CONFIG, raster_config_se);
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on SI */
|
||||
gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
|
||||
static void gfx_v6_0_setup_rb(struct amdgpu_device *adev,
|
||||
u32 se_num, u32 sh_per_se,
|
||||
u32 max_rb_num_per_se)
|
||||
|
@ -939,6 +1056,7 @@ static void gfx_v6_0_setup_rb(struct amdgpu_device *adev,
|
|||
u32 data, mask;
|
||||
u32 disabled_rbs = 0;
|
||||
u32 enabled_rbs = 0;
|
||||
unsigned num_rb_pipes;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (i = 0; i < se_num; i++) {
|
||||
|
@ -961,6 +1079,9 @@ static void gfx_v6_0_setup_rb(struct amdgpu_device *adev,
|
|||
adev->gfx.config.backend_enable_mask = enabled_rbs;
|
||||
adev->gfx.config.num_rbs = hweight32(enabled_rbs);
|
||||
|
||||
num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
|
||||
adev->gfx.config.max_shader_engines, 16);
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (i = 0; i < se_num; i++) {
|
||||
gfx_v6_0_select_se_sh(adev, i, 0xffffffff, 0xffffffff);
|
||||
|
@ -980,7 +1101,15 @@ static void gfx_v6_0_setup_rb(struct amdgpu_device *adev,
|
|||
}
|
||||
enabled_rbs >>= 2;
|
||||
}
|
||||
WREG32(PA_SC_RASTER_CONFIG, data);
|
||||
gfx_v6_0_raster_config(adev, &data);
|
||||
|
||||
if (!adev->gfx.config.backend_enable_mask ||
|
||||
adev->gfx.config.num_rbs >= num_rb_pipes)
|
||||
WREG32(PA_SC_RASTER_CONFIG, data);
|
||||
else
|
||||
gfx_v6_0_write_harvested_raster_configs(adev, data,
|
||||
adev->gfx.config.backend_enable_mask,
|
||||
num_rb_pipes);
|
||||
}
|
||||
gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
|
@ -1645,6 +1645,147 @@ static u32 gfx_v7_0_get_rb_active_bitmap(struct amdgpu_device *adev)
|
|||
return (~data) & mask;
|
||||
}
|
||||
|
||||
static void
|
||||
gfx_v7_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_BONAIRE:
|
||||
*rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
|
||||
SE_XSEL(1) | SE_YSEL(1);
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
case CHIP_HAWAII:
|
||||
*rconf |= RB_MAP_PKR0(2) | RB_MAP_PKR1(2) |
|
||||
RB_XSEL2(1) | PKR_MAP(2) | PKR_XSEL(1) |
|
||||
PKR_YSEL(1) | SE_MAP(2) | SE_XSEL(2) |
|
||||
SE_YSEL(3);
|
||||
*rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(3) |
|
||||
SE_PAIR_YSEL(2);
|
||||
break;
|
||||
case CHIP_KAVERI:
|
||||
*rconf |= RB_MAP_PKR0(2);
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
case CHIP_KABINI:
|
||||
case CHIP_MULLINS:
|
||||
*rconf |= 0x0;
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gfx_v7_0_write_harvested_raster_configs(struct amdgpu_device *adev,
|
||||
u32 raster_config, u32 raster_config_1,
|
||||
unsigned rb_mask, unsigned num_rb)
|
||||
{
|
||||
unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
|
||||
unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
|
||||
unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
|
||||
unsigned rb_per_se = num_rb / num_se;
|
||||
unsigned se_mask[4];
|
||||
unsigned se;
|
||||
|
||||
se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
|
||||
se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
|
||||
se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
|
||||
se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
|
||||
|
||||
WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
|
||||
WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
|
||||
WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
|
||||
|
||||
if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
|
||||
(!se_mask[2] && !se_mask[3]))) {
|
||||
raster_config_1 &= ~SE_PAIR_MAP_MASK;
|
||||
|
||||
if (!se_mask[0] && !se_mask[1]) {
|
||||
raster_config_1 |=
|
||||
SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_3);
|
||||
} else {
|
||||
raster_config_1 |=
|
||||
SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
for (se = 0; se < num_se; se++) {
|
||||
unsigned raster_config_se = raster_config;
|
||||
unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
|
||||
unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
|
||||
int idx = (se / 2) * 2;
|
||||
|
||||
if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
|
||||
raster_config_se &= ~SE_MAP_MASK;
|
||||
|
||||
if (!se_mask[idx]) {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
pkr0_mask &= rb_mask;
|
||||
pkr1_mask &= rb_mask;
|
||||
if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
|
||||
raster_config_se &= ~PKR_MAP_MASK;
|
||||
|
||||
if (!pkr0_mask) {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se >= 2) {
|
||||
unsigned rb0_mask = 1 << (se * rb_per_se);
|
||||
unsigned rb1_mask = rb0_mask << 1;
|
||||
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR0_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se > 2) {
|
||||
rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
|
||||
rb1_mask = rb0_mask << 1;
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR1_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on CI+ */
|
||||
gfx_v7_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG, raster_config_se);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on CI+ */
|
||||
gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* gfx_v7_0_setup_rb - setup the RBs on the asic
|
||||
*
|
||||
|
@ -1658,9 +1799,11 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev)
|
|||
{
|
||||
int i, j;
|
||||
u32 data;
|
||||
u32 raster_config = 0, raster_config_1 = 0;
|
||||
u32 active_rbs = 0;
|
||||
u32 rb_bitmap_width_per_sh = adev->gfx.config.max_backends_per_se /
|
||||
adev->gfx.config.max_sh_per_se;
|
||||
unsigned num_rb_pipes;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
|
||||
|
@ -1672,10 +1815,25 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev)
|
|||
}
|
||||
}
|
||||
gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
adev->gfx.config.backend_enable_mask = active_rbs;
|
||||
adev->gfx.config.num_rbs = hweight32(active_rbs);
|
||||
|
||||
num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
|
||||
adev->gfx.config.max_shader_engines, 16);
|
||||
|
||||
gfx_v7_0_raster_config(adev, &raster_config, &raster_config_1);
|
||||
|
||||
if (!adev->gfx.config.backend_enable_mask ||
|
||||
adev->gfx.config.num_rbs >= num_rb_pipes) {
|
||||
WREG32(mmPA_SC_RASTER_CONFIG, raster_config);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
|
||||
} else {
|
||||
gfx_v7_0_write_harvested_raster_configs(adev, raster_config, raster_config_1,
|
||||
adev->gfx.config.backend_enable_mask,
|
||||
num_rb_pipes);
|
||||
}
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3492,13 +3492,163 @@ static u32 gfx_v8_0_get_rb_active_bitmap(struct amdgpu_device *adev)
|
|||
return (~data) & mask;
|
||||
}
|
||||
|
||||
static void
|
||||
gfx_v8_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
*rconf |= RB_MAP_PKR0(2) | RB_MAP_PKR1(2) |
|
||||
RB_XSEL2(1) | PKR_MAP(2) |
|
||||
PKR_XSEL(1) | PKR_YSEL(1) |
|
||||
SE_MAP(2) | SE_XSEL(2) | SE_YSEL(3);
|
||||
*rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(3) |
|
||||
SE_PAIR_YSEL(2);
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
case CHIP_POLARIS10:
|
||||
*rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
|
||||
SE_XSEL(1) | SE_YSEL(1);
|
||||
*rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(2) |
|
||||
SE_PAIR_YSEL(2);
|
||||
break;
|
||||
case CHIP_TOPAZ:
|
||||
case CHIP_CARRIZO:
|
||||
*rconf |= RB_MAP_PKR0(2);
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
case CHIP_POLARIS11:
|
||||
*rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
|
||||
SE_XSEL(1) | SE_YSEL(1);
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
case CHIP_STONEY:
|
||||
*rconf |= 0x0;
|
||||
*rconf1 |= 0x0;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gfx_v8_0_write_harvested_raster_configs(struct amdgpu_device *adev,
|
||||
u32 raster_config, u32 raster_config_1,
|
||||
unsigned rb_mask, unsigned num_rb)
|
||||
{
|
||||
unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
|
||||
unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
|
||||
unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
|
||||
unsigned rb_per_se = num_rb / num_se;
|
||||
unsigned se_mask[4];
|
||||
unsigned se;
|
||||
|
||||
se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
|
||||
se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
|
||||
se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
|
||||
se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
|
||||
|
||||
WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
|
||||
WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
|
||||
WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
|
||||
|
||||
if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
|
||||
(!se_mask[2] && !se_mask[3]))) {
|
||||
raster_config_1 &= ~SE_PAIR_MAP_MASK;
|
||||
|
||||
if (!se_mask[0] && !se_mask[1]) {
|
||||
raster_config_1 |=
|
||||
SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_3);
|
||||
} else {
|
||||
raster_config_1 |=
|
||||
SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
for (se = 0; se < num_se; se++) {
|
||||
unsigned raster_config_se = raster_config;
|
||||
unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
|
||||
unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
|
||||
int idx = (se / 2) * 2;
|
||||
|
||||
if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
|
||||
raster_config_se &= ~SE_MAP_MASK;
|
||||
|
||||
if (!se_mask[idx]) {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
pkr0_mask &= rb_mask;
|
||||
pkr1_mask &= rb_mask;
|
||||
if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
|
||||
raster_config_se &= ~PKR_MAP_MASK;
|
||||
|
||||
if (!pkr0_mask) {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
|
||||
} else {
|
||||
raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se >= 2) {
|
||||
unsigned rb0_mask = 1 << (se * rb_per_se);
|
||||
unsigned rb1_mask = rb0_mask << 1;
|
||||
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR0_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb_per_se > 2) {
|
||||
rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
|
||||
rb1_mask = rb0_mask << 1;
|
||||
rb0_mask &= rb_mask;
|
||||
rb1_mask &= rb_mask;
|
||||
if (!rb0_mask || !rb1_mask) {
|
||||
raster_config_se &= ~RB_MAP_PKR1_MASK;
|
||||
|
||||
if (!rb0_mask) {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
|
||||
} else {
|
||||
raster_config_se |=
|
||||
RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on VI */
|
||||
gfx_v8_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG, raster_config_se);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
|
||||
}
|
||||
|
||||
/* GRBM_GFX_INDEX has a different offset on VI */
|
||||
gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
|
||||
static void gfx_v8_0_setup_rb(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, j;
|
||||
u32 data;
|
||||
u32 raster_config = 0, raster_config_1 = 0;
|
||||
u32 active_rbs = 0;
|
||||
u32 rb_bitmap_width_per_sh = adev->gfx.config.max_backends_per_se /
|
||||
adev->gfx.config.max_sh_per_se;
|
||||
unsigned num_rb_pipes;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
|
||||
|
@ -3510,10 +3660,26 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev)
|
|||
}
|
||||
}
|
||||
gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
adev->gfx.config.backend_enable_mask = active_rbs;
|
||||
adev->gfx.config.num_rbs = hweight32(active_rbs);
|
||||
|
||||
num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
|
||||
adev->gfx.config.max_shader_engines, 16);
|
||||
|
||||
gfx_v8_0_raster_config(adev, &raster_config, &raster_config_1);
|
||||
|
||||
if (!adev->gfx.config.backend_enable_mask ||
|
||||
adev->gfx.config.num_rbs >= num_rb_pipes) {
|
||||
WREG32(mmPA_SC_RASTER_CONFIG, raster_config);
|
||||
WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
|
||||
} else {
|
||||
gfx_v8_0_write_harvested_raster_configs(adev, raster_config, raster_config_1,
|
||||
adev->gfx.config.backend_enable_mask,
|
||||
num_rb_pipes);
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5817,6 +5983,76 @@ static int gfx_v8_0_update_gfx_clock_gating(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
uint32_t msg_id, pp_state;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
|
||||
if (state == AMD_CG_STATE_UNGATE)
|
||||
pp_state = 0;
|
||||
else
|
||||
pp_state = PP_STATE_CG | PP_STATE_LS;
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_CG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_MG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
uint32_t msg_id, pp_state;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
|
||||
if (state == AMD_CG_STATE_UNGATE)
|
||||
pp_state = 0;
|
||||
else
|
||||
pp_state = PP_STATE_CG | PP_STATE_LS;
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_CG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_3D,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_MG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_RLC,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_CP,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v8_0_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
|
@ -5829,6 +6065,13 @@ static int gfx_v8_0_set_clockgating_state(void *handle,
|
|||
gfx_v8_0_update_gfx_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
gfx_v8_0_tonga_update_gfx_clock_gating(adev, state);
|
||||
break;
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
gfx_v8_0_polaris_update_gfx_clock_gating(adev, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -269,8 +269,10 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
|
|||
|
||||
/* Skip MC ucode loading on SR-IOV capable boards.
|
||||
* vbios does this for us in asic_init in that case.
|
||||
* Skip MC ucode loading on VF, because hypervisor will do that
|
||||
* for this adaptor.
|
||||
*/
|
||||
if (adev->virtualization.supports_sr_iov)
|
||||
if (amdgpu_sriov_bios(adev))
|
||||
return 0;
|
||||
|
||||
hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data;
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "iceland_smum.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
|
||||
|
||||
static void iceland_dpm_set_funcs(struct amdgpu_device *adev);
|
||||
|
||||
static int iceland_dpm_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
iceland_dpm_set_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_init_microcode(struct amdgpu_device *adev)
|
||||
{
|
||||
char fw_name[30] = "amdgpu/topaz_smc.bin";
|
||||
int err;
|
||||
|
||||
err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = amdgpu_ucode_validate(adev->pm.fw);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int iceland_dpm_sw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
ret = iceland_dpm_init_microcode(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_sw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_hw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
/* smu init only needs to be called at startup, not resume.
|
||||
* It should be in sw_init, but requires the fw info gathered
|
||||
* in sw_init from other IP modules.
|
||||
*/
|
||||
ret = iceland_smu_init(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = iceland_smu_start(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
adev->firmware.smu_load = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int iceland_dpm_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
/* smu fini only needs to be called at teardown, not suspend.
|
||||
* It should be in sw_fini, but we put it here for symmetry
|
||||
* with smu init.
|
||||
*/
|
||||
iceland_smu_fini(adev);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_suspend(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_resume(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
ret = iceland_smu_start(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iceland_dpm_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_dpm_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs iceland_dpm_ip_funcs = {
|
||||
.name = "iceland_dpm",
|
||||
.early_init = iceland_dpm_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = iceland_dpm_sw_init,
|
||||
.sw_fini = iceland_dpm_sw_fini,
|
||||
.hw_init = iceland_dpm_hw_init,
|
||||
.hw_fini = iceland_dpm_hw_fini,
|
||||
.suspend = iceland_dpm_suspend,
|
||||
.resume = iceland_dpm_resume,
|
||||
.is_idle = NULL,
|
||||
.wait_for_idle = NULL,
|
||||
.soft_reset = NULL,
|
||||
.set_clockgating_state = iceland_dpm_set_clockgating_state,
|
||||
.set_powergating_state = iceland_dpm_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_dpm_funcs iceland_dpm_funcs = {
|
||||
.get_temperature = NULL,
|
||||
.pre_set_power_state = NULL,
|
||||
.set_power_state = NULL,
|
||||
.post_set_power_state = NULL,
|
||||
.display_configuration_changed = NULL,
|
||||
.get_sclk = NULL,
|
||||
.get_mclk = NULL,
|
||||
.print_power_state = NULL,
|
||||
.debugfs_print_current_performance_level = NULL,
|
||||
.force_performance_level = NULL,
|
||||
.vblank_too_short = NULL,
|
||||
.powergate_uvd = NULL,
|
||||
};
|
||||
|
||||
static void iceland_dpm_set_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
if (NULL == adev->pm.funcs)
|
||||
adev->pm.funcs = &iceland_dpm_funcs;
|
||||
}
|
|
@ -1,677 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "ppsmc.h"
|
||||
#include "iceland_smum.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
#include "smu/smu_7_1_1_d.h"
|
||||
#include "smu/smu_7_1_1_sh_mask.h"
|
||||
|
||||
#define ICELAND_SMC_SIZE 0x20000
|
||||
|
||||
static int iceland_set_smc_sram_address(struct amdgpu_device *adev,
|
||||
uint32_t smc_address, uint32_t limit)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (smc_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_address + 3) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
WREG32(mmSMC_IND_INDEX_0, smc_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_copy_bytes_to_smc(struct amdgpu_device *adev,
|
||||
uint32_t smc_start_address,
|
||||
const uint8_t *src,
|
||||
uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t data, orig_data;
|
||||
int result = 0;
|
||||
uint32_t extra_shift;
|
||||
unsigned long flags;
|
||||
|
||||
if (smc_start_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_start_address + byte_count) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first */
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
|
||||
result = iceland_set_smc_sram_address(adev, addr, limit);
|
||||
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
/* Now write odd bytes left, do a read modify write cycle */
|
||||
data = 0;
|
||||
|
||||
result = iceland_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
orig_data = RREG32(mmSMC_IND_DATA_0);
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
data = (data << 8) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
data |= (orig_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = iceland_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void iceland_start_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
}
|
||||
|
||||
static void iceland_reset_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
}
|
||||
|
||||
static int iceland_program_jump_on_start(struct amdgpu_device *adev)
|
||||
{
|
||||
static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
|
||||
iceland_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iceland_stop_smc_clock(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
}
|
||||
|
||||
static void iceland_start_smc_clock(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
}
|
||||
|
||||
static bool iceland_is_smc_ram_running(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
|
||||
|
||||
return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
static int wait_smu_response(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32(mmSMC_RESP_0);
|
||||
if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
|
||||
{
|
||||
if (!iceland_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg)
|
||||
{
|
||||
if (!iceland_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg,
|
||||
uint32_t parameter)
|
||||
{
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return iceland_send_msg_to_smc(adev, msg);
|
||||
}
|
||||
|
||||
static int iceland_send_msg_to_smc_with_parameter_without_waiting(
|
||||
struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg, uint32_t parameter)
|
||||
{
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return iceland_send_msg_to_smc_without_waiting(adev, msg);
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int iceland_wait_for_smc_inactive(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
if (!iceland_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iceland_smu_upload_firmware_image(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
uint32_t ucode_size;
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
uint32_t val;
|
||||
uint32_t byte_count;
|
||||
uint32_t data;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (!adev->pm.fw)
|
||||
return -EINVAL;
|
||||
|
||||
/* Skip SMC ucode loading on SR-IOV capable boards.
|
||||
* vbios does this for us in asic_init in that case.
|
||||
*/
|
||||
if (adev->virtualization.supports_sr_iov)
|
||||
return 0;
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
|
||||
amdgpu_ucode_print_smc_hdr(&hdr->header);
|
||||
|
||||
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
|
||||
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
|
||||
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
|
||||
src = (const uint8_t *)
|
||||
(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
|
||||
if (ucode_size & 3) {
|
||||
DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ucode_size > ICELAND_SMC_SIZE) {
|
||||
DRM_ERROR("SMC address is beyond the SMC RAM area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
if (REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
val = RREG32_SMC(ixSMC_SYSCON_MISC_CNTL);
|
||||
WREG32_SMC(ixSMC_SYSCON_MISC_CNTL, val | 1);
|
||||
|
||||
iceland_stop_smc_clock(adev);
|
||||
iceland_reset_smc(adev);
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
byte_count = ucode_size;
|
||||
while (byte_count >= 4) {
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
}
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int iceland_read_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t *value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = iceland_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
*value = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iceland_write_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = iceland_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
WREG32(mmSMC_IND_DATA_0, value);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iceland_smu_stop_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
iceland_reset_smc(adev);
|
||||
iceland_stop_smc_clock(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iceland_smu_start_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
iceland_program_jump_on_start(adev);
|
||||
iceland_start_smc_clock(adev);
|
||||
iceland_start_smc(adev);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED) == 1)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum AMDGPU_UCODE_ID iceland_convert_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
return AMDGPU_UCODE_ID_SDMA0;
|
||||
case UCODE_ID_SDMA1:
|
||||
return AMDGPU_UCODE_ID_SDMA1;
|
||||
case UCODE_ID_CP_CE:
|
||||
return AMDGPU_UCODE_ID_CP_CE;
|
||||
case UCODE_ID_CP_PFP:
|
||||
return AMDGPU_UCODE_ID_CP_PFP;
|
||||
case UCODE_ID_CP_ME:
|
||||
return AMDGPU_UCODE_ID_CP_ME;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
return AMDGPU_UCODE_ID_CP_MEC1;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
return AMDGPU_UCODE_ID_CP_MEC2;
|
||||
case UCODE_ID_RLC_G:
|
||||
return AMDGPU_UCODE_ID_RLC_G;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return AMDGPU_UCODE_ID_MAXIMUM;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t iceland_smu_get_mask_for_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case AMDGPU_UCODE_ID_SDMA0:
|
||||
return UCODE_ID_SDMA0_MASK;
|
||||
case AMDGPU_UCODE_ID_SDMA1:
|
||||
return UCODE_ID_SDMA1_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_CE:
|
||||
return UCODE_ID_CP_CE_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_PFP:
|
||||
return UCODE_ID_CP_PFP_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_ME:
|
||||
return UCODE_ID_CP_ME_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC1:
|
||||
return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC2:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_RLC_G:
|
||||
return UCODE_ID_RLC_G_MASK;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int iceland_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
enum AMDGPU_UCODE_ID id = iceland_convert_fw_type(fw_type);
|
||||
struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
|
||||
const struct gfx_firmware_header_v1_0 *header = NULL;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t data_size;
|
||||
|
||||
if (ucode->fw == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
gpu_addr = ucode->mc_addr;
|
||||
header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
data_size = le32_to_cpu(header->header.ucode_size_bytes);
|
||||
|
||||
entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = upper_32_bits(gpu_addr);
|
||||
entry->image_addr_low = lower_32_bits(gpu_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = data_size;
|
||||
entry->num_register_entries = 0;
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_smu_request_load_fw(struct amdgpu_device *adev)
|
||||
{
|
||||
struct iceland_smu_private_data *private = (struct iceland_smu_private_data *)adev->smu.priv;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
uint32_t fw_to_load;
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)private->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
if (!adev->firmware.smu_load)
|
||||
return 0;
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for RLC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for CE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for PFP\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for ME\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
|
||||
iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK |
|
||||
UCODE_ID_SDMA0_MASK |
|
||||
UCODE_ID_SDMA1_MASK |
|
||||
UCODE_ID_CP_CE_MASK |
|
||||
UCODE_ID_CP_ME_MASK |
|
||||
UCODE_ID_CP_PFP_MASK |
|
||||
UCODE_ID_CP_MEC_MASK |
|
||||
UCODE_ID_CP_MEC_JT1_MASK;
|
||||
|
||||
|
||||
if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
|
||||
DRM_ERROR("Fail to request SMU load ucode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_smu_check_fw_load_finish(struct amdgpu_device *adev,
|
||||
uint32_t fw_type)
|
||||
{
|
||||
uint32_t fw_mask = iceland_smu_get_mask_for_fw_type(fw_type);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_27) & fw_mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_smu_start(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = iceland_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
result = iceland_smu_start_smc(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return iceland_smu_request_load_fw(adev);
|
||||
}
|
||||
|
||||
static const struct amdgpu_smumgr_funcs iceland_smumgr_funcs = {
|
||||
.check_fw_load_finish = iceland_smu_check_fw_load_finish,
|
||||
.request_smu_load_fw = NULL,
|
||||
.request_smu_specific_fw = NULL,
|
||||
};
|
||||
|
||||
int iceland_smu_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct iceland_smu_private_data *private;
|
||||
uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
|
||||
uint64_t mc_addr;
|
||||
void *toc_buf_ptr;
|
||||
int ret;
|
||||
|
||||
private = kzalloc(sizeof(struct iceland_smu_private_data), GFP_KERNEL);
|
||||
if (NULL == private)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate firmware buffers */
|
||||
if (adev->firmware.smu_load)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
adev->smu.priv = private;
|
||||
adev->smu.fw_flags = 0;
|
||||
|
||||
/* Allocate FW image data structure and header buffer */
|
||||
ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
|
||||
NULL, NULL, toc_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for TOC buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Retrieve GPU address for header buffer and internal buffer */
|
||||
ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
private->header_addr_low = lower_32_bits(mc_addr);
|
||||
private->header_addr_high = upper_32_bits(mc_addr);
|
||||
private->header = toc_buf_ptr;
|
||||
|
||||
adev->smu.smumgr_funcs = &iceland_smumgr_funcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_smu_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
kfree(adev->smu.priv);
|
||||
adev->smu.priv = NULL;
|
||||
if (adev->firmware.fw_buf)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -952,12 +952,6 @@ static void si_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
|
|||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
}
|
||||
|
||||
static u32 si_get_virtual_caps(struct amdgpu_device *adev)
|
||||
{
|
||||
/* SI does not support SR-IOV */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct amdgpu_allowed_register_entry si_allowed_read_registers[] = {
|
||||
{GRBM_STATUS, false},
|
||||
{GB_ADDR_CONFIG, false},
|
||||
|
@ -1124,16 +1118,22 @@ static int si_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void si_detect_hw_virtualization(struct amdgpu_device *adev)
|
||||
{
|
||||
if (is_virtual_machine()) /* passthrough mode */
|
||||
adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
|
||||
}
|
||||
|
||||
static const struct amdgpu_asic_funcs si_asic_funcs =
|
||||
{
|
||||
.read_disabled_bios = &si_read_disabled_bios,
|
||||
.detect_hw_virtualization = si_detect_hw_virtualization,
|
||||
.read_register = &si_read_register,
|
||||
.reset = &si_asic_reset,
|
||||
.set_vga_state = &si_vga_set_state,
|
||||
.get_xclk = &si_get_xclk,
|
||||
.set_uvd_clocks = &si_set_uvd_clocks,
|
||||
.set_vce_clocks = NULL,
|
||||
.get_virtual_caps = &si_get_virtual_caps,
|
||||
};
|
||||
|
||||
static uint32_t si_get_rev_id(struct amdgpu_device *adev)
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "tonga_smum.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
|
||||
|
||||
static void tonga_dpm_set_funcs(struct amdgpu_device *adev);
|
||||
|
||||
static int tonga_dpm_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
tonga_dpm_set_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_dpm_init_microcode(struct amdgpu_device *adev)
|
||||
{
|
||||
char fw_name[30] = "amdgpu/tonga_smc.bin";
|
||||
int err;
|
||||
err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = amdgpu_ucode_validate(adev->pm.fw);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tonga_dpm_sw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
ret = tonga_dpm_init_microcode(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_dpm_sw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_dpm_hw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
/* smu init only needs to be called at startup, not resume.
|
||||
* It should be in sw_init, but requires the fw info gathered
|
||||
* in sw_init from other IP modules.
|
||||
*/
|
||||
ret = tonga_smu_init(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = tonga_smu_start(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
adev->firmware.smu_load = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tonga_dpm_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
/* smu fini only needs to be called at teardown, not suspend.
|
||||
* It should be in sw_fini, but we put it here for symmetry
|
||||
* with smu init.
|
||||
*/
|
||||
tonga_smu_fini(adev);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_dpm_suspend(void *handle)
|
||||
{
|
||||
return tonga_dpm_hw_fini(handle);
|
||||
}
|
||||
|
||||
static int tonga_dpm_resume(void *handle)
|
||||
{
|
||||
return tonga_dpm_hw_init(handle);
|
||||
}
|
||||
|
||||
static int tonga_dpm_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_dpm_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs tonga_dpm_ip_funcs = {
|
||||
.name = "tonga_dpm",
|
||||
.early_init = tonga_dpm_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = tonga_dpm_sw_init,
|
||||
.sw_fini = tonga_dpm_sw_fini,
|
||||
.hw_init = tonga_dpm_hw_init,
|
||||
.hw_fini = tonga_dpm_hw_fini,
|
||||
.suspend = tonga_dpm_suspend,
|
||||
.resume = tonga_dpm_resume,
|
||||
.is_idle = NULL,
|
||||
.wait_for_idle = NULL,
|
||||
.soft_reset = NULL,
|
||||
.set_clockgating_state = tonga_dpm_set_clockgating_state,
|
||||
.set_powergating_state = tonga_dpm_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_dpm_funcs tonga_dpm_funcs = {
|
||||
.get_temperature = NULL,
|
||||
.pre_set_power_state = NULL,
|
||||
.set_power_state = NULL,
|
||||
.post_set_power_state = NULL,
|
||||
.display_configuration_changed = NULL,
|
||||
.get_sclk = NULL,
|
||||
.get_mclk = NULL,
|
||||
.print_power_state = NULL,
|
||||
.debugfs_print_current_performance_level = NULL,
|
||||
.force_performance_level = NULL,
|
||||
.vblank_too_short = NULL,
|
||||
.powergate_uvd = NULL,
|
||||
};
|
||||
|
||||
static void tonga_dpm_set_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
if (NULL == adev->pm.funcs)
|
||||
adev->pm.funcs = &tonga_dpm_funcs;
|
||||
}
|
|
@ -1,862 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "tonga_ppsmc.h"
|
||||
#include "tonga_smum.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
#include "smu/smu_7_1_2_d.h"
|
||||
#include "smu/smu_7_1_2_sh_mask.h"
|
||||
|
||||
#define TONGA_SMC_SIZE 0x20000
|
||||
|
||||
static int tonga_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (smc_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_address + 3) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
WREG32(mmSMC_IND_INDEX_0, smc_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t data, orig_data;
|
||||
int result = 0;
|
||||
uint32_t extra_shift;
|
||||
unsigned long flags;
|
||||
|
||||
if (smc_start_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_start_address + byte_count) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first */
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
|
||||
result = tonga_set_smc_sram_address(adev, addr, limit);
|
||||
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
/* Now write odd bytes left, do a read modify write cycle */
|
||||
data = 0;
|
||||
|
||||
result = tonga_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
orig_data = RREG32(mmSMC_IND_DATA_0);
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
data = (data << 8) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
data |= (orig_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = tonga_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tonga_program_jump_on_start(struct amdgpu_device *adev)
|
||||
{
|
||||
static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
|
||||
tonga_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tonga_is_smc_ram_running(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
|
||||
|
||||
return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
static int wait_smu_response(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32(mmSMC_RESP_0);
|
||||
if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_send_msg_to_smc_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, 0x20000);
|
||||
WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
|
||||
{
|
||||
if (!tonga_is_smc_ram_running(adev))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg,
|
||||
uint32_t parameter)
|
||||
{
|
||||
if (!tonga_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return tonga_send_msg_to_smc(adev, msg);
|
||||
}
|
||||
|
||||
static int tonga_send_msg_to_smc_with_parameter_without_waiting(
|
||||
struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg, uint32_t parameter)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return tonga_send_msg_to_smc_without_waiting(adev, msg);
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int tonga_wait_for_smc_inactive(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
if (!tonga_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tonga_smu_upload_firmware_image(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
uint32_t ucode_size;
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
uint32_t val;
|
||||
uint32_t byte_count;
|
||||
uint32_t *data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!adev->pm.fw)
|
||||
return -EINVAL;
|
||||
|
||||
/* Skip SMC ucode loading on SR-IOV capable boards.
|
||||
* vbios does this for us in asic_init in that case.
|
||||
*/
|
||||
if (adev->virtualization.supports_sr_iov)
|
||||
return 0;
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
|
||||
amdgpu_ucode_print_smc_hdr(&hdr->header);
|
||||
|
||||
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
|
||||
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
|
||||
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
|
||||
src = (const uint8_t *)
|
||||
(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
|
||||
if (ucode_size & 3) {
|
||||
DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ucode_size > TONGA_SMC_SIZE) {
|
||||
DRM_ERROR("SMC address is beyond the SMC RAM area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
byte_count = ucode_size;
|
||||
data = (uint32_t *)src;
|
||||
for (; byte_count >= 4; data++, byte_count -= 4)
|
||||
WREG32(mmSMC_IND_DATA_0, data[0]);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int tonga_read_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t *value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = tonga_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
*value = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tonga_write_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = tonga_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
WREG32(mmSMC_IND_DATA_0, value);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tonga_smu_stop_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum AMDGPU_UCODE_ID tonga_convert_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
return AMDGPU_UCODE_ID_SDMA0;
|
||||
case UCODE_ID_SDMA1:
|
||||
return AMDGPU_UCODE_ID_SDMA1;
|
||||
case UCODE_ID_CP_CE:
|
||||
return AMDGPU_UCODE_ID_CP_CE;
|
||||
case UCODE_ID_CP_PFP:
|
||||
return AMDGPU_UCODE_ID_CP_PFP;
|
||||
case UCODE_ID_CP_ME:
|
||||
return AMDGPU_UCODE_ID_CP_ME;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
return AMDGPU_UCODE_ID_CP_MEC1;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
return AMDGPU_UCODE_ID_CP_MEC2;
|
||||
case UCODE_ID_RLC_G:
|
||||
return AMDGPU_UCODE_ID_RLC_G;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return AMDGPU_UCODE_ID_MAXIMUM;
|
||||
}
|
||||
}
|
||||
|
||||
static int tonga_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
enum AMDGPU_UCODE_ID id = tonga_convert_fw_type(fw_type);
|
||||
struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
|
||||
const struct gfx_firmware_header_v1_0 *header = NULL;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t data_size;
|
||||
|
||||
if (ucode->fw == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
gpu_addr = ucode->mc_addr;
|
||||
header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
data_size = le32_to_cpu(header->header.ucode_size_bytes);
|
||||
|
||||
if ((fw_type == UCODE_ID_CP_MEC_JT1) ||
|
||||
(fw_type == UCODE_ID_CP_MEC_JT2)) {
|
||||
gpu_addr += le32_to_cpu(header->jt_offset) << 2;
|
||||
data_size = le32_to_cpu(header->jt_size) << 2;
|
||||
}
|
||||
|
||||
entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = upper_32_bits(gpu_addr);
|
||||
entry->image_addr_low = lower_32_bits(gpu_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = data_size;
|
||||
entry->num_register_entries = 0;
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_smu_request_load_fw(struct amdgpu_device *adev)
|
||||
{
|
||||
struct tonga_smu_private_data *private = (struct tonga_smu_private_data *)adev->smu.priv;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
uint32_t fw_to_load;
|
||||
|
||||
WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0);
|
||||
|
||||
tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high);
|
||||
tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low);
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)private->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
if (!adev->firmware.smu_load)
|
||||
return 0;
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for RLC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for CE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for PFP\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for ME\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
|
||||
tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK |
|
||||
UCODE_ID_SDMA0_MASK |
|
||||
UCODE_ID_SDMA1_MASK |
|
||||
UCODE_ID_CP_CE_MASK |
|
||||
UCODE_ID_CP_ME_MASK |
|
||||
UCODE_ID_CP_PFP_MASK |
|
||||
UCODE_ID_CP_MEC_MASK;
|
||||
|
||||
if (tonga_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
|
||||
DRM_ERROR("Fail to request SMU load ucode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t tonga_smu_get_mask_for_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case AMDGPU_UCODE_ID_SDMA0:
|
||||
return UCODE_ID_SDMA0_MASK;
|
||||
case AMDGPU_UCODE_ID_SDMA1:
|
||||
return UCODE_ID_SDMA1_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_CE:
|
||||
return UCODE_ID_CP_CE_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_PFP:
|
||||
return UCODE_ID_CP_PFP_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_ME:
|
||||
return UCODE_ID_CP_ME_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC1:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC2:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_RLC_G:
|
||||
return UCODE_ID_RLC_G_MASK;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int tonga_smu_check_fw_load_finish(struct amdgpu_device *adev,
|
||||
uint32_t fw_type)
|
||||
{
|
||||
uint32_t fw_mask = tonga_smu_get_mask_for_fw_type(fw_type);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_smu_start_in_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = tonga_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Clear status */
|
||||
WREG32_SMC(ixSMU_STATUS, 0);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Set SMU Auto Start */
|
||||
val = RREG32_SMC(ixSMU_INPUT_DATA);
|
||||
val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1);
|
||||
WREG32_SMC(ixSMU_INPUT_DATA, val);
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Interrupt is not enabled by firmware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Call Test SMU message with 0x20000 offset
|
||||
* to trigger SMU start
|
||||
*/
|
||||
tonga_send_msg_to_smc_offset(adev);
|
||||
|
||||
/* Wait for done bit to be set */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMU start\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check pass/failed indicator */
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) {
|
||||
DRM_ERROR("SMU Firmware start failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMU firmware initialization failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_smu_start_in_non_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, result;
|
||||
uint32_t val;
|
||||
|
||||
/* wait for smc boot up */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done);
|
||||
if (val)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMC boot sequence is not completed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = tonga_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Set smc instruct start point at 0x0 */
|
||||
tonga_program_jump_on_start(adev);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMC firmware initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_smu_start(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
|
||||
if (!tonga_is_smc_ram_running(adev)) {
|
||||
val = RREG32_SMC(ixSMU_FIRMWARE);
|
||||
if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) {
|
||||
result = tonga_smu_start_in_non_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
result = tonga_smu_start_in_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return tonga_smu_request_load_fw(adev);
|
||||
}
|
||||
|
||||
static const struct amdgpu_smumgr_funcs tonga_smumgr_funcs = {
|
||||
.check_fw_load_finish = tonga_smu_check_fw_load_finish,
|
||||
.request_smu_load_fw = NULL,
|
||||
.request_smu_specific_fw = NULL,
|
||||
};
|
||||
|
||||
int tonga_smu_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct tonga_smu_private_data *private;
|
||||
uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
uint32_t smu_internal_buffer_size = 200*4096;
|
||||
struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
|
||||
struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
|
||||
uint64_t mc_addr;
|
||||
void *toc_buf_ptr;
|
||||
void *smu_buf_ptr;
|
||||
int ret;
|
||||
|
||||
private = kzalloc(sizeof(struct tonga_smu_private_data), GFP_KERNEL);
|
||||
if (NULL == private)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate firmware buffers */
|
||||
if (adev->firmware.smu_load)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
adev->smu.priv = private;
|
||||
adev->smu.fw_flags = 0;
|
||||
|
||||
/* Allocate FW image data structure and header buffer */
|
||||
ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
|
||||
NULL, NULL, toc_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for TOC buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate buffer for SMU internal buffer */
|
||||
ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
|
||||
NULL, NULL, smu_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Retrieve GPU address for header buffer and internal buffer */
|
||||
ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
private->header_addr_low = lower_32_bits(mc_addr);
|
||||
private->header_addr_high = upper_32_bits(mc_addr);
|
||||
private->header = toc_buf_ptr;
|
||||
|
||||
ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
private->smu_buffer_addr_low = lower_32_bits(mc_addr);
|
||||
private->smu_buffer_addr_high = upper_32_bits(mc_addr);
|
||||
|
||||
adev->smu.smumgr_funcs = &tonga_smumgr_funcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_smu_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
kfree(adev->smu.priv);
|
||||
adev->smu.priv = NULL;
|
||||
if (adev->firmware.fw_buf)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -79,6 +79,9 @@
|
|||
#endif
|
||||
#include "dce_virtual.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
|
||||
MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
|
||||
|
@ -445,18 +448,21 @@ static bool vi_read_bios_from_rom(struct amdgpu_device *adev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static u32 vi_get_virtual_caps(struct amdgpu_device *adev)
|
||||
static void vi_detect_hw_virtualization(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 caps = 0;
|
||||
u32 reg = RREG32(mmBIF_IOV_FUNC_IDENTIFIER);
|
||||
uint32_t reg = RREG32(mmBIF_IOV_FUNC_IDENTIFIER);
|
||||
/* bit0: 0 means pf and 1 means vf */
|
||||
/* bit31: 0 means disable IOV and 1 means enable */
|
||||
if (reg & 1)
|
||||
adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_IS_VF;
|
||||
|
||||
if (REG_GET_FIELD(reg, BIF_IOV_FUNC_IDENTIFIER, IOV_ENABLE))
|
||||
caps |= AMDGPU_VIRT_CAPS_SRIOV_EN;
|
||||
if (reg & 0x80000000)
|
||||
adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_ENABLE_IOV;
|
||||
|
||||
if (REG_GET_FIELD(reg, BIF_IOV_FUNC_IDENTIFIER, FUNC_IDENTIFIER))
|
||||
caps |= AMDGPU_VIRT_CAPS_IS_VF;
|
||||
|
||||
return caps;
|
||||
if (reg == 0) {
|
||||
if (is_virtual_machine()) /* passthrough mode exclus sr-iov mode */
|
||||
adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct amdgpu_allowed_register_entry tonga_allowed_read_registers[] = {
|
||||
|
@ -1521,13 +1527,13 @@ static const struct amdgpu_asic_funcs vi_asic_funcs =
|
|||
{
|
||||
.read_disabled_bios = &vi_read_disabled_bios,
|
||||
.read_bios_from_rom = &vi_read_bios_from_rom,
|
||||
.detect_hw_virtualization = vi_detect_hw_virtualization,
|
||||
.read_register = &vi_read_register,
|
||||
.reset = &vi_asic_reset,
|
||||
.set_vga_state = &vi_vga_set_state,
|
||||
.get_xclk = &vi_get_xclk,
|
||||
.set_uvd_clocks = &vi_set_uvd_clocks,
|
||||
.set_vce_clocks = &vi_set_vce_clocks,
|
||||
.get_virtual_caps = &vi_get_virtual_caps,
|
||||
};
|
||||
|
||||
static int vi_common_early_init(void *handle)
|
||||
|
@ -1657,6 +1663,10 @@ static int vi_common_early_init(void *handle)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* in early init stage, vbios code won't work */
|
||||
if (adev->asic_funcs->detect_hw_virtualization)
|
||||
amdgpu_asic_detect_hw_virtualization(adev);
|
||||
|
||||
if (amdgpu_smc_load_fw && smc_enabled)
|
||||
adev->firmware.smu_load = true;
|
||||
|
||||
|
@ -1800,6 +1810,63 @@ static void vi_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
|
|||
WREG32_SMC(ixCGTT_ROM_CLK_CTRL0, data);
|
||||
}
|
||||
|
||||
static int vi_common_set_clockgating_state_by_smu(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
uint32_t msg_id, pp_state;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
|
||||
if (state == AMD_CG_STATE_UNGATE)
|
||||
pp_state = 0;
|
||||
else
|
||||
pp_state = PP_STATE_CG | PP_STATE_LS;
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_MC,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_SDMA,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_HDP,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_BIF,
|
||||
PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_BIF,
|
||||
PP_STATE_SUPPORT_CG,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_DRM,
|
||||
PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_ROM,
|
||||
PP_STATE_SUPPORT_CG,
|
||||
pp_state);
|
||||
amd_set_clockgating_by_smu(pp_handle, msg_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vi_common_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
|
@ -1825,6 +1892,10 @@ static int vi_common_set_clockgating_state(void *handle,
|
|||
vi_update_hdp_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
vi_common_set_clockgating_state_by_smu(adev, state);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -373,4 +373,41 @@
|
|||
#define VCE_CMD_WAIT_GE 0x00000106
|
||||
#define VCE_CMD_UPDATE_PTB 0x00000107
|
||||
#define VCE_CMD_FLUSH_TLB 0x00000108
|
||||
|
||||
/* mmPA_SC_RASTER_CONFIG mask */
|
||||
#define RB_MAP_PKR0(x) ((x) << 0)
|
||||
#define RB_MAP_PKR0_MASK (0x3 << 0)
|
||||
#define RB_MAP_PKR1(x) ((x) << 2)
|
||||
#define RB_MAP_PKR1_MASK (0x3 << 2)
|
||||
#define RB_XSEL2(x) ((x) << 4)
|
||||
#define RB_XSEL2_MASK (0x3 << 4)
|
||||
#define RB_XSEL (1 << 6)
|
||||
#define RB_YSEL (1 << 7)
|
||||
#define PKR_MAP(x) ((x) << 8)
|
||||
#define PKR_MAP_MASK (0x3 << 8)
|
||||
#define PKR_XSEL(x) ((x) << 10)
|
||||
#define PKR_XSEL_MASK (0x3 << 10)
|
||||
#define PKR_YSEL(x) ((x) << 12)
|
||||
#define PKR_YSEL_MASK (0x3 << 12)
|
||||
#define SC_MAP(x) ((x) << 16)
|
||||
#define SC_MAP_MASK (0x3 << 16)
|
||||
#define SC_XSEL(x) ((x) << 18)
|
||||
#define SC_XSEL_MASK (0x3 << 18)
|
||||
#define SC_YSEL(x) ((x) << 20)
|
||||
#define SC_YSEL_MASK (0x3 << 20)
|
||||
#define SE_MAP(x) ((x) << 24)
|
||||
#define SE_MAP_MASK (0x3 << 24)
|
||||
#define SE_XSEL(x) ((x) << 26)
|
||||
#define SE_XSEL_MASK (0x3 << 26)
|
||||
#define SE_YSEL(x) ((x) << 28)
|
||||
#define SE_YSEL_MASK (0x3 << 28)
|
||||
|
||||
/* mmPA_SC_RASTER_CONFIG_1 mask */
|
||||
#define SE_PAIR_MAP(x) ((x) << 0)
|
||||
#define SE_PAIR_MAP_MASK (0x3 << 0)
|
||||
#define SE_PAIR_XSEL(x) ((x) << 2)
|
||||
#define SE_PAIR_XSEL_MASK (0x3 << 2)
|
||||
#define SE_PAIR_YSEL(x) ((x) << 4)
|
||||
#define SE_PAIR_YSEL_MASK (0x3 << 4)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1398,10 +1398,45 @@
|
|||
#define DB_DEPTH_INFO 0xA00F
|
||||
|
||||
#define PA_SC_RASTER_CONFIG 0xA0D4
|
||||
# define RB_MAP_PKR0(x) ((x) << 0)
|
||||
# define RB_MAP_PKR0_MASK (0x3 << 0)
|
||||
# define RB_MAP_PKR1(x) ((x) << 2)
|
||||
# define RB_MAP_PKR1_MASK (0x3 << 2)
|
||||
# define RASTER_CONFIG_RB_MAP_0 0
|
||||
# define RASTER_CONFIG_RB_MAP_1 1
|
||||
# define RASTER_CONFIG_RB_MAP_2 2
|
||||
# define RASTER_CONFIG_RB_MAP_3 3
|
||||
# define RB_XSEL2(x) ((x) << 4)
|
||||
# define RB_XSEL2_MASK (0x3 << 4)
|
||||
# define RB_XSEL (1 << 6)
|
||||
# define RB_YSEL (1 << 7)
|
||||
# define PKR_MAP(x) ((x) << 8)
|
||||
# define PKR_MAP_MASK (0x3 << 8)
|
||||
# define RASTER_CONFIG_PKR_MAP_0 0
|
||||
# define RASTER_CONFIG_PKR_MAP_1 1
|
||||
# define RASTER_CONFIG_PKR_MAP_2 2
|
||||
# define RASTER_CONFIG_PKR_MAP_3 3
|
||||
# define PKR_XSEL(x) ((x) << 10)
|
||||
# define PKR_XSEL_MASK (0x3 << 10)
|
||||
# define PKR_YSEL(x) ((x) << 12)
|
||||
# define PKR_YSEL_MASK (0x3 << 12)
|
||||
# define SC_MAP(x) ((x) << 16)
|
||||
# define SC_MAP_MASK (0x3 << 16)
|
||||
# define SC_XSEL(x) ((x) << 18)
|
||||
# define SC_XSEL_MASK (0x3 << 18)
|
||||
# define SC_YSEL(x) ((x) << 20)
|
||||
# define SC_YSEL_MASK (0x3 << 20)
|
||||
# define SE_MAP(x) ((x) << 24)
|
||||
# define SE_MAP_MASK (0x3 << 24)
|
||||
# define RASTER_CONFIG_SE_MAP_0 0
|
||||
# define RASTER_CONFIG_SE_MAP_1 1
|
||||
# define RASTER_CONFIG_SE_MAP_2 2
|
||||
# define RASTER_CONFIG_SE_MAP_3 3
|
||||
# define SE_XSEL(x) ((x) << 26)
|
||||
# define SE_XSEL_MASK (0x3 << 26)
|
||||
# define SE_YSEL(x) ((x) << 28)
|
||||
# define SE_YSEL_MASK (0x3 << 28)
|
||||
|
||||
|
||||
#define VGT_EVENT_INITIATOR 0xA2A4
|
||||
# define SAMPLE_STREAMOUTSTATS1 (1 << 0)
|
||||
|
|
|
@ -161,6 +161,7 @@ struct cgs_clock_limits {
|
|||
*/
|
||||
struct cgs_firmware_info {
|
||||
uint16_t version;
|
||||
uint16_t fw_version;
|
||||
uint16_t feature_version;
|
||||
uint32_t image_size;
|
||||
uint64_t mc_addr;
|
||||
|
|
|
@ -191,11 +191,9 @@ static int pp_sw_reset(void *handle)
|
|||
}
|
||||
|
||||
|
||||
static int pp_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
uint32_t msg_id, pp_state;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -209,76 +207,7 @@ static int pp_set_clockgating_state(void *handle,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (state == AMD_CG_STATE_UNGATE)
|
||||
pp_state = 0;
|
||||
else
|
||||
pp_state = PP_STATE_CG | PP_STATE_LS;
|
||||
|
||||
/* Enable/disable GFX blocks clock gating through SMU */
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_CG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_3D,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_RLC,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_CP,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
|
||||
PP_BLOCK_GFX_MG,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
|
||||
/* Enable/disable System blocks clock gating through SMU */
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_BIF,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_BIF,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_MC,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_ROM,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_DRM,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_HDP,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
|
||||
PP_BLOCK_SYS_SDMA,
|
||||
PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
|
||||
pp_state);
|
||||
hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
|
||||
return 0;
|
||||
return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
|
||||
}
|
||||
|
||||
static int pp_set_powergating_state(void *handle,
|
||||
|
@ -362,7 +291,7 @@ const struct amd_ip_funcs pp_ip_funcs = {
|
|||
.is_idle = pp_is_idle,
|
||||
.wait_for_idle = pp_wait_for_idle,
|
||||
.soft_reset = pp_sw_reset,
|
||||
.set_clockgating_state = pp_set_clockgating_state,
|
||||
.set_clockgating_state = NULL,
|
||||
.set_powergating_state = pp_set_powergating_state,
|
||||
};
|
||||
|
||||
|
@ -576,28 +505,6 @@ enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pp_debugfs_print_current_performance_level(void *handle,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL)
|
||||
return;
|
||||
|
||||
if (hwmgr->hwmgr_func->print_current_perforce_level == NULL) {
|
||||
printk(KERN_INFO "%s was not implemented.\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
|
||||
}
|
||||
|
||||
static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
@ -894,6 +801,25 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
|
|||
return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
|
||||
}
|
||||
|
||||
static int pp_dpm_read_sensor(void *handle, int idx, int32_t *value)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
PP_CHECK_HW(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->read_sensor == NULL) {
|
||||
printk(KERN_INFO "%s was not implemented.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value);
|
||||
}
|
||||
|
||||
const struct amd_powerplay_funcs pp_dpm_funcs = {
|
||||
.get_temperature = pp_dpm_get_temperature,
|
||||
.load_firmware = pp_dpm_load_fw,
|
||||
|
@ -906,7 +832,6 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
|
|||
.powergate_vce = pp_dpm_powergate_vce,
|
||||
.powergate_uvd = pp_dpm_powergate_uvd,
|
||||
.dispatch_tasks = pp_dpm_dispatch_tasks,
|
||||
.print_current_performance_level = pp_debugfs_print_current_performance_level,
|
||||
.set_fan_control_mode = pp_dpm_set_fan_control_mode,
|
||||
.get_fan_control_mode = pp_dpm_get_fan_control_mode,
|
||||
.set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
|
||||
|
@ -920,6 +845,7 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
|
|||
.set_sclk_od = pp_dpm_set_sclk_od,
|
||||
.get_mclk_od = pp_dpm_get_mclk_od,
|
||||
.set_mclk_od = pp_dpm_set_mclk_od,
|
||||
.read_sensor = pp_dpm_read_sensor,
|
||||
};
|
||||
|
||||
static int amd_pp_instance_init(struct amd_pp_init *pp_init,
|
||||
|
|
|
@ -262,6 +262,8 @@ static const pem_event_action * const display_config_change_event[] = {
|
|||
unblock_adjust_power_state_tasks,
|
||||
set_cpu_power_state,
|
||||
notify_hw_power_source_tasks,
|
||||
get_2d_performance_state_tasks,
|
||||
set_performance_state_tasks,
|
||||
/* updateDALConfigurationTasks,
|
||||
variBrightDisplayConfigurationChangeTasks, */
|
||||
adjust_power_state_tasks,
|
||||
|
|
|
@ -101,11 +101,12 @@ int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip)
|
|||
if (requested == NULL)
|
||||
return 0;
|
||||
|
||||
phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
|
||||
|
||||
if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr, &pcurrent->hardware, &requested->hardware, &equal)))
|
||||
equal = false;
|
||||
|
||||
if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
|
||||
phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
|
||||
phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
|
||||
memcpy(hwmgr->current_ps, hwmgr->request_ps, hwmgr->ps_size);
|
||||
}
|
||||
|
|
|
@ -3,16 +3,12 @@
|
|||
# It provides the hardware management services for the driver.
|
||||
|
||||
HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
|
||||
hardwaremanager.o pp_acpi.o cz_hwmgr.o \
|
||||
cz_clockpowergating.o tonga_powertune.o\
|
||||
process_pptables_v1_0.o ppatomctrl.o \
|
||||
tonga_hwmgr.o pppcielanes.o tonga_thermal.o\
|
||||
fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \
|
||||
fiji_clockpowergating.o fiji_thermal.o \
|
||||
polaris10_hwmgr.o polaris10_powertune.o polaris10_thermal.o \
|
||||
polaris10_clockpowergating.o iceland_hwmgr.o \
|
||||
iceland_clockpowergating.o iceland_thermal.o \
|
||||
iceland_powertune.o
|
||||
hardwaremanager.o pp_acpi.o cz_hwmgr.o \
|
||||
cz_clockpowergating.o pppcielanes.o\
|
||||
process_pptables_v1_0.o ppatomctrl.o \
|
||||
smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \
|
||||
smu7_clockpowergating.o
|
||||
|
||||
|
||||
AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
|
||||
|
||||
|
|
|
@ -1538,78 +1538,6 @@ int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
|
|||
return sizeof(struct cz_power_state);
|
||||
}
|
||||
|
||||
static void
|
||||
cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
|
||||
struct phm_clock_voltage_dependency_table *table =
|
||||
hwmgr->dyn_state.vddc_dependency_on_sclk;
|
||||
|
||||
struct phm_vce_clock_voltage_dependency_table *vce_table =
|
||||
hwmgr->dyn_state.vce_clock_voltage_dependency_table;
|
||||
|
||||
struct phm_uvd_clock_voltage_dependency_table *uvd_table =
|
||||
hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
|
||||
|
||||
uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
|
||||
uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
|
||||
uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
|
||||
|
||||
uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
|
||||
uint16_t vddnb, vddgfx;
|
||||
int result;
|
||||
|
||||
if (sclk_index >= NUM_SCLK_LEVELS) {
|
||||
seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
|
||||
} else {
|
||||
sclk = table->entries[sclk_index].clk;
|
||||
seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
|
||||
}
|
||||
|
||||
tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
|
||||
CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
|
||||
vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
|
||||
tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
|
||||
CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
|
||||
vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
|
||||
seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
|
||||
|
||||
seq_printf(m, "\n uvd %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
|
||||
if (!cz_hwmgr->uvd_power_gated) {
|
||||
if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
seq_printf(m, "\n invalid uvd dpm level %d\n", uvd_index);
|
||||
} else {
|
||||
vclk = uvd_table->entries[uvd_index].vclk;
|
||||
dclk = uvd_table->entries[uvd_index].dclk;
|
||||
seq_printf(m, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
|
||||
}
|
||||
}
|
||||
|
||||
seq_printf(m, "\n vce %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
|
||||
if (!cz_hwmgr->vce_power_gated) {
|
||||
if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
|
||||
} else {
|
||||
ecclk = vce_table->entries[vce_index].ecclk;
|
||||
seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
|
||||
}
|
||||
}
|
||||
|
||||
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
|
||||
if (0 == result) {
|
||||
activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
|
||||
activity_percent = activity_percent > 100 ? 100 : activity_percent;
|
||||
} else {
|
||||
activity_percent = 50;
|
||||
}
|
||||
|
||||
seq_printf(m, "\n [GPU load]: %u %%\n\n", activity_percent);
|
||||
}
|
||||
|
||||
static void cz_hw_print_display_cfg(
|
||||
const struct cc6_settings *cc6_settings)
|
||||
{
|
||||
|
@ -1857,6 +1785,107 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
|
||||
struct phm_clock_voltage_dependency_table *table =
|
||||
hwmgr->dyn_state.vddc_dependency_on_sclk;
|
||||
|
||||
struct phm_vce_clock_voltage_dependency_table *vce_table =
|
||||
hwmgr->dyn_state.vce_clock_voltage_dependency_table;
|
||||
|
||||
struct phm_uvd_clock_voltage_dependency_table *uvd_table =
|
||||
hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
|
||||
|
||||
uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
|
||||
uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
|
||||
uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
||||
TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
|
||||
|
||||
uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
|
||||
uint16_t vddnb, vddgfx;
|
||||
int result;
|
||||
|
||||
switch (idx) {
|
||||
case AMDGPU_PP_SENSOR_GFX_SCLK:
|
||||
if (sclk_index < NUM_SCLK_LEVELS) {
|
||||
sclk = table->entries[sclk_index].clk;
|
||||
*value = sclk;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
case AMDGPU_PP_SENSOR_VDDNB:
|
||||
tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
|
||||
CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
|
||||
vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
|
||||
*value = vddnb;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_VDDGFX:
|
||||
tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
|
||||
CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
|
||||
vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
|
||||
*value = vddgfx;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_UVD_VCLK:
|
||||
if (!cz_hwmgr->uvd_power_gated) {
|
||||
if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
vclk = uvd_table->entries[uvd_index].vclk;
|
||||
*value = vclk;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*value = 0;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_UVD_DCLK:
|
||||
if (!cz_hwmgr->uvd_power_gated) {
|
||||
if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
dclk = uvd_table->entries[uvd_index].dclk;
|
||||
*value = dclk;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*value = 0;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_VCE_ECCLK:
|
||||
if (!cz_hwmgr->vce_power_gated) {
|
||||
if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ecclk = vce_table->entries[vce_index].ecclk;
|
||||
*value = ecclk;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*value = 0;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_GPU_LOAD:
|
||||
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
|
||||
if (0 == result) {
|
||||
activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
|
||||
activity_percent = activity_percent > 100 ? 100 : activity_percent;
|
||||
} else {
|
||||
activity_percent = 50;
|
||||
}
|
||||
*value = activity_percent;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_UVD_POWER:
|
||||
*value = cz_hwmgr->uvd_power_gated ? 0 : 1;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_VCE_POWER:
|
||||
*value = cz_hwmgr->vce_power_gated ? 0 : 1;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pp_hwmgr_func cz_hwmgr_funcs = {
|
||||
.backend_init = cz_hwmgr_backend_init,
|
||||
.backend_fini = cz_hwmgr_backend_fini,
|
||||
|
@ -1872,7 +1901,6 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {
|
|||
.patch_boot_state = cz_dpm_patch_boot_state,
|
||||
.get_pp_table_entry = cz_dpm_get_pp_table_entry,
|
||||
.get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
|
||||
.print_current_perforce_level = cz_print_current_perforce_level,
|
||||
.set_cpu_power_state = cz_set_cpu_power_state,
|
||||
.store_cc6_data = cz_store_cc6_data,
|
||||
.force_clock_level = cz_force_clock_level,
|
||||
|
@ -1882,6 +1910,7 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {
|
|||
.get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks,
|
||||
.get_clock_by_type = cz_get_clock_by_type,
|
||||
.get_max_high_clocks = cz_get_max_high_clocks,
|
||||
.read_sensor = cz_read_sensor,
|
||||
};
|
||||
|
||||
int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "fiji_clockpowergating.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "fiji_hwmgr.h"
|
||||
|
||||
int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
data->uvd_power_gated = false;
|
||||
data->vce_power_gated = false;
|
||||
data->samu_power_gated = false;
|
||||
data->acp_power_gated = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->uvd_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
data->uvd_power_gated = bgate;
|
||||
|
||||
if (bgate) {
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_GATE);
|
||||
fiji_update_uvd_dpm(hwmgr, true);
|
||||
} else {
|
||||
fiji_update_uvd_dpm(hwmgr, false);
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
struct phm_set_power_state_input states;
|
||||
const struct pp_power_state *pcurrent;
|
||||
struct pp_power_state *requested;
|
||||
|
||||
if (data->vce_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
data->vce_power_gated = bgate;
|
||||
|
||||
pcurrent = hwmgr->current_ps;
|
||||
requested = hwmgr->request_ps;
|
||||
|
||||
states.pcurrent_state = &(pcurrent->hardware);
|
||||
states.pnew_state = &(requested->hardware);
|
||||
|
||||
fiji_update_vce_dpm(hwmgr, &states);
|
||||
fiji_enable_disable_vce_dpm(hwmgr, !bgate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->samu_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
data->samu_power_gated = bgate;
|
||||
|
||||
if (bgate)
|
||||
fiji_update_samu_dpm(hwmgr, true);
|
||||
else
|
||||
fiji_update_samu_dpm(hwmgr, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->acp_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
data->acp_power_gated = bgate;
|
||||
|
||||
if (bgate)
|
||||
fiji_update_acp_dpm(hwmgr, true);
|
||||
else
|
||||
fiji_update_acp_dpm(hwmgr, false);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 FIJI_DYN_DEFAULTS_H
|
||||
#define FIJI_DYN_DEFAULTS_H
|
||||
|
||||
/** \file
|
||||
* Volcanic Islands Dynamic default parameters.
|
||||
*/
|
||||
|
||||
enum FIJIdpm_TrendDetection
|
||||
{
|
||||
FIJIAdpm_TrendDetection_AUTO,
|
||||
FIJIAdpm_TrendDetection_UP,
|
||||
FIJIAdpm_TrendDetection_DOWN
|
||||
};
|
||||
typedef enum FIJIdpm_TrendDetection FIJIdpm_TrendDetection;
|
||||
|
||||
/* We need to fill in the default values!!!!!!!!!!!!!!!!!!!!!!! */
|
||||
|
||||
/* Bit vector representing same fields as hardware register. */
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy ????
|
||||
* HDP_busy
|
||||
* IH_busy
|
||||
* UVD_busy
|
||||
* VCE_busy
|
||||
* ACP_busy
|
||||
* SAMU_busy
|
||||
* SDMA enabled */
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. ????
|
||||
* SH_Gfx_busy
|
||||
* RB_Gfx_busy
|
||||
* VCE_busy */
|
||||
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility.
|
||||
* FE_Gfx_busy
|
||||
* RB_Gfx_busy
|
||||
* ACP_busy */
|
||||
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility.
|
||||
* FE_Gfx_busy
|
||||
* SH_Gfx_busy
|
||||
* UVD_busy */
|
||||
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy
|
||||
* VCE_busy
|
||||
* ACP_busy
|
||||
* SAMU_busy */
|
||||
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP */
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP */
|
||||
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP */
|
||||
|
||||
|
||||
/* thermal protection counter (units). */
|
||||
#define PPFIJI_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
|
||||
|
||||
/* static screen threshold unit */
|
||||
#define PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT 0
|
||||
|
||||
/* static screen threshold */
|
||||
#define PPFIJI_STATICSCREENTHRESHOLD_DFLT 0x00C8
|
||||
|
||||
/* gfx idle clock stop threshold */
|
||||
#define PPFIJI_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
|
||||
|
||||
/* Fixed reference divider to use when building baby stepping tables. */
|
||||
#define PPFIJI_REFERENCEDIVIDER_DFLT 4
|
||||
|
||||
/* ULV voltage change delay time
|
||||
* Used to be delay_vreg in N.I. split for S.I.
|
||||
* Using N.I. delay_vreg value as default
|
||||
* ReferenceClock = 2700
|
||||
* VoltageResponseTime = 1000
|
||||
* VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
|
||||
*/
|
||||
#define PPFIJI_ULVVOLTAGECHANGEDELAY_DFLT 1687
|
||||
|
||||
#define PPFIJI_CGULVPARAMETER_DFLT 0x00040035
|
||||
#define PPFIJI_CGULVCONTROL_DFLT 0x00007450
|
||||
#define PPFIJI_TARGETACTIVITY_DFLT 30 /* 30%*/
|
||||
#define PPFIJI_MCLK_TARGETACTIVITY_DFLT 10 /* 10% */
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 _FIJI_HWMGR_H_
|
||||
#define _FIJI_HWMGR_H_
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "smu73.h"
|
||||
#include "smu73_discrete.h"
|
||||
#include "ppatomctrl.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "pp_endian.h"
|
||||
|
||||
#define FIJI_MAX_HARDWARE_POWERLEVELS 2
|
||||
#define FIJI_AT_DFLT 30
|
||||
|
||||
#define FIJI_VOLTAGE_CONTROL_NONE 0x0
|
||||
#define FIJI_VOLTAGE_CONTROL_BY_GPIO 0x1
|
||||
#define FIJI_VOLTAGE_CONTROL_BY_SVID2 0x2
|
||||
#define FIJI_VOLTAGE_CONTROL_MERGED 0x3
|
||||
|
||||
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
|
||||
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
|
||||
#define DPMTABLE_UPDATE_SCLK 0x00000004
|
||||
#define DPMTABLE_UPDATE_MCLK 0x00000008
|
||||
|
||||
struct fiji_performance_level {
|
||||
uint32_t memory_clock;
|
||||
uint32_t engine_clock;
|
||||
uint16_t pcie_gen;
|
||||
uint16_t pcie_lane;
|
||||
};
|
||||
|
||||
struct fiji_uvd_clocks {
|
||||
uint32_t vclk;
|
||||
uint32_t dclk;
|
||||
};
|
||||
|
||||
struct fiji_vce_clocks {
|
||||
uint32_t evclk;
|
||||
uint32_t ecclk;
|
||||
};
|
||||
|
||||
struct fiji_power_state {
|
||||
uint32_t magic;
|
||||
struct fiji_uvd_clocks uvd_clks;
|
||||
struct fiji_vce_clocks vce_clks;
|
||||
uint32_t sam_clk;
|
||||
uint32_t acp_clk;
|
||||
uint16_t performance_level_count;
|
||||
bool dc_compatible;
|
||||
uint32_t sclk_threshold;
|
||||
struct fiji_performance_level performance_levels[FIJI_MAX_HARDWARE_POWERLEVELS];
|
||||
};
|
||||
|
||||
struct fiji_dpm_level {
|
||||
bool enabled;
|
||||
uint32_t value;
|
||||
uint32_t param1;
|
||||
};
|
||||
|
||||
#define FIJI_MAX_DEEPSLEEP_DIVIDER_ID 5
|
||||
#define MAX_REGULAR_DPM_NUMBER 8
|
||||
#define FIJI_MINIMUM_ENGINE_CLOCK 2500
|
||||
|
||||
struct fiji_single_dpm_table {
|
||||
uint32_t count;
|
||||
struct fiji_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
|
||||
};
|
||||
|
||||
struct fiji_dpm_table {
|
||||
struct fiji_single_dpm_table sclk_table;
|
||||
struct fiji_single_dpm_table mclk_table;
|
||||
struct fiji_single_dpm_table pcie_speed_table;
|
||||
struct fiji_single_dpm_table vddc_table;
|
||||
struct fiji_single_dpm_table vddci_table;
|
||||
struct fiji_single_dpm_table mvdd_table;
|
||||
};
|
||||
|
||||
struct fiji_clock_registers {
|
||||
uint32_t vCG_SPLL_FUNC_CNTL;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_2;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_3;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_4;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
|
||||
uint32_t vDLL_CNTL;
|
||||
uint32_t vMCLK_PWRMGT_CNTL;
|
||||
uint32_t vMPLL_AD_FUNC_CNTL;
|
||||
uint32_t vMPLL_DQ_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL_1;
|
||||
uint32_t vMPLL_FUNC_CNTL_2;
|
||||
uint32_t vMPLL_SS1;
|
||||
uint32_t vMPLL_SS2;
|
||||
};
|
||||
|
||||
struct fiji_voltage_smio_registers {
|
||||
uint32_t vS0_VID_LOWER_SMIO_CNTL;
|
||||
};
|
||||
|
||||
#define FIJI_MAX_LEAKAGE_COUNT 8
|
||||
struct fiji_leakage_voltage {
|
||||
uint16_t count;
|
||||
uint16_t leakage_id[FIJI_MAX_LEAKAGE_COUNT];
|
||||
uint16_t actual_voltage[FIJI_MAX_LEAKAGE_COUNT];
|
||||
};
|
||||
|
||||
struct fiji_vbios_boot_state {
|
||||
uint16_t mvdd_bootup_value;
|
||||
uint16_t vddc_bootup_value;
|
||||
uint16_t vddci_bootup_value;
|
||||
uint32_t sclk_bootup_value;
|
||||
uint32_t mclk_bootup_value;
|
||||
uint16_t pcie_gen_bootup_value;
|
||||
uint16_t pcie_lane_bootup_value;
|
||||
};
|
||||
|
||||
struct fiji_bacos {
|
||||
uint32_t best_match;
|
||||
uint32_t baco_flags;
|
||||
struct fiji_performance_level performance_level;
|
||||
};
|
||||
|
||||
/* Ultra Low Voltage parameter structure */
|
||||
struct fiji_ulv_parm {
|
||||
bool ulv_supported;
|
||||
uint32_t cg_ulv_parameter;
|
||||
uint32_t ulv_volt_change_delay;
|
||||
struct fiji_performance_level ulv_power_level;
|
||||
};
|
||||
|
||||
struct fiji_display_timing {
|
||||
uint32_t min_clock_in_sr;
|
||||
uint32_t num_existing_displays;
|
||||
};
|
||||
|
||||
struct fiji_dpmlevel_enable_mask {
|
||||
uint32_t uvd_dpm_enable_mask;
|
||||
uint32_t vce_dpm_enable_mask;
|
||||
uint32_t acp_dpm_enable_mask;
|
||||
uint32_t samu_dpm_enable_mask;
|
||||
uint32_t sclk_dpm_enable_mask;
|
||||
uint32_t mclk_dpm_enable_mask;
|
||||
uint32_t pcie_dpm_enable_mask;
|
||||
};
|
||||
|
||||
struct fiji_pcie_perf_range {
|
||||
uint16_t max;
|
||||
uint16_t min;
|
||||
};
|
||||
|
||||
struct fiji_hwmgr {
|
||||
struct fiji_dpm_table dpm_table;
|
||||
struct fiji_dpm_table golden_dpm_table;
|
||||
|
||||
uint32_t voting_rights_clients0;
|
||||
uint32_t voting_rights_clients1;
|
||||
uint32_t voting_rights_clients2;
|
||||
uint32_t voting_rights_clients3;
|
||||
uint32_t voting_rights_clients4;
|
||||
uint32_t voting_rights_clients5;
|
||||
uint32_t voting_rights_clients6;
|
||||
uint32_t voting_rights_clients7;
|
||||
uint32_t static_screen_threshold_unit;
|
||||
uint32_t static_screen_threshold;
|
||||
uint32_t voltage_control;
|
||||
uint32_t vddc_vddci_delta;
|
||||
|
||||
uint32_t active_auto_throttle_sources;
|
||||
|
||||
struct fiji_clock_registers clock_registers;
|
||||
struct fiji_voltage_smio_registers voltage_smio_registers;
|
||||
|
||||
bool is_memory_gddr5;
|
||||
uint16_t acpi_vddc;
|
||||
bool pspp_notify_required;
|
||||
uint16_t force_pcie_gen;
|
||||
uint16_t acpi_pcie_gen;
|
||||
uint32_t pcie_gen_cap;
|
||||
uint32_t pcie_lane_cap;
|
||||
uint32_t pcie_spc_cap;
|
||||
struct fiji_leakage_voltage vddc_leakage;
|
||||
struct fiji_leakage_voltage Vddci_leakage;
|
||||
|
||||
uint32_t mvdd_control;
|
||||
uint32_t vddc_mask_low;
|
||||
uint32_t mvdd_mask_low;
|
||||
uint16_t max_vddc_in_pptable;
|
||||
uint16_t min_vddc_in_pptable;
|
||||
uint16_t max_vddci_in_pptable;
|
||||
uint16_t min_vddci_in_pptable;
|
||||
uint32_t mclk_strobe_mode_threshold;
|
||||
uint32_t mclk_stutter_mode_threshold;
|
||||
uint32_t mclk_edc_enable_threshold;
|
||||
uint32_t mclk_edcwr_enable_threshold;
|
||||
bool is_uvd_enabled;
|
||||
struct fiji_vbios_boot_state vbios_boot_state;
|
||||
|
||||
bool battery_state;
|
||||
bool is_tlu_enabled;
|
||||
|
||||
/* ---- SMC SRAM Address of firmware header tables ---- */
|
||||
uint32_t sram_end;
|
||||
uint32_t dpm_table_start;
|
||||
uint32_t soft_regs_start;
|
||||
uint32_t mc_reg_table_start;
|
||||
uint32_t fan_table_start;
|
||||
uint32_t arb_table_start;
|
||||
struct SMU73_Discrete_DpmTable smc_state_table;
|
||||
struct SMU73_Discrete_Ulv ulv_setting;
|
||||
|
||||
/* ---- Stuff originally coming from Evergreen ---- */
|
||||
uint32_t vddci_control;
|
||||
struct pp_atomctrl_voltage_table vddc_voltage_table;
|
||||
struct pp_atomctrl_voltage_table vddci_voltage_table;
|
||||
struct pp_atomctrl_voltage_table mvdd_voltage_table;
|
||||
|
||||
uint32_t mgcg_cgtt_local2;
|
||||
uint32_t mgcg_cgtt_local3;
|
||||
uint32_t gpio_debug;
|
||||
uint32_t mc_micro_code_feature;
|
||||
uint32_t highest_mclk;
|
||||
uint16_t acpi_vddci;
|
||||
uint8_t mvdd_high_index;
|
||||
uint8_t mvdd_low_index;
|
||||
bool dll_default_on;
|
||||
bool performance_request_registered;
|
||||
|
||||
/* ---- Low Power Features ---- */
|
||||
struct fiji_bacos bacos;
|
||||
struct fiji_ulv_parm ulv;
|
||||
|
||||
/* ---- CAC Stuff ---- */
|
||||
uint32_t cac_table_start;
|
||||
bool cac_configuration_required;
|
||||
bool driver_calculate_cac_leakage;
|
||||
bool cac_enabled;
|
||||
|
||||
/* ---- DPM2 Parameters ---- */
|
||||
uint32_t power_containment_features;
|
||||
bool enable_dte_feature;
|
||||
bool enable_tdc_limit_feature;
|
||||
bool enable_pkg_pwr_tracking_feature;
|
||||
bool disable_uvd_power_tune_feature;
|
||||
const struct fiji_pt_defaults *power_tune_defaults;
|
||||
struct SMU73_Discrete_PmFuses power_tune_table;
|
||||
uint32_t dte_tj_offset;
|
||||
uint32_t fast_watermark_threshold;
|
||||
|
||||
/* ---- Phase Shedding ---- */
|
||||
bool vddc_phase_shed_control;
|
||||
|
||||
/* ---- DI/DT ---- */
|
||||
struct fiji_display_timing display_timing;
|
||||
|
||||
/* ---- Thermal Temperature Setting ---- */
|
||||
struct fiji_dpmlevel_enable_mask dpm_level_enable_mask;
|
||||
uint32_t need_update_smu7_dpm_table;
|
||||
uint32_t sclk_dpm_key_disabled;
|
||||
uint32_t mclk_dpm_key_disabled;
|
||||
uint32_t pcie_dpm_key_disabled;
|
||||
uint32_t min_engine_clocks;
|
||||
struct fiji_pcie_perf_range pcie_gen_performance;
|
||||
struct fiji_pcie_perf_range pcie_lane_performance;
|
||||
struct fiji_pcie_perf_range pcie_gen_power_saving;
|
||||
struct fiji_pcie_perf_range pcie_lane_power_saving;
|
||||
bool use_pcie_performance_levels;
|
||||
bool use_pcie_power_saving_levels;
|
||||
uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS];
|
||||
uint32_t mclk_activity_target;
|
||||
uint32_t mclk_dpm0_activity_target;
|
||||
uint32_t low_sclk_interrupt_threshold;
|
||||
uint32_t last_mclk_dpm_enable_mask;
|
||||
bool uvd_enabled;
|
||||
|
||||
/* ---- Power Gating States ---- */
|
||||
bool uvd_power_gated;
|
||||
bool vce_power_gated;
|
||||
bool samu_power_gated;
|
||||
bool acp_power_gated;
|
||||
bool pg_acp_init;
|
||||
bool frtc_enabled;
|
||||
bool frtc_status_changed;
|
||||
};
|
||||
|
||||
/* To convert to Q8.8 format for firmware */
|
||||
#define FIJI_Q88_FORMAT_CONVERSION_UNIT 256
|
||||
|
||||
enum Fiji_I2CLineID {
|
||||
Fiji_I2CLineID_DDC1 = 0x90,
|
||||
Fiji_I2CLineID_DDC2 = 0x91,
|
||||
Fiji_I2CLineID_DDC3 = 0x92,
|
||||
Fiji_I2CLineID_DDC4 = 0x93,
|
||||
Fiji_I2CLineID_DDC5 = 0x94,
|
||||
Fiji_I2CLineID_DDC6 = 0x95,
|
||||
Fiji_I2CLineID_SCLSDA = 0x96,
|
||||
Fiji_I2CLineID_DDCVGA = 0x97
|
||||
};
|
||||
|
||||
#define Fiji_I2C_DDC1DATA 0
|
||||
#define Fiji_I2C_DDC1CLK 1
|
||||
#define Fiji_I2C_DDC2DATA 2
|
||||
#define Fiji_I2C_DDC2CLK 3
|
||||
#define Fiji_I2C_DDC3DATA 4
|
||||
#define Fiji_I2C_DDC3CLK 5
|
||||
#define Fiji_I2C_SDA 40
|
||||
#define Fiji_I2C_SCL 41
|
||||
#define Fiji_I2C_DDC4DATA 65
|
||||
#define Fiji_I2C_DDC4CLK 66
|
||||
#define Fiji_I2C_DDC5DATA 0x48
|
||||
#define Fiji_I2C_DDC5CLK 0x49
|
||||
#define Fiji_I2C_DDC6DATA 0x4a
|
||||
#define Fiji_I2C_DDC6CLK 0x4b
|
||||
#define Fiji_I2C_DDCVGADATA 0x4c
|
||||
#define Fiji_I2C_DDCVGACLK 0x4d
|
||||
|
||||
#define FIJI_UNUSED_GPIO_PIN 0x7F
|
||||
|
||||
extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
|
||||
int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
|
||||
int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
|
||||
#endif /* _FIJI_HWMGR_H_ */
|
|
@ -1,610 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "smumgr.h"
|
||||
#include "fiji_hwmgr.h"
|
||||
#include "fiji_powertune.h"
|
||||
#include "fiji_smumgr.h"
|
||||
#include "smu73_discrete.h"
|
||||
#include "pp_debug.h"
|
||||
|
||||
#define VOLTAGE_SCALE 4
|
||||
#define POWERTUNE_DEFAULT_SET_MAX 1
|
||||
|
||||
const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
|
||||
/*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
|
||||
{1, 0xF, 0xFD,
|
||||
/* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
|
||||
0x19, 5, 45}
|
||||
};
|
||||
|
||||
void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *fiji_hwmgr = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
uint32_t tmp = 0;
|
||||
|
||||
if(table_info &&
|
||||
table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
|
||||
table_info->cac_dtp_table->usPowerTuneDataSetID)
|
||||
fiji_hwmgr->power_tune_defaults =
|
||||
&fiji_power_tune_data_set_array
|
||||
[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
|
||||
else
|
||||
fiji_hwmgr->power_tune_defaults = &fiji_power_tune_data_set_array[0];
|
||||
|
||||
/* Assume disabled */
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
fiji_hwmgr->dte_tj_offset = tmp;
|
||||
|
||||
if (!tmp) {
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
fiji_hwmgr->fast_watermark_threshold = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
tmp = 1;
|
||||
fiji_hwmgr->enable_dte_feature = tmp ? false : true;
|
||||
fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
|
||||
fiji_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PPGen has the gain setting generated in x * 100 unit
|
||||
* This function is to convert the unit to x * 4096(0x1000) unit.
|
||||
* This is the unit expected by SMC firmware
|
||||
*/
|
||||
static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
|
||||
{
|
||||
uint32_t tmp;
|
||||
tmp = raw_setting * 4096 / 100;
|
||||
return (uint16_t)tmp;
|
||||
}
|
||||
|
||||
static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda)
|
||||
{
|
||||
switch (line) {
|
||||
case Fiji_I2CLineID_DDC1 :
|
||||
*scl = Fiji_I2C_DDC1CLK;
|
||||
*sda = Fiji_I2C_DDC1DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDC2 :
|
||||
*scl = Fiji_I2C_DDC2CLK;
|
||||
*sda = Fiji_I2C_DDC2DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDC3 :
|
||||
*scl = Fiji_I2C_DDC3CLK;
|
||||
*sda = Fiji_I2C_DDC3DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDC4 :
|
||||
*scl = Fiji_I2C_DDC4CLK;
|
||||
*sda = Fiji_I2C_DDC4DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDC5 :
|
||||
*scl = Fiji_I2C_DDC5CLK;
|
||||
*sda = Fiji_I2C_DDC5DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDC6 :
|
||||
*scl = Fiji_I2C_DDC6CLK;
|
||||
*sda = Fiji_I2C_DDC6DATA;
|
||||
break;
|
||||
case Fiji_I2CLineID_SCLSDA :
|
||||
*scl = Fiji_I2C_SCL;
|
||||
*sda = Fiji_I2C_SDA;
|
||||
break;
|
||||
case Fiji_I2CLineID_DDCVGA :
|
||||
*scl = Fiji_I2C_DDCVGACLK;
|
||||
*sda = Fiji_I2C_DDCVGADATA;
|
||||
break;
|
||||
default:
|
||||
*scl = 0;
|
||||
*sda = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
|
||||
SMU73_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
|
||||
struct pp_advance_fan_control_parameters *fan_table=
|
||||
&hwmgr->thermal_controller.advanceFanControlParameters;
|
||||
uint8_t uc_scl, uc_sda;
|
||||
|
||||
/* TDP number of fraction bits are changed from 8 to 7 for Fiji
|
||||
* as requested by SMC team
|
||||
*/
|
||||
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
|
||||
(uint16_t)(cac_dtp_table->usTDP * 128));
|
||||
dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
|
||||
(uint16_t)(cac_dtp_table->usTDP * 128));
|
||||
|
||||
PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
|
||||
"Target Operating Temp is out of Range!",);
|
||||
|
||||
dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
|
||||
dpm_table->GpuTjHyst = 8;
|
||||
|
||||
dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
|
||||
|
||||
/* The following are for new Fiji Multi-input fan/thermal control */
|
||||
dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTargetOperatingTemp * 256);
|
||||
dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitHotspot * 256);
|
||||
dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitLiquid1 * 256);
|
||||
dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitLiquid2 * 256);
|
||||
dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitVrVddc * 256);
|
||||
dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitVrMvdd * 256);
|
||||
dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
|
||||
cac_dtp_table->usTemperatureLimitPlx * 256);
|
||||
|
||||
dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainEdge));
|
||||
dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainHotspot));
|
||||
dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainLiquid));
|
||||
dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainVrVddc));
|
||||
dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
|
||||
dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainPlx));
|
||||
dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
|
||||
scale_fan_gain_settings(fan_table->usFanGainHbm));
|
||||
|
||||
dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
|
||||
dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
|
||||
dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
|
||||
dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
|
||||
|
||||
get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
|
||||
dpm_table->Liquid_I2C_LineSCL = uc_scl;
|
||||
dpm_table->Liquid_I2C_LineSDA = uc_sda;
|
||||
|
||||
get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
|
||||
dpm_table->Vr_I2C_LineSCL = uc_scl;
|
||||
dpm_table->Vr_I2C_LineSDA = uc_sda;
|
||||
|
||||
get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
|
||||
dpm_table->Plx_I2C_LineSCL = uc_scl;
|
||||
dpm_table->Plx_I2C_LineSDA = uc_sda;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
|
||||
data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
|
||||
data->power_tune_table.SviLoadLineTrimVddC = 3;
|
||||
data->power_tune_table.SviLoadLineOffsetVddC = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint16_t tdc_limit;
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
/* TDC number of fraction bits are changed from 8 to 7
|
||||
* for Fiji as requested by SMC team
|
||||
*/
|
||||
tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
|
||||
data->power_tune_table.TDC_VDDC_PkgLimit =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
|
||||
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
|
||||
defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
|
||||
data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
|
||||
uint32_t temp;
|
||||
|
||||
if (fiji_read_smc_sram_dword(hwmgr->smumgr,
|
||||
fuse_table_offset +
|
||||
offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
|
||||
(uint32_t *)&temp, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
|
||||
return -EINVAL);
|
||||
else {
|
||||
data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
|
||||
data->power_tune_table.LPMLTemperatureMin =
|
||||
(uint8_t)((temp >> 16) & 0xff);
|
||||
data->power_tune_table.LPMLTemperatureMax =
|
||||
(uint8_t)((temp >> 8) & 0xff);
|
||||
data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int i;
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
/* Currently not used. Set all to zero. */
|
||||
for (i = 0; i < 16; i++)
|
||||
data->power_tune_table.LPMLTemperatureScaler[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if( (hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usFanOutputSensitivity & (1 << 15)) ||
|
||||
0 == hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usFanOutputSensitivity )
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usFanOutputSensitivity = hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usDefaultFanOutputSensitivity;
|
||||
|
||||
data->power_tune_table.FuzzyFan_PwmSetDelta =
|
||||
PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usFanOutputSensitivity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int i;
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
/* Currently not used. Set all to zero. */
|
||||
for (i = 0; i < 16; i++)
|
||||
data->power_tune_table.GnbLPML[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* int i, min, max;
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
uint8_t * pHiVID = data->power_tune_table.BapmVddCVidHiSidd;
|
||||
uint8_t * pLoVID = data->power_tune_table.BapmVddCVidLoSidd;
|
||||
|
||||
min = max = pHiVID[0];
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (0 != pHiVID[i]) {
|
||||
if (min > pHiVID[i])
|
||||
min = pHiVID[i];
|
||||
if (max < pHiVID[i])
|
||||
max = pHiVID[i];
|
||||
}
|
||||
|
||||
if (0 != pLoVID[i]) {
|
||||
if (min > pLoVID[i])
|
||||
min = pLoVID[i];
|
||||
if (max < pLoVID[i])
|
||||
max = pLoVID[i];
|
||||
}
|
||||
}
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 != min) && (0 != max), "BapmVddcVidSidd table does not exist!", return int_Failed);
|
||||
data->power_tune_table.GnbLPMLMaxVid = (uint8_t)max;
|
||||
data->power_tune_table.GnbLPMLMinVid = (uint8_t)min;
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
|
||||
uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
|
||||
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
|
||||
|
||||
HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
|
||||
LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
|
||||
|
||||
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
|
||||
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
uint32_t pm_fuse_table_offset;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
if (fiji_read_smc_sram_dword(hwmgr->smumgr,
|
||||
SMU7_FIRMWARE_HEADER_LOCATION +
|
||||
offsetof(SMU73_Firmware_Header, PmFuseTable),
|
||||
&pm_fuse_table_offset, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to get pm_fuse_table_offset Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW6 */
|
||||
if (fiji_populate_svi_load_line(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate SviLoadLine Failed!",
|
||||
return -EINVAL);
|
||||
/* DW7 */
|
||||
if (fiji_populate_tdc_limit(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TDCLimit Failed!", return -EINVAL);
|
||||
/* DW8 */
|
||||
if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TdcWaterfallCtl, "
|
||||
"LPMLTemperature Min and Max Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW9-DW12 */
|
||||
if (0 != fiji_populate_temperature_scaler(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate LPMLTemperatureScaler Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW13-DW14 */
|
||||
if(fiji_populate_fuzzy_fan(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate Fuzzy Fan Control parameters Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW15-DW18 */
|
||||
if (fiji_populate_gnb_lpml(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW19 */
|
||||
if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Min and Max Vid Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW20 */
|
||||
if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate BapmVddCBaseLeakage Hi and Lo "
|
||||
"Sidd Failed!", return -EINVAL);
|
||||
|
||||
if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
|
||||
(uint8_t *)&data->power_tune_table,
|
||||
sizeof(struct SMU73_Discrete_PmFuses), data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to download PmFuseTable Failed!",
|
||||
return -EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC)) {
|
||||
int smc_result;
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableCac));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable CAC in SMC.", result = -1);
|
||||
|
||||
data->cac_enabled = (0 == smc_result) ? true : false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC) && data->cac_enabled) {
|
||||
int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_DisableCac));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable CAC in SMC.", result = -1);
|
||||
|
||||
data->cac_enabled = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if(data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_PkgPwrSetLimit, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
|
||||
{
|
||||
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
|
||||
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
|
||||
}
|
||||
|
||||
int fiji_enable_power_containment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
int smc_result;
|
||||
int result = 0;
|
||||
|
||||
data->power_containment_features = 0;
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
if (data->enable_dte_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableDTE));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable DTE in SMC.", result = -1;);
|
||||
if (0 == smc_result)
|
||||
data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
|
||||
}
|
||||
|
||||
if (data->enable_tdc_limit_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable TDCLimit in SMC.", result = -1;);
|
||||
if (0 == smc_result)
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_TDCLimit;
|
||||
}
|
||||
|
||||
if (data->enable_pkg_pwr_tracking_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
|
||||
if (0 == smc_result) {
|
||||
struct phm_cac_tdp_table *cac_table =
|
||||
table_info->cac_dtp_table;
|
||||
uint32_t default_limit =
|
||||
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
|
||||
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
|
||||
|
||||
if (fiji_set_power_limit(hwmgr, default_limit))
|
||||
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int fiji_disable_power_containment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment) &&
|
||||
data->power_containment_features) {
|
||||
int smc_result;
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_TDCLimit) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_TDCLimitDisable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable TDCLimit in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_DTE) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_DisableDTE));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable DTE in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable PkgPwrTracking in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
data->power_containment_features = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int fiji_power_control_set_level(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
|
||||
int adjust_percent, target_tdp;
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
/* adjustment percentage has already been validated */
|
||||
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
|
||||
hwmgr->platform_descriptor.TDPAdjustment :
|
||||
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
|
||||
/* SMC requested that target_tdp to be 7 bit fraction in DPM table
|
||||
* but message to be 8 bit fraction for messages
|
||||
*/
|
||||
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
|
||||
result = fiji_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 FIJI_POWERTUNE_H
|
||||
#define FIJI_POWERTUNE_H
|
||||
|
||||
enum fiji_pt_config_reg_type {
|
||||
FIJI_CONFIGREG_MMR = 0,
|
||||
FIJI_CONFIGREG_SMC_IND,
|
||||
FIJI_CONFIGREG_DIDT_IND,
|
||||
FIJI_CONFIGREG_CACHE,
|
||||
FIJI_CONFIGREG_MAX
|
||||
};
|
||||
|
||||
/* PowerContainment Features */
|
||||
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
|
||||
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
|
||||
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
|
||||
|
||||
#define DIDT_SQ_CTRL0__UNUSED_0_MASK 0xffffffc0
|
||||
#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT 0x6
|
||||
#define DIDT_TD_CTRL0__UNUSED_0_MASK 0xffffffc0
|
||||
#define DIDT_TD_CTRL0__UNUSED_0__SHIFT 0x6
|
||||
#define DIDT_TCP_CTRL0__UNUSED_0_MASK 0xffffffc0
|
||||
#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT 0x6
|
||||
#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
|
||||
#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
|
||||
#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
|
||||
#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
|
||||
#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
|
||||
#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
|
||||
|
||||
struct fiji_pt_config_reg {
|
||||
uint32_t offset;
|
||||
uint32_t mask;
|
||||
uint32_t shift;
|
||||
uint32_t value;
|
||||
enum fiji_pt_config_reg_type type;
|
||||
};
|
||||
|
||||
struct fiji_pt_defaults
|
||||
{
|
||||
uint8_t SviLoadLineEn;
|
||||
uint8_t SviLoadLineVddC;
|
||||
uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
|
||||
uint8_t TDC_MAWt;
|
||||
uint8_t TdcWaterfallCtl;
|
||||
uint8_t DTEAmbientTempBase;
|
||||
};
|
||||
|
||||
void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
|
||||
int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
|
||||
int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr);
|
||||
int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int fiji_enable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int fiji_disable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
|
||||
int fiji_power_control_set_level(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif /* FIJI_POWERTUNE_H */
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 FIJI_THERMAL_H
|
||||
#define FIJI_THERMAL_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define FIJI_THERMAL_HIGH_ALERT_MASK 0x1
|
||||
#define FIJI_THERMAL_LOW_ALERT_MASK 0x2
|
||||
|
||||
#define FIJI_THERMAL_MINIMUM_TEMP_READING -256
|
||||
#define FIJI_THERMAL_MAXIMUM_TEMP_READING 255
|
||||
|
||||
#define FIJI_THERMAL_MINIMUM_ALERT_TEMP 0
|
||||
#define FIJI_THERMAL_MAXIMUM_ALERT_TEMP 255
|
||||
|
||||
#define FDO_PWM_MODE_STATIC 1
|
||||
#define FDO_PWM_MODE_STATIC_RPM 5
|
||||
|
||||
|
||||
extern int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
|
||||
extern int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
|
||||
extern int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
|
||||
extern int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
|
||||
extern int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
|
||||
extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -36,13 +36,13 @@
|
|||
#include "amd_acpi.h"
|
||||
|
||||
extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
|
||||
static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr);
|
||||
static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr);
|
||||
static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr);
|
||||
static int fiji_set_asic_special_caps(struct pp_hwmgr *hwmgr);
|
||||
static int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr);
|
||||
static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr);
|
||||
|
||||
uint8_t convert_to_vid(uint16_t vddc)
|
||||
{
|
||||
|
@ -79,21 +79,32 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
|
|||
case AMDGPU_FAMILY_VI:
|
||||
switch (hwmgr->chip_id) {
|
||||
case CHIP_TOPAZ:
|
||||
iceland_hwmgr_init(hwmgr);
|
||||
topaz_set_asic_special_caps(hwmgr);
|
||||
hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
|
||||
PP_VBI_TIME_SUPPORT_MASK |
|
||||
PP_ENABLE_GFX_CG_THRU_SMU);
|
||||
hwmgr->pp_table_version = PP_TABLE_V0;
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
tonga_hwmgr_init(hwmgr);
|
||||
tonga_set_asic_special_caps(hwmgr);
|
||||
hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
|
||||
PP_VBI_TIME_SUPPORT_MASK);
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
fiji_hwmgr_init(hwmgr);
|
||||
fiji_set_asic_special_caps(hwmgr);
|
||||
hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
|
||||
PP_VBI_TIME_SUPPORT_MASK |
|
||||
PP_ENABLE_GFX_CG_THRU_SMU);
|
||||
break;
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS10:
|
||||
polaris10_hwmgr_init(hwmgr);
|
||||
polaris_set_asic_special_caps(hwmgr);
|
||||
hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
smu7_hwmgr_init(hwmgr);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -388,12 +399,9 @@ int phm_reset_single_dpm_table(void *table,
|
|||
|
||||
struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
|
||||
|
||||
PP_ASSERT_WITH_CODE(count <= max,
|
||||
"Fatal error, can not set up single DPM table entries to exceed max number!",
|
||||
);
|
||||
dpm_table->count = count > max ? max : count;
|
||||
|
||||
dpm_table->count = count;
|
||||
for (i = 0; i < max; i++)
|
||||
for (i = 0; i < dpm_table->count; i++)
|
||||
dpm_table->dpm_level[i].enabled = false;
|
||||
|
||||
return 0;
|
||||
|
@ -713,3 +721,95 @@ int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* power tune caps Assume disabled */
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_RegulatorHot);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_AutomaticDCTransition);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface);
|
||||
|
||||
if (hwmgr->chip_id == CHIP_POLARIS11)
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SPLLShutdownSupport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_set_asic_special_caps(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_UVDPowerGating);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_VCEPowerGating);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_EVV);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "iceland_clockpowergating.h"
|
||||
#include "ppsmc.h"
|
||||
#include "iceland_hwmgr.h"
|
||||
|
||||
int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* iceland does not have MM hardware block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* iceland does not have MM hardware block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* iceland does not have MM hardware block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_phm_powerup_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* iceland does not have MM hardware block */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum
|
||||
PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (block) {
|
||||
case PHM_AsicBlock_UVD_MVC:
|
||||
case PHM_AsicBlock_UVD:
|
||||
case PHM_AsicBlock_UVD_HD:
|
||||
case PHM_AsicBlock_UVD_SD:
|
||||
if (gating == PHM_ClockGateSetting_StaticOff)
|
||||
ret = iceland_phm_powerdown_uvd(hwmgr);
|
||||
else
|
||||
ret = iceland_phm_powerup_uvd(hwmgr);
|
||||
break;
|
||||
case PHM_AsicBlock_GFX:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
|
||||
data->uvd_power_gated = false;
|
||||
data->vce_power_gated = false;
|
||||
|
||||
iceland_phm_powerup_uvd(hwmgr);
|
||||
iceland_phm_powerup_vce(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
if (bgate) {
|
||||
iceland_update_uvd_dpm(hwmgr, true);
|
||||
iceland_phm_powerdown_uvd(hwmgr);
|
||||
} else {
|
||||
iceland_phm_powerup_uvd(hwmgr);
|
||||
iceland_update_uvd_dpm(hwmgr, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
if (bgate)
|
||||
return iceland_phm_powerdown_vce(hwmgr);
|
||||
else
|
||||
return iceland_phm_powerup_vce(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
const uint32_t *msg_id)
|
||||
{
|
||||
/* iceland does not have MM hardware block */
|
||||
return 0;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ICELAND_CLOCK_POWER_GATING_H_
|
||||
#define _ICELAND_CLOCK_POWER_GATING_H_
|
||||
|
||||
#include "iceland_hwmgr.h"
|
||||
#include "pp_asicblocks.h"
|
||||
|
||||
extern int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
|
||||
extern int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
|
||||
#endif /* _ICELAND_CLOCK_POWER_GATING_H_ */
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef ICELAND_DYN_DEFAULTS_H
|
||||
#define ICELAND_DYN_DEFAULTS_H
|
||||
|
||||
enum ICELANDdpm_TrendDetection
|
||||
{
|
||||
ICELANDdpm_TrendDetection_AUTO,
|
||||
ICELANDdpm_TrendDetection_UP,
|
||||
ICELANDdpm_TrendDetection_DOWN
|
||||
};
|
||||
typedef enum ICELANDdpm_TrendDetection ICELANDdpm_TrendDetection;
|
||||
|
||||
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT1 0x000400
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033
|
||||
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000
|
||||
|
||||
|
||||
#define PPICELAND_THERMALPROTECTCOUNTER_DFLT 0x200
|
||||
|
||||
#define PPICELAND_STATICSCREENTHRESHOLDUNIT_DFLT 0
|
||||
|
||||
#define PPICELAND_STATICSCREENTHRESHOLD_DFLT 0x00C8
|
||||
|
||||
#define PPICELAND_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200
|
||||
|
||||
#define PPICELAND_REFERENCEDIVIDER_DFLT 4
|
||||
|
||||
#define PPICELAND_ULVVOLTAGECHANGEDELAY_DFLT 1687
|
||||
|
||||
#define PPICELAND_CGULVPARAMETER_DFLT 0x00040035
|
||||
#define PPICELAND_CGULVCONTROL_DFLT 0x00007450
|
||||
#define PPICELAND_TARGETACTIVITY_DFLT 30
|
||||
#define PPICELAND_MCLK_TARGETACTIVITY_DFLT 10
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
#ifndef ICELAND_HWMGR_H
|
||||
#define ICELAND_HWMGR_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "ppatomctrl.h"
|
||||
#include "ppinterrupt.h"
|
||||
#include "ppsmc.h"
|
||||
#include "iceland_powertune.h"
|
||||
#include "pp_endian.h"
|
||||
#include "smu71_discrete.h"
|
||||
|
||||
#define ICELAND_MAX_HARDWARE_POWERLEVELS 2
|
||||
#define ICELAND_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
|
||||
|
||||
struct iceland_performance_level {
|
||||
uint32_t memory_clock;
|
||||
uint32_t engine_clock;
|
||||
uint16_t pcie_gen;
|
||||
uint16_t pcie_lane;
|
||||
};
|
||||
|
||||
struct _phw_iceland_bacos {
|
||||
uint32_t best_match;
|
||||
uint32_t baco_flags;
|
||||
struct iceland_performance_level performance_level;
|
||||
};
|
||||
typedef struct _phw_iceland_bacos phw_iceland_bacos;
|
||||
|
||||
struct _phw_iceland_uvd_clocks {
|
||||
uint32_t VCLK;
|
||||
uint32_t DCLK;
|
||||
};
|
||||
|
||||
typedef struct _phw_iceland_uvd_clocks phw_iceland_uvd_clocks;
|
||||
|
||||
struct _phw_iceland_vce_clocks {
|
||||
uint32_t EVCLK;
|
||||
uint32_t ECCLK;
|
||||
};
|
||||
|
||||
typedef struct _phw_iceland_vce_clocks phw_iceland_vce_clocks;
|
||||
|
||||
struct iceland_power_state {
|
||||
uint32_t magic;
|
||||
phw_iceland_uvd_clocks uvd_clocks;
|
||||
phw_iceland_vce_clocks vce_clocks;
|
||||
uint32_t sam_clk;
|
||||
uint32_t acp_clk;
|
||||
uint16_t performance_level_count;
|
||||
bool dc_compatible;
|
||||
uint32_t sclk_threshold;
|
||||
struct iceland_performance_level performance_levels[ICELAND_MAX_HARDWARE_POWERLEVELS];
|
||||
};
|
||||
|
||||
struct _phw_iceland_dpm_level {
|
||||
bool enabled;
|
||||
uint32_t value;
|
||||
uint32_t param1;
|
||||
};
|
||||
typedef struct _phw_iceland_dpm_level phw_iceland_dpm_level;
|
||||
|
||||
#define ICELAND_MAX_DEEPSLEEP_DIVIDER_ID 5
|
||||
#define MAX_REGULAR_DPM_NUMBER 8
|
||||
#define ICELAND_MINIMUM_ENGINE_CLOCK 5000
|
||||
|
||||
struct iceland_single_dpm_table {
|
||||
uint32_t count;
|
||||
phw_iceland_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
|
||||
};
|
||||
|
||||
struct iceland_dpm_table {
|
||||
struct iceland_single_dpm_table sclk_table;
|
||||
struct iceland_single_dpm_table mclk_table;
|
||||
struct iceland_single_dpm_table pcie_speed_table;
|
||||
struct iceland_single_dpm_table vddc_table;
|
||||
struct iceland_single_dpm_table vdd_gfx_table;
|
||||
struct iceland_single_dpm_table vdd_ci_table;
|
||||
struct iceland_single_dpm_table mvdd_table;
|
||||
};
|
||||
typedef struct _phw_iceland_dpm_table phw_iceland_dpm_table;
|
||||
|
||||
|
||||
struct _phw_iceland_clock_regisiters {
|
||||
uint32_t vCG_SPLL_FUNC_CNTL;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_2;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_3;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_4;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
|
||||
uint32_t vDLL_CNTL;
|
||||
uint32_t vMCLK_PWRMGT_CNTL;
|
||||
uint32_t vMPLL_AD_FUNC_CNTL;
|
||||
uint32_t vMPLL_DQ_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL_1;
|
||||
uint32_t vMPLL_FUNC_CNTL_2;
|
||||
uint32_t vMPLL_SS1;
|
||||
uint32_t vMPLL_SS2;
|
||||
};
|
||||
typedef struct _phw_iceland_clock_regisiters phw_iceland_clock_registers;
|
||||
|
||||
struct _phw_iceland_voltage_smio_registers {
|
||||
uint32_t vs0_vid_lower_smio_cntl;
|
||||
};
|
||||
typedef struct _phw_iceland_voltage_smio_registers phw_iceland_voltage_smio_registers;
|
||||
|
||||
|
||||
struct _phw_iceland_mc_reg_entry {
|
||||
uint32_t mclk_max;
|
||||
uint32_t mc_data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct _phw_iceland_mc_reg_entry phw_iceland_mc_reg_entry;
|
||||
|
||||
struct _phw_iceland_mc_reg_table {
|
||||
uint8_t last; /* number of registers*/
|
||||
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
|
||||
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
|
||||
phw_iceland_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
|
||||
SMU71_Discrete_MCRegisterAddress mc_reg_address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct _phw_iceland_mc_reg_table phw_iceland_mc_reg_table;
|
||||
|
||||
#define DISABLE_MC_LOADMICROCODE 1
|
||||
#define DISABLE_MC_CFGPROGRAMMING 2
|
||||
|
||||
|
||||
/*Ultra Low Voltage parameter structure */
|
||||
struct phw_iceland_ulv_parm{
|
||||
bool ulv_supported;
|
||||
uint32_t ch_ulv_parameter;
|
||||
uint32_t ulv_volt_change_delay;
|
||||
struct iceland_performance_level ulv_power_level;
|
||||
};
|
||||
|
||||
#define ICELAND_MAX_LEAKAGE_COUNT 8
|
||||
|
||||
struct phw_iceland_leakage_voltage {
|
||||
uint16_t count;
|
||||
uint16_t leakage_id[ICELAND_MAX_LEAKAGE_COUNT];
|
||||
uint16_t actual_voltage[ICELAND_MAX_LEAKAGE_COUNT];
|
||||
};
|
||||
|
||||
struct _phw_iceland_display_timing {
|
||||
uint32_t min_clock_insr;
|
||||
uint32_t num_existing_displays;
|
||||
};
|
||||
typedef struct _phw_iceland_display_timing phw_iceland_display_timing;
|
||||
|
||||
|
||||
struct phw_iceland_thermal_temperature_setting
|
||||
{
|
||||
long temperature_low;
|
||||
long temperature_high;
|
||||
long temperature_shutdown;
|
||||
};
|
||||
|
||||
struct _phw_iceland_dpmlevel_enable_mask {
|
||||
uint32_t uvd_dpm_enable_mask;
|
||||
uint32_t vce_dpm_enable_mask;
|
||||
uint32_t acp_dpm_enable_mask;
|
||||
uint32_t samu_dpm_enable_mask;
|
||||
uint32_t sclk_dpm_enable_mask;
|
||||
uint32_t mclk_dpm_enable_mask;
|
||||
uint32_t pcie_dpm_enable_mask;
|
||||
};
|
||||
typedef struct _phw_iceland_dpmlevel_enable_mask phw_iceland_dpmlevel_enable_mask;
|
||||
|
||||
struct _phw_iceland_pcie_perf_range {
|
||||
uint16_t max;
|
||||
uint16_t min;
|
||||
};
|
||||
typedef struct _phw_iceland_pcie_perf_range phw_iceland_pcie_perf_range;
|
||||
|
||||
struct _phw_iceland_vbios_boot_state {
|
||||
uint16_t mvdd_bootup_value;
|
||||
uint16_t vddc_bootup_value;
|
||||
uint16_t vddci_bootup_value;
|
||||
uint16_t vddgfx_bootup_value;
|
||||
uint32_t sclk_bootup_value;
|
||||
uint32_t mclk_bootup_value;
|
||||
uint16_t pcie_gen_bootup_value;
|
||||
uint16_t pcie_lane_bootup_value;
|
||||
};
|
||||
typedef struct _phw_iceland_vbios_boot_state phw_iceland_vbios_boot_state;
|
||||
|
||||
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
|
||||
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
|
||||
#define DPMTABLE_UPDATE_SCLK 0x00000004
|
||||
#define DPMTABLE_UPDATE_MCLK 0x00000008
|
||||
|
||||
/* We need to review which fields are needed. */
|
||||
/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
|
||||
struct iceland_hwmgr {
|
||||
struct iceland_dpm_table dpm_table;
|
||||
struct iceland_dpm_table golden_dpm_table;
|
||||
|
||||
uint32_t voting_rights_clients0;
|
||||
uint32_t voting_rights_clients1;
|
||||
uint32_t voting_rights_clients2;
|
||||
uint32_t voting_rights_clients3;
|
||||
uint32_t voting_rights_clients4;
|
||||
uint32_t voting_rights_clients5;
|
||||
uint32_t voting_rights_clients6;
|
||||
uint32_t voting_rights_clients7;
|
||||
uint32_t static_screen_threshold_unit;
|
||||
uint32_t static_screen_threshold;
|
||||
uint32_t voltage_control;
|
||||
uint32_t vdd_gfx_control;
|
||||
|
||||
uint32_t vddc_vddci_delta;
|
||||
uint32_t vddc_vddgfx_delta;
|
||||
|
||||
struct pp_interrupt_registration_info internal_high_thermal_interrupt_info;
|
||||
struct pp_interrupt_registration_info internal_low_thermal_interrupt_info;
|
||||
struct pp_interrupt_registration_info smc_to_host_interrupt_info;
|
||||
uint32_t active_auto_throttle_sources;
|
||||
|
||||
struct pp_interrupt_registration_info external_throttle_interrupt;
|
||||
irq_handler_func_t external_throttle_callback;
|
||||
void *external_throttle_context;
|
||||
|
||||
struct pp_interrupt_registration_info ctf_interrupt_info;
|
||||
irq_handler_func_t ctf_callback;
|
||||
void *ctf_context;
|
||||
|
||||
phw_iceland_clock_registers clock_registers;
|
||||
phw_iceland_voltage_smio_registers voltage_smio_registers;
|
||||
|
||||
bool is_memory_GDDR5;
|
||||
uint16_t acpi_vddc;
|
||||
bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
|
||||
uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
|
||||
uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
|
||||
uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
|
||||
uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
|
||||
uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
|
||||
struct phw_iceland_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
|
||||
struct phw_iceland_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
|
||||
struct phw_iceland_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
|
||||
|
||||
uint32_t mvdd_control;
|
||||
uint32_t vddc_mask_low;
|
||||
uint32_t mvdd_mask_low;
|
||||
uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
|
||||
uint16_t min_vddc_in_pp_table;
|
||||
uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
|
||||
uint16_t min_vddci_in_pp_table;
|
||||
uint32_t mclk_strobe_mode_threshold;
|
||||
uint32_t mclk_stutter_mode_threshold;
|
||||
uint32_t mclk_edc_enable_threshold;
|
||||
uint32_t mclk_edc_wr_enable_threshold;
|
||||
bool is_uvd_enabled;
|
||||
bool is_xdma_enabled;
|
||||
phw_iceland_vbios_boot_state vbios_boot_state;
|
||||
|
||||
bool battery_state;
|
||||
bool is_tlu_enabled;
|
||||
bool pcie_performance_request;
|
||||
|
||||
/* -------------- SMC SRAM Address of firmware header tables ----------------*/
|
||||
uint32_t sram_end; /* The first address after the SMC SRAM. */
|
||||
uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
|
||||
uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
|
||||
uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
|
||||
uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
|
||||
uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
|
||||
uint32_t ulv_settings_start;
|
||||
SMU71_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
|
||||
SMU71_Discrete_MCRegisters mc_reg_table;
|
||||
SMU71_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
|
||||
|
||||
/* -------------- Stuff originally coming from Evergreen --------------------*/
|
||||
phw_iceland_mc_reg_table iceland_mc_reg_table;
|
||||
uint32_t vdd_ci_control;
|
||||
pp_atomctrl_voltage_table vddc_voltage_table;
|
||||
pp_atomctrl_voltage_table vddci_voltage_table;
|
||||
pp_atomctrl_voltage_table vddgfx_voltage_table;
|
||||
pp_atomctrl_voltage_table mvdd_voltage_table;
|
||||
|
||||
uint32_t mgcg_cgtt_local2;
|
||||
uint32_t mgcg_cgtt_local3;
|
||||
uint32_t gpio_debug;
|
||||
uint32_t mc_micro_code_feature;
|
||||
uint32_t highest_mclk;
|
||||
uint16_t acpi_vdd_ci;
|
||||
uint8_t mvdd_high_index;
|
||||
uint8_t mvdd_low_index;
|
||||
bool dll_defaule_on;
|
||||
bool performance_request_registered;
|
||||
|
||||
/* ----------------- Low Power Features ---------------------*/
|
||||
phw_iceland_bacos bacos;
|
||||
struct phw_iceland_ulv_parm ulv;
|
||||
|
||||
/* ----------------- CAC Stuff ---------------------*/
|
||||
uint32_t cac_table_start;
|
||||
bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
|
||||
bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
|
||||
bool cac_enabled;
|
||||
|
||||
/* ----------------- DPM2 Parameters ---------------------*/
|
||||
uint32_t power_containment_features;
|
||||
bool enable_bapm_feature;
|
||||
bool enable_dte_feature;
|
||||
bool enable_tdc_limit_feature;
|
||||
bool enable_pkg_pwr_tracking_feature;
|
||||
bool disable_uvd_power_tune_feature;
|
||||
struct iceland_pt_defaults *power_tune_defaults;
|
||||
SMU71_Discrete_PmFuses power_tune_table;
|
||||
uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
|
||||
uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
|
||||
|
||||
/* ----------------- Phase Shedding ---------------------*/
|
||||
bool vddc_phase_shed_control;
|
||||
|
||||
/* --------------------- DI/DT --------------------------*/
|
||||
phw_iceland_display_timing display_timing;
|
||||
|
||||
/* --------- ReadRegistry data for memory and engine clock margins ---- */
|
||||
uint32_t engine_clock_data;
|
||||
uint32_t memory_clock_data;
|
||||
|
||||
/* -------- Thermal Temperature Setting --------------*/
|
||||
struct phw_iceland_thermal_temperature_setting thermal_temp_setting;
|
||||
phw_iceland_dpmlevel_enable_mask dpm_level_enable_mask;
|
||||
|
||||
uint32_t need_update_smu7_dpm_table;
|
||||
uint32_t sclk_dpm_key_disabled;
|
||||
uint32_t mclk_dpm_key_disabled;
|
||||
uint32_t pcie_dpm_key_disabled;
|
||||
/* used to store the previous dal min sclock */
|
||||
uint32_t min_engine_clocks;
|
||||
phw_iceland_pcie_perf_range pcie_gen_performance;
|
||||
phw_iceland_pcie_perf_range pcie_lane_performance;
|
||||
phw_iceland_pcie_perf_range pcie_gen_power_saving;
|
||||
phw_iceland_pcie_perf_range pcie_lane_power_saving;
|
||||
bool use_pcie_performance_levels;
|
||||
bool use_pcie_power_saving_levels;
|
||||
/* percentage value from 0-100, default 50 */
|
||||
uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS];
|
||||
uint32_t mclk_activity_target;
|
||||
uint32_t low_sclk_interrupt_threshold;
|
||||
uint32_t last_mclk_dpm_enable_mask;
|
||||
bool uvd_enabled;
|
||||
uint32_t pcc_monitor_enabled;
|
||||
|
||||
/* --------- Power Gating States ------------*/
|
||||
bool uvd_power_gated; /* 1: gated, 0:not gated */
|
||||
bool vce_power_gated; /* 1: gated, 0:not gated */
|
||||
bool samu_power_gated; /* 1: gated, 0:not gated */
|
||||
bool acp_power_gated; /* 1: gated, 0:not gated */
|
||||
bool pg_acp_init;
|
||||
|
||||
/* soft pptable for re-uploading into smu */
|
||||
void *soft_pp_table;
|
||||
};
|
||||
|
||||
typedef struct iceland_hwmgr iceland_hwmgr;
|
||||
|
||||
int iceland_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
int iceland_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
uint32_t iceland_get_xclk(struct pp_hwmgr *hwmgr);
|
||||
int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr);
|
||||
int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#define ICELAND_DPM2_NEAR_TDP_DEC 10
|
||||
#define ICELAND_DPM2_ABOVE_SAFE_INC 5
|
||||
#define ICELAND_DPM2_BELOW_SAFE_INC 20
|
||||
|
||||
/*
|
||||
* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size
|
||||
* is 128, then this value should be Log2(128) = 7.
|
||||
*/
|
||||
#define ICELAND_DPM2_LTA_WINDOW_SIZE 7
|
||||
|
||||
#define ICELAND_DPM2_LTS_TRUNCATE 0
|
||||
|
||||
#define ICELAND_DPM2_TDP_SAFE_LIMIT_PERCENT 80 // Maximum 100
|
||||
|
||||
#define ICELAND_DPM2_MAXPS_PERCENT_H 90 // Maximum 0xFF
|
||||
#define ICELAND_DPM2_MAXPS_PERCENT_M 90 // Maximum 0xFF
|
||||
|
||||
#define ICELAND_DPM2_PWREFFICIENCYRATIO_MARGIN 50
|
||||
|
||||
#define ICELAND_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
|
||||
#define ICELAND_DPM2_SQ_RAMP_MIN_POWER 0x12
|
||||
#define ICELAND_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
|
||||
#define ICELAND_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
|
||||
#define ICELAND_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
|
||||
|
||||
#define ICELAND_VOLTAGE_CONTROL_NONE 0x0
|
||||
#define ICELAND_VOLTAGE_CONTROL_BY_GPIO 0x1
|
||||
#define ICELAND_VOLTAGE_CONTROL_BY_SVID2 0x2
|
||||
|
||||
/* convert to Q8.8 format for firmware */
|
||||
#define ICELAND_Q88_FORMAT_CONVERSION_UNIT 256
|
||||
|
||||
#define ICELAND_UNUSED_GPIO_PIN 0x7F
|
||||
|
||||
#endif
|
|
@ -1,490 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "hwmgr.h"
|
||||
#include "smumgr.h"
|
||||
#include "iceland_hwmgr.h"
|
||||
#include "iceland_powertune.h"
|
||||
#include "iceland_smumgr.h"
|
||||
#include "smu71_discrete.h"
|
||||
#include "smu71.h"
|
||||
#include "pp_debug.h"
|
||||
#include "cgs_common.h"
|
||||
#include "pp_endian.h"
|
||||
|
||||
#include "bif/bif_5_0_d.h"
|
||||
#include "bif/bif_5_0_sh_mask.h"
|
||||
|
||||
#define VOLTAGE_SCALE 4
|
||||
#define POWERTUNE_DEFAULT_SET_MAX 1
|
||||
|
||||
#define DEVICE_ID_VI_ICELAND_M_6900 0x6900
|
||||
#define DEVICE_ID_VI_ICELAND_M_6901 0x6901
|
||||
#define DEVICE_ID_VI_ICELAND_M_6902 0x6902
|
||||
#define DEVICE_ID_VI_ICELAND_M_6903 0x6903
|
||||
|
||||
|
||||
struct iceland_pt_defaults defaults_iceland =
|
||||
{
|
||||
/*
|
||||
* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,
|
||||
* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT
|
||||
*/
|
||||
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
|
||||
{ 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 },
|
||||
{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
|
||||
};
|
||||
|
||||
/* 35W - XT, XTL */
|
||||
struct iceland_pt_defaults defaults_icelandxt =
|
||||
{
|
||||
/*
|
||||
* sviLoadLIneEn, SviLoadLineVddC,
|
||||
* TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
|
||||
* TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
|
||||
* BAPM_TEMP_GRADIENT
|
||||
*/
|
||||
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
|
||||
{ 0xA7, 0x0, 0x0, 0xB5, 0x0, 0x0, 0x9F, 0x0, 0x0, 0xD6, 0x0, 0x0, 0xD7, 0x0, 0x0},
|
||||
{ 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
|
||||
};
|
||||
|
||||
/* 25W - PRO, LE */
|
||||
struct iceland_pt_defaults defaults_icelandpro =
|
||||
{
|
||||
/*
|
||||
* sviLoadLIneEn, SviLoadLineVddC,
|
||||
* TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
|
||||
* TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
|
||||
* BAPM_TEMP_GRADIENT
|
||||
*/
|
||||
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
|
||||
{ 0xB7, 0x0, 0x0, 0xC3, 0x0, 0x0, 0xB5, 0x0, 0x0, 0xEA, 0x0, 0x0, 0xE6, 0x0, 0x0},
|
||||
{ 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
|
||||
};
|
||||
|
||||
void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
uint32_t tmp = 0;
|
||||
struct cgs_system_info sys_info = {0};
|
||||
uint32_t pdev_id;
|
||||
|
||||
sys_info.size = sizeof(struct cgs_system_info);
|
||||
sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV;
|
||||
cgs_query_system_info(hwmgr->device, &sys_info);
|
||||
pdev_id = (uint32_t)sys_info.value;
|
||||
|
||||
switch (pdev_id) {
|
||||
case DEVICE_ID_VI_ICELAND_M_6900:
|
||||
case DEVICE_ID_VI_ICELAND_M_6903:
|
||||
data->power_tune_defaults = &defaults_icelandxt;
|
||||
break;
|
||||
|
||||
case DEVICE_ID_VI_ICELAND_M_6901:
|
||||
case DEVICE_ID_VI_ICELAND_M_6902:
|
||||
data->power_tune_defaults = &defaults_icelandpro;
|
||||
break;
|
||||
default:
|
||||
/* TODO: need to assign valid defaults */
|
||||
data->power_tune_defaults = &defaults_iceland;
|
||||
pr_warning("Unknown V.I. Device ID.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assume disabled */
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
data->ul_dte_tj_offset = tmp;
|
||||
|
||||
if (!tmp) {
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
data->fast_watermark_threshold = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
tmp = 1;
|
||||
data->enable_dte_feature = tmp ? false : true;
|
||||
data->enable_tdc_limit_feature = tmp ? true : false;
|
||||
data->enable_pkg_pwr_tracking_feature = tmp ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
struct iceland_pt_defaults *defaults = data->power_tune_defaults;
|
||||
SMU71_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
|
||||
struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
|
||||
struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
|
||||
uint16_t *def1, *def2;
|
||||
int i, j, k;
|
||||
|
||||
/*
|
||||
* TDP number of fraction bits are changed from 8 to 7 for Iceland
|
||||
* as requested by SMC team
|
||||
*/
|
||||
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
|
||||
dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
|
||||
|
||||
dpm_table->DTETjOffset = (uint8_t)data->ul_dte_tj_offset;
|
||||
|
||||
dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
|
||||
dpm_table->GpuTjHyst = 8;
|
||||
|
||||
dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
|
||||
|
||||
/* The following are for new Iceland Multi-input fan/thermal control */
|
||||
if(NULL != ppm) {
|
||||
dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
|
||||
dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
|
||||
} else {
|
||||
dpm_table->PPM_PkgPwrLimit = 0;
|
||||
dpm_table->PPM_TemperatureLimit = 0;
|
||||
}
|
||||
|
||||
CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
|
||||
CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
|
||||
|
||||
dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
|
||||
def1 = defaults->bapmti_r;
|
||||
def2 = defaults->bapmti_rc;
|
||||
|
||||
for (i = 0; i < SMU71_DTE_ITERATIONS; i++) {
|
||||
for (j = 0; j < SMU71_DTE_SOURCES; j++) {
|
||||
for (k = 0; k < SMU71_DTE_SINKS; k++) {
|
||||
dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
|
||||
dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
|
||||
def1++;
|
||||
def2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_svi_load_line(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
|
||||
data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
|
||||
data->power_tune_table.SviLoadLineTrimVddC = 3;
|
||||
data->power_tune_table.SviLoadLineOffsetVddC = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_tdc_limit(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint16_t tdc_limit;
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
/* TDC number of fraction bits are changed from 8 to 7
|
||||
* for Iceland as requested by SMC team
|
||||
*/
|
||||
tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
|
||||
data->power_tune_table.TDC_VDDC_PkgLimit =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
|
||||
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
|
||||
defaults->tdc_vddc_throttle_release_limit_perc;
|
||||
data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
|
||||
uint32_t temp;
|
||||
|
||||
if (iceland_read_smc_sram_dword(hwmgr->smumgr,
|
||||
fuse_table_offset +
|
||||
offsetof(SMU71_Discrete_PmFuses, TdcWaterfallCtl),
|
||||
(uint32_t *)&temp, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
|
||||
return -EINVAL);
|
||||
else
|
||||
data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int i;
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
|
||||
/* Currently not used. Set all to zero. */
|
||||
for (i = 0; i < 8; i++)
|
||||
data->power_tune_table.GnbLPML[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
|
||||
uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
|
||||
struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
|
||||
|
||||
HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
|
||||
LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
|
||||
|
||||
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
|
||||
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
uint32_t pm_fuse_table_offset;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
if (iceland_read_smc_sram_dword(hwmgr->smumgr,
|
||||
SMU71_FIRMWARE_HEADER_LOCATION +
|
||||
offsetof(SMU71_Firmware_Header, PmFuseTable),
|
||||
&pm_fuse_table_offset, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to get pm_fuse_table_offset Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW0 - DW3 */
|
||||
if (iceland_populate_bapm_vddc_vid_sidd(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate bapm vddc vid Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW4 - DW5 */
|
||||
if (iceland_populate_vddc_vid(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate vddc vid Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW6 */
|
||||
if (iceland_populate_svi_load_line(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate SviLoadLine Failed!",
|
||||
return -EINVAL);
|
||||
/* DW7 */
|
||||
if (iceland_populate_tdc_limit(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TDCLimit Failed!", return -EINVAL);
|
||||
/* DW8 */
|
||||
if (iceland_populate_dw8(hwmgr, pm_fuse_table_offset))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TdcWaterfallCtl, "
|
||||
"LPMLTemperature Min and Max Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW9-DW12 */
|
||||
if (0 != iceland_populate_temperature_scaler(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate LPMLTemperatureScaler Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW13-DW16 */
|
||||
if (iceland_populate_gnb_lpml(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW17 */
|
||||
if (iceland_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Min and Max Vid Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW18 */
|
||||
if (iceland_populate_bapm_vddc_base_leakage_sidd(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
if (iceland_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
|
||||
(uint8_t *)&data->power_tune_table,
|
||||
sizeof(struct SMU71_Discrete_PmFuses), data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to download PmFuseTable Failed!",
|
||||
return -EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC)) {
|
||||
int smc_result;
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableCac));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable CAC in SMC.", result = -1);
|
||||
|
||||
data->cac_enabled = (0 == smc_result) ? true : false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iceland_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if(data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_PkgPwrSetLimit, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
|
||||
{
|
||||
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
|
||||
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
|
||||
}
|
||||
|
||||
int iceland_enable_power_containment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
SMU71_Discrete_DpmTable *dpm_table = &data->smc_state_table;
|
||||
int smc_result;
|
||||
int result = 0;
|
||||
uint32_t is_asic_kicker;
|
||||
|
||||
data->power_containment_features = 0;
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
is_asic_kicker = cgs_read_register(hwmgr->device, mmCC_BIF_BX_STRAP2);
|
||||
is_asic_kicker = (is_asic_kicker >> 12) & 0x01;
|
||||
|
||||
if (data->enable_bapm_feature &&
|
||||
(!is_asic_kicker ||
|
||||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc))) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableDTE));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable BAPM in SMC.", result = -1;);
|
||||
if (0 == smc_result)
|
||||
data->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
|
||||
}
|
||||
|
||||
if (is_asic_kicker && !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc))
|
||||
dpm_table->DTEMode = 2;
|
||||
|
||||
if (data->enable_tdc_limit_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable TDCLimit in SMC.", result = -1;);
|
||||
if (0 == smc_result)
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_TDCLimit;
|
||||
}
|
||||
|
||||
if (data->enable_pkg_pwr_tracking_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((0 == smc_result),
|
||||
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
|
||||
if (0 == smc_result) {
|
||||
struct phm_cac_tdp_table *cac_table =
|
||||
hwmgr->dyn_state.cac_dtp_table;
|
||||
uint32_t default_limit =
|
||||
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
|
||||
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
|
||||
|
||||
if (iceland_set_power_limit(hwmgr, default_limit))
|
||||
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int iceland_power_control_set_level(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
|
||||
int adjust_percent, target_tdp;
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
/* adjustment percentage has already been validated */
|
||||
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
|
||||
hwmgr->platform_descriptor.TDPAdjustment :
|
||||
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
|
||||
/*
|
||||
* SMC requested that target_tdp to be 7 bit fraction in DPM table
|
||||
* but message to be 8 bit fraction for messages
|
||||
*/
|
||||
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
|
||||
result = iceland_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
#ifndef ICELAND_POWERTUNE_H
|
||||
#define ICELAND_POWERTUNE_H
|
||||
|
||||
#include "smu71.h"
|
||||
|
||||
enum iceland_pt_config_reg_type {
|
||||
ICELAND_CONFIGREG_MMR = 0,
|
||||
ICELAND_CONFIGREG_SMC_IND,
|
||||
ICELAND_CONFIGREG_DIDT_IND,
|
||||
ICELAND_CONFIGREG_CACHE,
|
||||
ICELAND_CONFIGREG_MAX
|
||||
};
|
||||
|
||||
/* PowerContainment Features */
|
||||
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
|
||||
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
|
||||
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
|
||||
#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
|
||||
|
||||
struct iceland_pt_config_reg {
|
||||
uint32_t offset;
|
||||
uint32_t mask;
|
||||
uint32_t shift;
|
||||
uint32_t value;
|
||||
enum iceland_pt_config_reg_type type;
|
||||
};
|
||||
|
||||
struct iceland_pt_defaults
|
||||
{
|
||||
uint8_t svi_load_line_en;
|
||||
uint8_t svi_load_line_vddc;
|
||||
uint8_t tdc_vddc_throttle_release_limit_perc;
|
||||
uint8_t tdc_mawt;
|
||||
uint8_t tdc_waterfall_ctl;
|
||||
uint8_t dte_ambient_temp_base;
|
||||
uint32_t display_cac;
|
||||
uint32_t bamp_temp_gradient;
|
||||
uint16_t bapmti_r[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
|
||||
uint16_t bapmti_rc[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
|
||||
};
|
||||
|
||||
void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
|
||||
int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
|
||||
int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr);
|
||||
int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int iceland_enable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int iceland_power_control_set_level(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif /* ICELAND_POWERTUNE_H */
|
||||
|
|
@ -1,595 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
#include <asm/div64.h>
|
||||
#include "iceland_thermal.h"
|
||||
#include "iceland_hwmgr.h"
|
||||
#include "iceland_smumgr.h"
|
||||
#include "atombios.h"
|
||||
#include "ppsmc.h"
|
||||
|
||||
#include "gmc/gmc_8_1_d.h"
|
||||
#include "gmc/gmc_8_1_sh_mask.h"
|
||||
|
||||
#include "bif/bif_5_0_d.h"
|
||||
#include "bif/bif_5_0_sh_mask.h"
|
||||
|
||||
#include "smu/smu_7_1_1_d.h"
|
||||
#include "smu/smu_7_1_1_sh_mask.h"
|
||||
|
||||
|
||||
/**
|
||||
* Get Fan Speed Control Parameters.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pSpeed is the address of the structure where the result is to be placed.
|
||||
* @exception Always succeeds except if we cannot zero out the output structure.
|
||||
*/
|
||||
int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
||||
struct phm_fan_speed_info *fan_speed_info)
|
||||
{
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
fan_speed_info->supports_percent_read = true;
|
||||
fan_speed_info->supports_percent_write = true;
|
||||
fan_speed_info->min_percent = 0;
|
||||
fan_speed_info->max_percent = 100;
|
||||
|
||||
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
|
||||
fan_speed_info->supports_rpm_read = true;
|
||||
fan_speed_info->supports_rpm_write = true;
|
||||
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
|
||||
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
|
||||
} else {
|
||||
fan_speed_info->min_rpm = 0;
|
||||
fan_speed_info->max_rpm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Fan Speed in percent.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pSpeed is the address of the structure where the result is to be placed.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
|
||||
|
||||
if (0 == duty100)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
tmp64 = (uint64_t)duty * 100;
|
||||
do_div(tmp64, duty100);
|
||||
*speed = (uint32_t)tmp64;
|
||||
|
||||
if (*speed > 100)
|
||||
*speed = 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Fan Speed in RPM.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the address of the structure where the result is to be placed.
|
||||
* @exception Returns not supported if no fan is found or if pulses per revolution are not set
|
||||
*/
|
||||
int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
||||
{
|
||||
|
||||
if (hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
|
||||
hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = false;
|
||||
}
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed Control to default mode.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
static int iceland_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iceland_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in percent.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (0% - 100%) to be set.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return -EINVAL;
|
||||
|
||||
if (speed > 100) {
|
||||
pr_warning("Cannot set more than 100%% duty cycle. Set it to 100.\n");
|
||||
speed = 100;
|
||||
}
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
|
||||
iceland_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (0 == duty100)
|
||||
return -EINVAL;
|
||||
|
||||
tmp64 = (uint64_t)speed * duty100;
|
||||
do_div(tmp64, 100);
|
||||
duty = (uint32_t)tmp64;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
|
||||
|
||||
return iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed to default.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Always succeeds.
|
||||
*/
|
||||
int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
result = iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
if (0 == result)
|
||||
result = iceland_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
} else
|
||||
result = iceland_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in RPM.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (min - max) to be set.
|
||||
* @exception Fails is the speed not lie between min and max.
|
||||
*/
|
||||
int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the remote temperature from the SIslands thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
|
||||
|
||||
/*
|
||||
* Bit 9 means the reading is lower than the lowest usable
|
||||
* value.
|
||||
*/
|
||||
if (0 != (0x200 & temp))
|
||||
temp = ICELAND_THERMAL_MAXIMUM_TEMP_READING;
|
||||
else
|
||||
temp = (temp & 0x1ff);
|
||||
|
||||
temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the requested temperature range for high and low alert signals
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @param range Temperature range to be programmed for high and low alert signals
|
||||
* @exception PP_Result_BadInput if the input data is not valid.
|
||||
*/
|
||||
static int iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
|
||||
{
|
||||
uint32_t low = ICELAND_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
uint32_t high = ICELAND_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
if (low < low_temp)
|
||||
low = low_temp;
|
||||
if (high > high_temp)
|
||||
high = high_temp;
|
||||
|
||||
if (low > high)
|
||||
return -EINVAL;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs thermal controller one-time setting registers
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int iceland_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_CTRL, EDGE_PER_REV,
|
||||
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable thermal alerts on the RV770 thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert &= ~(ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to enable internal thermal interrupts */
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable thermal alerts on the RV770 thermal controller.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert |= (ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to disable internal thermal interrupts */
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitialize the thermal controller.
|
||||
* Currently just disables alerts.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = iceland_thermal_disable_alert(hwmgr);
|
||||
|
||||
if (result)
|
||||
pr_warning("Failed to disable thermal alerts!\n");
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
iceland_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the fan table to control the fan using the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
|
||||
SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
|
||||
uint32_t duty100;
|
||||
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
|
||||
uint16_t fdo_min, slope1, slope2;
|
||||
uint32_t reference_clock;
|
||||
int res;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
|
||||
return 0;
|
||||
|
||||
if (0 == data->fan_table_start) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (0 == duty100) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
|
||||
do_div(tmp64, 10000);
|
||||
fdo_min = (uint16_t)tmp64;
|
||||
|
||||
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
|
||||
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
|
||||
|
||||
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
|
||||
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
|
||||
|
||||
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
|
||||
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
|
||||
|
||||
fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
|
||||
fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
|
||||
fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
|
||||
|
||||
fan_table.Slope1 = cpu_to_be16(slope1);
|
||||
fan_table.Slope2 = cpu_to_be16(slope2);
|
||||
|
||||
fan_table.FdoMin = cpu_to_be16(fdo_min);
|
||||
|
||||
fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
|
||||
|
||||
fan_table.HystUp = cpu_to_be16(1);
|
||||
|
||||
fan_table.HystSlope = cpu_to_be16(1);
|
||||
|
||||
fan_table.TempRespLim = cpu_to_be16(5);
|
||||
|
||||
reference_clock = iceland_get_xclk(hwmgr);
|
||||
|
||||
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
|
||||
|
||||
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
|
||||
|
||||
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
|
||||
|
||||
//fan_table.FanControl_GL_Flag = 1;
|
||||
|
||||
res = iceland_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
|
||||
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
|
||||
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
|
||||
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
|
||||
|
||||
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
|
||||
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
|
||||
|
||||
if (0 != res)
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the fan control on the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_iceland_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
|
||||
* Make sure that we still think controlling the fan is OK.
|
||||
*/
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
iceland_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set temperature range for high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
static int tf_iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
|
||||
|
||||
if (range == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return iceland_thermal_set_temperature_range(hwmgr, range->min, range->max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs one-time setting registers
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from initialize thermal controller routine
|
||||
*/
|
||||
static int tf_iceland_thermal_initialize(struct pp_hwmgr *hwmgr, void *input,
|
||||
void *output, void *storage, int result)
|
||||
{
|
||||
return iceland_thermal_initialize(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from enable alert routine
|
||||
*/
|
||||
static int tf_iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return iceland_thermal_enable_alert(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from disable alert routine
|
||||
*/
|
||||
static int tf_iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return iceland_thermal_disable_alert(hwmgr);
|
||||
}
|
||||
|
||||
static const struct phm_master_table_item iceland_thermal_start_thermal_controller_master_list[] = {
|
||||
{ NULL, tf_iceland_thermal_initialize },
|
||||
{ NULL, tf_iceland_thermal_set_temperature_range },
|
||||
{ NULL, tf_iceland_thermal_enable_alert },
|
||||
/*
|
||||
* We should restrict performance levels to low before we halt
|
||||
* the SMC. On the other hand we are still in boot state when
|
||||
* we do this so it would be pointless. If this assumption
|
||||
* changes we have to revisit this table.
|
||||
*/
|
||||
{ NULL, tf_iceland_thermal_setup_fan_table},
|
||||
{ NULL, tf_iceland_thermal_start_smc_fan_control},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header iceland_thermal_start_thermal_controller_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
iceland_thermal_start_thermal_controller_master_list
|
||||
};
|
||||
|
||||
static const struct phm_master_table_item iceland_thermal_set_temperature_range_master_list[] = {
|
||||
{ NULL, tf_iceland_thermal_disable_alert},
|
||||
{ NULL, tf_iceland_thermal_set_temperature_range},
|
||||
{ NULL, tf_iceland_thermal_enable_alert},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header iceland_thermal_set_temperature_range_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
iceland_thermal_set_temperature_range_master_list
|
||||
};
|
||||
|
||||
int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
iceland_fan_ctrl_set_default_mode(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thermal controller related functions in the Hardware Manager structure.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @exception Any error code from the low-level communication.
|
||||
*/
|
||||
int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = phm_construct_table(hwmgr, &iceland_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
|
||||
|
||||
if (0 == result) {
|
||||
result = phm_construct_table(hwmgr,
|
||||
&iceland_thermal_start_thermal_controller_master,
|
||||
&(hwmgr->start_thermal_controller));
|
||||
if (0 != result)
|
||||
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
|
||||
}
|
||||
|
||||
if (0 == result)
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui <ray.huang@amd.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ICELAND_THERMAL_H
|
||||
#define ICELAND_THERMAL_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define ICELAND_THERMAL_HIGH_ALERT_MASK 0x1
|
||||
#define ICELAND_THERMAL_LOW_ALERT_MASK 0x2
|
||||
|
||||
#define ICELAND_THERMAL_MINIMUM_TEMP_READING -256
|
||||
#define ICELAND_THERMAL_MAXIMUM_TEMP_READING 255
|
||||
|
||||
#define ICELAND_THERMAL_MINIMUM_ALERT_TEMP 0
|
||||
#define ICELAND_THERMAL_MAXIMUM_ALERT_TEMP 255
|
||||
|
||||
#define FDO_PWM_MODE_STATIC 1
|
||||
#define FDO_PWM_MODE_STATIC_RPM 5
|
||||
|
||||
|
||||
extern int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
|
||||
extern int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
|
||||
extern int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
|
||||
extern int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 POLARIS10_DYN_DEFAULTS_H
|
||||
#define POLARIS10_DYN_DEFAULTS_H
|
||||
|
||||
|
||||
enum Polaris10dpm_TrendDetection {
|
||||
Polaris10Adpm_TrendDetection_AUTO,
|
||||
Polaris10Adpm_TrendDetection_UP,
|
||||
Polaris10Adpm_TrendDetection_DOWN
|
||||
};
|
||||
typedef enum Polaris10dpm_TrendDetection Polaris10dpm_TrendDetection;
|
||||
|
||||
/* We need to fill in the default values */
|
||||
|
||||
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT1 0x000400
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033
|
||||
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000
|
||||
|
||||
|
||||
#define PPPOLARIS10_THERMALPROTECTCOUNTER_DFLT 0x200
|
||||
#define PPPOLARIS10_STATICSCREENTHRESHOLDUNIT_DFLT 0
|
||||
#define PPPOLARIS10_STATICSCREENTHRESHOLD_DFLT 0x00C8
|
||||
#define PPPOLARIS10_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200
|
||||
#define PPPOLARIS10_REFERENCEDIVIDER_DFLT 4
|
||||
|
||||
#define PPPOLARIS10_ULVVOLTAGECHANGEDELAY_DFLT 1687
|
||||
|
||||
#define PPPOLARIS10_CGULVPARAMETER_DFLT 0x00040035
|
||||
#define PPPOLARIS10_CGULVCONTROL_DFLT 0x00007450
|
||||
#define PPPOLARIS10_TARGETACTIVITY_DFLT 50
|
||||
#define PPPOLARIS10_MCLK_TARGETACTIVITY_DFLT 10
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,716 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include "polaris10_thermal.h"
|
||||
#include "polaris10_hwmgr.h"
|
||||
#include "polaris10_smumgr.h"
|
||||
#include "polaris10_ppsmc.h"
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
|
||||
int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
||||
struct phm_fan_speed_info *fan_speed_info)
|
||||
{
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
fan_speed_info->supports_percent_read = true;
|
||||
fan_speed_info->supports_percent_write = true;
|
||||
fan_speed_info->min_percent = 0;
|
||||
fan_speed_info->max_percent = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
|
||||
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
|
||||
fan_speed_info->supports_rpm_read = true;
|
||||
fan_speed_info->supports_rpm_write = true;
|
||||
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
|
||||
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
|
||||
} else {
|
||||
fan_speed_info->min_rpm = 0;
|
||||
fan_speed_info->max_rpm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
uint32_t *speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_STATUS, FDO_PWM_DUTY);
|
||||
|
||||
if (duty100 == 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
tmp64 = (uint64_t)duty * 100;
|
||||
do_div(tmp64, duty100);
|
||||
*speed = (uint32_t)tmp64;
|
||||
|
||||
if (*speed > 100)
|
||||
*speed = 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
uint32_t tach_period;
|
||||
uint32_t crystal_clock_freq;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
|
||||
(hwmgr->thermal_controller.fanInfo.
|
||||
ucTachometerPulsesPerRevolution == 0))
|
||||
return 0;
|
||||
|
||||
tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_STATUS, TACH_PERIOD);
|
||||
|
||||
if (tach_period == 0)
|
||||
return -EINVAL;
|
||||
|
||||
crystal_clock_freq = tonga_get_xclk(hwmgr);
|
||||
|
||||
*speed = 60 * crystal_clock_freq * 10000 / tach_period;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
||||
{
|
||||
|
||||
if (hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
hwmgr->fan_ctrl_default_mode =
|
||||
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, FDO_PWM_MODE);
|
||||
hwmgr->tmin =
|
||||
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, TMIN);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = false;
|
||||
}
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, TMIN, 0);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, FDO_PWM_MODE, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed Control to default mode.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, TMIN, hwmgr->tmin);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
|
||||
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
|
||||
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_FanSpeedInTableIsRPM))
|
||||
hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usMaxFanRPM);
|
||||
else
|
||||
hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usMaxFanPWM);
|
||||
|
||||
} else {
|
||||
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
|
||||
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
|
||||
}
|
||||
|
||||
if (!result && hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucTargetTemperature)
|
||||
result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetFanTemperatureTarget,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucTargetTemperature);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in percent.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (0% - 100%) to be set.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
uint32_t speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
if (speed > 100)
|
||||
speed = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl))
|
||||
polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (duty100 == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp64 = (uint64_t)speed * duty100;
|
||||
do_div(tmp64, 100);
|
||||
duty = (uint32_t)tmp64;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
|
||||
|
||||
return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed to default.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Always succeeds.
|
||||
*/
|
||||
int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
result = polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
if (!result)
|
||||
result = polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
} else
|
||||
result = polaris10_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in RPM.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (min - max) to be set.
|
||||
* @exception Fails is the speed not lie between min and max.
|
||||
*/
|
||||
int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
uint32_t tach_period;
|
||||
uint32_t crystal_clock_freq;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
|
||||
(hwmgr->thermal_controller.fanInfo.
|
||||
ucTachometerPulsesPerRevolution == 0) ||
|
||||
(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
|
||||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
|
||||
return 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl))
|
||||
polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
crystal_clock_freq = tonga_get_xclk(hwmgr);
|
||||
|
||||
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_STATUS, TACH_PERIOD, tach_period);
|
||||
|
||||
return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the remote temperature from the SIslands thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_MULT_THERMAL_STATUS, CTF_TEMP);
|
||||
|
||||
/* Bit 9 means the reading is lower than the lowest usable value. */
|
||||
if (temp & 0x200)
|
||||
temp = POLARIS10_THERMAL_MAXIMUM_TEMP_READING;
|
||||
else
|
||||
temp = temp & 0x1ff;
|
||||
|
||||
temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the requested temperature range for high and low alert signals
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @param range Temperature range to be programmed for high and low alert signals
|
||||
* @exception PP_Result_BadInput if the input data is not valid.
|
||||
*/
|
||||
static int polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
uint32_t low_temp, uint32_t high_temp)
|
||||
{
|
||||
uint32_t low = POLARIS10_THERMAL_MINIMUM_ALERT_TEMP *
|
||||
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
uint32_t high = POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP *
|
||||
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
if (low < low_temp)
|
||||
low = low_temp;
|
||||
if (high > high_temp)
|
||||
high = high_temp;
|
||||
|
||||
if (low > high)
|
||||
return -EINVAL;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, DIG_THERM_INTH,
|
||||
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, DIG_THERM_INTL,
|
||||
(low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_CTRL, DIG_THERM_DPM,
|
||||
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs thermal controller one-time setting registers
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_CTRL, EDGE_PER_REV,
|
||||
hwmgr->thermal_controller.fanInfo.
|
||||
ucTachometerPulsesPerRevolution - 1);
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable thermal alerts on the RV770 thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert &= ~(POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to enable internal thermal interrupts */
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable thermal alerts on the RV770 thermal controller.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert |= (POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to disable internal thermal interrupts */
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitialize the thermal controller.
|
||||
* Currently just disables alerts.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = polaris10_thermal_disable_alert(hwmgr);
|
||||
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
polaris10_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the fan table to control the fan using the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
static int tf_polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
SMU74_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
|
||||
uint32_t duty100;
|
||||
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
|
||||
uint16_t fdo_min, slope1, slope2;
|
||||
uint32_t reference_clock;
|
||||
int res;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (data->fan_table_start == 0) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (duty100 == 0) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usPWMMin * duty100;
|
||||
do_div(tmp64, 10000);
|
||||
fdo_min = (uint16_t)tmp64;
|
||||
|
||||
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
|
||||
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
|
||||
|
||||
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
|
||||
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
|
||||
|
||||
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
|
||||
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
|
||||
|
||||
fan_table.TempMin = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMin) / 100);
|
||||
fan_table.TempMed = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMed) / 100);
|
||||
fan_table.TempMax = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMax) / 100);
|
||||
|
||||
fan_table.Slope1 = cpu_to_be16(slope1);
|
||||
fan_table.Slope2 = cpu_to_be16(slope2);
|
||||
|
||||
fan_table.FdoMin = cpu_to_be16(fdo_min);
|
||||
|
||||
fan_table.HystDown = cpu_to_be16(hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.ucTHyst);
|
||||
|
||||
fan_table.HystUp = cpu_to_be16(1);
|
||||
|
||||
fan_table.HystSlope = cpu_to_be16(1);
|
||||
|
||||
fan_table.TempRespLim = cpu_to_be16(5);
|
||||
|
||||
reference_clock = tonga_get_xclk(hwmgr);
|
||||
|
||||
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.ulCycleDelay *
|
||||
reference_clock) / 1600);
|
||||
|
||||
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
|
||||
|
||||
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
|
||||
hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_MULT_THERMAL_CTRL, TEMP_SEL);
|
||||
|
||||
res = polaris10_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
|
||||
(uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
|
||||
data->sram_end);
|
||||
|
||||
if (!res && hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucMinimumPWMLimit)
|
||||
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetFanMinPwm,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucMinimumPWMLimit);
|
||||
|
||||
if (!res && hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
|
||||
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetFanSclkTarget,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
|
||||
|
||||
if (res)
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the fan control on the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
static int tf_polaris10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
/* If the fantable setup has failed we could have disabled
|
||||
* PHM_PlatformCaps_MicrocodeFanControl even after
|
||||
* this function was included in the table.
|
||||
* Make sure that we still think controlling the fan is OK.
|
||||
*/
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set temperature range for high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
|
||||
|
||||
if (range == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return polaris10_thermal_set_temperature_range(hwmgr, range->min, range->max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs one-time setting registers
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from initialize thermal controller routine
|
||||
*/
|
||||
int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return polaris10_thermal_initialize(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from enable alert routine
|
||||
*/
|
||||
int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return polaris10_thermal_enable_alert(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from disable alert routine
|
||||
*/
|
||||
static int tf_polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return polaris10_thermal_disable_alert(hwmgr);
|
||||
}
|
||||
|
||||
static int tf_polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
int ret;
|
||||
struct pp_smumgr *smumgr = (struct pp_smumgr *)(hwmgr->smumgr);
|
||||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
|
||||
return 0;
|
||||
|
||||
ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting);
|
||||
|
||||
ret = (smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs) == 0) ?
|
||||
0 : -1;
|
||||
|
||||
if (!ret)
|
||||
/* If this param is not changed, this function could fire unnecessarily */
|
||||
smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct phm_master_table_item
|
||||
polaris10_thermal_start_thermal_controller_master_list[] = {
|
||||
{NULL, tf_polaris10_thermal_initialize},
|
||||
{NULL, tf_polaris10_thermal_set_temperature_range},
|
||||
{NULL, tf_polaris10_thermal_enable_alert},
|
||||
{NULL, tf_polaris10_thermal_avfs_enable},
|
||||
/* We should restrict performance levels to low before we halt the SMC.
|
||||
* On the other hand we are still in boot state when we do this
|
||||
* so it would be pointless.
|
||||
* If this assumption changes we have to revisit this table.
|
||||
*/
|
||||
{NULL, tf_polaris10_thermal_setup_fan_table},
|
||||
{NULL, tf_polaris10_thermal_start_smc_fan_control},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header
|
||||
polaris10_thermal_start_thermal_controller_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
polaris10_thermal_start_thermal_controller_master_list
|
||||
};
|
||||
|
||||
static const struct phm_master_table_item
|
||||
polaris10_thermal_set_temperature_range_master_list[] = {
|
||||
{NULL, tf_polaris10_thermal_disable_alert},
|
||||
{NULL, tf_polaris10_thermal_set_temperature_range},
|
||||
{NULL, tf_polaris10_thermal_enable_alert},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header
|
||||
polaris10_thermal_set_temperature_range_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
polaris10_thermal_set_temperature_range_master_list
|
||||
};
|
||||
|
||||
int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
polaris10_fan_ctrl_set_default_mode(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thermal controller related functions in the Hardware Manager structure.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @exception Any error code from the low-level communication.
|
||||
*/
|
||||
int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = phm_construct_table(hwmgr,
|
||||
&polaris10_thermal_set_temperature_range_master,
|
||||
&(hwmgr->set_temperature_range));
|
||||
|
||||
if (!result) {
|
||||
result = phm_construct_table(hwmgr,
|
||||
&polaris10_thermal_start_thermal_controller_master,
|
||||
&(hwmgr->start_thermal_controller));
|
||||
if (result)
|
||||
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
|
||||
}
|
||||
|
||||
if (!result)
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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 _POLARIS10_THERMAL_H_
|
||||
#define _POLARIS10_THERMAL_H_
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define POLARIS10_THERMAL_HIGH_ALERT_MASK 0x1
|
||||
#define POLARIS10_THERMAL_LOW_ALERT_MASK 0x2
|
||||
|
||||
#define POLARIS10_THERMAL_MINIMUM_TEMP_READING -256
|
||||
#define POLARIS10_THERMAL_MAXIMUM_TEMP_READING 255
|
||||
|
||||
#define POLARIS10_THERMAL_MINIMUM_ALERT_TEMP 0
|
||||
#define POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP 255
|
||||
|
||||
#define FDO_PWM_MODE_STATIC 1
|
||||
#define FDO_PWM_MODE_STATIC_RPM 5
|
||||
|
||||
|
||||
extern int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
|
||||
extern int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
|
||||
extern int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
|
||||
extern int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
|
||||
extern int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
|
||||
extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -21,9 +21,53 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "polaris10_clockpowergating.h"
|
||||
#include "smu7_hwmgr.h"
|
||||
#include "smu7_clockpowergating.h"
|
||||
#include "smu7_common.h"
|
||||
|
||||
int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
||||
static int smu7_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
|
||||
PPSMC_MSG_UVDDPM_Enable :
|
||||
PPSMC_MSG_UVDDPM_Disable);
|
||||
}
|
||||
|
||||
static int smu7_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
|
||||
PPSMC_MSG_VCEDPM_Enable :
|
||||
PPSMC_MSG_VCEDPM_Disable);
|
||||
}
|
||||
|
||||
static int smu7_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
|
||||
PPSMC_MSG_SAMUDPM_Enable :
|
||||
PPSMC_MSG_SAMUDPM_Disable);
|
||||
}
|
||||
|
||||
static int smu7_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
if (!bgate)
|
||||
smum_update_smc_table(hwmgr, SMU_UVD_TABLE);
|
||||
return smu7_enable_disable_uvd_dpm(hwmgr, !bgate);
|
||||
}
|
||||
|
||||
static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
if (!bgate)
|
||||
smum_update_smc_table(hwmgr, SMU_VCE_TABLE);
|
||||
return smu7_enable_disable_vce_dpm(hwmgr, !bgate);
|
||||
}
|
||||
|
||||
static int smu7_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
if (!bgate)
|
||||
smum_update_smc_table(hwmgr, SMU_SAMU_TABLE);
|
||||
return smu7_enable_disable_samu_dpm(hwmgr, !bgate);
|
||||
}
|
||||
|
||||
int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_uvd_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
|
@ -31,7 +75,7 @@ int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
|
||||
int smu7_powerup_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_uvd_power_gating(hwmgr)) {
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
|
@ -47,7 +91,7 @@ static int polaris10_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
|
||||
int smu7_powerdown_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_vce_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
|
@ -55,7 +99,7 @@ static int polaris10_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_phm_powerup_vce(struct pp_hwmgr *hwmgr)
|
||||
int smu7_powerup_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_vce_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
|
@ -63,7 +107,7 @@ static int polaris10_phm_powerup_vce(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_phm_powerdown_samu(struct pp_hwmgr *hwmgr)
|
||||
int smu7_powerdown_samu(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SamuPowerGating))
|
||||
|
@ -72,7 +116,7 @@ static int polaris10_phm_powerdown_samu(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_phm_powerup_samu(struct pp_hwmgr *hwmgr)
|
||||
int smu7_powerup_samu(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SamuPowerGating))
|
||||
|
@ -81,27 +125,24 @@ static int polaris10_phm_powerup_samu(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
|
||||
int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
|
||||
data->uvd_power_gated = false;
|
||||
data->vce_power_gated = false;
|
||||
data->samu_power_gated = false;
|
||||
|
||||
polaris10_phm_powerup_uvd(hwmgr);
|
||||
polaris10_phm_powerup_vce(hwmgr);
|
||||
polaris10_phm_powerup_samu(hwmgr);
|
||||
smu7_powerup_uvd(hwmgr);
|
||||
smu7_powerup_vce(hwmgr);
|
||||
smu7_powerup_samu(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
int smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->uvd_power_gated == bgate)
|
||||
return 0;
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
|
||||
data->uvd_power_gated = bgate;
|
||||
|
||||
|
@ -109,11 +150,11 @@ int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
|||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_GATE);
|
||||
polaris10_update_uvd_dpm(hwmgr, true);
|
||||
polaris10_phm_powerdown_uvd(hwmgr);
|
||||
smu7_update_uvd_dpm(hwmgr, true);
|
||||
smu7_powerdown_uvd(hwmgr);
|
||||
} else {
|
||||
polaris10_phm_powerup_uvd(hwmgr);
|
||||
polaris10_update_uvd_dpm(hwmgr, false);
|
||||
smu7_powerup_uvd(hwmgr);
|
||||
smu7_update_uvd_dpm(hwmgr, false);
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
|
@ -122,9 +163,9 @@ int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
int smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->vce_power_gated == bgate)
|
||||
return 0;
|
||||
|
@ -135,11 +176,11 @@ int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
|||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_CG_STATE_GATE);
|
||||
polaris10_update_vce_dpm(hwmgr, true);
|
||||
polaris10_phm_powerdown_vce(hwmgr);
|
||||
smu7_update_vce_dpm(hwmgr, true);
|
||||
smu7_powerdown_vce(hwmgr);
|
||||
} else {
|
||||
polaris10_phm_powerup_vce(hwmgr);
|
||||
polaris10_update_vce_dpm(hwmgr, false);
|
||||
smu7_powerup_vce(hwmgr);
|
||||
smu7_update_vce_dpm(hwmgr, false);
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
|
@ -147,9 +188,9 @@ int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->samu_power_gated == bgate)
|
||||
return 0;
|
||||
|
@ -157,22 +198,25 @@ int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
|
|||
data->samu_power_gated = bgate;
|
||||
|
||||
if (bgate) {
|
||||
polaris10_update_samu_dpm(hwmgr, true);
|
||||
polaris10_phm_powerdown_samu(hwmgr);
|
||||
smu7_update_samu_dpm(hwmgr, true);
|
||||
smu7_powerdown_samu(hwmgr);
|
||||
} else {
|
||||
polaris10_phm_powerup_samu(hwmgr);
|
||||
polaris10_update_samu_dpm(hwmgr, false);
|
||||
smu7_powerup_samu(hwmgr);
|
||||
smu7_update_samu_dpm(hwmgr, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
const uint32_t *msg_id)
|
||||
{
|
||||
PPSMC_Msg msg;
|
||||
uint32_t value;
|
||||
|
||||
if (!(hwmgr->feature_mask & PP_ENABLE_GFX_CG_THRU_SMU))
|
||||
return 0;
|
||||
|
||||
switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
|
||||
case PP_GROUP_GFX:
|
||||
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
|
||||
|
@ -185,7 +229,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
|
@ -195,7 +239,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -208,7 +252,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
|
@ -219,7 +263,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -232,7 +276,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -245,7 +289,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -259,12 +303,12 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -279,7 +323,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
|
||||
|
@ -289,7 +333,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -302,7 +346,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
|
@ -313,7 +357,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -326,7 +370,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
|
||||
|
@ -336,7 +380,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -349,7 +393,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
|
@ -360,7 +404,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -373,7 +417,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
|
@ -384,7 +428,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -397,18 +441,18 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (smum_send_msg_to_smc_with_parameter(
|
||||
hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
|
@ -419,7 +463,7 @@ int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
|||
* Powerplay will only control the static per CU Power Gating.
|
||||
* Dynamic per CU Power Gating will be done in gfx.
|
||||
*/
|
||||
int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable)
|
||||
int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
struct cgs_system_info sys_info = {0};
|
||||
uint32_t active_cus;
|
||||
|
@ -432,8 +476,8 @@ int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable
|
|||
|
||||
if (result)
|
||||
return -EINVAL;
|
||||
else
|
||||
active_cus = sys_info.value;
|
||||
|
||||
active_cus = sys_info.value;
|
||||
|
||||
if (enable)
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
* Copyright 2016 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"),
|
||||
|
@ -21,15 +21,20 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _FIJI_CLOCK_POWER_GATING_H_
|
||||
#define _FIJI_CLOCK_POWER_GATING_H_
|
||||
#ifndef _SMU7_CLOCK_POWER_GATING_H_
|
||||
#define _SMU7_CLOCK__POWER_GATING_H_
|
||||
|
||||
#include "fiji_hwmgr.h"
|
||||
#include "smu7_hwmgr.h"
|
||||
#include "pp_asicblocks.h"
|
||||
|
||||
extern int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
|
||||
#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
|
||||
int smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr);
|
||||
int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
|
||||
int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
const uint32_t *msg_id);
|
||||
int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2015 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 _SMU7_DYN_DEFAULTS_H
|
||||
#define _SMU7_DYN_DEFAULTS_H
|
||||
|
||||
|
||||
/* We need to fill in the default values */
|
||||
|
||||
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT1 0x000400
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033
|
||||
#define SMU7_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000
|
||||
|
||||
|
||||
#define SMU7_THERMALPROTECTCOUNTER_DFLT 0x200
|
||||
#define SMU7_STATICSCREENTHRESHOLDUNIT_DFLT 0
|
||||
#define SMU7_STATICSCREENTHRESHOLD_DFLT 0x00C8
|
||||
#define SMU7_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200
|
||||
#define SMU7_REFERENCEDIVIDER_DFLT 4
|
||||
|
||||
#define SMU7_ULVVOLTAGECHANGEDELAY_DFLT 1687
|
||||
|
||||
#define SMU7_CGULVPARAMETER_DFLT 0x00040035
|
||||
#define SMU7_CGULVCONTROL_DFLT 0x00007450
|
||||
#define SMU7_TARGETACTIVITY_DFLT 50
|
||||
#define SMU7_MCLK_TARGETACTIVITY_DFLT 10
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -21,82 +21,100 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef POLARIS10_HWMGR_H
|
||||
#define POLARIS10_HWMGR_H
|
||||
#ifndef _SMU7_HWMGR_H
|
||||
#define _SMU7_HWMGR_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "smu74.h"
|
||||
#include "smu74_discrete.h"
|
||||
#include "ppatomctrl.h"
|
||||
#include "polaris10_ppsmc.h"
|
||||
#include "polaris10_powertune.h"
|
||||
#include "polaris10_smumgr.h"
|
||||
|
||||
#define POLARIS10_MAX_HARDWARE_POWERLEVELS 2
|
||||
#define SMU7_MAX_HARDWARE_POWERLEVELS 2
|
||||
|
||||
#define POLARIS10_VOLTAGE_CONTROL_NONE 0x0
|
||||
#define POLARIS10_VOLTAGE_CONTROL_BY_GPIO 0x1
|
||||
#define POLARIS10_VOLTAGE_CONTROL_BY_SVID2 0x2
|
||||
#define POLARIS10_VOLTAGE_CONTROL_MERGED 0x3
|
||||
#define SMU7_VOLTAGE_CONTROL_NONE 0x0
|
||||
#define SMU7_VOLTAGE_CONTROL_BY_GPIO 0x1
|
||||
#define SMU7_VOLTAGE_CONTROL_BY_SVID2 0x2
|
||||
#define SMU7_VOLTAGE_CONTROL_MERGED 0x3
|
||||
|
||||
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
|
||||
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
|
||||
#define DPMTABLE_UPDATE_SCLK 0x00000004
|
||||
#define DPMTABLE_UPDATE_MCLK 0x00000008
|
||||
|
||||
struct polaris10_performance_level {
|
||||
enum gpu_pt_config_reg_type {
|
||||
GPU_CONFIGREG_MMR = 0,
|
||||
GPU_CONFIGREG_SMC_IND,
|
||||
GPU_CONFIGREG_DIDT_IND,
|
||||
GPU_CONFIGREG_GC_CAC_IND,
|
||||
GPU_CONFIGREG_CACHE,
|
||||
GPU_CONFIGREG_MAX
|
||||
};
|
||||
|
||||
struct gpu_pt_config_reg {
|
||||
uint32_t offset;
|
||||
uint32_t mask;
|
||||
uint32_t shift;
|
||||
uint32_t value;
|
||||
enum gpu_pt_config_reg_type type;
|
||||
};
|
||||
|
||||
struct smu7_performance_level {
|
||||
uint32_t memory_clock;
|
||||
uint32_t engine_clock;
|
||||
uint16_t pcie_gen;
|
||||
uint16_t pcie_lane;
|
||||
};
|
||||
|
||||
struct polaris10_uvd_clocks {
|
||||
struct smu7_thermal_temperature_setting {
|
||||
long temperature_low;
|
||||
long temperature_high;
|
||||
long temperature_shutdown;
|
||||
};
|
||||
|
||||
struct smu7_uvd_clocks {
|
||||
uint32_t vclk;
|
||||
uint32_t dclk;
|
||||
};
|
||||
|
||||
struct polaris10_vce_clocks {
|
||||
struct smu7_vce_clocks {
|
||||
uint32_t evclk;
|
||||
uint32_t ecclk;
|
||||
};
|
||||
|
||||
struct polaris10_power_state {
|
||||
struct smu7_power_state {
|
||||
uint32_t magic;
|
||||
struct polaris10_uvd_clocks uvd_clks;
|
||||
struct polaris10_vce_clocks vce_clks;
|
||||
struct smu7_uvd_clocks uvd_clks;
|
||||
struct smu7_vce_clocks vce_clks;
|
||||
uint32_t sam_clk;
|
||||
uint16_t performance_level_count;
|
||||
bool dc_compatible;
|
||||
uint32_t sclk_threshold;
|
||||
struct polaris10_performance_level performance_levels[POLARIS10_MAX_HARDWARE_POWERLEVELS];
|
||||
struct smu7_performance_level performance_levels[SMU7_MAX_HARDWARE_POWERLEVELS];
|
||||
};
|
||||
|
||||
struct polaris10_dpm_level {
|
||||
struct smu7_dpm_level {
|
||||
bool enabled;
|
||||
uint32_t value;
|
||||
uint32_t param1;
|
||||
};
|
||||
|
||||
#define POLARIS10_MAX_DEEPSLEEP_DIVIDER_ID 5
|
||||
#define SMU7_MAX_DEEPSLEEP_DIVIDER_ID 5
|
||||
#define MAX_REGULAR_DPM_NUMBER 8
|
||||
#define POLARIS10_MINIMUM_ENGINE_CLOCK 2500
|
||||
#define SMU7_MINIMUM_ENGINE_CLOCK 2500
|
||||
|
||||
struct polaris10_single_dpm_table {
|
||||
struct smu7_single_dpm_table {
|
||||
uint32_t count;
|
||||
struct polaris10_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
|
||||
struct smu7_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
|
||||
};
|
||||
|
||||
struct polaris10_dpm_table {
|
||||
struct polaris10_single_dpm_table sclk_table;
|
||||
struct polaris10_single_dpm_table mclk_table;
|
||||
struct polaris10_single_dpm_table pcie_speed_table;
|
||||
struct polaris10_single_dpm_table vddc_table;
|
||||
struct polaris10_single_dpm_table vddci_table;
|
||||
struct polaris10_single_dpm_table mvdd_table;
|
||||
struct smu7_dpm_table {
|
||||
struct smu7_single_dpm_table sclk_table;
|
||||
struct smu7_single_dpm_table mclk_table;
|
||||
struct smu7_single_dpm_table pcie_speed_table;
|
||||
struct smu7_single_dpm_table vddc_table;
|
||||
struct smu7_single_dpm_table vddci_table;
|
||||
struct smu7_single_dpm_table mvdd_table;
|
||||
};
|
||||
|
||||
struct polaris10_clock_registers {
|
||||
struct smu7_clock_registers {
|
||||
uint32_t vCG_SPLL_FUNC_CNTL;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_2;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_3;
|
||||
|
@ -117,42 +135,35 @@ struct polaris10_clock_registers {
|
|||
#define DISABLE_MC_LOADMICROCODE 1
|
||||
#define DISABLE_MC_CFGPROGRAMMING 2
|
||||
|
||||
struct polaris10_voltage_smio_registers {
|
||||
struct smu7_voltage_smio_registers {
|
||||
uint32_t vS0_VID_LOWER_SMIO_CNTL;
|
||||
};
|
||||
|
||||
#define POLARIS10_MAX_LEAKAGE_COUNT 8
|
||||
#define SMU7_MAX_LEAKAGE_COUNT 8
|
||||
|
||||
struct polaris10_leakage_voltage {
|
||||
struct smu7_leakage_voltage {
|
||||
uint16_t count;
|
||||
uint16_t leakage_id[POLARIS10_MAX_LEAKAGE_COUNT];
|
||||
uint16_t actual_voltage[POLARIS10_MAX_LEAKAGE_COUNT];
|
||||
uint16_t leakage_id[SMU7_MAX_LEAKAGE_COUNT];
|
||||
uint16_t actual_voltage[SMU7_MAX_LEAKAGE_COUNT];
|
||||
};
|
||||
|
||||
struct polaris10_vbios_boot_state {
|
||||
struct smu7_vbios_boot_state {
|
||||
uint16_t mvdd_bootup_value;
|
||||
uint16_t vddc_bootup_value;
|
||||
uint16_t vddci_bootup_value;
|
||||
uint16_t vddgfx_bootup_value;
|
||||
uint32_t sclk_bootup_value;
|
||||
uint32_t mclk_bootup_value;
|
||||
uint16_t pcie_gen_bootup_value;
|
||||
uint16_t pcie_lane_bootup_value;
|
||||
};
|
||||
|
||||
/* Ultra Low Voltage parameter structure */
|
||||
struct polaris10_ulv_parm {
|
||||
bool ulv_supported;
|
||||
uint32_t cg_ulv_parameter;
|
||||
uint32_t ulv_volt_change_delay;
|
||||
struct polaris10_performance_level ulv_power_level;
|
||||
};
|
||||
|
||||
struct polaris10_display_timing {
|
||||
struct smu7_display_timing {
|
||||
uint32_t min_clock_in_sr;
|
||||
uint32_t num_existing_displays;
|
||||
};
|
||||
|
||||
struct polaris10_dpmlevel_enable_mask {
|
||||
struct smu7_dpmlevel_enable_mask {
|
||||
uint32_t uvd_dpm_enable_mask;
|
||||
uint32_t vce_dpm_enable_mask;
|
||||
uint32_t acp_dpm_enable_mask;
|
||||
|
@ -162,18 +173,15 @@ struct polaris10_dpmlevel_enable_mask {
|
|||
uint32_t pcie_dpm_enable_mask;
|
||||
};
|
||||
|
||||
struct polaris10_pcie_perf_range {
|
||||
struct smu7_pcie_perf_range {
|
||||
uint16_t max;
|
||||
uint16_t min;
|
||||
};
|
||||
|
||||
struct polaris10_hwmgr {
|
||||
struct polaris10_dpm_table dpm_table;
|
||||
struct polaris10_dpm_table golden_dpm_table;
|
||||
SMU74_Discrete_DpmTable smc_state_table;
|
||||
struct SMU74_Discrete_Ulv ulv_setting;
|
||||
struct smu7_hwmgr {
|
||||
struct smu7_dpm_table dpm_table;
|
||||
struct smu7_dpm_table golden_dpm_table;
|
||||
|
||||
struct polaris10_range_table range_table[NUM_SCLK_RANGE];
|
||||
uint32_t voting_rights_clients0;
|
||||
uint32_t voting_rights_clients1;
|
||||
uint32_t voting_rights_clients2;
|
||||
|
@ -185,12 +193,11 @@ struct polaris10_hwmgr {
|
|||
uint32_t static_screen_threshold_unit;
|
||||
uint32_t static_screen_threshold;
|
||||
uint32_t voltage_control;
|
||||
uint32_t vddc_vddci_delta;
|
||||
|
||||
uint32_t vdd_gfx_control;
|
||||
uint32_t vddc_vddgfx_delta;
|
||||
uint32_t active_auto_throttle_sources;
|
||||
|
||||
struct polaris10_clock_registers clock_registers;
|
||||
struct polaris10_voltage_smio_registers voltage_smio_registers;
|
||||
struct smu7_clock_registers clock_registers;
|
||||
|
||||
bool is_memory_gddr5;
|
||||
uint16_t acpi_vddc;
|
||||
|
@ -200,8 +207,9 @@ struct polaris10_hwmgr {
|
|||
uint32_t pcie_gen_cap;
|
||||
uint32_t pcie_lane_cap;
|
||||
uint32_t pcie_spc_cap;
|
||||
struct polaris10_leakage_voltage vddc_leakage;
|
||||
struct polaris10_leakage_voltage Vddci_leakage;
|
||||
struct smu7_leakage_voltage vddc_leakage;
|
||||
struct smu7_leakage_voltage vddci_leakage;
|
||||
struct smu7_leakage_voltage vddcgfx_leakage;
|
||||
|
||||
uint32_t mvdd_control;
|
||||
uint32_t vddc_mask_low;
|
||||
|
@ -210,30 +218,23 @@ struct polaris10_hwmgr {
|
|||
uint16_t min_vddc_in_pptable;
|
||||
uint16_t max_vddci_in_pptable;
|
||||
uint16_t min_vddci_in_pptable;
|
||||
uint32_t mclk_strobe_mode_threshold;
|
||||
uint32_t mclk_stutter_mode_threshold;
|
||||
uint32_t mclk_edc_enable_threshold;
|
||||
uint32_t mclk_edcwr_enable_threshold;
|
||||
bool is_uvd_enabled;
|
||||
struct polaris10_vbios_boot_state vbios_boot_state;
|
||||
struct smu7_vbios_boot_state vbios_boot_state;
|
||||
|
||||
bool pcie_performance_request;
|
||||
bool battery_state;
|
||||
bool is_tlu_enabled;
|
||||
bool disable_handshake;
|
||||
bool smc_voltage_control_enabled;
|
||||
bool vbi_time_out_support;
|
||||
|
||||
/* ---- SMC SRAM Address of firmware header tables ---- */
|
||||
uint32_t sram_end;
|
||||
uint32_t dpm_table_start;
|
||||
uint32_t soft_regs_start;
|
||||
uint32_t mc_reg_table_start;
|
||||
uint32_t fan_table_start;
|
||||
uint32_t arb_table_start;
|
||||
|
||||
uint32_t soft_regs_start;
|
||||
/* ---- Stuff originally coming from Evergreen ---- */
|
||||
uint32_t vddci_control;
|
||||
struct pp_atomctrl_voltage_table vddc_voltage_table;
|
||||
struct pp_atomctrl_voltage_table vddci_voltage_table;
|
||||
struct pp_atomctrl_voltage_table mvdd_voltage_table;
|
||||
struct pp_atomctrl_voltage_table vddgfx_voltage_table;
|
||||
|
||||
uint32_t mgcg_cgtt_local2;
|
||||
uint32_t mgcg_cgtt_local3;
|
||||
|
@ -247,7 +248,7 @@ struct polaris10_hwmgr {
|
|||
bool performance_request_registered;
|
||||
|
||||
/* ---- Low Power Features ---- */
|
||||
struct polaris10_ulv_parm ulv;
|
||||
bool ulv_supported;
|
||||
|
||||
/* ---- CAC Stuff ---- */
|
||||
uint32_t cac_table_start;
|
||||
|
@ -261,8 +262,8 @@ struct polaris10_hwmgr {
|
|||
bool enable_tdc_limit_feature;
|
||||
bool enable_pkg_pwr_tracking_feature;
|
||||
bool disable_uvd_power_tune_feature;
|
||||
const struct polaris10_pt_defaults *power_tune_defaults;
|
||||
struct SMU74_Discrete_PmFuses power_tune_table;
|
||||
|
||||
|
||||
uint32_t dte_tj_offset;
|
||||
uint32_t fast_watermark_threshold;
|
||||
|
||||
|
@ -270,23 +271,22 @@ struct polaris10_hwmgr {
|
|||
bool vddc_phase_shed_control;
|
||||
|
||||
/* ---- DI/DT ---- */
|
||||
struct polaris10_display_timing display_timing;
|
||||
uint32_t bif_sclk_table[SMU74_MAX_LEVELS_LINK];
|
||||
struct smu7_display_timing display_timing;
|
||||
|
||||
/* ---- Thermal Temperature Setting ---- */
|
||||
struct polaris10_dpmlevel_enable_mask dpm_level_enable_mask;
|
||||
struct smu7_thermal_temperature_setting thermal_temp_setting;
|
||||
struct smu7_dpmlevel_enable_mask dpm_level_enable_mask;
|
||||
uint32_t need_update_smu7_dpm_table;
|
||||
uint32_t sclk_dpm_key_disabled;
|
||||
uint32_t mclk_dpm_key_disabled;
|
||||
uint32_t pcie_dpm_key_disabled;
|
||||
uint32_t min_engine_clocks;
|
||||
struct polaris10_pcie_perf_range pcie_gen_performance;
|
||||
struct polaris10_pcie_perf_range pcie_lane_performance;
|
||||
struct polaris10_pcie_perf_range pcie_gen_power_saving;
|
||||
struct polaris10_pcie_perf_range pcie_lane_power_saving;
|
||||
struct smu7_pcie_perf_range pcie_gen_performance;
|
||||
struct smu7_pcie_perf_range pcie_lane_performance;
|
||||
struct smu7_pcie_perf_range pcie_gen_power_saving;
|
||||
struct smu7_pcie_perf_range pcie_lane_power_saving;
|
||||
bool use_pcie_performance_levels;
|
||||
bool use_pcie_power_saving_levels;
|
||||
uint32_t activity_target[SMU74_MAX_LEVELS_GRAPHICS];
|
||||
uint32_t mclk_activity_target;
|
||||
uint32_t mclk_dpm0_activity_target;
|
||||
uint32_t low_sclk_interrupt_threshold;
|
||||
|
@ -306,49 +306,48 @@ struct polaris10_hwmgr {
|
|||
uint32_t up_hyst;
|
||||
uint32_t disable_dpm_mask;
|
||||
bool apply_optimized_settings;
|
||||
|
||||
uint32_t avfs_vdroop_override_setting;
|
||||
bool apply_avfs_cks_off_voltage;
|
||||
uint32_t frame_time_x2;
|
||||
uint16_t mem_latency_high;
|
||||
uint16_t mem_latency_low;
|
||||
};
|
||||
|
||||
/* To convert to Q8.8 format for firmware */
|
||||
#define POLARIS10_Q88_FORMAT_CONVERSION_UNIT 256
|
||||
#define SMU7_Q88_FORMAT_CONVERSION_UNIT 256
|
||||
|
||||
enum Polaris10_I2CLineID {
|
||||
Polaris10_I2CLineID_DDC1 = 0x90,
|
||||
Polaris10_I2CLineID_DDC2 = 0x91,
|
||||
Polaris10_I2CLineID_DDC3 = 0x92,
|
||||
Polaris10_I2CLineID_DDC4 = 0x93,
|
||||
Polaris10_I2CLineID_DDC5 = 0x94,
|
||||
Polaris10_I2CLineID_DDC6 = 0x95,
|
||||
Polaris10_I2CLineID_SCLSDA = 0x96,
|
||||
Polaris10_I2CLineID_DDCVGA = 0x97
|
||||
enum SMU7_I2CLineID {
|
||||
SMU7_I2CLineID_DDC1 = 0x90,
|
||||
SMU7_I2CLineID_DDC2 = 0x91,
|
||||
SMU7_I2CLineID_DDC3 = 0x92,
|
||||
SMU7_I2CLineID_DDC4 = 0x93,
|
||||
SMU7_I2CLineID_DDC5 = 0x94,
|
||||
SMU7_I2CLineID_DDC6 = 0x95,
|
||||
SMU7_I2CLineID_SCLSDA = 0x96,
|
||||
SMU7_I2CLineID_DDCVGA = 0x97
|
||||
};
|
||||
|
||||
#define POLARIS10_I2C_DDC1DATA 0
|
||||
#define POLARIS10_I2C_DDC1CLK 1
|
||||
#define POLARIS10_I2C_DDC2DATA 2
|
||||
#define POLARIS10_I2C_DDC2CLK 3
|
||||
#define POLARIS10_I2C_DDC3DATA 4
|
||||
#define POLARIS10_I2C_DDC3CLK 5
|
||||
#define POLARIS10_I2C_SDA 40
|
||||
#define POLARIS10_I2C_SCL 41
|
||||
#define POLARIS10_I2C_DDC4DATA 65
|
||||
#define POLARIS10_I2C_DDC4CLK 66
|
||||
#define POLARIS10_I2C_DDC5DATA 0x48
|
||||
#define POLARIS10_I2C_DDC5CLK 0x49
|
||||
#define POLARIS10_I2C_DDC6DATA 0x4a
|
||||
#define POLARIS10_I2C_DDC6CLK 0x4b
|
||||
#define POLARIS10_I2C_DDCVGADATA 0x4c
|
||||
#define POLARIS10_I2C_DDCVGACLK 0x4d
|
||||
#define SMU7_I2C_DDC1DATA 0
|
||||
#define SMU7_I2C_DDC1CLK 1
|
||||
#define SMU7_I2C_DDC2DATA 2
|
||||
#define SMU7_I2C_DDC2CLK 3
|
||||
#define SMU7_I2C_DDC3DATA 4
|
||||
#define SMU7_I2C_DDC3CLK 5
|
||||
#define SMU7_I2C_SDA 40
|
||||
#define SMU7_I2C_SCL 41
|
||||
#define SMU7_I2C_DDC4DATA 65
|
||||
#define SMU7_I2C_DDC4CLK 66
|
||||
#define SMU7_I2C_DDC5DATA 0x48
|
||||
#define SMU7_I2C_DDC5CLK 0x49
|
||||
#define SMU7_I2C_DDC6DATA 0x4a
|
||||
#define SMU7_I2C_DDC6CLK 0x4b
|
||||
#define SMU7_I2C_DDCVGADATA 0x4c
|
||||
#define SMU7_I2C_DDCVGACLK 0x4d
|
||||
|
||||
#define POLARIS10_UNUSED_GPIO_PIN 0x7F
|
||||
|
||||
int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
|
||||
int polaris10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int polaris10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
int polaris10_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
#define SMU7_UNUSED_GPIO_PIN 0x7F
|
||||
uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr);
|
||||
uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
|
||||
uint32_t clock_insr);
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -20,17 +20,8 @@
|
|||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef POLARIS10_POWERTUNE_H
|
||||
#define POLARIS10_POWERTUNE_H
|
||||
|
||||
enum polaris10_pt_config_reg_type {
|
||||
POLARIS10_CONFIGREG_MMR = 0,
|
||||
POLARIS10_CONFIGREG_SMC_IND,
|
||||
POLARIS10_CONFIGREG_DIDT_IND,
|
||||
POLARIS10_CONFIGREG_GC_CAC_IND,
|
||||
POLARIS10_CONFIGREG_CACHE,
|
||||
POLARIS10_CONFIGREG_MAX
|
||||
};
|
||||
#ifndef _SMU7_POWERTUNE_H
|
||||
#define _SMU7_POWERTUNE_H
|
||||
|
||||
#define DIDT_SQ_CTRL0__UNUSED_0_MASK 0xfffc0000
|
||||
#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT 0x12
|
||||
|
@ -52,30 +43,20 @@ enum polaris10_pt_config_reg_type {
|
|||
|
||||
#define ixGC_CAC_CNTL 0x0000
|
||||
#define ixDIDT_SQ_STALL_CTRL 0x0004
|
||||
#define ixDIDT_SQ_TUNING_CTRL 0x0005
|
||||
#define ixDIDT_SQ_TUNING_CTRL 0x0005
|
||||
#define ixDIDT_TD_STALL_CTRL 0x0044
|
||||
#define ixDIDT_TD_TUNING_CTRL 0x0045
|
||||
#define ixDIDT_TCP_STALL_CTRL 0x0064
|
||||
#define ixDIDT_TCP_TUNING_CTRL 0x0065
|
||||
|
||||
struct polaris10_pt_config_reg {
|
||||
uint32_t offset;
|
||||
uint32_t mask;
|
||||
uint32_t shift;
|
||||
uint32_t value;
|
||||
enum polaris10_pt_config_reg_type type;
|
||||
};
|
||||
|
||||
|
||||
void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_enable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_disable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_enable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_disable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
|
||||
int polaris10_power_control_set_level(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_enable_didt_config(struct pp_hwmgr *hwmgr);
|
||||
#endif /* POLARIS10_POWERTUNE_H */
|
||||
int smu7_enable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int smu7_disable_smc_cac(struct pp_hwmgr *hwmgr);
|
||||
int smu7_enable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int smu7_disable_power_containment(struct pp_hwmgr *hwmgr);
|
||||
int smu7_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
|
||||
int smu7_power_control_set_level(struct pp_hwmgr *hwmgr);
|
||||
int smu7_enable_didt_config(struct pp_hwmgr *hwmgr);
|
||||
int smu7_disable_didt_config(struct pp_hwmgr *hwmgr);
|
||||
#endif /* DGPU_POWERTUNE_H */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
* Copyright 2016 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"),
|
||||
|
@ -20,18 +20,15 @@
|
|||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <asm/div64.h>
|
||||
#include "fiji_thermal.h"
|
||||
#include "fiji_hwmgr.h"
|
||||
#include "fiji_smumgr.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
|
||||
int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
||||
#include <asm/div64.h>
|
||||
#include "smu7_thermal.h"
|
||||
#include "smu7_hwmgr.h"
|
||||
#include "smu7_common.h"
|
||||
|
||||
int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
||||
struct phm_fan_speed_info *fan_speed_info)
|
||||
{
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
|
@ -55,7 +52,7 @@ int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
uint32_t *speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
|
@ -84,7 +81,7 @@ int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
uint32_t tach_period;
|
||||
uint32_t crystal_clock_freq;
|
||||
|
@ -100,9 +97,9 @@ int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
|||
if (tach_period == 0)
|
||||
return -EINVAL;
|
||||
|
||||
crystal_clock_freq = tonga_get_xclk(hwmgr);
|
||||
crystal_clock_freq = smu7_get_xclk(hwmgr);
|
||||
|
||||
*speed = 60 * crystal_clock_freq * 10000/ tach_period;
|
||||
*speed = 60 * crystal_clock_freq * 10000 / tach_period;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,7 +110,7 @@ int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
|||
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
||||
int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
||||
{
|
||||
|
||||
if (hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
|
@ -139,7 +136,7 @@ int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
|||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
||||
int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
|
@ -152,7 +149,7 @@ int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
static int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
|
@ -187,7 +184,7 @@ static int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
|||
}
|
||||
|
||||
|
||||
int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
|
||||
}
|
||||
|
@ -198,7 +195,7 @@ int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
|||
* @param speed is the percentage value (0% - 100%) to be set.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
||||
uint32_t speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
|
@ -213,7 +210,7 @@ int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl))
|
||||
fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
@ -228,7 +225,7 @@ int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
|||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
|
||||
|
||||
return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,7 +233,7 @@ int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
|
|||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Always succeeds.
|
||||
*/
|
||||
int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
||||
int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
|
@ -245,11 +242,11 @@ int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
|||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
if (!result)
|
||||
result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
result = smu7_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
} else
|
||||
result = fiji_fan_ctrl_set_default_mode(hwmgr);
|
||||
result = smu7_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -260,7 +257,7 @@ int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
|||
* @param speed is the percentage value (min - max) to be set.
|
||||
* @exception Fails is the speed not lie between min and max.
|
||||
*/
|
||||
int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
uint32_t tach_period;
|
||||
uint32_t crystal_clock_freq;
|
||||
|
@ -272,14 +269,18 @@ int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
|||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
|
||||
return 0;
|
||||
|
||||
crystal_clock_freq = tonga_get_xclk(hwmgr);
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl))
|
||||
smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
crystal_clock_freq = smu7_get_xclk(hwmgr);
|
||||
|
||||
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_STATUS, TACH_PERIOD, tach_period);
|
||||
|
||||
return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,7 +288,7 @@ int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
|||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
||||
int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int temp;
|
||||
|
||||
|
@ -296,7 +297,7 @@ int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
|||
|
||||
/* Bit 9 means the reading is lower than the lowest usable value. */
|
||||
if (temp & 0x200)
|
||||
temp = FIJI_THERMAL_MAXIMUM_TEMP_READING;
|
||||
temp = SMU7_THERMAL_MAXIMUM_TEMP_READING;
|
||||
else
|
||||
temp = temp & 0x1ff;
|
||||
|
||||
|
@ -312,12 +313,12 @@ int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
|||
* @param range Temperature range to be programmed for high and low alert signals
|
||||
* @exception PP_Result_BadInput if the input data is not valid.
|
||||
*/
|
||||
static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
uint32_t low_temp, uint32_t high_temp)
|
||||
{
|
||||
uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
|
||||
uint32_t low = SMU7_THERMAL_MINIMUM_ALERT_TEMP *
|
||||
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
uint32_t high = FIJI_THERMAL_MAXIMUM_ALERT_TEMP *
|
||||
uint32_t high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP *
|
||||
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
if (low < low_temp)
|
||||
|
@ -346,7 +347,7 @@ static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
|||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
|
@ -365,13 +366,13 @@ static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
|
|||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
||||
int smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert &= ~(FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
|
||||
alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
|
@ -383,13 +384,13 @@ static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
|||
* Disable thermal alerts on the RV770 thermal controller.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
||||
int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert |= (FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
|
||||
alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
|
@ -402,128 +403,16 @@ static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
|||
* Currently just disables alerts.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = fiji_thermal_disable_alert(hwmgr);
|
||||
int result = smu7_thermal_disable_alert(hwmgr);
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
fiji_fan_ctrl_set_default_mode(hwmgr);
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
smu7_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the fan table to control the fan using the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
static int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||
SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
|
||||
uint32_t duty100;
|
||||
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
|
||||
uint16_t fdo_min, slope1, slope2;
|
||||
uint32_t reference_clock;
|
||||
int res;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (data->fan_table_start == 0) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (duty100 == 0) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usPWMMin * duty100;
|
||||
do_div(tmp64, 10000);
|
||||
fdo_min = (uint16_t)tmp64;
|
||||
|
||||
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
|
||||
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
|
||||
|
||||
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
|
||||
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
|
||||
|
||||
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
|
||||
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
|
||||
|
||||
fan_table.TempMin = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMin) / 100);
|
||||
fan_table.TempMed = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMed) / 100);
|
||||
fan_table.TempMax = cpu_to_be16((50 + hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.usTMax) / 100);
|
||||
|
||||
fan_table.Slope1 = cpu_to_be16(slope1);
|
||||
fan_table.Slope2 = cpu_to_be16(slope2);
|
||||
|
||||
fan_table.FdoMin = cpu_to_be16(fdo_min);
|
||||
|
||||
fan_table.HystDown = cpu_to_be16(hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.ucTHyst);
|
||||
|
||||
fan_table.HystUp = cpu_to_be16(1);
|
||||
|
||||
fan_table.HystSlope = cpu_to_be16(1);
|
||||
|
||||
fan_table.TempRespLim = cpu_to_be16(5);
|
||||
|
||||
reference_clock = tonga_get_xclk(hwmgr);
|
||||
|
||||
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
|
||||
thermal_controller.advanceFanControlParameters.ulCycleDelay *
|
||||
reference_clock) / 1600);
|
||||
|
||||
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
|
||||
|
||||
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
|
||||
hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_MULT_THERMAL_CTRL, TEMP_SEL);
|
||||
|
||||
res = fiji_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
|
||||
(uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
|
||||
data->sram_end);
|
||||
|
||||
if (!res && hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucMinimumPWMLimit)
|
||||
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetFanMinPwm,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ucMinimumPWMLimit);
|
||||
|
||||
if (!res && hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
|
||||
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_SetFanSclkTarget,
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
|
||||
|
||||
if (res)
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the fan control on the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
|
@ -533,7 +422,7 @@ static int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
|
|||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
static int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
|
||||
static int tf_smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
/* If the fantable setup has failed we could have disabled
|
||||
|
@ -543,8 +432,8 @@ static int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
|
|||
*/
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
fiji_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
smu7_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -559,7 +448,7 @@ static int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
|
|||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
static int tf_smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
|
||||
|
@ -567,7 +456,7 @@ int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
|||
if (range == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return fiji_thermal_set_temperature_range(hwmgr, range->min, range->max);
|
||||
return smu7_thermal_set_temperature_range(hwmgr, range->min, range->max);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,10 +468,10 @@ int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
|||
* @param Result the last failure code
|
||||
* @return result from initialize thermal controller routine
|
||||
*/
|
||||
int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
|
||||
static int tf_smu7_thermal_initialize(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_thermal_initialize(hwmgr);
|
||||
return smu7_thermal_initialize(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -594,10 +483,10 @@ int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
|
|||
* @param Result the last failure code
|
||||
* @return result from enable alert routine
|
||||
*/
|
||||
int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
||||
static int tf_smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_thermal_enable_alert(hwmgr);
|
||||
return smu7_thermal_enable_alert(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -609,53 +498,54 @@ int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
|||
* @param Result the last failure code
|
||||
* @return result from disable alert routine
|
||||
*/
|
||||
static int tf_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
|
||||
static int tf_smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_thermal_disable_alert(hwmgr);
|
||||
return smu7_thermal_disable_alert(hwmgr);
|
||||
}
|
||||
|
||||
static const struct phm_master_table_item
|
||||
fiji_thermal_start_thermal_controller_master_list[] = {
|
||||
{NULL, tf_fiji_thermal_initialize},
|
||||
{NULL, tf_fiji_thermal_set_temperature_range},
|
||||
{NULL, tf_fiji_thermal_enable_alert},
|
||||
phm_thermal_start_thermal_controller_master_list[] = {
|
||||
{NULL, tf_smu7_thermal_initialize},
|
||||
{NULL, tf_smu7_thermal_set_temperature_range},
|
||||
{NULL, tf_smu7_thermal_enable_alert},
|
||||
{NULL, smum_thermal_avfs_enable},
|
||||
/* We should restrict performance levels to low before we halt the SMC.
|
||||
* On the other hand we are still in boot state when we do this
|
||||
* so it would be pointless.
|
||||
* If this assumption changes we have to revisit this table.
|
||||
*/
|
||||
{NULL, tf_fiji_thermal_setup_fan_table},
|
||||
{NULL, tf_fiji_thermal_start_smc_fan_control},
|
||||
{NULL, smum_thermal_setup_fan_table},
|
||||
{NULL, tf_smu7_thermal_start_smc_fan_control},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header
|
||||
fiji_thermal_start_thermal_controller_master = {
|
||||
phm_thermal_start_thermal_controller_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
fiji_thermal_start_thermal_controller_master_list
|
||||
phm_thermal_start_thermal_controller_master_list
|
||||
};
|
||||
|
||||
static const struct phm_master_table_item
|
||||
fiji_thermal_set_temperature_range_master_list[] = {
|
||||
{NULL, tf_fiji_thermal_disable_alert},
|
||||
{NULL, tf_fiji_thermal_set_temperature_range},
|
||||
{NULL, tf_fiji_thermal_enable_alert},
|
||||
phm_thermal_set_temperature_range_master_list[] = {
|
||||
{NULL, tf_smu7_thermal_disable_alert},
|
||||
{NULL, tf_smu7_thermal_set_temperature_range},
|
||||
{NULL, tf_smu7_thermal_enable_alert},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header
|
||||
fiji_thermal_set_temperature_range_master = {
|
||||
phm_thermal_set_temperature_range_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
fiji_thermal_set_temperature_range_master_list
|
||||
phm_thermal_set_temperature_range_master_list
|
||||
};
|
||||
|
||||
int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
fiji_fan_ctrl_set_default_mode(hwmgr);
|
||||
smu7_fan_ctrl_set_default_mode(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -664,17 +554,17 @@ int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
|||
* @param hwmgr The address of the hardware manager.
|
||||
* @exception Any error code from the low-level communication.
|
||||
*/
|
||||
int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = phm_construct_table(hwmgr,
|
||||
&fiji_thermal_set_temperature_range_master,
|
||||
&phm_thermal_set_temperature_range_master,
|
||||
&(hwmgr->set_temperature_range));
|
||||
|
||||
if (!result) {
|
||||
result = phm_construct_table(hwmgr,
|
||||
&fiji_thermal_start_thermal_controller_master,
|
||||
&phm_thermal_start_thermal_controller_master,
|
||||
&(hwmgr->start_thermal_controller));
|
||||
if (result)
|
||||
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2016 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 _SMU7_THERMAL_H_
|
||||
#define _SMU7_THERMAL_H_
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define SMU7_THERMAL_HIGH_ALERT_MASK 0x1
|
||||
#define SMU7_THERMAL_LOW_ALERT_MASK 0x2
|
||||
|
||||
#define SMU7_THERMAL_MINIMUM_TEMP_READING -256
|
||||
#define SMU7_THERMAL_MAXIMUM_TEMP_READING 255
|
||||
|
||||
#define SMU7_THERMAL_MINIMUM_ALERT_TEMP 0
|
||||
#define SMU7_THERMAL_MAXIMUM_ALERT_TEMP 255
|
||||
|
||||
#define FDO_PWM_MODE_STATIC 1
|
||||
#define FDO_PWM_MODE_STATIC_RPM 5
|
||||
|
||||
extern int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
|
||||
extern int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
|
||||
extern int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
|
||||
extern int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr);
|
||||
extern int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "tonga_clockpowergating.h"
|
||||
#include "tonga_ppsmc.h"
|
||||
#include "tonga_hwmgr.h"
|
||||
|
||||
int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_uvd_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
PPSMC_MSG_UVDPowerOFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_uvd_power_gating(hwmgr)) {
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_UVDDynamicPowerGating)) {
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_UVDPowerON, 1);
|
||||
} else {
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_UVDPowerON, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_vce_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
PPSMC_MSG_VCEPowerOFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_powerup_vce(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (phm_cf_want_vce_power_gating(hwmgr))
|
||||
return smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
PPSMC_MSG_VCEPowerON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (block) {
|
||||
case PHM_AsicBlock_UVD_MVC:
|
||||
case PHM_AsicBlock_UVD:
|
||||
case PHM_AsicBlock_UVD_HD:
|
||||
case PHM_AsicBlock_UVD_SD:
|
||||
if (gating == PHM_ClockGateSetting_StaticOff)
|
||||
ret = tonga_phm_powerdown_uvd(hwmgr);
|
||||
else
|
||||
ret = tonga_phm_powerup_uvd(hwmgr);
|
||||
break;
|
||||
case PHM_AsicBlock_GFX:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
data->uvd_power_gated = false;
|
||||
data->vce_power_gated = false;
|
||||
|
||||
tonga_phm_powerup_uvd(hwmgr);
|
||||
tonga_phm_powerup_vce(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->uvd_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
data->uvd_power_gated = bgate;
|
||||
|
||||
if (bgate) {
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
cgs_set_powergating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_PG_STATE_GATE);
|
||||
tonga_update_uvd_dpm(hwmgr, true);
|
||||
tonga_phm_powerdown_uvd(hwmgr);
|
||||
} else {
|
||||
tonga_phm_powerup_uvd(hwmgr);
|
||||
cgs_set_powergating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_PG_STATE_GATE);
|
||||
|
||||
tonga_update_uvd_dpm(hwmgr, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct phm_set_power_state_input states;
|
||||
const struct pp_power_state *pcurrent;
|
||||
struct pp_power_state *requested;
|
||||
|
||||
pcurrent = hwmgr->current_ps;
|
||||
requested = hwmgr->request_ps;
|
||||
|
||||
states.pcurrent_state = &(pcurrent->hardware);
|
||||
states.pnew_state = &(requested->hardware);
|
||||
|
||||
if (phm_cf_want_vce_power_gating(hwmgr)) {
|
||||
if (data->vce_power_gated != bgate) {
|
||||
if (bgate) {
|
||||
cgs_set_clockgating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
cgs_set_powergating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_GATE);
|
||||
tonga_enable_disable_vce_dpm(hwmgr, false);
|
||||
data->vce_power_gated = true;
|
||||
} else {
|
||||
tonga_phm_powerup_vce(hwmgr);
|
||||
data->vce_power_gated = false;
|
||||
cgs_set_powergating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
cgs_set_clockgating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_GATE);
|
||||
|
||||
tonga_update_vce_dpm(hwmgr, &states);
|
||||
tonga_enable_disable_vce_dpm(hwmgr, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tonga_update_vce_dpm(hwmgr, &states);
|
||||
tonga_enable_disable_vce_dpm(hwmgr, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!data->vce_power_gated)
|
||||
tonga_update_vce_dpm(hwmgr, &states);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
|
||||
const uint32_t *msg_id)
|
||||
{
|
||||
PPSMC_Msg msg;
|
||||
uint32_t value;
|
||||
|
||||
switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
|
||||
case PP_GROUP_GFX:
|
||||
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
|
||||
case PP_BLOCK_GFX_CG:
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_GFX_CGCG_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_GFX_CGLS_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_BLOCK_GFX_MG:
|
||||
/* For GFX MGCG, there are three different ones;
|
||||
* CPF, RLC, and all others. CPF MGCG will not be used for Tonga.
|
||||
* For GFX MGLS, Tonga will not support it.
|
||||
* */
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = (CG_RLC_MGCG_MASK | CG_GFX_OTHERS_MGCG_MASK);
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_GROUP_SYS:
|
||||
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
|
||||
case PP_BLOCK_SYS_BIF:
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_BIF_MGLS_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_BLOCK_SYS_MC:
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_MC_MGCG_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_MC_MGLS_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_BLOCK_SYS_HDP:
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_HDP_MGCG_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
|
||||
value = CG_SYS_HDP_MGLS_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_BLOCK_SYS_SDMA:
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_SDMA_MGCG_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PP_STATE_SUPPORT_LS & *msg_id) {
|
||||
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
|
||||
value = CG_SYS_SDMA_MGLS_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_BLOCK_SYS_ROM:
|
||||
if (PP_STATE_SUPPORT_CG & *msg_id) {
|
||||
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
|
||||
? PPSMC_MSG_EnableClockGatingFeature
|
||||
: PPSMC_MSG_DisableClockGatingFeature;
|
||||
value = CG_SYS_ROM_MASK;
|
||||
|
||||
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 TONGA_DYN_DEFAULTS_H
|
||||
#define TONGA_DYN_DEFAULTS_H
|
||||
|
||||
|
||||
/** \file
|
||||
* Volcanic Islands Dynamic default parameters.
|
||||
*/
|
||||
|
||||
enum TONGAdpm_TrendDetection {
|
||||
TONGAdpm_TrendDetection_AUTO,
|
||||
TONGAdpm_TrendDetection_UP,
|
||||
TONGAdpm_TrendDetection_DOWN
|
||||
};
|
||||
typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
|
||||
|
||||
/* Bit vector representing same fields as hardware register. */
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy */
|
||||
/* HDP_busy */
|
||||
/* IH_busy */
|
||||
/* DRM_busy */
|
||||
/* DRMDMA_busy */
|
||||
/* UVD_busy */
|
||||
/* VCE_busy */
|
||||
/* ACP_busy */
|
||||
/* SAMU_busy */
|
||||
/* AVP_busy */
|
||||
/* SDMA enabled */
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
|
||||
/* SH_Gfx_busy */
|
||||
/* RB_Gfx_busy */
|
||||
/* VCE_busy */
|
||||
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
|
||||
/* FE_Gfx_busy */
|
||||
/* RB_Gfx_busy */
|
||||
/* ACP_busy */
|
||||
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
|
||||
/* FE_Gfx_busy */
|
||||
/* SH_Gfx_busy */
|
||||
/* UVD_busy */
|
||||
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy */
|
||||
/* VCE_busy */
|
||||
/* ACP_busy */
|
||||
/* SAMU_busy */
|
||||
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP, DRMDMA */
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP, DRMDMA */
|
||||
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP, DRMDMA */
|
||||
|
||||
|
||||
/* thermal protection counter (units).*/
|
||||
#define PPTONGA_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
|
||||
|
||||
/* static screen threshold unit */
|
||||
#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT 0
|
||||
|
||||
/* static screen threshold */
|
||||
#define PPTONGA_STATICSCREENTHRESHOLD_DFLT 0x00C8
|
||||
|
||||
/* gfx idle clock stop threshold */
|
||||
#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
|
||||
|
||||
/* Fixed reference divider to use when building baby stepping tables. */
|
||||
#define PPTONGA_REFERENCEDIVIDER_DFLT 4
|
||||
|
||||
/*
|
||||
* ULV voltage change delay time
|
||||
* Used to be delay_vreg in N.I. split for S.I.
|
||||
* Using N.I. delay_vreg value as default
|
||||
* ReferenceClock = 2700
|
||||
* VoltageResponseTime = 1000
|
||||
* VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
|
||||
*/
|
||||
|
||||
#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT 1687
|
||||
|
||||
#define PPTONGA_CGULVPARAMETER_DFLT 0x00040035
|
||||
#define PPTONGA_CGULVCONTROL_DFLT 0x00007450
|
||||
#define PPTONGA_TARGETACTIVITY_DFLT 30 /*30% */
|
||||
#define PPTONGA_MCLK_TARGETACTIVITY_DFLT 10 /*10% */
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,402 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 TONGA_HWMGR_H
|
||||
#define TONGA_HWMGR_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "smu72_discrete.h"
|
||||
#include "ppatomctrl.h"
|
||||
#include "ppinterrupt.h"
|
||||
#include "tonga_powertune.h"
|
||||
#include "pp_endian.h"
|
||||
|
||||
#define TONGA_MAX_HARDWARE_POWERLEVELS 2
|
||||
#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
|
||||
|
||||
struct tonga_performance_level {
|
||||
uint32_t memory_clock;
|
||||
uint32_t engine_clock;
|
||||
uint16_t pcie_gen;
|
||||
uint16_t pcie_lane;
|
||||
};
|
||||
|
||||
struct _phw_tonga_bacos {
|
||||
uint32_t best_match;
|
||||
uint32_t baco_flags;
|
||||
struct tonga_performance_level performance_level;
|
||||
};
|
||||
typedef struct _phw_tonga_bacos phw_tonga_bacos;
|
||||
|
||||
struct _phw_tonga_uvd_clocks {
|
||||
uint32_t VCLK;
|
||||
uint32_t DCLK;
|
||||
};
|
||||
|
||||
typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
|
||||
|
||||
struct _phw_tonga_vce_clocks {
|
||||
uint32_t EVCLK;
|
||||
uint32_t ECCLK;
|
||||
};
|
||||
|
||||
typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
|
||||
|
||||
struct tonga_power_state {
|
||||
uint32_t magic;
|
||||
phw_tonga_uvd_clocks uvd_clocks;
|
||||
phw_tonga_vce_clocks vce_clocks;
|
||||
uint32_t sam_clk;
|
||||
uint32_t acp_clk;
|
||||
uint16_t performance_level_count;
|
||||
bool dc_compatible;
|
||||
uint32_t sclk_threshold;
|
||||
struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
|
||||
};
|
||||
|
||||
struct _phw_tonga_dpm_level {
|
||||
bool enabled;
|
||||
uint32_t value;
|
||||
uint32_t param1;
|
||||
};
|
||||
typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
|
||||
|
||||
#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
|
||||
#define MAX_REGULAR_DPM_NUMBER 8
|
||||
#define TONGA_MINIMUM_ENGINE_CLOCK 2500
|
||||
|
||||
struct tonga_single_dpm_table {
|
||||
uint32_t count;
|
||||
phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
|
||||
};
|
||||
|
||||
struct tonga_dpm_table {
|
||||
struct tonga_single_dpm_table sclk_table;
|
||||
struct tonga_single_dpm_table mclk_table;
|
||||
struct tonga_single_dpm_table pcie_speed_table;
|
||||
struct tonga_single_dpm_table vddc_table;
|
||||
struct tonga_single_dpm_table vdd_gfx_table;
|
||||
struct tonga_single_dpm_table vdd_ci_table;
|
||||
struct tonga_single_dpm_table mvdd_table;
|
||||
};
|
||||
typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
|
||||
|
||||
|
||||
struct _phw_tonga_clock_regisiters {
|
||||
uint32_t vCG_SPLL_FUNC_CNTL;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_2;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_3;
|
||||
uint32_t vCG_SPLL_FUNC_CNTL_4;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
|
||||
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
|
||||
uint32_t vDLL_CNTL;
|
||||
uint32_t vMCLK_PWRMGT_CNTL;
|
||||
uint32_t vMPLL_AD_FUNC_CNTL;
|
||||
uint32_t vMPLL_DQ_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL;
|
||||
uint32_t vMPLL_FUNC_CNTL_1;
|
||||
uint32_t vMPLL_FUNC_CNTL_2;
|
||||
uint32_t vMPLL_SS1;
|
||||
uint32_t vMPLL_SS2;
|
||||
};
|
||||
typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
|
||||
|
||||
struct _phw_tonga_voltage_smio_registers {
|
||||
uint32_t vs0_vid_lower_smio_cntl;
|
||||
};
|
||||
typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
|
||||
|
||||
|
||||
struct _phw_tonga_mc_reg_entry {
|
||||
uint32_t mclk_max;
|
||||
uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
|
||||
|
||||
struct _phw_tonga_mc_reg_table {
|
||||
uint8_t last; /* number of registers*/
|
||||
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
|
||||
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
|
||||
phw_tonga_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
|
||||
SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
|
||||
|
||||
#define DISABLE_MC_LOADMICROCODE 1
|
||||
#define DISABLE_MC_CFGPROGRAMMING 2
|
||||
|
||||
/*Ultra Low Voltage parameter structure */
|
||||
struct _phw_tonga_ulv_parm{
|
||||
bool ulv_supported;
|
||||
uint32_t ch_ulv_parameter;
|
||||
uint32_t ulv_volt_change_delay;
|
||||
struct tonga_performance_level ulv_power_level;
|
||||
};
|
||||
typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
|
||||
|
||||
#define TONGA_MAX_LEAKAGE_COUNT 8
|
||||
|
||||
struct _phw_tonga_leakage_voltage {
|
||||
uint16_t count;
|
||||
uint16_t leakage_id[TONGA_MAX_LEAKAGE_COUNT];
|
||||
uint16_t actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
|
||||
};
|
||||
typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
|
||||
|
||||
struct _phw_tonga_display_timing {
|
||||
uint32_t min_clock_insr;
|
||||
uint32_t num_existing_displays;
|
||||
};
|
||||
typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
|
||||
|
||||
struct _phw_tonga_dpmlevel_enable_mask {
|
||||
uint32_t uvd_dpm_enable_mask;
|
||||
uint32_t vce_dpm_enable_mask;
|
||||
uint32_t acp_dpm_enable_mask;
|
||||
uint32_t samu_dpm_enable_mask;
|
||||
uint32_t sclk_dpm_enable_mask;
|
||||
uint32_t mclk_dpm_enable_mask;
|
||||
uint32_t pcie_dpm_enable_mask;
|
||||
};
|
||||
typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
|
||||
|
||||
struct _phw_tonga_pcie_perf_range {
|
||||
uint16_t max;
|
||||
uint16_t min;
|
||||
};
|
||||
typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
|
||||
|
||||
struct _phw_tonga_vbios_boot_state {
|
||||
uint16_t mvdd_bootup_value;
|
||||
uint16_t vddc_bootup_value;
|
||||
uint16_t vddci_bootup_value;
|
||||
uint16_t vddgfx_bootup_value;
|
||||
uint32_t sclk_bootup_value;
|
||||
uint32_t mclk_bootup_value;
|
||||
uint16_t pcie_gen_bootup_value;
|
||||
uint16_t pcie_lane_bootup_value;
|
||||
};
|
||||
typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
|
||||
|
||||
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
|
||||
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
|
||||
#define DPMTABLE_UPDATE_SCLK 0x00000004
|
||||
#define DPMTABLE_UPDATE_MCLK 0x00000008
|
||||
|
||||
/* We need to review which fields are needed. */
|
||||
/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
|
||||
struct tonga_hwmgr {
|
||||
struct tonga_dpm_table dpm_table;
|
||||
struct tonga_dpm_table golden_dpm_table;
|
||||
|
||||
uint32_t voting_rights_clients0;
|
||||
uint32_t voting_rights_clients1;
|
||||
uint32_t voting_rights_clients2;
|
||||
uint32_t voting_rights_clients3;
|
||||
uint32_t voting_rights_clients4;
|
||||
uint32_t voting_rights_clients5;
|
||||
uint32_t voting_rights_clients6;
|
||||
uint32_t voting_rights_clients7;
|
||||
uint32_t static_screen_threshold_unit;
|
||||
uint32_t static_screen_threshold;
|
||||
uint32_t voltage_control;
|
||||
uint32_t vdd_gfx_control;
|
||||
|
||||
uint32_t vddc_vddci_delta;
|
||||
uint32_t vddc_vddgfx_delta;
|
||||
|
||||
struct pp_interrupt_registration_info internal_high_thermal_interrupt_info;
|
||||
struct pp_interrupt_registration_info internal_low_thermal_interrupt_info;
|
||||
struct pp_interrupt_registration_info smc_to_host_interrupt_info;
|
||||
uint32_t active_auto_throttle_sources;
|
||||
|
||||
struct pp_interrupt_registration_info external_throttle_interrupt;
|
||||
irq_handler_func_t external_throttle_callback;
|
||||
void *external_throttle_context;
|
||||
|
||||
struct pp_interrupt_registration_info ctf_interrupt_info;
|
||||
irq_handler_func_t ctf_callback;
|
||||
void *ctf_context;
|
||||
|
||||
phw_tonga_clock_registers clock_registers;
|
||||
phw_tonga_voltage_smio_registers voltage_smio_registers;
|
||||
|
||||
bool is_memory_GDDR5;
|
||||
uint16_t acpi_vddc;
|
||||
bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
|
||||
uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
|
||||
uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
|
||||
uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
|
||||
uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
|
||||
uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
|
||||
phw_tonga_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
|
||||
phw_tonga_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
|
||||
phw_tonga_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
|
||||
|
||||
uint32_t mvdd_control;
|
||||
uint32_t vddc_mask_low;
|
||||
uint32_t mvdd_mask_low;
|
||||
uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
|
||||
uint16_t min_vddc_in_pp_table;
|
||||
uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
|
||||
uint16_t min_vddci_in_pp_table;
|
||||
uint32_t mclk_strobe_mode_threshold;
|
||||
uint32_t mclk_stutter_mode_threshold;
|
||||
uint32_t mclk_edc_enable_threshold;
|
||||
uint32_t mclk_edc_wr_enable_threshold;
|
||||
bool is_uvd_enabled;
|
||||
bool is_xdma_enabled;
|
||||
phw_tonga_vbios_boot_state vbios_boot_state;
|
||||
|
||||
bool battery_state;
|
||||
bool is_tlu_enabled;
|
||||
bool pcie_performance_request;
|
||||
|
||||
/* -------------- SMC SRAM Address of firmware header tables ----------------*/
|
||||
uint32_t sram_end; /* The first address after the SMC SRAM. */
|
||||
uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
|
||||
uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
|
||||
uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
|
||||
uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
|
||||
uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
|
||||
SMU72_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
|
||||
SMU72_Discrete_MCRegisters mc_reg_table;
|
||||
SMU72_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
|
||||
/* -------------- Stuff originally coming from Evergreen --------------------*/
|
||||
phw_tonga_mc_reg_table tonga_mc_reg_table;
|
||||
uint32_t vdd_ci_control;
|
||||
pp_atomctrl_voltage_table vddc_voltage_table;
|
||||
pp_atomctrl_voltage_table vddci_voltage_table;
|
||||
pp_atomctrl_voltage_table vddgfx_voltage_table;
|
||||
pp_atomctrl_voltage_table mvdd_voltage_table;
|
||||
|
||||
uint32_t mgcg_cgtt_local2;
|
||||
uint32_t mgcg_cgtt_local3;
|
||||
uint32_t gpio_debug;
|
||||
uint32_t mc_micro_code_feature;
|
||||
uint32_t highest_mclk;
|
||||
uint16_t acpi_vdd_ci;
|
||||
uint8_t mvdd_high_index;
|
||||
uint8_t mvdd_low_index;
|
||||
bool dll_defaule_on;
|
||||
bool performance_request_registered;
|
||||
|
||||
|
||||
/* ----------------- Low Power Features ---------------------*/
|
||||
phw_tonga_bacos bacos;
|
||||
phw_tonga_ulv_parm ulv;
|
||||
/* ----------------- CAC Stuff ---------------------*/
|
||||
uint32_t cac_table_start;
|
||||
bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
|
||||
bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
|
||||
bool cac_enabled;
|
||||
/* ----------------- DPM2 Parameters ---------------------*/
|
||||
uint32_t power_containment_features;
|
||||
bool enable_bapm_feature;
|
||||
bool enable_tdc_limit_feature;
|
||||
bool enable_pkg_pwr_tracking_feature;
|
||||
bool disable_uvd_power_tune_feature;
|
||||
struct tonga_pt_defaults *power_tune_defaults;
|
||||
SMU72_Discrete_PmFuses power_tune_table;
|
||||
uint32_t dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
|
||||
uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
|
||||
|
||||
|
||||
bool enable_dte_feature;
|
||||
|
||||
|
||||
/* ----------------- Phase Shedding ---------------------*/
|
||||
bool vddc_phase_shed_control;
|
||||
/* --------------------- DI/DT --------------------------*/
|
||||
phw_tonga_display_timing display_timing;
|
||||
/* --------- ReadRegistry data for memory and engine clock margins ---- */
|
||||
uint32_t engine_clock_data;
|
||||
uint32_t memory_clock_data;
|
||||
/* -------- Thermal Temperature Setting --------------*/
|
||||
phw_tonga_dpmlevel_enable_mask dpm_level_enable_mask;
|
||||
uint32_t need_update_smu7_dpm_table;
|
||||
uint32_t sclk_dpm_key_disabled;
|
||||
uint32_t mclk_dpm_key_disabled;
|
||||
uint32_t pcie_dpm_key_disabled;
|
||||
uint32_t min_engine_clocks; /* used to store the previous dal min sclock */
|
||||
phw_tonga_pcie_perf_range pcie_gen_performance;
|
||||
phw_tonga_pcie_perf_range pcie_lane_performance;
|
||||
phw_tonga_pcie_perf_range pcie_gen_power_saving;
|
||||
phw_tonga_pcie_perf_range pcie_lane_power_saving;
|
||||
bool use_pcie_performance_levels;
|
||||
bool use_pcie_power_saving_levels;
|
||||
uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
|
||||
uint32_t mclk_activity_target;
|
||||
uint32_t low_sclk_interrupt_threshold;
|
||||
uint32_t last_mclk_dpm_enable_mask;
|
||||
bool uvd_enabled;
|
||||
uint32_t pcc_monitor_enabled;
|
||||
|
||||
/* --------- Power Gating States ------------*/
|
||||
bool uvd_power_gated; /* 1: gated, 0:not gated */
|
||||
bool vce_power_gated; /* 1: gated, 0:not gated */
|
||||
bool samu_power_gated; /* 1: gated, 0:not gated */
|
||||
bool acp_power_gated; /* 1: gated, 0:not gated */
|
||||
bool pg_acp_init;
|
||||
};
|
||||
|
||||
typedef struct tonga_hwmgr tonga_hwmgr;
|
||||
|
||||
#define TONGA_DPM2_NEAR_TDP_DEC 10
|
||||
#define TONGA_DPM2_ABOVE_SAFE_INC 5
|
||||
#define TONGA_DPM2_BELOW_SAFE_INC 20
|
||||
|
||||
#define TONGA_DPM2_LTA_WINDOW_SIZE 7 /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
|
||||
|
||||
#define TONGA_DPM2_LTS_TRUNCATE 0
|
||||
|
||||
#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT 80 /* Maximum 100 */
|
||||
|
||||
#define TONGA_DPM2_MAXPS_PERCENT_H 90 /* Maximum 0xFF */
|
||||
#define TONGA_DPM2_MAXPS_PERCENT_M 90 /* Maximum 0xFF */
|
||||
|
||||
#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN 50
|
||||
|
||||
#define TONGA_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
|
||||
#define TONGA_DPM2_SQ_RAMP_MIN_POWER 0x12
|
||||
#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
|
||||
#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
|
||||
#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
|
||||
|
||||
#define TONGA_VOLTAGE_CONTROL_NONE 0x0
|
||||
#define TONGA_VOLTAGE_CONTROL_BY_GPIO 0x1
|
||||
#define TONGA_VOLTAGE_CONTROL_BY_SVID2 0x2
|
||||
#define TONGA_VOLTAGE_CONTROL_MERGED 0x3
|
||||
|
||||
#define TONGA_Q88_FORMAT_CONVERSION_UNIT 256 /*To convert to Q8.8 format for firmware */
|
||||
|
||||
#define TONGA_UNUSED_GPIO_PIN 0x7F
|
||||
|
||||
int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
|
||||
int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,495 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hwmgr.h"
|
||||
#include "smumgr.h"
|
||||
#include "tonga_hwmgr.h"
|
||||
#include "tonga_powertune.h"
|
||||
#include "tonga_smumgr.h"
|
||||
#include "smu72_discrete.h"
|
||||
#include "pp_debug.h"
|
||||
#include "tonga_ppsmc.h"
|
||||
|
||||
#define VOLTAGE_SCALE 4
|
||||
#define POWERTUNE_DEFAULT_SET_MAX 1
|
||||
|
||||
struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
|
||||
/* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */
|
||||
{1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
|
||||
{0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
|
||||
{0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } },
|
||||
};
|
||||
|
||||
void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *tonga_hwmgr = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
uint32_t tmp = 0;
|
||||
|
||||
if (table_info &&
|
||||
table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
|
||||
table_info->cac_dtp_table->usPowerTuneDataSetID)
|
||||
tonga_hwmgr->power_tune_defaults =
|
||||
&tonga_power_tune_data_set_array
|
||||
[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
|
||||
else
|
||||
tonga_hwmgr->power_tune_defaults = &tonga_power_tune_data_set_array[0];
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_SQRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_DBRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TDRamping);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TCPRamping);
|
||||
|
||||
tonga_hwmgr->dte_tj_offset = tmp;
|
||||
|
||||
if (!tmp) {
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
tonga_hwmgr->fast_watermark_threshold = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
tmp = 1;
|
||||
tonga_hwmgr->enable_dte_feature = tmp ? false : true;
|
||||
tonga_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
|
||||
tonga_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct tonga_pt_defaults *defaults = data->power_tune_defaults;
|
||||
SMU72_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
|
||||
int i, j, k;
|
||||
uint16_t *pdef1;
|
||||
uint16_t *pdef2;
|
||||
|
||||
|
||||
/* TDP number of fraction bits are changed from 8 to 7 for Fiji
|
||||
* as requested by SMC team
|
||||
*/
|
||||
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
|
||||
(uint16_t)(cac_dtp_table->usTDP * 256));
|
||||
dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
|
||||
(uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
|
||||
|
||||
PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
|
||||
"Target Operating Temp is out of Range!",
|
||||
);
|
||||
|
||||
dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
|
||||
dpm_table->GpuTjHyst = 8;
|
||||
|
||||
dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
|
||||
|
||||
dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
|
||||
pdef1 = defaults->bapmti_r;
|
||||
pdef2 = defaults->bapmti_rc;
|
||||
|
||||
for (i = 0; i < SMU72_DTE_ITERATIONS; i++) {
|
||||
for (j = 0; j < SMU72_DTE_SOURCES; j++) {
|
||||
for (k = 0; k < SMU72_DTE_SINKS; k++) {
|
||||
dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1);
|
||||
dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2);
|
||||
pdef1++;
|
||||
pdef2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
|
||||
data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC;
|
||||
data->power_tune_table.SviLoadLineTrimVddC = 3;
|
||||
data->power_tune_table.SviLoadLineOffsetVddC = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint16_t tdc_limit;
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
|
||||
|
||||
/* TDC number of fraction bits are changed from 8 to 7
|
||||
* for Fiji as requested by SMC team
|
||||
*/
|
||||
tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256);
|
||||
data->power_tune_table.TDC_VDDC_PkgLimit =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
|
||||
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
|
||||
defaults->tdc_vddc_throttle_release_limit_perc;
|
||||
data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
|
||||
uint32_t temp;
|
||||
|
||||
if (tonga_read_smc_sram_dword(hwmgr->smumgr,
|
||||
fuse_table_offset +
|
||||
offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl),
|
||||
(uint32_t *)&temp, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
|
||||
return -EINVAL);
|
||||
else
|
||||
data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int i;
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
/* Currently not used. Set all to zero. */
|
||||
for (i = 0; i < 16; i++)
|
||||
data->power_tune_table.LPMLTemperatureScaler[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if ((hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usFanOutputSensitivity & (1 << 15)) ||
|
||||
(hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0))
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.
|
||||
usFanOutputSensitivity = hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usDefaultFanOutputSensitivity;
|
||||
|
||||
data->power_tune_table.FuzzyFan_PwmSetDelta =
|
||||
PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usFanOutputSensitivity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int i;
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
/* Currently not used. Set all to zero. */
|
||||
for (i = 0; i < 16; i++)
|
||||
data->power_tune_table.GnbLPML[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
uint16_t hi_sidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
|
||||
uint16_t lo_sidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
|
||||
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
|
||||
|
||||
hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
|
||||
lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
|
||||
|
||||
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
|
||||
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
|
||||
CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
uint32_t pm_fuse_table_offset;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
if (tonga_read_smc_sram_dword(hwmgr->smumgr,
|
||||
SMU72_FIRMWARE_HEADER_LOCATION +
|
||||
offsetof(SMU72_Firmware_Header, PmFuseTable),
|
||||
&pm_fuse_table_offset, data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to get pm_fuse_table_offset Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW6 */
|
||||
if (tonga_populate_svi_load_line(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate SviLoadLine Failed!",
|
||||
return -EINVAL);
|
||||
/* DW7 */
|
||||
if (tonga_populate_tdc_limit(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TDCLimit Failed!", return -EINVAL);
|
||||
/* DW8 */
|
||||
if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate TdcWaterfallCtl Failed !",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW9-DW12 */
|
||||
if (tonga_populate_temperature_scaler(hwmgr) != 0)
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate LPMLTemperatureScaler Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW13-DW14 */
|
||||
if (tonga_populate_fuzzy_fan(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate Fuzzy Fan Control parameters Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW15-DW18 */
|
||||
if (tonga_populate_gnb_lpml(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW19 */
|
||||
if (tonga_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate GnbLPML Min and Max Vid Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
/* DW20 */
|
||||
if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
|
||||
return -EINVAL);
|
||||
|
||||
if (tonga_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
|
||||
(uint8_t *)&data->power_tune_table,
|
||||
sizeof(struct SMU72_Discrete_PmFuses), data->sram_end))
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"Attempt to download PmFuseTable Failed!",
|
||||
return -EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_enable_smc_cac(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC)) {
|
||||
int smc_result;
|
||||
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableCac));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to enable CAC in SMC.", result = -1);
|
||||
|
||||
data->cac_enabled = (smc_result == 0) ? true : false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int tonga_disable_smc_cac(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC) && data->cac_enabled) {
|
||||
int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_DisableCac));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable CAC in SMC.", result = -1);
|
||||
|
||||
data->cac_enabled = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int tonga_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
|
||||
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_PkgPwrSetLimit, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tonga_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
|
||||
{
|
||||
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
|
||||
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
|
||||
}
|
||||
|
||||
int tonga_enable_power_containment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
int smc_result;
|
||||
int result = 0;
|
||||
|
||||
data->power_containment_features = 0;
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
if (data->enable_dte_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_EnableDTE));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to enable DTE in SMC.", result = -1;);
|
||||
if (smc_result == 0)
|
||||
data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
|
||||
}
|
||||
|
||||
if (data->enable_tdc_limit_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to enable TDCLimit in SMC.", result = -1;);
|
||||
if (smc_result == 0)
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_TDCLimit;
|
||||
}
|
||||
|
||||
if (data->enable_pkg_pwr_tracking_feature) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
|
||||
if (smc_result == 0) {
|
||||
struct phm_cac_tdp_table *cac_table =
|
||||
table_info->cac_dtp_table;
|
||||
uint32_t default_limit =
|
||||
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
|
||||
|
||||
data->power_containment_features |=
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
|
||||
|
||||
if (tonga_set_power_limit(hwmgr, default_limit))
|
||||
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int tonga_disable_power_containment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment) &&
|
||||
data->power_containment_features) {
|
||||
int smc_result;
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_TDCLimit) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_TDCLimitDisable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable TDCLimit in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_DTE) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_DisableDTE));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable DTE in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
|
||||
if (data->power_containment_features &
|
||||
POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
|
||||
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
|
||||
(uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
|
||||
PP_ASSERT_WITH_CODE((smc_result == 0),
|
||||
"Failed to disable PkgPwrTracking in SMC.",
|
||||
result = smc_result);
|
||||
}
|
||||
data->power_containment_features = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int tonga_power_control_set_level(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
|
||||
int adjust_percent, target_tdp;
|
||||
int result = 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment)) {
|
||||
/* adjustment percentage has already been validated */
|
||||
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
|
||||
hwmgr->platform_descriptor.TDPAdjustment :
|
||||
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
|
||||
/* SMC requested that target_tdp to be 7 bit fraction in DPM table
|
||||
* but message to be 8 bit fraction for messages
|
||||
*/
|
||||
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
|
||||
result = tonga_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,590 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <asm/div64.h>
|
||||
#include "tonga_thermal.h"
|
||||
#include "tonga_hwmgr.h"
|
||||
#include "tonga_smumgr.h"
|
||||
#include "tonga_ppsmc.h"
|
||||
#include "smu/smu_7_1_2_d.h"
|
||||
#include "smu/smu_7_1_2_sh_mask.h"
|
||||
|
||||
/**
|
||||
* Get Fan Speed Control Parameters.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pSpeed is the address of the structure where the result is to be placed.
|
||||
* @exception Always succeeds except if we cannot zero out the output structure.
|
||||
*/
|
||||
int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info)
|
||||
{
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
fan_speed_info->supports_percent_read = true;
|
||||
fan_speed_info->supports_percent_write = true;
|
||||
fan_speed_info->min_percent = 0;
|
||||
fan_speed_info->max_percent = 100;
|
||||
|
||||
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
|
||||
fan_speed_info->supports_rpm_read = true;
|
||||
fan_speed_info->supports_rpm_write = true;
|
||||
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
|
||||
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
|
||||
} else {
|
||||
fan_speed_info->min_rpm = 0;
|
||||
fan_speed_info->max_rpm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Fan Speed in percent.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pSpeed is the address of the structure where the result is to be placed.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
|
||||
|
||||
if (0 == duty100)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
tmp64 = (uint64_t)duty * 100;
|
||||
do_div(tmp64, duty100);
|
||||
*speed = (uint32_t)tmp64;
|
||||
|
||||
if (*speed > 100)
|
||||
*speed = 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Fan Speed in RPM.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the address of the structure where the result is to be placed.
|
||||
* @exception Returns not supported if no fan is found or if pulses per revolution are not set
|
||||
*/
|
||||
int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
||||
{
|
||||
|
||||
if (hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
|
||||
hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = false;
|
||||
}
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed Control to default mode.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Should always succeed.
|
||||
*/
|
||||
int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->fan_ctrl_is_in_default_mode) {
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
|
||||
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
|
||||
result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
|
||||
/*
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM))
|
||||
hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM);
|
||||
else
|
||||
hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM);
|
||||
*/
|
||||
} else {
|
||||
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
|
||||
result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
|
||||
}
|
||||
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
|
||||
if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0)
|
||||
result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL);
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in percent.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (0% - 100%) to be set.
|
||||
* @exception Fails is the 100% setting appears to be 0.
|
||||
*/
|
||||
int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
uint32_t duty100;
|
||||
uint32_t duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return -EINVAL;
|
||||
|
||||
if (speed > 100)
|
||||
speed = 100;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
|
||||
tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (0 == duty100)
|
||||
return -EINVAL;
|
||||
|
||||
tmp64 = (uint64_t)speed * duty100;
|
||||
do_div(tmp64, 100);
|
||||
duty = (uint32_t)tmp64;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
|
||||
|
||||
return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed to default.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @exception Always succeeds.
|
||||
*/
|
||||
int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
if (0 == result)
|
||||
result = tonga_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
} else
|
||||
result = tonga_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fan Speed in RPM.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param speed is the percentage value (min - max) to be set.
|
||||
* @exception Fails is the speed not lie between min and max.
|
||||
*/
|
||||
int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the remote temperature from the SIslands thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
|
||||
|
||||
/* Bit 9 means the reading is lower than the lowest usable value. */
|
||||
if (0 != (0x200 & temp))
|
||||
temp = TONGA_THERMAL_MAXIMUM_TEMP_READING;
|
||||
else
|
||||
temp = (temp & 0x1ff);
|
||||
|
||||
temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the requested temperature range for high and low alert signals
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @param range Temperature range to be programmed for high and low alert signals
|
||||
* @exception PP_Result_BadInput if the input data is not valid.
|
||||
*/
|
||||
static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
|
||||
{
|
||||
uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
|
||||
if (low < low_temp)
|
||||
low = low_temp;
|
||||
if (high > high_temp)
|
||||
high = high_temp;
|
||||
|
||||
if (low > high)
|
||||
return -EINVAL;
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs thermal controller one-time setting registers
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
|
||||
CG_TACH_CTRL, EDGE_PER_REV,
|
||||
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
|
||||
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable thermal alerts on the RV770 thermal controller.
|
||||
*
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to enable internal thermal interrupts */
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable thermal alerts on the RV770 thermal controller.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t alert;
|
||||
|
||||
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
|
||||
alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
|
||||
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
|
||||
|
||||
/* send message to SMU to disable internal thermal interrupts */
|
||||
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitialize the thermal controller.
|
||||
* Currently just disables alerts.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
*/
|
||||
int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = tonga_thermal_disable_alert(hwmgr);
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
tonga_fan_ctrl_set_default_mode(hwmgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the fan table to control the fan using the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||
SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
|
||||
uint32_t duty100;
|
||||
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
|
||||
uint16_t fdo_min, slope1, slope2;
|
||||
uint32_t reference_clock;
|
||||
int res;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
|
||||
return 0;
|
||||
|
||||
if (0 == data->fan_table_start) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
|
||||
if (0 == duty100) {
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
|
||||
do_div(tmp64, 10000);
|
||||
fdo_min = (uint16_t)tmp64;
|
||||
|
||||
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
|
||||
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
|
||||
|
||||
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
|
||||
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
|
||||
|
||||
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
|
||||
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
|
||||
|
||||
fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
|
||||
fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
|
||||
fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
|
||||
|
||||
fan_table.Slope1 = cpu_to_be16(slope1);
|
||||
fan_table.Slope2 = cpu_to_be16(slope2);
|
||||
|
||||
fan_table.FdoMin = cpu_to_be16(fdo_min);
|
||||
|
||||
fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
|
||||
|
||||
fan_table.HystUp = cpu_to_be16(1);
|
||||
|
||||
fan_table.HystSlope = cpu_to_be16(1);
|
||||
|
||||
fan_table.TempRespLim = cpu_to_be16(5);
|
||||
|
||||
reference_clock = tonga_get_xclk(hwmgr);
|
||||
|
||||
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
|
||||
|
||||
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
|
||||
|
||||
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
|
||||
|
||||
fan_table.FanControl_GL_Flag = 1;
|
||||
|
||||
res = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
|
||||
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
|
||||
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
|
||||
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
|
||||
|
||||
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
|
||||
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
|
||||
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
|
||||
|
||||
if (0 != res)
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the fan control on the SMC.
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_tonga_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
|
||||
* Make sure that we still think controlling the fan is OK.
|
||||
*/
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
tonga_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set temperature range for high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from set temperature range routine
|
||||
*/
|
||||
int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
|
||||
|
||||
if (range == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Programs one-time setting registers
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from initialize thermal controller routine
|
||||
*/
|
||||
int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return tonga_thermal_initialize(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from enable alert routine
|
||||
*/
|
||||
int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return tonga_thermal_enable_alert(hwmgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable high and low alerts
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
* @param pInput the pointer to input data
|
||||
* @param pOutput the pointer to output data
|
||||
* @param pStorage the pointer to temporary storage
|
||||
* @param Result the last failure code
|
||||
* @return result from disable alert routine
|
||||
*/
|
||||
static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return tonga_thermal_disable_alert(hwmgr);
|
||||
}
|
||||
|
||||
static const struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = {
|
||||
{ NULL, tf_tonga_thermal_initialize },
|
||||
{ NULL, tf_tonga_thermal_set_temperature_range },
|
||||
{ NULL, tf_tonga_thermal_enable_alert },
|
||||
/* We should restrict performance levels to low before we halt the SMC.
|
||||
* On the other hand we are still in boot state when we do this so it would be pointless.
|
||||
* If this assumption changes we have to revisit this table.
|
||||
*/
|
||||
{ NULL, tf_tonga_thermal_setup_fan_table},
|
||||
{ NULL, tf_tonga_thermal_start_smc_fan_control},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header tonga_thermal_start_thermal_controller_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
tonga_thermal_start_thermal_controller_master_list
|
||||
};
|
||||
|
||||
static const struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = {
|
||||
{ NULL, tf_tonga_thermal_disable_alert},
|
||||
{ NULL, tf_tonga_thermal_set_temperature_range},
|
||||
{ NULL, tf_tonga_thermal_enable_alert},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct phm_master_table_header tonga_thermal_set_temperature_range_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
tonga_thermal_set_temperature_range_master_list
|
||||
};
|
||||
|
||||
int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
tonga_fan_ctrl_set_default_mode(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thermal controller related functions in the Hardware Manager structure.
|
||||
* @param hwmgr The address of the hardware manager.
|
||||
* @exception Any error code from the low-level communication.
|
||||
*/
|
||||
int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
|
||||
|
||||
if (0 == result) {
|
||||
result = phm_construct_table(hwmgr,
|
||||
&tonga_thermal_start_thermal_controller_master,
|
||||
&(hwmgr->start_thermal_controller));
|
||||
if (0 != result)
|
||||
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
|
||||
}
|
||||
|
||||
if (0 == result)
|
||||
hwmgr->fan_ctrl_is_in_default_mode = true;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 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 TONGA_THERMAL_H
|
||||
#define TONGA_THERMAL_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define TONGA_THERMAL_HIGH_ALERT_MASK 0x1
|
||||
#define TONGA_THERMAL_LOW_ALERT_MASK 0x2
|
||||
|
||||
#define TONGA_THERMAL_MINIMUM_TEMP_READING -256
|
||||
#define TONGA_THERMAL_MAXIMUM_TEMP_READING 255
|
||||
|
||||
#define TONGA_THERMAL_MINIMUM_ALERT_TEMP 0
|
||||
#define TONGA_THERMAL_MAXIMUM_ALERT_TEMP 255
|
||||
|
||||
#define FDO_PWM_MODE_STATIC 1
|
||||
#define FDO_PWM_MODE_STATIC_RPM 5
|
||||
|
||||
|
||||
extern int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
extern int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
|
||||
|
||||
extern int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
|
||||
extern int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
|
||||
extern int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
|
||||
extern int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
|
||||
extern int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
|
||||
extern int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -29,6 +29,19 @@
|
|||
#include "amd_shared.h"
|
||||
#include "cgs_common.h"
|
||||
|
||||
enum amd_pp_sensors {
|
||||
AMDGPU_PP_SENSOR_GFX_SCLK = 0,
|
||||
AMDGPU_PP_SENSOR_VDDNB,
|
||||
AMDGPU_PP_SENSOR_VDDGFX,
|
||||
AMDGPU_PP_SENSOR_UVD_VCLK,
|
||||
AMDGPU_PP_SENSOR_UVD_DCLK,
|
||||
AMDGPU_PP_SENSOR_VCE_ECCLK,
|
||||
AMDGPU_PP_SENSOR_GPU_LOAD,
|
||||
AMDGPU_PP_SENSOR_GFX_MCLK,
|
||||
AMDGPU_PP_SENSOR_GPU_TEMP,
|
||||
AMDGPU_PP_SENSOR_VCE_POWER,
|
||||
AMDGPU_PP_SENSOR_UVD_POWER,
|
||||
};
|
||||
|
||||
enum amd_pp_event {
|
||||
AMD_PP_EVENT_INITIALIZE = 0,
|
||||
|
@ -260,6 +273,7 @@ enum amd_pp_clock_type {
|
|||
struct amd_pp_clocks {
|
||||
uint32_t count;
|
||||
uint32_t clock[MAX_NUM_CLOCKS];
|
||||
uint32_t latency[MAX_NUM_CLOCKS];
|
||||
};
|
||||
|
||||
|
||||
|
@ -331,8 +345,6 @@ struct amd_powerplay_funcs {
|
|||
int (*powergate_uvd)(void *handle, bool gate);
|
||||
int (*dispatch_tasks)(void *handle, enum amd_pp_event event_id,
|
||||
void *input, void *output);
|
||||
void (*print_current_performance_level)(void *handle,
|
||||
struct seq_file *m);
|
||||
int (*set_fan_control_mode)(void *handle, uint32_t mode);
|
||||
int (*get_fan_control_mode)(void *handle);
|
||||
int (*set_fan_speed_percent)(void *handle, uint32_t percent);
|
||||
|
@ -346,6 +358,7 @@ struct amd_powerplay_funcs {
|
|||
int (*set_sclk_od)(void *handle, uint32_t value);
|
||||
int (*get_mclk_od)(void *handle);
|
||||
int (*set_mclk_od)(void *handle, uint32_t value);
|
||||
int (*read_sensor)(void *handle, int idx, int32_t *value);
|
||||
};
|
||||
|
||||
struct amd_powerplay {
|
||||
|
@ -377,4 +390,6 @@ int amd_powerplay_get_clock_by_type(void *handle,
|
|||
int amd_powerplay_get_display_mode_validation_clocks(void *handle,
|
||||
struct amd_pp_simple_clock_info *output);
|
||||
|
||||
int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id);
|
||||
|
||||
#endif /* _AMD_POWERPLAY_H_ */
|
||||
|
|
|
@ -311,8 +311,6 @@ struct pp_hwmgr_func {
|
|||
int (*get_sclk)(struct pp_hwmgr *hwmgr, bool low);
|
||||
int (*power_state_set)(struct pp_hwmgr *hwmgr,
|
||||
const void *state);
|
||||
void (*print_current_perforce_level)(struct pp_hwmgr *hwmgr,
|
||||
struct seq_file *m);
|
||||
int (*enable_clock_power_gating)(struct pp_hwmgr *hwmgr);
|
||||
int (*notify_smc_display_config_after_ps_adjustment)(struct pp_hwmgr *hwmgr);
|
||||
int (*display_config_changed)(struct pp_hwmgr *hwmgr);
|
||||
|
@ -359,6 +357,7 @@ struct pp_hwmgr_func {
|
|||
int (*set_sclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);
|
||||
int (*get_mclk_od)(struct pp_hwmgr *hwmgr);
|
||||
int (*set_mclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);
|
||||
int (*read_sensor)(struct pp_hwmgr *hwmgr, int idx, int32_t *value);
|
||||
};
|
||||
|
||||
struct pp_table_func {
|
||||
|
@ -709,6 +708,7 @@ extern int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
|
|||
extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
|
||||
extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
|
||||
|
||||
extern int smu7_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
|
||||
uint32_t sclk, uint16_t id, uint16_t *voltage);
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
#ifndef _POLARIS10_PWRVIRUS_H
|
||||
#define _POLARIS10_PWRVIRUS_H
|
||||
|
||||
#define mmSMC_IND_INDEX_11 0x01AC
|
||||
#define mmSMC_IND_DATA_11 0x01AD
|
||||
|
||||
#define mmCP_HYP_MEC1_UCODE_ADDR 0xf81a
|
||||
#define mmCP_HYP_MEC1_UCODE_DATA 0xf81b
|
||||
#define mmCP_HYP_MEC2_UCODE_ADDR 0xf81c
|
||||
|
|
|
@ -21,21 +21,38 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef ICELAND_SMUM_H
|
||||
#define ICELAND_SMUM_H
|
||||
#ifndef _PP_COMMON_H
|
||||
#define _PP_COMMON_H
|
||||
|
||||
#include "ppsmc.h"
|
||||
#include "smu7_ppsmc.h"
|
||||
#include "cgs_common.h"
|
||||
|
||||
extern int iceland_smu_init(struct amdgpu_device *adev);
|
||||
extern int iceland_smu_fini(struct amdgpu_device *adev);
|
||||
extern int iceland_smu_start(struct amdgpu_device *adev);
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
|
||||
|
||||
#include "smu74.h"
|
||||
#include "smu74_discrete.h"
|
||||
|
||||
#include "gmc/gmc_8_1_d.h"
|
||||
#include "gmc/gmc_8_1_sh_mask.h"
|
||||
|
||||
#include "bif/bif_5_0_d.h"
|
||||
#include "bif/bif_5_0_sh_mask.h"
|
||||
|
||||
|
||||
#include "bif/bif_5_0_d.h"
|
||||
#include "bif/bif_5_0_sh_mask.h"
|
||||
|
||||
#include "dce/dce_10_0_d.h"
|
||||
#include "dce/dce_10_0_sh_mask.h"
|
||||
|
||||
#include "gca/gfx_8_0_d.h"
|
||||
#include "gca/gfx_8_0_sh_mask.h"
|
||||
|
||||
#include "oss/oss_3_0_d.h"
|
||||
#include "oss/oss_3_0_sh_mask.h"
|
||||
|
||||
struct iceland_smu_private_data
|
||||
{
|
||||
uint8_t *header;
|
||||
uint8_t *mec_image;
|
||||
uint32_t header_addr_high;
|
||||
uint32_t header_addr_low;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* Copyright 2015 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 DGPU_VI_PP_SMC_H
|
||||
#define DGPU_VI_PP_SMC_H
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define PPSMC_MSG_SetGBDroopSettings ((uint16_t) 0x305)
|
||||
|
||||
#define PPSMC_SWSTATE_FLAG_DC 0x01
|
||||
#define PPSMC_SWSTATE_FLAG_UVD 0x02
|
||||
#define PPSMC_SWSTATE_FLAG_VCE 0x04
|
||||
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
|
||||
#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
|
||||
#define PPSMC_SYSTEMFLAG_GDDR5 0x04
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
|
||||
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
|
||||
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
|
||||
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
|
||||
|
||||
|
||||
#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
|
||||
#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
|
||||
#define PPSMC_DPM2FLAGS_OCP 0x04
|
||||
|
||||
|
||||
#define PPSMC_DISPLAY_WATERMARK_LOW 0
|
||||
#define PPSMC_DISPLAY_WATERMARK_HIGH 1
|
||||
|
||||
|
||||
#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
|
||||
#define PPSMC_STATEFLAG_POWERBOOST 0x02
|
||||
#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
|
||||
#define PPSMC_STATEFLAG_POWERSHIFT 0x08
|
||||
#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
|
||||
#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
|
||||
#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
|
||||
|
||||
|
||||
#define FDO_MODE_HARDWARE 0
|
||||
#define FDO_MODE_PIECE_WISE_LINEAR 1
|
||||
|
||||
enum FAN_CONTROL {
|
||||
FAN_CONTROL_FUZZY,
|
||||
FAN_CONTROL_TABLE
|
||||
};
|
||||
|
||||
|
||||
#define PPSMC_Result_OK ((uint16_t)0x01)
|
||||
#define PPSMC_Result_NoMore ((uint16_t)0x02)
|
||||
|
||||
#define PPSMC_Result_NotNow ((uint16_t)0x03)
|
||||
#define PPSMC_Result_Failed ((uint16_t)0xFF)
|
||||
#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
|
||||
#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
|
||||
|
||||
typedef uint16_t PPSMC_Result;
|
||||
|
||||
#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
|
||||
|
||||
|
||||
#define PPSMC_MSG_Halt ((uint16_t)0x10)
|
||||
#define PPSMC_MSG_Resume ((uint16_t)0x11)
|
||||
#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
|
||||
#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
|
||||
#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
|
||||
#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
|
||||
#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
|
||||
#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
|
||||
#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
|
||||
#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
|
||||
#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
|
||||
#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
|
||||
#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
|
||||
#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
|
||||
#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
|
||||
#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
|
||||
#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
|
||||
#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
|
||||
#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
|
||||
#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
|
||||
#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
|
||||
#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
|
||||
#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
|
||||
#define PPSMC_CACHistoryStart ((uint16_t)0x57)
|
||||
#define PPSMC_CACHistoryStop ((uint16_t)0x58)
|
||||
#define PPSMC_TDPClampingActive ((uint16_t)0x59)
|
||||
#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
|
||||
#define PPSMC_StartFanControl ((uint16_t)0x5B)
|
||||
#define PPSMC_StopFanControl ((uint16_t)0x5C)
|
||||
#define PPSMC_NoDisplay ((uint16_t)0x5D)
|
||||
#define PPSMC_HasDisplay ((uint16_t)0x5E)
|
||||
#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
|
||||
#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
|
||||
#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
|
||||
#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
|
||||
#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
|
||||
#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
|
||||
#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
|
||||
#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
|
||||
#define PPSMC_OCPActive ((uint16_t)0x6C)
|
||||
#define PPSMC_OCPInactive ((uint16_t)0x6D)
|
||||
#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
|
||||
#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
|
||||
#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
|
||||
#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
|
||||
#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
|
||||
#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
|
||||
#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
|
||||
#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
|
||||
#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
|
||||
#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
|
||||
#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
|
||||
#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
|
||||
#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
|
||||
#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
|
||||
#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
|
||||
#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
|
||||
|
||||
#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
|
||||
#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
|
||||
#define PPSMC_FlushDataCache ((uint16_t)0x80)
|
||||
#define PPSMC_FlushInstrCache ((uint16_t)0x81)
|
||||
|
||||
#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
|
||||
#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
|
||||
|
||||
#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
|
||||
|
||||
#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
|
||||
#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
|
||||
#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
|
||||
#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
|
||||
|
||||
#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
|
||||
#define PPSM_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
|
||||
#define PPSM_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
|
||||
#define PPSM_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
|
||||
|
||||
#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
|
||||
|
||||
#define PPSMC_MSG_Test ((uint16_t) 0x100)
|
||||
#define PPSMC_MSG_DPM_Voltage_Pwrmgt ((uint16_t) 0x101)
|
||||
#define PPSMC_MSG_DPM_Config ((uint16_t) 0x102)
|
||||
#define PPSMC_MSG_PM_Controller_Start ((uint16_t) 0x103)
|
||||
#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104)
|
||||
#define PPSMC_MSG_PG_PowerDownSIMD ((uint16_t) 0x105)
|
||||
#define PPSMC_MSG_PG_PowerUpSIMD ((uint16_t) 0x106)
|
||||
#define PPSMC_MSG_PM_Controller_Stop ((uint16_t) 0x107)
|
||||
#define PPSMC_MSG_PG_SIMD_Config ((uint16_t) 0x108)
|
||||
#define PPSMC_MSG_Voltage_Cntl_Enable ((uint16_t) 0x109)
|
||||
#define PPSMC_MSG_Thermal_Cntl_Enable ((uint16_t) 0x10a)
|
||||
#define PPSMC_MSG_Reset_Service ((uint16_t) 0x10b)
|
||||
#define PPSMC_MSG_VCEPowerOFF ((uint16_t) 0x10e)
|
||||
#define PPSMC_MSG_VCEPowerON ((uint16_t) 0x10f)
|
||||
#define PPSMC_MSG_DPM_Disable_VCE_HS ((uint16_t) 0x110)
|
||||
#define PPSMC_MSG_DPM_Enable_VCE_HS ((uint16_t) 0x111)
|
||||
#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint16_t) 0x112)
|
||||
#define PPSMC_MSG_DCEPowerOFF ((uint16_t) 0x113)
|
||||
#define PPSMC_MSG_DCEPowerON ((uint16_t) 0x114)
|
||||
#define PPSMC_MSG_PCIE_DDIPowerDown ((uint16_t) 0x117)
|
||||
#define PPSMC_MSG_PCIE_DDIPowerUp ((uint16_t) 0x118)
|
||||
#define PPSMC_MSG_PCIE_CascadePLLPowerDown ((uint16_t) 0x119)
|
||||
#define PPSMC_MSG_PCIE_CascadePLLPowerUp ((uint16_t) 0x11a)
|
||||
#define PPSMC_MSG_SYSPLLPowerOff ((uint16_t) 0x11b)
|
||||
#define PPSMC_MSG_SYSPLLPowerOn ((uint16_t) 0x11c)
|
||||
#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d)
|
||||
#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint16_t) 0x11e)
|
||||
#define PPSMC_MSG_DISPLAYPHYStatusNotify ((uint16_t) 0x11f)
|
||||
#define PPSMC_MSG_EnableBAPM ((uint16_t) 0x120)
|
||||
#define PPSMC_MSG_DisableBAPM ((uint16_t) 0x121)
|
||||
#define PPSMC_MSG_Spmi_Enable ((uint16_t) 0x122)
|
||||
#define PPSMC_MSG_Spmi_Timer ((uint16_t) 0x123)
|
||||
#define PPSMC_MSG_LCLK_DPM_Config ((uint16_t) 0x124)
|
||||
#define PPSMC_MSG_VddNB_Request ((uint16_t) 0x125)
|
||||
#define PPSMC_MSG_PCIE_DDIPhyPowerDown ((uint32_t) 0x126)
|
||||
#define PPSMC_MSG_PCIE_DDIPhyPowerUp ((uint32_t) 0x127)
|
||||
#define PPSMC_MSG_MCLKDPM_Config ((uint16_t) 0x128)
|
||||
|
||||
#define PPSMC_MSG_UVDDPM_Config ((uint16_t) 0x129)
|
||||
#define PPSMC_MSG_VCEDPM_Config ((uint16_t) 0x12A)
|
||||
#define PPSMC_MSG_ACPDPM_Config ((uint16_t) 0x12B)
|
||||
#define PPSMC_MSG_SAMUDPM_Config ((uint16_t) 0x12C)
|
||||
#define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D)
|
||||
#define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E)
|
||||
#define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F)
|
||||
#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130)
|
||||
#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131)
|
||||
#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132)
|
||||
#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133)
|
||||
#define PPSMC_MSG_SetTDPLimit ((uint16_t) 0x134)
|
||||
#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135)
|
||||
#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136)
|
||||
#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137)
|
||||
#define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138)
|
||||
#define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139)
|
||||
#define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a)
|
||||
#define PPSMC_MSG_SDMAPowerOFF ((uint16_t) 0x13b)
|
||||
#define PPSMC_MSG_SDMAPowerON ((uint16_t) 0x13c)
|
||||
#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d)
|
||||
#define PPSMC_MSG_IOMMUPowerOFF ((uint16_t) 0x13e)
|
||||
#define PPSMC_MSG_IOMMUPowerON ((uint16_t) 0x13f)
|
||||
#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140)
|
||||
#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141)
|
||||
#define PPSMC_MSG_NBDPM_ForceNominal ((uint16_t) 0x142)
|
||||
#define PPSMC_MSG_NBDPM_ForcePerformance ((uint16_t) 0x143)
|
||||
#define PPSMC_MSG_NBDPM_UnForce ((uint16_t) 0x144)
|
||||
#define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145)
|
||||
#define PPSMC_MSG_MCLKDPM_SetEnabledMask ((uint16_t) 0x146)
|
||||
#define PPSMC_MSG_PCIeDPM_ForceLevel ((uint16_t) 0x147)
|
||||
#define PPSMC_MSG_PCIeDPM_UnForceLevel ((uint16_t) 0x148)
|
||||
#define PPSMC_MSG_EnableACDCGPIOInterrupt ((uint16_t) 0x149)
|
||||
#define PPSMC_MSG_EnableVRHotGPIOInterrupt ((uint16_t) 0x14a)
|
||||
#define PPSMC_MSG_SwitchToAC ((uint16_t) 0x14b)
|
||||
#define PPSMC_MSG_XDMAPowerOFF ((uint16_t) 0x14c)
|
||||
#define PPSMC_MSG_XDMAPowerON ((uint16_t) 0x14d)
|
||||
|
||||
#define PPSMC_MSG_DPM_Enable ((uint16_t) 0x14e)
|
||||
#define PPSMC_MSG_DPM_Disable ((uint16_t) 0x14f)
|
||||
#define PPSMC_MSG_MCLKDPM_Enable ((uint16_t) 0x150)
|
||||
#define PPSMC_MSG_MCLKDPM_Disable ((uint16_t) 0x151)
|
||||
#define PPSMC_MSG_LCLKDPM_Enable ((uint16_t) 0x152)
|
||||
#define PPSMC_MSG_LCLKDPM_Disable ((uint16_t) 0x153)
|
||||
#define PPSMC_MSG_UVDDPM_Enable ((uint16_t) 0x154)
|
||||
#define PPSMC_MSG_UVDDPM_Disable ((uint16_t) 0x155)
|
||||
#define PPSMC_MSG_SAMUDPM_Enable ((uint16_t) 0x156)
|
||||
#define PPSMC_MSG_SAMUDPM_Disable ((uint16_t) 0x157)
|
||||
#define PPSMC_MSG_ACPDPM_Enable ((uint16_t) 0x158)
|
||||
#define PPSMC_MSG_ACPDPM_Disable ((uint16_t) 0x159)
|
||||
#define PPSMC_MSG_VCEDPM_Enable ((uint16_t) 0x15a)
|
||||
#define PPSMC_MSG_VCEDPM_Disable ((uint16_t) 0x15b)
|
||||
#define PPSMC_MSG_LCLKDPM_SetEnabledMask ((uint16_t) 0x15c)
|
||||
#define PPSMC_MSG_DPM_FPS_Mode ((uint16_t) 0x15d)
|
||||
#define PPSMC_MSG_DPM_Activity_Mode ((uint16_t) 0x15e)
|
||||
#define PPSMC_MSG_VddC_Request ((uint16_t) 0x15f)
|
||||
#define PPSMC_MSG_MCLKDPM_GetEnabledMask ((uint16_t) 0x160)
|
||||
#define PPSMC_MSG_LCLKDPM_GetEnabledMask ((uint16_t) 0x161)
|
||||
#define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162)
|
||||
#define PPSMC_MSG_UVDDPM_GetEnabledMask ((uint16_t) 0x163)
|
||||
#define PPSMC_MSG_SAMUDPM_GetEnabledMask ((uint16_t) 0x164)
|
||||
#define PPSMC_MSG_ACPDPM_GetEnabledMask ((uint16_t) 0x165)
|
||||
#define PPSMC_MSG_VCEDPM_GetEnabledMask ((uint16_t) 0x166)
|
||||
#define PPSMC_MSG_PCIeDPM_SetEnabledMask ((uint16_t) 0x167)
|
||||
#define PPSMC_MSG_PCIeDPM_GetEnabledMask ((uint16_t) 0x168)
|
||||
#define PPSMC_MSG_TDCLimitEnable ((uint16_t) 0x169)
|
||||
#define PPSMC_MSG_TDCLimitDisable ((uint16_t) 0x16a)
|
||||
#define PPSMC_MSG_DPM_AutoRotate_Mode ((uint16_t) 0x16b)
|
||||
#define PPSMC_MSG_DISPCLK_FROM_FCH ((uint16_t) 0x16c)
|
||||
#define PPSMC_MSG_DISPCLK_FROM_DFS ((uint16_t) 0x16d)
|
||||
#define PPSMC_MSG_DPREFCLK_FROM_FCH ((uint16_t) 0x16e)
|
||||
#define PPSMC_MSG_DPREFCLK_FROM_DFS ((uint16_t) 0x16f)
|
||||
#define PPSMC_MSG_PmStatusLogStart ((uint16_t) 0x170)
|
||||
#define PPSMC_MSG_PmStatusLogSample ((uint16_t) 0x171)
|
||||
#define PPSMC_MSG_SCLK_AutoDPM_ON ((uint16_t) 0x172)
|
||||
#define PPSMC_MSG_MCLK_AutoDPM_ON ((uint16_t) 0x173)
|
||||
#define PPSMC_MSG_LCLK_AutoDPM_ON ((uint16_t) 0x174)
|
||||
#define PPSMC_MSG_UVD_AutoDPM_ON ((uint16_t) 0x175)
|
||||
#define PPSMC_MSG_SAMU_AutoDPM_ON ((uint16_t) 0x176)
|
||||
#define PPSMC_MSG_ACP_AutoDPM_ON ((uint16_t) 0x177)
|
||||
#define PPSMC_MSG_VCE_AutoDPM_ON ((uint16_t) 0x178)
|
||||
#define PPSMC_MSG_PCIe_AutoDPM_ON ((uint16_t) 0x179)
|
||||
#define PPSMC_MSG_MASTER_AutoDPM_ON ((uint16_t) 0x17a)
|
||||
#define PPSMC_MSG_MASTER_AutoDPM_OFF ((uint16_t) 0x17b)
|
||||
#define PPSMC_MSG_DYNAMICDISPPHYPOWER ((uint16_t) 0x17c)
|
||||
#define PPSMC_MSG_CAC_COLLECTION_ON ((uint16_t) 0x17d)
|
||||
#define PPSMC_MSG_CAC_COLLECTION_OFF ((uint16_t) 0x17e)
|
||||
#define PPSMC_MSG_CAC_CORRELATION_ON ((uint16_t) 0x17f)
|
||||
#define PPSMC_MSG_CAC_CORRELATION_OFF ((uint16_t) 0x180)
|
||||
#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON ((uint16_t) 0x181)
|
||||
#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF ((uint16_t) 0x182)
|
||||
#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT ((uint16_t) 0x184)
|
||||
#define PPSMC_MSG_PkgPwrLimitEnable ((uint16_t) 0x185)
|
||||
#define PPSMC_MSG_PkgPwrLimitDisable ((uint16_t) 0x186)
|
||||
#define PPSMC_MSG_PkgPwrSetLimit ((uint16_t) 0x187)
|
||||
#define PPSMC_MSG_OverDriveSetTargetTdp ((uint16_t) 0x188)
|
||||
#define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189)
|
||||
#define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A)
|
||||
#define PPSMC_MSG_MCLKDPM_FreezeLevel ((uint16_t) 0x18B)
|
||||
#define PPSMC_MSG_MCLKDPM_UnfreezeLevel ((uint16_t) 0x18C)
|
||||
#define PPSMC_MSG_START_DRAM_LOGGING ((uint16_t) 0x18D)
|
||||
#define PPSMC_MSG_STOP_DRAM_LOGGING ((uint16_t) 0x18E)
|
||||
#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
|
||||
#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
|
||||
#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
|
||||
#define PPSMC_MSG_DisableACDCGPIOInterrupt ((uint16_t) 0x192)
|
||||
#define PPSMC_MSG_OverrideVoltageControl_SetVddc ((uint16_t) 0x193)
|
||||
#define PPSMC_MSG_OverrideVoltageControl_SetVddci ((uint16_t) 0x194)
|
||||
#define PPSMC_MSG_SetVidOffset_1 ((uint16_t) 0x195)
|
||||
#define PPSMC_MSG_SetVidOffset_2 ((uint16_t) 0x207)
|
||||
#define PPSMC_MSG_GetVidOffset_1 ((uint16_t) 0x196)
|
||||
#define PPSMC_MSG_GetVidOffset_2 ((uint16_t) 0x208)
|
||||
#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable ((uint16_t) 0x197)
|
||||
#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable ((uint16_t) 0x198)
|
||||
#define PPSMC_MSG_SetTjMax ((uint16_t) 0x199)
|
||||
#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A)
|
||||
#define PPSMC_MSG_WaitForMclkSwitchFinish ((uint16_t) 0x19B)
|
||||
#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C)
|
||||
#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D)
|
||||
|
||||
#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
|
||||
#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
|
||||
#define PPSMC_MSG_API_GetSclkBusy ((uint16_t) 0x202)
|
||||
#define PPSMC_MSG_API_GetMclkBusy ((uint16_t) 0x203)
|
||||
#define PPSMC_MSG_API_GetAsicPower ((uint16_t) 0x204)
|
||||
#define PPSMC_MSG_SetFanRpmMax ((uint16_t) 0x205)
|
||||
#define PPSMC_MSG_SetFanSclkTarget ((uint16_t) 0x206)
|
||||
#define PPSMC_MSG_SetFanMinPwm ((uint16_t) 0x209)
|
||||
#define PPSMC_MSG_SetFanTemperatureTarget ((uint16_t) 0x20A)
|
||||
|
||||
#define PPSMC_MSG_BACO_StartMonitor ((uint16_t) 0x240)
|
||||
#define PPSMC_MSG_BACO_Cancel ((uint16_t) 0x241)
|
||||
#define PPSMC_MSG_EnableVddGfx ((uint16_t) 0x242)
|
||||
#define PPSMC_MSG_DisableVddGfx ((uint16_t) 0x243)
|
||||
#define PPSMC_MSG_UcodeAddressLow ((uint16_t) 0x244)
|
||||
#define PPSMC_MSG_UcodeAddressHigh ((uint16_t) 0x245)
|
||||
#define PPSMC_MSG_UcodeLoadStatus ((uint16_t) 0x246)
|
||||
|
||||
#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t) 0x250)
|
||||
#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t) 0x251)
|
||||
#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t) 0x252)
|
||||
#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t) 0x253)
|
||||
#define PPSMC_MSG_LoadUcodes ((uint16_t) 0x254)
|
||||
#define PPSMC_MSG_PowerStateNotify ((uint16_t) 0x255)
|
||||
#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI ((uint16_t) 0x256)
|
||||
#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO ((uint16_t) 0x257)
|
||||
#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI ((uint16_t) 0x258)
|
||||
#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO ((uint16_t) 0x259)
|
||||
#define PPSMC_MSG_LoadVBios ((uint16_t) 0x25A)
|
||||
#define PPSMC_MSG_GetUcodeVersion ((uint16_t) 0x25B)
|
||||
#define DMCUSMC_MSG_PSREntry ((uint16_t) 0x25C)
|
||||
#define DMCUSMC_MSG_PSRExit ((uint16_t) 0x25D)
|
||||
#define PPSMC_MSG_EnableClockGatingFeature ((uint16_t) 0x260)
|
||||
#define PPSMC_MSG_DisableClockGatingFeature ((uint16_t) 0x261)
|
||||
#define PPSMC_MSG_IsDeviceRunning ((uint16_t) 0x262)
|
||||
#define PPSMC_MSG_LoadMetaData ((uint16_t) 0x263)
|
||||
#define PPSMC_MSG_TMON_AutoCaliberate_Enable ((uint16_t) 0x264)
|
||||
#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
|
||||
#define PPSMC_MSG_GetTelemetry1Slope ((uint16_t) 0x266)
|
||||
#define PPSMC_MSG_GetTelemetry1Offset ((uint16_t) 0x267)
|
||||
#define PPSMC_MSG_GetTelemetry2Slope ((uint16_t) 0x268)
|
||||
#define PPSMC_MSG_GetTelemetry2Offset ((uint16_t) 0x269)
|
||||
#define PPSMC_MSG_EnableAvfs ((uint16_t) 0x26A)
|
||||
#define PPSMC_MSG_DisableAvfs ((uint16_t) 0x26B)
|
||||
|
||||
#define PPSMC_MSG_PerformBtc ((uint16_t) 0x26C)
|
||||
#define PPSMC_MSG_VftTableIsValid ((uint16_t) 0x275)
|
||||
#define PPSMC_MSG_UseNewGPIOScheme ((uint16_t) 0x277)
|
||||
#define PPSMC_MSG_GetEnabledPsm ((uint16_t) 0x400)
|
||||
#define PPSMC_MSG_AgmStartPsm ((uint16_t) 0x401)
|
||||
#define PPSMC_MSG_AgmReadPsm ((uint16_t) 0x402)
|
||||
#define PPSMC_MSG_AgmResetPsm ((uint16_t) 0x403)
|
||||
#define PPSMC_MSG_ReadVftCell ((uint16_t) 0x404)
|
||||
|
||||
#define PPSMC_MSG_GFX_CU_PG_ENABLE ((uint16_t) 0x280)
|
||||
#define PPSMC_MSG_GFX_CU_PG_DISABLE ((uint16_t) 0x281)
|
||||
#define PPSMC_MSG_GetCurrPkgPwr ((uint16_t) 0x282)
|
||||
|
||||
#define PPSMC_MSG_SetGpuPllDfsForSclk ((uint16_t) 0x300)
|
||||
#define PPSMC_MSG_Didt_Block_Function ((uint16_t) 0x301)
|
||||
|
||||
#define PPSMC_MSG_SetVBITimeout ((uint16_t) 0x306)
|
||||
|
||||
#define PPSMC_MSG_SecureSRBMWrite ((uint16_t) 0x600)
|
||||
#define PPSMC_MSG_SecureSRBMRead ((uint16_t) 0x601)
|
||||
#define PPSMC_MSG_SetAddress ((uint16_t) 0x800)
|
||||
#define PPSMC_MSG_GetData ((uint16_t) 0x801)
|
||||
#define PPSMC_MSG_SetData ((uint16_t) 0x802)
|
||||
|
||||
typedef uint16_t PPSMC_Msg;
|
||||
|
||||
#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
|
||||
#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
|
||||
#define PPSMC_EVENT_STATUS_DC 0x00000004
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
struct pp_smumgr;
|
||||
struct pp_instance;
|
||||
struct pp_hwmgr;
|
||||
|
||||
#define smu_lower_32_bits(n) ((uint32_t)(n))
|
||||
#define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16))
|
||||
|
@ -53,6 +54,45 @@ enum AVFS_BTC_STATUS {
|
|||
AVFS_BTC_SMUMSG_ERROR
|
||||
};
|
||||
|
||||
enum SMU_TABLE {
|
||||
SMU_UVD_TABLE = 0,
|
||||
SMU_VCE_TABLE,
|
||||
SMU_SAMU_TABLE,
|
||||
SMU_BIF_TABLE,
|
||||
};
|
||||
|
||||
enum SMU_TYPE {
|
||||
SMU_SoftRegisters = 0,
|
||||
SMU_Discrete_DpmTable,
|
||||
};
|
||||
|
||||
enum SMU_MEMBER {
|
||||
HandshakeDisables = 0,
|
||||
VoltageChangeTimeout,
|
||||
AverageGraphicsActivity,
|
||||
PreVBlankGap,
|
||||
VBlankTimeout,
|
||||
UcodeLoadStatus,
|
||||
UvdBootLevel,
|
||||
VceBootLevel,
|
||||
SamuBootLevel,
|
||||
LowSclkInterruptThreshold,
|
||||
};
|
||||
|
||||
|
||||
enum SMU_MAC_DEFINITION {
|
||||
SMU_MAX_LEVELS_GRAPHICS = 0,
|
||||
SMU_MAX_LEVELS_MEMORY,
|
||||
SMU_MAX_LEVELS_LINK,
|
||||
SMU_MAX_ENTRIES_SMIO,
|
||||
SMU_MAX_LEVELS_VDDC,
|
||||
SMU_MAX_LEVELS_VDDGFX,
|
||||
SMU_MAX_LEVELS_VDDCI,
|
||||
SMU_MAX_LEVELS_MVDD,
|
||||
SMU_UVD_MCLK_HANDSHAKE_DISABLE,
|
||||
};
|
||||
|
||||
|
||||
struct pp_smumgr_func {
|
||||
int (*smu_init)(struct pp_smumgr *smumgr);
|
||||
int (*smu_fini)(struct pp_smumgr *smumgr);
|
||||
|
@ -69,6 +109,18 @@ struct pp_smumgr_func {
|
|||
int (*download_pptable_settings)(struct pp_smumgr *smumgr,
|
||||
void **table);
|
||||
int (*upload_pptable_settings)(struct pp_smumgr *smumgr);
|
||||
int (*update_smc_table)(struct pp_hwmgr *hwmgr, uint32_t type);
|
||||
int (*process_firmware_header)(struct pp_hwmgr *hwmgr);
|
||||
int (*update_sclk_threshold)(struct pp_hwmgr *hwmgr);
|
||||
int (*thermal_setup_fan_table)(struct pp_hwmgr *hwmgr);
|
||||
int (*thermal_avfs_enable)(struct pp_hwmgr *hwmgr);
|
||||
int (*init_smc_table)(struct pp_hwmgr *hwmgr);
|
||||
int (*populate_all_graphic_levels)(struct pp_hwmgr *hwmgr);
|
||||
int (*populate_all_memory_levels)(struct pp_hwmgr *hwmgr);
|
||||
int (*initialize_mc_reg_table)(struct pp_hwmgr *hwmgr);
|
||||
uint32_t (*get_offsetof)(uint32_t type, uint32_t member);
|
||||
uint32_t (*get_mac_definition)(uint32_t value);
|
||||
bool (*is_dpm_running)(struct pp_hwmgr *hwmgr);
|
||||
};
|
||||
|
||||
struct pp_smumgr {
|
||||
|
@ -127,6 +179,24 @@ extern int tonga_smum_init(struct pp_smumgr *smumgr);
|
|||
extern int fiji_smum_init(struct pp_smumgr *smumgr);
|
||||
extern int polaris10_smum_init(struct pp_smumgr *smumgr);
|
||||
|
||||
extern int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr);
|
||||
|
||||
extern int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
|
||||
extern int smum_process_firmware_header(struct pp_hwmgr *hwmgr);
|
||||
extern int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result);
|
||||
extern int smum_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result);
|
||||
extern int smum_init_smc_table(struct pp_hwmgr *hwmgr);
|
||||
extern int smum_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
|
||||
extern int smum_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
|
||||
extern int smum_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
|
||||
extern uint32_t smum_get_offsetof(struct pp_smumgr *smumgr,
|
||||
uint32_t type, uint32_t member);
|
||||
extern uint32_t smum_get_mac_definition(struct pp_smumgr *smumgr, uint32_t value);
|
||||
|
||||
extern bool smum_is_dpm_running(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#define SMUM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
|
||||
|
||||
#define SMUM_FIELD_MASK(reg, field) reg##__##field##_MASK
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
# Makefile for the 'smu manager' sub-component of powerplay.
|
||||
# It provides the smu management services for the driver.
|
||||
|
||||
SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o \
|
||||
polaris10_smumgr.o iceland_smumgr.o
|
||||
SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o \
|
||||
polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o tonga_smc.o \
|
||||
smu7_smumgr.o iceland_smc.o
|
||||
|
||||
AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR))
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
* Copyright 2015 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"),
|
||||
|
@ -20,23 +20,32 @@
|
|||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef FIJI_SMC_H
|
||||
#define FIJI_SMC_H
|
||||
|
||||
#ifndef FIJI_SMUMGR_H
|
||||
#define FIJI_SMUMGR_H
|
||||
#include "smumgr.h"
|
||||
#include "smu73.h"
|
||||
|
||||
#include "fiji_ppsmc.h"
|
||||
|
||||
int fiji_smu_init(struct amdgpu_device *adev);
|
||||
int fiji_smu_fini(struct amdgpu_device *adev);
|
||||
int fiji_smu_start(struct amdgpu_device *adev);
|
||||
|
||||
struct fiji_smu_private_data
|
||||
{
|
||||
uint8_t *header;
|
||||
uint32_t smu_buffer_addr_high;
|
||||
uint32_t smu_buffer_addr_low;
|
||||
uint32_t header_addr_high;
|
||||
uint32_t header_addr_low;
|
||||
struct fiji_pt_defaults {
|
||||
uint8_t SviLoadLineEn;
|
||||
uint8_t SviLoadLineVddC;
|
||||
uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
|
||||
uint8_t TDC_MAWt;
|
||||
uint8_t TdcWaterfallCtl;
|
||||
uint8_t DTEAmbientTempBase;
|
||||
};
|
||||
|
||||
int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
|
||||
int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
|
||||
int fiji_init_smc_table(struct pp_hwmgr *hwmgr);
|
||||
int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
|
||||
int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
|
||||
int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr);
|
||||
uint32_t fiji_get_offsetof(uint32_t type, uint32_t member);
|
||||
uint32_t fiji_get_mac_definition(uint32_t value);
|
||||
int fiji_process_firmware_header(struct pp_hwmgr *hwmgr);
|
||||
int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
|
||||
bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "bif/bif_5_0_sh_mask.h"
|
||||
#include "pp_debug.h"
|
||||
#include "fiji_pwrvirus.h"
|
||||
#include "fiji_smc.h"
|
||||
|
||||
#define AVFS_EN_MSB 1568
|
||||
#define AVFS_EN_LSB 1568
|
||||
|
@ -57,509 +58,6 @@ static const struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = {
|
|||
{ 0xf811d047, 0x80380100, 0x01, 0x00, 0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000, 0, 0, 0x0c, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
static enum cgs_ucode_id fiji_convert_fw_type_to_cgs(uint32_t fw_type)
|
||||
{
|
||||
enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SMU:
|
||||
result = CGS_UCODE_ID_SMU;
|
||||
break;
|
||||
case UCODE_ID_SDMA0:
|
||||
result = CGS_UCODE_ID_SDMA0;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = CGS_UCODE_ID_SDMA1;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = CGS_UCODE_ID_CP_CE;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = CGS_UCODE_ID_CP_PFP;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = CGS_UCODE_ID_CP_ME;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
result = CGS_UCODE_ID_CP_MEC;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT1;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT2;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = CGS_UCODE_ID_RLC_G;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Set the address for reading/writing the SMC SRAM space.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smc_addr the address in the SMC RAM to access.
|
||||
*/
|
||||
static int fiji_set_smc_sram_address(struct pp_smumgr *smumgr,
|
||||
uint32_t smc_addr, uint32_t limit)
|
||||
{
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)),
|
||||
"SMC address must be 4 byte aligned.", return -EINVAL;);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)),
|
||||
"SMC address is beyond the SMC RAM area.", return -EINVAL;);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smc_addr);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an array into the SMC RAM space.
|
||||
*
|
||||
* @param smumgr the address of the powerplay SMU manager.
|
||||
* @param smcStartAddress the start address in the SMC RAM to copy bytes to.
|
||||
* @param src the byte array to copy the bytes from.
|
||||
* @param byteCount the number of bytes to copy.
|
||||
*/
|
||||
int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr,
|
||||
uint32_t smcStartAddress, const uint8_t *src,
|
||||
uint32_t byteCount, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
uint32_t data, originalData;
|
||||
uint32_t addr, extraShift;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
|
||||
"SMC address must be 4 byte aligned.", return -EINVAL;);
|
||||
PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
|
||||
"SMC address is beyond the SMC RAM area.", return -EINVAL;);
|
||||
|
||||
addr = smcStartAddress;
|
||||
|
||||
while (byteCount >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first. */
|
||||
data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
|
||||
|
||||
result = fiji_set_smc_sram_address(smumgr, addr, limit);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byteCount -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (byteCount) {
|
||||
/* Now write the odd bytes left.
|
||||
* Do a read modify write cycle.
|
||||
*/
|
||||
data = 0;
|
||||
|
||||
result = fiji_set_smc_sram_address(smumgr, addr, limit);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
originalData = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
|
||||
extraShift = 8 * (4 - byteCount);
|
||||
|
||||
while (byteCount > 0) {
|
||||
/* Bytes are written into the SMC addres
|
||||
* space with the MSB first.
|
||||
*/
|
||||
data = (0x100 * data) + *src++;
|
||||
byteCount--;
|
||||
}
|
||||
data <<= extraShift;
|
||||
data |= (originalData & ~((~0UL) << extraShift));
|
||||
|
||||
result = fiji_set_smc_sram_address(smumgr, addr, limit);
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_program_jump_on_start(struct pp_smumgr *smumgr)
|
||||
{
|
||||
static const unsigned char data[] = { 0xE0, 0x00, 0x80, 0x40 };
|
||||
|
||||
fiji_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data) + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the SMC is currently running.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
*/
|
||||
bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
|
||||
CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
|
||||
&& (0x20100 <= cgs_read_ind_register(smumgr->device,
|
||||
CGS_IND_REG__SMC, ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC, and wait for its response.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param msg the message to send.
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(smumgr))
|
||||
return -1;
|
||||
|
||||
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
|
||||
printk(KERN_ERR "Failed to send Previous Message.");
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
}
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC with parameter
|
||||
* @param smumgr: the address of the powerplay hardware manager.
|
||||
* @param msg: the message to send.
|
||||
* @param parameter: the parameter to send
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int fiji_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
|
||||
uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(smumgr))
|
||||
return -1;
|
||||
|
||||
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
|
||||
printk(KERN_ERR "Failed to send Previous Message.");
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
}
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to the SMC with parameter, do not wait for response
|
||||
*
|
||||
* @param smumgr: the address of the powerplay hardware manager.
|
||||
* @param msg: the message to send.
|
||||
* @param parameter: the parameter to send
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int fiji_send_msg_to_smc_with_parameter_without_waiting(
|
||||
struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
|
||||
printk(KERN_ERR "Failed to send Previous Message.");
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
}
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the SMU firmware from .hex file
|
||||
*
|
||||
* @param smumgr the address of the powerplay SMU manager.
|
||||
* @return 0 or -1.
|
||||
*/
|
||||
|
||||
static int fiji_upload_smu_firmware_image(struct pp_smumgr *smumgr)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint32_t byte_count;
|
||||
uint32_t *data;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
fiji_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
|
||||
|
||||
if (info.image_size & 3) {
|
||||
printk(KERN_ERR "SMC ucode is not 4 bytes aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info.image_size > FIJI_SMC_SIZE) {
|
||||
printk(KERN_ERR "SMC address is beyond the SMC RAM area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
|
||||
byte_count = info.image_size;
|
||||
src = (const uint8_t *)info.kptr;
|
||||
|
||||
data = (uint32_t *)src;
|
||||
for (; byte_count >= 4; data++, byte_count -= 4)
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32bit value from the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smc_addr the address in the SMC RAM to access.
|
||||
* @param value and output parameter for the data read from the SMC SRAM.
|
||||
*/
|
||||
int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
|
||||
uint32_t *value, uint32_t limit)
|
||||
{
|
||||
int result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32bit value to the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smc_addr the address in the SMC RAM to access.
|
||||
* @param value to write to the SMC SRAM.
|
||||
*/
|
||||
int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
|
||||
uint32_t value, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t fiji_get_mask_for_firmware_type(uint32_t fw_type)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
result = UCODE_ID_SDMA0_MASK;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = UCODE_ID_SDMA1_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = UCODE_ID_CP_CE_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = UCODE_ID_CP_PFP_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = UCODE_ID_CP_ME_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT2_MASK;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = UCODE_ID_RLC_G_MASK;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "UCode type is out of range!");
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Populate one firmware image to the data structure */
|
||||
static int fiji_populate_single_firmware_entry(struct pp_smumgr *smumgr,
|
||||
uint32_t fw_type, struct SMU_Entry *entry)
|
||||
{
|
||||
int result;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
result = cgs_get_firmware_info(
|
||||
smumgr->device,
|
||||
fiji_convert_fw_type_to_cgs(fw_type),
|
||||
&info);
|
||||
|
||||
if (!result) {
|
||||
entry->version = 0;
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
|
||||
entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = info.image_size;
|
||||
entry->num_register_entries = 0;
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_request_smu_load_fw(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
|
||||
uint32_t fw_to_load;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
|
||||
if (priv->soft_regs_start)
|
||||
cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
|
||||
priv->soft_regs_start +
|
||||
offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
|
||||
0x0);
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)priv->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == fiji_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n" , return -1 );
|
||||
|
||||
fiji_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI,
|
||||
priv->header_buffer.mc_addr_high);
|
||||
fiji_send_msg_to_smc_with_parameter(smumgr,PPSMC_MSG_DRV_DRAM_ADDR_LO,
|
||||
priv->header_buffer.mc_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK
|
||||
+ UCODE_ID_SDMA0_MASK
|
||||
+ UCODE_ID_SDMA1_MASK
|
||||
+ UCODE_ID_CP_CE_MASK
|
||||
+ UCODE_ID_CP_ME_MASK
|
||||
+ UCODE_ID_CP_PFP_MASK
|
||||
+ UCODE_ID_CP_MEC_MASK
|
||||
+ UCODE_ID_CP_MEC_JT1_MASK
|
||||
+ UCODE_ID_CP_MEC_JT2_MASK;
|
||||
|
||||
if (fiji_send_msg_to_smc_with_parameter(smumgr,
|
||||
PPSMC_MSG_LoadUcodes, fw_to_load))
|
||||
printk(KERN_ERR "Fail to Request SMU Load uCode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Check if the FW has been loaded, SMU will not return
|
||||
* if loading has not finished.
|
||||
*/
|
||||
static int fiji_check_fw_load_finish(struct pp_smumgr *smumgr,
|
||||
uint32_t fw_type)
|
||||
{
|
||||
struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
|
||||
uint32_t mask = fiji_get_mask_for_firmware_type(fw_type);
|
||||
|
||||
/* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
|
||||
if (smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX,
|
||||
priv->soft_regs_start +
|
||||
offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
|
||||
mask, mask)) {
|
||||
printk(KERN_ERR "check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fiji_reload_firmware(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return smumgr->smumgr_funcs->start_smu(smumgr);
|
||||
}
|
||||
|
||||
static bool fiji_is_hw_virtualization_enabled(struct pp_smumgr *smumgr)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
value = cgs_read_register(smumgr->device, mmBIF_IOV_FUNC_IDENTIFIER);
|
||||
if (value & BIF_IOV_FUNC_IDENTIFIER__IOV_ENABLE_MASK) {
|
||||
/* driver reads on SR-IOV enabled PF: 0x80000000
|
||||
* driver reads on SR-IOV enabled VF: 0x80000001
|
||||
* driver reads on SR-IOV disabled: 0x00000000
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int fiji_request_smu_specific_fw_load(struct pp_smumgr *smumgr, uint32_t fw_type)
|
||||
{
|
||||
if (fiji_is_hw_virtualization_enabled(smumgr)) {
|
||||
uint32_t masks = fiji_get_mask_for_firmware_type(fw_type);
|
||||
if (fiji_send_msg_to_smc_with_parameter_without_waiting(smumgr,
|
||||
PPSMC_MSG_LoadUcodes, masks))
|
||||
printk(KERN_ERR "Fail to Request SMU Load uCode");
|
||||
}
|
||||
/* For non-virtualization cases,
|
||||
* SMU loads all FWs at once in fiji_request_smu_load_fw.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
|
||||
{
|
||||
int result = 0;
|
||||
|
@ -571,7 +69,7 @@ static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
|
|||
SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
|
||||
result = fiji_upload_smu_firmware_image(smumgr);
|
||||
result = smu7_upload_smu_firmware_image(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
@ -610,8 +108,8 @@ static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
|
|||
SMU_STATUS, SMU_DONE, 0);
|
||||
|
||||
/* Check pass/failed indicator */
|
||||
if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMU_STATUS, SMU_PASS)) {
|
||||
if (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMU_STATUS, SMU_PASS) != 1) {
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"SMU Firmware start failed!", return -1);
|
||||
}
|
||||
|
@ -639,12 +137,12 @@ static int fiji_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
|
|||
SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
|
||||
result = fiji_upload_smu_firmware_image(smumgr);
|
||||
result = smu7_upload_smu_firmware_image(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Set smc instruct start point at 0x0 */
|
||||
fiji_program_jump_on_start(smumgr);
|
||||
smu7_program_jump_on_start(smumgr);
|
||||
|
||||
/* Enable clock */
|
||||
SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
|
@ -698,15 +196,15 @@ static int fiji_start_avfs_btc(struct pp_smumgr *smumgr)
|
|||
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_STARTED;
|
||||
if (priv->avfs.AvfsBtcParam) {
|
||||
if (!fiji_send_msg_to_smc_with_parameter(smumgr,
|
||||
if (!smum_send_msg_to_smc_with_parameter(smumgr,
|
||||
PPSMC_MSG_PerformBtc, priv->avfs.AvfsBtcParam)) {
|
||||
if (!fiji_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
|
||||
if (!smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED;
|
||||
result = 0;
|
||||
} else {
|
||||
printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt"
|
||||
" to Enable AVFS Failed!");
|
||||
fiji_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
|
||||
smum_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
|
||||
result = -1;
|
||||
}
|
||||
} else {
|
||||
|
@ -736,7 +234,7 @@ int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
|
|||
charz_freq = 0x30750000; /* In 10KHz units 0x00007530 Actual value */
|
||||
inversion_voltage = 0x1A04; /* mV Q14.2 0x41A Actual value */
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
|
||||
SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU73_Firmware_Header,
|
||||
PmFuseTable), &table_start, 0x40000),
|
||||
"[AVFS][Fiji_SetupGfxLvlStruct] SMU could not communicate "
|
||||
|
@ -748,13 +246,13 @@ int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
|
|||
inversion_voltage_addr = table_start +
|
||||
offsetof(struct SMU73_Discrete_PmFuses, InversionVoltage);
|
||||
|
||||
result = fiji_copy_bytes_to_smc(smumgr, charz_freq_addr,
|
||||
result = smu7_copy_bytes_to_smc(smumgr, charz_freq_addr,
|
||||
(uint8_t *)(&charz_freq), sizeof(charz_freq), 0x40000);
|
||||
PP_ASSERT_WITH_CODE(0 == result,
|
||||
"[AVFS][fiji_setup_pm_fuse_for_avfs] charz_freq could not "
|
||||
"be populated.", return -1;);
|
||||
|
||||
result = fiji_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
|
||||
result = smu7_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
|
||||
(uint8_t *)(&inversion_voltage), sizeof(inversion_voltage), 0x40000);
|
||||
PP_ASSERT_WITH_CODE(0 == result, "[AVFS][fiji_setup_pm_fuse_for_avfs] "
|
||||
"charz_freq could not be populated.", return -1;);
|
||||
|
@ -769,7 +267,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
uint32_t level_addr, vr_config_addr;
|
||||
uint32_t level_size = sizeof(avfs_graphics_level);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
|
||||
SMU7_FIRMWARE_HEADER_LOCATION +
|
||||
offsetof(SMU73_Firmware_Header, DpmTable),
|
||||
&table_start, 0x40000),
|
||||
|
@ -784,7 +282,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
vr_config_addr = table_start +
|
||||
offsetof(SMU73_Discrete_DpmTable, VRConfig);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, vr_config_addr,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, vr_config_addr,
|
||||
(uint8_t *)&vr_config, sizeof(int32_t), 0x40000),
|
||||
"[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
|
||||
"vr_config value over to SMC",
|
||||
|
@ -792,7 +290,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
|
||||
level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, level_addr,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, level_addr,
|
||||
(uint8_t *)(&avfs_graphics_level), level_size, 0x40000),
|
||||
"[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
|
||||
return -1;);
|
||||
|
@ -839,13 +337,13 @@ int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started)
|
|||
break;
|
||||
case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
|
||||
PPSMC_MSG_VftTableIsValid),
|
||||
PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(smumgr,
|
||||
0x666),
|
||||
"[AVFS][fiji_avfs_event_mgr] SMU did not respond "
|
||||
"correctly to VftTableIsValid Msg",
|
||||
return -1;);
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
|
||||
PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
|
||||
PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(smumgr,
|
||||
PPSMC_MSG_EnableAvfs),
|
||||
"[AVFS][fiji_avfs_event_mgr] SMU did not respond "
|
||||
"correctly to EnableAvfs Message Msg",
|
||||
|
@ -898,7 +396,7 @@ static int fiji_start_smu(struct pp_smumgr *smumgr)
|
|||
struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
|
||||
|
||||
/* Only start SMC if SMC RAM is not running */
|
||||
if (!fiji_is_smc_ram_running(smumgr)) {
|
||||
if (!smu7_is_smc_ram_running(smumgr)) {
|
||||
fiji_avfs_event_mgr(smumgr, false);
|
||||
|
||||
/* Check if SMU is running in protected mode */
|
||||
|
@ -929,12 +427,12 @@ static int fiji_start_smu(struct pp_smumgr *smumgr)
|
|||
/* Setup SoftRegsStart here for register lookup in case
|
||||
* DummyBackEnd is used and ProcessFirmwareHeader is not executed
|
||||
*/
|
||||
fiji_read_smc_sram_dword(smumgr,
|
||||
smu7_read_smc_sram_dword(smumgr,
|
||||
SMU7_FIRMWARE_HEADER_LOCATION +
|
||||
offsetof(SMU73_Firmware_Header, SoftRegisters),
|
||||
&(priv->soft_regs_start), 0x40000);
|
||||
&(priv->smu7_data.soft_regs_start), 0x40000);
|
||||
|
||||
result = fiji_request_smu_load_fw(smumgr);
|
||||
result = smu7_request_smu_load_fw(smumgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -963,28 +461,10 @@ static bool fiji_is_hw_avfs_present(struct pp_smumgr *smumgr)
|
|||
static int fiji_smu_init(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
|
||||
uint64_t mc_addr;
|
||||
int i;
|
||||
|
||||
priv->header_buffer.data_size =
|
||||
((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
smu_allocate_memory(smumgr->device,
|
||||
priv->header_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&priv->header_buffer.kaddr,
|
||||
&priv->header_buffer.handle);
|
||||
|
||||
priv->header = priv->header_buffer.kaddr;
|
||||
priv->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
priv->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != priv->header),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)priv->header_buffer.handle);
|
||||
return -1);
|
||||
if (smu7_init(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
|
||||
if (fiji_is_hw_avfs_present(smumgr))
|
||||
|
@ -999,37 +479,35 @@ static int fiji_smu_init(struct pp_smumgr *smumgr)
|
|||
else
|
||||
priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
|
||||
|
||||
priv->acpi_optimization = 1;
|
||||
for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
|
||||
priv->activity_target[i] = 30;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_fini(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
|
||||
|
||||
smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle);
|
||||
|
||||
if (smumgr->backend) {
|
||||
kfree(smumgr->backend);
|
||||
smumgr->backend = NULL;
|
||||
}
|
||||
|
||||
cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pp_smumgr_func fiji_smu_funcs = {
|
||||
.smu_init = &fiji_smu_init,
|
||||
.smu_fini = &fiji_smu_fini,
|
||||
.smu_fini = &smu7_smu_fini,
|
||||
.start_smu = &fiji_start_smu,
|
||||
.check_fw_load_finish = &fiji_check_fw_load_finish,
|
||||
.request_smu_load_fw = &fiji_reload_firmware,
|
||||
.request_smu_load_specific_fw = &fiji_request_smu_specific_fw_load,
|
||||
.send_msg_to_smc = &fiji_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter,
|
||||
.check_fw_load_finish = &smu7_check_fw_load_finish,
|
||||
.request_smu_load_fw = &smu7_reload_firmware,
|
||||
.request_smu_load_specific_fw = NULL,
|
||||
.send_msg_to_smc = &smu7_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
|
||||
.download_pptable_settings = NULL,
|
||||
.upload_pptable_settings = NULL,
|
||||
.update_smc_table = fiji_update_smc_table,
|
||||
.get_offsetof = fiji_get_offsetof,
|
||||
.process_firmware_header = fiji_process_firmware_header,
|
||||
.init_smc_table = fiji_init_smc_table,
|
||||
.update_sclk_threshold = fiji_update_sclk_threshold,
|
||||
.thermal_setup_fan_table = fiji_thermal_setup_fan_table,
|
||||
.populate_all_graphic_levels = fiji_populate_all_graphic_levels,
|
||||
.populate_all_memory_levels = fiji_populate_all_memory_levels,
|
||||
.get_mac_definition = fiji_get_mac_definition,
|
||||
.initialize_mc_reg_table = fiji_initialize_mc_reg_table,
|
||||
.is_dpm_running = fiji_is_dpm_running,
|
||||
};
|
||||
|
||||
int fiji_smum_init(struct pp_smumgr *smumgr)
|
||||
|
|
|
@ -23,37 +23,31 @@
|
|||
#ifndef _FIJI_SMUMANAGER_H_
|
||||
#define _FIJI_SMUMANAGER_H_
|
||||
|
||||
#include "smu73_discrete.h"
|
||||
#include <pp_endian.h>
|
||||
#include "smu7_smumgr.h"
|
||||
|
||||
|
||||
|
||||
struct fiji_smu_avfs {
|
||||
enum AVFS_BTC_STATUS AvfsBtcStatus;
|
||||
uint32_t AvfsBtcParam;
|
||||
};
|
||||
|
||||
struct fiji_buffer_entry {
|
||||
uint32_t data_size;
|
||||
uint32_t mc_addr_low;
|
||||
uint32_t mc_addr_high;
|
||||
void *kaddr;
|
||||
unsigned long handle;
|
||||
};
|
||||
|
||||
struct fiji_smumgr {
|
||||
uint8_t *header;
|
||||
uint8_t *mec_image;
|
||||
uint32_t soft_regs_start;
|
||||
struct fiji_smu_avfs avfs;
|
||||
uint32_t acpi_optimization;
|
||||
struct smu7_smumgr smu7_data;
|
||||
|
||||
struct fiji_smu_avfs avfs;
|
||||
struct SMU73_Discrete_DpmTable smc_state_table;
|
||||
struct SMU73_Discrete_Ulv ulv_setting;
|
||||
struct SMU73_Discrete_PmFuses power_tune_table;
|
||||
const struct fiji_pt_defaults *power_tune_defaults;
|
||||
uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS];
|
||||
|
||||
struct fiji_buffer_entry header_buffer;
|
||||
};
|
||||
|
||||
int fiji_smum_init(struct pp_smumgr *smumgr);
|
||||
int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
|
||||
uint32_t *value, uint32_t limit);
|
||||
int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
|
||||
uint32_t value, uint32_t limit);
|
||||
int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smcStartAddress,
|
||||
const uint8_t *src, uint32_t byteCount, uint32_t limit);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,17 +20,21 @@
|
|||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _ICELAND_SMC_H
|
||||
#define _ICELAND_SMC_H
|
||||
|
||||
#ifndef _TONGA_CLOCK_POWER_GATING_H_
|
||||
#define _TONGA_CLOCK_POWER_GATING_H_
|
||||
#include "smumgr.h"
|
||||
|
||||
#include "tonga_hwmgr.h"
|
||||
#include "pp_asicblocks.h"
|
||||
|
||||
extern int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
|
||||
extern int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
|
||||
extern int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
|
||||
#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
|
||||
int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
|
||||
int iceland_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
|
||||
int iceland_init_smc_table(struct pp_hwmgr *hwmgr);
|
||||
int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
|
||||
int iceland_update_sclk_threshold(struct pp_hwmgr *hwmgr);
|
||||
uint32_t iceland_get_offsetof(uint32_t type, uint32_t member);
|
||||
uint32_t iceland_get_mac_definition(uint32_t value);
|
||||
int iceland_process_firmware_header(struct pp_hwmgr *hwmgr);
|
||||
int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
|
||||
bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr);
|
||||
#endif
|
||||
|
|
@ -35,120 +35,10 @@
|
|||
#include "smu/smu_7_1_1_d.h"
|
||||
#include "smu/smu_7_1_1_sh_mask.h"
|
||||
#include "cgs_common.h"
|
||||
#include "iceland_smc.h"
|
||||
|
||||
#define ICELAND_SMC_SIZE 0x20000
|
||||
#define BUFFER_SIZE 80000
|
||||
#define MAX_STRING_SIZE 15
|
||||
#define BUFFER_SIZETWO 131072 /*128 *1024*/
|
||||
#define ICELAND_SMC_SIZE 0x20000
|
||||
|
||||
/**
|
||||
* Set the address for reading/writing the SMC SRAM space.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smcAddress the address in the SMC RAM to access.
|
||||
*/
|
||||
static int iceland_set_smc_sram_address(struct pp_smumgr *smumgr,
|
||||
uint32_t smcAddress, uint32_t limit)
|
||||
{
|
||||
if (smumgr == NULL || smumgr->device == NULL)
|
||||
return -EINVAL;
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)),
|
||||
"SMC address must be 4 byte aligned.",
|
||||
return -1;);
|
||||
|
||||
PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)),
|
||||
"SMC address is beyond the SMC RAM area.",
|
||||
return -1;);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an array into the SMC RAM space.
|
||||
*
|
||||
* @param smumgr the address of the powerplay SMU manager.
|
||||
* @param smcStartAddress the start address in the SMC RAM to copy bytes to.
|
||||
* @param src the byte array to copy the bytes from.
|
||||
* @param byteCount the number of bytes to copy.
|
||||
*/
|
||||
int iceland_copy_bytes_to_smc(struct pp_smumgr *smumgr,
|
||||
uint32_t smcStartAddress, const uint8_t *src,
|
||||
uint32_t byteCount, uint32_t limit)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t data, orig_data;
|
||||
int result = 0;
|
||||
uint32_t extra_shift;
|
||||
|
||||
if (smumgr == NULL || smumgr->device == NULL)
|
||||
return -EINVAL;
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
|
||||
"SMC address must be 4 byte aligned.",
|
||||
return 0;);
|
||||
|
||||
PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
|
||||
"SMC address is beyond the SMC RAM area.",
|
||||
return 0;);
|
||||
|
||||
addr = smcStartAddress;
|
||||
|
||||
while (byteCount >= 4) {
|
||||
/*
|
||||
* Bytes are written into the
|
||||
* SMC address space with the MSB first
|
||||
*/
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
|
||||
result = iceland_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byteCount -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byteCount) {
|
||||
/* Now write odd bytes left, do a read modify write cycle */
|
||||
data = 0;
|
||||
|
||||
result = iceland_set_smc_sram_address(smumgr, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
orig_data = cgs_read_register(smumgr->device,
|
||||
mmSMC_IND_DATA_0);
|
||||
extra_shift = 8 * (4 - byteCount);
|
||||
|
||||
while (byteCount > 0) {
|
||||
data = (data << 8) + *src++;
|
||||
byteCount--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
data |= (orig_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = iceland_set_smc_sram_address(smumgr, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deassert the reset'pin' (set it to high).
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
*/
|
||||
static int iceland_start_smc(struct pp_smumgr *smumgr)
|
||||
{
|
||||
SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
|
@ -157,284 +47,15 @@ static int iceland_start_smc(struct pp_smumgr *smumgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void iceland_pp_reset_smc(struct pp_smumgr *smumgr)
|
||||
static void iceland_reset_smc(struct pp_smumgr *smumgr)
|
||||
{
|
||||
SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_RESET_CNTL,
|
||||
rst_reg, 1);
|
||||
}
|
||||
|
||||
int iceland_program_jump_on_start(struct pp_smumgr *smumgr)
|
||||
{
|
||||
static const unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 };
|
||||
|
||||
iceland_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the SMC is currently running.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
*/
|
||||
bool iceland_is_smc_ram_running(struct pp_smumgr *smumgr)
|
||||
{
|
||||
uint32_t val1, val2;
|
||||
|
||||
val1 = SMUM_READ_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
|
||||
val2 = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC,
|
||||
ixSMC_PC_C);
|
||||
|
||||
return ((0 == val1) && (0x20100 <= val2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC, and wait for its response.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param msg the message to send.
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
static int iceland_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
if (smumgr == NULL || smumgr->device == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!iceland_is_smc_ram_running(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
|
||||
"Failed to send Previous Message.",
|
||||
);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
|
||||
"Failed to send Message.",
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC with parameter
|
||||
*
|
||||
* @param smumgr: the address of the powerplay hardware manager.
|
||||
* @param msg: the message to send.
|
||||
* @param parameter: the parameter to send
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
static int iceland_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
|
||||
uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
if (smumgr == NULL || smumgr->device == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return iceland_send_msg_to_smc(smumgr, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a 32bit value from the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smcAddress the address in the SMC RAM to access.
|
||||
* @param value and output parameter for the data read from the SMC SRAM.
|
||||
*/
|
||||
int iceland_read_smc_sram_dword(struct pp_smumgr *smumgr,
|
||||
uint32_t smcAddress, uint32_t *value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = iceland_set_smc_sram_address(smumgr, smcAddress, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 32bit value to the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smcAddress the address in the SMC RAM to access.
|
||||
* @param value to write to the SMC SRAM.
|
||||
*/
|
||||
int iceland_write_smc_sram_dword(struct pp_smumgr *smumgr,
|
||||
uint32_t smcAddress, uint32_t value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = iceland_set_smc_sram_address(smumgr, smcAddress, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_smu_fini(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct iceland_smumgr *priv = (struct iceland_smumgr *)(smumgr->backend);
|
||||
|
||||
smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle);
|
||||
|
||||
if (smumgr->backend != NULL) {
|
||||
kfree(smumgr->backend);
|
||||
smumgr->backend = NULL;
|
||||
}
|
||||
|
||||
cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum cgs_ucode_id iceland_convert_fw_type_to_cgs(uint32_t fw_type)
|
||||
{
|
||||
enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SMU:
|
||||
result = CGS_UCODE_ID_SMU;
|
||||
break;
|
||||
case UCODE_ID_SDMA0:
|
||||
result = CGS_UCODE_ID_SDMA0;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = CGS_UCODE_ID_SDMA1;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = CGS_UCODE_ID_CP_CE;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = CGS_UCODE_ID_CP_PFP;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = CGS_UCODE_ID_CP_ME;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
result = CGS_UCODE_ID_CP_MEC;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT1;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT2;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = CGS_UCODE_ID_RLC_G;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the PPIRI firmware type to SMU type mask.
|
||||
* For MEC, we need to check all MEC related type
|
||||
*/
|
||||
static uint16_t iceland_get_mask_for_firmware_type(uint16_t firmwareType)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
|
||||
switch (firmwareType) {
|
||||
case UCODE_ID_SDMA0:
|
||||
result = UCODE_ID_SDMA0_MASK;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = UCODE_ID_SDMA1_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = UCODE_ID_CP_CE_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = UCODE_ID_CP_PFP_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = UCODE_ID_CP_ME_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = UCODE_ID_CP_MEC_MASK;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = UCODE_ID_RLC_G_MASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the FW has been loaded,
|
||||
* SMU will not return if loading has not finished.
|
||||
*/
|
||||
static int iceland_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType)
|
||||
{
|
||||
uint16_t fwMask = iceland_get_mask_for_firmware_type(fwType);
|
||||
|
||||
if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
|
||||
SOFT_REGISTERS_TABLE_27, fwMask, fwMask)) {
|
||||
pr_err("[ powerplay ] check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Populate one firmware image to the data structure */
|
||||
static int iceland_populate_single_firmware_entry(struct pp_smumgr *smumgr,
|
||||
uint16_t firmware_type,
|
||||
struct SMU_Entry *pentry)
|
||||
{
|
||||
int result;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
result = cgs_get_firmware_info(
|
||||
smumgr->device,
|
||||
iceland_convert_fw_type_to_cgs(firmware_type),
|
||||
&info);
|
||||
|
||||
if (result == 0) {
|
||||
pentry->version = 0;
|
||||
pentry->id = (uint16_t)firmware_type;
|
||||
pentry->image_addr_high = smu_upper_32_bits(info.mc_addr);
|
||||
pentry->image_addr_low = smu_lower_32_bits(info.mc_addr);
|
||||
pentry->meta_data_addr_high = 0;
|
||||
pentry->meta_data_addr_low = 0;
|
||||
pentry->data_size_byte = info.image_size;
|
||||
pentry->num_register_entries = 0;
|
||||
|
||||
if (firmware_type == UCODE_ID_RLC_G)
|
||||
pentry->flags = 1;
|
||||
else
|
||||
pentry->flags = 0;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void iceland_pp_stop_smc_clock(struct pp_smumgr *smumgr)
|
||||
static void iceland_stop_smc_clock(struct pp_smumgr *smumgr)
|
||||
{
|
||||
SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_CLOCK_CNTL_0,
|
||||
|
@ -448,10 +69,10 @@ static void iceland_start_smc_clock(struct pp_smumgr *smumgr)
|
|||
ck_disable, 0);
|
||||
}
|
||||
|
||||
int iceland_smu_start_smc(struct pp_smumgr *smumgr)
|
||||
static int iceland_smu_start_smc(struct pp_smumgr *smumgr)
|
||||
{
|
||||
/* set smc instruct start point at 0x0 */
|
||||
iceland_program_jump_on_start(smumgr);
|
||||
smu7_program_jump_on_start(smumgr);
|
||||
|
||||
/* enable smc clock */
|
||||
iceland_start_smc_clock(smumgr);
|
||||
|
@ -465,17 +86,37 @@ int iceland_smu_start_smc(struct pp_smumgr *smumgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the SMC firmware to the SMC microcontroller.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param pFirmware the data structure containing the various sections of the firmware.
|
||||
*/
|
||||
int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
|
||||
|
||||
static int iceland_upload_smc_firmware_data(struct pp_smumgr *smumgr,
|
||||
uint32_t length, const uint8_t *src,
|
||||
uint32_t limit, uint32_t start_addr)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint32_t byte_count, val;
|
||||
uint32_t byte_count = length;
|
||||
uint32_t data;
|
||||
|
||||
PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, start_addr);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
|
||||
while (byte_count >= 4) {
|
||||
data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
}
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
|
||||
{
|
||||
uint32_t val;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
if (smumgr == NULL || smumgr->device == NULL)
|
||||
|
@ -483,7 +124,7 @@ int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
|
|||
|
||||
/* load SMC firmware */
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
iceland_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
|
||||
smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
|
||||
|
||||
if (info.image_size & 3) {
|
||||
pr_err("[ powerplay ] SMC ucode is not 4 bytes aligned\n");
|
||||
|
@ -506,122 +147,17 @@ int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
|
|||
ixSMC_SYSCON_MISC_CNTL, val | 1);
|
||||
|
||||
/* stop smc clock */
|
||||
iceland_pp_stop_smc_clock(smumgr);
|
||||
iceland_stop_smc_clock(smumgr);
|
||||
|
||||
/* reset smc */
|
||||
iceland_pp_reset_smc(smumgr);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0,
|
||||
info.ucode_start_address);
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL,
|
||||
AUTO_INCREMENT_IND_0, 1);
|
||||
|
||||
byte_count = info.image_size;
|
||||
src = (const uint8_t *)info.kptr;
|
||||
|
||||
while (byte_count >= 4) {
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
}
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL,
|
||||
AUTO_INCREMENT_IND_0, 0);
|
||||
iceland_reset_smc(smumgr);
|
||||
iceland_upload_smc_firmware_data(smumgr, info.image_size,
|
||||
(uint8_t *)info.kptr, ICELAND_SMC_SIZE,
|
||||
info.ucode_start_address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iceland_request_smu_reload_fw(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct iceland_smumgr *iceland_smu =
|
||||
(struct iceland_smumgr *)(smumgr->backend);
|
||||
uint16_t fw_to_load;
|
||||
int result = 0;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)iceland_smu->pHeader;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_RLC_G,
|
||||
&toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n",
|
||||
return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_CE,
|
||||
&toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n",
|
||||
return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_populate_single_firmware_entry
|
||||
(smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.\n", return -1);
|
||||
|
||||
if (!iceland_is_smc_ram_running(smumgr)) {
|
||||
result = iceland_smu_upload_firmware_image(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = iceland_smu_start_smc(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
iceland_send_msg_to_smc_with_parameter(smumgr,
|
||||
PPSMC_MSG_DRV_DRAM_ADDR_HI,
|
||||
iceland_smu->header_buffer.mc_addr_high);
|
||||
|
||||
iceland_send_msg_to_smc_with_parameter(smumgr,
|
||||
PPSMC_MSG_DRV_DRAM_ADDR_LO,
|
||||
iceland_smu->header_buffer.mc_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK
|
||||
+ UCODE_ID_SDMA0_MASK
|
||||
+ UCODE_ID_SDMA1_MASK
|
||||
+ UCODE_ID_CP_CE_MASK
|
||||
+ UCODE_ID_CP_ME_MASK
|
||||
+ UCODE_ID_CP_PFP_MASK
|
||||
+ UCODE_ID_CP_MEC_MASK
|
||||
+ UCODE_ID_CP_MEC_JT1_MASK
|
||||
+ UCODE_ID_CP_MEC_JT2_MASK;
|
||||
|
||||
PP_ASSERT_WITH_CODE(
|
||||
0 == iceland_send_msg_to_smc_with_parameter(
|
||||
smumgr, PPSMC_MSG_LoadUcodes, fw_to_load),
|
||||
"Fail to Request SMU Load uCode", return 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iceland_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
|
||||
uint32_t firmwareType)
|
||||
{
|
||||
|
@ -635,12 +171,22 @@ static int iceland_start_smu(struct pp_smumgr *smumgr)
|
|||
result = iceland_smu_upload_firmware_image(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = iceland_smu_start_smc(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = iceland_request_smu_reload_fw(smumgr);
|
||||
if (!smu7_is_smc_ram_running(smumgr)) {
|
||||
printk("smu not running, upload firmware again \n");
|
||||
result = iceland_smu_upload_firmware_image(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = iceland_smu_start_smc(smumgr);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = smu7_request_smu_load_fw(smumgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -654,47 +200,38 @@ static int iceland_start_smu(struct pp_smumgr *smumgr)
|
|||
*/
|
||||
static int iceland_smu_init(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct iceland_smumgr *iceland_smu;
|
||||
uint64_t mc_addr = 0;
|
||||
int i;
|
||||
struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
|
||||
if (smu7_init(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate memory for backend private data */
|
||||
iceland_smu = (struct iceland_smumgr *)(smumgr->backend);
|
||||
iceland_smu->header_buffer.data_size =
|
||||
((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
|
||||
smu_allocate_memory(smumgr->device,
|
||||
iceland_smu->header_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&iceland_smu->header_buffer.kaddr,
|
||||
&iceland_smu->header_buffer.handle);
|
||||
|
||||
iceland_smu->pHeader = iceland_smu->header_buffer.kaddr;
|
||||
iceland_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
iceland_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != iceland_smu->pHeader),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)iceland_smu->header_buffer.handle);
|
||||
return -1);
|
||||
for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
|
||||
smu_data->activity_target[i] = 30;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pp_smumgr_func iceland_smu_funcs = {
|
||||
.smu_init = &iceland_smu_init,
|
||||
.smu_fini = &iceland_smu_fini,
|
||||
.smu_fini = &smu7_smu_fini,
|
||||
.start_smu = &iceland_start_smu,
|
||||
.check_fw_load_finish = &iceland_check_fw_load_finish,
|
||||
.request_smu_load_fw = &iceland_request_smu_reload_fw,
|
||||
.check_fw_load_finish = &smu7_check_fw_load_finish,
|
||||
.request_smu_load_fw = &smu7_reload_firmware,
|
||||
.request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw,
|
||||
.send_msg_to_smc = &iceland_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = &iceland_send_msg_to_smc_with_parameter,
|
||||
.send_msg_to_smc = &smu7_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
|
||||
.download_pptable_settings = NULL,
|
||||
.upload_pptable_settings = NULL,
|
||||
.get_offsetof = iceland_get_offsetof,
|
||||
.process_firmware_header = iceland_process_firmware_header,
|
||||
.init_smc_table = iceland_init_smc_table,
|
||||
.update_sclk_threshold = iceland_update_sclk_threshold,
|
||||
.thermal_setup_fan_table = iceland_thermal_setup_fan_table,
|
||||
.populate_all_graphic_levels = iceland_populate_all_graphic_levels,
|
||||
.populate_all_memory_levels = iceland_populate_all_memory_levels,
|
||||
.get_mac_definition = iceland_get_mac_definition,
|
||||
.initialize_mc_reg_table = iceland_initialize_mc_reg_table,
|
||||
.is_dpm_running = iceland_is_dpm_running,
|
||||
};
|
||||
|
||||
int iceland_smum_init(struct pp_smumgr *smumgr)
|
||||
|
|
|
@ -26,39 +26,46 @@
|
|||
#ifndef _ICELAND_SMUMGR_H_
|
||||
#define _ICELAND_SMUMGR_H_
|
||||
|
||||
struct iceland_buffer_entry {
|
||||
uint32_t data_size;
|
||||
uint32_t mc_addr_low;
|
||||
uint32_t mc_addr_high;
|
||||
void *kaddr;
|
||||
unsigned long handle;
|
||||
|
||||
#include "smu7_smumgr.h"
|
||||
#include "pp_endian.h"
|
||||
#include "smu71_discrete.h"
|
||||
|
||||
struct iceland_pt_defaults {
|
||||
uint8_t svi_load_line_en;
|
||||
uint8_t svi_load_line_vddc;
|
||||
uint8_t tdc_vddc_throttle_release_limit_perc;
|
||||
uint8_t tdc_mawt;
|
||||
uint8_t tdc_waterfall_ctl;
|
||||
uint8_t dte_ambient_temp_base;
|
||||
uint32_t display_cac;
|
||||
uint32_t bamp_temp_gradient;
|
||||
uint16_t bapmti_r[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
|
||||
uint16_t bapmti_rc[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
|
||||
};
|
||||
|
||||
struct iceland_mc_reg_entry {
|
||||
uint32_t mclk_max;
|
||||
uint32_t mc_data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
struct iceland_mc_reg_table {
|
||||
uint8_t last; /* number of registers*/
|
||||
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
|
||||
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
|
||||
struct iceland_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
|
||||
SMU71_Discrete_MCRegisterAddress mc_reg_address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
/* Iceland only has header_buffer, don't have smu buffer. */
|
||||
struct iceland_smumgr {
|
||||
uint8_t *pHeader;
|
||||
uint8_t *pMecImage;
|
||||
uint32_t ulSoftRegsStart;
|
||||
|
||||
struct iceland_buffer_entry header_buffer;
|
||||
struct smu7_smumgr smu7_data;
|
||||
struct SMU71_Discrete_DpmTable smc_state_table;
|
||||
struct SMU71_Discrete_PmFuses power_tune_table;
|
||||
struct SMU71_Discrete_Ulv ulv_setting;
|
||||
struct iceland_pt_defaults *power_tune_defaults;
|
||||
SMU71_Discrete_MCRegisters mc_regs;
|
||||
struct iceland_mc_reg_table mc_reg_table;
|
||||
uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS];
|
||||
};
|
||||
|
||||
extern int iceland_smum_init(struct pp_smumgr *smumgr);
|
||||
extern int iceland_copy_bytes_to_smc(struct pp_smumgr *smumgr,
|
||||
uint32_t smcStartAddress,
|
||||
const uint8_t *src,
|
||||
uint32_t byteCount, uint32_t limit);
|
||||
|
||||
extern int iceland_smu_start_smc(struct pp_smumgr *smumgr);
|
||||
|
||||
extern int iceland_read_smc_sram_dword(struct pp_smumgr *smumgr,
|
||||
uint32_t smcAddress,
|
||||
uint32_t *value, uint32_t limit);
|
||||
extern int iceland_write_smc_sram_dword(struct pp_smumgr *smumgr,
|
||||
uint32_t smcAddress,
|
||||
uint32_t value, uint32_t limit);
|
||||
|
||||
extern bool iceland_is_smc_ram_running(struct pp_smumgr *smumgr);
|
||||
extern int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
* Copyright 2015 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"),
|
||||
|
@ -20,23 +20,23 @@
|
|||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef POLARIS10_SMC_H
|
||||
#define POLARIS10_SMC_H
|
||||
|
||||
#ifndef TONGA_SMUMGR_H
|
||||
#define TONGA_SMUMGR_H
|
||||
#include "smumgr.h"
|
||||
|
||||
#include "tonga_ppsmc.h"
|
||||
|
||||
int tonga_smu_init(struct amdgpu_device *adev);
|
||||
int tonga_smu_fini(struct amdgpu_device *adev);
|
||||
int tonga_smu_start(struct amdgpu_device *adev);
|
||||
|
||||
struct tonga_smu_private_data
|
||||
{
|
||||
uint8_t *header;
|
||||
uint32_t smu_buffer_addr_high;
|
||||
uint32_t smu_buffer_addr_low;
|
||||
uint32_t header_addr_high;
|
||||
uint32_t header_addr_low;
|
||||
};
|
||||
int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_init_smc_table(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr);
|
||||
int polaris10_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
|
||||
int polaris10_update_sclk_threshold(struct pp_hwmgr *hwmgr);
|
||||
uint32_t polaris10_get_offsetof(uint32_t type, uint32_t member);
|
||||
uint32_t polaris10_get_mac_definition(uint32_t value);
|
||||
int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr);
|
||||
bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr);
|
||||
|
||||
#endif
|
||||
|
|
@ -38,15 +38,11 @@
|
|||
#include "ppatomctrl.h"
|
||||
#include "pp_debug.h"
|
||||
#include "cgs_common.h"
|
||||
#include "polaris10_smc.h"
|
||||
#include "smu7_ppsmc.h"
|
||||
#include "smu7_smumgr.h"
|
||||
|
||||
#define POLARIS10_SMC_SIZE 0x20000
|
||||
|
||||
/* Microcode file is stored in this buffer */
|
||||
#define BUFFER_SIZE 80000
|
||||
#define MAX_STRING_SIZE 15
|
||||
#define BUFFER_SIZETWO 131072 /* 128 *1024 */
|
||||
|
||||
#define SMC_RAM_END 0x40000
|
||||
#define PPPOLARIS10_TARGETACTIVITY_DFLT 50
|
||||
|
||||
static const SMU74_Discrete_GraphicsLevel avfs_graphics_level_polaris10[8] = {
|
||||
/* Min pcie DeepSleep Activity CgSpll CgSpll CcPwr CcPwr Sclk Enabled Enabled Voltage Power */
|
||||
|
@ -61,572 +57,9 @@ static const SMU74_Discrete_GraphicsLevel avfs_graphics_level_polaris10[8] = {
|
|||
{ 0xa00fa446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0xa0860100, 0x2800, 0, 0x2000, 2, 1, 0x0004, 0x0c02, 0xffff, 0x2700, 0x6433, 0x2100 } }
|
||||
};
|
||||
|
||||
static const SMU74_Discrete_MemoryLevel avfs_memory_level_polaris10 =
|
||||
{0x100ea446, 0, 0x30750000, 0x01, 0x01, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x1f00, 0x00, 0x00};
|
||||
static const SMU74_Discrete_MemoryLevel avfs_memory_level_polaris10 = {
|
||||
0x100ea446, 0, 0x30750000, 0x01, 0x01, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x1f00, 0x00, 0x00};
|
||||
|
||||
/**
|
||||
* Set the address for reading/writing the SMC SRAM space.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smcAddress the address in the SMC RAM to access.
|
||||
*/
|
||||
static int polaris10_set_smc_sram_address(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t limit)
|
||||
{
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, smc_addr);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from SMC RAM space into driver memory.
|
||||
*
|
||||
* @param smumgr the address of the powerplay SMU manager.
|
||||
* @param smc_start_address the start address in the SMC RAM to copy bytes from
|
||||
* @param src the byte array to copy the bytes to.
|
||||
* @param byte_count the number of bytes to copy.
|
||||
*/
|
||||
int polaris10_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t data;
|
||||
uint32_t addr;
|
||||
uint8_t *dest_byte;
|
||||
uint8_t i, data_byte[4] = {0};
|
||||
uint32_t *pdata = (uint32_t *)&data_byte;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1;);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1);
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
while (byte_count >= 4) {
|
||||
polaris10_read_smc_sram_dword(smumgr, addr, &data, limit);
|
||||
|
||||
*dest = PP_SMC_TO_HOST_UL(data);
|
||||
|
||||
dest += 1;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (byte_count) {
|
||||
polaris10_read_smc_sram_dword(smumgr, addr, &data, limit);
|
||||
*pdata = PP_SMC_TO_HOST_UL(data);
|
||||
/* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */
|
||||
dest_byte = (uint8_t *)dest;
|
||||
for (i = 0; i < byte_count; i++)
|
||||
dest_byte[i] = data_byte[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an array into the SMC RAM space.
|
||||
*
|
||||
* @param pSmuMgr the address of the powerplay SMU manager.
|
||||
* @param smc_start_address the start address in the SMC RAM to copy bytes to.
|
||||
* @param src the byte array to copy the bytes from.
|
||||
* @param byte_count the number of bytes to copy.
|
||||
*/
|
||||
int polaris10_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
|
||||
const uint8_t *src, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
uint32_t data = 0;
|
||||
uint32_t original_data;
|
||||
uint32_t addr = 0;
|
||||
uint32_t extra_shift;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1);
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first. */
|
||||
data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
|
||||
|
||||
result = polaris10_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
|
||||
data = 0;
|
||||
|
||||
result = polaris10_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
|
||||
original_data = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
|
||||
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first. */
|
||||
data = (0x100 * data) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
|
||||
data |= (original_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = polaris10_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int polaris10_program_jump_on_start(struct pp_smumgr *smumgr)
|
||||
{
|
||||
static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
|
||||
|
||||
polaris10_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the SMC is currently running.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
*/
|
||||
bool polaris10_is_smc_ram_running(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
|
||||
&& (0x20100 <= cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr)
|
||||
{
|
||||
uint32_t efuse;
|
||||
|
||||
efuse = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_EFUSE_0 + (49*4));
|
||||
efuse &= 0x00000001;
|
||||
if (efuse)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC, and wait for its response.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param msg the message to send.
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int polaris10_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!polaris10_is_smc_ram_running(smumgr))
|
||||
return -1;
|
||||
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
|
||||
|
||||
if (ret != 1)
|
||||
printk("\n failed to send pre message %x ret is %d \n", msg, ret);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
|
||||
|
||||
if (ret != 1)
|
||||
printk("\n failed to send message %x ret is %d \n", msg, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to the SMC, and do not wait for its response.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param msg the message to send.
|
||||
* @return Always return 0.
|
||||
*/
|
||||
int polaris10_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the SMC with parameter
|
||||
*
|
||||
* @param smumgr: the address of the powerplay hardware manager.
|
||||
* @param msg: the message to send.
|
||||
* @param parameter: the parameter to send
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int polaris10_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
if (!polaris10_is_smc_ram_running(smumgr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return polaris10_send_msg_to_smc(smumgr, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to the SMC with parameter, do not wait for response
|
||||
*
|
||||
* @param smumgr: the address of the powerplay hardware manager.
|
||||
* @param msg: the message to send.
|
||||
* @param parameter: the parameter to send
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int polaris10_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return polaris10_send_msg_to_smc_without_waiting(smumgr, msg);
|
||||
}
|
||||
|
||||
int polaris10_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP))
|
||||
printk("Failed to send Message.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the SMC is doing nithing. Doing nothing means that the SMC is either turned off or it is sitting on the STOP instruction.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param msg the message to send.
|
||||
* @return The response that came from the SMC.
|
||||
*/
|
||||
int polaris10_wait_for_smc_inactive(struct pp_smumgr *smumgr)
|
||||
{
|
||||
/* If the SMC is not even on it qualifies as inactive. */
|
||||
if (!polaris10_is_smc_ram_running(smumgr))
|
||||
return -1;
|
||||
|
||||
SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, SMC_SYSCON_CLOCK_CNTL_0, cken, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Upload the SMC firmware to the SMC microcontroller.
|
||||
*
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param pFirmware the data structure containing the various sections of the firmware.
|
||||
*/
|
||||
static int polaris10_upload_smc_firmware_data(struct pp_smumgr *smumgr, uint32_t length, uint32_t *src, uint32_t limit)
|
||||
{
|
||||
uint32_t byte_count = length;
|
||||
|
||||
PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -1);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, 0x20000);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1);
|
||||
|
||||
for (; byte_count >= 4; byte_count -= 4)
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, *src++);
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum cgs_ucode_id polaris10_convert_fw_type_to_cgs(uint32_t fw_type)
|
||||
{
|
||||
enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SMU:
|
||||
result = CGS_UCODE_ID_SMU;
|
||||
break;
|
||||
case UCODE_ID_SMU_SK:
|
||||
result = CGS_UCODE_ID_SMU_SK;
|
||||
break;
|
||||
case UCODE_ID_SDMA0:
|
||||
result = CGS_UCODE_ID_SDMA0;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = CGS_UCODE_ID_SDMA1;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = CGS_UCODE_ID_CP_CE;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = CGS_UCODE_ID_CP_PFP;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = CGS_UCODE_ID_CP_ME;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
result = CGS_UCODE_ID_CP_MEC;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT1;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT2;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = CGS_UCODE_ID_RLC_G;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int polaris10_upload_smu_firmware_image(struct pp_smumgr *smumgr)
|
||||
{
|
||||
int result = 0;
|
||||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
if (smu_data->security_hard_key == 1)
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
|
||||
else
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info);
|
||||
|
||||
/* TO DO cgs_init_samu_load_smu(smumgr->device, (uint32_t *)info.kptr, info.image_size, smu_data->post_initial_boot);*/
|
||||
result = polaris10_upload_smc_firmware_data(smumgr, info.image_size, (uint32_t *)info.kptr, POLARIS10_SMC_SIZE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32bit value from the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smcAddress the address in the SMC RAM to access.
|
||||
* @param value and output parameter for the data read from the SMC SRAM.
|
||||
*/
|
||||
int polaris10_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32bit value to the SMC SRAM space.
|
||||
* ALL PARAMETERS ARE IN HOST BYTE ORDER.
|
||||
* @param smumgr the address of the powerplay hardware manager.
|
||||
* @param smc_addr the address in the SMC RAM to access.
|
||||
* @param value to write to the SMC SRAM.
|
||||
*/
|
||||
int polaris10_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int polaris10_smu_fini(struct pp_smumgr *smumgr)
|
||||
{
|
||||
if (smumgr->backend) {
|
||||
kfree(smumgr->backend);
|
||||
smumgr->backend = NULL;
|
||||
}
|
||||
cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert the firmware type to SMU type mask. For MEC, we need to check all MEC related type */
|
||||
static uint32_t polaris10_get_mask_for_firmware_type(uint32_t fw_type)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
result = UCODE_ID_SDMA0_MASK;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = UCODE_ID_SDMA1_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = UCODE_ID_CP_CE_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = UCODE_ID_CP_PFP_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = UCODE_ID_CP_ME_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = UCODE_ID_CP_MEC_MASK;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = UCODE_ID_RLC_G_MASK;
|
||||
break;
|
||||
default:
|
||||
printk("UCode type is out of range! \n");
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Populate one firmware image to the data structure */
|
||||
|
||||
static int polaris10_populate_single_firmware_entry(struct pp_smumgr *smumgr,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
int result = 0;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
result = cgs_get_firmware_info(smumgr->device,
|
||||
polaris10_convert_fw_type_to_cgs(fw_type),
|
||||
&info);
|
||||
|
||||
if (!result) {
|
||||
entry->version = info.version;
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
|
||||
entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = info.image_size;
|
||||
entry->num_register_entries = 0;
|
||||
}
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int polaris10_request_smu_load_fw(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
uint32_t fw_to_load;
|
||||
|
||||
int result = 0;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
|
||||
if (!smumgr->reload_fw) {
|
||||
printk(KERN_INFO "[ powerplay ] skip reloading...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (smu_data->soft_regs_start)
|
||||
cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
|
||||
smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus),
|
||||
0x0);
|
||||
|
||||
polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
|
||||
polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)smu_data->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
|
||||
|
||||
polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high);
|
||||
polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK
|
||||
+ UCODE_ID_SDMA0_MASK
|
||||
+ UCODE_ID_SDMA1_MASK
|
||||
+ UCODE_ID_CP_CE_MASK
|
||||
+ UCODE_ID_CP_ME_MASK
|
||||
+ UCODE_ID_CP_PFP_MASK
|
||||
+ UCODE_ID_CP_MEC_MASK;
|
||||
|
||||
if (polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_LoadUcodes, fw_to_load))
|
||||
printk(KERN_ERR "Fail to Request SMU Load uCode");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Check if the FW has been loaded, SMU will not return if loading has not finished. */
|
||||
static int polaris10_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type)
|
||||
{
|
||||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
uint32_t fw_mask = polaris10_get_mask_for_firmware_type(fw_type);
|
||||
uint32_t ret;
|
||||
/* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
|
||||
ret = smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX_11,
|
||||
smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus),
|
||||
fw_mask, fw_mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int polaris10_reload_firmware(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return smumgr->smumgr_funcs->start_smu(smumgr);
|
||||
}
|
||||
|
||||
static int polaris10_setup_pwr_virus(struct pp_smumgr *smumgr)
|
||||
{
|
||||
|
@ -668,7 +101,7 @@ static int polaris10_perform_btc(struct pp_smumgr *smumgr)
|
|||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
|
||||
if (0 != smu_data->avfs.avfs_btc_param) {
|
||||
if (0 != polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) {
|
||||
if (0 != smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) {
|
||||
printk("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed");
|
||||
result = -1;
|
||||
}
|
||||
|
@ -696,7 +129,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
graphics_level_size = sizeof(avfs_graphics_level_polaris10);
|
||||
u16_boot_mvdd = PP_HOST_TO_SMC_US(1300 * VOLTAGE_SCALE);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_read_smc_sram_dword(smumgr,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
|
||||
SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, DpmTable),
|
||||
&dpm_table_start, 0x40000),
|
||||
"[AVFS][Polaris10_SetupGfxLvlStruct] SMU could not communicate starting address of DPM table",
|
||||
|
@ -707,14 +140,14 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
|
||||
vr_config_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, VRConfig);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, vr_config_address,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, vr_config_address,
|
||||
(uint8_t *)&vr_config, sizeof(uint32_t), 0x40000),
|
||||
"[AVFS][Polaris10_SetupGfxLvlStruct] Problems copying VRConfig value over to SMC",
|
||||
return -1);
|
||||
|
||||
graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, GraphicsLevel);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
(uint8_t *)(&avfs_graphics_level_polaris10),
|
||||
graphics_level_size, 0x40000),
|
||||
"[AVFS][Polaris10_SetupGfxLvlStruct] Copying of SCLK DPM table failed!",
|
||||
|
@ -722,7 +155,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
|
||||
graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, MemoryLevel);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
(uint8_t *)(&avfs_memory_level_polaris10), sizeof(avfs_memory_level_polaris10), 0x40000),
|
||||
"[AVFS][Polaris10_SetupGfxLvlStruct] Copying of MCLK DPM table failed!",
|
||||
return -1);
|
||||
|
@ -731,7 +164,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
|
|||
|
||||
graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, BootMVdd);
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
|
||||
(uint8_t *)(&u16_boot_mvdd), sizeof(u16_boot_mvdd), 0x40000),
|
||||
"[AVFS][Polaris10_SetupGfxLvlStruct] Copying of DPM table failed!",
|
||||
return -1);
|
||||
|
@ -792,7 +225,7 @@ static int polaris10_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
|
|||
SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
|
||||
result = polaris10_upload_smu_firmware_image(smumgr);
|
||||
result = smu7_upload_smu_firmware_image(smumgr);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
|
@ -811,7 +244,7 @@ static int polaris10_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
|
|||
|
||||
|
||||
/* Call Test SMU message with 0x20000 offset to trigger SMU start */
|
||||
polaris10_send_msg_to_smc_offset(smumgr);
|
||||
smu7_send_msg_to_smc_offset(smumgr);
|
||||
|
||||
/* Wait done bit to be set */
|
||||
/* Check pass/failed indicator */
|
||||
|
@ -852,12 +285,12 @@ static int polaris10_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
|
|||
SMC_SYSCON_RESET_CNTL,
|
||||
rst_reg, 1);
|
||||
|
||||
result = polaris10_upload_smu_firmware_image(smumgr);
|
||||
result = smu7_upload_smu_firmware_image(smumgr);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
/* Set smc instruct start point at 0x0 */
|
||||
polaris10_program_jump_on_start(smumgr);
|
||||
smu7_program_jump_on_start(smumgr);
|
||||
|
||||
SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
|
||||
SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
|
@ -880,10 +313,10 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
|
|||
bool SMU_VFT_INTACT;
|
||||
|
||||
/* Only start SMC if SMC RAM is not running */
|
||||
if (!polaris10_is_smc_ram_running(smumgr)) {
|
||||
if (!smu7_is_smc_ram_running(smumgr)) {
|
||||
SMU_VFT_INTACT = false;
|
||||
smu_data->protected_mode = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_MODE));
|
||||
smu_data->security_hard_key = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL));
|
||||
smu_data->smu7_data.security_hard_key = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL));
|
||||
|
||||
/* Check if SMU is running in protected mode */
|
||||
if (smu_data->protected_mode == 0) {
|
||||
|
@ -893,7 +326,7 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
|
|||
|
||||
/* If failed, try with different security Key. */
|
||||
if (result != 0) {
|
||||
smu_data->security_hard_key ^= 1;
|
||||
smu_data->smu7_data.security_hard_key ^= 1;
|
||||
result = polaris10_start_smu_in_protection_mode(smumgr);
|
||||
}
|
||||
}
|
||||
|
@ -905,89 +338,69 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
|
|||
} else
|
||||
SMU_VFT_INTACT = true; /*Driver went offline but SMU was still alive and contains the VFT table */
|
||||
|
||||
smu_data->post_initial_boot = true;
|
||||
polaris10_avfs_event_mgr(smumgr, SMU_VFT_INTACT);
|
||||
/* Setup SoftRegsStart here for register lookup in case DummyBackEnd is used and ProcessFirmwareHeader is not executed */
|
||||
polaris10_read_smc_sram_dword(smumgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters),
|
||||
&(smu_data->soft_regs_start), 0x40000);
|
||||
smu7_read_smc_sram_dword(smumgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters),
|
||||
&(smu_data->smu7_data.soft_regs_start), 0x40000);
|
||||
|
||||
result = polaris10_request_smu_load_fw(smumgr);
|
||||
result = smu7_request_smu_load_fw(smumgr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr)
|
||||
{
|
||||
uint32_t efuse;
|
||||
|
||||
efuse = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_EFUSE_0 + (49*4));
|
||||
efuse &= 0x00000001;
|
||||
if (efuse)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int polaris10_smu_init(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct polaris10_smumgr *smu_data;
|
||||
uint8_t *internal_buf;
|
||||
uint64_t mc_addr = 0;
|
||||
/* Allocate memory for backend private data */
|
||||
smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
smu_data->header_buffer.data_size =
|
||||
((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
smu_data->smu_buffer.data_size = 200*4096;
|
||||
smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED;
|
||||
/* Allocate FW image data structure and header buffer and
|
||||
* send the header buffer address to SMU */
|
||||
smu_allocate_memory(smumgr->device,
|
||||
smu_data->header_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&smu_data->header_buffer.kaddr,
|
||||
&smu_data->header_buffer.handle);
|
||||
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
|
||||
int i;
|
||||
|
||||
smu_data->header = smu_data->header_buffer.kaddr;
|
||||
smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != smu_data->header),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)smu_data->header_buffer.handle);
|
||||
return -1);
|
||||
|
||||
/* Allocate buffer for SMU internal buffer and send the address to SMU.
|
||||
* Iceland SMU does not need internal buffer.*/
|
||||
smu_allocate_memory(smumgr->device,
|
||||
smu_data->smu_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&smu_data->smu_buffer.kaddr,
|
||||
&smu_data->smu_buffer.handle);
|
||||
|
||||
internal_buf = smu_data->smu_buffer.kaddr;
|
||||
smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != internal_buf),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)smu_data->smu_buffer.handle);
|
||||
return -1;);
|
||||
if (smu7_init(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
if (polaris10_is_hw_avfs_present(smumgr))
|
||||
smu_data->avfs.avfs_btc_status = AVFS_BTC_BOOT;
|
||||
else
|
||||
smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED;
|
||||
|
||||
for (i = 0; i < SMU74_MAX_LEVELS_GRAPHICS; i++)
|
||||
smu_data->activity_target[i] = PPPOLARIS10_TARGETACTIVITY_DFLT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pp_smumgr_func polaris10_smu_funcs = {
|
||||
.smu_init = polaris10_smu_init,
|
||||
.smu_fini = polaris10_smu_fini,
|
||||
.smu_fini = smu7_smu_fini,
|
||||
.start_smu = polaris10_start_smu,
|
||||
.check_fw_load_finish = polaris10_check_fw_load_finish,
|
||||
.request_smu_load_fw = polaris10_reload_firmware,
|
||||
.check_fw_load_finish = smu7_check_fw_load_finish,
|
||||
.request_smu_load_fw = smu7_reload_firmware,
|
||||
.request_smu_load_specific_fw = NULL,
|
||||
.send_msg_to_smc = polaris10_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = polaris10_send_msg_to_smc_with_parameter,
|
||||
.send_msg_to_smc = smu7_send_msg_to_smc,
|
||||
.send_msg_to_smc_with_parameter = smu7_send_msg_to_smc_with_parameter,
|
||||
.download_pptable_settings = NULL,
|
||||
.upload_pptable_settings = NULL,
|
||||
.update_smc_table = polaris10_update_smc_table,
|
||||
.get_offsetof = polaris10_get_offsetof,
|
||||
.process_firmware_header = polaris10_process_firmware_header,
|
||||
.init_smc_table = polaris10_init_smc_table,
|
||||
.update_sclk_threshold = polaris10_update_sclk_threshold,
|
||||
.thermal_avfs_enable = polaris10_thermal_avfs_enable,
|
||||
.thermal_setup_fan_table = polaris10_thermal_setup_fan_table,
|
||||
.populate_all_graphic_levels = polaris10_populate_all_graphic_levels,
|
||||
.populate_all_memory_levels = polaris10_populate_all_memory_levels,
|
||||
.get_mac_definition = polaris10_get_mac_definition,
|
||||
.is_dpm_running = polaris10_is_dpm_running,
|
||||
};
|
||||
|
||||
int polaris10_smum_init(struct pp_smumgr *smumgr)
|
||||
|
@ -997,7 +410,7 @@ int polaris10_smum_init(struct pp_smumgr *smumgr)
|
|||
polaris10_smu = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL);
|
||||
|
||||
if (polaris10_smu == NULL)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
smumgr->backend = polaris10_smu;
|
||||
smumgr->smumgr_funcs = &polaris10_smu_funcs;
|
||||
|
|
|
@ -24,9 +24,13 @@
|
|||
#ifndef _POLARIS10_SMUMANAGER_H
|
||||
#define _POLARIS10_SMUMANAGER_H
|
||||
|
||||
#include <polaris10_ppsmc.h>
|
||||
|
||||
#include <pp_endian.h>
|
||||
#include "smu74.h"
|
||||
#include "smu74_discrete.h"
|
||||
#include "smu7_smumgr.h"
|
||||
|
||||
#define SMC_RAM_END 0x40000
|
||||
|
||||
struct polaris10_avfs {
|
||||
enum AVFS_BTC_STATUS avfs_btc_status;
|
||||
|
@ -47,13 +51,7 @@ struct polaris10_pt_defaults {
|
|||
uint16_t BAPMTI_RC[SMU74_DTE_ITERATIONS * SMU74_DTE_SOURCES * SMU74_DTE_SINKS];
|
||||
};
|
||||
|
||||
struct polaris10_buffer_entry {
|
||||
uint32_t data_size;
|
||||
uint32_t mc_addr_low;
|
||||
uint32_t mc_addr_high;
|
||||
void *kaddr;
|
||||
unsigned long handle;
|
||||
};
|
||||
|
||||
|
||||
struct polaris10_range_table {
|
||||
uint32_t trans_lower_frequency; /* in 10khz */
|
||||
|
@ -61,28 +59,17 @@ struct polaris10_range_table {
|
|||
};
|
||||
|
||||
struct polaris10_smumgr {
|
||||
uint8_t *header;
|
||||
uint8_t *mec_image;
|
||||
struct polaris10_buffer_entry smu_buffer;
|
||||
struct polaris10_buffer_entry header_buffer;
|
||||
uint32_t soft_regs_start;
|
||||
uint8_t *read_rrm_straps;
|
||||
uint32_t read_drm_straps_mc_address_high;
|
||||
uint32_t read_drm_straps_mc_address_low;
|
||||
uint32_t acpi_optimization;
|
||||
bool post_initial_boot;
|
||||
struct smu7_smumgr smu7_data;
|
||||
uint8_t protected_mode;
|
||||
uint8_t security_hard_key;
|
||||
struct polaris10_avfs avfs;
|
||||
SMU74_Discrete_DpmTable smc_state_table;
|
||||
struct SMU74_Discrete_Ulv ulv_setting;
|
||||
struct SMU74_Discrete_PmFuses power_tune_table;
|
||||
struct polaris10_range_table range_table[NUM_SCLK_RANGE];
|
||||
const struct polaris10_pt_defaults *power_tune_defaults;
|
||||
uint32_t activity_target[SMU74_MAX_LEVELS_GRAPHICS];
|
||||
uint32_t bif_sclk_table[SMU74_MAX_LEVELS_LINK];
|
||||
};
|
||||
|
||||
|
||||
int polaris10_smum_init(struct pp_smumgr *smumgr);
|
||||
|
||||
int polaris10_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit);
|
||||
int polaris10_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit);
|
||||
int polaris10_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
|
||||
const uint8_t *src, uint32_t byte_count, uint32_t limit);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "smumgr.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
#include "ppatomctrl.h"
|
||||
#include "pp_debug.h"
|
||||
#include "cgs_common.h"
|
||||
#include "smu7_ppsmc.h"
|
||||
#include "smu7_smumgr.h"
|
||||
|
||||
#define SMU7_SMC_SIZE 0x20000
|
||||
|
||||
static int smu7_set_smc_sram_address(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t limit)
|
||||
{
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, smc_addr);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); /* on ci, SMC_IND_ACCESS_CNTL is different */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int smu7_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t data;
|
||||
uint32_t addr;
|
||||
uint8_t *dest_byte;
|
||||
uint8_t i, data_byte[4] = {0};
|
||||
uint32_t *pdata = (uint32_t *)&data_byte;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
while (byte_count >= 4) {
|
||||
smu7_read_smc_sram_dword(smumgr, addr, &data, limit);
|
||||
|
||||
*dest = PP_SMC_TO_HOST_UL(data);
|
||||
|
||||
dest += 1;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (byte_count) {
|
||||
smu7_read_smc_sram_dword(smumgr, addr, &data, limit);
|
||||
*pdata = PP_SMC_TO_HOST_UL(data);
|
||||
/* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */
|
||||
dest_byte = (uint8_t *)dest;
|
||||
for (i = 0; i < byte_count; i++)
|
||||
dest_byte[i] = data_byte[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int smu7_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
|
||||
const uint8_t *src, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
uint32_t data = 0;
|
||||
uint32_t original_data;
|
||||
uint32_t addr = 0;
|
||||
uint32_t extra_shift;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first. */
|
||||
data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
|
||||
|
||||
result = smu7_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
|
||||
data = 0;
|
||||
|
||||
result = smu7_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
|
||||
original_data = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
|
||||
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first. */
|
||||
data = (0x100 * data) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
|
||||
data |= (original_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = smu7_set_smc_sram_address(smumgr, addr, limit);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int smu7_program_jump_on_start(struct pp_smumgr *smumgr)
|
||||
{
|
||||
static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
|
||||
|
||||
smu7_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smu7_is_smc_ram_running(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
|
||||
&& (0x20100 <= cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!smu7_is_smc_ram_running(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
|
||||
|
||||
if (ret != 1)
|
||||
printk("\n failed to send pre message %x ret is %d \n", msg, ret);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP);
|
||||
|
||||
if (ret != 1)
|
||||
printk("\n failed to send message %x ret is %d \n", msg, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu7_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu7_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
if (!smu7_is_smc_ram_running(smumgr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return smu7_send_msg_to_smc(smumgr, msg);
|
||||
}
|
||||
|
||||
int smu7_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return smu7_send_msg_to_smc_without_waiting(smumgr, msg);
|
||||
}
|
||||
|
||||
int smu7_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
|
||||
{
|
||||
cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
|
||||
|
||||
SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
|
||||
|
||||
if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP))
|
||||
printk("Failed to send Message.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu7_wait_for_smc_inactive(struct pp_smumgr *smumgr)
|
||||
{
|
||||
if (!smu7_is_smc_ram_running(smumgr))
|
||||
return -EINVAL;
|
||||
|
||||
SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, SMC_SYSCON_CLOCK_CNTL_0, cken, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum cgs_ucode_id smu7_convert_fw_type_to_cgs(uint32_t fw_type)
|
||||
{
|
||||
enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SMU:
|
||||
result = CGS_UCODE_ID_SMU;
|
||||
break;
|
||||
case UCODE_ID_SMU_SK:
|
||||
result = CGS_UCODE_ID_SMU_SK;
|
||||
break;
|
||||
case UCODE_ID_SDMA0:
|
||||
result = CGS_UCODE_ID_SDMA0;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = CGS_UCODE_ID_SDMA1;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = CGS_UCODE_ID_CP_CE;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = CGS_UCODE_ID_CP_PFP;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = CGS_UCODE_ID_CP_ME;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
result = CGS_UCODE_ID_CP_MEC;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT1;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = CGS_UCODE_ID_CP_MEC_JT2;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = CGS_UCODE_ID_RLC_G;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int smu7_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = smu7_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
*value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu7_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = smu7_set_smc_sram_address(smumgr, smc_addr, limit);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert the firmware type to SMU type mask. For MEC, we need to check all MEC related type */
|
||||
|
||||
static uint32_t smu7_get_mask_for_firmware_type(uint32_t fw_type)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
result = UCODE_ID_SDMA0_MASK;
|
||||
break;
|
||||
case UCODE_ID_SDMA1:
|
||||
result = UCODE_ID_SDMA1_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_CE:
|
||||
result = UCODE_ID_CP_CE_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_PFP:
|
||||
result = UCODE_ID_CP_PFP_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_ME:
|
||||
result = UCODE_ID_CP_ME_MASK;
|
||||
break;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
result = UCODE_ID_CP_MEC_MASK;
|
||||
break;
|
||||
case UCODE_ID_RLC_G:
|
||||
result = UCODE_ID_RLC_G_MASK;
|
||||
break;
|
||||
default:
|
||||
printk("UCode type is out of range! \n");
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int smu7_populate_single_firmware_entry(struct pp_smumgr *smumgr,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
int result = 0;
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
result = cgs_get_firmware_info(smumgr->device,
|
||||
smu7_convert_fw_type_to_cgs(fw_type),
|
||||
&info);
|
||||
|
||||
if (!result) {
|
||||
entry->version = info.version;
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
|
||||
entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = info.image_size;
|
||||
entry->num_register_entries = 0;
|
||||
}
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
|
||||
uint32_t fw_to_load;
|
||||
int result = 0;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
|
||||
if (!smumgr->reload_fw) {
|
||||
printk(KERN_INFO "[ powerplay ] skip reloading...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (smu_data->soft_regs_start)
|
||||
cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
|
||||
smu_data->soft_regs_start + smum_get_offsetof(smumgr,
|
||||
SMU_SoftRegisters, UcodeLoadStatus),
|
||||
0x0);
|
||||
|
||||
if (smumgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */
|
||||
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
|
||||
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK
|
||||
+ UCODE_ID_SDMA0_MASK
|
||||
+ UCODE_ID_SDMA1_MASK
|
||||
+ UCODE_ID_CP_CE_MASK
|
||||
+ UCODE_ID_CP_ME_MASK
|
||||
+ UCODE_ID_CP_PFP_MASK
|
||||
+ UCODE_ID_CP_MEC_MASK;
|
||||
} else {
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK
|
||||
+ UCODE_ID_SDMA0_MASK
|
||||
+ UCODE_ID_SDMA1_MASK
|
||||
+ UCODE_ID_CP_CE_MASK
|
||||
+ UCODE_ID_CP_ME_MASK
|
||||
+ UCODE_ID_CP_PFP_MASK
|
||||
+ UCODE_ID_CP_MEC_MASK
|
||||
+ UCODE_ID_CP_MEC_JT1_MASK
|
||||
+ UCODE_ID_CP_MEC_JT2_MASK;
|
||||
}
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)smu_data->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
|
||||
UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
|
||||
"Failed to Get Firmware Entry.", return -EINVAL);
|
||||
|
||||
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high);
|
||||
smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low);
|
||||
|
||||
if (smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_LoadUcodes, fw_to_load))
|
||||
printk(KERN_ERR "Fail to Request SMU Load uCode");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Check if the FW has been loaded, SMU will not return if loading has not finished. */
|
||||
int smu7_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type)
|
||||
{
|
||||
struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
|
||||
uint32_t fw_mask = smu7_get_mask_for_firmware_type(fw_type);
|
||||
uint32_t ret;
|
||||
|
||||
ret = smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX_11,
|
||||
smu_data->soft_regs_start + smum_get_offsetof(smumgr,
|
||||
SMU_SoftRegisters, UcodeLoadStatus),
|
||||
fw_mask, fw_mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int smu7_reload_firmware(struct pp_smumgr *smumgr)
|
||||
{
|
||||
return smumgr->smumgr_funcs->start_smu(smumgr);
|
||||
}
|
||||
|
||||
static int smu7_upload_smc_firmware_data(struct pp_smumgr *smumgr, uint32_t length, uint32_t *src, uint32_t limit)
|
||||
{
|
||||
uint32_t byte_count = length;
|
||||
|
||||
PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);
|
||||
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, 0x20000);
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1);
|
||||
|
||||
for (; byte_count >= 4; byte_count -= 4)
|
||||
cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, *src++);
|
||||
|
||||
SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int smu7_upload_smu_firmware_image(struct pp_smumgr *smumgr)
|
||||
{
|
||||
int result = 0;
|
||||
struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
|
||||
|
||||
struct cgs_firmware_info info = {0};
|
||||
|
||||
if (smu_data->security_hard_key == 1)
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
|
||||
else
|
||||
cgs_get_firmware_info(smumgr->device,
|
||||
smu7_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info);
|
||||
|
||||
result = smu7_upload_smc_firmware_data(smumgr, info.image_size, (uint32_t *)info.kptr, SMU7_SMC_SIZE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int smu7_init(struct pp_smumgr *smumgr)
|
||||
{
|
||||
struct smu7_smumgr *smu_data;
|
||||
uint8_t *internal_buf;
|
||||
uint64_t mc_addr = 0;
|
||||
|
||||
/* Allocate memory for backend private data */
|
||||
smu_data = (struct smu7_smumgr *)(smumgr->backend);
|
||||
smu_data->header_buffer.data_size =
|
||||
((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
smu_data->smu_buffer.data_size = 200*4096;
|
||||
|
||||
/* Allocate FW image data structure and header buffer and
|
||||
* send the header buffer address to SMU */
|
||||
smu_allocate_memory(smumgr->device,
|
||||
smu_data->header_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&smu_data->header_buffer.kaddr,
|
||||
&smu_data->header_buffer.handle);
|
||||
|
||||
smu_data->header = smu_data->header_buffer.kaddr;
|
||||
smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != smu_data->header),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)smu_data->header_buffer.handle);
|
||||
return -EINVAL);
|
||||
|
||||
smu_allocate_memory(smumgr->device,
|
||||
smu_data->smu_buffer.data_size,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
PAGE_SIZE,
|
||||
&mc_addr,
|
||||
&smu_data->smu_buffer.kaddr,
|
||||
&smu_data->smu_buffer.handle);
|
||||
|
||||
internal_buf = smu_data->smu_buffer.kaddr;
|
||||
smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
|
||||
smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != internal_buf),
|
||||
"Out of memory.",
|
||||
kfree(smumgr->backend);
|
||||
cgs_free_gpu_mem(smumgr->device,
|
||||
(cgs_handle_t)smu_data->smu_buffer.handle);
|
||||
return -EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int smu7_smu_fini(struct pp_smumgr *smumgr)
|
||||
{
|
||||
if (smumgr->backend) {
|
||||
kfree(smumgr->backend);
|
||||
smumgr->backend = NULL;
|
||||
}
|
||||
cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2015 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 _SMU7_SMUMANAGER_H
|
||||
#define _SMU7_SMUMANAGER_H
|
||||
|
||||
|
||||
#include <pp_endian.h>
|
||||
|
||||
#define SMC_RAM_END 0x40000
|
||||
#define mmSMC_IND_INDEX_11 0x01AC
|
||||
#define mmSMC_IND_DATA_11 0x01AD
|
||||
|
||||
struct smu7_buffer_entry {
|
||||
uint32_t data_size;
|
||||
uint32_t mc_addr_low;
|
||||
uint32_t mc_addr_high;
|
||||
void *kaddr;
|
||||
unsigned long handle;
|
||||
};
|
||||
|
||||
struct smu7_smumgr {
|
||||
uint8_t *header;
|
||||
uint8_t *mec_image;
|
||||
struct smu7_buffer_entry smu_buffer;
|
||||
struct smu7_buffer_entry header_buffer;
|
||||
|
||||
uint32_t soft_regs_start;
|
||||
uint32_t dpm_table_start;
|
||||
uint32_t mc_reg_table_start;
|
||||
uint32_t fan_table_start;
|
||||
uint32_t arb_table_start;
|
||||
uint32_t ulv_setting_starts;
|
||||
uint8_t security_hard_key;
|
||||
uint32_t acpi_optimization;
|
||||
};
|
||||
|
||||
|
||||
int smu7_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
|
||||
uint32_t *dest, uint32_t byte_count, uint32_t limit);
|
||||
int smu7_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
|
||||
const uint8_t *src, uint32_t byte_count, uint32_t limit);
|
||||
int smu7_program_jump_on_start(struct pp_smumgr *smumgr);
|
||||
bool smu7_is_smc_ram_running(struct pp_smumgr *smumgr);
|
||||
int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg);
|
||||
int smu7_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg);
|
||||
int smu7_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg,
|
||||
uint32_t parameter);
|
||||
int smu7_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr,
|
||||
uint16_t msg, uint32_t parameter);
|
||||
int smu7_send_msg_to_smc_offset(struct pp_smumgr *smumgr);
|
||||
int smu7_wait_for_smc_inactive(struct pp_smumgr *smumgr);
|
||||
|
||||
enum cgs_ucode_id smu7_convert_fw_type_to_cgs(uint32_t fw_type);
|
||||
int smu7_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
|
||||
uint32_t *value, uint32_t limit);
|
||||
int smu7_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
|
||||
uint32_t value, uint32_t limit);
|
||||
|
||||
int smu7_request_smu_load_fw(struct pp_smumgr *smumgr);
|
||||
int smu7_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type);
|
||||
int smu7_reload_firmware(struct pp_smumgr *smumgr);
|
||||
int smu7_upload_smu_firmware_image(struct pp_smumgr *smumgr);
|
||||
int smu7_init(struct pp_smumgr *smumgr);
|
||||
int smu7_smu_fini(struct pp_smumgr *smumgr);
|
||||
|
||||
#endif
|
|
@ -86,6 +86,57 @@ int smum_fini(struct pp_smumgr *smumgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->thermal_avfs_enable)
|
||||
return hwmgr->smumgr->smumgr_funcs->thermal_avfs_enable(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->thermal_setup_fan_table)
|
||||
return hwmgr->smumgr->smumgr_funcs->thermal_setup_fan_table(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->update_sclk_threshold)
|
||||
return hwmgr->smumgr->smumgr_funcs->update_sclk_threshold(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
|
||||
{
|
||||
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->update_smc_table)
|
||||
return hwmgr->smumgr->smumgr_funcs->update_smc_table(hwmgr, type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t smum_get_offsetof(struct pp_smumgr *smumgr, uint32_t type, uint32_t member)
|
||||
{
|
||||
if (NULL != smumgr->smumgr_funcs->get_offsetof)
|
||||
return smumgr->smumgr_funcs->get_offsetof(type, member);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_process_firmware_header(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->process_firmware_header)
|
||||
return hwmgr->smumgr->smumgr_funcs->process_firmware_header(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_get_argument(struct pp_smumgr *smumgr)
|
||||
{
|
||||
if (NULL != smumgr->smumgr_funcs->get_argument)
|
||||
|
@ -94,13 +145,20 @@ int smum_get_argument(struct pp_smumgr *smumgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t smum_get_mac_definition(struct pp_smumgr *smumgr, uint32_t value)
|
||||
{
|
||||
if (NULL != smumgr->smumgr_funcs->get_mac_definition)
|
||||
return smumgr->smumgr_funcs->get_mac_definition(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_download_powerplay_table(struct pp_smumgr *smumgr,
|
||||
void **table)
|
||||
{
|
||||
if (NULL != smumgr->smumgr_funcs->download_pptable_settings)
|
||||
return smumgr->smumgr_funcs->download_pptable_settings(smumgr,
|
||||
table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -267,3 +325,44 @@ int smu_free_memory(void *device, void *handle)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_init_smc_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->init_smc_table)
|
||||
return hwmgr->smumgr->smumgr_funcs->init_smc_table(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->populate_all_graphic_levels)
|
||||
return hwmgr->smumgr->smumgr_funcs->populate_all_graphic_levels(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smum_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->populate_all_memory_levels)
|
||||
return hwmgr->smumgr->smumgr_funcs->populate_all_memory_levels(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*this interface is needed by island ci/vi */
|
||||
int smum_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->initialize_mc_reg_table)
|
||||
return hwmgr->smumgr->smumgr_funcs->initialize_mc_reg_table(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smum_is_dpm_running(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->smumgr->smumgr_funcs->is_dpm_running)
|
||||
return hwmgr->smumgr->smumgr_funcs->is_dpm_running(hwmgr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue