mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main drm pull request for 4.5. I don't think I've missed
anything too major, I'm mostly back at work now but I'll probably get
some sleep in 5 years time.
Summary:
New drivers:
- etnaviv:
GPU driver for the 3D core on the Vivante core used in numerous
ARM boards.
Highlights:
Core:
- Atomic suspend/resume helpers
- Move the headers to using userspace friendlier types.
- Documentation updates
- Lots of struct_mutex removal.
- Bunch of DP MST fixes from AMD.
Panel:
- More DSI helpers
- Support for some new basic panels
i915:
- Basic Kabylake support
- DP link training and detect code refactoring
- fbc/psr fixes
- FIFO underrun fixes
- SDE interrupt handling fixes
- dma-buf/fence support in pageflip path.
- GPU side for MST audio support
radeon/amdgpu:
- Drop UMS support
- GPUVM/Scheduler optimisations
- Initial Powerplay support for Tonga/Fiji/CZ/ST
- ACP audio prerequisites
nouveau:
- GK20a instmem improvements
- PCIE link speed change support
msm:
- DSI support for msm8960/apq8064
tegra:
- Host1X support for Tegra210 SoC
vc4:
- 3D acceleration support
armada:
- Get rid of struct mutex
tda998x:
- Atomic modesetting support
- TMDS clock limitations
omapdrm:
- Atomic modesetting support
- improved TILER performance
rockchip:
- RK3036 VOP support
- Atomic modesetting support
- Synopsys DW MIPI DSI support
exynos:
- Runtime PM support
- of_graph binding for DP panels
- Cleanup of IPP code
- Configurable plane support
- Kernel panic fixes at release time"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (711 commits)
drm/fb_cma_helper: Remove implicit call to disable_unused_functions
drm/amdgpu: add missing irq.h include
drm/vmwgfx: Fix a width / pitch mismatch on framebuffer updates
drm/vmwgfx: Fix an incorrect lock check
drm: nouveau: fix nouveau_debugfs_init prototype
drm/nouveau/pci: fix check in nvkm_pcie_set_link
drm/amdgpu: validate duplicates first
drm/amdgpu: move VM page tables to the LRU end on CS v2
drm/ttm: add ttm_bo_move_to_lru_tail function v2
drm/ttm: fix adding foreign BOs to the swap LRU
drm/ttm: fix adding foreign BOs to the LRU during init v2
drm/radeon: use kobj_to_dev()
drm/amdgpu: use kobj_to_dev()
drm/amdgpu/cz: force vce clocks when sclks are forced
drm/amdgpu/cz: force uvd clocks when sclks are forced
drm/amdgpu/cz: add code to enable forcing VCE clocks
drm/amdgpu/cz: add code to enable forcing UVD clocks
drm/amdgpu: fix lost sync_to if scheduler is enabled.
drm/amd/powerplay: fix static checker warning for return meaningless value.
drm/sysfs: use kobj_to_dev()
...
This commit is contained in:
commit
984065055e
711 changed files with 83692 additions and 27096 deletions
|
|
@ -160,6 +160,7 @@ config DRM_AMDGPU
|
|||
If M is selected, the module will be called amdgpu.
|
||||
|
||||
source "drivers/gpu/drm/amd/amdgpu/Kconfig"
|
||||
source "drivers/gpu/drm/amd/powerplay/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/nouveau/Kconfig"
|
||||
|
||||
|
|
@ -266,3 +267,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
|
|||
source "drivers/gpu/drm/imx/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/vc4/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/etnaviv/Kconfig"
|
||||
|
|
|
|||
|
|
@ -75,3 +75,4 @@ obj-y += i2c/
|
|||
obj-y += panel/
|
||||
obj-y += bridge/
|
||||
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
|
||||
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/asic_reg \
|
||||
-Idrivers/gpu/drm/amd/include \
|
||||
-Idrivers/gpu/drm/amd/amdgpu \
|
||||
-Idrivers/gpu/drm/amd/scheduler
|
||||
FULL_AMD_PATH=$(src)/..
|
||||
|
||||
ccflags-y := -Iinclude/drm -I$(FULL_AMD_PATH)/include/asic_reg \
|
||||
-I$(FULL_AMD_PATH)/include \
|
||||
-I$(FULL_AMD_PATH)/amdgpu \
|
||||
-I$(FULL_AMD_PATH)/scheduler \
|
||||
-I$(FULL_AMD_PATH)/powerplay/inc
|
||||
|
||||
amdgpu-y := amdgpu_drv.o
|
||||
|
||||
|
|
@ -44,6 +47,7 @@ amdgpu-y += \
|
|||
# add SMC block
|
||||
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 \
|
||||
|
|
@ -94,6 +98,14 @@ amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
|
|||
amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
|
||||
amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o
|
||||
|
||||
ifneq ($(CONFIG_DRM_AMD_POWERPLAY),)
|
||||
|
||||
include $(FULL_AMD_PATH)/powerplay/Makefile
|
||||
|
||||
amdgpu-y += $(AMD_POWERPLAY_FILES)
|
||||
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
|
||||
|
||||
CFLAGS_amdgpu_trace_points.o := -I$(src)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#include "amdgpu_irq.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
#include "amdgpu_gds.h"
|
||||
#include "amd_powerplay.h"
|
||||
|
||||
#include "gpu_scheduler.h"
|
||||
|
||||
|
|
@ -85,6 +86,7 @@ extern int amdgpu_enable_scheduler;
|
|||
extern int amdgpu_sched_jobs;
|
||||
extern int amdgpu_sched_hw_submission;
|
||||
extern int amdgpu_enable_semaphores;
|
||||
extern int amdgpu_powerplay;
|
||||
|
||||
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
|
||||
#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||
|
|
@ -918,8 +920,8 @@ struct amdgpu_ring {
|
|||
#define AMDGPU_VM_FAULT_STOP_ALWAYS 2
|
||||
|
||||
struct amdgpu_vm_pt {
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t addr;
|
||||
struct amdgpu_bo_list_entry entry;
|
||||
uint64_t addr;
|
||||
};
|
||||
|
||||
struct amdgpu_vm_id {
|
||||
|
|
@ -981,9 +983,12 @@ struct amdgpu_vm_manager {
|
|||
void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
|
||||
void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
|
||||
struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
struct list_head *head);
|
||||
void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
|
||||
struct list_head *validated,
|
||||
struct amdgpu_bo_list_entry *entry);
|
||||
void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates);
|
||||
void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
||||
struct amdgpu_sync *sync);
|
||||
void amdgpu_vm_flush(struct amdgpu_ring *ring,
|
||||
|
|
@ -1024,11 +1029,9 @@ int amdgpu_vm_free_job(struct amdgpu_job *job);
|
|||
* context related structures
|
||||
*/
|
||||
|
||||
#define AMDGPU_CTX_MAX_CS_PENDING 16
|
||||
|
||||
struct amdgpu_ctx_ring {
|
||||
uint64_t sequence;
|
||||
struct fence *fences[AMDGPU_CTX_MAX_CS_PENDING];
|
||||
struct fence **fences;
|
||||
struct amd_sched_entity entity;
|
||||
};
|
||||
|
||||
|
|
@ -1037,6 +1040,7 @@ struct amdgpu_ctx {
|
|||
struct amdgpu_device *adev;
|
||||
unsigned reset_counter;
|
||||
spinlock_t ring_lock;
|
||||
struct fence **fences;
|
||||
struct amdgpu_ctx_ring rings[AMDGPU_MAX_RINGS];
|
||||
};
|
||||
|
||||
|
|
@ -1047,7 +1051,7 @@ struct amdgpu_ctx_mgr {
|
|||
struct idr ctx_handles;
|
||||
};
|
||||
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
|
||||
struct amdgpu_ctx *ctx);
|
||||
void amdgpu_ctx_fini(struct amdgpu_ctx *ctx);
|
||||
|
||||
|
|
@ -1254,7 +1258,7 @@ struct amdgpu_cs_parser {
|
|||
unsigned nchunks;
|
||||
struct amdgpu_cs_chunk *chunks;
|
||||
/* relocations */
|
||||
struct amdgpu_bo_list_entry *vm_bos;
|
||||
struct amdgpu_bo_list_entry vm_pd;
|
||||
struct list_head validated;
|
||||
struct fence *fence;
|
||||
|
||||
|
|
@ -1301,31 +1305,7 @@ struct amdgpu_wb {
|
|||
int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb);
|
||||
void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb);
|
||||
|
||||
/**
|
||||
* struct amdgpu_pm - power management datas
|
||||
* It keeps track of various data needed to take powermanagement decision.
|
||||
*/
|
||||
|
||||
enum amdgpu_pm_state_type {
|
||||
/* not used for dpm */
|
||||
POWER_STATE_TYPE_DEFAULT,
|
||||
POWER_STATE_TYPE_POWERSAVE,
|
||||
/* user selectable states */
|
||||
POWER_STATE_TYPE_BATTERY,
|
||||
POWER_STATE_TYPE_BALANCED,
|
||||
POWER_STATE_TYPE_PERFORMANCE,
|
||||
/* internal states */
|
||||
POWER_STATE_TYPE_INTERNAL_UVD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_SD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_HD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_HD2,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_MVC,
|
||||
POWER_STATE_TYPE_INTERNAL_BOOT,
|
||||
POWER_STATE_TYPE_INTERNAL_THERMAL,
|
||||
POWER_STATE_TYPE_INTERNAL_ACPI,
|
||||
POWER_STATE_TYPE_INTERNAL_ULV,
|
||||
POWER_STATE_TYPE_INTERNAL_3DPERF,
|
||||
};
|
||||
|
||||
enum amdgpu_int_thermal_type {
|
||||
THERMAL_TYPE_NONE,
|
||||
|
|
@ -1607,8 +1587,8 @@ struct amdgpu_dpm {
|
|||
/* vce requirements */
|
||||
struct amdgpu_vce_state vce_states[AMDGPU_MAX_VCE_LEVELS];
|
||||
enum amdgpu_vce_level vce_level;
|
||||
enum amdgpu_pm_state_type state;
|
||||
enum amdgpu_pm_state_type user_state;
|
||||
enum amd_pm_state_type state;
|
||||
enum amd_pm_state_type user_state;
|
||||
u32 platform_caps;
|
||||
u32 voltage_response_time;
|
||||
u32 backbias_response_time;
|
||||
|
|
@ -1661,8 +1641,13 @@ struct amdgpu_pm {
|
|||
const struct firmware *fw; /* SMC firmware */
|
||||
uint32_t fw_version;
|
||||
const struct amdgpu_dpm_funcs *funcs;
|
||||
uint32_t pcie_gen_mask;
|
||||
uint32_t pcie_mlw_mask;
|
||||
struct amd_pp_display_configuration pm_display_cfg;/* set by DAL */
|
||||
};
|
||||
|
||||
void amdgpu_get_pcie_info(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
* UVD
|
||||
*/
|
||||
|
|
@ -1830,6 +1815,8 @@ struct amdgpu_cu_info {
|
|||
*/
|
||||
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);
|
||||
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);
|
||||
|
|
@ -2060,6 +2047,10 @@ struct amdgpu_device {
|
|||
/* interrupts */
|
||||
struct amdgpu_irq irq;
|
||||
|
||||
/* powerplay */
|
||||
struct amd_powerplay powerplay;
|
||||
bool pp_enabled;
|
||||
|
||||
/* dpm */
|
||||
struct amdgpu_pm pm;
|
||||
u32 cg_flags;
|
||||
|
|
@ -2236,6 +2227,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
|||
#define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
|
||||
#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_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
|
||||
#define amdgpu_asic_get_cu_info(adev, info) (adev)->asic_funcs->get_cu_info((adev), (info))
|
||||
#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
|
||||
|
|
@ -2277,24 +2269,78 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
|||
#define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s))
|
||||
#define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib), (s), (d), (b))
|
||||
#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
|
||||
#define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev))
|
||||
#define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev))
|
||||
#define amdgpu_dpm_set_power_state(adev) (adev)->pm.funcs->set_power_state((adev))
|
||||
#define amdgpu_dpm_post_set_power_state(adev) (adev)->pm.funcs->post_set_power_state((adev))
|
||||
#define amdgpu_dpm_display_configuration_changed(adev) (adev)->pm.funcs->display_configuration_changed((adev))
|
||||
#define amdgpu_dpm_get_sclk(adev, l) (adev)->pm.funcs->get_sclk((adev), (l))
|
||||
#define amdgpu_dpm_get_mclk(adev, l) (adev)->pm.funcs->get_mclk((adev), (l))
|
||||
#define amdgpu_dpm_print_power_state(adev, ps) (adev)->pm.funcs->print_power_state((adev), (ps))
|
||||
#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m))
|
||||
#define amdgpu_dpm_force_performance_level(adev, l) (adev)->pm.funcs->force_performance_level((adev), (l))
|
||||
#define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev))
|
||||
#define amdgpu_dpm_powergate_uvd(adev, g) (adev)->pm.funcs->powergate_uvd((adev), (g))
|
||||
#define amdgpu_dpm_powergate_vce(adev, g) (adev)->pm.funcs->powergate_vce((adev), (g))
|
||||
#define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e))
|
||||
#define amdgpu_dpm_set_fan_control_mode(adev, m) (adev)->pm.funcs->set_fan_control_mode((adev), (m))
|
||||
#define amdgpu_dpm_get_fan_control_mode(adev) (adev)->pm.funcs->get_fan_control_mode((adev))
|
||||
#define amdgpu_dpm_set_fan_speed_percent(adev, s) (adev)->pm.funcs->set_fan_speed_percent((adev), (s))
|
||||
#define amdgpu_dpm_get_fan_speed_percent(adev, s) (adev)->pm.funcs->get_fan_speed_percent((adev), (s))
|
||||
|
||||
#define amdgpu_dpm_get_temperature(adev) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle) : \
|
||||
(adev)->pm.funcs->get_temperature((adev))
|
||||
|
||||
#define amdgpu_dpm_set_fan_control_mode(adev, m) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->set_fan_control_mode((adev)->powerplay.pp_handle, (m)) : \
|
||||
(adev)->pm.funcs->set_fan_control_mode((adev), (m))
|
||||
|
||||
#define amdgpu_dpm_get_fan_control_mode(adev) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_fan_control_mode((adev)->powerplay.pp_handle) : \
|
||||
(adev)->pm.funcs->get_fan_control_mode((adev))
|
||||
|
||||
#define amdgpu_dpm_set_fan_speed_percent(adev, s) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->set_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
|
||||
(adev)->pm.funcs->set_fan_speed_percent((adev), (s))
|
||||
|
||||
#define amdgpu_dpm_get_fan_speed_percent(adev, s) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
|
||||
(adev)->pm.funcs->get_fan_speed_percent((adev), (s))
|
||||
|
||||
#define amdgpu_dpm_get_sclk(adev, l) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_sclk((adev)->powerplay.pp_handle, (l)) : \
|
||||
(adev)->pm.funcs->get_sclk((adev), (l))
|
||||
|
||||
#define amdgpu_dpm_get_mclk(adev, l) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->get_mclk((adev)->powerplay.pp_handle, (l)) : \
|
||||
(adev)->pm.funcs->get_mclk((adev), (l))
|
||||
|
||||
|
||||
#define amdgpu_dpm_force_performance_level(adev, l) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->force_performance_level((adev)->powerplay.pp_handle, (l)) : \
|
||||
(adev)->pm.funcs->force_performance_level((adev), (l))
|
||||
|
||||
#define amdgpu_dpm_powergate_uvd(adev, g) \
|
||||
(adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->powergate_uvd((adev)->powerplay.pp_handle, (g)) : \
|
||||
(adev)->pm.funcs->powergate_uvd((adev), (g))
|
||||
|
||||
#define amdgpu_dpm_powergate_vce(adev, g) \
|
||||
(adev)->pp_enabled ? \
|
||||
(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)
|
||||
|
||||
#define amdgpu_dpm_get_performance_level(adev) \
|
||||
(adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle)
|
||||
|
||||
#define amdgpu_dpm_dispatch_task(adev, event_id, input, output) \
|
||||
(adev)->powerplay.pp_funcs->dispatch_tasks((adev)->powerplay.pp_handle, (event_id), (input), (output))
|
||||
|
||||
#define amdgpu_gds_switch(adev, r, v, d, w, a) (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
|
||||
|
||||
|
|
|
|||
|
|
@ -29,66 +29,10 @@
|
|||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_acpi.h"
|
||||
#include "amd_acpi.h"
|
||||
#include "atom.h"
|
||||
|
||||
#define ACPI_AC_CLASS "ac_adapter"
|
||||
|
||||
extern void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev);
|
||||
|
||||
struct atif_verify_interface {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 version; /* version */
|
||||
u32 notification_mask; /* supported notifications mask */
|
||||
u32 function_bits; /* supported functions bit vector */
|
||||
} __packed;
|
||||
|
||||
struct atif_system_params {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u32 valid_mask; /* valid flags mask */
|
||||
u32 flags; /* flags */
|
||||
u8 command_code; /* notify command code */
|
||||
} __packed;
|
||||
|
||||
struct atif_sbios_requests {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u32 pending; /* pending sbios requests */
|
||||
u8 panel_exp_mode; /* panel expansion mode */
|
||||
u8 thermal_gfx; /* thermal state: target gfx controller */
|
||||
u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */
|
||||
u8 forced_power_gfx; /* forced power state: target gfx controller */
|
||||
u8 forced_power_state; /* forced power state: state id */
|
||||
u8 system_power_src; /* system power source */
|
||||
u8 backlight_level; /* panel backlight level (0-255) */
|
||||
} __packed;
|
||||
|
||||
#define ATIF_NOTIFY_MASK 0x3
|
||||
#define ATIF_NOTIFY_NONE 0
|
||||
#define ATIF_NOTIFY_81 1
|
||||
#define ATIF_NOTIFY_N 2
|
||||
|
||||
struct atcs_verify_interface {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 version; /* version */
|
||||
u32 function_bits; /* supported functions bit vector */
|
||||
} __packed;
|
||||
|
||||
#define ATCS_VALID_FLAGS_MASK 0x3
|
||||
|
||||
struct atcs_pref_req_input {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
|
||||
u16 valid_flags_mask; /* valid flags mask */
|
||||
u16 flags; /* flags */
|
||||
u8 req_type; /* request type */
|
||||
u8 perf_req; /* performance request */
|
||||
} __packed;
|
||||
|
||||
struct atcs_pref_req_output {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u8 ret_val; /* return value */
|
||||
} __packed;
|
||||
|
||||
/* Call the ATIF method
|
||||
*/
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "amdgpu_acpi.h"
|
||||
#include "amd_acpi.h"
|
||||
|
||||
struct amdgpu_atpx_functions {
|
||||
bool px_params;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@
|
|||
* BIOS.
|
||||
*/
|
||||
|
||||
#define AMD_VBIOS_SIGNATURE " 761295520"
|
||||
#define AMD_VBIOS_SIGNATURE_OFFSET 0x30
|
||||
#define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
|
||||
#define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
|
||||
#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
|
||||
#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
|
||||
|
||||
/* If you boot an IGP board with a discrete card as the primary,
|
||||
* the IGP rom is not accessible via the rom bar as the IGP rom is
|
||||
* part of the system bios. On boot, the system bios puts a
|
||||
|
|
@ -58,7 +65,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
|
||||
if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
|
||||
iounmap(bios);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -74,7 +81,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
|
|||
|
||||
bool amdgpu_read_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
uint8_t __iomem *bios, val1, val2;
|
||||
uint8_t __iomem *bios, val[2];
|
||||
size_t size;
|
||||
|
||||
adev->bios = NULL;
|
||||
|
|
@ -84,10 +91,10 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
val1 = readb(&bios[0]);
|
||||
val2 = readb(&bios[1]);
|
||||
val[0] = readb(&bios[0]);
|
||||
val[1] = readb(&bios[1]);
|
||||
|
||||
if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
|
||||
if (size == 0 || !AMD_IS_VALID_VBIOS(val)) {
|
||||
pci_unmap_rom(adev->pdev, bios);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -101,6 +108,38 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
|
||||
{
|
||||
u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
|
||||
int len;
|
||||
|
||||
if (!adev->asic_funcs->read_bios_from_rom)
|
||||
return false;
|
||||
|
||||
/* validate VBIOS signature */
|
||||
if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
|
||||
return false;
|
||||
header[AMD_VBIOS_SIGNATURE_END] = 0;
|
||||
|
||||
if ((!AMD_IS_VALID_VBIOS(header)) ||
|
||||
0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
|
||||
AMD_VBIOS_SIGNATURE,
|
||||
strlen(AMD_VBIOS_SIGNATURE)))
|
||||
return false;
|
||||
|
||||
/* valid vbios, go on */
|
||||
len = AMD_VBIOS_LENGTH(header);
|
||||
len = ALIGN(len, 4);
|
||||
adev->bios = kmalloc(len, GFP_KERNEL);
|
||||
if (!adev->bios) {
|
||||
DRM_ERROR("no memory to allocate for BIOS\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read complete BIOS */
|
||||
return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
|
||||
}
|
||||
|
||||
static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
uint8_t __iomem *bios;
|
||||
|
|
@ -113,7 +152,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
|
||||
if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
|
||||
return false;
|
||||
}
|
||||
adev->bios = kmemdup(bios, size, GFP_KERNEL);
|
||||
|
|
@ -230,7 +269,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
|||
break;
|
||||
}
|
||||
|
||||
if (i == 0 || adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
|
||||
if (i == 0 || !AMD_IS_VALID_VBIOS(adev->bios)) {
|
||||
kfree(adev->bios);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -319,6 +358,9 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
|
|||
r = igp_read_bios_from_vram(adev);
|
||||
if (r == false)
|
||||
r = amdgpu_read_bios(adev);
|
||||
if (r == false) {
|
||||
r = amdgpu_read_bios_from_rom(adev);
|
||||
}
|
||||
if (r == false) {
|
||||
r = amdgpu_read_disabled_bios(adev);
|
||||
}
|
||||
|
|
@ -330,7 +372,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
|
|||
adev->bios = NULL;
|
||||
return false;
|
||||
}
|
||||
if (adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
|
||||
if (!AMD_IS_VALID_VBIOS(adev->bios)) {
|
||||
printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
|
||||
goto free_bios;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
|
|
@ -32,7 +33,6 @@
|
|||
#include "atom.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
|
||||
struct amdgpu_cgs_device {
|
||||
struct cgs_device base;
|
||||
struct amdgpu_device *adev;
|
||||
|
|
@ -398,6 +398,41 @@ static void amdgpu_cgs_write_pci_config_dword(void *cgs_device, unsigned addr,
|
|||
WARN(ret, "pci_write_config_dword error");
|
||||
}
|
||||
|
||||
|
||||
static int amdgpu_cgs_get_pci_resource(void *cgs_device,
|
||||
enum cgs_resource_type resource_type,
|
||||
uint64_t size,
|
||||
uint64_t offset,
|
||||
uint64_t *resource_base)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
|
||||
if (resource_base == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
switch (resource_type) {
|
||||
case CGS_RESOURCE_TYPE_MMIO:
|
||||
if (adev->rmmio_size == 0)
|
||||
return -ENOENT;
|
||||
if ((offset + size) > adev->rmmio_size)
|
||||
return -EINVAL;
|
||||
*resource_base = adev->rmmio_base;
|
||||
return 0;
|
||||
case CGS_RESOURCE_TYPE_DOORBELL:
|
||||
if (adev->doorbell.size == 0)
|
||||
return -ENOENT;
|
||||
if ((offset + size) > adev->doorbell.size)
|
||||
return -EINVAL;
|
||||
*resource_base = adev->doorbell.base;
|
||||
return 0;
|
||||
case CGS_RESOURCE_TYPE_FB:
|
||||
case CGS_RESOURCE_TYPE_IO:
|
||||
case CGS_RESOURCE_TYPE_ROM:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const void *amdgpu_cgs_atom_get_data_table(void *cgs_device,
|
||||
unsigned table, uint16_t *size,
|
||||
uint8_t *frev, uint8_t *crev)
|
||||
|
|
@ -703,6 +738,9 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,
|
|||
case CHIP_TONGA:
|
||||
strcpy(fw_name, "amdgpu/tonga_smc.bin");
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
strcpy(fw_name, "amdgpu/fiji_smc.bin");
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("SMC firmware not supported\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -736,6 +774,288 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_query_system_info(void *cgs_device,
|
||||
struct cgs_system_info *sys_info)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
|
||||
if (NULL == sys_info)
|
||||
return -ENODEV;
|
||||
|
||||
if (sizeof(struct cgs_system_info) != sys_info->size)
|
||||
return -ENODEV;
|
||||
|
||||
switch (sys_info->info_id) {
|
||||
case CGS_SYSTEM_INFO_ADAPTER_BDF_ID:
|
||||
sys_info->value = adev->pdev->devfn | (adev->pdev->bus->number << 8);
|
||||
break;
|
||||
case CGS_SYSTEM_INFO_PCIE_GEN_INFO:
|
||||
sys_info->value = adev->pm.pcie_gen_mask;
|
||||
break;
|
||||
case CGS_SYSTEM_INFO_PCIE_MLW:
|
||||
sys_info->value = adev->pm.pcie_mlw_mask;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_get_active_displays_info(void *cgs_device,
|
||||
struct cgs_display_info *info)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
struct amdgpu_crtc *amdgpu_crtc;
|
||||
struct drm_device *ddev = adev->ddev;
|
||||
struct drm_crtc *crtc;
|
||||
uint32_t line_time_us, vblank_lines;
|
||||
|
||||
if (info == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
|
||||
list_for_each_entry(crtc,
|
||||
&ddev->mode_config.crtc_list, head) {
|
||||
amdgpu_crtc = to_amdgpu_crtc(crtc);
|
||||
if (crtc->enabled) {
|
||||
info->active_display_mask |= (1 << amdgpu_crtc->crtc_id);
|
||||
info->display_count++;
|
||||
}
|
||||
if (info->mode_info != NULL &&
|
||||
crtc->enabled && amdgpu_crtc->enabled &&
|
||||
amdgpu_crtc->hw_mode.clock) {
|
||||
line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
|
||||
amdgpu_crtc->hw_mode.clock;
|
||||
vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
|
||||
amdgpu_crtc->hw_mode.crtc_vdisplay +
|
||||
(amdgpu_crtc->v_border * 2);
|
||||
info->mode_info->vblank_time_us = vblank_lines * line_time_us;
|
||||
info->mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
|
||||
info->mode_info->ref_clock = adev->clock.spll.reference_freq;
|
||||
info->mode_info++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \brief evaluate acpi namespace object, handle or pathname must be valid
|
||||
* \param cgs_device
|
||||
* \param info input/output arguments for the control method
|
||||
* \return status
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ACPI)
|
||||
static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
|
||||
struct cgs_acpi_method_info *info)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
acpi_handle handle;
|
||||
struct acpi_object_list input;
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *params = NULL;
|
||||
union acpi_object *obj = NULL;
|
||||
uint8_t name[5] = {'\0'};
|
||||
struct cgs_acpi_method_argument *argument = NULL;
|
||||
uint32_t i, count;
|
||||
acpi_status status;
|
||||
int result;
|
||||
uint32_t func_no = 0xFFFFFFFF;
|
||||
|
||||
handle = ACPI_HANDLE(&adev->pdev->dev);
|
||||
if (!handle)
|
||||
return -ENODEV;
|
||||
|
||||
memset(&input, 0, sizeof(struct acpi_object_list));
|
||||
|
||||
/* validate input info */
|
||||
if (info->size != sizeof(struct cgs_acpi_method_info))
|
||||
return -EINVAL;
|
||||
|
||||
input.count = info->input_count;
|
||||
if (info->input_count > 0) {
|
||||
if (info->pinput_argument == NULL)
|
||||
return -EINVAL;
|
||||
argument = info->pinput_argument;
|
||||
func_no = argument->value;
|
||||
for (i = 0; i < info->input_count; i++) {
|
||||
if (((argument->type == ACPI_TYPE_STRING) ||
|
||||
(argument->type == ACPI_TYPE_BUFFER)) &&
|
||||
(argument->pointer == NULL))
|
||||
return -EINVAL;
|
||||
argument++;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->output_count > 0) {
|
||||
if (info->poutput_argument == NULL)
|
||||
return -EINVAL;
|
||||
argument = info->poutput_argument;
|
||||
for (i = 0; i < info->output_count; i++) {
|
||||
if (((argument->type == ACPI_TYPE_STRING) ||
|
||||
(argument->type == ACPI_TYPE_BUFFER))
|
||||
&& (argument->pointer == NULL))
|
||||
return -EINVAL;
|
||||
argument++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The path name passed to acpi_evaluate_object should be null terminated */
|
||||
if ((info->field & CGS_ACPI_FIELD_METHOD_NAME) != 0) {
|
||||
strncpy(name, (char *)&(info->name), sizeof(uint32_t));
|
||||
name[4] = '\0';
|
||||
}
|
||||
|
||||
/* parse input parameters */
|
||||
if (input.count > 0) {
|
||||
input.pointer = params =
|
||||
kzalloc(sizeof(union acpi_object) * input.count, GFP_KERNEL);
|
||||
if (params == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
argument = info->pinput_argument;
|
||||
|
||||
for (i = 0; i < input.count; i++) {
|
||||
params->type = argument->type;
|
||||
switch (params->type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
params->integer.value = argument->value;
|
||||
break;
|
||||
case ACPI_TYPE_STRING:
|
||||
params->string.length = argument->method_length;
|
||||
params->string.pointer = argument->pointer;
|
||||
break;
|
||||
case ACPI_TYPE_BUFFER:
|
||||
params->buffer.length = argument->method_length;
|
||||
params->buffer.pointer = argument->pointer;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
params++;
|
||||
argument++;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse output info */
|
||||
count = info->output_count;
|
||||
argument = info->poutput_argument;
|
||||
|
||||
/* evaluate the acpi method */
|
||||
status = acpi_evaluate_object(handle, name, &input, &output);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* return the output info */
|
||||
obj = output.pointer;
|
||||
|
||||
if (count > 1) {
|
||||
if ((obj->type != ACPI_TYPE_PACKAGE) ||
|
||||
(obj->package.count != count)) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
params = obj->package.elements;
|
||||
} else
|
||||
params = obj;
|
||||
|
||||
if (params == NULL) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (argument->type != params->type) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
switch (params->type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
argument->value = params->integer.value;
|
||||
break;
|
||||
case ACPI_TYPE_STRING:
|
||||
if ((params->string.length != argument->data_length) ||
|
||||
(params->string.pointer == NULL)) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
strncpy(argument->pointer,
|
||||
params->string.pointer,
|
||||
params->string.length);
|
||||
break;
|
||||
case ACPI_TYPE_BUFFER:
|
||||
if (params->buffer.pointer == NULL) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
memcpy(argument->pointer,
|
||||
params->buffer.pointer,
|
||||
argument->data_length);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
argument++;
|
||||
params++;
|
||||
}
|
||||
|
||||
error:
|
||||
if (obj != NULL)
|
||||
kfree(obj);
|
||||
kfree((void *)input.pointer);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
|
||||
struct cgs_acpi_method_info *info)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
int amdgpu_cgs_call_acpi_method(void *cgs_device,
|
||||
uint32_t acpi_method,
|
||||
uint32_t acpi_function,
|
||||
void *pinput, void *poutput,
|
||||
uint32_t output_count,
|
||||
uint32_t input_size,
|
||||
uint32_t output_size)
|
||||
{
|
||||
struct cgs_acpi_method_argument acpi_input[2] = { {0}, {0} };
|
||||
struct cgs_acpi_method_argument acpi_output = {0};
|
||||
struct cgs_acpi_method_info info = {0};
|
||||
|
||||
acpi_input[0].type = CGS_ACPI_TYPE_INTEGER;
|
||||
acpi_input[0].method_length = sizeof(uint32_t);
|
||||
acpi_input[0].data_length = sizeof(uint32_t);
|
||||
acpi_input[0].value = acpi_function;
|
||||
|
||||
acpi_input[1].type = CGS_ACPI_TYPE_BUFFER;
|
||||
acpi_input[1].method_length = CGS_ACPI_MAX_BUFFER_SIZE;
|
||||
acpi_input[1].data_length = input_size;
|
||||
acpi_input[1].pointer = pinput;
|
||||
|
||||
acpi_output.type = CGS_ACPI_TYPE_BUFFER;
|
||||
acpi_output.method_length = CGS_ACPI_MAX_BUFFER_SIZE;
|
||||
acpi_output.data_length = output_size;
|
||||
acpi_output.pointer = poutput;
|
||||
|
||||
info.size = sizeof(struct cgs_acpi_method_info);
|
||||
info.field = CGS_ACPI_FIELD_METHOD_NAME | CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT;
|
||||
info.input_count = 2;
|
||||
info.name = acpi_method;
|
||||
info.pinput_argument = acpi_input;
|
||||
info.output_count = output_count;
|
||||
info.poutput_argument = &acpi_output;
|
||||
|
||||
return amdgpu_cgs_acpi_eval_object(cgs_device, &info);
|
||||
}
|
||||
|
||||
static const struct cgs_ops amdgpu_cgs_ops = {
|
||||
amdgpu_cgs_gpu_mem_info,
|
||||
amdgpu_cgs_gmap_kmem,
|
||||
|
|
@ -756,6 +1076,7 @@ static const struct cgs_ops amdgpu_cgs_ops = {
|
|||
amdgpu_cgs_write_pci_config_byte,
|
||||
amdgpu_cgs_write_pci_config_word,
|
||||
amdgpu_cgs_write_pci_config_dword,
|
||||
amdgpu_cgs_get_pci_resource,
|
||||
amdgpu_cgs_atom_get_data_table,
|
||||
amdgpu_cgs_atom_get_cmd_table_revs,
|
||||
amdgpu_cgs_atom_exec_cmd_table,
|
||||
|
|
@ -768,7 +1089,10 @@ static const struct cgs_ops amdgpu_cgs_ops = {
|
|||
amdgpu_cgs_set_camera_voltages,
|
||||
amdgpu_cgs_get_firmware_info,
|
||||
amdgpu_cgs_set_powergating_state,
|
||||
amdgpu_cgs_set_clockgating_state
|
||||
amdgpu_cgs_set_clockgating_state,
|
||||
amdgpu_cgs_get_active_displays_info,
|
||||
amdgpu_cgs_call_acpi_method,
|
||||
amdgpu_cgs_query_system_info,
|
||||
};
|
||||
|
||||
static const struct cgs_os_ops amdgpu_cgs_os_ops = {
|
||||
|
|
|
|||
|
|
@ -406,8 +406,8 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
|
|||
amdgpu_cs_buckets_get_list(&buckets, &p->validated);
|
||||
}
|
||||
|
||||
p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
|
||||
&p->validated);
|
||||
INIT_LIST_HEAD(&duplicates);
|
||||
amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
|
||||
|
||||
if (p->uf.bo)
|
||||
list_add(&p->uf_entry.tv.head, &p->validated);
|
||||
|
|
@ -415,20 +415,23 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
|
|||
if (need_mmap_lock)
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
|
||||
INIT_LIST_HEAD(&duplicates);
|
||||
r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates);
|
||||
if (unlikely(r != 0))
|
||||
goto error_reserve;
|
||||
|
||||
r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
|
||||
amdgpu_vm_get_pt_bos(&fpriv->vm, &duplicates);
|
||||
|
||||
r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
|
||||
if (r)
|
||||
goto error_validate;
|
||||
|
||||
r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
|
||||
r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
|
||||
|
||||
error_validate:
|
||||
if (r)
|
||||
if (r) {
|
||||
amdgpu_vm_move_pt_bos_in_lru(p->adev, &fpriv->vm);
|
||||
ttm_eu_backoff_reservation(&p->ticket, &p->validated);
|
||||
}
|
||||
|
||||
error_reserve:
|
||||
if (need_mmap_lock)
|
||||
|
|
@ -472,8 +475,11 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a,
|
|||
**/
|
||||
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
|
||||
{
|
||||
struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
|
||||
unsigned i;
|
||||
|
||||
amdgpu_vm_move_pt_bos_in_lru(parser->adev, &fpriv->vm);
|
||||
|
||||
if (!error) {
|
||||
/* Sort the buffer list from the smallest to largest buffer,
|
||||
* which affects the order of buffers in the LRU list.
|
||||
|
|
@ -501,7 +507,6 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
|
|||
if (parser->bo_list)
|
||||
amdgpu_bo_list_put(parser->bo_list);
|
||||
|
||||
drm_free_large(parser->vm_bos);
|
||||
for (i = 0; i < parser->nchunks; i++)
|
||||
drm_free_large(parser->chunks[i].kdata);
|
||||
kfree(parser->chunks);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <drm/drmP.h>
|
||||
#include "amdgpu.h"
|
||||
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
|
||||
struct amdgpu_ctx *ctx)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
|
@ -35,17 +35,25 @@ int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
|||
ctx->adev = adev;
|
||||
kref_init(&ctx->refcount);
|
||||
spin_lock_init(&ctx->ring_lock);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
ctx->rings[i].sequence = 1;
|
||||
ctx->fences = kzalloc(sizeof(struct fence *) * amdgpu_sched_jobs *
|
||||
AMDGPU_MAX_RINGS, GFP_KERNEL);
|
||||
if (!ctx->fences)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
ctx->rings[i].sequence = 1;
|
||||
ctx->rings[i].fences = (void *)ctx->fences + sizeof(struct fence *) *
|
||||
amdgpu_sched_jobs * i;
|
||||
}
|
||||
if (amdgpu_enable_scheduler) {
|
||||
/* create context entity for each ring */
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
struct amd_sched_rq *rq;
|
||||
if (kernel)
|
||||
rq = &adev->rings[i]->sched.kernel_rq;
|
||||
else
|
||||
rq = &adev->rings[i]->sched.sched_rq;
|
||||
if (pri >= AMD_SCHED_MAX_PRIORITY) {
|
||||
kfree(ctx->fences);
|
||||
return -EINVAL;
|
||||
}
|
||||
rq = &adev->rings[i]->sched.sched_rq[pri];
|
||||
r = amd_sched_entity_init(&adev->rings[i]->sched,
|
||||
&ctx->rings[i].entity,
|
||||
rq, amdgpu_sched_jobs);
|
||||
|
|
@ -57,7 +65,7 @@ int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
|||
for (j = 0; j < i; j++)
|
||||
amd_sched_entity_fini(&adev->rings[j]->sched,
|
||||
&ctx->rings[j].entity);
|
||||
kfree(ctx);
|
||||
kfree(ctx->fences);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
@ -73,8 +81,9 @@ void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
|
|||
return;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
for (j = 0; j < AMDGPU_CTX_MAX_CS_PENDING; ++j)
|
||||
for (j = 0; j < amdgpu_sched_jobs; ++j)
|
||||
fence_put(ctx->rings[i].fences[j]);
|
||||
kfree(ctx->fences);
|
||||
|
||||
if (amdgpu_enable_scheduler) {
|
||||
for (i = 0; i < adev->num_rings; i++)
|
||||
|
|
@ -103,9 +112,13 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
|
|||
return r;
|
||||
}
|
||||
*id = (uint32_t)r;
|
||||
r = amdgpu_ctx_init(adev, false, ctx);
|
||||
r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_NORMAL, ctx);
|
||||
if (r) {
|
||||
idr_remove(&mgr->ctx_handles, *id);
|
||||
*id = 0;
|
||||
kfree(ctx);
|
||||
}
|
||||
mutex_unlock(&mgr->lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +252,7 @@ uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
|
|||
unsigned idx = 0;
|
||||
struct fence *other = NULL;
|
||||
|
||||
idx = seq % AMDGPU_CTX_MAX_CS_PENDING;
|
||||
idx = seq & (amdgpu_sched_jobs - 1);
|
||||
other = cring->fences[idx];
|
||||
if (other) {
|
||||
signed long r;
|
||||
|
|
@ -274,12 +287,12 @@ struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
|
|||
}
|
||||
|
||||
|
||||
if (seq + AMDGPU_CTX_MAX_CS_PENDING < cring->sequence) {
|
||||
if (seq + amdgpu_sched_jobs < cring->sequence) {
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fence = fence_get(cring->fences[seq % AMDGPU_CTX_MAX_CS_PENDING]);
|
||||
fence = fence_get(cring->fences[seq & (amdgpu_sched_jobs - 1)]);
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
|
||||
return fence;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "amdgpu_i2c.h"
|
||||
#include "atom.h"
|
||||
#include "amdgpu_atombios.h"
|
||||
#include "amd_pcie.h"
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
#include "cik.h"
|
||||
#endif
|
||||
|
|
@ -949,6 +950,15 @@ static bool amdgpu_check_pot_argument(int arg)
|
|||
*/
|
||||
static void amdgpu_check_arguments(struct amdgpu_device *adev)
|
||||
{
|
||||
if (amdgpu_sched_jobs < 4) {
|
||||
dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
|
||||
amdgpu_sched_jobs);
|
||||
amdgpu_sched_jobs = 4;
|
||||
} else if (!amdgpu_check_pot_argument(amdgpu_sched_jobs)){
|
||||
dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n",
|
||||
amdgpu_sched_jobs);
|
||||
amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs);
|
||||
}
|
||||
/* vramlimit must be a power of two */
|
||||
if (!amdgpu_check_pot_argument(amdgpu_vram_limit)) {
|
||||
dev_warn(adev->dev, "vram limit (%d) must be a power of 2\n",
|
||||
|
|
@ -1214,12 +1224,14 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
|
|||
} else {
|
||||
if (adev->ip_blocks[i].funcs->early_init) {
|
||||
r = adev->ip_blocks[i].funcs->early_init((void *)adev);
|
||||
if (r == -ENOENT)
|
||||
if (r == -ENOENT) {
|
||||
adev->ip_block_status[i].valid = false;
|
||||
else if (r)
|
||||
} else if (r) {
|
||||
DRM_ERROR("early_init %d failed %d\n", i, r);
|
||||
return r;
|
||||
else
|
||||
} else {
|
||||
adev->ip_block_status[i].valid = true;
|
||||
}
|
||||
} else {
|
||||
adev->ip_block_status[i].valid = true;
|
||||
}
|
||||
|
|
@ -1237,20 +1249,28 @@ static int amdgpu_init(struct amdgpu_device *adev)
|
|||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("sw_init %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_block_status[i].sw = true;
|
||||
/* need to do gmc hw init early so we can allocate gpu mem */
|
||||
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
|
||||
r = amdgpu_vram_scratch_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r);
|
||||
return r;
|
||||
}
|
||||
r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("hw_init %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_wb_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu_wb_init failed %d\n", r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_block_status[i].hw = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1262,8 +1282,10 @@ static int amdgpu_init(struct amdgpu_device *adev)
|
|||
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("hw_init %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_block_status[i].hw = true;
|
||||
}
|
||||
|
||||
|
|
@ -1280,12 +1302,16 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
|
|||
/* enable clockgating to save power */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_GATE);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(gate) %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
if (adev->ip_blocks[i].funcs->late_init) {
|
||||
r = adev->ip_blocks[i].funcs->late_init((void *)adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("late_init %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1306,10 +1332,15 @@ static int amdgpu_fini(struct amdgpu_device *adev)
|
|||
/* ungate blocks before hw fini so that we can shutdown the blocks safely */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
|
||||
/* XXX handle errors */
|
||||
if (r) {
|
||||
DRM_DEBUG("hw_fini %d failed %d\n", i, r);
|
||||
}
|
||||
adev->ip_block_status[i].hw = false;
|
||||
}
|
||||
|
||||
|
|
@ -1318,6 +1349,9 @@ static int amdgpu_fini(struct amdgpu_device *adev)
|
|||
continue;
|
||||
r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
|
||||
/* XXX handle errors */
|
||||
if (r) {
|
||||
DRM_DEBUG("sw_fini %d failed %d\n", i, r);
|
||||
}
|
||||
adev->ip_block_status[i].sw = false;
|
||||
adev->ip_block_status[i].valid = false;
|
||||
}
|
||||
|
|
@ -1335,9 +1369,15 @@ static int amdgpu_suspend(struct amdgpu_device *adev)
|
|||
/* ungate blocks so that suspend can properly shut them down */
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
if (r) {
|
||||
DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
|
||||
}
|
||||
/* XXX handle errors */
|
||||
r = adev->ip_blocks[i].funcs->suspend(adev);
|
||||
/* XXX handle errors */
|
||||
if (r) {
|
||||
DRM_ERROR("suspend %d failed %d\n", i, r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1351,8 +1391,10 @@ static int amdgpu_resume(struct amdgpu_device *adev)
|
|||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].funcs->resume(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("resume %d failed %d\n", i, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1484,8 +1526,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
return -EINVAL;
|
||||
}
|
||||
r = amdgpu_atombios_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_atombios_init failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Post card if necessary */
|
||||
if (!amdgpu_card_posted(adev)) {
|
||||
|
|
@ -1499,21 +1543,26 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
|
||||
/* Initialize clocks */
|
||||
r = amdgpu_atombios_get_clock_info(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
|
||||
return r;
|
||||
}
|
||||
/* init i2c buses */
|
||||
amdgpu_atombios_i2c_init(adev);
|
||||
|
||||
/* Fence driver */
|
||||
r = amdgpu_fence_driver_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_fence_driver_init failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* init the mode config */
|
||||
drm_mode_config_init(adev->ddev);
|
||||
|
||||
r = amdgpu_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_init failed\n");
|
||||
amdgpu_fini(adev);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1528,7 +1577,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_ctx_init(adev, true, &adev->kernel_ctx);
|
||||
r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_KERNEL, &adev->kernel_ctx);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "failed to create kernel context (%d).\n", r);
|
||||
return r;
|
||||
|
|
@ -1570,8 +1619,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
* explicit gating rather than handling it automatically.
|
||||
*/
|
||||
r = amdgpu_late_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_late_init failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1788,6 +1839,7 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
|
|||
}
|
||||
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
drm_helper_hpd_irq_event(dev);
|
||||
|
||||
if (fbcon) {
|
||||
amdgpu_fbdev_set_suspend(adev, 0);
|
||||
|
|
@ -1881,6 +1933,83 @@ retry:
|
|||
return r;
|
||||
}
|
||||
|
||||
void amdgpu_get_pcie_info(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
if (pci_is_root_bus(adev->pdev->bus))
|
||||
return;
|
||||
|
||||
if (amdgpu_pcie_gen2 == 0)
|
||||
return;
|
||||
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
|
||||
if (!ret) {
|
||||
adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
|
||||
CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
|
||||
CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
|
||||
|
||||
if (mask & DRM_PCIE_SPEED_25)
|
||||
adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
|
||||
if (mask & DRM_PCIE_SPEED_50)
|
||||
adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2;
|
||||
if (mask & DRM_PCIE_SPEED_80)
|
||||
adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3;
|
||||
}
|
||||
ret = drm_pcie_get_max_link_width(adev->ddev, &mask);
|
||||
if (!ret) {
|
||||
switch (mask) {
|
||||
case 32:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 16:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 12:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 8:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 4:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 2:
|
||||
adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
|
||||
CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
|
||||
break;
|
||||
case 1:
|
||||
adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugfs
|
||||
|
|
|
|||
|
|
@ -79,9 +79,10 @@ int amdgpu_vm_fault_stop = 0;
|
|||
int amdgpu_vm_debug = 0;
|
||||
int amdgpu_exp_hw_support = 0;
|
||||
int amdgpu_enable_scheduler = 1;
|
||||
int amdgpu_sched_jobs = 16;
|
||||
int amdgpu_sched_jobs = 32;
|
||||
int amdgpu_sched_hw_submission = 2;
|
||||
int amdgpu_enable_semaphores = 0;
|
||||
int amdgpu_powerplay = -1;
|
||||
|
||||
MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
|
||||
module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
|
||||
|
|
@ -155,7 +156,7 @@ module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
|
|||
MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable (default), 0 = disable)");
|
||||
module_param_named(enable_scheduler, amdgpu_enable_scheduler, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 16)");
|
||||
MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)");
|
||||
module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)");
|
||||
|
|
@ -164,6 +165,11 @@ module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
|
|||
MODULE_PARM_DESC(enable_semaphores, "Enable semaphores (1 = enable, 0 = disable (default))");
|
||||
module_param_named(enable_semaphores, amdgpu_enable_semaphores, int, 0644);
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 = auto (default))");
|
||||
module_param_named(powerplay, amdgpu_powerplay, int, 0444);
|
||||
#endif
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
/* Kaveri */
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ out_unref:
|
|||
|
||||
}
|
||||
if (fb && ret) {
|
||||
drm_gem_object_unreference(gobj);
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
drm_framebuffer_unregister_private(fb);
|
||||
drm_framebuffer_cleanup(fb);
|
||||
kfree(fb);
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
|||
struct amdgpu_bo_va *bo_va, uint32_t operation)
|
||||
{
|
||||
struct ttm_validate_buffer tv, *entry;
|
||||
struct amdgpu_bo_list_entry *vm_bos;
|
||||
struct amdgpu_bo_list_entry vm_pd;
|
||||
struct ww_acquire_ctx ticket;
|
||||
struct list_head list, duplicates;
|
||||
unsigned domain;
|
||||
|
|
@ -461,15 +461,14 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
|||
tv.shared = true;
|
||||
list_add(&tv.head, &list);
|
||||
|
||||
vm_bos = amdgpu_vm_get_bos(adev, bo_va->vm, &list);
|
||||
if (!vm_bos)
|
||||
return;
|
||||
amdgpu_vm_get_pd_bo(bo_va->vm, &list, &vm_pd);
|
||||
|
||||
/* Provide duplicates to avoid -EALREADY */
|
||||
r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates);
|
||||
if (r)
|
||||
goto error_free;
|
||||
goto error_print;
|
||||
|
||||
amdgpu_vm_get_pt_bos(bo_va->vm, &duplicates);
|
||||
list_for_each_entry(entry, &list, head) {
|
||||
domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
|
||||
/* if anything is swapped out don't swap it in here,
|
||||
|
|
@ -499,9 +498,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
|||
error_unreserve:
|
||||
ttm_eu_backoff_reservation(&ticket, &list);
|
||||
|
||||
error_free:
|
||||
drm_free_large(vm_bos);
|
||||
|
||||
error_print:
|
||||
if (r && r != -ERESTARTSYS)
|
||||
DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
* Alex Deucher
|
||||
* Jerome Glisse
|
||||
*/
|
||||
#include <linux/irq.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
|
|
@ -312,6 +313,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
|
|||
}
|
||||
|
||||
adev->irq.sources[src_id] = source;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -335,15 +337,19 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
|||
return;
|
||||
}
|
||||
|
||||
src = adev->irq.sources[src_id];
|
||||
if (!src) {
|
||||
DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
|
||||
return;
|
||||
}
|
||||
if (adev->irq.virq[src_id]) {
|
||||
generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
|
||||
} else {
|
||||
src = adev->irq.sources[src_id];
|
||||
if (!src) {
|
||||
DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
|
||||
return;
|
||||
}
|
||||
|
||||
r = src->funcs->process(adev, src, entry);
|
||||
if (r)
|
||||
DRM_ERROR("error processing interrupt (%d)\n", r);
|
||||
r = src->funcs->process(adev, src, entry);
|
||||
if (r)
|
||||
DRM_ERROR("error processing interrupt (%d)\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -461,3 +467,90 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
|
|||
|
||||
return !!atomic_read(&src->enabled_types[type]);
|
||||
}
|
||||
|
||||
/* gen irq */
|
||||
static void amdgpu_irq_mask(struct irq_data *irqd)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
static void amdgpu_irq_unmask(struct irq_data *irqd)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
static struct irq_chip amdgpu_irq_chip = {
|
||||
.name = "amdgpu-ih",
|
||||
.irq_mask = amdgpu_irq_mask,
|
||||
.irq_unmask = amdgpu_irq_unmask,
|
||||
};
|
||||
|
||||
static int amdgpu_irqdomain_map(struct irq_domain *d,
|
||||
unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
|
||||
return -EPERM;
|
||||
|
||||
irq_set_chip_and_handler(irq,
|
||||
&amdgpu_irq_chip, handle_simple_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
|
||||
.map = amdgpu_irqdomain_map,
|
||||
};
|
||||
|
||||
/**
|
||||
* amdgpu_irq_add_domain - create a linear irq domain
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
*
|
||||
* Create an irq domain for GPU interrupt sources
|
||||
* that may be driven by another driver (e.g., ACP).
|
||||
*/
|
||||
int amdgpu_irq_add_domain(struct amdgpu_device *adev)
|
||||
{
|
||||
adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
|
||||
&amdgpu_hw_irqdomain_ops, adev);
|
||||
if (!adev->irq.domain) {
|
||||
DRM_ERROR("GPU irq add domain failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_irq_remove_domain - remove the irq domain
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
*
|
||||
* Remove the irq domain for GPU interrupt sources
|
||||
* that may be driven by another driver (e.g., ACP).
|
||||
*/
|
||||
void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->irq.domain) {
|
||||
irq_domain_remove(adev->irq.domain);
|
||||
adev->irq.domain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_irq_create_mapping - create a mapping between a domain irq and a
|
||||
* Linux irq
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @src_id: IH source id
|
||||
*
|
||||
* Create a mapping between a domain irq (GPU IH src id) and a Linux irq
|
||||
* Use this for components that generate a GPU interrupt, but are driven
|
||||
* by a different driver (e.g., ACP).
|
||||
* Returns the Linux irq.
|
||||
*/
|
||||
unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
|
||||
{
|
||||
adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
|
||||
|
||||
return adev->irq.virq[src_id];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef __AMDGPU_IRQ_H__
|
||||
#define __AMDGPU_IRQ_H__
|
||||
|
||||
#include <linux/irqdomain.h>
|
||||
#include "amdgpu_ih.h"
|
||||
|
||||
#define AMDGPU_MAX_IRQ_SRC_ID 0x100
|
||||
|
|
@ -65,6 +66,10 @@ struct amdgpu_irq {
|
|||
/* interrupt ring */
|
||||
struct amdgpu_ih_ring ih;
|
||||
const struct amdgpu_ih_funcs *ih_funcs;
|
||||
|
||||
/* gen irq stuff */
|
||||
struct irq_domain *domain; /* GPU irq controller domain */
|
||||
unsigned virq[AMDGPU_MAX_IRQ_SRC_ID];
|
||||
};
|
||||
|
||||
void amdgpu_irq_preinstall(struct drm_device *dev);
|
||||
|
|
@ -90,4 +95,8 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
|
|||
bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
|
||||
unsigned type);
|
||||
|
||||
int amdgpu_irq_add_domain(struct amdgpu_device *adev);
|
||||
void amdgpu_irq_remove_domain(struct amdgpu_device *adev);
|
||||
unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_fixed.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo)
|
|||
*/
|
||||
static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
|
||||
{
|
||||
WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
|
||||
return bo->tbo.offset;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,10 +30,16 @@
|
|||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
#include "amd_powerplay.h"
|
||||
|
||||
static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->pp_enabled)
|
||||
/* TODO */
|
||||
return;
|
||||
|
||||
if (adev->pm.dpm_enabled) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
|
|
@ -52,7 +58,12 @@ static ssize_t amdgpu_get_dpm_state(struct device *dev,
|
|||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = ddev->dev_private;
|
||||
enum amdgpu_pm_state_type pm = adev->pm.dpm.user_state;
|
||||
enum amd_pm_state_type pm;
|
||||
|
||||
if (adev->pp_enabled) {
|
||||
pm = amdgpu_dpm_get_current_power_state(adev);
|
||||
} else
|
||||
pm = adev->pm.dpm.user_state;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
|
||||
|
|
@ -66,40 +77,57 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,
|
|||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = ddev->dev_private;
|
||||
enum amd_pm_state_type state;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (strncmp("battery", buf, strlen("battery")) == 0)
|
||||
adev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
|
||||
state = POWER_STATE_TYPE_BATTERY;
|
||||
else if (strncmp("balanced", buf, strlen("balanced")) == 0)
|
||||
adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
|
||||
state = POWER_STATE_TYPE_BALANCED;
|
||||
else if (strncmp("performance", buf, strlen("performance")) == 0)
|
||||
adev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
|
||||
state = POWER_STATE_TYPE_PERFORMANCE;
|
||||
else {
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
||||
/* Can't set dpm state when the card is off */
|
||||
if (!(adev->flags & AMD_IS_PX) ||
|
||||
(ddev->switch_power_state == DRM_SWITCH_POWER_ON))
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
if (adev->pp_enabled) {
|
||||
amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.user_state = state;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
||||
/* Can't set dpm state when the card is off */
|
||||
if (!(adev->flags & AMD_IS_PX) ||
|
||||
(ddev->switch_power_state == DRM_SWITCH_POWER_ON))
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
}
|
||||
fail:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = ddev->dev_private;
|
||||
enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
|
||||
(level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
|
||||
if (adev->pp_enabled) {
|
||||
enum amd_dpm_forced_level level;
|
||||
|
||||
level = amdgpu_dpm_get_performance_level(adev);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
|
||||
(level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
|
||||
} else {
|
||||
enum amdgpu_dpm_forced_level level;
|
||||
|
||||
level = adev->pm.dpm.forced_level;
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
|
||||
(level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
||||
|
|
@ -112,7 +140,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
|||
enum amdgpu_dpm_forced_level level;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (strncmp("low", buf, strlen("low")) == 0) {
|
||||
level = AMDGPU_DPM_FORCED_LEVEL_LOW;
|
||||
} else if (strncmp("high", buf, strlen("high")) == 0) {
|
||||
|
|
@ -123,7 +150,11 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
|||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (adev->pm.funcs->force_performance_level) {
|
||||
|
||||
if (adev->pp_enabled)
|
||||
amdgpu_dpm_force_performance_level(adev, level);
|
||||
else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->pm.dpm.thermal_active) {
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
|
|
@ -131,6 +162,9 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
|
|||
ret = amdgpu_dpm_force_performance_level(adev, level);
|
||||
if (ret)
|
||||
count = -EINVAL;
|
||||
else
|
||||
adev->pm.dpm.forced_level = level;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
fail:
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
|
@ -150,10 +184,10 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
|
|||
struct amdgpu_device *adev = dev_get_drvdata(dev);
|
||||
int temp;
|
||||
|
||||
if (adev->pm.funcs->get_temperature)
|
||||
temp = amdgpu_dpm_get_temperature(adev);
|
||||
else
|
||||
if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
|
||||
temp = 0;
|
||||
else
|
||||
temp = amdgpu_dpm_get_temperature(adev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", temp);
|
||||
}
|
||||
|
|
@ -181,8 +215,10 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev,
|
|||
struct amdgpu_device *adev = dev_get_drvdata(dev);
|
||||
u32 pwm_mode = 0;
|
||||
|
||||
if (adev->pm.funcs->get_fan_control_mode)
|
||||
pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
|
||||
if (!adev->pp_enabled && !adev->pm.funcs->get_fan_control_mode)
|
||||
return -EINVAL;
|
||||
|
||||
pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
|
||||
|
||||
/* never 0 (full-speed), fuse or smc-controlled always */
|
||||
return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
|
||||
|
|
@ -197,7 +233,7 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
|
|||
int err;
|
||||
int value;
|
||||
|
||||
if(!adev->pm.funcs->set_fan_control_mode)
|
||||
if (!adev->pp_enabled && !adev->pm.funcs->set_fan_control_mode)
|
||||
return -EINVAL;
|
||||
|
||||
err = kstrtoint(buf, 10, &value);
|
||||
|
|
@ -290,11 +326,11 @@ static struct attribute *hwmon_attributes[] = {
|
|||
static umode_t hwmon_attributes_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int index)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct amdgpu_device *adev = dev_get_drvdata(dev);
|
||||
umode_t effective_mode = attr->mode;
|
||||
|
||||
/* Skip attributes if DPM is not enabled */
|
||||
/* Skip limit attributes if DPM is not enabled */
|
||||
if (!adev->pm.dpm_enabled &&
|
||||
(attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
|
||||
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr ||
|
||||
|
|
@ -304,6 +340,9 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
|
|||
attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
|
||||
return 0;
|
||||
|
||||
if (adev->pp_enabled)
|
||||
return effective_mode;
|
||||
|
||||
/* Skip fan attributes if fan is not present */
|
||||
if (adev->pm.no_fan &&
|
||||
(attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
|
||||
|
|
@ -351,7 +390,7 @@ void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
|
|||
container_of(work, struct amdgpu_device,
|
||||
pm.dpm.thermal.work);
|
||||
/* switch to the thermal state */
|
||||
enum amdgpu_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
|
||||
enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
|
||||
|
||||
if (!adev->pm.dpm_enabled)
|
||||
return;
|
||||
|
|
@ -379,7 +418,7 @@ void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
|
|||
}
|
||||
|
||||
static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
|
||||
enum amdgpu_pm_state_type dpm_state)
|
||||
enum amd_pm_state_type dpm_state)
|
||||
{
|
||||
int i;
|
||||
struct amdgpu_ps *ps;
|
||||
|
|
@ -516,7 +555,7 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
|
|||
{
|
||||
int i;
|
||||
struct amdgpu_ps *ps;
|
||||
enum amdgpu_pm_state_type dpm_state;
|
||||
enum amd_pm_state_type dpm_state;
|
||||
int ret;
|
||||
|
||||
/* if dpm init failed */
|
||||
|
|
@ -635,49 +674,54 @@ done:
|
|||
|
||||
void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
if (adev->pm.funcs->powergate_uvd) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
/* enable/disable UVD */
|
||||
if (adev->pp_enabled)
|
||||
amdgpu_dpm_powergate_uvd(adev, !enable);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
if (enable) {
|
||||
else {
|
||||
if (adev->pm.funcs->powergate_uvd) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.uvd_active = true;
|
||||
adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
|
||||
/* enable/disable UVD */
|
||||
amdgpu_dpm_powergate_uvd(adev, !enable);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.uvd_active = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
if (enable) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.uvd_active = true;
|
||||
adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.uvd_active = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
}
|
||||
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
}
|
||||
}
|
||||
|
||||
void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
if (adev->pm.funcs->powergate_vce) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
/* enable/disable VCE */
|
||||
if (adev->pp_enabled)
|
||||
amdgpu_dpm_powergate_vce(adev, !enable);
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
if (enable) {
|
||||
else {
|
||||
if (adev->pm.funcs->powergate_vce) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.vce_active = true;
|
||||
/* XXX select vce level based on ring/task */
|
||||
adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
|
||||
amdgpu_dpm_powergate_vce(adev, !enable);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.vce_active = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
if (enable) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.vce_active = true;
|
||||
/* XXX select vce level based on ring/task */
|
||||
adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.vce_active = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
}
|
||||
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -685,10 +729,13 @@ void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->pm.dpm.num_ps; i++) {
|
||||
printk("== power state %d ==\n", i);
|
||||
if (adev->pp_enabled)
|
||||
/* TO DO */
|
||||
return;
|
||||
|
||||
for (i = 0; i < adev->pm.dpm.num_ps; i++)
|
||||
amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
|
||||
|
|
@ -698,8 +745,11 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
|
|||
if (adev->pm.sysfs_initialized)
|
||||
return 0;
|
||||
|
||||
if (adev->pm.funcs->get_temperature == NULL)
|
||||
return 0;
|
||||
if (!adev->pp_enabled) {
|
||||
if (adev->pm.funcs->get_temperature == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev,
|
||||
DRIVER_NAME, adev,
|
||||
hwmon_groups);
|
||||
|
|
@ -748,32 +798,43 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
|
|||
if (!adev->pm.dpm_enabled)
|
||||
return;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->pp_enabled) {
|
||||
int i = 0;
|
||||
|
||||
/* update active crtc counts */
|
||||
adev->pm.dpm.new_active_crtcs = 0;
|
||||
adev->pm.dpm.new_active_crtc_count = 0;
|
||||
if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
|
||||
list_for_each_entry(crtc,
|
||||
&ddev->mode_config.crtc_list, head) {
|
||||
amdgpu_crtc = to_amdgpu_crtc(crtc);
|
||||
if (crtc->enabled) {
|
||||
adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
|
||||
adev->pm.dpm.new_active_crtc_count++;
|
||||
amdgpu_display_bandwidth_update(adev);
|
||||
mutex_lock(&adev->ring_lock);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (ring && ring->ready)
|
||||
amdgpu_fence_wait_empty(ring);
|
||||
}
|
||||
mutex_unlock(&adev->ring_lock);
|
||||
|
||||
amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE, NULL, NULL);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
adev->pm.dpm.new_active_crtcs = 0;
|
||||
adev->pm.dpm.new_active_crtc_count = 0;
|
||||
if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
|
||||
list_for_each_entry(crtc,
|
||||
&ddev->mode_config.crtc_list, head) {
|
||||
amdgpu_crtc = to_amdgpu_crtc(crtc);
|
||||
if (crtc->enabled) {
|
||||
adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
|
||||
adev->pm.dpm.new_active_crtc_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* update battery/ac status */
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
adev->pm.dpm.ac_power = true;
|
||||
else
|
||||
adev->pm.dpm.ac_power = false;
|
||||
|
||||
amdgpu_dpm_change_power_state_locked(adev);
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
|
||||
/* update battery/ac status */
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
adev->pm.dpm.ac_power = true;
|
||||
else
|
||||
adev->pm.dpm.ac_power = false;
|
||||
|
||||
amdgpu_dpm_change_power_state_locked(adev);
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -787,7 +848,13 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
|
|||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
|
||||
if (adev->pm.dpm_enabled) {
|
||||
if (!adev->pm.dpm_enabled) {
|
||||
seq_printf(m, "dpm not enabled\n");
|
||||
return 0;
|
||||
}
|
||||
if (adev->pp_enabled) {
|
||||
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->pm.funcs->debugfs_print_current_performance_level)
|
||||
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
|
||||
|
|
|
|||
317
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
Normal file
317
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
#include "atom.h"
|
||||
#include "amdgpu.h"
|
||||
#include "amd_shared.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include "amdgpu_pm.h"
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu_powerplay.h"
|
||||
#include "cik_dpm.h"
|
||||
#include "vi_dpm.h"
|
||||
|
||||
static int amdgpu_powerplay_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amd_powerplay *amd_pp;
|
||||
|
||||
amd_pp = &(adev->powerplay);
|
||||
|
||||
if (adev->pp_enabled) {
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
struct amd_pp_init *pp_init;
|
||||
|
||||
pp_init = kzalloc(sizeof(struct amd_pp_init), GFP_KERNEL);
|
||||
|
||||
if (pp_init == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pp_init->chip_family = adev->family;
|
||||
pp_init->chip_id = adev->asic_type;
|
||||
pp_init->device = amdgpu_cgs_create_device(adev);
|
||||
|
||||
ret = amd_powerplay_init(pp_init, amd_pp);
|
||||
kfree(pp_init);
|
||||
#endif
|
||||
} else {
|
||||
amd_pp->pp_handle = (void *)adev;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
case CHIP_BONAIRE:
|
||||
case CHIP_HAWAII:
|
||||
amd_pp->ip_funcs = &ci_dpm_ip_funcs;
|
||||
break;
|
||||
case CHIP_KABINI:
|
||||
case CHIP_MULLINS:
|
||||
case CHIP_KAVERI:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_TONGA:
|
||||
case CHIP_FIJI:
|
||||
adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
|
||||
break;
|
||||
default:
|
||||
adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
adev->pp_enabled = false;
|
||||
#endif
|
||||
|
||||
ret = amdgpu_powerplay_init(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adev->powerplay.ip_funcs->early_init)
|
||||
ret = adev->powerplay.ip_funcs->early_init(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int amdgpu_pp_late_init(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->late_init)
|
||||
ret = adev->powerplay.ip_funcs->late_init(
|
||||
adev->powerplay.pp_handle);
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
if (adev->pp_enabled)
|
||||
amdgpu_pm_sysfs_init(adev);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_sw_init(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->sw_init)
|
||||
ret = adev->powerplay.ip_funcs->sw_init(
|
||||
adev->powerplay.pp_handle);
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
if (adev->pp_enabled) {
|
||||
if (amdgpu_dpm == 0)
|
||||
adev->pm.dpm_enabled = false;
|
||||
else
|
||||
adev->pm.dpm_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_sw_fini(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->sw_fini)
|
||||
ret = adev->powerplay.ip_funcs->sw_fini(
|
||||
adev->powerplay.pp_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_POWERPLAY
|
||||
if (adev->pp_enabled) {
|
||||
amdgpu_pm_sysfs_fini(adev);
|
||||
amd_powerplay_fini(adev->powerplay.pp_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_hw_init(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->pp_enabled && adev->firmware.smu_load)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
if (adev->powerplay.ip_funcs->hw_init)
|
||||
ret = adev->powerplay.ip_funcs->hw_init(
|
||||
adev->powerplay.pp_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_hw_fini(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->hw_fini)
|
||||
ret = adev->powerplay.ip_funcs->hw_fini(
|
||||
adev->powerplay.pp_handle);
|
||||
|
||||
if (adev->pp_enabled && adev->firmware.smu_load)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_suspend(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->suspend)
|
||||
ret = adev->powerplay.ip_funcs->suspend(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_resume(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->resume)
|
||||
ret = adev->powerplay.ip_funcs->resume(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->set_clockgating_state)
|
||||
ret = adev->powerplay.ip_funcs->set_clockgating_state(
|
||||
adev->powerplay.pp_handle, state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->set_powergating_state)
|
||||
ret = adev->powerplay.ip_funcs->set_powergating_state(
|
||||
adev->powerplay.pp_handle, state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static bool amdgpu_pp_is_idle(void *handle)
|
||||
{
|
||||
bool ret = true;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->is_idle)
|
||||
ret = adev->powerplay.ip_funcs->is_idle(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_wait_for_idle(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->wait_for_idle)
|
||||
ret = adev->powerplay.ip_funcs->wait_for_idle(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_pp_soft_reset(void *handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->soft_reset)
|
||||
ret = adev->powerplay.ip_funcs->soft_reset(
|
||||
adev->powerplay.pp_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void amdgpu_pp_print_status(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->powerplay.ip_funcs->print_status)
|
||||
adev->powerplay.ip_funcs->print_status(
|
||||
adev->powerplay.pp_handle);
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs amdgpu_pp_ip_funcs = {
|
||||
.early_init = amdgpu_pp_early_init,
|
||||
.late_init = amdgpu_pp_late_init,
|
||||
.sw_init = amdgpu_pp_sw_init,
|
||||
.sw_fini = amdgpu_pp_sw_fini,
|
||||
.hw_init = amdgpu_pp_hw_init,
|
||||
.hw_fini = amdgpu_pp_hw_fini,
|
||||
.suspend = amdgpu_pp_suspend,
|
||||
.resume = amdgpu_pp_resume,
|
||||
.is_idle = amdgpu_pp_is_idle,
|
||||
.wait_for_idle = amdgpu_pp_wait_for_idle,
|
||||
.soft_reset = amdgpu_pp_soft_reset,
|
||||
.print_status = amdgpu_pp_print_status,
|
||||
.set_clockgating_state = amdgpu_pp_set_clockgating_state,
|
||||
.set_powergating_state = amdgpu_pp_set_powergating_state,
|
||||
};
|
||||
33
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
Normal file
33
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_POPWERPLAY_H__
|
||||
#define __AMDGPU_POPWERPLAY_H__
|
||||
|
||||
#include "amd_shared.h"
|
||||
|
||||
extern const struct amd_ip_funcs amdgpu_pp_ip_funcs;
|
||||
|
||||
#endif /* __AMDSOC_DM_H__ */
|
||||
|
|
@ -293,7 +293,8 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
|
|||
fence = to_amdgpu_fence(sync->sync_to[i]);
|
||||
|
||||
/* check if we really need to sync */
|
||||
if (!amdgpu_fence_need_sync(fence, ring))
|
||||
if (!amdgpu_enable_scheduler &&
|
||||
!amdgpu_fence_need_sync(fence, ring))
|
||||
continue;
|
||||
|
||||
/* prevent GPU deadlocks */
|
||||
|
|
@ -303,7 +304,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
|
|||
}
|
||||
|
||||
if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) {
|
||||
r = fence_wait(&fence->base, true);
|
||||
r = fence_wait(sync->sync_to[i], true);
|
||||
if (r)
|
||||
return r;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -75,50 +75,77 @@ static unsigned amdgpu_vm_directory_size(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_get_bos - add the vm BOs to a validation list
|
||||
* amdgpu_vm_get_pd_bo - add the VM PD to a validation list
|
||||
*
|
||||
* @vm: vm providing the BOs
|
||||
* @head: head of validation list
|
||||
* @validated: head of validation list
|
||||
* @entry: entry to add
|
||||
*
|
||||
* Add the page directory to the list of BOs to
|
||||
* validate for command submission (cayman+).
|
||||
* validate for command submission.
|
||||
*/
|
||||
struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
struct list_head *head)
|
||||
void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
|
||||
struct list_head *validated,
|
||||
struct amdgpu_bo_list_entry *entry)
|
||||
{
|
||||
struct amdgpu_bo_list_entry *list;
|
||||
unsigned i, idx;
|
||||
entry->robj = vm->page_directory;
|
||||
entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
entry->priority = 0;
|
||||
entry->tv.bo = &vm->page_directory->tbo;
|
||||
entry->tv.shared = true;
|
||||
list_add(&entry->tv.head, validated);
|
||||
}
|
||||
|
||||
list = drm_malloc_ab(vm->max_pde_used + 2,
|
||||
sizeof(struct amdgpu_bo_list_entry));
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* amdgpu_vm_get_bos - add the vm BOs to a duplicates list
|
||||
*
|
||||
* @vm: vm providing the BOs
|
||||
* @duplicates: head of duplicates list
|
||||
*
|
||||
* Add the page directory to the BO duplicates list
|
||||
* for command submission.
|
||||
*/
|
||||
void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* add the vm page table to the list */
|
||||
list[0].robj = vm->page_directory;
|
||||
list[0].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
list[0].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
list[0].priority = 0;
|
||||
list[0].tv.bo = &vm->page_directory->tbo;
|
||||
list[0].tv.shared = true;
|
||||
list_add(&list[0].tv.head, head);
|
||||
for (i = 0; i <= vm->max_pde_used; ++i) {
|
||||
struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
|
||||
|
||||
for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
|
||||
if (!vm->page_tables[i].bo)
|
||||
if (!entry->robj)
|
||||
continue;
|
||||
|
||||
list[idx].robj = vm->page_tables[i].bo;
|
||||
list[idx].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
list[idx].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
list[idx].priority = 0;
|
||||
list[idx].tv.bo = &list[idx].robj->tbo;
|
||||
list[idx].tv.shared = true;
|
||||
list_add(&list[idx++].tv.head, head);
|
||||
list_add(&entry->tv.head, duplicates);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_move_pt_bos_in_lru - move the PT BOs to the LRU tail
|
||||
*
|
||||
* @adev: amdgpu device instance
|
||||
* @vm: vm providing the BOs
|
||||
*
|
||||
* Move the PT BOs to the tail of the LRU.
|
||||
*/
|
||||
void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm)
|
||||
{
|
||||
struct ttm_bo_global *glob = adev->mman.bdev.glob;
|
||||
unsigned i;
|
||||
|
||||
spin_lock(&glob->lru_lock);
|
||||
for (i = 0; i <= vm->max_pde_used; ++i) {
|
||||
struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
|
||||
|
||||
if (!entry->robj)
|
||||
continue;
|
||||
|
||||
ttm_bo_move_to_lru_tail(&entry->robj->tbo);
|
||||
}
|
||||
spin_unlock(&glob->lru_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -461,7 +488,7 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
|||
|
||||
/* walk over the address space and update the page directory */
|
||||
for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
|
||||
struct amdgpu_bo *bo = vm->page_tables[pt_idx].bo;
|
||||
struct amdgpu_bo *bo = vm->page_tables[pt_idx].entry.robj;
|
||||
uint64_t pde, pt;
|
||||
|
||||
if (bo == NULL)
|
||||
|
|
@ -638,7 +665,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,
|
|||
/* walk over the address space and update the page tables */
|
||||
for (addr = start; addr < end; ) {
|
||||
uint64_t pt_idx = addr >> amdgpu_vm_block_size;
|
||||
struct amdgpu_bo *pt = vm->page_tables[pt_idx].bo;
|
||||
struct amdgpu_bo *pt = vm->page_tables[pt_idx].entry.robj;
|
||||
unsigned nptes;
|
||||
uint64_t pte;
|
||||
int r;
|
||||
|
|
@ -1010,13 +1037,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
return -EINVAL;
|
||||
|
||||
/* make sure object fit at this offset */
|
||||
eaddr = saddr + size;
|
||||
eaddr = saddr + size - 1;
|
||||
if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
|
||||
return -EINVAL;
|
||||
|
||||
last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
|
||||
if (last_pfn > adev->vm_manager.max_pfn) {
|
||||
dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n",
|
||||
if (last_pfn >= adev->vm_manager.max_pfn) {
|
||||
dev_err(adev->dev, "va above limit (0x%08X >= 0x%08X)\n",
|
||||
last_pfn, adev->vm_manager.max_pfn);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1025,7 +1052,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
eaddr /= AMDGPU_GPU_PAGE_SIZE;
|
||||
|
||||
spin_lock(&vm->it_lock);
|
||||
it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
|
||||
it = interval_tree_iter_first(&vm->va, saddr, eaddr);
|
||||
spin_unlock(&vm->it_lock);
|
||||
if (it) {
|
||||
struct amdgpu_bo_va_mapping *tmp;
|
||||
|
|
@ -1046,7 +1073,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
|
||||
INIT_LIST_HEAD(&mapping->list);
|
||||
mapping->it.start = saddr;
|
||||
mapping->it.last = eaddr - 1;
|
||||
mapping->it.last = eaddr;
|
||||
mapping->offset = offset;
|
||||
mapping->flags = flags;
|
||||
|
||||
|
|
@ -1070,9 +1097,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
/* walk over the address space and allocate the page tables */
|
||||
for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
|
||||
struct reservation_object *resv = vm->page_directory->tbo.resv;
|
||||
struct amdgpu_bo_list_entry *entry;
|
||||
struct amdgpu_bo *pt;
|
||||
|
||||
if (vm->page_tables[pt_idx].bo)
|
||||
entry = &vm->page_tables[pt_idx].entry;
|
||||
if (entry->robj)
|
||||
continue;
|
||||
|
||||
r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
|
||||
|
|
@ -1094,8 +1123,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
goto error_free;
|
||||
}
|
||||
|
||||
entry->robj = pt;
|
||||
entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
entry->priority = 0;
|
||||
entry->tv.bo = &entry->robj->tbo;
|
||||
entry->tv.shared = true;
|
||||
vm->page_tables[pt_idx].addr = 0;
|
||||
vm->page_tables[pt_idx].bo = pt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1326,7 +1360,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|||
}
|
||||
|
||||
for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
|
||||
amdgpu_bo_unref(&vm->page_tables[i].bo);
|
||||
amdgpu_bo_unref(&vm->page_tables[i].entry.robj);
|
||||
kfree(vm->page_tables);
|
||||
|
||||
amdgpu_bo_unref(&vm->page_directory);
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA
|
|||
|
||||
/* convert bits per color to bits per pixel */
|
||||
/* get bpc from the EDID */
|
||||
static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
|
||||
static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
|
||||
{
|
||||
if (bpc == 0)
|
||||
return 24;
|
||||
|
|
@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
|
|||
return bpc * 3;
|
||||
}
|
||||
|
||||
/* get the max pix clock supported by the link rate and lane num */
|
||||
static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate,
|
||||
int lane_num,
|
||||
int bpp)
|
||||
{
|
||||
return (link_rate * lane_num * 8) / bpp;
|
||||
}
|
||||
|
||||
/***** amdgpu specific DP functions *****/
|
||||
|
||||
/* First get the min lane# when low rate is used according to pixel clock
|
||||
* (prefer low rate), second check max lane# supported by DP panel,
|
||||
* if the max lane# < low rate lane# then use max lane# instead.
|
||||
*/
|
||||
static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector,
|
||||
static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE],
|
||||
int pix_clock)
|
||||
unsigned pix_clock,
|
||||
unsigned *dp_lanes, unsigned *dp_rate)
|
||||
{
|
||||
int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
|
||||
int max_link_rate = drm_dp_max_link_rate(dpcd);
|
||||
int max_lane_num = drm_dp_max_lane_count(dpcd);
|
||||
int lane_num;
|
||||
int max_dp_pix_clock;
|
||||
unsigned bpp =
|
||||
amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
|
||||
static const unsigned link_rates[3] = { 162000, 270000, 540000 };
|
||||
unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
|
||||
unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
|
||||
unsigned lane_num, i, max_pix_clock;
|
||||
|
||||
for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
|
||||
max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
|
||||
if (pix_clock <= max_dp_pix_clock)
|
||||
break;
|
||||
for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
|
||||
for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
|
||||
max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
|
||||
if (max_pix_clock >= pix_clock) {
|
||||
*dp_lanes = lane_num;
|
||||
*dp_rate = link_rates[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lane_num;
|
||||
}
|
||||
|
||||
static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE],
|
||||
int pix_clock)
|
||||
{
|
||||
int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
|
||||
int lane_num, max_pix_clock;
|
||||
|
||||
if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
|
||||
ENCODER_OBJECT_ID_NUTMEG)
|
||||
return 270000;
|
||||
|
||||
lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock);
|
||||
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 162000;
|
||||
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 270000;
|
||||
if (amdgpu_connector_is_dp12_capable(connector)) {
|
||||
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 540000;
|
||||
}
|
||||
|
||||
return drm_dp_max_link_rate(dpcd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
|
||||
|
|
@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
|
|||
{
|
||||
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
|
||||
struct amdgpu_connector_atom_dig *dig_connector;
|
||||
int ret;
|
||||
|
||||
if (!amdgpu_connector->con_priv)
|
||||
return;
|
||||
|
|
@ -429,10 +398,14 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
|
|||
|
||||
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
|
||||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
|
||||
dig_connector->dp_clock =
|
||||
amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
|
||||
dig_connector->dp_lane_count =
|
||||
amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
|
||||
ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
|
||||
mode->clock,
|
||||
&dig_connector->dp_lane_count,
|
||||
&dig_connector->dp_clock);
|
||||
if (ret) {
|
||||
dig_connector->dp_clock = 0;
|
||||
dig_connector->dp_lane_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
|
|||
{
|
||||
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
|
||||
struct amdgpu_connector_atom_dig *dig_connector;
|
||||
int dp_clock;
|
||||
unsigned dp_lanes, dp_clock;
|
||||
int ret;
|
||||
|
||||
if (!amdgpu_connector->con_priv)
|
||||
return MODE_CLOCK_HIGH;
|
||||
dig_connector = amdgpu_connector->con_priv;
|
||||
|
||||
dp_clock =
|
||||
amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
|
||||
ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
|
||||
mode->clock, &dp_lanes, &dp_clock);
|
||||
if (ret)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if ((dp_clock == 540000) &&
|
||||
(!amdgpu_connector_is_dp12_capable(connector)))
|
||||
|
|
|
|||
|
|
@ -1395,7 +1395,6 @@ static void ci_thermal_stop_thermal_controller(struct amdgpu_device *adev)
|
|||
ci_fan_ctrl_set_default_mode(adev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int ci_read_smc_soft_register(struct amdgpu_device *adev,
|
||||
u16 reg_offset, u32 *value)
|
||||
{
|
||||
|
|
@ -1405,7 +1404,6 @@ static int ci_read_smc_soft_register(struct amdgpu_device *adev,
|
|||
pi->soft_regs_start + reg_offset,
|
||||
value, pi->sram_end);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ci_write_smc_soft_register(struct amdgpu_device *adev,
|
||||
u16 reg_offset, u32 value)
|
||||
|
|
@ -6084,11 +6082,23 @@ ci_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
|
|||
struct amdgpu_ps *rps = &pi->current_rps;
|
||||
u32 sclk = ci_get_average_sclk_freq(adev);
|
||||
u32 mclk = ci_get_average_mclk_freq(adev);
|
||||
u32 activity_percent = 50;
|
||||
int ret;
|
||||
|
||||
ret = ci_read_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, AverageGraphicsA),
|
||||
&activity_percent);
|
||||
|
||||
if (ret == 0) {
|
||||
activity_percent += 0x80;
|
||||
activity_percent >>= 8;
|
||||
activity_percent = activity_percent > 100 ? 100 : activity_percent;
|
||||
}
|
||||
|
||||
seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis");
|
||||
seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
|
||||
seq_printf(m, "power level avg sclk: %u mclk: %u\n",
|
||||
sclk, mclk);
|
||||
seq_printf(m, "GPU load: %u %%\n", activity_percent);
|
||||
}
|
||||
|
||||
static void ci_dpm_print_power_state(struct amdgpu_device *adev,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "amdgpu_vce.h"
|
||||
#include "cikd.h"
|
||||
#include "atom.h"
|
||||
#include "amd_pcie.h"
|
||||
|
||||
#include "cik.h"
|
||||
#include "gmc_v7_0.h"
|
||||
|
|
@ -65,6 +66,7 @@
|
|||
#include "oss/oss_2_0_sh_mask.h"
|
||||
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_powerplay.h"
|
||||
|
||||
/*
|
||||
* Indirect registers accessor
|
||||
|
|
@ -929,6 +931,37 @@ static bool cik_read_disabled_bios(struct amdgpu_device *adev)
|
|||
return r;
|
||||
}
|
||||
|
||||
static bool cik_read_bios_from_rom(struct amdgpu_device *adev,
|
||||
u8 *bios, u32 length_bytes)
|
||||
{
|
||||
u32 *dw_ptr;
|
||||
unsigned long flags;
|
||||
u32 i, length_dw;
|
||||
|
||||
if (bios == NULL)
|
||||
return false;
|
||||
if (length_bytes == 0)
|
||||
return false;
|
||||
/* APU vbios image is part of sbios image */
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return false;
|
||||
|
||||
dw_ptr = (u32 *)bios;
|
||||
length_dw = ALIGN(length_bytes, 4) / 4;
|
||||
/* take the smc lock since we are using the smc index */
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
/* set rom index to 0 */
|
||||
WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
|
||||
WREG32(mmSMC_IND_DATA_0, 0);
|
||||
/* set index to data for continous read */
|
||||
WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
|
||||
for (i = 0; i < length_dw; i++)
|
||||
dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
|
||||
{mmGRBM_STATUS, false},
|
||||
{mmGB_ADDR_CONFIG, false},
|
||||
|
|
@ -1563,8 +1596,8 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
{
|
||||
struct pci_dev *root = adev->pdev->bus->self;
|
||||
int bridge_pos, gpu_pos;
|
||||
u32 speed_cntl, mask, current_data_rate;
|
||||
int ret, i;
|
||||
u32 speed_cntl, current_data_rate;
|
||||
int i;
|
||||
u16 tmp16;
|
||||
|
||||
if (pci_is_root_bus(adev->pdev->bus))
|
||||
|
|
@ -1576,23 +1609,20 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
|
||||
if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
|
||||
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
|
||||
return;
|
||||
|
||||
speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
|
||||
current_data_rate = (speed_cntl & PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) >>
|
||||
PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
|
||||
if (mask & DRM_PCIE_SPEED_80) {
|
||||
if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
|
||||
if (current_data_rate == 2) {
|
||||
DRM_INFO("PCIE gen 3 link speeds already enabled\n");
|
||||
return;
|
||||
}
|
||||
DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n");
|
||||
} else if (mask & DRM_PCIE_SPEED_50) {
|
||||
} else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) {
|
||||
if (current_data_rate == 1) {
|
||||
DRM_INFO("PCIE gen 2 link speeds already enabled\n");
|
||||
return;
|
||||
|
|
@ -1608,7 +1638,7 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
if (!gpu_pos)
|
||||
return;
|
||||
|
||||
if (mask & DRM_PCIE_SPEED_80) {
|
||||
if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
|
||||
/* re-try equalization if gen3 is not already enabled */
|
||||
if (current_data_rate != 2) {
|
||||
u16 bridge_cfg, gpu_cfg;
|
||||
|
|
@ -1703,9 +1733,9 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
|
||||
pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
|
||||
tmp16 &= ~0xf;
|
||||
if (mask & DRM_PCIE_SPEED_80)
|
||||
if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
|
||||
tmp16 |= 3; /* gen3 */
|
||||
else if (mask & DRM_PCIE_SPEED_50)
|
||||
else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
|
||||
tmp16 |= 2; /* gen2 */
|
||||
else
|
||||
tmp16 |= 1; /* gen1 */
|
||||
|
|
@ -1922,7 +1952,7 @@ static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &ci_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -1990,7 +2020,7 @@ static const struct amdgpu_ip_block_version hawaii_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &ci_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -2058,7 +2088,7 @@ static const struct amdgpu_ip_block_version kabini_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &kv_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -2126,7 +2156,7 @@ static const struct amdgpu_ip_block_version mullins_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &kv_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -2194,7 +2224,7 @@ static const struct amdgpu_ip_block_version kaveri_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &kv_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -2267,6 +2297,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
|
|||
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,
|
||||
.read_register = &cik_read_register,
|
||||
.reset = &cik_asic_reset,
|
||||
.set_vga_state = &cik_vga_set_state,
|
||||
|
|
@ -2417,6 +2448,8 @@ static int cik_common_early_init(void *handle)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_get_pcie_info(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,11 @@ static void cik_ih_set_rptr(struct amdgpu_device *adev)
|
|||
static int cik_ih_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int ret;
|
||||
|
||||
ret = amdgpu_irq_add_domain(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cik_ih_set_interrupt_funcs(adev);
|
||||
|
||||
|
|
@ -300,6 +305,7 @@ static int cik_ih_sw_fini(void *handle)
|
|||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev);
|
||||
amdgpu_irq_remove_domain(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1078,6 +1078,37 @@ static uint32_t cz_get_eclk_level(struct amdgpu_device *adev,
|
|||
return i;
|
||||
}
|
||||
|
||||
static uint32_t cz_get_uvd_level(struct amdgpu_device *adev,
|
||||
uint32_t clock, uint16_t msg)
|
||||
{
|
||||
int i = 0;
|
||||
struct amdgpu_uvd_clock_voltage_dependency_table *table =
|
||||
&adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
|
||||
|
||||
switch (msg) {
|
||||
case PPSMC_MSG_SetUvdSoftMin:
|
||||
case PPSMC_MSG_SetUvdHardMin:
|
||||
for (i = 0; i < table->count; i++)
|
||||
if (clock <= table->entries[i].vclk)
|
||||
break;
|
||||
if (i == table->count)
|
||||
i = table->count - 1;
|
||||
break;
|
||||
case PPSMC_MSG_SetUvdSoftMax:
|
||||
case PPSMC_MSG_SetUvdHardMax:
|
||||
for (i = table->count - 1; i >= 0; i--)
|
||||
if (clock >= table->entries[i].vclk)
|
||||
break;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int cz_program_bootup_state(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
|
|
@ -1739,6 +1770,200 @@ static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cz_dpm_uvd_force_highest(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
int ret = 0;
|
||||
|
||||
if (pi->uvd_dpm.soft_min_clk != pi->uvd_dpm.soft_max_clk) {
|
||||
pi->uvd_dpm.soft_min_clk =
|
||||
pi->uvd_dpm.soft_max_clk;
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetUvdSoftMin,
|
||||
cz_get_uvd_level(adev,
|
||||
pi->uvd_dpm.soft_min_clk,
|
||||
PPSMC_MSG_SetUvdSoftMin));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cz_dpm_uvd_force_lowest(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
int ret = 0;
|
||||
|
||||
if (pi->uvd_dpm.soft_max_clk != pi->uvd_dpm.soft_min_clk) {
|
||||
pi->uvd_dpm.soft_max_clk = pi->uvd_dpm.soft_min_clk;
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetUvdSoftMax,
|
||||
cz_get_uvd_level(adev,
|
||||
pi->uvd_dpm.soft_max_clk,
|
||||
PPSMC_MSG_SetUvdSoftMax));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t cz_dpm_get_max_uvd_level(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
|
||||
if (!pi->max_uvd_level) {
|
||||
cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
|
||||
pi->max_uvd_level = cz_get_argument(adev) + 1;
|
||||
}
|
||||
|
||||
if (pi->max_uvd_level > CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
DRM_ERROR("Invalid max uvd level!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pi->max_uvd_level;
|
||||
}
|
||||
|
||||
static int cz_dpm_unforce_uvd_dpm_levels(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
struct amdgpu_uvd_clock_voltage_dependency_table *dep_table =
|
||||
&adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
|
||||
uint32_t level = 0;
|
||||
int ret = 0;
|
||||
|
||||
pi->uvd_dpm.soft_min_clk = dep_table->entries[0].vclk;
|
||||
level = cz_dpm_get_max_uvd_level(adev) - 1;
|
||||
if (level < dep_table->count)
|
||||
pi->uvd_dpm.soft_max_clk = dep_table->entries[level].vclk;
|
||||
else
|
||||
pi->uvd_dpm.soft_max_clk =
|
||||
dep_table->entries[dep_table->count - 1].vclk;
|
||||
|
||||
/* get min/max sclk soft value
|
||||
* notify SMU to execute */
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetUvdSoftMin,
|
||||
cz_get_uvd_level(adev,
|
||||
pi->uvd_dpm.soft_min_clk,
|
||||
PPSMC_MSG_SetUvdSoftMin));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetUvdSoftMax,
|
||||
cz_get_uvd_level(adev,
|
||||
pi->uvd_dpm.soft_max_clk,
|
||||
PPSMC_MSG_SetUvdSoftMax));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_DEBUG("DPM uvd unforce state min=%d, max=%d.\n",
|
||||
pi->uvd_dpm.soft_min_clk,
|
||||
pi->uvd_dpm.soft_max_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cz_dpm_vce_force_highest(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
int ret = 0;
|
||||
|
||||
if (pi->vce_dpm.soft_min_clk != pi->vce_dpm.soft_max_clk) {
|
||||
pi->vce_dpm.soft_min_clk =
|
||||
pi->vce_dpm.soft_max_clk;
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetEclkSoftMin,
|
||||
cz_get_eclk_level(adev,
|
||||
pi->vce_dpm.soft_min_clk,
|
||||
PPSMC_MSG_SetEclkSoftMin));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cz_dpm_vce_force_lowest(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
int ret = 0;
|
||||
|
||||
if (pi->vce_dpm.soft_max_clk != pi->vce_dpm.soft_min_clk) {
|
||||
pi->vce_dpm.soft_max_clk = pi->vce_dpm.soft_min_clk;
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetEclkSoftMax,
|
||||
cz_get_uvd_level(adev,
|
||||
pi->vce_dpm.soft_max_clk,
|
||||
PPSMC_MSG_SetEclkSoftMax));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t cz_dpm_get_max_vce_level(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
|
||||
if (!pi->max_vce_level) {
|
||||
cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
|
||||
pi->max_vce_level = cz_get_argument(adev) + 1;
|
||||
}
|
||||
|
||||
if (pi->max_vce_level > CZ_MAX_HARDWARE_POWERLEVELS) {
|
||||
DRM_ERROR("Invalid max vce level!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pi->max_vce_level;
|
||||
}
|
||||
|
||||
static int cz_dpm_unforce_vce_dpm_levels(struct amdgpu_device *adev)
|
||||
{
|
||||
struct cz_power_info *pi = cz_get_pi(adev);
|
||||
struct amdgpu_vce_clock_voltage_dependency_table *dep_table =
|
||||
&adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
|
||||
uint32_t level = 0;
|
||||
int ret = 0;
|
||||
|
||||
pi->vce_dpm.soft_min_clk = dep_table->entries[0].ecclk;
|
||||
level = cz_dpm_get_max_vce_level(adev) - 1;
|
||||
if (level < dep_table->count)
|
||||
pi->vce_dpm.soft_max_clk = dep_table->entries[level].ecclk;
|
||||
else
|
||||
pi->vce_dpm.soft_max_clk =
|
||||
dep_table->entries[dep_table->count - 1].ecclk;
|
||||
|
||||
/* get min/max sclk soft value
|
||||
* notify SMU to execute */
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetEclkSoftMin,
|
||||
cz_get_eclk_level(adev,
|
||||
pi->vce_dpm.soft_min_clk,
|
||||
PPSMC_MSG_SetEclkSoftMin));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cz_send_msg_to_smc_with_parameter(adev,
|
||||
PPSMC_MSG_SetEclkSoftMax,
|
||||
cz_get_eclk_level(adev,
|
||||
pi->vce_dpm.soft_max_clk,
|
||||
PPSMC_MSG_SetEclkSoftMax));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_DEBUG("DPM vce unforce state min=%d, max=%d.\n",
|
||||
pi->vce_dpm.soft_min_clk,
|
||||
pi->vce_dpm.soft_max_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
|
||||
enum amdgpu_dpm_forced_level level)
|
||||
{
|
||||
|
|
@ -1746,23 +1971,68 @@ static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
|
|||
|
||||
switch (level) {
|
||||
case AMDGPU_DPM_FORCED_LEVEL_HIGH:
|
||||
/* sclk */
|
||||
ret = cz_dpm_unforce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_force_highest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* uvd */
|
||||
ret = cz_dpm_unforce_uvd_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_uvd_force_highest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* vce */
|
||||
ret = cz_dpm_unforce_vce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_vce_force_highest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case AMDGPU_DPM_FORCED_LEVEL_LOW:
|
||||
/* sclk */
|
||||
ret = cz_dpm_unforce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_force_lowest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* uvd */
|
||||
ret = cz_dpm_unforce_uvd_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_uvd_force_lowest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* vce */
|
||||
ret = cz_dpm_unforce_vce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cz_dpm_vce_force_lowest(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case AMDGPU_DPM_FORCED_LEVEL_AUTO:
|
||||
/* sclk */
|
||||
ret = cz_dpm_unforce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* uvd */
|
||||
ret = cz_dpm_unforce_uvd_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* vce */
|
||||
ret = cz_dpm_unforce_vce_dpm_levels(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
|
@ -1905,7 +2175,8 @@ static int cz_update_vce_dpm(struct amdgpu_device *adev)
|
|||
pi->vce_dpm.hard_min_clk = table->entries[table->count-1].ecclk;
|
||||
|
||||
} else { /* non-stable p-state cases. without vce.Arbiter.EcclkHardMin */
|
||||
pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;
|
||||
/* leave it as set by user */
|
||||
/*pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;*/
|
||||
}
|
||||
|
||||
cz_send_msg_to_smc_with_parameter(adev,
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ struct cz_power_info {
|
|||
uint32_t voltage_drop_threshold;
|
||||
uint32_t gfx_pg_threshold;
|
||||
uint32_t max_sclk_level;
|
||||
uint32_t max_uvd_level;
|
||||
uint32_t max_vce_level;
|
||||
/* flags */
|
||||
bool didt_enabled;
|
||||
bool video_start;
|
||||
|
|
|
|||
|
|
@ -253,8 +253,14 @@ static void cz_ih_set_rptr(struct amdgpu_device *adev)
|
|||
static int cz_ih_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int ret;
|
||||
|
||||
ret = amdgpu_irq_add_domain(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cz_ih_set_interrupt_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +284,7 @@ static int cz_ih_sw_fini(void *handle)
|
|||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev);
|
||||
amdgpu_irq_remove_domain(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3729,7 +3729,7 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
|
|||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v10_0_dac_helper_funcs);
|
||||
break;
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
|
||||
|
|
@ -3740,15 +3740,15 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
|
|||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
amdgpu_encoder->rmx_type = RMX_FULL;
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
|
||||
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
} else {
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
}
|
||||
drm_encoder_helper_add(encoder, &dce_v10_0_dig_helper_funcs);
|
||||
|
|
@ -3766,13 +3766,13 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
|
|||
amdgpu_encoder->is_ext_encoder = true;
|
||||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
else
|
||||
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v10_0_ext_helper_funcs);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,9 +211,9 @@ static bool dce_v11_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
|
|||
*/
|
||||
static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
||||
{
|
||||
unsigned i = 0;
|
||||
unsigned i = 100;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc)
|
||||
if (crtc < 0 || crtc >= adev->mode_info.num_crtc)
|
||||
return;
|
||||
|
||||
if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK))
|
||||
|
|
@ -223,14 +223,16 @@ static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
|||
* wait for another frame.
|
||||
*/
|
||||
while (dce_v11_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v11_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!dce_v11_0_is_in_vblank(adev, crtc)) {
|
||||
if (i++ % 100 == 0) {
|
||||
if (i++ == 100) {
|
||||
i = 0;
|
||||
if (!dce_v11_0_is_counter_moving(adev, crtc))
|
||||
break;
|
||||
}
|
||||
|
|
@ -239,7 +241,7 @@ static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
|
|||
|
||||
static u32 dce_v11_0_vblank_get_counter(struct amdgpu_device *adev, int crtc)
|
||||
{
|
||||
if (crtc >= adev->mode_info.num_crtc)
|
||||
if (crtc < 0 || crtc >= adev->mode_info.num_crtc)
|
||||
return 0;
|
||||
else
|
||||
return RREG32(mmCRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
|
||||
|
|
@ -3384,7 +3386,7 @@ static void dce_v11_0_crtc_vblank_int_ack(struct amdgpu_device *adev,
|
|||
{
|
||||
u32 tmp;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc) {
|
||||
if (crtc < 0 || crtc >= adev->mode_info.num_crtc) {
|
||||
DRM_DEBUG("invalid crtc %d\n", crtc);
|
||||
return;
|
||||
}
|
||||
|
|
@ -3399,7 +3401,7 @@ static void dce_v11_0_crtc_vline_int_ack(struct amdgpu_device *adev,
|
|||
{
|
||||
u32 tmp;
|
||||
|
||||
if (crtc >= adev->mode_info.num_crtc) {
|
||||
if (crtc < 0 || crtc >= adev->mode_info.num_crtc) {
|
||||
DRM_DEBUG("invalid crtc %d\n", crtc);
|
||||
return;
|
||||
}
|
||||
|
|
@ -3722,7 +3724,7 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
|
|||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v11_0_dac_helper_funcs);
|
||||
break;
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
|
||||
|
|
@ -3733,15 +3735,15 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
|
|||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
amdgpu_encoder->rmx_type = RMX_FULL;
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
|
||||
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
} else {
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
}
|
||||
drm_encoder_helper_add(encoder, &dce_v11_0_dig_helper_funcs);
|
||||
|
|
@ -3759,13 +3761,13 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
|
|||
amdgpu_encoder->is_ext_encoder = true;
|
||||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
else
|
||||
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v11_0_ext_helper_funcs);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3659,7 +3659,7 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
|
|||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v8_0_dac_helper_funcs);
|
||||
break;
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
|
||||
|
|
@ -3670,15 +3670,15 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
|
|||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
amdgpu_encoder->rmx_type = RMX_FULL;
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
|
||||
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
} else {
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
|
||||
}
|
||||
drm_encoder_helper_add(encoder, &dce_v8_0_dig_helper_funcs);
|
||||
|
|
@ -3696,13 +3696,13 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
|
|||
amdgpu_encoder->is_ext_encoder = true;
|
||||
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
DRM_MODE_ENCODER_LVDS, NULL);
|
||||
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
else
|
||||
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
drm_encoder_helper_add(encoder, &dce_v8_0_ext_helper_funcs);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_smumgr.h"
|
||||
#include "fiji_smum.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,182 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FIJI_PP_SMC_H
|
||||
#define FIJI_PP_SMC_H
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
//Gemini Modes
|
||||
#define PPSMC_GeminiModeNone 0 //Single GPU board
|
||||
#define PPSMC_GeminiModeMaster 1 //Master GPU on a Gemini board
|
||||
#define PPSMC_GeminiModeSlave 2 //Slave GPU on a Gemini board
|
||||
|
||||
#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 PPSMC_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
|
||||
#define PPSMC_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
|
||||
#define PPSMC_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
|
||||
|
||||
#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
|
||||
|
||||
#define PPSMC_MSG_Test ((uint16_t)0x100)
|
||||
#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)
|
||||
|
||||
typedef uint16_t PPSMC_Msg;
|
||||
|
||||
#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
|
||||
#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
|
||||
#define PPSMC_EVENT_STATUS_DC 0x00000004
|
||||
#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "fiji_smumgr.h"
|
||||
#include "fiji_smum.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -370,6 +370,10 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
|
|||
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
|
||||
adev->mc.visible_vram_size = adev->mc.aper_size;
|
||||
|
||||
/* In case the PCI BAR is larger than the actual amount of vram */
|
||||
if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
|
||||
adev->mc.visible_vram_size = adev->mc.real_vram_size;
|
||||
|
||||
/* unless the user had overridden it, set the gart
|
||||
* size equal to the 1024 or vram, whichever is larger.
|
||||
*/
|
||||
|
|
@ -1012,7 +1016,6 @@ static int gmc_v7_0_suspend(void *handle)
|
|||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
amdgpu_vm_manager_fini(adev);
|
||||
gmc_v7_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,6 +476,10 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
|
|||
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
|
||||
adev->mc.visible_vram_size = adev->mc.aper_size;
|
||||
|
||||
/* In case the PCI BAR is larger than the actual amount of vram */
|
||||
if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
|
||||
adev->mc.visible_vram_size = adev->mc.real_vram_size;
|
||||
|
||||
/* unless the user had overridden it, set the gart
|
||||
* size equal to the 1024 or vram, whichever is larger.
|
||||
*/
|
||||
|
|
@ -1033,7 +1037,6 @@ static int gmc_v8_0_suspend(void *handle)
|
|||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
amdgpu_vm_manager_fini(adev);
|
||||
gmc_v8_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
|
|
@ -1324,9 +1327,181 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fiji_update_mc_medium_grain_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (enable) {
|
||||
data = RREG32(mmMC_HUB_MISC_HUB_CG);
|
||||
data |= MC_HUB_MISC_HUB_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_HUB_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_SIP_CG);
|
||||
data |= MC_HUB_MISC_SIP_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_SIP_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_VM_CG);
|
||||
data |= MC_HUB_MISC_VM_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmMC_XPB_CLK_GAT);
|
||||
data |= MC_XPB_CLK_GAT__ENABLE_MASK;
|
||||
WREG32(mmMC_XPB_CLK_GAT, data);
|
||||
|
||||
data = RREG32(mmATC_MISC_CG);
|
||||
data |= ATC_MISC_CG__ENABLE_MASK;
|
||||
WREG32(mmATC_MISC_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_WR_CG);
|
||||
data |= MC_CITF_MISC_WR_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_WR_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_RD_CG);
|
||||
data |= MC_CITF_MISC_RD_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_RD_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_VM_CG);
|
||||
data |= MC_CITF_MISC_VM_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmVM_L2_CG);
|
||||
data |= VM_L2_CG__ENABLE_MASK;
|
||||
WREG32(mmVM_L2_CG, data);
|
||||
} else {
|
||||
data = RREG32(mmMC_HUB_MISC_HUB_CG);
|
||||
data &= ~MC_HUB_MISC_HUB_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_HUB_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_SIP_CG);
|
||||
data &= ~MC_HUB_MISC_SIP_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_SIP_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_VM_CG);
|
||||
data &= ~MC_HUB_MISC_VM_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmMC_XPB_CLK_GAT);
|
||||
data &= ~MC_XPB_CLK_GAT__ENABLE_MASK;
|
||||
WREG32(mmMC_XPB_CLK_GAT, data);
|
||||
|
||||
data = RREG32(mmATC_MISC_CG);
|
||||
data &= ~ATC_MISC_CG__ENABLE_MASK;
|
||||
WREG32(mmATC_MISC_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_WR_CG);
|
||||
data &= ~MC_CITF_MISC_WR_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_WR_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_RD_CG);
|
||||
data &= ~MC_CITF_MISC_RD_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_RD_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_VM_CG);
|
||||
data &= ~MC_CITF_MISC_VM_CG__ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmVM_L2_CG);
|
||||
data &= ~VM_L2_CG__ENABLE_MASK;
|
||||
WREG32(mmVM_L2_CG, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void fiji_update_mc_light_sleep(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (enable) {
|
||||
data = RREG32(mmMC_HUB_MISC_HUB_CG);
|
||||
data |= MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_HUB_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_SIP_CG);
|
||||
data |= MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_SIP_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_VM_CG);
|
||||
data |= MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmMC_XPB_CLK_GAT);
|
||||
data |= MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_XPB_CLK_GAT, data);
|
||||
|
||||
data = RREG32(mmATC_MISC_CG);
|
||||
data |= ATC_MISC_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmATC_MISC_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_WR_CG);
|
||||
data |= MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_WR_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_RD_CG);
|
||||
data |= MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_RD_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_VM_CG);
|
||||
data |= MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmVM_L2_CG);
|
||||
data |= VM_L2_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmVM_L2_CG, data);
|
||||
} else {
|
||||
data = RREG32(mmMC_HUB_MISC_HUB_CG);
|
||||
data &= ~MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_HUB_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_SIP_CG);
|
||||
data &= ~MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_SIP_CG, data);
|
||||
|
||||
data = RREG32(mmMC_HUB_MISC_VM_CG);
|
||||
data &= ~MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_HUB_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmMC_XPB_CLK_GAT);
|
||||
data &= ~MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_XPB_CLK_GAT, data);
|
||||
|
||||
data = RREG32(mmATC_MISC_CG);
|
||||
data &= ~ATC_MISC_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmATC_MISC_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_WR_CG);
|
||||
data &= ~MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_WR_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_RD_CG);
|
||||
data &= ~MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_RD_CG, data);
|
||||
|
||||
data = RREG32(mmMC_CITF_MISC_VM_CG);
|
||||
data &= ~MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmMC_CITF_MISC_VM_CG, data);
|
||||
|
||||
data = RREG32(mmVM_L2_CG);
|
||||
data &= ~VM_L2_CG__MEM_LS_ENABLE_MASK;
|
||||
WREG32(mmVM_L2_CG, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int gmc_v8_0_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
fiji_update_mc_medium_grain_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
fiji_update_mc_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -253,8 +253,14 @@ static void iceland_ih_set_rptr(struct amdgpu_device *adev)
|
|||
static int iceland_ih_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int ret;
|
||||
|
||||
ret = amdgpu_irq_add_domain(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iceland_ih_set_interrupt_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +284,7 @@ static int iceland_ih_sw_fini(void *handle)
|
|||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev);
|
||||
amdgpu_irq_remove_domain(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -727,18 +727,20 @@ static int sdma_v3_0_start(struct amdgpu_device *adev)
|
|||
{
|
||||
int r, i;
|
||||
|
||||
if (!adev->firmware.smu_load) {
|
||||
r = sdma_v3_0_load_microcode(adev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
|
||||
(i == 0) ?
|
||||
AMDGPU_UCODE_ID_SDMA0 :
|
||||
AMDGPU_UCODE_ID_SDMA1);
|
||||
if (!adev->pp_enabled) {
|
||||
if (!adev->firmware.smu_load) {
|
||||
r = sdma_v3_0_load_microcode(adev);
|
||||
if (r)
|
||||
return -EINVAL;
|
||||
return r;
|
||||
} else {
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
|
||||
(i == 0) ?
|
||||
AMDGPU_UCODE_ID_SDMA0 :
|
||||
AMDGPU_UCODE_ID_SDMA1);
|
||||
if (r)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1427,9 +1429,114 @@ static int sdma_v3_0_process_illegal_inst_irq(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fiji_update_sdma_medium_grain_clock_gating(
|
||||
struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
if (enable) {
|
||||
temp = data = RREG32(mmSDMA0_CLK_CTRL);
|
||||
data &= ~(SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK);
|
||||
if (data != temp)
|
||||
WREG32(mmSDMA0_CLK_CTRL, data);
|
||||
|
||||
temp = data = RREG32(mmSDMA1_CLK_CTRL);
|
||||
data &= ~(SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK);
|
||||
|
||||
if (data != temp)
|
||||
WREG32(mmSDMA1_CLK_CTRL, data);
|
||||
} else {
|
||||
temp = data = RREG32(mmSDMA0_CLK_CTRL);
|
||||
data |= SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
|
||||
SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK;
|
||||
|
||||
if (data != temp)
|
||||
WREG32(mmSDMA0_CLK_CTRL, data);
|
||||
|
||||
temp = data = RREG32(mmSDMA1_CLK_CTRL);
|
||||
data |= SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
|
||||
SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK;
|
||||
|
||||
if (data != temp)
|
||||
WREG32(mmSDMA1_CLK_CTRL, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void fiji_update_sdma_medium_grain_light_sleep(
|
||||
struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
if (enable) {
|
||||
temp = data = RREG32(mmSDMA0_POWER_CNTL);
|
||||
data |= SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmSDMA0_POWER_CNTL, data);
|
||||
|
||||
temp = data = RREG32(mmSDMA1_POWER_CNTL);
|
||||
data |= SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmSDMA1_POWER_CNTL, data);
|
||||
} else {
|
||||
temp = data = RREG32(mmSDMA0_POWER_CNTL);
|
||||
data &= ~SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmSDMA0_POWER_CNTL, data);
|
||||
|
||||
temp = data = RREG32(mmSDMA1_POWER_CNTL);
|
||||
data &= ~SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmSDMA1_POWER_CNTL, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int sdma_v3_0_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
fiji_update_sdma_medium_grain_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
fiji_update_sdma_medium_grain_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "tonga_smumgr.h"
|
||||
#include "tonga_smum.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
|
||||
|
||||
|
|
|
|||
|
|
@ -273,8 +273,14 @@ static void tonga_ih_set_rptr(struct amdgpu_device *adev)
|
|||
static int tonga_ih_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
int ret;
|
||||
|
||||
ret = amdgpu_irq_add_domain(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tonga_ih_set_interrupt_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -301,6 +307,7 @@ static int tonga_ih_sw_fini(void *handle)
|
|||
|
||||
amdgpu_irq_fini(adev);
|
||||
amdgpu_ih_ring_fini(adev);
|
||||
amdgpu_irq_add_domain(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,198 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONGA_PP_SMC_H
|
||||
#define TONGA_PP_SMC_H
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define PPSMC_SWSTATE_FLAG_DC 0x01
|
||||
#define PPSMC_SWSTATE_FLAG_UVD 0x02
|
||||
#define PPSMC_SWSTATE_FLAG_VCE 0x04
|
||||
#define PPSMC_SWSTATE_FLAG_PCIE_X1 0x08
|
||||
|
||||
#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_SYSTEMFLAG_12CHANNEL 0x40
|
||||
|
||||
#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_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH 0x10
|
||||
#define PPSMC_EXTRAFLAGS_DRIVER_TO_GPIO17 0x20
|
||||
#define PPSMC_EXTRAFLAGS_PCC_TO_GPIO17 0x40
|
||||
|
||||
#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 PPSMC_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
|
||||
#define PPSMC_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
|
||||
#define PPSMC_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
|
||||
#define PPSMC_MSG_ChangeNearTDPLimit ((uint16_t)0x90)
|
||||
#define PPSMC_MSG_ChangeSafePowerLimit ((uint16_t)0x91)
|
||||
#define PPSMC_MSG_DPMStateSweepStart ((uint16_t)0x92)
|
||||
#define PPSMC_MSG_DPMStateSweepStop ((uint16_t)0x93)
|
||||
#define PPSMC_MSG_OVRDDisableSCLKDS ((uint16_t)0x94)
|
||||
#define PPSMC_MSG_CancelDisableOVRDSCLKDS ((uint16_t)0x95)
|
||||
#define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint16_t)0x96)
|
||||
#define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint16_t)0x97)
|
||||
#define PPSMC_MSG_GPIO17 ((uint16_t)0x98)
|
||||
#define PPSMC_MSG_API_SetSvi2Volt_Vddc ((uint16_t)0x99)
|
||||
#define PPSMC_MSG_API_SetSvi2Volt_Vddci ((uint16_t)0x9A)
|
||||
#define PPSMC_MSG_API_SetSvi2Volt_Mvdd ((uint16_t)0x9B)
|
||||
#define PPSMC_MSG_API_GetSvi2Volt_Vddc ((uint16_t)0x9C)
|
||||
#define PPSMC_MSG_API_GetSvi2Volt_Vddci ((uint16_t)0x9D)
|
||||
#define PPSMC_MSG_API_GetSvi2Volt_Mvdd ((uint16_t)0x9E)
|
||||
|
||||
#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
|
||||
|
||||
#define PPSMC_MSG_Test ((uint16_t)0x100)
|
||||
#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)
|
||||
|
||||
typedef uint16_t PPSMC_Msg;
|
||||
|
||||
#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
|
||||
#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
|
||||
#define PPSMC_EVENT_STATUS_DC 0x00000004
|
||||
#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "tonga_ppsmc.h"
|
||||
#include "tonga_smumgr.h"
|
||||
#include "tonga_smum.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -279,6 +279,234 @@ static void uvd_v6_0_mc_resume(struct amdgpu_device *adev)
|
|||
WREG32(mmUVD_VCPU_CACHE_SIZE2, size);
|
||||
}
|
||||
|
||||
static void cz_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
u32 data, data1;
|
||||
|
||||
data = RREG32(mmUVD_CGC_GATE);
|
||||
data1 = RREG32(mmUVD_SUVD_CGC_GATE);
|
||||
if (enable) {
|
||||
data |= UVD_CGC_GATE__SYS_MASK |
|
||||
UVD_CGC_GATE__UDEC_MASK |
|
||||
UVD_CGC_GATE__MPEG2_MASK |
|
||||
UVD_CGC_GATE__RBC_MASK |
|
||||
UVD_CGC_GATE__LMI_MC_MASK |
|
||||
UVD_CGC_GATE__IDCT_MASK |
|
||||
UVD_CGC_GATE__MPRD_MASK |
|
||||
UVD_CGC_GATE__MPC_MASK |
|
||||
UVD_CGC_GATE__LBSI_MASK |
|
||||
UVD_CGC_GATE__LRBBM_MASK |
|
||||
UVD_CGC_GATE__UDEC_RE_MASK |
|
||||
UVD_CGC_GATE__UDEC_CM_MASK |
|
||||
UVD_CGC_GATE__UDEC_IT_MASK |
|
||||
UVD_CGC_GATE__UDEC_DB_MASK |
|
||||
UVD_CGC_GATE__UDEC_MP_MASK |
|
||||
UVD_CGC_GATE__WCB_MASK |
|
||||
UVD_CGC_GATE__VCPU_MASK |
|
||||
UVD_CGC_GATE__SCPU_MASK;
|
||||
data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_MASK |
|
||||
UVD_SUVD_CGC_GATE__SMP_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_MASK |
|
||||
UVD_SUVD_CGC_GATE__SRE_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_HEVC_MASK;
|
||||
} else {
|
||||
data &= ~(UVD_CGC_GATE__SYS_MASK |
|
||||
UVD_CGC_GATE__UDEC_MASK |
|
||||
UVD_CGC_GATE__MPEG2_MASK |
|
||||
UVD_CGC_GATE__RBC_MASK |
|
||||
UVD_CGC_GATE__LMI_MC_MASK |
|
||||
UVD_CGC_GATE__LMI_UMC_MASK |
|
||||
UVD_CGC_GATE__IDCT_MASK |
|
||||
UVD_CGC_GATE__MPRD_MASK |
|
||||
UVD_CGC_GATE__MPC_MASK |
|
||||
UVD_CGC_GATE__LBSI_MASK |
|
||||
UVD_CGC_GATE__LRBBM_MASK |
|
||||
UVD_CGC_GATE__UDEC_RE_MASK |
|
||||
UVD_CGC_GATE__UDEC_CM_MASK |
|
||||
UVD_CGC_GATE__UDEC_IT_MASK |
|
||||
UVD_CGC_GATE__UDEC_DB_MASK |
|
||||
UVD_CGC_GATE__UDEC_MP_MASK |
|
||||
UVD_CGC_GATE__WCB_MASK |
|
||||
UVD_CGC_GATE__VCPU_MASK |
|
||||
UVD_CGC_GATE__SCPU_MASK);
|
||||
data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_MASK |
|
||||
UVD_SUVD_CGC_GATE__SMP_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_MASK |
|
||||
UVD_SUVD_CGC_GATE__SRE_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_H264_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_HEVC_MASK);
|
||||
}
|
||||
WREG32(mmUVD_CGC_GATE, data);
|
||||
WREG32(mmUVD_SUVD_CGC_GATE, data1);
|
||||
}
|
||||
|
||||
static void tonga_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
u32 data, data1;
|
||||
|
||||
data = RREG32(mmUVD_CGC_GATE);
|
||||
data1 = RREG32(mmUVD_SUVD_CGC_GATE);
|
||||
if (enable) {
|
||||
data |= UVD_CGC_GATE__SYS_MASK |
|
||||
UVD_CGC_GATE__UDEC_MASK |
|
||||
UVD_CGC_GATE__MPEG2_MASK |
|
||||
UVD_CGC_GATE__RBC_MASK |
|
||||
UVD_CGC_GATE__LMI_MC_MASK |
|
||||
UVD_CGC_GATE__IDCT_MASK |
|
||||
UVD_CGC_GATE__MPRD_MASK |
|
||||
UVD_CGC_GATE__MPC_MASK |
|
||||
UVD_CGC_GATE__LBSI_MASK |
|
||||
UVD_CGC_GATE__LRBBM_MASK |
|
||||
UVD_CGC_GATE__UDEC_RE_MASK |
|
||||
UVD_CGC_GATE__UDEC_CM_MASK |
|
||||
UVD_CGC_GATE__UDEC_IT_MASK |
|
||||
UVD_CGC_GATE__UDEC_DB_MASK |
|
||||
UVD_CGC_GATE__UDEC_MP_MASK |
|
||||
UVD_CGC_GATE__WCB_MASK |
|
||||
UVD_CGC_GATE__VCPU_MASK |
|
||||
UVD_CGC_GATE__SCPU_MASK;
|
||||
data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_MASK |
|
||||
UVD_SUVD_CGC_GATE__SMP_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_MASK;
|
||||
} else {
|
||||
data &= ~(UVD_CGC_GATE__SYS_MASK |
|
||||
UVD_CGC_GATE__UDEC_MASK |
|
||||
UVD_CGC_GATE__MPEG2_MASK |
|
||||
UVD_CGC_GATE__RBC_MASK |
|
||||
UVD_CGC_GATE__LMI_MC_MASK |
|
||||
UVD_CGC_GATE__LMI_UMC_MASK |
|
||||
UVD_CGC_GATE__IDCT_MASK |
|
||||
UVD_CGC_GATE__MPRD_MASK |
|
||||
UVD_CGC_GATE__MPC_MASK |
|
||||
UVD_CGC_GATE__LBSI_MASK |
|
||||
UVD_CGC_GATE__LRBBM_MASK |
|
||||
UVD_CGC_GATE__UDEC_RE_MASK |
|
||||
UVD_CGC_GATE__UDEC_CM_MASK |
|
||||
UVD_CGC_GATE__UDEC_IT_MASK |
|
||||
UVD_CGC_GATE__UDEC_DB_MASK |
|
||||
UVD_CGC_GATE__UDEC_MP_MASK |
|
||||
UVD_CGC_GATE__WCB_MASK |
|
||||
UVD_CGC_GATE__VCPU_MASK |
|
||||
UVD_CGC_GATE__SCPU_MASK);
|
||||
data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
|
||||
UVD_SUVD_CGC_GATE__SIT_MASK |
|
||||
UVD_SUVD_CGC_GATE__SMP_MASK |
|
||||
UVD_SUVD_CGC_GATE__SCM_MASK |
|
||||
UVD_SUVD_CGC_GATE__SDB_MASK);
|
||||
}
|
||||
WREG32(mmUVD_CGC_GATE, data);
|
||||
WREG32(mmUVD_SUVD_CGC_GATE, data1);
|
||||
}
|
||||
|
||||
static void uvd_v6_0_set_uvd_dynamic_clock_mode(struct amdgpu_device *adev,
|
||||
bool swmode)
|
||||
{
|
||||
u32 data, data1 = 0, data2;
|
||||
|
||||
/* Always un-gate UVD REGS bit */
|
||||
data = RREG32(mmUVD_CGC_GATE);
|
||||
data &= ~(UVD_CGC_GATE__REGS_MASK);
|
||||
WREG32(mmUVD_CGC_GATE, data);
|
||||
|
||||
data = RREG32(mmUVD_CGC_CTRL);
|
||||
data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
|
||||
UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
|
||||
data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
|
||||
1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER) |
|
||||
4 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_OFF_DELAY);
|
||||
|
||||
data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
|
||||
if (swmode) {
|
||||
data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
|
||||
UVD_CGC_CTRL__SYS_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPEG2_MODE_MASK |
|
||||
UVD_CGC_CTRL__REGS_MODE_MASK |
|
||||
UVD_CGC_CTRL__RBC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LMI_MC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
|
||||
UVD_CGC_CTRL__IDCT_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPRD_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LBSI_MODE_MASK |
|
||||
UVD_CGC_CTRL__LRBBM_MODE_MASK |
|
||||
UVD_CGC_CTRL__WCB_MODE_MASK |
|
||||
UVD_CGC_CTRL__VCPU_MODE_MASK |
|
||||
UVD_CGC_CTRL__JPEG_MODE_MASK |
|
||||
UVD_CGC_CTRL__SCPU_MODE_MASK);
|
||||
data1 |= UVD_CGC_CTRL2__DYN_OCLK_RAMP_EN_MASK |
|
||||
UVD_CGC_CTRL2__DYN_RCLK_RAMP_EN_MASK;
|
||||
data1 &= ~UVD_CGC_CTRL2__GATER_DIV_ID_MASK;
|
||||
data1 |= 7 << REG_FIELD_SHIFT(UVD_CGC_CTRL2, GATER_DIV_ID);
|
||||
data2 &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
|
||||
} else {
|
||||
data |= UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
|
||||
UVD_CGC_CTRL__SYS_MODE_MASK |
|
||||
UVD_CGC_CTRL__UDEC_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPEG2_MODE_MASK |
|
||||
UVD_CGC_CTRL__REGS_MODE_MASK |
|
||||
UVD_CGC_CTRL__RBC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LMI_MC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
|
||||
UVD_CGC_CTRL__IDCT_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPRD_MODE_MASK |
|
||||
UVD_CGC_CTRL__MPC_MODE_MASK |
|
||||
UVD_CGC_CTRL__LBSI_MODE_MASK |
|
||||
UVD_CGC_CTRL__LRBBM_MODE_MASK |
|
||||
UVD_CGC_CTRL__WCB_MODE_MASK |
|
||||
UVD_CGC_CTRL__VCPU_MODE_MASK |
|
||||
UVD_CGC_CTRL__SCPU_MODE_MASK;
|
||||
data2 |= UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
|
||||
UVD_SUVD_CGC_CTRL__SDB_MODE_MASK;
|
||||
}
|
||||
WREG32(mmUVD_CGC_CTRL, data);
|
||||
WREG32(mmUVD_SUVD_CGC_CTRL, data2);
|
||||
|
||||
data = RREG32_UVD_CTX(ixUVD_CGC_CTRL2);
|
||||
data &= ~(REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
|
||||
REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
|
||||
REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
|
||||
data1 &= (REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
|
||||
REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
|
||||
REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
|
||||
data |= data1;
|
||||
WREG32_UVD_CTX(ixUVD_CGC_CTRL2, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* uvd_v6_0_start - start UVD block
|
||||
*
|
||||
|
|
@ -303,8 +531,19 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
|
|||
|
||||
uvd_v6_0_mc_resume(adev);
|
||||
|
||||
/* disable clock gating */
|
||||
WREG32(mmUVD_CGC_GATE, 0);
|
||||
/* Set dynamic clock gating in S/W control mode */
|
||||
if (adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG) {
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
cz_set_uvd_clock_gating_branches(adev, false);
|
||||
else
|
||||
tonga_set_uvd_clock_gating_branches(adev, false);
|
||||
uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
|
||||
} else {
|
||||
/* disable clock gating */
|
||||
uint32_t data = RREG32(mmUVD_CGC_CTRL);
|
||||
data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
|
||||
WREG32(mmUVD_CGC_CTRL, data);
|
||||
}
|
||||
|
||||
/* disable interupt */
|
||||
WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1));
|
||||
|
|
@ -758,6 +997,24 @@ static int uvd_v6_0_process_interrupt(struct amdgpu_device *adev,
|
|||
static int uvd_v6_0_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
|
||||
|
||||
if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG))
|
||||
return 0;
|
||||
|
||||
if (enable) {
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
cz_set_uvd_clock_gating_branches(adev, enable);
|
||||
else
|
||||
tonga_set_uvd_clock_gating_branches(adev, enable);
|
||||
uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
|
||||
} else {
|
||||
uint32_t data = RREG32(mmUVD_CGC_CTRL);
|
||||
data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
|
||||
WREG32(mmUVD_CGC_CTRL, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,108 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
|
|||
WREG32(mmVCE_RB_WPTR2, ring->wptr);
|
||||
}
|
||||
|
||||
static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
|
||||
{
|
||||
u32 tmp, data;
|
||||
|
||||
tmp = data = RREG32(mmVCE_RB_ARB_CTRL);
|
||||
if (override)
|
||||
data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
|
||||
else
|
||||
data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
|
||||
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_RB_ARB_CTRL, data);
|
||||
}
|
||||
|
||||
static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
|
||||
bool gated)
|
||||
{
|
||||
u32 tmp, data;
|
||||
/* Set Override to disable Clock Gating */
|
||||
vce_v3_0_override_vce_clock_gating(adev, true);
|
||||
|
||||
if (!gated) {
|
||||
/* Force CLOCK ON for VCE_CLOCK_GATING_B,
|
||||
* {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
|
||||
* VREG can be FORCE ON or set to Dynamic, but can't be OFF
|
||||
*/
|
||||
tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
|
||||
data |= 0x1ff;
|
||||
data &= ~0xef0000;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_CLOCK_GATING_B, data);
|
||||
|
||||
/* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
|
||||
* {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
|
||||
*/
|
||||
tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
|
||||
data |= 0x3ff000;
|
||||
data &= ~0xffc00000;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_CLOCK_GATING, data);
|
||||
|
||||
/* set VCE_UENC_CLOCK_GATING_2 */
|
||||
tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
|
||||
data |= 0x2;
|
||||
data &= ~0x2;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
|
||||
|
||||
/* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
|
||||
tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
|
||||
data |= 0x37f;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
|
||||
|
||||
/* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
|
||||
tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
|
||||
data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
|
||||
VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
|
||||
VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
|
||||
0x8;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
|
||||
} else {
|
||||
/* Force CLOCK OFF for VCE_CLOCK_GATING_B,
|
||||
* {*, *_FORCE_OFF} = {*, 1}
|
||||
* set VREG to Dynamic, as it can't be OFF
|
||||
*/
|
||||
tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
|
||||
data &= ~0x80010;
|
||||
data |= 0xe70008;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_CLOCK_GATING_B, data);
|
||||
/* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
|
||||
* Force ClOCK OFF takes precedent over Force CLOCK ON setting.
|
||||
* {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
|
||||
*/
|
||||
tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
|
||||
data |= 0xffc00000;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_CLOCK_GATING, data);
|
||||
/* Set VCE_UENC_CLOCK_GATING_2 */
|
||||
tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
|
||||
data |= 0x10000;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
|
||||
/* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
|
||||
tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
|
||||
data &= ~0xffc00000;
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
|
||||
/* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
|
||||
tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
|
||||
data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
|
||||
VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
|
||||
VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
|
||||
0x8);
|
||||
if (tmp != data)
|
||||
WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
|
||||
}
|
||||
vce_v3_0_override_vce_clock_gating(adev, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* vce_v3_0_start - start VCE block
|
||||
*
|
||||
|
|
@ -121,7 +223,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
|
|||
if (adev->vce.harvest_config & (1 << idx))
|
||||
continue;
|
||||
|
||||
if(idx == 0)
|
||||
if (idx == 0)
|
||||
WREG32_P(mmGRBM_GFX_INDEX, 0,
|
||||
~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
|
||||
else
|
||||
|
|
@ -174,6 +276,10 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
|
|||
/* clear BUSY flag */
|
||||
WREG32_P(mmVCE_STATUS, 0, ~1);
|
||||
|
||||
/* Set Clock-Gating off */
|
||||
if (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)
|
||||
vce_v3_0_set_vce_sw_clock_gating(adev, false);
|
||||
|
||||
if (r) {
|
||||
DRM_ERROR("VCE not responding, giving up!!!\n");
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
@ -208,14 +314,11 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
|
|||
static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 tmp;
|
||||
unsigned ret;
|
||||
|
||||
/* Fiji, Stoney are single pipe */
|
||||
if ((adev->asic_type == CHIP_FIJI) ||
|
||||
(adev->asic_type == CHIP_STONEY)){
|
||||
ret = AMDGPU_VCE_HARVEST_VCE1;
|
||||
return ret;
|
||||
}
|
||||
(adev->asic_type == CHIP_STONEY))
|
||||
return AMDGPU_VCE_HARVEST_VCE1;
|
||||
|
||||
/* Tonga and CZ are dual or single pipe */
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
|
|
@ -229,19 +332,14 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
|
|||
|
||||
switch (tmp) {
|
||||
case 1:
|
||||
ret = AMDGPU_VCE_HARVEST_VCE0;
|
||||
break;
|
||||
return AMDGPU_VCE_HARVEST_VCE0;
|
||||
case 2:
|
||||
ret = AMDGPU_VCE_HARVEST_VCE1;
|
||||
break;
|
||||
return AMDGPU_VCE_HARVEST_VCE1;
|
||||
case 3:
|
||||
ret = AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
|
||||
break;
|
||||
return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
|
||||
default:
|
||||
ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vce_v3_0_early_init(void *handle)
|
||||
|
|
@ -316,28 +414,22 @@ static int vce_v3_0_sw_fini(void *handle)
|
|||
|
||||
static int vce_v3_0_hw_init(void *handle)
|
||||
{
|
||||
struct amdgpu_ring *ring;
|
||||
int r;
|
||||
int r, i;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
r = vce_v3_0_start(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ring = &adev->vce.ring[0];
|
||||
ring->ready = true;
|
||||
r = amdgpu_ring_test_ring(ring);
|
||||
if (r) {
|
||||
ring->ready = false;
|
||||
return r;
|
||||
}
|
||||
adev->vce.ring[0].ready = false;
|
||||
adev->vce.ring[1].ready = false;
|
||||
|
||||
ring = &adev->vce.ring[1];
|
||||
ring->ready = true;
|
||||
r = amdgpu_ring_test_ring(ring);
|
||||
if (r) {
|
||||
ring->ready = false;
|
||||
return r;
|
||||
for (i = 0; i < 2; i++) {
|
||||
r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
adev->vce.ring[i].ready = true;
|
||||
}
|
||||
|
||||
DRM_INFO("VCE initialized successfully.\n");
|
||||
|
|
@ -437,17 +529,9 @@ static bool vce_v3_0_is_idle(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
u32 mask = 0;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < 2; ++idx) {
|
||||
if (adev->vce.harvest_config & (1 << idx))
|
||||
continue;
|
||||
|
||||
if (idx == 0)
|
||||
mask |= SRBM_STATUS2__VCE0_BUSY_MASK;
|
||||
else
|
||||
mask |= SRBM_STATUS2__VCE1_BUSY_MASK;
|
||||
}
|
||||
mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
|
||||
mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
|
||||
|
||||
return !(RREG32(mmSRBM_STATUS2) & mask);
|
||||
}
|
||||
|
|
@ -456,23 +540,11 @@ static int vce_v3_0_wait_for_idle(void *handle)
|
|||
{
|
||||
unsigned i;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
u32 mask = 0;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < 2; ++idx) {
|
||||
if (adev->vce.harvest_config & (1 << idx))
|
||||
continue;
|
||||
|
||||
if (idx == 0)
|
||||
mask |= SRBM_STATUS2__VCE0_BUSY_MASK;
|
||||
else
|
||||
mask |= SRBM_STATUS2__VCE1_BUSY_MASK;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (!(RREG32(mmSRBM_STATUS2) & mask))
|
||||
for (i = 0; i < adev->usec_timeout; i++)
|
||||
if (vce_v3_0_is_idle(handle))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
@ -480,17 +552,10 @@ static int vce_v3_0_soft_reset(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
u32 mask = 0;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < 2; ++idx) {
|
||||
if (adev->vce.harvest_config & (1 << idx))
|
||||
continue;
|
||||
mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
|
||||
mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
|
||||
|
||||
if (idx == 0)
|
||||
mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
|
||||
else
|
||||
mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
|
||||
}
|
||||
WREG32_P(mmSRBM_SOFT_RESET, mask,
|
||||
~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK |
|
||||
SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK));
|
||||
|
|
@ -592,10 +657,8 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
|
|||
|
||||
switch (entry->src_data) {
|
||||
case 0:
|
||||
amdgpu_fence_process(&adev->vce.ring[0]);
|
||||
break;
|
||||
case 1:
|
||||
amdgpu_fence_process(&adev->vce.ring[1]);
|
||||
amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unhandled interrupt: %d %d\n",
|
||||
|
|
@ -609,6 +672,47 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
|
|||
static int vce_v3_0_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
|
||||
int i;
|
||||
|
||||
if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* Program VCE Instance 0 or 1 if not harvested */
|
||||
if (adev->vce.harvest_config & (1 << i))
|
||||
continue;
|
||||
|
||||
if (i == 0)
|
||||
WREG32_P(mmGRBM_GFX_INDEX, 0,
|
||||
~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
|
||||
else
|
||||
WREG32_P(mmGRBM_GFX_INDEX,
|
||||
GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
|
||||
~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
|
||||
|
||||
if (enable) {
|
||||
/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
|
||||
uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
|
||||
data &= ~(0xf | 0xff0);
|
||||
data |= ((0x0 << 0) | (0x04 << 4));
|
||||
WREG32(mmVCE_CLOCK_GATING_A, data);
|
||||
|
||||
/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
|
||||
data = RREG32(mmVCE_UENC_CLOCK_GATING);
|
||||
data &= ~(0xf | 0xff0);
|
||||
data |= ((0x0 << 0) | (0x04 << 4));
|
||||
WREG32(mmVCE_UENC_CLOCK_GATING, data);
|
||||
}
|
||||
|
||||
vce_v3_0_set_vce_sw_clock_gating(adev, enable);
|
||||
}
|
||||
|
||||
WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "amdgpu_vce.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
#include "atom.h"
|
||||
#include "amd_pcie.h"
|
||||
|
||||
#include "gmc/gmc_8_1_d.h"
|
||||
#include "gmc/gmc_8_1_sh_mask.h"
|
||||
|
|
@ -71,6 +72,7 @@
|
|||
#include "uvd_v5_0.h"
|
||||
#include "uvd_v6_0.h"
|
||||
#include "vce_v3_0.h"
|
||||
#include "amdgpu_powerplay.h"
|
||||
|
||||
/*
|
||||
* Indirect registers accessor
|
||||
|
|
@ -376,6 +378,38 @@ static bool vi_read_disabled_bios(struct amdgpu_device *adev)
|
|||
WREG32_SMC(ixROM_CNTL, rom_cntl);
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool vi_read_bios_from_rom(struct amdgpu_device *adev,
|
||||
u8 *bios, u32 length_bytes)
|
||||
{
|
||||
u32 *dw_ptr;
|
||||
unsigned long flags;
|
||||
u32 i, length_dw;
|
||||
|
||||
if (bios == NULL)
|
||||
return false;
|
||||
if (length_bytes == 0)
|
||||
return false;
|
||||
/* APU vbios image is part of sbios image */
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return false;
|
||||
|
||||
dw_ptr = (u32 *)bios;
|
||||
length_dw = ALIGN(length_bytes, 4) / 4;
|
||||
/* take the smc lock since we are using the smc index */
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
/* set rom index to 0 */
|
||||
WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
|
||||
WREG32(mmSMC_IND_DATA_0, 0);
|
||||
/* set index to data for continous read */
|
||||
WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
|
||||
for (i = 0; i < length_dw; i++)
|
||||
dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct amdgpu_allowed_register_entry tonga_allowed_read_registers[] = {
|
||||
{mmGB_MACROTILE_MODE7, true},
|
||||
};
|
||||
|
|
@ -1019,9 +1053,6 @@ static int vi_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk)
|
|||
|
||||
static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
if (pci_is_root_bus(adev->pdev->bus))
|
||||
return;
|
||||
|
||||
|
|
@ -1031,11 +1062,8 @@ static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
|
||||
if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
|
||||
CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
|
||||
return;
|
||||
|
||||
/* todo */
|
||||
|
|
@ -1098,7 +1126,7 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &iceland_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_GFX,
|
||||
|
|
@ -1145,7 +1173,7 @@ static const struct amdgpu_ip_block_version tonga_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &tonga_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -1213,7 +1241,7 @@ static const struct amdgpu_ip_block_version fiji_ip_blocks[] =
|
|||
.major = 7,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &fiji_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -1281,7 +1309,7 @@ static const struct amdgpu_ip_block_version cz_ip_blocks[] =
|
|||
.major = 8,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &cz_dpm_ip_funcs,
|
||||
.funcs = &amdgpu_pp_ip_funcs
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
|
|
@ -1354,20 +1382,18 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
|
|||
|
||||
static uint32_t vi_get_rev_id(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->asic_type == CHIP_TOPAZ)
|
||||
return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
|
||||
>> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
|
||||
else if (adev->flags & AMD_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return (RREG32_SMC(ATI_REV_ID_FUSE_MACRO__ADDRESS) & ATI_REV_ID_FUSE_MACRO__MASK)
|
||||
>> ATI_REV_ID_FUSE_MACRO__SHIFT;
|
||||
else
|
||||
return (RREG32(mmCC_DRM_ID_STRAPS) & CC_DRM_ID_STRAPS__ATI_REV_ID_MASK)
|
||||
>> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
|
||||
return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
|
||||
>> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
|
||||
}
|
||||
|
||||
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,
|
||||
.read_register = &vi_read_register,
|
||||
.reset = &vi_asic_reset,
|
||||
.set_vga_state = &vi_vga_set_state,
|
||||
|
|
@ -1416,7 +1442,8 @@ static int vi_common_early_init(void *handle)
|
|||
break;
|
||||
case CHIP_FIJI:
|
||||
adev->has_uvd = true;
|
||||
adev->cg_flags = 0;
|
||||
adev->cg_flags = AMDGPU_CG_SUPPORT_UVD_MGCG |
|
||||
AMDGPU_CG_SUPPORT_VCE_MGCG;
|
||||
adev->pg_flags = 0;
|
||||
adev->external_rev_id = adev->rev_id + 0x3c;
|
||||
break;
|
||||
|
|
@ -1442,6 +1469,8 @@ static int vi_common_early_init(void *handle)
|
|||
if (amdgpu_smc_load_fw && smc_enabled)
|
||||
adev->firmware.smu_load = true;
|
||||
|
||||
amdgpu_get_pcie_info(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1515,9 +1544,95 @@ static int vi_common_soft_reset(void *handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fiji_update_bif_medium_grain_light_sleep(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
temp = data = RREG32_PCIE(ixPCIE_CNTL2);
|
||||
|
||||
if (enable)
|
||||
data |= PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
|
||||
PCIE_CNTL2__MST_MEM_LS_EN_MASK |
|
||||
PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK;
|
||||
else
|
||||
data &= ~(PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
|
||||
PCIE_CNTL2__MST_MEM_LS_EN_MASK |
|
||||
PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK);
|
||||
|
||||
if (temp != data)
|
||||
WREG32_PCIE(ixPCIE_CNTL2, data);
|
||||
}
|
||||
|
||||
static void fiji_update_hdp_medium_grain_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
temp = data = RREG32(mmHDP_HOST_PATH_CNTL);
|
||||
|
||||
if (enable)
|
||||
data &= ~HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
|
||||
else
|
||||
data |= HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmHDP_HOST_PATH_CNTL, data);
|
||||
}
|
||||
|
||||
static void fiji_update_hdp_light_sleep(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
temp = data = RREG32(mmHDP_MEM_POWER_LS);
|
||||
|
||||
if (enable)
|
||||
data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
else
|
||||
data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32(mmHDP_MEM_POWER_LS, data);
|
||||
}
|
||||
|
||||
static void fiji_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
|
||||
bool enable)
|
||||
{
|
||||
uint32_t temp, data;
|
||||
|
||||
temp = data = RREG32_SMC(ixCGTT_ROM_CLK_CTRL0);
|
||||
|
||||
if (enable)
|
||||
data &= ~(CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
|
||||
CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK);
|
||||
else
|
||||
data |= CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
|
||||
CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK;
|
||||
|
||||
if (temp != data)
|
||||
WREG32_SMC(ixCGTT_ROM_CLK_CTRL0, data);
|
||||
}
|
||||
|
||||
static int vi_common_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
fiji_update_bif_medium_grain_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
fiji_update_hdp_medium_grain_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
fiji_update_hdp_light_sleep(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
fiji_update_rom_medium_grain_clock_gating(adev,
|
||||
state == AMD_CG_STATE_GATE ? true : false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,14 +21,63 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef AMDGPU_ACPI_H
|
||||
#define AMDGPU_ACPI_H
|
||||
#ifndef AMD_ACPI_H
|
||||
#define AMD_ACPI_H
|
||||
|
||||
struct amdgpu_device;
|
||||
struct acpi_bus_event;
|
||||
#define ACPI_AC_CLASS "ac_adapter"
|
||||
|
||||
int amdgpu_atif_handler(struct amdgpu_device *adev,
|
||||
struct acpi_bus_event *event);
|
||||
struct atif_verify_interface {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 version; /* version */
|
||||
u32 notification_mask; /* supported notifications mask */
|
||||
u32 function_bits; /* supported functions bit vector */
|
||||
} __packed;
|
||||
|
||||
struct atif_system_params {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u32 valid_mask; /* valid flags mask */
|
||||
u32 flags; /* flags */
|
||||
u8 command_code; /* notify command code */
|
||||
} __packed;
|
||||
|
||||
struct atif_sbios_requests {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u32 pending; /* pending sbios requests */
|
||||
u8 panel_exp_mode; /* panel expansion mode */
|
||||
u8 thermal_gfx; /* thermal state: target gfx controller */
|
||||
u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */
|
||||
u8 forced_power_gfx; /* forced power state: target gfx controller */
|
||||
u8 forced_power_state; /* forced power state: state id */
|
||||
u8 system_power_src; /* system power source */
|
||||
u8 backlight_level; /* panel backlight level (0-255) */
|
||||
} __packed;
|
||||
|
||||
#define ATIF_NOTIFY_MASK 0x3
|
||||
#define ATIF_NOTIFY_NONE 0
|
||||
#define ATIF_NOTIFY_81 1
|
||||
#define ATIF_NOTIFY_N 2
|
||||
|
||||
struct atcs_verify_interface {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 version; /* version */
|
||||
u32 function_bits; /* supported functions bit vector */
|
||||
} __packed;
|
||||
|
||||
#define ATCS_VALID_FLAGS_MASK 0x3
|
||||
|
||||
struct atcs_pref_req_input {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
|
||||
u16 valid_flags_mask; /* valid flags mask */
|
||||
u16 flags; /* flags */
|
||||
u8 req_type; /* request type */
|
||||
u8 perf_req; /* performance request */
|
||||
} __packed;
|
||||
|
||||
struct atcs_pref_req_output {
|
||||
u16 size; /* structure size in bytes (includes size field) */
|
||||
u8 ret_val; /* return value */
|
||||
} __packed;
|
||||
|
||||
/* AMD hw uses four ACPI control methods:
|
||||
* 1. ATIF
|
||||
50
drivers/gpu/drm/amd/include/amd_pcie.h
Normal file
50
drivers/gpu/drm/amd/include/amd_pcie.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 __AMD_PCIE_H__
|
||||
#define __AMD_PCIE_H__
|
||||
|
||||
/* Following flags shows PCIe link speed supported in driver which are decided by chipset and ASIC */
|
||||
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00010000
|
||||
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00020000
|
||||
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00040000
|
||||
#define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK 0xFFFF0000
|
||||
#define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT 16
|
||||
|
||||
/* Following flags shows PCIe link speed supported by ASIC H/W.*/
|
||||
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00000001
|
||||
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00000002
|
||||
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00000004
|
||||
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK 0x0000FFFF
|
||||
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT 0
|
||||
|
||||
/* Following flags shows PCIe lane width switch supported in driver which are decided by chipset and ASIC */
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X1 0x00010000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 0x00020000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 0x00040000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 0x00080000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 0x00100000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 0x00200000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 0x00400000
|
||||
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT 16
|
||||
|
||||
#endif
|
||||
141
drivers/gpu/drm/amd/include/amd_pcie_helpers.h
Normal file
141
drivers/gpu/drm/amd/include/amd_pcie_helpers.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 __AMD_PCIE_HELPERS_H__
|
||||
#define __AMD_PCIE_HELPERS_H__
|
||||
|
||||
#include "amd_pcie.h"
|
||||
|
||||
static inline bool is_pcie_gen3_supported(uint32_t pcie_link_speed_cap)
|
||||
{
|
||||
if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_pcie_gen2_supported(uint32_t pcie_link_speed_cap)
|
||||
{
|
||||
if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the new PCIE speed given the ASIC PCIE Cap and the NewState's requested PCIE speed*/
|
||||
static inline uint16_t get_pcie_gen_support(uint32_t pcie_link_speed_cap,
|
||||
uint16_t ns_pcie_gen)
|
||||
{
|
||||
uint32_t asic_pcie_link_speed_cap = (pcie_link_speed_cap &
|
||||
CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK);
|
||||
uint32_t sys_pcie_link_speed_cap = (pcie_link_speed_cap &
|
||||
CAIL_PCIE_LINK_SPEED_SUPPORT_MASK);
|
||||
|
||||
switch (asic_pcie_link_speed_cap) {
|
||||
case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1:
|
||||
return PP_PCIEGen1;
|
||||
|
||||
case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2:
|
||||
return PP_PCIEGen2;
|
||||
|
||||
case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3:
|
||||
return PP_PCIEGen3;
|
||||
|
||||
default:
|
||||
if (is_pcie_gen3_supported(sys_pcie_link_speed_cap) &&
|
||||
(ns_pcie_gen == PP_PCIEGen3)) {
|
||||
return PP_PCIEGen3;
|
||||
} else if (is_pcie_gen2_supported(sys_pcie_link_speed_cap) &&
|
||||
((ns_pcie_gen == PP_PCIEGen3) || (ns_pcie_gen == PP_PCIEGen2))) {
|
||||
return PP_PCIEGen2;
|
||||
}
|
||||
}
|
||||
|
||||
return PP_PCIEGen1;
|
||||
}
|
||||
|
||||
static inline uint16_t get_pcie_lane_support(uint32_t pcie_lane_width_cap,
|
||||
uint16_t ns_pcie_lanes)
|
||||
{
|
||||
int i, j;
|
||||
uint16_t new_pcie_lanes = ns_pcie_lanes;
|
||||
uint16_t pcie_lanes[7] = {1, 2, 4, 8, 12, 16, 32};
|
||||
|
||||
switch (pcie_lane_width_cap) {
|
||||
case 0:
|
||||
printk(KERN_ERR "No valid PCIE lane width reported");
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X1:
|
||||
new_pcie_lanes = 1;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X2:
|
||||
new_pcie_lanes = 2;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X4:
|
||||
new_pcie_lanes = 4;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X8:
|
||||
new_pcie_lanes = 8;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X12:
|
||||
new_pcie_lanes = 12;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X16:
|
||||
new_pcie_lanes = 16;
|
||||
break;
|
||||
case CAIL_PCIE_LINK_WIDTH_SUPPORT_X32:
|
||||
new_pcie_lanes = 32;
|
||||
break;
|
||||
default:
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (ns_pcie_lanes == pcie_lanes[i]) {
|
||||
if (pcie_lane_width_cap & (0x10000 << i)) {
|
||||
break;
|
||||
} else {
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
if (pcie_lane_width_cap & (0x10000 << j)) {
|
||||
new_pcie_lanes = pcie_lanes[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j < 0) {
|
||||
for (j = i + 1; j < 7; j++) {
|
||||
if (pcie_lane_width_cap & (0x10000 << j)) {
|
||||
new_pcie_lanes = pcie_lanes[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j > 7)
|
||||
printk(KERN_ERR "Cannot find a valid PCIE lane width!");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return new_pcie_lanes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -85,6 +85,27 @@ enum amd_powergating_state {
|
|||
AMD_PG_STATE_UNGATE,
|
||||
};
|
||||
|
||||
enum amd_pm_state_type {
|
||||
/* not used for dpm */
|
||||
POWER_STATE_TYPE_DEFAULT,
|
||||
POWER_STATE_TYPE_POWERSAVE,
|
||||
/* user selectable states */
|
||||
POWER_STATE_TYPE_BATTERY,
|
||||
POWER_STATE_TYPE_BALANCED,
|
||||
POWER_STATE_TYPE_PERFORMANCE,
|
||||
/* internal states */
|
||||
POWER_STATE_TYPE_INTERNAL_UVD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_SD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_HD,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_HD2,
|
||||
POWER_STATE_TYPE_INTERNAL_UVD_MVC,
|
||||
POWER_STATE_TYPE_INTERNAL_BOOT,
|
||||
POWER_STATE_TYPE_INTERNAL_THERMAL,
|
||||
POWER_STATE_TYPE_INTERNAL_ACPI,
|
||||
POWER_STATE_TYPE_INTERNAL_ULV,
|
||||
POWER_STATE_TYPE_INTERNAL_3DPERF,
|
||||
};
|
||||
|
||||
struct amd_ip_funcs {
|
||||
/* sets up early driver state (pre sw_init), does not configure hw - Optional */
|
||||
int (*early_init)(void *handle);
|
||||
|
|
|
|||
|
|
@ -596,6 +596,7 @@
|
|||
#define mmSWRST_EP_CONTROL_0 0x14ac
|
||||
#define mmCPM_CONTROL 0x14b8
|
||||
#define mmGSKT_CONTROL 0x14bf
|
||||
#define ixSWRST_COMMAND_1 0x1400103
|
||||
#define ixLM_CONTROL 0x1400120
|
||||
#define ixLM_PCIETXMUX0 0x1400121
|
||||
#define ixLM_PCIETXMUX1 0x1400122
|
||||
|
|
|
|||
|
|
@ -2807,5 +2807,18 @@
|
|||
#define ixDIDT_DBR_WEIGHT0_3 0x90
|
||||
#define ixDIDT_DBR_WEIGHT4_7 0x91
|
||||
#define ixDIDT_DBR_WEIGHT8_11 0x92
|
||||
#define mmTD_EDC_CNT 0x252e
|
||||
#define mmCPF_EDC_TAG_CNT 0x3188
|
||||
#define mmCPF_EDC_ROQ_CNT 0x3189
|
||||
#define mmCPF_EDC_ATC_CNT 0x318a
|
||||
#define mmCPG_EDC_TAG_CNT 0x318b
|
||||
#define mmCPG_EDC_ATC_CNT 0x318c
|
||||
#define mmCPG_EDC_DMA_CNT 0x318d
|
||||
#define mmCPC_EDC_SCRATCH_CNT 0x318e
|
||||
#define mmCPC_EDC_UCODE_CNT 0x318f
|
||||
#define mmCPC_EDC_ATC_CNT 0x3190
|
||||
#define mmDC_EDC_STATE_CNT 0x3191
|
||||
#define mmDC_EDC_CSINVOC_CNT 0x3192
|
||||
#define mmDC_EDC_RESTORE_CNT 0x3193
|
||||
|
||||
#endif /* GFX_8_0_D_H */
|
||||
|
|
|
|||
|
|
@ -550,6 +550,13 @@ typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1
|
|||
//MPLL_CNTL_FLAG_BYPASS_AD_PLL has a wrong name, should be BYPASS_DQ_PLL
|
||||
#define MPLL_CNTL_FLAG_BYPASS_AD_PLL 0x04
|
||||
|
||||
// use for ComputeMemoryClockParamTable
|
||||
typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2
|
||||
{
|
||||
COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 ulClock;
|
||||
ULONG ulReserved;
|
||||
}COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2;
|
||||
|
||||
typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
|
||||
{
|
||||
ATOM_COMPUTE_CLOCK_FREQ ulClock;
|
||||
|
|
@ -4988,6 +4995,78 @@ typedef struct _ATOM_ASIC_PROFILING_INFO_V3_3
|
|||
ULONG ulSDCMargine;
|
||||
}ATOM_ASIC_PROFILING_INFO_V3_3;
|
||||
|
||||
// for Fiji speed EVV algorithm
|
||||
typedef struct _ATOM_ASIC_PROFILING_INFO_V3_4
|
||||
{
|
||||
ATOM_COMMON_TABLE_HEADER asHeader;
|
||||
ULONG ulEvvLkgFactor;
|
||||
ULONG ulBoardCoreTemp;
|
||||
ULONG ulMaxVddc;
|
||||
ULONG ulMinVddc;
|
||||
ULONG ulLoadLineSlop;
|
||||
ULONG ulLeakageTemp;
|
||||
ULONG ulLeakageVoltage;
|
||||
EFUSE_LINEAR_FUNC_PARAM sCACm;
|
||||
EFUSE_LINEAR_FUNC_PARAM sCACb;
|
||||
EFUSE_LOGISTIC_FUNC_PARAM sKt_b;
|
||||
EFUSE_LOGISTIC_FUNC_PARAM sKv_m;
|
||||
EFUSE_LOGISTIC_FUNC_PARAM sKv_b;
|
||||
USHORT usLkgEuseIndex;
|
||||
UCHAR ucLkgEfuseBitLSB;
|
||||
UCHAR ucLkgEfuseLength;
|
||||
ULONG ulLkgEncodeLn_MaxDivMin;
|
||||
ULONG ulLkgEncodeMax;
|
||||
ULONG ulLkgEncodeMin;
|
||||
ULONG ulEfuseLogisticAlpha;
|
||||
USHORT usPowerDpm0;
|
||||
USHORT usPowerDpm1;
|
||||
USHORT usPowerDpm2;
|
||||
USHORT usPowerDpm3;
|
||||
USHORT usPowerDpm4;
|
||||
USHORT usPowerDpm5;
|
||||
USHORT usPowerDpm6;
|
||||
USHORT usPowerDpm7;
|
||||
ULONG ulTdpDerateDPM0;
|
||||
ULONG ulTdpDerateDPM1;
|
||||
ULONG ulTdpDerateDPM2;
|
||||
ULONG ulTdpDerateDPM3;
|
||||
ULONG ulTdpDerateDPM4;
|
||||
ULONG ulTdpDerateDPM5;
|
||||
ULONG ulTdpDerateDPM6;
|
||||
ULONG ulTdpDerateDPM7;
|
||||
EFUSE_LINEAR_FUNC_PARAM sRoFuse;
|
||||
ULONG ulEvvDefaultVddc;
|
||||
ULONG ulEvvNoCalcVddc;
|
||||
USHORT usParamNegFlag;
|
||||
USHORT usSpeed_Model;
|
||||
ULONG ulSM_A0;
|
||||
ULONG ulSM_A1;
|
||||
ULONG ulSM_A2;
|
||||
ULONG ulSM_A3;
|
||||
ULONG ulSM_A4;
|
||||
ULONG ulSM_A5;
|
||||
ULONG ulSM_A6;
|
||||
ULONG ulSM_A7;
|
||||
UCHAR ucSM_A0_sign;
|
||||
UCHAR ucSM_A1_sign;
|
||||
UCHAR ucSM_A2_sign;
|
||||
UCHAR ucSM_A3_sign;
|
||||
UCHAR ucSM_A4_sign;
|
||||
UCHAR ucSM_A5_sign;
|
||||
UCHAR ucSM_A6_sign;
|
||||
UCHAR ucSM_A7_sign;
|
||||
ULONG ulMargin_RO_a;
|
||||
ULONG ulMargin_RO_b;
|
||||
ULONG ulMargin_RO_c;
|
||||
ULONG ulMargin_fixed;
|
||||
ULONG ulMargin_Fmax_mean;
|
||||
ULONG ulMargin_plat_mean;
|
||||
ULONG ulMargin_Fmax_sigma;
|
||||
ULONG ulMargin_plat_sigma;
|
||||
ULONG ulMargin_DC_sigma;
|
||||
ULONG ulReserved[8]; // Reserved for future ASIC
|
||||
}ATOM_ASIC_PROFILING_INFO_V3_4;
|
||||
|
||||
typedef struct _ATOM_POWER_SOURCE_OBJECT
|
||||
{
|
||||
UCHAR ucPwrSrcId; // Power source
|
||||
|
|
|
|||
|
|
@ -105,6 +105,34 @@ enum cgs_ucode_id {
|
|||
CGS_UCODE_ID_MAXIMUM,
|
||||
};
|
||||
|
||||
enum cgs_system_info_id {
|
||||
CGS_SYSTEM_INFO_ADAPTER_BDF_ID = 1,
|
||||
CGS_SYSTEM_INFO_PCIE_GEN_INFO,
|
||||
CGS_SYSTEM_INFO_PCIE_MLW,
|
||||
CGS_SYSTEM_INFO_ID_MAXIMUM,
|
||||
};
|
||||
|
||||
struct cgs_system_info {
|
||||
uint64_t size;
|
||||
uint64_t info_id;
|
||||
union {
|
||||
void *ptr;
|
||||
uint64_t value;
|
||||
};
|
||||
uint64_t padding[13];
|
||||
};
|
||||
|
||||
/*
|
||||
* enum cgs_resource_type - GPU resource type
|
||||
*/
|
||||
enum cgs_resource_type {
|
||||
CGS_RESOURCE_TYPE_MMIO = 0,
|
||||
CGS_RESOURCE_TYPE_FB,
|
||||
CGS_RESOURCE_TYPE_IO,
|
||||
CGS_RESOURCE_TYPE_DOORBELL,
|
||||
CGS_RESOURCE_TYPE_ROM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cgs_clock_limits - Clock limits
|
||||
*
|
||||
|
|
@ -127,8 +155,53 @@ struct cgs_firmware_info {
|
|||
void *kptr;
|
||||
};
|
||||
|
||||
struct cgs_mode_info {
|
||||
uint32_t refresh_rate;
|
||||
uint32_t ref_clock;
|
||||
uint32_t vblank_time_us;
|
||||
};
|
||||
|
||||
struct cgs_display_info {
|
||||
uint32_t display_count;
|
||||
uint32_t active_display_mask;
|
||||
struct cgs_mode_info *mode_info;
|
||||
};
|
||||
|
||||
typedef unsigned long cgs_handle_t;
|
||||
|
||||
#define CGS_ACPI_METHOD_ATCS 0x53435441
|
||||
#define CGS_ACPI_METHOD_ATIF 0x46495441
|
||||
#define CGS_ACPI_METHOD_ATPX 0x58505441
|
||||
#define CGS_ACPI_FIELD_METHOD_NAME 0x00000001
|
||||
#define CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT 0x00000002
|
||||
#define CGS_ACPI_MAX_BUFFER_SIZE 256
|
||||
#define CGS_ACPI_TYPE_ANY 0x00
|
||||
#define CGS_ACPI_TYPE_INTEGER 0x01
|
||||
#define CGS_ACPI_TYPE_STRING 0x02
|
||||
#define CGS_ACPI_TYPE_BUFFER 0x03
|
||||
#define CGS_ACPI_TYPE_PACKAGE 0x04
|
||||
|
||||
struct cgs_acpi_method_argument {
|
||||
uint32_t type;
|
||||
uint32_t method_length;
|
||||
uint32_t data_length;
|
||||
union{
|
||||
uint32_t value;
|
||||
void *pointer;
|
||||
};
|
||||
};
|
||||
|
||||
struct cgs_acpi_method_info {
|
||||
uint32_t size;
|
||||
uint32_t field;
|
||||
uint32_t input_count;
|
||||
uint32_t name;
|
||||
struct cgs_acpi_method_argument *pinput_argument;
|
||||
uint32_t output_count;
|
||||
struct cgs_acpi_method_argument *poutput_argument;
|
||||
uint32_t padding[9];
|
||||
};
|
||||
|
||||
/**
|
||||
* cgs_gpu_mem_info() - Return information about memory heaps
|
||||
* @cgs_device: opaque device handle
|
||||
|
|
@ -355,6 +428,23 @@ typedef void (*cgs_write_pci_config_word_t)(void *cgs_device, unsigned addr,
|
|||
typedef void (*cgs_write_pci_config_dword_t)(void *cgs_device, unsigned addr,
|
||||
uint32_t value);
|
||||
|
||||
|
||||
/**
|
||||
* cgs_get_pci_resource() - provide access to a device resource (PCI BAR)
|
||||
* @cgs_device: opaque device handle
|
||||
* @resource_type: Type of Resource (MMIO, IO, ROM, FB, DOORBELL)
|
||||
* @size: size of the region
|
||||
* @offset: offset from the start of the region
|
||||
* @resource_base: base address (not including offset) returned
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_get_pci_resource_t)(void *cgs_device,
|
||||
enum cgs_resource_type resource_type,
|
||||
uint64_t size,
|
||||
uint64_t offset,
|
||||
uint64_t *resource_base);
|
||||
|
||||
/**
|
||||
* cgs_atom_get_data_table() - Get a pointer to an ATOM BIOS data table
|
||||
* @cgs_device: opaque device handle
|
||||
|
|
@ -493,6 +583,21 @@ typedef int(*cgs_set_clockgating_state)(void *cgs_device,
|
|||
enum amd_ip_block_type block_type,
|
||||
enum amd_clockgating_state state);
|
||||
|
||||
typedef int(*cgs_get_active_displays_info)(
|
||||
void *cgs_device,
|
||||
struct cgs_display_info *info);
|
||||
|
||||
typedef int (*cgs_call_acpi_method)(void *cgs_device,
|
||||
uint32_t acpi_method,
|
||||
uint32_t acpi_function,
|
||||
void *pinput, void *poutput,
|
||||
uint32_t output_count,
|
||||
uint32_t input_size,
|
||||
uint32_t output_size);
|
||||
|
||||
typedef int (*cgs_query_system_info)(void *cgs_device,
|
||||
struct cgs_system_info *sys_info);
|
||||
|
||||
struct cgs_ops {
|
||||
/* memory management calls (similar to KFD interface) */
|
||||
cgs_gpu_mem_info_t gpu_mem_info;
|
||||
|
|
@ -516,6 +621,8 @@ struct cgs_ops {
|
|||
cgs_write_pci_config_byte_t write_pci_config_byte;
|
||||
cgs_write_pci_config_word_t write_pci_config_word;
|
||||
cgs_write_pci_config_dword_t write_pci_config_dword;
|
||||
/* PCI resources */
|
||||
cgs_get_pci_resource_t get_pci_resource;
|
||||
/* ATOM BIOS */
|
||||
cgs_atom_get_data_table_t atom_get_data_table;
|
||||
cgs_atom_get_cmd_table_revs_t atom_get_cmd_table_revs;
|
||||
|
|
@ -533,7 +640,12 @@ struct cgs_ops {
|
|||
/* cg pg interface*/
|
||||
cgs_set_powergating_state set_powergating_state;
|
||||
cgs_set_clockgating_state set_clockgating_state;
|
||||
/* ACPI (TODO) */
|
||||
/* display manager */
|
||||
cgs_get_active_displays_info get_active_displays_info;
|
||||
/* ACPI */
|
||||
cgs_call_acpi_method call_acpi_method;
|
||||
/* get system info */
|
||||
cgs_query_system_info query_system_info;
|
||||
};
|
||||
|
||||
struct cgs_os_ops; /* To be define in OS-specific CGS header */
|
||||
|
|
@ -620,5 +732,15 @@ struct cgs_device
|
|||
CGS_CALL(set_powergating_state, dev, block_type, state)
|
||||
#define cgs_set_clockgating_state(dev, block_type, state) \
|
||||
CGS_CALL(set_clockgating_state, dev, block_type, state)
|
||||
#define cgs_get_active_displays_info(dev, info) \
|
||||
CGS_CALL(get_active_displays_info, dev, info)
|
||||
#define cgs_call_acpi_method(dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size) \
|
||||
CGS_CALL(call_acpi_method, dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size)
|
||||
#define cgs_query_system_info(dev, sys_info) \
|
||||
CGS_CALL(query_system_info, dev, sys_info)
|
||||
#define cgs_get_pci_resource(cgs_device, resource_type, size, offset, \
|
||||
resource_base) \
|
||||
CGS_CALL(get_pci_resource, cgs_device, resource_type, size, offset, \
|
||||
resource_base)
|
||||
|
||||
#endif /* _CGS_COMMON_H */
|
||||
|
|
|
|||
6
drivers/gpu/drm/amd/powerplay/Kconfig
Normal file
6
drivers/gpu/drm/amd/powerplay/Kconfig
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
config DRM_AMD_POWERPLAY
|
||||
bool "Enable AMD powerplay component"
|
||||
depends on DRM_AMDGPU
|
||||
default n
|
||||
help
|
||||
select this option will enable AMD powerplay component.
|
||||
22
drivers/gpu/drm/amd/powerplay/Makefile
Normal file
22
drivers/gpu/drm/amd/powerplay/Makefile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
subdir-ccflags-y += -Iinclude/drm \
|
||||
-Idrivers/gpu/drm/amd/powerplay/inc/ \
|
||||
-Idrivers/gpu/drm/amd/include/asic_reg \
|
||||
-Idrivers/gpu/drm/amd/include \
|
||||
-Idrivers/gpu/drm/amd/powerplay/smumgr\
|
||||
-Idrivers/gpu/drm/amd/powerplay/hwmgr \
|
||||
-Idrivers/gpu/drm/amd/powerplay/eventmgr
|
||||
|
||||
AMD_PP_PATH = ../powerplay
|
||||
|
||||
PP_LIBS = smumgr hwmgr eventmgr
|
||||
|
||||
AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix drivers/gpu/drm/amd/powerplay/,$(PP_LIBS)))
|
||||
|
||||
include $(AMD_POWERPLAY)
|
||||
|
||||
POWER_MGR = amd_powerplay.o
|
||||
|
||||
AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR))
|
||||
|
||||
AMD_POWERPLAY_FILES += $(AMD_PP_POWER)
|
||||
660
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
Normal file
660
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
Normal file
|
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
* 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 <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/slab.h>
|
||||
#include "amd_shared.h"
|
||||
#include "amd_powerplay.h"
|
||||
#include "pp_instance.h"
|
||||
#include "power_state.h"
|
||||
#include "eventmanager.h"
|
||||
|
||||
#define PP_CHECK(handle) \
|
||||
do { \
|
||||
if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
|
||||
return -EINVAL; \
|
||||
} while (0)
|
||||
|
||||
static int pp_early_init(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_sw_init(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_hwmgr *hwmgr;
|
||||
int ret = 0;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
hwmgr = pp_handle->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->pptable_func == NULL ||
|
||||
hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->pptable_func->pptable_init == NULL ||
|
||||
hwmgr->hwmgr_func->backend_init == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = hwmgr->pptable_func->pptable_init(hwmgr);
|
||||
|
||||
if (ret == 0)
|
||||
ret = hwmgr->hwmgr_func->backend_init(hwmgr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pp_sw_fini(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_hwmgr *hwmgr;
|
||||
int ret = 0;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
hwmgr = pp_handle->hwmgr;
|
||||
|
||||
if (hwmgr != NULL || hwmgr->hwmgr_func != NULL ||
|
||||
hwmgr->hwmgr_func->backend_fini != NULL)
|
||||
ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pp_hw_init(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_smumgr *smumgr;
|
||||
struct pp_eventmgr *eventmgr;
|
||||
int ret = 0;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
smumgr = pp_handle->smu_mgr;
|
||||
|
||||
if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
|
||||
smumgr->smumgr_funcs->smu_init == NULL ||
|
||||
smumgr->smumgr_funcs->start_smu == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smumgr->smumgr_funcs->smu_init(smumgr);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = smumgr->smumgr_funcs->start_smu(smumgr);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "[ powerplay ] smc start failed\n");
|
||||
smumgr->smumgr_funcs->smu_fini(smumgr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hw_init_power_state_table(pp_handle->hwmgr);
|
||||
eventmgr = pp_handle->eventmgr;
|
||||
|
||||
if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = eventmgr->pp_eventmgr_init(eventmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_hw_fini(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_smumgr *smumgr;
|
||||
struct pp_eventmgr *eventmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
eventmgr = pp_handle->eventmgr;
|
||||
|
||||
if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
|
||||
eventmgr->pp_eventmgr_fini(eventmgr);
|
||||
|
||||
smumgr = pp_handle->smu_mgr;
|
||||
|
||||
if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
|
||||
smumgr->smumgr_funcs->smu_fini != NULL)
|
||||
smumgr->smumgr_funcs->smu_fini(smumgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pp_is_idle(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_wait_for_idle(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_sw_reset(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pp_print_status(void *handle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int pp_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_suspend(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_eventmgr *eventmgr;
|
||||
struct pem_event_data event_data = { {0} };
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
eventmgr = pp_handle->eventmgr;
|
||||
pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_resume(void *handle)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_eventmgr *eventmgr;
|
||||
struct pem_event_data event_data = { {0} };
|
||||
struct pp_smumgr *smumgr;
|
||||
int ret;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
smumgr = pp_handle->smu_mgr;
|
||||
|
||||
if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
|
||||
smumgr->smumgr_funcs->start_smu == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smumgr->smumgr_funcs->start_smu(smumgr);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "[ powerplay ] smc start failed\n");
|
||||
smumgr->smumgr_funcs->smu_fini(smumgr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
eventmgr = pp_handle->eventmgr;
|
||||
pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs pp_ip_funcs = {
|
||||
.early_init = pp_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = pp_sw_init,
|
||||
.sw_fini = pp_sw_fini,
|
||||
.hw_init = pp_hw_init,
|
||||
.hw_fini = pp_hw_fini,
|
||||
.suspend = pp_suspend,
|
||||
.resume = pp_resume,
|
||||
.is_idle = pp_is_idle,
|
||||
.wait_for_idle = pp_wait_for_idle,
|
||||
.soft_reset = pp_sw_reset,
|
||||
.print_status = pp_print_status,
|
||||
.set_clockgating_state = pp_set_clockgating_state,
|
||||
.set_powergating_state = pp_set_powergating_state,
|
||||
};
|
||||
|
||||
static int pp_dpm_load_fw(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_dpm_fw_loading_complete(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_dpm_force_performance_level(void *handle,
|
||||
enum amd_dpm_forced_level level)
|
||||
{
|
||||
struct pp_instance *pp_handle;
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
|
||||
hwmgr = pp_handle->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->force_dpm_level == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum amd_dpm_forced_level pp_dpm_get_performance_level(
|
||||
void *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return (((struct pp_instance *)handle)->hwmgr->dpm_level);
|
||||
}
|
||||
|
||||
static int pp_dpm_get_sclk(void *handle, bool low)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->get_sclk == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
|
||||
}
|
||||
|
||||
static int pp_dpm_get_mclk(void *handle, bool low)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->get_mclk == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
|
||||
}
|
||||
|
||||
static int pp_dpm_powergate_vce(void *handle, bool gate)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->powergate_vce == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
|
||||
}
|
||||
|
||||
static int pp_dpm_powergate_uvd(void *handle, bool gate)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->powergate_uvd == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
|
||||
}
|
||||
|
||||
static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state)
|
||||
{
|
||||
switch (state) {
|
||||
case POWER_STATE_TYPE_BATTERY:
|
||||
return PP_StateUILabel_Battery;
|
||||
case POWER_STATE_TYPE_BALANCED:
|
||||
return PP_StateUILabel_Balanced;
|
||||
case POWER_STATE_TYPE_PERFORMANCE:
|
||||
return PP_StateUILabel_Performance;
|
||||
default:
|
||||
return PP_StateUILabel_None;
|
||||
}
|
||||
}
|
||||
|
||||
int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, void *output)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pp_instance *pp_handle;
|
||||
struct pem_event_data data = { {0} };
|
||||
|
||||
pp_handle = (struct pp_instance *)handle;
|
||||
|
||||
if (pp_handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
switch (event_id) {
|
||||
case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
|
||||
ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
|
||||
break;
|
||||
case AMD_PP_EVENT_ENABLE_USER_STATE:
|
||||
{
|
||||
enum amd_pm_state_type ps;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
ps = *(unsigned long *)input;
|
||||
|
||||
data.requested_ui_label = power_state_convert(ps);
|
||||
ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
struct pp_power_state *state;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->current_ps == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state = hwmgr->current_ps;
|
||||
|
||||
switch (state->classification.ui_label) {
|
||||
case PP_StateUILabel_Battery:
|
||||
return POWER_STATE_TYPE_BATTERY;
|
||||
case PP_StateUILabel_Balanced:
|
||||
return POWER_STATE_TYPE_BALANCED;
|
||||
case PP_StateUILabel_Performance:
|
||||
return POWER_STATE_TYPE_PERFORMANCE;
|
||||
default:
|
||||
return POWER_STATE_TYPE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
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 ||
|
||||
hwmgr->hwmgr_func->print_current_perforce_level == NULL)
|
||||
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;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->set_fan_control_mode == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
|
||||
}
|
||||
|
||||
static int pp_dpm_get_fan_control_mode(void *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->get_fan_control_mode == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
|
||||
}
|
||||
|
||||
static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->set_fan_speed_percent == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
|
||||
}
|
||||
|
||||
static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->get_fan_speed_percent == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
|
||||
}
|
||||
|
||||
static int pp_dpm_get_temperature(void *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
|
||||
hwmgr->hwmgr_func->get_temperature == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_temperature(hwmgr);
|
||||
}
|
||||
|
||||
const struct amd_powerplay_funcs pp_dpm_funcs = {
|
||||
.get_temperature = pp_dpm_get_temperature,
|
||||
.load_firmware = pp_dpm_load_fw,
|
||||
.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
|
||||
.force_performance_level = pp_dpm_force_performance_level,
|
||||
.get_performance_level = pp_dpm_get_performance_level,
|
||||
.get_current_power_state = pp_dpm_get_current_power_state,
|
||||
.get_sclk = pp_dpm_get_sclk,
|
||||
.get_mclk = pp_dpm_get_mclk,
|
||||
.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,
|
||||
.get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
|
||||
};
|
||||
|
||||
static int amd_pp_instance_init(struct amd_pp_init *pp_init,
|
||||
struct amd_powerplay *amd_pp)
|
||||
{
|
||||
int ret;
|
||||
struct pp_instance *handle;
|
||||
|
||||
handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
|
||||
if (handle == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
handle->pp_valid = PP_VALID;
|
||||
|
||||
ret = smum_init(pp_init, handle);
|
||||
if (ret)
|
||||
goto fail_smum;
|
||||
|
||||
ret = hwmgr_init(pp_init, handle);
|
||||
if (ret)
|
||||
goto fail_hwmgr;
|
||||
|
||||
ret = eventmgr_init(handle);
|
||||
if (ret)
|
||||
goto fail_eventmgr;
|
||||
|
||||
amd_pp->pp_handle = handle;
|
||||
return 0;
|
||||
|
||||
fail_eventmgr:
|
||||
hwmgr_fini(handle->hwmgr);
|
||||
fail_hwmgr:
|
||||
smum_fini(handle->smu_mgr);
|
||||
fail_smum:
|
||||
kfree(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amd_pp_instance_fini(void *handle)
|
||||
{
|
||||
struct pp_instance *instance = (struct pp_instance *)handle;
|
||||
|
||||
if (instance == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
eventmgr_fini(instance->eventmgr);
|
||||
|
||||
hwmgr_fini(instance->hwmgr);
|
||||
|
||||
smum_fini(instance->smu_mgr);
|
||||
|
||||
kfree(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amd_powerplay_init(struct amd_pp_init *pp_init,
|
||||
struct amd_powerplay *amd_pp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pp_init == NULL || amd_pp == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = amd_pp_instance_init(pp_init, amd_pp);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
amd_pp->ip_funcs = &pp_ip_funcs;
|
||||
amd_pp->pp_funcs = &pp_dpm_funcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amd_powerplay_fini(void *handle)
|
||||
{
|
||||
amd_pp_instance_fini(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* export this function to DAL */
|
||||
|
||||
int amd_powerplay_display_configuration_change(void *handle, const void *input)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
const struct amd_pp_display_configuration *display_config = input;
|
||||
|
||||
PP_CHECK((struct pp_instance *)handle);
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
phm_store_dal_configuration_data(hwmgr, display_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amd_powerplay_get_display_power_level(void *handle,
|
||||
struct amd_pp_dal_clock_info *output)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
PP_CHECK((struct pp_instance *)handle);
|
||||
|
||||
if (output == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = ((struct pp_instance *)handle)->hwmgr;
|
||||
|
||||
return phm_get_dal_power_level(hwmgr, output);
|
||||
}
|
||||
11
drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
Normal file
11
drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Makefile for the 'event manager' sub-component of powerplay.
|
||||
# It provides the event management services for the driver.
|
||||
|
||||
EVENT_MGR = eventmgr.o eventinit.o eventmanagement.o \
|
||||
eventactionchains.o eventsubchains.o eventtasks.o psm.o
|
||||
|
||||
AMD_PP_EVENT = $(addprefix $(AMD_PP_PATH)/eventmgr/,$(EVENT_MGR))
|
||||
|
||||
AMD_POWERPLAY_FILES += $(AMD_PP_EVENT)
|
||||
|
||||
289
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
Normal file
289
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* 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 "eventmgr.h"
|
||||
#include "eventactionchains.h"
|
||||
#include "eventsubchains.h"
|
||||
|
||||
static const pem_event_action *initialize_event[] = {
|
||||
block_adjust_power_state_tasks,
|
||||
power_budget_tasks,
|
||||
system_config_tasks,
|
||||
setup_asic_tasks,
|
||||
enable_dynamic_state_management_tasks,
|
||||
enable_clock_power_gatings_tasks,
|
||||
get_2d_performance_state_tasks,
|
||||
set_performance_state_tasks,
|
||||
initialize_thermal_controller_tasks,
|
||||
conditionally_force_3d_performance_state_tasks,
|
||||
process_vbios_eventinfo_tasks,
|
||||
broadcast_power_policy_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain initialize_action_chain = {
|
||||
"Initialize",
|
||||
initialize_event
|
||||
};
|
||||
|
||||
static const pem_event_action *uninitialize_event[] = {
|
||||
ungate_all_display_phys_tasks,
|
||||
uninitialize_display_phy_access_tasks,
|
||||
disable_gfx_voltage_island_power_gating_tasks,
|
||||
disable_gfx_clock_gating_tasks,
|
||||
set_boot_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
disable_dynamic_state_management_tasks,
|
||||
disable_clock_power_gatings_tasks,
|
||||
cleanup_asic_tasks,
|
||||
prepare_for_pnp_stop_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain uninitialize_action_chain = {
|
||||
"Uninitialize",
|
||||
uninitialize_event
|
||||
};
|
||||
|
||||
static const pem_event_action *power_source_change_event_pp_enabled[] = {
|
||||
set_power_source_tasks,
|
||||
set_power_saving_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
enable_disable_fps_tasks,
|
||||
set_nbmcu_state_tasks,
|
||||
broadcast_power_policy_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain power_source_change_action_chain_pp_enabled = {
|
||||
"Power source change - PowerPlay enabled",
|
||||
power_source_change_event_pp_enabled
|
||||
};
|
||||
|
||||
static const pem_event_action *power_source_change_event_pp_disabled[] = {
|
||||
set_power_source_tasks,
|
||||
set_nbmcu_state_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain power_source_changes_action_chain_pp_disabled = {
|
||||
"Power source change - PowerPlay disabled",
|
||||
power_source_change_event_pp_disabled
|
||||
};
|
||||
|
||||
static const pem_event_action *power_source_change_event_hardware_dc[] = {
|
||||
set_power_source_tasks,
|
||||
set_power_saving_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
enable_disable_fps_tasks,
|
||||
reset_hardware_dc_notification_tasks,
|
||||
set_nbmcu_state_tasks,
|
||||
broadcast_power_policy_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain power_source_change_action_chain_hardware_dc = {
|
||||
"Power source change - with Hardware DC switching",
|
||||
power_source_change_event_hardware_dc
|
||||
};
|
||||
|
||||
static const pem_event_action *suspend_event[] = {
|
||||
reset_display_phy_access_tasks,
|
||||
unregister_interrupt_tasks,
|
||||
disable_gfx_voltage_island_power_gating_tasks,
|
||||
disable_gfx_clock_gating_tasks,
|
||||
notify_smu_suspend_tasks,
|
||||
disable_smc_firmware_ctf_tasks,
|
||||
set_boot_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
disable_fps_tasks,
|
||||
vari_bright_suspend_tasks,
|
||||
reset_fan_speed_to_default_tasks,
|
||||
power_down_asic_tasks,
|
||||
disable_stutter_mode_tasks,
|
||||
set_connected_standby_tasks,
|
||||
block_hw_access_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain suspend_action_chain = {
|
||||
"Suspend",
|
||||
suspend_event
|
||||
};
|
||||
|
||||
static const pem_event_action *resume_event[] = {
|
||||
unblock_hw_access_tasks,
|
||||
resume_connected_standby_tasks,
|
||||
notify_smu_resume_tasks,
|
||||
reset_display_configCounter_tasks,
|
||||
update_dal_configuration_tasks,
|
||||
vari_bright_resume_tasks,
|
||||
block_adjust_power_state_tasks,
|
||||
setup_asic_tasks,
|
||||
enable_stutter_mode_tasks, /*must do this in boot state and before SMC is started */
|
||||
enable_dynamic_state_management_tasks,
|
||||
enable_clock_power_gatings_tasks,
|
||||
enable_disable_bapm_tasks,
|
||||
initialize_thermal_controller_tasks,
|
||||
reset_boot_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
enable_disable_fps_tasks,
|
||||
notify_hw_power_source_tasks,
|
||||
process_vbios_event_info_tasks,
|
||||
enable_gfx_clock_gating_tasks,
|
||||
enable_gfx_voltage_island_power_gating_tasks,
|
||||
reset_clock_gating_tasks,
|
||||
notify_smu_vpu_recovery_end_tasks,
|
||||
disable_vpu_cap_tasks,
|
||||
execute_escape_sequence_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const struct action_chain resume_action_chain = {
|
||||
"resume",
|
||||
resume_event
|
||||
};
|
||||
|
||||
static const pem_event_action *complete_init_event[] = {
|
||||
adjust_power_state_tasks,
|
||||
enable_gfx_clock_gating_tasks,
|
||||
enable_gfx_voltage_island_power_gating_tasks,
|
||||
notify_power_state_change_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain complete_init_action_chain = {
|
||||
"complete init",
|
||||
complete_init_event
|
||||
};
|
||||
|
||||
static const pem_event_action *enable_gfx_clock_gating_event[] = {
|
||||
enable_gfx_clock_gating_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain enable_gfx_clock_gating_action_chain = {
|
||||
"enable gfx clock gate",
|
||||
enable_gfx_clock_gating_event
|
||||
};
|
||||
|
||||
static const pem_event_action *disable_gfx_clock_gating_event[] = {
|
||||
disable_gfx_clock_gating_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain disable_gfx_clock_gating_action_chain = {
|
||||
"disable gfx clock gate",
|
||||
disable_gfx_clock_gating_event
|
||||
};
|
||||
|
||||
static const pem_event_action *enable_cgpg_event[] = {
|
||||
enable_cgpg_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain enable_cgpg_action_chain = {
|
||||
"eable cg pg",
|
||||
enable_cgpg_event
|
||||
};
|
||||
|
||||
static const pem_event_action *disable_cgpg_event[] = {
|
||||
disable_cgpg_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain disable_cgpg_action_chain = {
|
||||
"disable cg pg",
|
||||
disable_cgpg_event
|
||||
};
|
||||
|
||||
|
||||
/* Enable user _2d performance and activate */
|
||||
|
||||
static const pem_event_action *enable_user_state_event[] = {
|
||||
create_new_user_performance_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain enable_user_state_action_chain = {
|
||||
"Enable user state",
|
||||
enable_user_state_event
|
||||
};
|
||||
|
||||
static const pem_event_action *enable_user_2d_performance_event[] = {
|
||||
enable_user_2d_performance_tasks,
|
||||
add_user_2d_performance_state_tasks,
|
||||
set_performance_state_tasks,
|
||||
adjust_power_state_tasks,
|
||||
delete_user_2d_performance_state_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain enable_user_2d_performance_action_chain = {
|
||||
"enable_user_2d_performance_event_activate",
|
||||
enable_user_2d_performance_event
|
||||
};
|
||||
|
||||
|
||||
static const pem_event_action *disable_user_2d_performance_event[] = {
|
||||
disable_user_2d_performance_tasks,
|
||||
delete_user_2d_performance_state_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain disable_user_2d_performance_action_chain = {
|
||||
"disable_user_2d_performance_event",
|
||||
disable_user_2d_performance_event
|
||||
};
|
||||
|
||||
|
||||
static const pem_event_action *display_config_change_event[] = {
|
||||
/* countDisplayConfigurationChangeEventTasks, */
|
||||
unblock_adjust_power_state_tasks,
|
||||
set_cpu_power_state,
|
||||
notify_hw_power_source_tasks,
|
||||
/* updateDALConfigurationTasks,
|
||||
variBrightDisplayConfigurationChangeTasks, */
|
||||
adjust_power_state_tasks,
|
||||
/*enableDisableFPSTasks,
|
||||
setNBMCUStateTasks,
|
||||
notifyPCIEDeviceReadyTasks,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain display_config_change_action_chain = {
|
||||
"Display configuration change",
|
||||
display_config_change_event
|
||||
};
|
||||
|
||||
static const pem_event_action *readjust_power_state_event[] = {
|
||||
adjust_power_state_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct action_chain readjust_power_state_action_chain = {
|
||||
"re-adjust power state",
|
||||
readjust_power_state_event
|
||||
};
|
||||
|
||||
62
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
Normal file
62
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 _EVENT_ACTION_CHAINS_H_
|
||||
#define _EVENT_ACTION_CHAINS_H_
|
||||
#include "eventmgr.h"
|
||||
|
||||
extern const struct action_chain initialize_action_chain;
|
||||
|
||||
extern const struct action_chain uninitialize_action_chain;
|
||||
|
||||
extern const struct action_chain power_source_change_action_chain_pp_enabled;
|
||||
|
||||
extern const struct action_chain power_source_changes_action_chain_pp_disabled;
|
||||
|
||||
extern const struct action_chain power_source_change_action_chain_hardware_dc;
|
||||
|
||||
extern const struct action_chain suspend_action_chain;
|
||||
|
||||
extern const struct action_chain resume_action_chain;
|
||||
|
||||
extern const struct action_chain complete_init_action_chain;
|
||||
|
||||
extern const struct action_chain enable_gfx_clock_gating_action_chain;
|
||||
|
||||
extern const struct action_chain disable_gfx_clock_gating_action_chain;
|
||||
|
||||
extern const struct action_chain enable_cgpg_action_chain;
|
||||
|
||||
extern const struct action_chain disable_cgpg_action_chain;
|
||||
|
||||
extern const struct action_chain enable_user_2d_performance_action_chain;
|
||||
|
||||
extern const struct action_chain disable_user_2d_performance_action_chain;
|
||||
|
||||
extern const struct action_chain enable_user_state_action_chain;
|
||||
|
||||
extern const struct action_chain readjust_power_state_action_chain;
|
||||
|
||||
extern const struct action_chain display_config_change_action_chain;
|
||||
|
||||
#endif /*_EVENT_ACTION_CHAINS_H_*/
|
||||
|
||||
195
drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
Normal file
195
drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* 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 "eventmgr.h"
|
||||
#include "eventinit.h"
|
||||
#include "ppinterrupt.h"
|
||||
#include "hardwaremanager.h"
|
||||
|
||||
void pem_init_feature_info(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
|
||||
/* PowerPlay info */
|
||||
eventmgr->ui_state_info[PP_PowerSource_AC].default_ui_lable =
|
||||
PP_StateUILabel_Performance;
|
||||
|
||||
eventmgr->ui_state_info[PP_PowerSource_AC].current_ui_label =
|
||||
PP_StateUILabel_Performance;
|
||||
|
||||
eventmgr->ui_state_info[PP_PowerSource_DC].default_ui_lable =
|
||||
PP_StateUILabel_Battery;
|
||||
|
||||
eventmgr->ui_state_info[PP_PowerSource_DC].current_ui_label =
|
||||
PP_StateUILabel_Battery;
|
||||
|
||||
if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_PowerPlaySupport)) {
|
||||
eventmgr->features[PP_Feature_PowerPlay].supported = true;
|
||||
eventmgr->features[PP_Feature_PowerPlay].version = PEM_CURRENT_POWERPLAY_FEATURE_VERSION;
|
||||
eventmgr->features[PP_Feature_PowerPlay].enabled_default = true;
|
||||
eventmgr->features[PP_Feature_PowerPlay].enabled = true;
|
||||
} else {
|
||||
eventmgr->features[PP_Feature_PowerPlay].supported = false;
|
||||
eventmgr->features[PP_Feature_PowerPlay].enabled = false;
|
||||
eventmgr->features[PP_Feature_PowerPlay].enabled_default = false;
|
||||
}
|
||||
|
||||
eventmgr->features[PP_Feature_Force3DClock].supported = true;
|
||||
eventmgr->features[PP_Feature_Force3DClock].enabled = false;
|
||||
eventmgr->features[PP_Feature_Force3DClock].enabled_default = false;
|
||||
eventmgr->features[PP_Feature_Force3DClock].version = 1;
|
||||
|
||||
/* over drive*/
|
||||
eventmgr->features[PP_Feature_User2DPerformance].version = 4;
|
||||
eventmgr->features[PP_Feature_User3DPerformance].version = 4;
|
||||
eventmgr->features[PP_Feature_OverdriveTest].version = 4;
|
||||
|
||||
eventmgr->features[PP_Feature_OverDrive].version = 4;
|
||||
eventmgr->features[PP_Feature_OverDrive].enabled = false;
|
||||
eventmgr->features[PP_Feature_OverDrive].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_User2DPerformance].supported = false;
|
||||
eventmgr->features[PP_Feature_User2DPerformance].enabled = false;
|
||||
eventmgr->features[PP_Feature_User2DPerformance].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_User3DPerformance].supported = false;
|
||||
eventmgr->features[PP_Feature_User3DPerformance].enabled = false;
|
||||
eventmgr->features[PP_Feature_User3DPerformance].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_OverdriveTest].supported = false;
|
||||
eventmgr->features[PP_Feature_OverdriveTest].enabled = false;
|
||||
eventmgr->features[PP_Feature_OverdriveTest].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_OverDrive].supported = false;
|
||||
|
||||
eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled_default = false;
|
||||
eventmgr->features[PP_Feature_PowerBudgetWaiver].version = 1;
|
||||
eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
|
||||
eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled = false;
|
||||
|
||||
/* Multi UVD States support */
|
||||
eventmgr->features[PP_Feature_MultiUVDState].supported = false;
|
||||
eventmgr->features[PP_Feature_MultiUVDState].enabled = false;
|
||||
eventmgr->features[PP_Feature_MultiUVDState].enabled_default = false;
|
||||
|
||||
/* Dynamic UVD States support */
|
||||
eventmgr->features[PP_Feature_DynamicUVDState].supported = false;
|
||||
eventmgr->features[PP_Feature_DynamicUVDState].enabled = false;
|
||||
eventmgr->features[PP_Feature_DynamicUVDState].enabled_default = false;
|
||||
|
||||
/* VCE DPM support */
|
||||
eventmgr->features[PP_Feature_VCEDPM].supported = false;
|
||||
eventmgr->features[PP_Feature_VCEDPM].enabled = false;
|
||||
eventmgr->features[PP_Feature_VCEDPM].enabled_default = false;
|
||||
|
||||
/* ACP PowerGating support */
|
||||
eventmgr->features[PP_Feature_ACP_POWERGATING].supported = false;
|
||||
eventmgr->features[PP_Feature_ACP_POWERGATING].enabled = false;
|
||||
eventmgr->features[PP_Feature_ACP_POWERGATING].enabled_default = false;
|
||||
|
||||
/* PPM support */
|
||||
eventmgr->features[PP_Feature_PPM].version = 1;
|
||||
eventmgr->features[PP_Feature_PPM].supported = false;
|
||||
eventmgr->features[PP_Feature_PPM].enabled = false;
|
||||
|
||||
/* FFC support (enables fan and temp settings, Gemini needs temp settings) */
|
||||
if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport) ||
|
||||
phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_GeminiRegulatorFanControlSupport)) {
|
||||
eventmgr->features[PP_Feature_FFC].version = 1;
|
||||
eventmgr->features[PP_Feature_FFC].supported = true;
|
||||
eventmgr->features[PP_Feature_FFC].enabled = true;
|
||||
eventmgr->features[PP_Feature_FFC].enabled_default = true;
|
||||
} else {
|
||||
eventmgr->features[PP_Feature_FFC].supported = false;
|
||||
eventmgr->features[PP_Feature_FFC].enabled = false;
|
||||
eventmgr->features[PP_Feature_FFC].enabled_default = false;
|
||||
}
|
||||
|
||||
eventmgr->features[PP_Feature_VariBright].supported = false;
|
||||
eventmgr->features[PP_Feature_VariBright].enabled = false;
|
||||
eventmgr->features[PP_Feature_VariBright].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_BACO].supported = false;
|
||||
eventmgr->features[PP_Feature_BACO].supported = false;
|
||||
eventmgr->features[PP_Feature_BACO].enabled_default = false;
|
||||
|
||||
/* PowerDown feature support */
|
||||
eventmgr->features[PP_Feature_PowerDown].supported = false;
|
||||
eventmgr->features[PP_Feature_PowerDown].enabled = false;
|
||||
eventmgr->features[PP_Feature_PowerDown].enabled_default = false;
|
||||
|
||||
eventmgr->features[PP_Feature_FPS].version = 1;
|
||||
eventmgr->features[PP_Feature_FPS].supported = false;
|
||||
eventmgr->features[PP_Feature_FPS].enabled_default = false;
|
||||
eventmgr->features[PP_Feature_FPS].enabled = false;
|
||||
|
||||
eventmgr->features[PP_Feature_ViPG].version = 1;
|
||||
eventmgr->features[PP_Feature_ViPG].supported = false;
|
||||
eventmgr->features[PP_Feature_ViPG].enabled_default = false;
|
||||
eventmgr->features[PP_Feature_ViPG].enabled = false;
|
||||
}
|
||||
|
||||
static int thermal_interrupt_callback(void *private_data,
|
||||
unsigned src_id, const uint32_t *iv_entry)
|
||||
{
|
||||
/* TO DO hanle PEM_Event_ThermalNotification (struct pp_eventmgr *)private_data*/
|
||||
printk("current thermal is out of range \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_register_interrupts(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
int result = 0;
|
||||
struct pp_interrupt_registration_info info;
|
||||
|
||||
info.call_back = thermal_interrupt_callback;
|
||||
info.context = eventmgr;
|
||||
|
||||
result = phm_register_thermal_interrupt(eventmgr->hwmgr, &info);
|
||||
|
||||
/* TODO:
|
||||
* 2. Register CTF event interrupt
|
||||
* 3. Register for vbios events interrupt
|
||||
* 4. Register External Throttle Interrupt
|
||||
* 5. Register Smc To Host Interrupt
|
||||
* */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int pem_unregister_interrupts(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
eventmgr->features[PP_Feature_MultiUVDState].supported = false;
|
||||
eventmgr->features[PP_Feature_VariBright].supported = false;
|
||||
eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
|
||||
eventmgr->features[PP_Feature_OverDrive].supported = false;
|
||||
eventmgr->features[PP_Feature_OverdriveTest].supported = false;
|
||||
eventmgr->features[PP_Feature_User3DPerformance].supported = false;
|
||||
eventmgr->features[PP_Feature_User2DPerformance].supported = false;
|
||||
eventmgr->features[PP_Feature_PowerPlay].supported = false;
|
||||
eventmgr->features[PP_Feature_Force3DClock].supported = false;
|
||||
}
|
||||
34
drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
Normal file
34
drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 _EVENTINIT_H_
|
||||
#define _EVENTINIT_H_
|
||||
|
||||
#define PEM_CURRENT_POWERPLAY_FEATURE_VERSION 4
|
||||
|
||||
void pem_init_feature_info(struct pp_eventmgr *eventmgr);
|
||||
void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr);
|
||||
int pem_register_interrupts(struct pp_eventmgr *eventmgr);
|
||||
int pem_unregister_interrupts(struct pp_eventmgr *eventmgr);
|
||||
|
||||
#endif /* _EVENTINIT_H_ */
|
||||
215
drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
Normal file
215
drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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 "eventmanagement.h"
|
||||
#include "eventmgr.h"
|
||||
#include "eventactionchains.h"
|
||||
|
||||
int pem_init_event_action_chains(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMD_PP_EVENT_MAX; i++)
|
||||
eventmgr->event_chain[i] = NULL;
|
||||
|
||||
eventmgr->event_chain[AMD_PP_EVENT_SUSPEND] = pem_get_suspend_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_INITIALIZE] = pem_get_initialize_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_UNINITIALIZE] = pem_get_uninitialize_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_POWER_SOURCE_CHANGE] = pem_get_power_source_change_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_HIBERNATE] = pem_get_hibernate_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_RESUME] = pem_get_resume_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_THERMAL_NOTIFICATION] = pem_get_thermal_notification_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_VBIOS_NOTIFICATION] = pem_get_vbios_notification_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENTER_THERMAL_STATE] = pem_get_enter_thermal_state_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_EXIT_THERMAL_STATE] = pem_get_exit_thermal_state_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENABLE_POWER_PLAY] = pem_get_enable_powerplay_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_DISABLE_POWER_PLAY] = pem_get_disable_powerplay_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST] = pem_get_enable_overdrive_test_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST] = pem_get_disable_overdrive_test_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING] = pem_get_enable_gfx_clock_gating_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING] = pem_get_disable_gfx_clock_gating_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENABLE_CGPG] = pem_get_enable_cgpg_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_DISABLE_CGPG] = pem_get_disable_cgpg_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_COMPLETE_INIT] = pem_get_complete_init_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_SCREEN_ON] = pem_get_screen_on_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_SCREEN_OFF] = pem_get_screen_off_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_PRE_SUSPEND] = pem_get_pre_suspend_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_PRE_RESUME] = pem_get_pre_resume_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_ENABLE_USER_STATE] = pem_enable_user_state_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_READJUST_POWER_STATE] = pem_readjust_power_state_action_chain(eventmgr);
|
||||
eventmgr->event_chain[AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE] = pem_display_config_change_action_chain(eventmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data)
|
||||
{
|
||||
const pem_event_action **paction_chain;
|
||||
const pem_event_action *psub_chain;
|
||||
int tmp_result = 0;
|
||||
int result = 0;
|
||||
|
||||
if (eventmgr == NULL || event_chain == NULL || event_data == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (paction_chain = event_chain->action_chain; NULL != *paction_chain; paction_chain++) {
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
for (psub_chain = *paction_chain; NULL != *psub_chain; psub_chain++) {
|
||||
tmp_result = (*psub_chain)(eventmgr, event_data);
|
||||
if (0 == result)
|
||||
result = tmp_result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &suspend_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &initialize_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &uninitialize_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &power_source_change_action_chain_pp_enabled; /* other case base on feature info*/
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &resume_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &enable_gfx_clock_gating_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &disable_gfx_clock_gating_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &enable_cgpg_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &disable_cgpg_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &complete_init_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &enable_user_state_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &readjust_power_state_action_chain;
|
||||
}
|
||||
|
||||
const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return &display_config_change_action_chain;
|
||||
}
|
||||
59
drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
Normal file
59
drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 _EVENT_MANAGEMENT_H_
|
||||
#define _EVENT_MANAGEMENT_H_
|
||||
|
||||
#include "eventmgr.h"
|
||||
|
||||
int pem_init_event_action_chains(struct pp_eventmgr *eventmgr);
|
||||
int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data);
|
||||
const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr);
|
||||
|
||||
extern const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr);
|
||||
extern const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr);
|
||||
const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr);
|
||||
|
||||
|
||||
#endif /* _EVENT_MANAGEMENT_H_ */
|
||||
114
drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
Normal file
114
drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "eventmgr.h"
|
||||
#include "hwmgr.h"
|
||||
#include "eventinit.h"
|
||||
#include "eventmanagement.h"
|
||||
|
||||
static int pem_init(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
int result = 0;
|
||||
struct pem_event_data event_data;
|
||||
|
||||
/* Initialize PowerPlay feature info */
|
||||
pem_init_feature_info(eventmgr);
|
||||
|
||||
/* Initialize event action chains */
|
||||
pem_init_event_action_chains(eventmgr);
|
||||
|
||||
/* Call initialization event */
|
||||
result = pem_handle_event(eventmgr, AMD_PP_EVENT_INITIALIZE, &event_data);
|
||||
|
||||
if (0 != result)
|
||||
return result;
|
||||
|
||||
/* Register interrupt callback functions */
|
||||
result = pem_register_interrupts(eventmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pem_fini(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
struct pem_event_data event_data;
|
||||
|
||||
pem_uninit_featureInfo(eventmgr);
|
||||
pem_unregister_interrupts(eventmgr);
|
||||
|
||||
pem_handle_event(eventmgr, AMD_PP_EVENT_UNINITIALIZE, &event_data);
|
||||
|
||||
if (eventmgr != NULL)
|
||||
kfree(eventmgr);
|
||||
}
|
||||
|
||||
int eventmgr_init(struct pp_instance *handle)
|
||||
{
|
||||
int result = 0;
|
||||
struct pp_eventmgr *eventmgr;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
eventmgr = kzalloc(sizeof(struct pp_eventmgr), GFP_KERNEL);
|
||||
if (eventmgr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
eventmgr->hwmgr = handle->hwmgr;
|
||||
handle->eventmgr = eventmgr;
|
||||
|
||||
eventmgr->platform_descriptor = &(eventmgr->hwmgr->platform_descriptor);
|
||||
eventmgr->pp_eventmgr_init = pem_init;
|
||||
eventmgr->pp_eventmgr_fini = pem_fini;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int eventmgr_fini(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
kfree(eventmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pem_handle_event_unlocked(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *data)
|
||||
{
|
||||
if (eventmgr == NULL || event >= AMD_PP_EVENT_MAX || data == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return pem_excute_event_chain(eventmgr, eventmgr->event_chain[event], data);
|
||||
}
|
||||
|
||||
int pem_handle_event(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *event_data)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
r = pem_handle_event_unlocked(eventmgr, event, event_data);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool pem_is_hw_access_blocked(struct pp_eventmgr *eventmgr)
|
||||
{
|
||||
return (eventmgr->block_adjust_power_state || phm_is_hw_access_blocked(eventmgr->hwmgr));
|
||||
}
|
||||
410
drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
Normal file
410
drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* 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 "eventmgr.h"
|
||||
#include "eventsubchains.h"
|
||||
#include "eventtasks.h"
|
||||
#include "hardwaremanager.h"
|
||||
|
||||
const pem_event_action reset_display_phy_access_tasks[] = {
|
||||
pem_task_reset_display_phys_access,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action broadcast_power_policy_tasks[] = {
|
||||
/* PEM_Task_BroadcastPowerPolicyChange, */
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action unregister_interrupt_tasks[] = {
|
||||
pem_task_unregister_interrupts,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Disable GFX Voltage Islands Power Gating */
|
||||
const pem_event_action disable_gfx_voltage_island_powergating_tasks[] = {
|
||||
pem_task_disable_voltage_island_power_gating,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_gfx_clockgating_tasks[] = {
|
||||
pem_task_disable_gfx_clock_gating,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action block_adjust_power_state_tasks[] = {
|
||||
pem_task_block_adjust_power_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const pem_event_action unblock_adjust_power_state_tasks[] = {
|
||||
pem_task_unblock_adjust_power_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_performance_state_tasks[] = {
|
||||
pem_task_set_performance_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action get_2d_performance_state_tasks[] = {
|
||||
pem_task_get_2D_performance_state_id,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action conditionally_force3D_performance_state_tasks[] = {
|
||||
pem_task_conditionally_force_3d_performance_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action process_vbios_eventinfo_tasks[] = {
|
||||
/* PEM_Task_ProcessVbiosEventInfo,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_dynamic_state_management_tasks[] = {
|
||||
/* PEM_Task_ResetBAPMPolicyChangedFlag,*/
|
||||
pem_task_get_boot_state_id,
|
||||
pem_task_enable_dynamic_state_management,
|
||||
pem_task_register_interrupts,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_clock_power_gatings_tasks[] = {
|
||||
pem_task_enable_clock_power_gatings_tasks,
|
||||
pem_task_powerdown_uvd_tasks,
|
||||
pem_task_powerdown_vce_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action setup_asic_tasks[] = {
|
||||
pem_task_setup_asic,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action power_budget_tasks[] = {
|
||||
/* TODO
|
||||
* PEM_Task_PowerBudgetWaiverAvailable,
|
||||
* PEM_Task_PowerBudgetWarningMessage,
|
||||
* PEM_Task_PruneStatesBasedOnPowerBudget,
|
||||
*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action system_config_tasks[] = {
|
||||
/* PEM_Task_PruneStatesBasedOnSystemConfig,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const pem_event_action conditionally_force_3d_performance_state_tasks[] = {
|
||||
pem_task_conditionally_force_3d_performance_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action ungate_all_display_phys_tasks[] = {
|
||||
/* PEM_Task_GetDisplayPhyAccessInfo */
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action uninitialize_display_phy_access_tasks[] = {
|
||||
/* PEM_Task_UninitializeDisplayPhysAccess, */
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_gfx_voltage_island_power_gating_tasks[] = {
|
||||
/* PEM_Task_DisableVoltageIslandPowerGating, */
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_gfx_clock_gating_tasks[] = {
|
||||
pem_task_disable_gfx_clock_gating,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_boot_state_tasks[] = {
|
||||
pem_task_get_boot_state_id,
|
||||
pem_task_set_boot_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action adjust_power_state_tasks[] = {
|
||||
pem_task_notify_hw_mgr_display_configuration_change,
|
||||
pem_task_adjust_power_state,
|
||||
pem_task_notify_smc_display_config_after_power_state_adjustment,
|
||||
pem_task_update_allowed_performance_levels,
|
||||
/* to do pem_task_Enable_disable_bapm, */
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_dynamic_state_management_tasks[] = {
|
||||
pem_task_unregister_interrupts,
|
||||
pem_task_get_boot_state_id,
|
||||
pem_task_disable_dynamic_state_management,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_clock_power_gatings_tasks[] = {
|
||||
pem_task_disable_clock_power_gatings_tasks,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action cleanup_asic_tasks[] = {
|
||||
/* PEM_Task_DisableFPS,*/
|
||||
pem_task_cleanup_asic,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action prepare_for_pnp_stop_tasks[] = {
|
||||
/* PEM_Task_PrepareForPnpStop,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_power_source_tasks[] = {
|
||||
pem_task_set_power_source,
|
||||
pem_task_notify_hw_of_power_source,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_power_saving_state_tasks[] = {
|
||||
pem_task_reset_power_saving_state,
|
||||
pem_task_get_power_saving_state,
|
||||
pem_task_set_power_saving_state,
|
||||
/* PEM_Task_ResetODDCState,
|
||||
* PEM_Task_GetODDCState,
|
||||
* PEM_Task_SetODDCState,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_disable_fps_tasks[] = {
|
||||
/* PEM_Task_EnableDisableFPS,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_nbmcu_state_tasks[] = {
|
||||
/* PEM_Task_NBMCUStateChange,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action reset_hardware_dc_notification_tasks[] = {
|
||||
/* PEM_Task_ResetHardwareDCNotification,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const pem_event_action notify_smu_suspend_tasks[] = {
|
||||
/* PEM_Task_NotifySMUSuspend,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_smc_firmware_ctf_tasks[] = {
|
||||
/* PEM_Task_DisableSMCFirmwareCTF,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_fps_tasks[] = {
|
||||
/* PEM_Task_DisableFPS,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action vari_bright_suspend_tasks[] = {
|
||||
/* PEM_Task_VariBright_Suspend,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action reset_fan_speed_to_default_tasks[] = {
|
||||
/* PEM_Task_ResetFanSpeedToDefault,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action power_down_asic_tasks[] = {
|
||||
/* PEM_Task_DisableFPS,*/
|
||||
pem_task_power_down_asic,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_stutter_mode_tasks[] = {
|
||||
/* PEM_Task_DisableStutterMode,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_connected_standby_tasks[] = {
|
||||
/* PEM_Task_SetConnectedStandby,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action block_hw_access_tasks[] = {
|
||||
pem_task_block_hw_access,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action unblock_hw_access_tasks[] = {
|
||||
pem_task_un_block_hw_access,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action resume_connected_standby_tasks[] = {
|
||||
/* PEM_Task_ResumeConnectedStandby,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action notify_smu_resume_tasks[] = {
|
||||
/* PEM_Task_NotifySMUResume,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action reset_display_configCounter_tasks[] = {
|
||||
pem_task_reset_display_phys_access,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action update_dal_configuration_tasks[] = {
|
||||
/* PEM_Task_CheckVBlankTime,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action vari_bright_resume_tasks[] = {
|
||||
/* PEM_Task_VariBright_Resume,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action notify_hw_power_source_tasks[] = {
|
||||
pem_task_notify_hw_of_power_source,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action process_vbios_event_info_tasks[] = {
|
||||
/* PEM_Task_ProcessVbiosEventInfo,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_gfx_clock_gating_tasks[] = {
|
||||
pem_task_enable_gfx_clock_gating,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_gfx_voltage_island_power_gating_tasks[] = {
|
||||
pem_task_enable_voltage_island_power_gating,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action reset_clock_gating_tasks[] = {
|
||||
/* PEM_Task_ResetClockGating*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action notify_smu_vpu_recovery_end_tasks[] = {
|
||||
/* PEM_Task_NotifySmuVPURecoveryEnd,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_vpu_cap_tasks[] = {
|
||||
/* PEM_Task_DisableVPUCap,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action execute_escape_sequence_tasks[] = {
|
||||
/* PEM_Task_ExecuteEscapesequence,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action notify_power_state_change_tasks[] = {
|
||||
pem_task_notify_power_state_change,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_cgpg_tasks[] = {
|
||||
pem_task_enable_cgpg,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_cgpg_tasks[] = {
|
||||
pem_task_disable_cgpg,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_user_2d_performance_tasks[] = {
|
||||
/* PEM_Task_SetUser2DPerformanceFlag,*/
|
||||
/* PEM_Task_UpdateUser2DPerformanceEnableEvents,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action add_user_2d_performance_state_tasks[] = {
|
||||
/* PEM_Task_Get2DPerformanceTemplate,*/
|
||||
/* PEM_Task_AllocateNewPowerStateMemory,*/
|
||||
/* PEM_Task_CopyNewPowerStateInfo,*/
|
||||
/* PEM_Task_UpdateNewPowerStateClocks,*/
|
||||
/* PEM_Task_UpdateNewPowerStateUser2DPerformanceFlag,*/
|
||||
/* PEM_Task_AddPowerState,*/
|
||||
/* PEM_Task_ReleaseNewPowerStateMemory,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action delete_user_2d_performance_state_tasks[] = {
|
||||
/* PEM_Task_GetCurrentUser2DPerformanceStateID,*/
|
||||
/* PEM_Task_DeletePowerState,*/
|
||||
/* PEM_Task_SetCurrentUser2DPerformanceStateID,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action disable_user_2d_performance_tasks[] = {
|
||||
/* PEM_Task_ResetUser2DPerformanceFlag,*/
|
||||
/* PEM_Task_UpdateUser2DPerformanceDisableEvents,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_stutter_mode_tasks[] = {
|
||||
pem_task_enable_stutter_mode,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action enable_disable_bapm_tasks[] = {
|
||||
/*PEM_Task_EnableDisableBAPM,*/
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action reset_boot_state_tasks[] = {
|
||||
pem_task_reset_boot_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action create_new_user_performance_state_tasks[] = {
|
||||
pem_task_create_user_performance_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action initialize_thermal_controller_tasks[] = {
|
||||
pem_task_initialize_thermal_controller,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action uninitialize_thermal_controller_tasks[] = {
|
||||
pem_task_uninitialize_thermal_controller,
|
||||
NULL
|
||||
};
|
||||
|
||||
const pem_event_action set_cpu_power_state[] = {
|
||||
pem_task_set_cpu_power_state,
|
||||
NULL
|
||||
};
|
||||
100
drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
Normal file
100
drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 _EVENT_SUB_CHAINS_H_
|
||||
#define _EVENT_SUB_CHAINS_H_
|
||||
|
||||
#include "eventmgr.h"
|
||||
|
||||
extern const pem_event_action reset_display_phy_access_tasks[];
|
||||
extern const pem_event_action broadcast_power_policy_tasks[];
|
||||
extern const pem_event_action unregister_interrupt_tasks[];
|
||||
extern const pem_event_action disable_GFX_voltage_island_powergating_tasks[];
|
||||
extern const pem_event_action disable_GFX_clockgating_tasks[];
|
||||
extern const pem_event_action block_adjust_power_state_tasks[];
|
||||
extern const pem_event_action unblock_adjust_power_state_tasks[];
|
||||
extern const pem_event_action set_performance_state_tasks[];
|
||||
extern const pem_event_action get_2D_performance_state_tasks[];
|
||||
extern const pem_event_action conditionally_force3D_performance_state_tasks[];
|
||||
extern const pem_event_action process_vbios_eventinfo_tasks[];
|
||||
extern const pem_event_action enable_dynamic_state_management_tasks[];
|
||||
extern const pem_event_action enable_clock_power_gatings_tasks[];
|
||||
extern const pem_event_action conditionally_force3D_performance_state_tasks[];
|
||||
extern const pem_event_action setup_asic_tasks[];
|
||||
extern const pem_event_action power_budget_tasks[];
|
||||
extern const pem_event_action system_config_tasks[];
|
||||
extern const pem_event_action get_2d_performance_state_tasks[];
|
||||
extern const pem_event_action conditionally_force_3d_performance_state_tasks[];
|
||||
extern const pem_event_action ungate_all_display_phys_tasks[];
|
||||
extern const pem_event_action uninitialize_display_phy_access_tasks[];
|
||||
extern const pem_event_action disable_gfx_voltage_island_power_gating_tasks[];
|
||||
extern const pem_event_action disable_gfx_clock_gating_tasks[];
|
||||
extern const pem_event_action set_boot_state_tasks[];
|
||||
extern const pem_event_action adjust_power_state_tasks[];
|
||||
extern const pem_event_action disable_dynamic_state_management_tasks[];
|
||||
extern const pem_event_action disable_clock_power_gatings_tasks[];
|
||||
extern const pem_event_action cleanup_asic_tasks[];
|
||||
extern const pem_event_action prepare_for_pnp_stop_tasks[];
|
||||
extern const pem_event_action set_power_source_tasks[];
|
||||
extern const pem_event_action set_power_saving_state_tasks[];
|
||||
extern const pem_event_action enable_disable_fps_tasks[];
|
||||
extern const pem_event_action set_nbmcu_state_tasks[];
|
||||
extern const pem_event_action reset_hardware_dc_notification_tasks[];
|
||||
extern const pem_event_action notify_smu_suspend_tasks[];
|
||||
extern const pem_event_action disable_smc_firmware_ctf_tasks[];
|
||||
extern const pem_event_action disable_fps_tasks[];
|
||||
extern const pem_event_action vari_bright_suspend_tasks[];
|
||||
extern const pem_event_action reset_fan_speed_to_default_tasks[];
|
||||
extern const pem_event_action power_down_asic_tasks[];
|
||||
extern const pem_event_action disable_stutter_mode_tasks[];
|
||||
extern const pem_event_action set_connected_standby_tasks[];
|
||||
extern const pem_event_action block_hw_access_tasks[];
|
||||
extern const pem_event_action unblock_hw_access_tasks[];
|
||||
extern const pem_event_action resume_connected_standby_tasks[];
|
||||
extern const pem_event_action notify_smu_resume_tasks[];
|
||||
extern const pem_event_action reset_display_configCounter_tasks[];
|
||||
extern const pem_event_action update_dal_configuration_tasks[];
|
||||
extern const pem_event_action vari_bright_resume_tasks[];
|
||||
extern const pem_event_action notify_hw_power_source_tasks[];
|
||||
extern const pem_event_action process_vbios_event_info_tasks[];
|
||||
extern const pem_event_action enable_gfx_clock_gating_tasks[];
|
||||
extern const pem_event_action enable_gfx_voltage_island_power_gating_tasks[];
|
||||
extern const pem_event_action reset_clock_gating_tasks[];
|
||||
extern const pem_event_action notify_smu_vpu_recovery_end_tasks[];
|
||||
extern const pem_event_action disable_vpu_cap_tasks[];
|
||||
extern const pem_event_action execute_escape_sequence_tasks[];
|
||||
extern const pem_event_action notify_power_state_change_tasks[];
|
||||
extern const pem_event_action enable_cgpg_tasks[];
|
||||
extern const pem_event_action disable_cgpg_tasks[];
|
||||
extern const pem_event_action enable_user_2d_performance_tasks[];
|
||||
extern const pem_event_action add_user_2d_performance_state_tasks[];
|
||||
extern const pem_event_action delete_user_2d_performance_state_tasks[];
|
||||
extern const pem_event_action disable_user_2d_performance_tasks[];
|
||||
extern const pem_event_action enable_stutter_mode_tasks[];
|
||||
extern const pem_event_action enable_disable_bapm_tasks[];
|
||||
extern const pem_event_action reset_boot_state_tasks[];
|
||||
extern const pem_event_action create_new_user_performance_state_tasks[];
|
||||
extern const pem_event_action initialize_thermal_controller_tasks[];
|
||||
extern const pem_event_action uninitialize_thermal_controller_tasks[];
|
||||
extern const pem_event_action set_cpu_power_state[];
|
||||
#endif /* _EVENT_SUB_CHAINS_H_ */
|
||||
438
drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
Normal file
438
drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* 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 "eventmgr.h"
|
||||
#include "eventinit.h"
|
||||
#include "eventmanagement.h"
|
||||
#include "eventmanager.h"
|
||||
#include "hardwaremanager.h"
|
||||
#include "eventtasks.h"
|
||||
#include "power_state.h"
|
||||
#include "hwmgr.h"
|
||||
#include "amd_powerplay.h"
|
||||
#include "psm.h"
|
||||
|
||||
#define TEMP_RANGE_MIN (90 * 1000)
|
||||
#define TEMP_RANGE_MAX (120 * 1000)
|
||||
|
||||
int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
|
||||
if (pem_is_hw_access_blocked(eventmgr))
|
||||
return 0;
|
||||
|
||||
phm_force_dpm_levels(eventmgr->hwmgr, AMD_DPM_FORCED_LEVEL_AUTO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* eventtasks_generic.c */
|
||||
int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if (pem_is_hw_access_blocked(eventmgr))
|
||||
return 0;
|
||||
|
||||
hwmgr = eventmgr->hwmgr;
|
||||
if (event_data->pnew_power_state != NULL)
|
||||
hwmgr->request_ps = event_data->pnew_power_state;
|
||||
|
||||
if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
|
||||
psm_adjust_power_state_dynamic(eventmgr, event_data->skip_state_adjust_rules);
|
||||
else
|
||||
psm_adjust_power_state_static(eventmgr, event_data->skip_state_adjust_rules);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_power_down_asic(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
|
||||
return psm_set_states(eventmgr, &(event_data->requested_state_id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return pem_unregister_interrupts(eventmgr);
|
||||
}
|
||||
|
||||
int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = psm_get_state_by_classification(eventmgr,
|
||||
PP_StateClassificationFlag_Boot,
|
||||
&(event_data->requested_state_id)
|
||||
);
|
||||
|
||||
if (0 == result)
|
||||
pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
|
||||
else
|
||||
pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_enable_dynamic_state_management(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_enable_clock_power_gatings(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_powerdown_uvd(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
phm_powergate_uvd(eventmgr->hwmgr, true);
|
||||
phm_powergate_vce(eventmgr->hwmgr, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_setup_asic(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_store_dal_configuration(struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
/*phm_store_dal_configuration_data(eventmgr->hwmgr, display_config) */
|
||||
}
|
||||
|
||||
int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
if (pem_is_hw_access_blocked(eventmgr))
|
||||
return 0;
|
||||
|
||||
return phm_display_configuration_changed(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
if (pem_is_hw_access_blocked(eventmgr))
|
||||
return 0;
|
||||
|
||||
return phm_notify_smc_display_config_after_ps_adjustment(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
eventmgr->block_adjust_power_state = true;
|
||||
/* to do PHM_ResetIPSCounter(pEventMgr->pHwMgr);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
eventmgr->block_adjust_power_state = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_set_cpu_power_state(eventmgr->hwmgr);
|
||||
}
|
||||
|
||||
/*powersaving*/
|
||||
|
||||
int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_enable_clock_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* performance */
|
||||
int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
|
||||
return psm_set_states(eventmgr, &(event_data->requested_state_id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (eventmgr->features[PP_Feature_PowerPlay].supported &&
|
||||
!(eventmgr->features[PP_Feature_PowerPlay].enabled))
|
||||
result = psm_get_state_by_classification(eventmgr,
|
||||
PP_StateClassificationFlag_Boot,
|
||||
&(event_data->requested_state_id));
|
||||
else if (eventmgr->features[PP_Feature_User2DPerformance].enabled)
|
||||
result = psm_get_state_by_classification(eventmgr,
|
||||
PP_StateClassificationFlag_User2DPerformance,
|
||||
&(event_data->requested_state_id));
|
||||
else
|
||||
result = psm_get_ui_state(eventmgr, PP_StateUILabel_Performance,
|
||||
&(event_data->requested_state_id));
|
||||
|
||||
if (0 == result)
|
||||
pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
|
||||
else
|
||||
pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
struct pp_power_state *state;
|
||||
int table_entries;
|
||||
struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
|
||||
int i;
|
||||
|
||||
table_entries = hwmgr->num_ps;
|
||||
state = hwmgr->ps;
|
||||
|
||||
restart_search:
|
||||
for (i = 0; i < table_entries; i++) {
|
||||
if (state->classification.ui_label & event_data->requested_ui_label) {
|
||||
event_data->pnew_power_state = state;
|
||||
return 0;
|
||||
}
|
||||
state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
|
||||
}
|
||||
|
||||
switch (event_data->requested_ui_label) {
|
||||
case PP_StateUILabel_Battery:
|
||||
case PP_StateUILabel_Balanced:
|
||||
event_data->requested_ui_label = PP_StateUILabel_Performance;
|
||||
goto restart_search;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
struct PP_TemperatureRange range;
|
||||
|
||||
range.max = TEMP_RANGE_MAX;
|
||||
range.min = TEMP_RANGE_MIN;
|
||||
|
||||
if (eventmgr == NULL || eventmgr->platform_descriptor == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ThermalController))
|
||||
return phm_start_thermal_controller(eventmgr->hwmgr, &range);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
|
||||
{
|
||||
return phm_stop_thermal_controller(eventmgr->hwmgr);
|
||||
}
|
||||
88
drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
Normal file
88
drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 _EVENT_TASKS_H_
|
||||
#define _EVENT_TASKS_H_
|
||||
#include "eventmgr.h"
|
||||
|
||||
struct amd_display_configuration;
|
||||
|
||||
/* eventtasks_generic.c */
|
||||
int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_store_dal_configuration (struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config);
|
||||
int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
/*powersaving*/
|
||||
|
||||
int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
|
||||
/* performance */
|
||||
int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
/*thermal */
|
||||
int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
|
||||
|
||||
#endif /* _EVENT_TASKS_H_ */
|
||||
117
drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
Normal file
117
drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 "psm.h"
|
||||
|
||||
int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id)
|
||||
{
|
||||
struct pp_power_state *state;
|
||||
int table_entries;
|
||||
struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
|
||||
int i;
|
||||
|
||||
table_entries = hwmgr->num_ps;
|
||||
state = hwmgr->ps;
|
||||
|
||||
for (i = 0; i < table_entries; i++) {
|
||||
if (state->classification.ui_label & ui_label) {
|
||||
*state_id = state->id;
|
||||
return 0;
|
||||
}
|
||||
state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id)
|
||||
{
|
||||
struct pp_power_state *state;
|
||||
int table_entries;
|
||||
struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
|
||||
int i;
|
||||
|
||||
table_entries = hwmgr->num_ps;
|
||||
state = hwmgr->ps;
|
||||
|
||||
for (i = 0; i < table_entries; i++) {
|
||||
if (state->classification.flags & flag) {
|
||||
*state_id = state->id;
|
||||
return 0;
|
||||
}
|
||||
state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id)
|
||||
{
|
||||
struct pp_power_state *state;
|
||||
int table_entries;
|
||||
struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
|
||||
int i;
|
||||
|
||||
table_entries = hwmgr->num_ps;
|
||||
state = hwmgr->ps;
|
||||
|
||||
for (i = 0; i < table_entries; i++) {
|
||||
if (state->id == *state_id) {
|
||||
hwmgr->request_ps = state;
|
||||
return 0;
|
||||
}
|
||||
state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip)
|
||||
{
|
||||
|
||||
struct pp_power_state *pcurrent;
|
||||
struct pp_power_state *requested;
|
||||
struct pp_hwmgr *hwmgr;
|
||||
bool equal;
|
||||
|
||||
if (skip)
|
||||
return 0;
|
||||
|
||||
hwmgr = eventmgr->hwmgr;
|
||||
pcurrent = hwmgr->current_ps;
|
||||
requested = hwmgr->request_ps;
|
||||
|
||||
if (requested == NULL)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
hwmgr->current_ps = requested;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
38
drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
Normal file
38
drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "eventmgr.h"
|
||||
#include "eventinit.h"
|
||||
#include "eventmanagement.h"
|
||||
#include "eventmanager.h"
|
||||
#include "power_state.h"
|
||||
#include "hardwaremanager.h"
|
||||
|
||||
int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id);
|
||||
|
||||
int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id);
|
||||
|
||||
int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id);
|
||||
|
||||
int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip);
|
||||
|
||||
int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip);
|
||||
15
drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
Normal file
15
drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Makefile for the 'hw manager' sub-component of powerplay.
|
||||
# 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_processpptables.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
|
||||
|
||||
AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
|
||||
|
||||
AMD_POWERPLAY_FILES += $(AMD_PP_HWMGR)
|
||||
252
drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
Normal file
252
drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* 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 "cz_clockpowergating.h"
|
||||
#include "cz_ppsmc.h"
|
||||
|
||||
/* PhyID -> Status Mapping in DDI_PHY_GEN_STATUS
|
||||
0 GFX0L (3:0), (27:24),
|
||||
1 GFX0H (7:4), (31:28),
|
||||
2 GFX1L (3:0), (19:16),
|
||||
3 GFX1H (7:4), (23:20),
|
||||
4 DDIL (3:0), (11: 8),
|
||||
5 DDIH (7:4), (15:12),
|
||||
6 DDI2L (3:0), ( 3: 0),
|
||||
7 DDI2H (7:4), ( 7: 4),
|
||||
*/
|
||||
#define DDI_PHY_GEN_STATUS_VAL(phyID) (1 << ((3 - ((phyID & 0x07)/2))*8 + (phyID & 0x01)*4))
|
||||
#define IS_PHY_ID_USED_BY_PLL(PhyID) (((0xF3 & (1 << PhyID)) & 0xFF) ? true : false)
|
||||
|
||||
|
||||
int cz_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 = cz_dpm_powerdown_uvd(hwmgr);
|
||||
else
|
||||
ret = cz_dpm_powerup_uvd(hwmgr);
|
||||
break;
|
||||
case PHM_AsicBlock_GFX:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool cz_phm_is_safe_for_asic_block(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, enum PHM_AsicBlock block)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int cz_phm_enable_disable_gfx_power_gating(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_phm_smu_power_up_down_pcie(struct pp_hwmgr *hwmgr, uint32_t target, bool up, uint32_t args)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_phm_initialize_display_phy_access(struct pp_hwmgr *hwmgr, bool initialize, bool accesshw)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_phm_get_display_phy_access_info(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_phm_gate_unused_display_phys(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_phm_ungate_all_display_phys(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cz_tf_uvd_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cz_tf_vce_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
uint32_t dpm_features = 0;
|
||||
|
||||
if (enable &&
|
||||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_UVDDPM)) {
|
||||
cz_hwmgr->dpm_flags |= DPMFlags_UVD_Enabled;
|
||||
dpm_features |= UVD_DPM_MASK;
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
|
||||
} else {
|
||||
dpm_features |= UVD_DPM_MASK;
|
||||
cz_hwmgr->dpm_flags &= ~DPMFlags_UVD_Enabled;
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
uint32_t dpm_features = 0;
|
||||
|
||||
if (enable && phm_cap_enabled(
|
||||
hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_VCEDPM)) {
|
||||
cz_hwmgr->dpm_flags |= DPMFlags_VCE_Enabled;
|
||||
dpm_features |= VCE_DPM_MASK;
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
|
||||
} else {
|
||||
dpm_features |= VCE_DPM_MASK;
|
||||
cz_hwmgr->dpm_flags &= ~DPMFlags_VCE_Enabled;
|
||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||
PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (cz_hwmgr->uvd_power_gated == bgate)
|
||||
return 0;
|
||||
|
||||
cz_hwmgr->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);
|
||||
cz_dpm_update_uvd_dpm(hwmgr, true);
|
||||
cz_dpm_powerdown_uvd(hwmgr);
|
||||
} else {
|
||||
cz_dpm_powerup_uvd(hwmgr);
|
||||
cgs_set_clockgating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_PG_STATE_GATE);
|
||||
cgs_set_powergating_state(hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
cz_dpm_update_uvd_dpm(hwmgr, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
|
||||
{
|
||||
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_VCEPowerGating)) {
|
||||
if (cz_hwmgr->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);
|
||||
cz_enable_disable_vce_dpm(hwmgr, false);
|
||||
/* TODO: to figure out why vce can't be poweroff*/
|
||||
cz_hwmgr->vce_power_gated = true;
|
||||
} else {
|
||||
cz_dpm_powerup_vce(hwmgr);
|
||||
cz_hwmgr->vce_power_gated = false;
|
||||
cgs_set_clockgating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_GATE);
|
||||
cgs_set_powergating_state(
|
||||
hwmgr->device,
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
cz_dpm_update_vce_dpm(hwmgr);
|
||||
cz_enable_disable_vce_dpm(hwmgr, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cz_dpm_update_vce_dpm(hwmgr);
|
||||
cz_enable_disable_vce_dpm(hwmgr, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cz_hwmgr->vce_power_gated)
|
||||
cz_dpm_update_vce_dpm(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct phm_master_table_item cz_enable_clock_power_gatings_list[] = {
|
||||
/*we don't need an exit table here, because there is only D3 cold on Kv*/
|
||||
{ phm_cf_want_uvd_power_gating, cz_tf_uvd_power_gating_initialize },
|
||||
{ phm_cf_want_vce_power_gating, cz_tf_vce_power_gating_initialize },
|
||||
/* to do { NULL, cz_tf_xdma_power_gating_enable }, */
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
struct phm_master_table_header cz_phm_enable_clock_power_gatings_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
cz_enable_clock_power_gatings_list
|
||||
};
|
||||
37
drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
Normal file
37
drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 _CZ_CLOCK_POWER_GATING_H_
|
||||
#define _CZ_CLOCK_POWER_GATING_H_
|
||||
|
||||
#include "cz_hwmgr.h"
|
||||
#include "pp_asicblocks.h"
|
||||
|
||||
extern int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
|
||||
extern struct phm_master_table_header cz_phm_enable_clock_power_gatings_master;
|
||||
extern struct phm_master_table_header cz_phm_disable_clock_power_gatings_master;
|
||||
extern int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
extern int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
extern int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
|
||||
#endif /* _CZ_CLOCK_POWER_GATING_H_ */
|
||||
1737
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
Normal file
1737
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
Normal file
File diff suppressed because it is too large
Load diff
326
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
Normal file
326
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* 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 _CZ_HWMGR_H_
|
||||
#define _CZ_HWMGR_H_
|
||||
|
||||
#include "cgs_common.h"
|
||||
#include "ppatomctrl.h"
|
||||
|
||||
#define CZ_NUM_NBPSTATES 4
|
||||
#define CZ_NUM_NBPMEMORYCLOCK 2
|
||||
#define MAX_DISPLAY_CLOCK_LEVEL 8
|
||||
#define CZ_AT_DFLT 30
|
||||
#define CZ_MAX_HARDWARE_POWERLEVELS 8
|
||||
#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
|
||||
#define CZ_MIN_DEEP_SLEEP_SCLK 800
|
||||
|
||||
/* Carrizo device IDs */
|
||||
#define DEVICE_ID_CZ_9870 0x9870
|
||||
#define DEVICE_ID_CZ_9874 0x9874
|
||||
#define DEVICE_ID_CZ_9875 0x9875
|
||||
#define DEVICE_ID_CZ_9876 0x9876
|
||||
#define DEVICE_ID_CZ_9877 0x9877
|
||||
|
||||
#define PHMCZ_WRITE_SMC_REGISTER(device, reg, value) \
|
||||
cgs_write_ind_register(device, CGS_IND_REG__SMC, ix##reg, value)
|
||||
|
||||
struct cz_dpm_entry {
|
||||
uint32_t soft_min_clk;
|
||||
uint32_t hard_min_clk;
|
||||
uint32_t soft_max_clk;
|
||||
uint32_t hard_max_clk;
|
||||
};
|
||||
|
||||
struct cz_sys_info {
|
||||
uint32_t bootup_uma_clock;
|
||||
uint32_t bootup_engine_clock;
|
||||
uint32_t dentist_vco_freq;
|
||||
uint32_t nb_dpm_enable;
|
||||
uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK];
|
||||
uint32_t nbp_n_clock[CZ_NUM_NBPSTATES];
|
||||
uint16_t nbp_voltage_index[CZ_NUM_NBPSTATES];
|
||||
uint32_t display_clock[MAX_DISPLAY_CLOCK_LEVEL];
|
||||
uint16_t bootup_nb_voltage_index;
|
||||
uint8_t htc_tmp_lmt;
|
||||
uint8_t htc_hyst_lmt;
|
||||
uint32_t system_config;
|
||||
uint32_t uma_channel_number;
|
||||
};
|
||||
|
||||
#define MAX_DISPLAYPHY_IDS 0x8
|
||||
#define DISPLAYPHY_LANEMASK 0xF
|
||||
#define UNKNOWN_TRANSMITTER_PHY_ID (-1)
|
||||
|
||||
#define DISPLAYPHY_PHYID_SHIFT 24
|
||||
#define DISPLAYPHY_LANESELECT_SHIFT 16
|
||||
|
||||
#define DISPLAYPHY_RX_SELECT 0x1
|
||||
#define DISPLAYPHY_TX_SELECT 0x2
|
||||
#define DISPLAYPHY_CORE_SELECT 0x4
|
||||
|
||||
#define DDI_POWERGATING_ARG(phyID, lanemask, rx, tx, core) \
|
||||
(((uint32_t)(phyID))<<DISPLAYPHY_PHYID_SHIFT | \
|
||||
((uint32_t)(lanemask))<<DISPLAYPHY_LANESELECT_SHIFT | \
|
||||
((rx) ? DISPLAYPHY_RX_SELECT : 0) | \
|
||||
((tx) ? DISPLAYPHY_TX_SELECT : 0) | \
|
||||
((core) ? DISPLAYPHY_CORE_SELECT : 0))
|
||||
|
||||
struct cz_display_phy_info_entry {
|
||||
uint8_t phy_present;
|
||||
uint8_t active_lane_mapping;
|
||||
uint8_t display_config_type;
|
||||
uint8_t active_number_of_lanes;
|
||||
};
|
||||
|
||||
#define CZ_MAX_DISPLAYPHY_IDS 10
|
||||
|
||||
struct cz_display_phy_info {
|
||||
bool display_phy_access_initialized;
|
||||
struct cz_display_phy_info_entry entries[CZ_MAX_DISPLAYPHY_IDS];
|
||||
};
|
||||
|
||||
struct cz_power_level {
|
||||
uint32_t engineClock;
|
||||
uint8_t vddcIndex;
|
||||
uint8_t dsDividerIndex;
|
||||
uint8_t ssDividerIndex;
|
||||
uint8_t allowGnbSlow;
|
||||
uint8_t forceNBPstate;
|
||||
uint8_t display_wm;
|
||||
uint8_t vce_wm;
|
||||
uint8_t numSIMDToPowerDown;
|
||||
uint8_t hysteresis_up;
|
||||
uint8_t rsv[3];
|
||||
};
|
||||
|
||||
struct cz_uvd_clocks {
|
||||
uint32_t vclk;
|
||||
uint32_t dclk;
|
||||
uint32_t vclk_low_divider;
|
||||
uint32_t vclk_high_divider;
|
||||
uint32_t dclk_low_divider;
|
||||
uint32_t dclk_high_divider;
|
||||
};
|
||||
|
||||
enum cz_pstate_previous_action {
|
||||
DO_NOTHING = 1,
|
||||
FORCE_HIGH,
|
||||
CANCEL_FORCE_HIGH
|
||||
};
|
||||
|
||||
struct pp_disable_nb_ps_flags {
|
||||
union {
|
||||
struct {
|
||||
uint32_t entry : 1;
|
||||
uint32_t display : 1;
|
||||
uint32_t driver: 1;
|
||||
uint32_t vce : 1;
|
||||
uint32_t uvd : 1;
|
||||
uint32_t acp : 1;
|
||||
uint32_t reserved: 26;
|
||||
} bits;
|
||||
uint32_t u32All;
|
||||
};
|
||||
};
|
||||
|
||||
struct cz_power_state {
|
||||
unsigned int magic;
|
||||
uint32_t level;
|
||||
struct cz_uvd_clocks uvd_clocks;
|
||||
uint32_t evclk;
|
||||
uint32_t ecclk;
|
||||
uint32_t samclk;
|
||||
uint32_t acpclk;
|
||||
bool need_dfs_bypass;
|
||||
uint32_t nbps_flags;
|
||||
uint32_t bapm_flags;
|
||||
uint8_t dpm_0_pg_nb_ps_low;
|
||||
uint8_t dpm_0_pg_nb_ps_high;
|
||||
uint8_t dpm_x_nb_ps_low;
|
||||
uint8_t dpm_x_nb_ps_high;
|
||||
enum cz_pstate_previous_action action;
|
||||
struct cz_power_level levels[CZ_MAX_HARDWARE_POWERLEVELS];
|
||||
struct pp_disable_nb_ps_flags disable_nb_ps_flag;
|
||||
};
|
||||
|
||||
#define DPMFlags_SCLK_Enabled 0x00000001
|
||||
#define DPMFlags_UVD_Enabled 0x00000002
|
||||
#define DPMFlags_VCE_Enabled 0x00000004
|
||||
#define DPMFlags_ACP_Enabled 0x00000008
|
||||
#define DPMFlags_ForceHighestValid 0x40000000
|
||||
#define DPMFlags_Debug 0x80000000
|
||||
|
||||
#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 /* bit 0 */
|
||||
#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000
|
||||
#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000 /* bit 23 */
|
||||
#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000 /* bit 24 */
|
||||
|
||||
struct cc6_settings {
|
||||
bool cc6_setting_changed;
|
||||
bool nb_pstate_switch_disable;/* controls NB PState switch */
|
||||
bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
|
||||
bool cpu_pstate_disable;
|
||||
uint32_t cpu_pstate_separation_time;
|
||||
};
|
||||
|
||||
struct cz_hwmgr {
|
||||
uint32_t activity_target[CZ_MAX_HARDWARE_POWERLEVELS];
|
||||
uint32_t dpm_interval;
|
||||
|
||||
uint32_t voltage_drop_threshold;
|
||||
|
||||
uint32_t voting_rights_clients;
|
||||
|
||||
uint32_t disable_driver_thermal_policy;
|
||||
|
||||
uint32_t static_screen_threshold;
|
||||
|
||||
uint32_t gfx_power_gating_threshold;
|
||||
|
||||
uint32_t activity_hysteresis;
|
||||
uint32_t bootup_sclk_divider;
|
||||
uint32_t gfx_ramp_step;
|
||||
uint32_t gfx_ramp_delay; /* in micro-seconds */
|
||||
|
||||
uint32_t thermal_auto_throttling_treshold;
|
||||
|
||||
struct cz_sys_info sys_info;
|
||||
|
||||
struct cz_power_level boot_power_level;
|
||||
struct cz_power_state *cz_current_ps;
|
||||
struct cz_power_state *cz_requested_ps;
|
||||
|
||||
uint32_t mgcg_cgtt_local0;
|
||||
uint32_t mgcg_cgtt_local1;
|
||||
|
||||
uint32_t tdr_clock; /* in 10khz unit */
|
||||
|
||||
uint32_t ddi_power_gating_disabled;
|
||||
uint32_t disable_gfx_power_gating_in_uvd;
|
||||
uint32_t disable_nb_ps3_in_battery;
|
||||
|
||||
uint32_t lock_nb_ps_in_uvd_play_back;
|
||||
|
||||
struct cz_display_phy_info display_phy_info;
|
||||
uint32_t vce_slow_sclk_threshold; /* default 200mhz */
|
||||
uint32_t dce_slow_sclk_threshold; /* default 300mhz */
|
||||
uint32_t min_sclk_did; /* minimum sclk divider */
|
||||
|
||||
bool disp_clk_bypass;
|
||||
bool disp_clk_bypass_pending;
|
||||
uint32_t bapm_enabled;
|
||||
uint32_t clock_slow_down_freq;
|
||||
uint32_t skip_clock_slow_down;
|
||||
uint32_t enable_nb_ps_policy;
|
||||
uint32_t voltage_drop_in_dce_power_gating;
|
||||
uint32_t uvd_dpm_interval;
|
||||
uint32_t override_dynamic_mgpg;
|
||||
uint32_t lclk_deep_enabled;
|
||||
|
||||
uint32_t uvd_performance;
|
||||
|
||||
bool video_start;
|
||||
bool battery_state;
|
||||
uint32_t lowest_valid;
|
||||
uint32_t highest_valid;
|
||||
uint32_t high_voltage_threshold;
|
||||
uint32_t is_nb_dpm_enabled;
|
||||
struct cc6_settings cc6_settings;
|
||||
uint32_t is_voltage_island_enabled;
|
||||
|
||||
bool pgacpinit;
|
||||
|
||||
uint8_t disp_config;
|
||||
|
||||
/* PowerTune */
|
||||
uint32_t power_containment_features;
|
||||
bool cac_enabled;
|
||||
bool disable_uvd_power_tune_feature;
|
||||
bool enable_ba_pm_feature;
|
||||
bool enable_tdc_limit_feature;
|
||||
|
||||
uint32_t sram_end;
|
||||
uint32_t dpm_table_start;
|
||||
uint32_t soft_regs_start;
|
||||
|
||||
uint8_t uvd_level_count;
|
||||
uint8_t vce_level_count;
|
||||
|
||||
uint8_t acp_level_count;
|
||||
uint8_t samu_level_count;
|
||||
uint32_t fps_high_threshold;
|
||||
uint32_t fps_low_threshold;
|
||||
|
||||
uint32_t dpm_flags;
|
||||
struct cz_dpm_entry sclk_dpm;
|
||||
struct cz_dpm_entry uvd_dpm;
|
||||
struct cz_dpm_entry vce_dpm;
|
||||
struct cz_dpm_entry acp_dpm;
|
||||
|
||||
uint8_t uvd_boot_level;
|
||||
uint8_t vce_boot_level;
|
||||
uint8_t acp_boot_level;
|
||||
uint8_t samu_boot_level;
|
||||
uint8_t uvd_interval;
|
||||
uint8_t vce_interval;
|
||||
uint8_t acp_interval;
|
||||
uint8_t samu_interval;
|
||||
|
||||
uint8_t graphics_interval;
|
||||
uint8_t graphics_therm_throttle_enable;
|
||||
uint8_t graphics_voltage_change_enable;
|
||||
|
||||
uint8_t graphics_clk_slow_enable;
|
||||
uint8_t graphics_clk_slow_divider;
|
||||
|
||||
uint32_t display_cac;
|
||||
uint32_t low_sclk_interrupt_threshold;
|
||||
|
||||
uint32_t dram_log_addr_h;
|
||||
uint32_t dram_log_addr_l;
|
||||
uint32_t dram_log_phy_addr_h;
|
||||
uint32_t dram_log_phy_addr_l;
|
||||
uint32_t dram_log_buff_size;
|
||||
|
||||
bool uvd_power_gated;
|
||||
bool vce_power_gated;
|
||||
bool samu_power_gated;
|
||||
bool acp_power_gated;
|
||||
bool acp_power_up_no_dsp;
|
||||
uint32_t active_process_mask;
|
||||
|
||||
uint32_t max_sclk_level;
|
||||
uint32_t num_of_clk_entries;
|
||||
};
|
||||
|
||||
struct pp_hwmgr;
|
||||
|
||||
int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
|
||||
int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr);
|
||||
int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr);
|
||||
int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr);
|
||||
int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr);
|
||||
int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
|
||||
int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr);
|
||||
#endif /* _CZ_HWMGR_H_ */
|
||||
114
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
Normal file
114
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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)
|
||||
fiji_update_uvd_dpm(hwmgr, true);
|
||||
else
|
||||
fiji_update_uvd_dpm(hwmgr, false);
|
||||
|
||||
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;
|
||||
}
|
||||
35
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
Normal file
35
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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_CLOCK_POWER_GATING_H_
|
||||
#define _FIJI_CLOCK_POWER_GATING_H_
|
||||
|
||||
#include "fiji_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_ */
|
||||
105
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
Normal file
105
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
5127
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
Normal file
5127
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
Normal file
File diff suppressed because it is too large
Load diff
361
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
Normal file
361
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#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;
|
||||
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_hwmgr_backend_fini(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);
|
||||
|
||||
#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
|
||||
#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
|
||||
|
||||
#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
|
||||
#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
|
||||
|
||||
#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
|
||||
#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
|
||||
|
||||
#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
|
||||
|
||||
#endif /* _FIJI_HWMGR_H_ */
|
||||
553
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
Normal file
553
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
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_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);
|
||||
|
||||
fiji_hwmgr->dte_tj_offset = tmp;
|
||||
|
||||
if (!tmp) {
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment);
|
||||
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_CAC);
|
||||
|
||||
fiji_hwmgr->fast_watermark_threshold = 100;
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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_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_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;
|
||||
}
|
||||
66
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
Normal file
66
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
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_enable_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 */
|
||||
|
||||
687
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
Normal file
687
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
/*
|
||||
* 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 "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,
|
||||
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 fiji_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 fiji_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 fiji_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 fiji_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 fiji_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 fiji_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 fiji_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))
|
||||
fiji_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 * 100;
|
||||
do_div(tmp64, duty100);
|
||||
duty = (uint32_t)tmp64;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Fan Speed to default.
|
||||
* @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 result;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_MicrocodeFanControl)) {
|
||||
result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
|
||||
if (!result)
|
||||
result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
} else
|
||||
result = fiji_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 fiji_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;
|
||||
|
||||
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 fiji_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 fiji_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 = FIJI_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 fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
|
||||
uint32_t low_temp, uint32_t high_temp)
|
||||
{
|
||||
uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
|
||||
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
|
||||
uint32_t high = FIJI_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 fiji_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 fiji_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);
|
||||
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 fiji_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);
|
||||
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 fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = fiji_thermal_disable_alert(hwmgr);
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
fiji_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_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.
|
||||
* @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_fiji_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)) {
|
||||
fiji_fan_ctrl_start_smc_fan_control(hwmgr);
|
||||
fiji_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_fiji_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 fiji_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_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_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_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_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_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
|
||||
void *input, void *output, void *storage, int result)
|
||||
{
|
||||
return fiji_thermal_disable_alert(hwmgr);
|
||||
}
|
||||
|
||||
static 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},
|
||||
/* 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, NULL}
|
||||
};
|
||||
|
||||
static struct phm_master_table_header
|
||||
fiji_thermal_start_thermal_controller_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
fiji_thermal_start_thermal_controller_master_list
|
||||
};
|
||||
|
||||
static 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},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
struct phm_master_table_header
|
||||
fiji_thermal_set_temperature_range_master = {
|
||||
0,
|
||||
PHM_MasterTableFlag_None,
|
||||
fiji_thermal_set_temperature_range_master_list
|
||||
};
|
||||
|
||||
int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
fiji_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_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = phm_construct_table(hwmgr,
|
||||
&fiji_thermal_set_temperature_range_master,
|
||||
&(hwmgr->set_temperature_range));
|
||||
|
||||
if (!result) {
|
||||
result = phm_construct_table(hwmgr,
|
||||
&fiji_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;
|
||||
}
|
||||
|
||||
62
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
Normal file
62
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
155
drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
Normal file
155
drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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 <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "hwmgr.h"
|
||||
|
||||
static int phm_run_table(struct pp_hwmgr *hwmgr,
|
||||
struct phm_runtime_table_header *rt_table,
|
||||
void *input,
|
||||
void *output,
|
||||
void *temp_storage)
|
||||
{
|
||||
int result = 0;
|
||||
phm_table_function *function;
|
||||
|
||||
for (function = rt_table->function_list; NULL != *function; function++) {
|
||||
int tmp = (*function)(hwmgr, input, output, temp_storage, result);
|
||||
|
||||
if (tmp == PP_Result_TableImmediateExit)
|
||||
break;
|
||||
if (tmp) {
|
||||
if (0 == result)
|
||||
result = tmp;
|
||||
if (rt_table->exit_error)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int phm_dispatch_table(struct pp_hwmgr *hwmgr,
|
||||
struct phm_runtime_table_header *rt_table,
|
||||
void *input, void *output)
|
||||
{
|
||||
int result = 0;
|
||||
void *temp_storage = NULL;
|
||||
|
||||
if (hwmgr == NULL || rt_table == NULL || rt_table->function_list == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
|
||||
return 0; /*temp return ture because some function not implement on some asic */
|
||||
}
|
||||
|
||||
if (0 != rt_table->storage_size) {
|
||||
temp_storage = kzalloc(rt_table->storage_size, GFP_KERNEL);
|
||||
if (temp_storage == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Could not allocate table temporary storage\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
result = phm_run_table(hwmgr, rt_table, input, output, temp_storage);
|
||||
|
||||
if (NULL != temp_storage)
|
||||
kfree(temp_storage);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int phm_construct_table(struct pp_hwmgr *hwmgr,
|
||||
struct phm_master_table_header *master_table,
|
||||
struct phm_runtime_table_header *rt_table)
|
||||
{
|
||||
uint32_t function_count = 0;
|
||||
const struct phm_master_table_item *table_item;
|
||||
uint32_t size;
|
||||
phm_table_function *run_time_list;
|
||||
phm_table_function *rtf;
|
||||
|
||||
if (hwmgr == NULL || master_table == NULL || rt_table == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (table_item = master_table->master_list;
|
||||
NULL != table_item->tableFunction; table_item++) {
|
||||
if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
|
||||
(table_item->isFunctionNeededInRuntimeTable(hwmgr)))
|
||||
function_count++;
|
||||
}
|
||||
|
||||
size = (function_count + 1) * sizeof(phm_table_function);
|
||||
run_time_list = kzalloc(size, GFP_KERNEL);
|
||||
|
||||
if (NULL == run_time_list)
|
||||
return -ENOMEM;
|
||||
|
||||
rtf = run_time_list;
|
||||
for (table_item = master_table->master_list;
|
||||
NULL != table_item->tableFunction; table_item++) {
|
||||
if ((rtf - run_time_list) > function_count) {
|
||||
printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
|
||||
kfree(run_time_list);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
|
||||
(table_item->isFunctionNeededInRuntimeTable(hwmgr))) {
|
||||
*(rtf++) = table_item->tableFunction;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rtf - run_time_list) > function_count) {
|
||||
printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
|
||||
kfree(run_time_list);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*rtf = NULL;
|
||||
rt_table->function_list = run_time_list;
|
||||
rt_table->exit_error = (0 != (master_table->flags & PHM_MasterTableFlag_ExitOnError));
|
||||
rt_table->storage_size = master_table->storage_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_destroy_table(struct pp_hwmgr *hwmgr,
|
||||
struct phm_runtime_table_header *rt_table)
|
||||
{
|
||||
if (hwmgr == NULL || rt_table == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (NULL == rt_table->function_list)
|
||||
return 0;
|
||||
|
||||
kfree(rt_table->function_list);
|
||||
|
||||
rt_table->function_list = NULL;
|
||||
rt_table->storage_size = 0;
|
||||
rt_table->exit_error = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
334
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
Normal file
334
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* 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 <linux/errno.h>
|
||||
#include "hwmgr.h"
|
||||
#include "hardwaremanager.h"
|
||||
#include "power_state.h"
|
||||
#include "pp_acpi.h"
|
||||
#include "amd_acpi.h"
|
||||
#include "amd_powerplay.h"
|
||||
|
||||
#define PHM_FUNC_CHECK(hw) \
|
||||
do { \
|
||||
if ((hw) == NULL || (hw)->hwmgr_func == NULL) \
|
||||
return -EINVAL; \
|
||||
} while (0)
|
||||
|
||||
void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageTransition);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableEngineTransition);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMemoryTransition);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGClockGating);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGCGTSSM);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLSClockGating);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_Force3DClockSupport);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLightSleep);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMCLS);
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisablePowerGating);
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableDPM);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableSMUUVDHandshake);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalAutoThrottling);
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_NoOD5Support);
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UserMaxClockForMultiDisplays);
|
||||
|
||||
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VpuRecoveryInProgress);
|
||||
|
||||
if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) &&
|
||||
acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION))
|
||||
phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
|
||||
}
|
||||
|
||||
bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return hwmgr->block_hw_access;
|
||||
}
|
||||
|
||||
int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block)
|
||||
{
|
||||
hwmgr->block_hw_access = block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_setup_asic(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->asic_setup)
|
||||
return hwmgr->hwmgr_func->asic_setup(hwmgr);
|
||||
} else {
|
||||
return phm_dispatch_table(hwmgr, &(hwmgr->setup_asic),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_power_down_asic(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->power_off_asic)
|
||||
return hwmgr->hwmgr_func->power_off_asic(hwmgr);
|
||||
} else {
|
||||
return phm_dispatch_table(hwmgr, &(hwmgr->power_down_asic),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_set_power_state(struct pp_hwmgr *hwmgr,
|
||||
const struct pp_hw_power_state *pcurrent_state,
|
||||
const struct pp_hw_power_state *pnew_power_state)
|
||||
{
|
||||
struct phm_set_power_state_input states;
|
||||
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
states.pcurrent_state = pcurrent_state;
|
||||
states.pnew_state = pnew_power_state;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->power_state_set)
|
||||
return hwmgr->hwmgr_func->power_state_set(hwmgr, &states);
|
||||
} else {
|
||||
return phm_dispatch_table(hwmgr, &(hwmgr->set_power_state), &states, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable)
|
||||
return hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr);
|
||||
} else {
|
||||
return phm_dispatch_table(hwmgr,
|
||||
&(hwmgr->enable_dynamic_state_management),
|
||||
NULL, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->force_dpm_level != NULL)
|
||||
return hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
||||
struct pp_power_state *adjusted_ps,
|
||||
const struct pp_power_state *current_ps)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->apply_state_adjust_rules != NULL)
|
||||
return hwmgr->hwmgr_func->apply_state_adjust_rules(
|
||||
hwmgr,
|
||||
adjusted_ps,
|
||||
current_ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->powerdown_uvd != NULL)
|
||||
return hwmgr->hwmgr_func->powerdown_uvd(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->powergate_uvd != NULL)
|
||||
return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->powergate_vce != NULL)
|
||||
return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->enable_clock_power_gating)
|
||||
return hwmgr->hwmgr_func->enable_clock_power_gating(hwmgr);
|
||||
} else {
|
||||
return phm_dispatch_table(hwmgr, &(hwmgr->enable_clock_power_gatings), NULL, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface)) {
|
||||
if (NULL != hwmgr->hwmgr_func->display_config_changed)
|
||||
hwmgr->hwmgr_func->display_config_changed(hwmgr);
|
||||
} else
|
||||
return phm_dispatch_table(hwmgr, &hwmgr->display_configuration_changed, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_TablelessHardwareInterface))
|
||||
if (NULL != hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment)
|
||||
hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->stop_thermal_controller == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->stop_thermal_controller(hwmgr);
|
||||
}
|
||||
|
||||
int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->register_internal_thermal_interrupt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->register_internal_thermal_interrupt(hwmgr, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thermal controller subsystem.
|
||||
*
|
||||
* @param pHwMgr the address of the powerplay hardware manager.
|
||||
* @param pTemperatureRange the address of the structure holding the temperature range.
|
||||
* @exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher.
|
||||
*/
|
||||
int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range)
|
||||
{
|
||||
return phm_dispatch_table(hwmgr, &(hwmgr->start_thermal_controller), temperature_range, NULL);
|
||||
}
|
||||
|
||||
|
||||
bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);
|
||||
}
|
||||
|
||||
|
||||
int phm_check_states_equal(struct pp_hwmgr *hwmgr,
|
||||
const struct pp_hw_power_state *pstate1,
|
||||
const struct pp_hw_power_state *pstate2,
|
||||
bool *equal)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->check_states_equal == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->check_states_equal(hwmgr, pstate1, pstate2, equal);
|
||||
}
|
||||
|
||||
int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
|
||||
const struct amd_pp_display_configuration *display_config)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->store_cc6_data == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr->display_config = *display_config;
|
||||
/* to do pass other display configuration in furture */
|
||||
|
||||
if (hwmgr->hwmgr_func->store_cc6_data)
|
||||
hwmgr->hwmgr_func->store_cc6_data(hwmgr,
|
||||
display_config->cpu_pstate_separation_time,
|
||||
display_config->cpu_cc6_disable,
|
||||
display_config->cpu_pstate_disable,
|
||||
display_config->nb_pstate_switch_disable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_dal_clock_info *info)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
|
||||
}
|
||||
|
||||
int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (hwmgr->hwmgr_func->set_cpu_power_state != NULL)
|
||||
return hwmgr->hwmgr_func->set_cpu_power_state(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
563
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
Normal file
563
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* 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 "linux/delay.h"
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "cgs_common.h"
|
||||
#include "power_state.h"
|
||||
#include "hwmgr.h"
|
||||
#include "pppcielanes.h"
|
||||
#include "pp_debug.h"
|
||||
#include "ppatomctrl.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);
|
||||
|
||||
int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr;
|
||||
|
||||
if ((handle == NULL) || (pp_init == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
|
||||
if (hwmgr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
handle->hwmgr = hwmgr;
|
||||
hwmgr->smumgr = handle->smu_mgr;
|
||||
hwmgr->device = pp_init->device;
|
||||
hwmgr->chip_family = pp_init->chip_family;
|
||||
hwmgr->chip_id = pp_init->chip_id;
|
||||
hwmgr->hw_revision = pp_init->rev_id;
|
||||
hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
|
||||
hwmgr->power_source = PP_PowerSource_AC;
|
||||
|
||||
switch (hwmgr->chip_family) {
|
||||
case AMD_FAMILY_CZ:
|
||||
cz_hwmgr_init(hwmgr);
|
||||
break;
|
||||
case AMD_FAMILY_VI:
|
||||
switch (hwmgr->chip_id) {
|
||||
case CHIP_TONGA:
|
||||
tonga_hwmgr_init(hwmgr);
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
fiji_hwmgr_init(hwmgr);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
phm_init_dynamic_caps(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hwmgr_fini(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (hwmgr == NULL || hwmgr->ps == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
kfree(hwmgr->ps);
|
||||
kfree(hwmgr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result;
|
||||
unsigned int i;
|
||||
unsigned int table_entries;
|
||||
struct pp_power_state *state;
|
||||
int size;
|
||||
|
||||
if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (hwmgr->hwmgr_func->get_power_state_size == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
|
||||
|
||||
hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
|
||||
sizeof(struct pp_power_state);
|
||||
|
||||
hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
|
||||
|
||||
if (hwmgr->ps == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
state = hwmgr->ps;
|
||||
|
||||
for (i = 0; i < table_entries; i++) {
|
||||
result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
|
||||
|
||||
if (state->classification.flags & PP_StateClassificationFlag_Boot) {
|
||||
hwmgr->boot_ps = state;
|
||||
hwmgr->current_ps = hwmgr->request_ps = state;
|
||||
}
|
||||
|
||||
state->id = i + 1; /* assigned unique num for every power state id */
|
||||
|
||||
if (state->classification.flags & PP_StateClassificationFlag_Uvd)
|
||||
hwmgr->uvd_ps = state;
|
||||
state = (struct pp_power_state *)((unsigned long)state + size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns once the part of the register indicated by the mask has
|
||||
* reached the given value.
|
||||
*/
|
||||
int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
|
||||
uint32_t value, uint32_t mask)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t cur_value;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->device == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < hwmgr->usec_timeout; i++) {
|
||||
cur_value = cgs_read_register(hwmgr->device, index);
|
||||
if ((cur_value & mask) == (value & mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* timeout means wrong logic*/
|
||||
if (i == hwmgr->usec_timeout)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
|
||||
uint32_t index, uint32_t value, uint32_t mask)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t cur_value;
|
||||
|
||||
if (hwmgr == NULL || hwmgr->device == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < hwmgr->usec_timeout; i++) {
|
||||
cur_value = cgs_read_register(hwmgr->device, index);
|
||||
if ((cur_value & mask) != (value & mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* timeout means wrong logic*/
|
||||
if (i == hwmgr->usec_timeout)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns once the part of the register indicated by the mask has
|
||||
* reached the given value.The indirect space is described by giving
|
||||
* the memory-mapped index of the indirect index register.
|
||||
*/
|
||||
void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
|
||||
uint32_t indirect_port,
|
||||
uint32_t index,
|
||||
uint32_t value,
|
||||
uint32_t mask)
|
||||
{
|
||||
if (hwmgr == NULL || hwmgr->device == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
|
||||
return;
|
||||
}
|
||||
|
||||
cgs_write_register(hwmgr->device, indirect_port, index);
|
||||
phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
|
||||
}
|
||||
|
||||
void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
|
||||
uint32_t indirect_port,
|
||||
uint32_t index,
|
||||
uint32_t value,
|
||||
uint32_t mask)
|
||||
{
|
||||
if (hwmgr == NULL || hwmgr->device == NULL) {
|
||||
printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
|
||||
return;
|
||||
}
|
||||
|
||||
cgs_write_register(hwmgr->device, indirect_port, index);
|
||||
phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
|
||||
value, mask);
|
||||
}
|
||||
|
||||
bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
|
||||
}
|
||||
|
||||
bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
|
||||
}
|
||||
|
||||
|
||||
int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint16_t vvalue;
|
||||
bool found = false;
|
||||
struct pp_atomctrl_voltage_table *table;
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != vol_table),
|
||||
"Voltage Table empty.", return -EINVAL);
|
||||
|
||||
table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (NULL == table)
|
||||
return -EINVAL;
|
||||
|
||||
table->mask_low = vol_table->mask_low;
|
||||
table->phase_delay = vol_table->phase_delay;
|
||||
|
||||
for (i = 0; i < vol_table->count; i++) {
|
||||
vvalue = vol_table->entries[i].value;
|
||||
found = false;
|
||||
|
||||
for (j = 0; j < table->count; j++) {
|
||||
if (vvalue == table->entries[j].value) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
table->entries[table->count].value = vvalue;
|
||||
table->entries[table->count].smio_low =
|
||||
vol_table->entries[i].smio_low;
|
||||
table->count++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
|
||||
kfree(table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
|
||||
phm_ppt_v1_clock_voltage_dependency_table *dep_table)
|
||||
{
|
||||
uint32_t i;
|
||||
int result;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 != dep_table->count),
|
||||
"Voltage Dependency Table empty.", return -EINVAL);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != vol_table),
|
||||
"vol_table empty.", return -EINVAL);
|
||||
|
||||
vol_table->mask_low = 0;
|
||||
vol_table->phase_delay = 0;
|
||||
vol_table->count = dep_table->count;
|
||||
|
||||
for (i = 0; i < dep_table->count; i++) {
|
||||
vol_table->entries[i].value = dep_table->entries[i].mvdd;
|
||||
vol_table->entries[i].smio_low = 0;
|
||||
}
|
||||
|
||||
result = phm_trim_voltage_table(vol_table);
|
||||
PP_ASSERT_WITH_CODE((0 == result),
|
||||
"Failed to trim MVDD table.", return result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
|
||||
phm_ppt_v1_clock_voltage_dependency_table *dep_table)
|
||||
{
|
||||
uint32_t i;
|
||||
int result;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 != dep_table->count),
|
||||
"Voltage Dependency Table empty.", return -EINVAL);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != vol_table),
|
||||
"vol_table empty.", return -EINVAL);
|
||||
|
||||
vol_table->mask_low = 0;
|
||||
vol_table->phase_delay = 0;
|
||||
vol_table->count = dep_table->count;
|
||||
|
||||
for (i = 0; i < dep_table->count; i++) {
|
||||
vol_table->entries[i].value = dep_table->entries[i].vddci;
|
||||
vol_table->entries[i].smio_low = 0;
|
||||
}
|
||||
|
||||
result = phm_trim_voltage_table(vol_table);
|
||||
PP_ASSERT_WITH_CODE((0 == result),
|
||||
"Failed to trim VDDCI table.", return result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
|
||||
phm_ppt_v1_voltage_lookup_table *lookup_table)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 != lookup_table->count),
|
||||
"Voltage Lookup Table empty.", return -EINVAL);
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != vol_table),
|
||||
"vol_table empty.", return -EINVAL);
|
||||
|
||||
vol_table->mask_low = 0;
|
||||
vol_table->phase_delay = 0;
|
||||
|
||||
vol_table->count = lookup_table->count;
|
||||
|
||||
for (i = 0; i < vol_table->count; i++) {
|
||||
vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
|
||||
vol_table->entries[i].smio_low = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
|
||||
struct pp_atomctrl_voltage_table *vol_table)
|
||||
{
|
||||
unsigned int i, diff;
|
||||
|
||||
if (vol_table->count <= max_vol_steps)
|
||||
return;
|
||||
|
||||
diff = vol_table->count - max_vol_steps;
|
||||
|
||||
for (i = 0; i < max_vol_steps; i++)
|
||||
vol_table->entries[i] = vol_table->entries[i + diff];
|
||||
|
||||
vol_table->count = max_vol_steps;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int phm_reset_single_dpm_table(void *table,
|
||||
uint32_t count, int max)
|
||||
{
|
||||
int i;
|
||||
|
||||
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;
|
||||
for (i = 0; i < max; i++)
|
||||
dpm_table->dpm_level[i].enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void phm_setup_pcie_table_entry(
|
||||
void *table,
|
||||
uint32_t index, uint32_t pcie_gen,
|
||||
uint32_t pcie_lanes)
|
||||
{
|
||||
struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
|
||||
dpm_table->dpm_level[index].value = pcie_gen;
|
||||
dpm_table->dpm_level[index].param1 = pcie_lanes;
|
||||
dpm_table->dpm_level[index].enabled = 1;
|
||||
}
|
||||
|
||||
int32_t phm_get_dpm_level_enable_mask_value(void *table)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t mask = 0;
|
||||
struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
|
||||
|
||||
for (i = dpm_table->count; i > 0; i--) {
|
||||
mask = mask << 1;
|
||||
if (dpm_table->dpm_level[i - 1].enabled)
|
||||
mask |= 0x1;
|
||||
else
|
||||
mask &= 0xFFFFFFFE;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
uint8_t phm_get_voltage_index(
|
||||
struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
|
||||
{
|
||||
uint8_t count = (uint8_t) (lookup_table->count);
|
||||
uint8_t i;
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != lookup_table),
|
||||
"Lookup Table empty.", return 0);
|
||||
PP_ASSERT_WITH_CODE((0 != count),
|
||||
"Lookup Table empty.", return 0);
|
||||
|
||||
for (i = 0; i < lookup_table->count; i++) {
|
||||
/* find first voltage equal or bigger than requested */
|
||||
if (lookup_table->entries[i].us_vdd >= voltage)
|
||||
return i;
|
||||
}
|
||||
/* voltage is bigger than max voltage in the table */
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < vddci_table->count; i++) {
|
||||
if (vddci_table->entries[i].value >= vddci)
|
||||
return vddci_table->entries[i].value;
|
||||
}
|
||||
|
||||
PP_ASSERT_WITH_CODE(false,
|
||||
"VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
|
||||
return vddci_table->entries[i].value);
|
||||
}
|
||||
|
||||
int phm_find_boot_level(void *table,
|
||||
uint32_t value, uint32_t *boot_level)
|
||||
{
|
||||
int result = -EINVAL;
|
||||
uint32_t i;
|
||||
struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
|
||||
|
||||
for (i = 0; i < dpm_table->count; i++) {
|
||||
if (value == dpm_table->dpm_level[i].value) {
|
||||
*boot_level = i;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
|
||||
phm_ppt_v1_voltage_lookup_table *lookup_table,
|
||||
uint16_t virtual_voltage_id, int32_t *sclk)
|
||||
{
|
||||
uint8_t entryId;
|
||||
uint8_t voltageId;
|
||||
struct phm_ppt_v1_information *table_info =
|
||||
(struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
|
||||
PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
|
||||
|
||||
/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
|
||||
for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
|
||||
voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
|
||||
if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
|
||||
break;
|
||||
}
|
||||
|
||||
PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
|
||||
"Can't find requested voltage id in vdd_dep_on_sclk table!",
|
||||
return -EINVAL;
|
||||
);
|
||||
|
||||
*sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Dynamic State Adjustment Rule Settings
|
||||
*
|
||||
* @param hwmgr the address of the powerplay hardware manager.
|
||||
*/
|
||||
int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
uint32_t table_size;
|
||||
struct phm_clock_voltage_dependency_table *table_clk_vlt;
|
||||
struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
|
||||
|
||||
/* initialize vddc_dep_on_dal_pwrl table */
|
||||
table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
|
||||
table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
|
||||
|
||||
if (NULL == table_clk_vlt) {
|
||||
printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
table_clk_vlt->count = 4;
|
||||
table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
|
||||
table_clk_vlt->entries[0].v = 0;
|
||||
table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
|
||||
table_clk_vlt->entries[1].v = 720;
|
||||
table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
|
||||
table_clk_vlt->entries[2].v = 810;
|
||||
table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
|
||||
table_clk_vlt->entries[3].v = 900;
|
||||
pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
|
||||
kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
|
||||
}
|
||||
|
||||
if (NULL != hwmgr->backend) {
|
||||
kfree(hwmgr->backend);
|
||||
hwmgr->backend = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
|
||||
{
|
||||
uint32_t level = 0;
|
||||
|
||||
while (0 == (mask & (1 << level)))
|
||||
level++;
|
||||
|
||||
return level;
|
||||
}
|
||||
105
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
Normal file
105
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 PP_HWMGR_PPT_H
|
||||
#define PP_HWMGR_PPT_H
|
||||
|
||||
#include "hardwaremanager.h"
|
||||
#include "smumgr.h"
|
||||
#include "atom-types.h"
|
||||
|
||||
struct phm_ppt_v1_clock_voltage_dependency_record {
|
||||
uint32_t clk;
|
||||
uint8_t vddInd;
|
||||
uint16_t vdd_offset;
|
||||
uint16_t vddc;
|
||||
uint16_t vddgfx;
|
||||
uint16_t vddci;
|
||||
uint16_t mvdd;
|
||||
uint8_t phases;
|
||||
uint8_t cks_enable;
|
||||
uint8_t cks_voffset;
|
||||
};
|
||||
|
||||
typedef struct phm_ppt_v1_clock_voltage_dependency_record phm_ppt_v1_clock_voltage_dependency_record;
|
||||
|
||||
struct phm_ppt_v1_clock_voltage_dependency_table {
|
||||
uint32_t count; /* Number of entries. */
|
||||
phm_ppt_v1_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
|
||||
};
|
||||
|
||||
typedef struct phm_ppt_v1_clock_voltage_dependency_table phm_ppt_v1_clock_voltage_dependency_table;
|
||||
|
||||
|
||||
/* Multimedia Clock Voltage Dependency records and table */
|
||||
struct phm_ppt_v1_mm_clock_voltage_dependency_record {
|
||||
uint32_t dclk; /* UVD D-clock */
|
||||
uint32_t vclk; /* UVD V-clock */
|
||||
uint32_t eclk; /* VCE clock */
|
||||
uint32_t aclk; /* ACP clock */
|
||||
uint32_t samclock; /* SAMU clock */
|
||||
uint8_t vddcInd;
|
||||
uint16_t vddgfx_offset;
|
||||
uint16_t vddc;
|
||||
uint16_t vddgfx;
|
||||
uint8_t phases;
|
||||
};
|
||||
typedef struct phm_ppt_v1_mm_clock_voltage_dependency_record phm_ppt_v1_mm_clock_voltage_dependency_record;
|
||||
|
||||
struct phm_ppt_v1_mm_clock_voltage_dependency_table {
|
||||
uint32_t count; /* Number of entries. */
|
||||
phm_ppt_v1_mm_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
|
||||
};
|
||||
typedef struct phm_ppt_v1_mm_clock_voltage_dependency_table phm_ppt_v1_mm_clock_voltage_dependency_table;
|
||||
|
||||
struct phm_ppt_v1_voltage_lookup_record {
|
||||
uint16_t us_calculated;
|
||||
uint16_t us_vdd; /* Base voltage */
|
||||
uint16_t us_cac_low;
|
||||
uint16_t us_cac_mid;
|
||||
uint16_t us_cac_high;
|
||||
};
|
||||
typedef struct phm_ppt_v1_voltage_lookup_record phm_ppt_v1_voltage_lookup_record;
|
||||
|
||||
struct phm_ppt_v1_voltage_lookup_table {
|
||||
uint32_t count;
|
||||
phm_ppt_v1_voltage_lookup_record entries[1]; /* Dynamically allocate count entries. */
|
||||
};
|
||||
typedef struct phm_ppt_v1_voltage_lookup_table phm_ppt_v1_voltage_lookup_table;
|
||||
|
||||
/* PCIE records and Table */
|
||||
|
||||
struct phm_ppt_v1_pcie_record {
|
||||
uint8_t gen_speed;
|
||||
uint8_t lane_width;
|
||||
};
|
||||
typedef struct phm_ppt_v1_pcie_record phm_ppt_v1_pcie_record;
|
||||
|
||||
struct phm_ppt_v1_pcie_table {
|
||||
uint32_t count; /* Number of entries. */
|
||||
phm_ppt_v1_pcie_record entries[1]; /* Dynamically allocate count entries. */
|
||||
};
|
||||
typedef struct phm_ppt_v1_pcie_table phm_ppt_v1_pcie_table;
|
||||
|
||||
#endif
|
||||
|
||||
76
drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
Normal file
76
drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#include <linux/errno.h>
|
||||
#include "linux/delay.h"
|
||||
#include "hwmgr.h"
|
||||
#include "amd_acpi.h"
|
||||
|
||||
bool acpi_atcs_functions_supported(void *device, uint32_t index)
|
||||
{
|
||||
int32_t result;
|
||||
struct atcs_verify_interface output_buf = {0};
|
||||
|
||||
int32_t temp_buffer = 1;
|
||||
|
||||
result = cgs_call_acpi_method(device, CGS_ACPI_METHOD_ATCS,
|
||||
ATCS_FUNCTION_VERIFY_INTERFACE,
|
||||
&temp_buffer,
|
||||
&output_buf,
|
||||
1,
|
||||
sizeof(temp_buffer),
|
||||
sizeof(output_buf));
|
||||
|
||||
return result == 0 ? (output_buf.function_bits & (1 << (index - 1))) != 0 : false;
|
||||
}
|
||||
|
||||
int acpi_pcie_perf_request(void *device, uint8_t perf_req, bool advertise)
|
||||
{
|
||||
struct atcs_pref_req_input atcs_input;
|
||||
struct atcs_pref_req_output atcs_output;
|
||||
u32 retry = 3;
|
||||
int result;
|
||||
struct cgs_system_info info = {0};
|
||||
|
||||
if (!acpi_atcs_functions_supported(device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST))
|
||||
return -EINVAL;
|
||||
|
||||
info.size = sizeof(struct cgs_system_info);
|
||||
info.info_id = CGS_SYSTEM_INFO_ADAPTER_BDF_ID;
|
||||
result = cgs_query_system_info(device, &info);
|
||||
if (result != 0)
|
||||
return -EINVAL;
|
||||
atcs_input.client_id = (uint16_t)info.value;
|
||||
atcs_input.size = sizeof(struct atcs_pref_req_input);
|
||||
atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
|
||||
atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
|
||||
if (advertise)
|
||||
atcs_input.flags |= ATCS_ADVERTISE_CAPS;
|
||||
atcs_input.req_type = ATCS_PCIE_LINK_SPEED;
|
||||
atcs_input.perf_req = perf_req;
|
||||
|
||||
atcs_output.size = sizeof(struct atcs_pref_req_input);
|
||||
|
||||
while (retry--) {
|
||||
result = cgs_call_acpi_method(device,
|
||||
CGS_ACPI_METHOD_ATCS,
|
||||
ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST,
|
||||
&atcs_input,
|
||||
&atcs_output,
|
||||
0,
|
||||
sizeof(atcs_input),
|
||||
sizeof(atcs_output));
|
||||
if (result != 0)
|
||||
return -EIO;
|
||||
|
||||
switch (atcs_output.ret_val) {
|
||||
case ATCS_REQUEST_REFUSED:
|
||||
default:
|
||||
return -EINVAL;
|
||||
case ATCS_REQUEST_COMPLETE:
|
||||
return 0;
|
||||
case ATCS_REQUEST_IN_PROGRESS:
|
||||
udelay(10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1207
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
Normal file
1207
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
Normal file
File diff suppressed because it is too large
Load diff
246
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
Normal file
246
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* 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 PP_ATOMVOLTAGECTRL_H
|
||||
#define PP_ATOMVOLTAGECTRL_H
|
||||
|
||||
#include "hwmgr.h"
|
||||
|
||||
#define MEM_TYPE_GDDR5 0x50
|
||||
#define MEM_TYPE_GDDR4 0x40
|
||||
#define MEM_TYPE_GDDR3 0x30
|
||||
#define MEM_TYPE_DDR2 0x20
|
||||
#define MEM_TYPE_GDDR1 0x10
|
||||
#define MEM_TYPE_DDR3 0xb0
|
||||
#define MEM_TYPE_MASK 0xF0
|
||||
|
||||
|
||||
/* As returned from PowerConnectorDetectionTable. */
|
||||
#define PP_ATOM_POWER_BUDGET_DISABLE_OVERDRIVE 0x80
|
||||
#define PP_ATOM_POWER_BUDGET_SHOW_WARNING 0x40
|
||||
#define PP_ATOM_POWER_BUDGET_SHOW_WAIVER 0x20
|
||||
#define PP_ATOM_POWER_POWER_BUDGET_BEHAVIOUR 0x0F
|
||||
|
||||
/* New functions for Evergreen and beyond. */
|
||||
#define PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES 32
|
||||
|
||||
struct pp_atomctrl_clock_dividers {
|
||||
uint32_t pll_post_divider;
|
||||
uint32_t pll_feedback_divider;
|
||||
uint32_t pll_ref_divider;
|
||||
bool enable_post_divider;
|
||||
};
|
||||
|
||||
typedef struct pp_atomctrl_clock_dividers pp_atomctrl_clock_dividers;
|
||||
|
||||
union pp_atomctrl_tcipll_fb_divider {
|
||||
struct {
|
||||
uint32_t ul_fb_div_frac : 14;
|
||||
uint32_t ul_fb_div : 12;
|
||||
uint32_t un_used : 6;
|
||||
};
|
||||
uint32_t ul_fb_divider;
|
||||
};
|
||||
|
||||
typedef union pp_atomctrl_tcipll_fb_divider pp_atomctrl_tcipll_fb_divider;
|
||||
|
||||
struct pp_atomctrl_clock_dividers_rv730 {
|
||||
uint32_t pll_post_divider;
|
||||
pp_atomctrl_tcipll_fb_divider mpll_feedback_divider;
|
||||
uint32_t pll_ref_divider;
|
||||
bool enable_post_divider;
|
||||
bool enable_dithen;
|
||||
uint32_t vco_mode;
|
||||
};
|
||||
typedef struct pp_atomctrl_clock_dividers_rv730 pp_atomctrl_clock_dividers_rv730;
|
||||
|
||||
|
||||
struct pp_atomctrl_clock_dividers_kong {
|
||||
uint32_t pll_post_divider;
|
||||
uint32_t real_clock;
|
||||
};
|
||||
typedef struct pp_atomctrl_clock_dividers_kong pp_atomctrl_clock_dividers_kong;
|
||||
|
||||
struct pp_atomctrl_clock_dividers_ci {
|
||||
uint32_t pll_post_divider; /* post divider value */
|
||||
uint32_t real_clock;
|
||||
pp_atomctrl_tcipll_fb_divider ul_fb_div; /* Output Parameter: PLL FB divider */
|
||||
uint8_t uc_pll_ref_div; /* Output Parameter: PLL ref divider */
|
||||
uint8_t uc_pll_post_div; /* Output Parameter: PLL post divider */
|
||||
uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
|
||||
};
|
||||
typedef struct pp_atomctrl_clock_dividers_ci pp_atomctrl_clock_dividers_ci;
|
||||
|
||||
struct pp_atomctrl_clock_dividers_vi {
|
||||
uint32_t pll_post_divider; /* post divider value */
|
||||
uint32_t real_clock;
|
||||
pp_atomctrl_tcipll_fb_divider ul_fb_div; /*Output Parameter: PLL FB divider */
|
||||
uint8_t uc_pll_ref_div; /*Output Parameter: PLL ref divider */
|
||||
uint8_t uc_pll_post_div; /*Output Parameter: PLL post divider */
|
||||
uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
|
||||
};
|
||||
typedef struct pp_atomctrl_clock_dividers_vi pp_atomctrl_clock_dividers_vi;
|
||||
|
||||
union pp_atomctrl_s_mpll_fb_divider {
|
||||
struct {
|
||||
uint32_t cl_kf : 12;
|
||||
uint32_t clk_frac : 12;
|
||||
uint32_t un_used : 8;
|
||||
};
|
||||
uint32_t ul_fb_divider;
|
||||
};
|
||||
typedef union pp_atomctrl_s_mpll_fb_divider pp_atomctrl_s_mpll_fb_divider;
|
||||
|
||||
enum pp_atomctrl_spread_spectrum_mode {
|
||||
pp_atomctrl_spread_spectrum_mode_down = 0,
|
||||
pp_atomctrl_spread_spectrum_mode_center
|
||||
};
|
||||
typedef enum pp_atomctrl_spread_spectrum_mode pp_atomctrl_spread_spectrum_mode;
|
||||
|
||||
struct pp_atomctrl_memory_clock_param {
|
||||
pp_atomctrl_s_mpll_fb_divider mpll_fb_divider;
|
||||
uint32_t mpll_post_divider;
|
||||
uint32_t bw_ctrl;
|
||||
uint32_t dll_speed;
|
||||
uint32_t vco_mode;
|
||||
uint32_t yclk_sel;
|
||||
uint32_t qdr;
|
||||
uint32_t half_rate;
|
||||
};
|
||||
typedef struct pp_atomctrl_memory_clock_param pp_atomctrl_memory_clock_param;
|
||||
|
||||
struct pp_atomctrl_internal_ss_info {
|
||||
uint32_t speed_spectrum_percentage; /* in 1/100 percentage */
|
||||
uint32_t speed_spectrum_rate; /* in KHz */
|
||||
pp_atomctrl_spread_spectrum_mode speed_spectrum_mode;
|
||||
};
|
||||
typedef struct pp_atomctrl_internal_ss_info pp_atomctrl_internal_ss_info;
|
||||
|
||||
#ifndef NUMBER_OF_M3ARB_PARAMS
|
||||
#define NUMBER_OF_M3ARB_PARAMS 3
|
||||
#endif
|
||||
|
||||
#ifndef NUMBER_OF_M3ARB_PARAM_SETS
|
||||
#define NUMBER_OF_M3ARB_PARAM_SETS 10
|
||||
#endif
|
||||
|
||||
struct pp_atomctrl_kong_system_info {
|
||||
uint32_t ul_bootup_uma_clock; /* in 10kHz unit */
|
||||
uint16_t us_max_nb_voltage; /* high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
|
||||
uint16_t us_min_nb_voltage; /* low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
|
||||
uint16_t us_bootup_nb_voltage; /* boot up NB voltage */
|
||||
uint8_t uc_htc_tmp_lmt; /* bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD */
|
||||
uint8_t uc_tj_offset; /* bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD */
|
||||
/* 0: default 1: uvd 2: fs-3d */
|
||||
uint32_t ul_csr_m3_srb_cntl[NUMBER_OF_M3ARB_PARAM_SETS][NUMBER_OF_M3ARB_PARAMS];/* arrays with values for CSR M3 arbiter for default */
|
||||
};
|
||||
typedef struct pp_atomctrl_kong_system_info pp_atomctrl_kong_system_info;
|
||||
|
||||
struct pp_atomctrl_memory_info {
|
||||
uint8_t memory_vendor;
|
||||
uint8_t memory_type;
|
||||
};
|
||||
typedef struct pp_atomctrl_memory_info pp_atomctrl_memory_info;
|
||||
|
||||
#define MAX_AC_TIMING_ENTRIES 16
|
||||
|
||||
struct pp_atomctrl_memory_clock_range_table {
|
||||
uint8_t num_entries;
|
||||
uint8_t rsv[3];
|
||||
|
||||
uint32_t mclk[MAX_AC_TIMING_ENTRIES];
|
||||
};
|
||||
typedef struct pp_atomctrl_memory_clock_range_table pp_atomctrl_memory_clock_range_table;
|
||||
|
||||
struct pp_atomctrl_voltage_table_entry {
|
||||
uint16_t value;
|
||||
uint32_t smio_low;
|
||||
};
|
||||
|
||||
typedef struct pp_atomctrl_voltage_table_entry pp_atomctrl_voltage_table_entry;
|
||||
|
||||
struct pp_atomctrl_voltage_table {
|
||||
uint32_t count;
|
||||
uint32_t mask_low;
|
||||
uint32_t phase_delay; /* Used for ATOM_GPIO_VOLTAGE_OBJECT_V3 and later */
|
||||
pp_atomctrl_voltage_table_entry entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES];
|
||||
};
|
||||
|
||||
typedef struct pp_atomctrl_voltage_table pp_atomctrl_voltage_table;
|
||||
|
||||
#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
|
||||
#define VBIOS_MAX_AC_TIMING_ENTRIES 20
|
||||
|
||||
struct pp_atomctrl_mc_reg_entry {
|
||||
uint32_t mclk_max;
|
||||
uint32_t mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct pp_atomctrl_mc_reg_entry pp_atomctrl_mc_reg_entry;
|
||||
|
||||
struct pp_atomctrl_mc_register_address {
|
||||
uint16_t s1;
|
||||
uint8_t uc_pre_reg_data;
|
||||
};
|
||||
|
||||
typedef struct pp_atomctrl_mc_register_address pp_atomctrl_mc_register_address;
|
||||
|
||||
struct pp_atomctrl_mc_reg_table {
|
||||
uint8_t last; /* number of registers */
|
||||
uint8_t num_entries; /* number of AC timing entries */
|
||||
pp_atomctrl_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
|
||||
pp_atomctrl_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
|
||||
};
|
||||
typedef struct pp_atomctrl_mc_reg_table pp_atomctrl_mc_reg_table;
|
||||
|
||||
struct pp_atomctrl_gpio_pin_assignment {
|
||||
uint16_t us_gpio_pin_aindex;
|
||||
uint8_t uc_gpio_pin_bit_shift;
|
||||
};
|
||||
typedef struct pp_atomctrl_gpio_pin_assignment pp_atomctrl_gpio_pin_assignment;
|
||||
|
||||
extern bool atomctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pinId, pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment);
|
||||
extern int atomctrl_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage);
|
||||
extern uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr);
|
||||
extern int atomctrl_get_memory_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t memory_clock, pp_atomctrl_internal_ss_info *ssInfo);
|
||||
extern int atomctrl_get_engine_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t engine_clock, pp_atomctrl_internal_ss_info *ssInfo);
|
||||
extern int atomctrl_initialize_mc_reg_table(struct pp_hwmgr *hwmgr, uint8_t module_index, pp_atomctrl_mc_reg_table *table);
|
||||
extern int atomctrl_set_engine_dram_timings_rv770(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint32_t memory_clock);
|
||||
extern uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr);
|
||||
extern int atomctrl_get_memory_pll_dividers_si(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param, bool strobe_mode);
|
||||
extern int atomctrl_get_engine_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
|
||||
extern int atomctrl_get_dfs_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
|
||||
extern bool atomctrl_is_voltage_controled_by_gpio_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode);
|
||||
extern int atomctrl_get_voltage_table_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, pp_atomctrl_voltage_table *voltage_table);
|
||||
extern int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
|
||||
uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param);
|
||||
extern int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
|
||||
uint32_t clock_value,
|
||||
pp_atomctrl_clock_dividers_kong *dividers);
|
||||
extern int atomctrl_read_efuse(void *device, uint16_t start_index,
|
||||
uint16_t end_index, uint32_t mask, uint32_t *efuse);
|
||||
extern int atomctrl_calculate_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
|
||||
uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage, uint16_t dpm_level, bool debug);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
612
drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
Normal file
612
drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#define SHIFT_AMOUNT 16 /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */
|
||||
|
||||
#define PRECISION 5 /* Change this value to change the number of decimal places in the final output - 5 is a good default */
|
||||
|
||||
#define SHIFTED_2 (2 << SHIFT_AMOUNT)
|
||||
#define MAX (1 << (SHIFT_AMOUNT - 1)) - 1 /* 32767 - Might change in the future */
|
||||
|
||||
/* -------------------------------------------------------------------------------
|
||||
* NEW TYPE - fINT
|
||||
* -------------------------------------------------------------------------------
|
||||
* A variable of type fInt can be accessed in 3 ways using the dot (.) operator
|
||||
* fInt A;
|
||||
* A.full => The full number as it is. Generally not easy to read
|
||||
* A.partial.real => Only the integer portion
|
||||
* A.partial.decimal => Only the fractional portion
|
||||
*/
|
||||
typedef union _fInt {
|
||||
int full;
|
||||
struct _partial {
|
||||
unsigned int decimal: SHIFT_AMOUNT; /*Needs to always be unsigned*/
|
||||
int real: 32 - SHIFT_AMOUNT;
|
||||
} partial;
|
||||
} fInt;
|
||||
|
||||
/* -------------------------------------------------------------------------------
|
||||
* Function Declarations
|
||||
* -------------------------------------------------------------------------------
|
||||
*/
|
||||
fInt ConvertToFraction(int); /* Use this to convert an INT to a FINT */
|
||||
fInt Convert_ULONG_ToFraction(uint32_t); /* Use this to convert an uint32_t to a FINT */
|
||||
fInt GetScaledFraction(int, int); /* Use this to convert an INT to a FINT after scaling it by a factor */
|
||||
int ConvertBackToInteger(fInt); /* Convert a FINT back to an INT that is scaled by 1000 (i.e. last 3 digits are the decimal digits) */
|
||||
|
||||
fInt fNegate(fInt); /* Returns -1 * input fInt value */
|
||||
fInt fAdd (fInt, fInt); /* Returns the sum of two fInt numbers */
|
||||
fInt fSubtract (fInt A, fInt B); /* Returns A-B - Sometimes easier than Adding negative numbers */
|
||||
fInt fMultiply (fInt, fInt); /* Returns the product of two fInt numbers */
|
||||
fInt fDivide (fInt A, fInt B); /* Returns A/B */
|
||||
fInt fGetSquare(fInt); /* Returns the square of a fInt number */
|
||||
fInt fSqrt(fInt); /* Returns the Square Root of a fInt number */
|
||||
|
||||
int uAbs(int); /* Returns the Absolute value of the Int */
|
||||
fInt fAbs(fInt); /* Returns the Absolute value of the fInt */
|
||||
int uPow(int base, int exponent); /* Returns base^exponent an INT */
|
||||
|
||||
void SolveQuadracticEqn(fInt, fInt, fInt, fInt[]); /* Returns the 2 roots via the array */
|
||||
bool Equal(fInt, fInt); /* Returns true if two fInts are equal to each other */
|
||||
bool GreaterThan(fInt A, fInt B); /* Returns true if A > B */
|
||||
|
||||
fInt fExponential(fInt exponent); /* Can be used to calculate e^exponent */
|
||||
fInt fNaturalLog(fInt value); /* Can be used to calculate ln(value) */
|
||||
|
||||
/* Fuse decoding functions
|
||||
* -------------------------------------------------------------------------------------
|
||||
*/
|
||||
fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength);
|
||||
fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength);
|
||||
fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength);
|
||||
|
||||
/* Internal Support Functions - Use these ONLY for testing or adding to internal functions
|
||||
* -------------------------------------------------------------------------------------
|
||||
* Some of the following functions take two INTs as their input - This is unsafe for a variety of reasons.
|
||||
*/
|
||||
fInt Add (int, int); /* Add two INTs and return Sum as FINT */
|
||||
fInt Multiply (int, int); /* Multiply two INTs and return Product as FINT */
|
||||
fInt Divide (int, int); /* You get the idea... */
|
||||
fInt fNegate(fInt);
|
||||
|
||||
int uGetScaledDecimal (fInt); /* Internal function */
|
||||
int GetReal (fInt A); /* Internal function */
|
||||
|
||||
/* Future Additions and Incomplete Functions
|
||||
* -------------------------------------------------------------------------------------
|
||||
*/
|
||||
int GetRoundedValue(fInt); /* Incomplete function - Useful only when Precision is lacking */
|
||||
/* Let us say we have 2.126 but can only handle 2 decimal points. We could */
|
||||
/* either chop of 6 and keep 2.12 or use this function to get 2.13, which is more accurate */
|
||||
|
||||
/* -------------------------------------------------------------------------------------
|
||||
* TROUBLESHOOTING INFORMATION
|
||||
* -------------------------------------------------------------------------------------
|
||||
* 1) ConvertToFraction - InputOutOfRangeException: Only accepts numbers smaller than MAX (default: 32767)
|
||||
* 2) fAdd - OutputOutOfRangeException: Output bigger than MAX (default: 32767)
|
||||
* 3) fMultiply - OutputOutOfRangeException:
|
||||
* 4) fGetSquare - OutputOutOfRangeException:
|
||||
* 5) fDivide - DivideByZeroException
|
||||
* 6) fSqrt - NegativeSquareRootException: Input cannot be a negative number
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------------------
|
||||
* START OF CODE
|
||||
* -------------------------------------------------------------------------------------
|
||||
*/
|
||||
fInt fExponential(fInt exponent) /*Can be used to calculate e^exponent*/
|
||||
{
|
||||
uint32_t i;
|
||||
bool bNegated = false;
|
||||
|
||||
fInt fPositiveOne = ConvertToFraction(1);
|
||||
fInt fZERO = ConvertToFraction(0);
|
||||
|
||||
fInt lower_bound = Divide(78, 10000);
|
||||
fInt solution = fPositiveOne; /*Starting off with baseline of 1 */
|
||||
fInt error_term;
|
||||
|
||||
uint32_t k_array[11] = {55452, 27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
|
||||
uint32_t expk_array[11] = {2560000, 160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
|
||||
|
||||
if (GreaterThan(fZERO, exponent)) {
|
||||
exponent = fNegate(exponent);
|
||||
bNegated = true;
|
||||
}
|
||||
|
||||
while (GreaterThan(exponent, lower_bound)) {
|
||||
for (i = 0; i < 11; i++) {
|
||||
if (GreaterThan(exponent, GetScaledFraction(k_array[i], 10000))) {
|
||||
exponent = fSubtract(exponent, GetScaledFraction(k_array[i], 10000));
|
||||
solution = fMultiply(solution, GetScaledFraction(expk_array[i], 10000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_term = fAdd(fPositiveOne, exponent);
|
||||
|
||||
solution = fMultiply(solution, error_term);
|
||||
|
||||
if (bNegated)
|
||||
solution = fDivide(fPositiveOne, solution);
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
fInt fNaturalLog(fInt value)
|
||||
{
|
||||
uint32_t i;
|
||||
fInt upper_bound = Divide(8, 1000);
|
||||
fInt fNegativeOne = ConvertToFraction(-1);
|
||||
fInt solution = ConvertToFraction(0); /*Starting off with baseline of 0 */
|
||||
fInt error_term;
|
||||
|
||||
uint32_t k_array[10] = {160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
|
||||
uint32_t logk_array[10] = {27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
|
||||
|
||||
while (GreaterThan(fAdd(value, fNegativeOne), upper_bound)) {
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (GreaterThan(value, GetScaledFraction(k_array[i], 10000))) {
|
||||
value = fDivide(value, GetScaledFraction(k_array[i], 10000));
|
||||
solution = fAdd(solution, GetScaledFraction(logk_array[i], 10000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_term = fAdd(fNegativeOne, value);
|
||||
|
||||
return (fAdd(solution, error_term));
|
||||
}
|
||||
|
||||
fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength)
|
||||
{
|
||||
fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
|
||||
fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
|
||||
|
||||
fInt f_decoded_value;
|
||||
|
||||
f_decoded_value = fDivide(f_fuse_value, f_bit_max_value);
|
||||
f_decoded_value = fMultiply(f_decoded_value, f_range);
|
||||
f_decoded_value = fAdd(f_decoded_value, f_min);
|
||||
|
||||
return f_decoded_value;
|
||||
}
|
||||
|
||||
|
||||
fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength)
|
||||
{
|
||||
fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
|
||||
fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
|
||||
|
||||
fInt f_CONSTANT_NEG13 = ConvertToFraction(-13);
|
||||
fInt f_CONSTANT1 = ConvertToFraction(1);
|
||||
|
||||
fInt f_decoded_value;
|
||||
|
||||
f_decoded_value = fSubtract(fDivide(f_bit_max_value, f_fuse_value), f_CONSTANT1);
|
||||
f_decoded_value = fNaturalLog(f_decoded_value);
|
||||
f_decoded_value = fMultiply(f_decoded_value, fDivide(f_range, f_CONSTANT_NEG13));
|
||||
f_decoded_value = fAdd(f_decoded_value, f_average);
|
||||
|
||||
return f_decoded_value;
|
||||
}
|
||||
|
||||
fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength)
|
||||
{
|
||||
fInt fLeakage;
|
||||
fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
|
||||
|
||||
fLeakage = fMultiply(ln_max_div_min, Convert_ULONG_ToFraction(leakageID_fuse));
|
||||
fLeakage = fDivide(fLeakage, f_bit_max_value);
|
||||
fLeakage = fExponential(fLeakage);
|
||||
fLeakage = fMultiply(fLeakage, f_min);
|
||||
|
||||
return fLeakage;
|
||||
}
|
||||
|
||||
fInt ConvertToFraction(int X) /*Add all range checking here. Is it possible to make fInt a private declaration? */
|
||||
{
|
||||
fInt temp;
|
||||
|
||||
if (X <= MAX)
|
||||
temp.full = (X << SHIFT_AMOUNT);
|
||||
else
|
||||
temp.full = 0;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
fInt fNegate(fInt X)
|
||||
{
|
||||
fInt CONSTANT_NEGONE = ConvertToFraction(-1);
|
||||
return (fMultiply(X, CONSTANT_NEGONE));
|
||||
}
|
||||
|
||||
fInt Convert_ULONG_ToFraction(uint32_t X)
|
||||
{
|
||||
fInt temp;
|
||||
|
||||
if (X <= MAX)
|
||||
temp.full = (X << SHIFT_AMOUNT);
|
||||
else
|
||||
temp.full = 0;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
fInt GetScaledFraction(int X, int factor)
|
||||
{
|
||||
int times_shifted, factor_shifted;
|
||||
bool bNEGATED;
|
||||
fInt fValue;
|
||||
|
||||
times_shifted = 0;
|
||||
factor_shifted = 0;
|
||||
bNEGATED = false;
|
||||
|
||||
if (X < 0) {
|
||||
X = -1*X;
|
||||
bNEGATED = true;
|
||||
}
|
||||
|
||||
if (factor < 0) {
|
||||
factor = -1*factor;
|
||||
bNEGATED = !bNEGATED; /*If bNEGATED = true due to X < 0, this will cover the case of negative cancelling negative */
|
||||
}
|
||||
|
||||
if ((X > MAX) || factor > MAX) {
|
||||
if ((X/factor) <= MAX) {
|
||||
while (X > MAX) {
|
||||
X = X >> 1;
|
||||
times_shifted++;
|
||||
}
|
||||
|
||||
while (factor > MAX) {
|
||||
factor = factor >> 1;
|
||||
factor_shifted++;
|
||||
}
|
||||
} else {
|
||||
fValue.full = 0;
|
||||
return fValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (factor == 1)
|
||||
return (ConvertToFraction(X));
|
||||
|
||||
fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor));
|
||||
|
||||
fValue.full = fValue.full << times_shifted;
|
||||
fValue.full = fValue.full >> factor_shifted;
|
||||
|
||||
return fValue;
|
||||
}
|
||||
|
||||
/* Addition using two fInts */
|
||||
fInt fAdd (fInt X, fInt Y)
|
||||
{
|
||||
fInt Sum;
|
||||
|
||||
Sum.full = X.full + Y.full;
|
||||
|
||||
return Sum;
|
||||
}
|
||||
|
||||
/* Addition using two fInts */
|
||||
fInt fSubtract (fInt X, fInt Y)
|
||||
{
|
||||
fInt Difference;
|
||||
|
||||
Difference.full = X.full - Y.full;
|
||||
|
||||
return Difference;
|
||||
}
|
||||
|
||||
bool Equal(fInt A, fInt B)
|
||||
{
|
||||
if (A.full == B.full)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GreaterThan(fInt A, fInt B)
|
||||
{
|
||||
if (A.full > B.full)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
fInt fMultiply (fInt X, fInt Y) /* Uses 64-bit integers (int64_t) */
|
||||
{
|
||||
fInt Product;
|
||||
int64_t tempProduct;
|
||||
bool X_LessThanOne, Y_LessThanOne;
|
||||
|
||||
X_LessThanOne = (X.partial.real == 0 && X.partial.decimal != 0 && X.full >= 0);
|
||||
Y_LessThanOne = (Y.partial.real == 0 && Y.partial.decimal != 0 && Y.full >= 0);
|
||||
|
||||
/*The following is for a very specific common case: Non-zero number with ONLY fractional portion*/
|
||||
/* TEMPORARILY DISABLED - CAN BE USED TO IMPROVE PRECISION
|
||||
|
||||
if (X_LessThanOne && Y_LessThanOne) {
|
||||
Product.full = X.full * Y.full;
|
||||
return Product
|
||||
}*/
|
||||
|
||||
tempProduct = ((int64_t)X.full) * ((int64_t)Y.full); /*Q(16,16)*Q(16,16) = Q(32, 32) - Might become a negative number! */
|
||||
tempProduct = tempProduct >> 16; /*Remove lagging 16 bits - Will lose some precision from decimal; */
|
||||
Product.full = (int)tempProduct; /*The int64_t will lose the leading 16 bits that were part of the integer portion */
|
||||
|
||||
return Product;
|
||||
}
|
||||
|
||||
fInt fDivide (fInt X, fInt Y)
|
||||
{
|
||||
fInt fZERO, fQuotient;
|
||||
int64_t longlongX, longlongY;
|
||||
|
||||
fZERO = ConvertToFraction(0);
|
||||
|
||||
if (Equal(Y, fZERO))
|
||||
return fZERO;
|
||||
|
||||
longlongX = (int64_t)X.full;
|
||||
longlongY = (int64_t)Y.full;
|
||||
|
||||
longlongX = longlongX << 16; /*Q(16,16) -> Q(32,32) */
|
||||
|
||||
div64_s64(longlongX, longlongY); /*Q(32,32) divided by Q(16,16) = Q(16,16) Back to original format */
|
||||
|
||||
fQuotient.full = (int)longlongX;
|
||||
return fQuotient;
|
||||
}
|
||||
|
||||
int ConvertBackToInteger (fInt A) /*THIS is the function that will be used to check with the Golden settings table*/
|
||||
{
|
||||
fInt fullNumber, scaledDecimal, scaledReal;
|
||||
|
||||
scaledReal.full = GetReal(A) * uPow(10, PRECISION-1); /* DOUBLE CHECK THISSSS!!! */
|
||||
|
||||
scaledDecimal.full = uGetScaledDecimal(A);
|
||||
|
||||
fullNumber = fAdd(scaledDecimal,scaledReal);
|
||||
|
||||
return fullNumber.full;
|
||||
}
|
||||
|
||||
fInt fGetSquare(fInt A)
|
||||
{
|
||||
return fMultiply(A,A);
|
||||
}
|
||||
|
||||
/* x_new = x_old - (x_old^2 - C) / (2 * x_old) */
|
||||
fInt fSqrt(fInt num)
|
||||
{
|
||||
fInt F_divide_Fprime, Fprime;
|
||||
fInt test;
|
||||
fInt twoShifted;
|
||||
int seed, counter, error;
|
||||
fInt x_new, x_old, C, y;
|
||||
|
||||
fInt fZERO = ConvertToFraction(0);
|
||||
|
||||
/* (0 > num) is the same as (num < 0), i.e., num is negative */
|
||||
|
||||
if (GreaterThan(fZERO, num) || Equal(fZERO, num))
|
||||
return fZERO;
|
||||
|
||||
C = num;
|
||||
|
||||
if (num.partial.real > 3000)
|
||||
seed = 60;
|
||||
else if (num.partial.real > 1000)
|
||||
seed = 30;
|
||||
else if (num.partial.real > 100)
|
||||
seed = 10;
|
||||
else
|
||||
seed = 2;
|
||||
|
||||
counter = 0;
|
||||
|
||||
if (Equal(num, fZERO)) /*Square Root of Zero is zero */
|
||||
return fZERO;
|
||||
|
||||
twoShifted = ConvertToFraction(2);
|
||||
x_new = ConvertToFraction(seed);
|
||||
|
||||
do {
|
||||
counter++;
|
||||
|
||||
x_old.full = x_new.full;
|
||||
|
||||
test = fGetSquare(x_old); /*1.75*1.75 is reverting back to 1 when shifted down */
|
||||
y = fSubtract(test, C); /*y = f(x) = x^2 - C; */
|
||||
|
||||
Fprime = fMultiply(twoShifted, x_old);
|
||||
F_divide_Fprime = fDivide(y, Fprime);
|
||||
|
||||
x_new = fSubtract(x_old, F_divide_Fprime);
|
||||
|
||||
error = ConvertBackToInteger(x_new) - ConvertBackToInteger(x_old);
|
||||
|
||||
if (counter > 20) /*20 is already way too many iterations. If we dont have an answer by then, we never will*/
|
||||
return x_new;
|
||||
|
||||
} while (uAbs(error) > 0);
|
||||
|
||||
return (x_new);
|
||||
}
|
||||
|
||||
void SolveQuadracticEqn(fInt A, fInt B, fInt C, fInt Roots[])
|
||||
{
|
||||
fInt *pRoots = &Roots[0];
|
||||
fInt temp, root_first, root_second;
|
||||
fInt f_CONSTANT10, f_CONSTANT100;
|
||||
|
||||
f_CONSTANT100 = ConvertToFraction(100);
|
||||
f_CONSTANT10 = ConvertToFraction(10);
|
||||
|
||||
while(GreaterThan(A, f_CONSTANT100) || GreaterThan(B, f_CONSTANT100) || GreaterThan(C, f_CONSTANT100)) {
|
||||
A = fDivide(A, f_CONSTANT10);
|
||||
B = fDivide(B, f_CONSTANT10);
|
||||
C = fDivide(C, f_CONSTANT10);
|
||||
}
|
||||
|
||||
temp = fMultiply(ConvertToFraction(4), A); /* root = 4*A */
|
||||
temp = fMultiply(temp, C); /* root = 4*A*C */
|
||||
temp = fSubtract(fGetSquare(B), temp); /* root = b^2 - 4AC */
|
||||
temp = fSqrt(temp); /*root = Sqrt (b^2 - 4AC); */
|
||||
|
||||
root_first = fSubtract(fNegate(B), temp); /* b - Sqrt(b^2 - 4AC) */
|
||||
root_second = fAdd(fNegate(B), temp); /* b + Sqrt(b^2 - 4AC) */
|
||||
|
||||
root_first = fDivide(root_first, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
|
||||
root_first = fDivide(root_first, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
|
||||
|
||||
root_second = fDivide(root_second, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
|
||||
root_second = fDivide(root_second, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
|
||||
|
||||
*(pRoots + 0) = root_first;
|
||||
*(pRoots + 1) = root_second;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* SUPPORT FUNCTIONS
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Addition using two normal ints - Temporary - Use only for testing purposes?. */
|
||||
fInt Add (int X, int Y)
|
||||
{
|
||||
fInt A, B, Sum;
|
||||
|
||||
A.full = (X << SHIFT_AMOUNT);
|
||||
B.full = (Y << SHIFT_AMOUNT);
|
||||
|
||||
Sum.full = A.full + B.full;
|
||||
|
||||
return Sum;
|
||||
}
|
||||
|
||||
/* Conversion Functions */
|
||||
int GetReal (fInt A)
|
||||
{
|
||||
return (A.full >> SHIFT_AMOUNT);
|
||||
}
|
||||
|
||||
/* Temporarily Disabled */
|
||||
int GetRoundedValue(fInt A) /*For now, round the 3rd decimal place */
|
||||
{
|
||||
/* ROUNDING TEMPORARLY DISABLED
|
||||
int temp = A.full;
|
||||
int decimal_cutoff, decimal_mask = 0x000001FF;
|
||||
decimal_cutoff = temp & decimal_mask;
|
||||
if (decimal_cutoff > 0x147) {
|
||||
temp += 673;
|
||||
}*/
|
||||
|
||||
return ConvertBackToInteger(A)/10000; /*Temporary - in case this was used somewhere else */
|
||||
}
|
||||
|
||||
fInt Multiply (int X, int Y)
|
||||
{
|
||||
fInt A, B, Product;
|
||||
|
||||
A.full = X << SHIFT_AMOUNT;
|
||||
B.full = Y << SHIFT_AMOUNT;
|
||||
|
||||
Product = fMultiply(A, B);
|
||||
|
||||
return Product;
|
||||
}
|
||||
|
||||
fInt Divide (int X, int Y)
|
||||
{
|
||||
fInt A, B, Quotient;
|
||||
|
||||
A.full = X << SHIFT_AMOUNT;
|
||||
B.full = Y << SHIFT_AMOUNT;
|
||||
|
||||
Quotient = fDivide(A, B);
|
||||
|
||||
return Quotient;
|
||||
}
|
||||
|
||||
int uGetScaledDecimal (fInt A) /*Converts the fractional portion to whole integers - Costly function */
|
||||
{
|
||||
int dec[PRECISION];
|
||||
int i, scaledDecimal = 0, tmp = A.partial.decimal;
|
||||
|
||||
for (i = 0; i < PRECISION; i++) {
|
||||
dec[i] = tmp / (1 << SHIFT_AMOUNT);
|
||||
tmp = tmp - ((1 << SHIFT_AMOUNT)*dec[i]);
|
||||
tmp *= 10;
|
||||
scaledDecimal = scaledDecimal + dec[i]*uPow(10, PRECISION - 1 -i);
|
||||
}
|
||||
|
||||
return scaledDecimal;
|
||||
}
|
||||
|
||||
int uPow(int base, int power)
|
||||
{
|
||||
if (power == 0)
|
||||
return 1;
|
||||
else
|
||||
return (base)*uPow(base, power - 1);
|
||||
}
|
||||
|
||||
fInt fAbs(fInt A)
|
||||
{
|
||||
if (A.partial.real < 0)
|
||||
return (fMultiply(A, ConvertToFraction(-1)));
|
||||
else
|
||||
return A;
|
||||
}
|
||||
|
||||
int uAbs(int X)
|
||||
{
|
||||
if (X < 0)
|
||||
return (X * -1);
|
||||
else
|
||||
return X;
|
||||
}
|
||||
|
||||
fInt fRoundUpByStepSize(fInt A, fInt fStepSize, bool error_term)
|
||||
{
|
||||
fInt solution;
|
||||
|
||||
solution = fDivide(A, fStepSize);
|
||||
solution.partial.decimal = 0; /*All fractional digits changes to 0 */
|
||||
|
||||
if (error_term)
|
||||
solution.partial.real += 1; /*Error term of 1 added */
|
||||
|
||||
solution = fMultiply(solution, fStepSize);
|
||||
solution = fAdd(solution, fStepSize);
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
64
drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
Normal file
64
drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 <linux/types.h>
|
||||
#include "atom-types.h"
|
||||
#include "atombios.h"
|
||||
#include "pppcielanes.h"
|
||||
|
||||
/** \file
|
||||
* Functions related to PCIe lane changes.
|
||||
*/
|
||||
|
||||
/* For converting from number of lanes to lane bits. */
|
||||
static const unsigned char pp_r600_encode_lanes[] = {
|
||||
0, /* 0 Not Supported */
|
||||
1, /* 1 Lane */
|
||||
2, /* 2 Lanes */
|
||||
0, /* 3 Not Supported */
|
||||
3, /* 4 Lanes */
|
||||
0, /* 5 Not Supported */
|
||||
0, /* 6 Not Supported */
|
||||
0, /* 7 Not Supported */
|
||||
4, /* 8 Lanes */
|
||||
0, /* 9 Not Supported */
|
||||
0, /* 10 Not Supported */
|
||||
0, /* 11 Not Supported */
|
||||
5, /* 12 Lanes (Not actually supported) */
|
||||
0, /* 13 Not Supported */
|
||||
0, /* 14 Not Supported */
|
||||
0, /* 15 Not Supported */
|
||||
6 /* 16 Lanes */
|
||||
};
|
||||
|
||||
static const unsigned char pp_r600_decoded_lanes[8] = { 16, 1, 2, 4, 8, 12, 16, };
|
||||
|
||||
uint8_t encode_pcie_lane_width(uint32_t num_lanes)
|
||||
{
|
||||
return pp_r600_encode_lanes[num_lanes];
|
||||
}
|
||||
|
||||
uint8_t decode_pcie_lane_width(uint32_t num_lanes)
|
||||
{
|
||||
return pp_r600_decoded_lanes[num_lanes];
|
||||
}
|
||||
31
drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
Normal file
31
drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 PP_PCIELANES_H
|
||||
#define PP_PCIELANES_H
|
||||
|
||||
extern uint8_t encode_pcie_lane_width(uint32_t num_lanes);
|
||||
extern uint8_t decode_pcie_lane_width(uint32_t num_lanes);
|
||||
|
||||
#endif
|
||||
|
||||
1688
drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
Normal file
1688
drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
Normal file
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 a new issue