diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-08-14 01:01:40 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-08-30 16:30:28 -0400 |
commit | 41a524abff2630dce0f9c38eb7340fbf2dc5bf27 (patch) | |
tree | 212adab0104b0605013934e95dcb0460daf1130e | |
parent | 6bb5c0d74c1962a8b1c722521c01e19d38c47370 (diff) |
drm/radeon/kms: add dpm support for KB/KV
This adds dpm support for KB/KV asics. This includes:
- dynamic engine clock scaling
- dynamic voltage scaling
- power containment
- shader power scaling
Set radeon.dpm=1 to enable.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/cik.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/cikd.h | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/kv_dpm.c | 2536 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/kv_dpm.h | 199 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/kv_smc.c | 207 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/ppsmc.h | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/smu7.h | 170 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/smu7_fusion.h | 300 |
12 files changed, 3576 insertions, 4 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index bfabd69b4e39..d3265b5d4661 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile | |||
@@ -79,7 +79,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ | |||
79 | si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ | 79 | si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ |
80 | r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ | 80 | r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ |
81 | rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ | 81 | rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ |
82 | trinity_smc.o ni_dpm.o si_smc.o si_dpm.o | 82 | trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o |
83 | 83 | ||
84 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o | 84 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o |
85 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o | 85 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o |
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index d0804f79efed..87e5aeed6e88 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c | |||
@@ -6593,6 +6593,7 @@ int cik_irq_set(struct radeon_device *rdev) | |||
6593 | u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; | 6593 | u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; |
6594 | u32 grbm_int_cntl = 0; | 6594 | u32 grbm_int_cntl = 0; |
6595 | u32 dma_cntl, dma_cntl1; | 6595 | u32 dma_cntl, dma_cntl1; |
6596 | u32 thermal_int; | ||
6596 | 6597 | ||
6597 | if (!rdev->irq.installed) { | 6598 | if (!rdev->irq.installed) { |
6598 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); | 6599 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
@@ -6625,6 +6626,9 @@ int cik_irq_set(struct radeon_device *rdev) | |||
6625 | cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; | 6626 | cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
6626 | cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; | 6627 | cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
6627 | 6628 | ||
6629 | thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) & | ||
6630 | ~(THERM_INTH_MASK | THERM_INTL_MASK); | ||
6631 | |||
6628 | /* enable CP interrupts on all rings */ | 6632 | /* enable CP interrupts on all rings */ |
6629 | if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { | 6633 | if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { |
6630 | DRM_DEBUG("cik_irq_set: sw int gfx\n"); | 6634 | DRM_DEBUG("cik_irq_set: sw int gfx\n"); |
@@ -6782,6 +6786,11 @@ int cik_irq_set(struct radeon_device *rdev) | |||
6782 | hpd6 |= DC_HPDx_INT_EN; | 6786 | hpd6 |= DC_HPDx_INT_EN; |
6783 | } | 6787 | } |
6784 | 6788 | ||
6789 | if (rdev->irq.dpm_thermal) { | ||
6790 | DRM_DEBUG("dpm thermal\n"); | ||
6791 | thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; | ||
6792 | } | ||
6793 | |||
6785 | WREG32(CP_INT_CNTL_RING0, cp_int_cntl); | 6794 | WREG32(CP_INT_CNTL_RING0, cp_int_cntl); |
6786 | 6795 | ||
6787 | WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl); | 6796 | WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl); |
@@ -6816,6 +6825,8 @@ int cik_irq_set(struct radeon_device *rdev) | |||
6816 | WREG32(DC_HPD5_INT_CONTROL, hpd5); | 6825 | WREG32(DC_HPD5_INT_CONTROL, hpd5); |
6817 | WREG32(DC_HPD6_INT_CONTROL, hpd6); | 6826 | WREG32(DC_HPD6_INT_CONTROL, hpd6); |
6818 | 6827 | ||
6828 | WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); | ||
6829 | |||
6819 | return 0; | 6830 | return 0; |
6820 | } | 6831 | } |
6821 | 6832 | ||
@@ -7027,6 +7038,7 @@ int cik_irq_process(struct radeon_device *rdev) | |||
7027 | bool queue_hotplug = false; | 7038 | bool queue_hotplug = false; |
7028 | bool queue_reset = false; | 7039 | bool queue_reset = false; |
7029 | u32 addr, status, mc_client; | 7040 | u32 addr, status, mc_client; |
7041 | bool queue_thermal = false; | ||
7030 | 7042 | ||
7031 | if (!rdev->ih.enabled || rdev->shutdown) | 7043 | if (!rdev->ih.enabled || rdev->shutdown) |
7032 | return IRQ_NONE; | 7044 | return IRQ_NONE; |
@@ -7377,6 +7389,19 @@ restart_ih: | |||
7377 | break; | 7389 | break; |
7378 | } | 7390 | } |
7379 | break; | 7391 | break; |
7392 | case 230: /* thermal low to high */ | ||
7393 | DRM_DEBUG("IH: thermal low to high\n"); | ||
7394 | rdev->pm.dpm.thermal.high_to_low = false; | ||
7395 | queue_thermal = true; | ||
7396 | break; | ||
7397 | case 231: /* thermal high to low */ | ||
7398 | DRM_DEBUG("IH: thermal high to low\n"); | ||
7399 | rdev->pm.dpm.thermal.high_to_low = true; | ||
7400 | queue_thermal = true; | ||
7401 | break; | ||
7402 | case 233: /* GUI IDLE */ | ||
7403 | DRM_DEBUG("IH: GUI idle\n"); | ||
7404 | break; | ||
7380 | case 241: /* SDMA Privileged inst */ | 7405 | case 241: /* SDMA Privileged inst */ |
7381 | case 247: /* SDMA Privileged inst */ | 7406 | case 247: /* SDMA Privileged inst */ |
7382 | DRM_ERROR("Illegal instruction in SDMA command stream\n"); | 7407 | DRM_ERROR("Illegal instruction in SDMA command stream\n"); |
@@ -7416,9 +7441,6 @@ restart_ih: | |||
7416 | break; | 7441 | break; |
7417 | } | 7442 | } |
7418 | break; | 7443 | break; |
7419 | case 233: /* GUI IDLE */ | ||
7420 | DRM_DEBUG("IH: GUI idle\n"); | ||
7421 | break; | ||
7422 | default: | 7444 | default: |
7423 | DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); | 7445 | DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
7424 | break; | 7446 | break; |
@@ -7432,6 +7454,8 @@ restart_ih: | |||
7432 | schedule_work(&rdev->hotplug_work); | 7454 | schedule_work(&rdev->hotplug_work); |
7433 | if (queue_reset) | 7455 | if (queue_reset) |
7434 | schedule_work(&rdev->reset_work); | 7456 | schedule_work(&rdev->reset_work); |
7457 | if (queue_thermal) | ||
7458 | schedule_work(&rdev->pm.dpm.thermal.work); | ||
7435 | rdev->ih.rptr = rptr; | 7459 | rdev->ih.rptr = rptr; |
7436 | WREG32(IH_RB_RPTR, rdev->ih.rptr); | 7460 | WREG32(IH_RB_RPTR, rdev->ih.rptr); |
7437 | atomic_set(&rdev->ih.lock, 0); | 7461 | atomic_set(&rdev->ih.lock, 0); |
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 65886caaf756..179ca3625ae4 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h | |||
@@ -28,10 +28,59 @@ | |||
28 | 28 | ||
29 | #define CIK_RB_BITMAP_WIDTH_PER_SH 2 | 29 | #define CIK_RB_BITMAP_WIDTH_PER_SH 2 |
30 | 30 | ||
31 | /* DIDT IND registers */ | ||
32 | #define DIDT_SQ_CTRL0 0x0 | ||
33 | # define DIDT_CTRL_EN (1 << 0) | ||
34 | #define DIDT_DB_CTRL0 0x20 | ||
35 | #define DIDT_TD_CTRL0 0x40 | ||
36 | #define DIDT_TCP_CTRL0 0x60 | ||
37 | |||
31 | /* SMC IND registers */ | 38 | /* SMC IND registers */ |
39 | #define NB_DPM_CONFIG_1 0x3F9E8 | ||
40 | # define Dpm0PgNbPsLo(x) ((x) << 0) | ||
41 | # define Dpm0PgNbPsLo_MASK 0x000000ff | ||
42 | # define Dpm0PgNbPsLo_SHIFT 0 | ||
43 | # define Dpm0PgNbPsHi(x) ((x) << 8) | ||
44 | # define Dpm0PgNbPsHi_MASK 0x0000ff00 | ||
45 | # define Dpm0PgNbPsHi_SHIFT 8 | ||
46 | # define DpmXNbPsLo(x) ((x) << 16) | ||
47 | # define DpmXNbPsLo_MASK 0x00ff0000 | ||
48 | # define DpmXNbPsLo_SHIFT 16 | ||
49 | # define DpmXNbPsHi(x) ((x) << 24) | ||
50 | # define DpmXNbPsHi_MASK 0xff000000 | ||
51 | # define DpmXNbPsHi_SHIFT 24 | ||
52 | |||
53 | #define SMC_SYSCON_MSG_ARG_0 0x80000068 | ||
54 | |||
32 | #define GENERAL_PWRMGT 0xC0200000 | 55 | #define GENERAL_PWRMGT 0xC0200000 |
56 | # define GLOBAL_PWRMGT_EN (1 << 0) | ||
33 | # define GPU_COUNTER_CLK (1 << 15) | 57 | # define GPU_COUNTER_CLK (1 << 15) |
34 | 58 | ||
59 | #define SCLK_PWRMGT_CNTL 0xC0200008 | ||
60 | # define RESET_BUSY_CNT (1 << 4) | ||
61 | # define RESET_SCLK_CNT (1 << 5) | ||
62 | # define DYNAMIC_PM_EN (1 << 21) | ||
63 | |||
64 | #define CG_FTV_0 0xC02001A8 | ||
65 | |||
66 | #define LCAC_SX0_OVR_SEL 0xC0400D04 | ||
67 | #define LCAC_SX0_OVR_VAL 0xC0400D08 | ||
68 | |||
69 | #define LCAC_MC0_OVR_SEL 0xC0400D34 | ||
70 | #define LCAC_MC0_OVR_VAL 0xC0400D38 | ||
71 | |||
72 | #define LCAC_MC1_OVR_SEL 0xC0400D40 | ||
73 | #define LCAC_MC1_OVR_VAL 0xC0400D44 | ||
74 | |||
75 | #define LCAC_MC2_OVR_SEL 0xC0400D4C | ||
76 | #define LCAC_MC2_OVR_VAL 0xC0400D50 | ||
77 | |||
78 | #define LCAC_MC3_OVR_SEL 0xC0400D58 | ||
79 | #define LCAC_MC3_OVR_VAL 0xC0400D5C | ||
80 | |||
81 | #define LCAC_CPL_OVR_SEL 0xC0400D84 | ||
82 | #define LCAC_CPL_OVR_VAL 0xC0400D88 | ||
83 | |||
35 | #define CG_MULT_THERMAL_STATUS 0xC0300014 | 84 | #define CG_MULT_THERMAL_STATUS 0xC0300014 |
36 | #define ASIC_MAX_TEMP(x) ((x) << 0) | 85 | #define ASIC_MAX_TEMP(x) ((x) << 0) |
37 | #define ASIC_MAX_TEMP_MASK 0x000001ff | 86 | #define ASIC_MAX_TEMP_MASK 0x000001ff |
@@ -60,6 +109,16 @@ | |||
60 | # define ZCLK_SEL(x) ((x) << 8) | 109 | # define ZCLK_SEL(x) ((x) << 8) |
61 | # define ZCLK_SEL_MASK 0xFF00 | 110 | # define ZCLK_SEL_MASK 0xFF00 |
62 | 111 | ||
112 | #define CG_THERMAL_INT_CTRL 0xC2100028 | ||
113 | #define DIG_THERM_INTH(x) ((x) << 0) | ||
114 | #define DIG_THERM_INTH_MASK 0x000000FF | ||
115 | #define DIG_THERM_INTH_SHIFT 0 | ||
116 | #define DIG_THERM_INTL(x) ((x) << 8) | ||
117 | #define DIG_THERM_INTL_MASK 0x0000FF00 | ||
118 | #define DIG_THERM_INTL_SHIFT 8 | ||
119 | #define THERM_INTH_MASK (1 << 24) | ||
120 | #define THERM_INTL_MASK (1 << 25) | ||
121 | |||
63 | /* PCIE registers idx/data 0x38/0x3c */ | 122 | /* PCIE registers idx/data 0x38/0x3c */ |
64 | #define PB0_PIF_PWRDOWN_0 0x1100012 /* PCIE */ | 123 | #define PB0_PIF_PWRDOWN_0 0x1100012 /* PCIE */ |
65 | # define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7) | 124 | # define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7) |
@@ -173,6 +232,19 @@ | |||
173 | #define PCIE_INDEX 0x38 | 232 | #define PCIE_INDEX 0x38 |
174 | #define PCIE_DATA 0x3C | 233 | #define PCIE_DATA 0x3C |
175 | 234 | ||
235 | #define SMC_IND_INDEX_0 0x200 | ||
236 | #define SMC_IND_DATA_0 0x204 | ||
237 | |||
238 | #define SMC_IND_ACCESS_CNTL 0x240 | ||
239 | #define AUTO_INCREMENT_IND_0 (1 << 0) | ||
240 | |||
241 | #define SMC_MESSAGE_0 0x250 | ||
242 | #define SMC_MSG_MASK 0xffff | ||
243 | #define SMC_RESP_0 0x254 | ||
244 | #define SMC_RESP_MASK 0xffff | ||
245 | |||
246 | #define SMC_MSG_ARG_0 0x290 | ||
247 | |||
176 | #define VGA_HDP_CONTROL 0x328 | 248 | #define VGA_HDP_CONTROL 0x328 |
177 | #define VGA_MEMORY_DISABLE (1 << 4) | 249 | #define VGA_MEMORY_DISABLE (1 << 4) |
178 | 250 | ||
diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c new file mode 100644 index 000000000000..2e4016356dab --- /dev/null +++ b/drivers/gpu/drm/radeon/kv_dpm.c | |||
@@ -0,0 +1,2536 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "drmP.h" | ||
25 | #include "radeon.h" | ||
26 | #include "cikd.h" | ||
27 | #include "r600_dpm.h" | ||
28 | #include "kv_dpm.h" | ||
29 | |||
30 | #define KV_MAX_DEEPSLEEP_DIVIDER_ID 5 | ||
31 | #define KV_MINIMUM_ENGINE_CLOCK 800 | ||
32 | #define SMC_RAM_END 0x40000 | ||
33 | |||
34 | static void kv_init_graphics_levels(struct radeon_device *rdev); | ||
35 | static int kv_calculate_ds_divider(struct radeon_device *rdev); | ||
36 | static int kv_calculate_nbps_level_settings(struct radeon_device *rdev); | ||
37 | static int kv_calculate_dpm_settings(struct radeon_device *rdev); | ||
38 | static void kv_enable_new_levels(struct radeon_device *rdev); | ||
39 | static void kv_program_nbps_index_settings(struct radeon_device *rdev, | ||
40 | struct radeon_ps *new_rps); | ||
41 | static int kv_set_enabled_levels(struct radeon_device *rdev); | ||
42 | static int kv_force_dpm_lowest(struct radeon_device *rdev); | ||
43 | static void kv_apply_state_adjust_rules(struct radeon_device *rdev, | ||
44 | struct radeon_ps *new_rps, | ||
45 | struct radeon_ps *old_rps); | ||
46 | static int kv_set_thermal_temperature_range(struct radeon_device *rdev, | ||
47 | int min_temp, int max_temp); | ||
48 | static int kv_init_fps_limits(struct radeon_device *rdev); | ||
49 | |||
50 | static void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); | ||
51 | static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate); | ||
52 | static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate); | ||
53 | static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate); | ||
54 | |||
55 | extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev); | ||
56 | extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); | ||
57 | extern void cik_update_cg(struct radeon_device *rdev, | ||
58 | u32 block, bool enable); | ||
59 | |||
60 | static const struct kv_lcac_config_values sx_local_cac_cfg_kv[] = | ||
61 | { | ||
62 | { 0, 4, 1 }, | ||
63 | { 1, 4, 1 }, | ||
64 | { 2, 5, 1 }, | ||
65 | { 3, 4, 2 }, | ||
66 | { 4, 1, 1 }, | ||
67 | { 5, 5, 2 }, | ||
68 | { 6, 6, 1 }, | ||
69 | { 7, 9, 2 }, | ||
70 | { 0xffffffff } | ||
71 | }; | ||
72 | |||
73 | static const struct kv_lcac_config_values mc0_local_cac_cfg_kv[] = | ||
74 | { | ||
75 | { 0, 4, 1 }, | ||
76 | { 0xffffffff } | ||
77 | }; | ||
78 | |||
79 | static const struct kv_lcac_config_values mc1_local_cac_cfg_kv[] = | ||
80 | { | ||
81 | { 0, 4, 1 }, | ||
82 | { 0xffffffff } | ||
83 | }; | ||
84 | |||
85 | static const struct kv_lcac_config_values mc2_local_cac_cfg_kv[] = | ||
86 | { | ||
87 | { 0, 4, 1 }, | ||
88 | { 0xffffffff } | ||
89 | }; | ||
90 | |||
91 | static const struct kv_lcac_config_values mc3_local_cac_cfg_kv[] = | ||
92 | { | ||
93 | { 0, 4, 1 }, | ||
94 | { 0xffffffff } | ||
95 | }; | ||
96 | |||
97 | static const struct kv_lcac_config_values cpl_local_cac_cfg_kv[] = | ||
98 | { | ||
99 | { 0, 4, 1 }, | ||
100 | { 1, 4, 1 }, | ||
101 | { 2, 5, 1 }, | ||
102 | { 3, 4, 1 }, | ||
103 | { 4, 1, 1 }, | ||
104 | { 5, 5, 1 }, | ||
105 | { 6, 6, 1 }, | ||
106 | { 7, 9, 1 }, | ||
107 | { 8, 4, 1 }, | ||
108 | { 9, 2, 1 }, | ||
109 | { 10, 3, 1 }, | ||
110 | { 11, 6, 1 }, | ||
111 | { 12, 8, 2 }, | ||
112 | { 13, 1, 1 }, | ||
113 | { 14, 2, 1 }, | ||
114 | { 15, 3, 1 }, | ||
115 | { 16, 1, 1 }, | ||
116 | { 17, 4, 1 }, | ||
117 | { 18, 3, 1 }, | ||
118 | { 19, 1, 1 }, | ||
119 | { 20, 8, 1 }, | ||
120 | { 21, 5, 1 }, | ||
121 | { 22, 1, 1 }, | ||
122 | { 23, 1, 1 }, | ||
123 | { 24, 4, 1 }, | ||
124 | { 27, 6, 1 }, | ||
125 | { 28, 1, 1 }, | ||
126 | { 0xffffffff } | ||
127 | }; | ||
128 | |||
129 | static const struct kv_lcac_config_reg sx0_cac_config_reg[] = | ||
130 | { | ||
131 | { 0xc0400d00, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
132 | }; | ||
133 | |||
134 | static const struct kv_lcac_config_reg mc0_cac_config_reg[] = | ||
135 | { | ||
136 | { 0xc0400d30, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
137 | }; | ||
138 | |||
139 | static const struct kv_lcac_config_reg mc1_cac_config_reg[] = | ||
140 | { | ||
141 | { 0xc0400d3c, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
142 | }; | ||
143 | |||
144 | static const struct kv_lcac_config_reg mc2_cac_config_reg[] = | ||
145 | { | ||
146 | { 0xc0400d48, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
147 | }; | ||
148 | |||
149 | static const struct kv_lcac_config_reg mc3_cac_config_reg[] = | ||
150 | { | ||
151 | { 0xc0400d54, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
152 | }; | ||
153 | |||
154 | static const struct kv_lcac_config_reg cpl_cac_config_reg[] = | ||
155 | { | ||
156 | { 0xc0400d80, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } | ||
157 | }; | ||
158 | |||
159 | static const struct kv_pt_config_reg didt_config_kv[] = | ||
160 | { | ||
161 | { 0x10, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
162 | { 0x10, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
163 | { 0x10, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
164 | { 0x10, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
165 | { 0x11, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
166 | { 0x11, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
167 | { 0x11, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
168 | { 0x11, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
169 | { 0x12, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
170 | { 0x12, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
171 | { 0x12, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
172 | { 0x12, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
173 | { 0x2, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, | ||
174 | { 0x2, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, | ||
175 | { 0x2, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, | ||
176 | { 0x1, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
177 | { 0x1, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
178 | { 0x0, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
179 | { 0x30, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
180 | { 0x30, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
181 | { 0x30, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
182 | { 0x30, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
183 | { 0x31, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
184 | { 0x31, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
185 | { 0x31, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
186 | { 0x31, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
187 | { 0x32, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
188 | { 0x32, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
189 | { 0x32, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
190 | { 0x32, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
191 | { 0x22, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, | ||
192 | { 0x22, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, | ||
193 | { 0x22, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, | ||
194 | { 0x21, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
195 | { 0x21, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
196 | { 0x20, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
197 | { 0x50, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
198 | { 0x50, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
199 | { 0x50, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
200 | { 0x50, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
201 | { 0x51, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
202 | { 0x51, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
203 | { 0x51, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
204 | { 0x51, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
205 | { 0x52, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
206 | { 0x52, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
207 | { 0x52, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
208 | { 0x52, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
209 | { 0x42, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, | ||
210 | { 0x42, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, | ||
211 | { 0x42, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, | ||
212 | { 0x41, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
213 | { 0x41, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
214 | { 0x40, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
215 | { 0x70, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
216 | { 0x70, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
217 | { 0x70, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
218 | { 0x70, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
219 | { 0x71, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
220 | { 0x71, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
221 | { 0x71, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
222 | { 0x71, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
223 | { 0x72, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
224 | { 0x72, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
225 | { 0x72, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
226 | { 0x72, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
227 | { 0x62, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, | ||
228 | { 0x62, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, | ||
229 | { 0x62, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, | ||
230 | { 0x61, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
231 | { 0x61, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, | ||
232 | { 0x60, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, | ||
233 | { 0xFFFFFFFF } | ||
234 | }; | ||
235 | |||
236 | static struct kv_ps *kv_get_ps(struct radeon_ps *rps) | ||
237 | { | ||
238 | struct kv_ps *ps = rps->ps_priv; | ||
239 | |||
240 | return ps; | ||
241 | } | ||
242 | |||
243 | static struct kv_power_info *kv_get_pi(struct radeon_device *rdev) | ||
244 | { | ||
245 | struct kv_power_info *pi = rdev->pm.dpm.priv; | ||
246 | |||
247 | return pi; | ||
248 | } | ||
249 | |||
250 | #if 0 | ||
251 | static void kv_program_local_cac_table(struct radeon_device *rdev, | ||
252 | const struct kv_lcac_config_values *local_cac_table, | ||
253 | const struct kv_lcac_config_reg *local_cac_reg) | ||
254 | { | ||
255 | u32 i, count, data; | ||
256 | const struct kv_lcac_config_values *values = local_cac_table; | ||
257 | |||
258 | while (values->block_id != 0xffffffff) { | ||
259 | count = values->signal_id; | ||
260 | for (i = 0; i < count; i++) { | ||
261 | data = ((values->block_id << local_cac_reg->block_shift) & | ||
262 | local_cac_reg->block_mask); | ||
263 | data |= ((i << local_cac_reg->signal_shift) & | ||
264 | local_cac_reg->signal_mask); | ||
265 | data |= ((values->t << local_cac_reg->t_shift) & | ||
266 | local_cac_reg->t_mask); | ||
267 | data |= ((1 << local_cac_reg->enable_shift) & | ||
268 | local_cac_reg->enable_mask); | ||
269 | WREG32_SMC(local_cac_reg->cntl, data); | ||
270 | } | ||
271 | values++; | ||
272 | } | ||
273 | } | ||
274 | #endif | ||
275 | |||
276 | static int kv_program_pt_config_registers(struct radeon_device *rdev, | ||
277 | const struct kv_pt_config_reg *cac_config_regs) | ||
278 | { | ||
279 | const struct kv_pt_config_reg *config_regs = cac_config_regs; | ||
280 | u32 data; | ||
281 | u32 cache = 0; | ||
282 | |||
283 | if (config_regs == NULL) | ||
284 | return -EINVAL; | ||
285 | |||
286 | while (config_regs->offset != 0xFFFFFFFF) { | ||
287 | if (config_regs->type == KV_CONFIGREG_CACHE) { | ||
288 | cache |= ((config_regs->value << config_regs->shift) & config_regs->mask); | ||
289 | } else { | ||
290 | switch (config_regs->type) { | ||
291 | case KV_CONFIGREG_SMC_IND: | ||
292 | data = RREG32_SMC(config_regs->offset); | ||
293 | break; | ||
294 | case KV_CONFIGREG_DIDT_IND: | ||
295 | data = RREG32_DIDT(config_regs->offset); | ||
296 | break; | ||
297 | default: | ||
298 | data = RREG32(config_regs->offset << 2); | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | data &= ~config_regs->mask; | ||
303 | data |= ((config_regs->value << config_regs->shift) & config_regs->mask); | ||
304 | data |= cache; | ||
305 | cache = 0; | ||
306 | |||
307 | switch (config_regs->type) { | ||
308 | case KV_CONFIGREG_SMC_IND: | ||
309 | WREG32_SMC(config_regs->offset, data); | ||
310 | break; | ||
311 | case KV_CONFIGREG_DIDT_IND: | ||
312 | WREG32_DIDT(config_regs->offset, data); | ||
313 | break; | ||
314 | default: | ||
315 | WREG32(config_regs->offset << 2, data); | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | config_regs++; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void kv_do_enable_didt(struct radeon_device *rdev, bool enable) | ||
326 | { | ||
327 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
328 | u32 data; | ||
329 | |||
330 | if (pi->caps_sq_ramping) { | ||
331 | data = RREG32_DIDT(DIDT_SQ_CTRL0); | ||
332 | if (enable) | ||
333 | data |= DIDT_CTRL_EN; | ||
334 | else | ||
335 | data &= ~DIDT_CTRL_EN; | ||
336 | WREG32_DIDT(DIDT_SQ_CTRL0, data); | ||
337 | } | ||
338 | |||
339 | if (pi->caps_db_ramping) { | ||
340 | data = RREG32_DIDT(DIDT_DB_CTRL0); | ||
341 | if (enable) | ||
342 | data |= DIDT_CTRL_EN; | ||
343 | else | ||
344 | data &= ~DIDT_CTRL_EN; | ||
345 | WREG32_DIDT(DIDT_DB_CTRL0, data); | ||
346 | } | ||
347 | |||
348 | if (pi->caps_td_ramping) { | ||
349 | data = RREG32_DIDT(DIDT_TD_CTRL0); | ||
350 | if (enable) | ||
351 | data |= DIDT_CTRL_EN; | ||
352 | else | ||
353 | data &= ~DIDT_CTRL_EN; | ||
354 | WREG32_DIDT(DIDT_TD_CTRL0, data); | ||
355 | } | ||
356 | |||
357 | if (pi->caps_tcp_ramping) { | ||
358 | data = RREG32_DIDT(DIDT_TCP_CTRL0); | ||
359 | if (enable) | ||
360 | data |= DIDT_CTRL_EN; | ||
361 | else | ||
362 | data &= ~DIDT_CTRL_EN; | ||
363 | WREG32_DIDT(DIDT_TCP_CTRL0, data); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | static int kv_enable_didt(struct radeon_device *rdev, bool enable) | ||
368 | { | ||
369 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
370 | int ret; | ||
371 | |||
372 | if (pi->caps_sq_ramping || | ||
373 | pi->caps_db_ramping || | ||
374 | pi->caps_td_ramping || | ||
375 | pi->caps_tcp_ramping) { | ||
376 | cik_enter_rlc_safe_mode(rdev); | ||
377 | |||
378 | if (enable) { | ||
379 | ret = kv_program_pt_config_registers(rdev, didt_config_kv); | ||
380 | if (ret) { | ||
381 | cik_exit_rlc_safe_mode(rdev); | ||
382 | return ret; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | kv_do_enable_didt(rdev, enable); | ||
387 | |||
388 | cik_exit_rlc_safe_mode(rdev); | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | #if 0 | ||
395 | static void kv_initialize_hardware_cac_manager(struct radeon_device *rdev) | ||
396 | { | ||
397 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
398 | |||
399 | if (pi->caps_cac) { | ||
400 | WREG32_SMC(LCAC_SX0_OVR_SEL, 0); | ||
401 | WREG32_SMC(LCAC_SX0_OVR_VAL, 0); | ||
402 | kv_program_local_cac_table(rdev, sx_local_cac_cfg_kv, sx0_cac_config_reg); | ||
403 | |||
404 | WREG32_SMC(LCAC_MC0_OVR_SEL, 0); | ||
405 | WREG32_SMC(LCAC_MC0_OVR_VAL, 0); | ||
406 | kv_program_local_cac_table(rdev, mc0_local_cac_cfg_kv, mc0_cac_config_reg); | ||
407 | |||
408 | WREG32_SMC(LCAC_MC1_OVR_SEL, 0); | ||
409 | WREG32_SMC(LCAC_MC1_OVR_VAL, 0); | ||
410 | kv_program_local_cac_table(rdev, mc1_local_cac_cfg_kv, mc1_cac_config_reg); | ||
411 | |||
412 | WREG32_SMC(LCAC_MC2_OVR_SEL, 0); | ||
413 | WREG32_SMC(LCAC_MC2_OVR_VAL, 0); | ||
414 | kv_program_local_cac_table(rdev, mc2_local_cac_cfg_kv, mc2_cac_config_reg); | ||
415 | |||
416 | WREG32_SMC(LCAC_MC3_OVR_SEL, 0); | ||
417 | WREG32_SMC(LCAC_MC3_OVR_VAL, 0); | ||
418 | kv_program_local_cac_table(rdev, mc3_local_cac_cfg_kv, mc3_cac_config_reg); | ||
419 | |||
420 | WREG32_SMC(LCAC_CPL_OVR_SEL, 0); | ||
421 | WREG32_SMC(LCAC_CPL_OVR_VAL, 0); | ||
422 | kv_program_local_cac_table(rdev, cpl_local_cac_cfg_kv, cpl_cac_config_reg); | ||
423 | } | ||
424 | } | ||
425 | #endif | ||
426 | |||
427 | static int kv_enable_smc_cac(struct radeon_device *rdev, bool enable) | ||
428 | { | ||
429 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
430 | int ret = 0; | ||
431 | |||
432 | if (pi->caps_cac) { | ||
433 | if (enable) { | ||
434 | ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableCac); | ||
435 | if (ret) | ||
436 | pi->cac_enabled = false; | ||
437 | else | ||
438 | pi->cac_enabled = true; | ||
439 | } else if (pi->cac_enabled) { | ||
440 | kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableCac); | ||
441 | pi->cac_enabled = false; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | static int kv_process_firmware_header(struct radeon_device *rdev) | ||
449 | { | ||
450 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
451 | u32 tmp; | ||
452 | int ret; | ||
453 | |||
454 | ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + | ||
455 | offsetof(SMU7_Firmware_Header, DpmTable), | ||
456 | &tmp, pi->sram_end); | ||
457 | |||
458 | if (ret == 0) | ||
459 | pi->dpm_table_start = tmp; | ||
460 | |||
461 | ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + | ||
462 | offsetof(SMU7_Firmware_Header, SoftRegisters), | ||
463 | &tmp, pi->sram_end); | ||
464 | |||
465 | if (ret == 0) | ||
466 | pi->soft_regs_start = tmp; | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static int kv_enable_dpm_voltage_scaling(struct radeon_device *rdev) | ||
472 | { | ||
473 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
474 | int ret; | ||
475 | |||
476 | pi->graphics_voltage_change_enable = 1; | ||
477 | |||
478 | ret = kv_copy_bytes_to_smc(rdev, | ||
479 | pi->dpm_table_start + | ||
480 | offsetof(SMU7_Fusion_DpmTable, GraphicsVoltageChangeEnable), | ||
481 | &pi->graphics_voltage_change_enable, | ||
482 | sizeof(u8), pi->sram_end); | ||
483 | |||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | static int kv_set_dpm_interval(struct radeon_device *rdev) | ||
488 | { | ||
489 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
490 | int ret; | ||
491 | |||
492 | pi->graphics_interval = 1; | ||
493 | |||
494 | ret = kv_copy_bytes_to_smc(rdev, | ||
495 | pi->dpm_table_start + | ||
496 | offsetof(SMU7_Fusion_DpmTable, GraphicsInterval), | ||
497 | &pi->graphics_interval, | ||
498 | sizeof(u8), pi->sram_end); | ||
499 | |||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | static int kv_set_dpm_boot_state(struct radeon_device *rdev) | ||
504 | { | ||
505 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
506 | int ret; | ||
507 | |||
508 | ret = kv_copy_bytes_to_smc(rdev, | ||
509 | pi->dpm_table_start + | ||
510 | offsetof(SMU7_Fusion_DpmTable, GraphicsBootLevel), | ||
511 | &pi->graphics_boot_level, | ||
512 | sizeof(u8), pi->sram_end); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | static void kv_program_vc(struct radeon_device *rdev) | ||
518 | { | ||
519 | WREG32_SMC(CG_FTV_0, 0x3FFFC000); | ||
520 | } | ||
521 | |||
522 | static void kv_clear_vc(struct radeon_device *rdev) | ||
523 | { | ||
524 | WREG32_SMC(CG_FTV_0, 0); | ||
525 | } | ||
526 | |||
527 | static int kv_set_divider_value(struct radeon_device *rdev, | ||
528 | u32 index, u32 sclk) | ||
529 | { | ||
530 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
531 | struct atom_clock_dividers dividers; | ||
532 | int ret; | ||
533 | |||
534 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
535 | sclk, false, ÷rs); | ||
536 | if (ret) | ||
537 | return ret; | ||
538 | |||
539 | pi->graphics_level[index].SclkDid = (u8)dividers.post_div; | ||
540 | pi->graphics_level[index].SclkFrequency = cpu_to_be32(sclk); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev, | ||
546 | u16 voltage) | ||
547 | { | ||
548 | return 6200 - (voltage * 25); | ||
549 | } | ||
550 | |||
551 | static u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev, | ||
552 | u32 vid_2bit) | ||
553 | { | ||
554 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
555 | u32 vid_8bit = sumo_convert_vid2_to_vid7(rdev, | ||
556 | &pi->sys_info.vid_mapping_table, | ||
557 | vid_2bit); | ||
558 | |||
559 | return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit); | ||
560 | } | ||
561 | |||
562 | |||
563 | static int kv_set_vid(struct radeon_device *rdev, u32 index, u32 vid) | ||
564 | { | ||
565 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
566 | |||
567 | pi->graphics_level[index].VoltageDownH = (u8)pi->voltage_drop_t; | ||
568 | pi->graphics_level[index].MinVddNb = | ||
569 | cpu_to_be32(kv_convert_2bit_index_to_voltage(rdev, vid)); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int kv_set_at(struct radeon_device *rdev, u32 index, u32 at) | ||
575 | { | ||
576 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
577 | |||
578 | pi->graphics_level[index].AT = cpu_to_be16((u16)at); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static void kv_dpm_power_level_enable(struct radeon_device *rdev, | ||
584 | u32 index, bool enable) | ||
585 | { | ||
586 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
587 | |||
588 | pi->graphics_level[index].EnabledForActivity = enable ? 1 : 0; | ||
589 | } | ||
590 | |||
591 | static void kv_start_dpm(struct radeon_device *rdev) | ||
592 | { | ||
593 | u32 tmp = RREG32_SMC(GENERAL_PWRMGT); | ||
594 | |||
595 | tmp |= GLOBAL_PWRMGT_EN; | ||
596 | WREG32_SMC(GENERAL_PWRMGT, tmp); | ||
597 | |||
598 | kv_smc_dpm_enable(rdev, true); | ||
599 | } | ||
600 | |||
601 | static void kv_stop_dpm(struct radeon_device *rdev) | ||
602 | { | ||
603 | kv_smc_dpm_enable(rdev, false); | ||
604 | } | ||
605 | |||
606 | static void kv_start_am(struct radeon_device *rdev) | ||
607 | { | ||
608 | u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); | ||
609 | |||
610 | sclk_pwrmgt_cntl &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT); | ||
611 | sclk_pwrmgt_cntl |= DYNAMIC_PM_EN; | ||
612 | |||
613 | WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); | ||
614 | } | ||
615 | |||
616 | static void kv_reset_am(struct radeon_device *rdev) | ||
617 | { | ||
618 | u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); | ||
619 | |||
620 | sclk_pwrmgt_cntl |= (RESET_SCLK_CNT | RESET_BUSY_CNT); | ||
621 | |||
622 | WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); | ||
623 | } | ||
624 | |||
625 | static int kv_freeze_sclk_dpm(struct radeon_device *rdev, bool freeze) | ||
626 | { | ||
627 | return kv_notify_message_to_smu(rdev, freeze ? | ||
628 | PPSMC_MSG_SCLKDPM_FreezeLevel : PPSMC_MSG_SCLKDPM_UnfreezeLevel); | ||
629 | } | ||
630 | |||
631 | static int kv_force_lowest_valid(struct radeon_device *rdev) | ||
632 | { | ||
633 | return kv_force_dpm_lowest(rdev); | ||
634 | } | ||
635 | |||
636 | static int kv_unforce_levels(struct radeon_device *rdev) | ||
637 | { | ||
638 | return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel); | ||
639 | } | ||
640 | |||
641 | static int kv_update_sclk_t(struct radeon_device *rdev) | ||
642 | { | ||
643 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
644 | u32 low_sclk_interrupt_t = 0; | ||
645 | int ret = 0; | ||
646 | |||
647 | if (pi->caps_sclk_throttle_low_notification) { | ||
648 | low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t); | ||
649 | |||
650 | ret = kv_copy_bytes_to_smc(rdev, | ||
651 | pi->dpm_table_start + | ||
652 | offsetof(SMU7_Fusion_DpmTable, LowSclkInterruptT), | ||
653 | (u8 *)&low_sclk_interrupt_t, | ||
654 | sizeof(u32), pi->sram_end); | ||
655 | } | ||
656 | return ret; | ||
657 | } | ||
658 | |||
659 | static int kv_program_bootup_state(struct radeon_device *rdev) | ||
660 | { | ||
661 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
662 | u32 i; | ||
663 | struct radeon_clock_voltage_dependency_table *table = | ||
664 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
665 | |||
666 | if (table && table->count) { | ||
667 | for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) { | ||
668 | if ((table->entries[i].clk == pi->boot_pl.sclk) || | ||
669 | (i == 0)) | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | pi->graphics_boot_level = (u8)i; | ||
674 | kv_dpm_power_level_enable(rdev, i, true); | ||
675 | } else { | ||
676 | struct sumo_sclk_voltage_mapping_table *table = | ||
677 | &pi->sys_info.sclk_voltage_mapping_table; | ||
678 | |||
679 | if (table->num_max_dpm_entries == 0) | ||
680 | return -EINVAL; | ||
681 | |||
682 | for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) { | ||
683 | if ((table->entries[i].sclk_frequency == pi->boot_pl.sclk) || | ||
684 | (i == 0)) | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | pi->graphics_boot_level = (u8)i; | ||
689 | kv_dpm_power_level_enable(rdev, i, true); | ||
690 | } | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int kv_enable_auto_thermal_throttling(struct radeon_device *rdev) | ||
695 | { | ||
696 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
697 | int ret; | ||
698 | |||
699 | pi->graphics_therm_throttle_enable = 1; | ||
700 | |||
701 | ret = kv_copy_bytes_to_smc(rdev, | ||
702 | pi->dpm_table_start + | ||
703 | offsetof(SMU7_Fusion_DpmTable, GraphicsThermThrottleEnable), | ||
704 | &pi->graphics_therm_throttle_enable, | ||
705 | sizeof(u8), pi->sram_end); | ||
706 | |||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | static int kv_upload_dpm_settings(struct radeon_device *rdev) | ||
711 | { | ||
712 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
713 | int ret; | ||
714 | |||
715 | ret = kv_copy_bytes_to_smc(rdev, | ||
716 | pi->dpm_table_start + | ||
717 | offsetof(SMU7_Fusion_DpmTable, GraphicsLevel), | ||
718 | (u8 *)&pi->graphics_level, | ||
719 | sizeof(SMU7_Fusion_GraphicsLevel) * SMU7_MAX_LEVELS_GRAPHICS, | ||
720 | pi->sram_end); | ||
721 | |||
722 | if (ret) | ||
723 | return ret; | ||
724 | |||
725 | ret = kv_copy_bytes_to_smc(rdev, | ||
726 | pi->dpm_table_start + | ||
727 | offsetof(SMU7_Fusion_DpmTable, GraphicsDpmLevelCount), | ||
728 | &pi->graphics_dpm_level_count, | ||
729 | sizeof(u8), pi->sram_end); | ||
730 | |||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | static u32 kv_get_clock_difference(u32 a, u32 b) | ||
735 | { | ||
736 | return (a >= b) ? a - b : b - a; | ||
737 | } | ||
738 | |||
739 | static u32 kv_get_clk_bypass(struct radeon_device *rdev, u32 clk) | ||
740 | { | ||
741 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
742 | u32 value; | ||
743 | |||
744 | if (pi->caps_enable_dfs_bypass) { | ||
745 | if (kv_get_clock_difference(clk, 40000) < 200) | ||
746 | value = 3; | ||
747 | else if (kv_get_clock_difference(clk, 30000) < 200) | ||
748 | value = 2; | ||
749 | else if (kv_get_clock_difference(clk, 20000) < 200) | ||
750 | value = 7; | ||
751 | else if (kv_get_clock_difference(clk, 15000) < 200) | ||
752 | value = 6; | ||
753 | else if (kv_get_clock_difference(clk, 10000) < 200) | ||
754 | value = 8; | ||
755 | else | ||
756 | value = 0; | ||
757 | } else { | ||
758 | value = 0; | ||
759 | } | ||
760 | |||
761 | return value; | ||
762 | } | ||
763 | |||
764 | static int kv_populate_uvd_table(struct radeon_device *rdev) | ||
765 | { | ||
766 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
767 | struct radeon_uvd_clock_voltage_dependency_table *table = | ||
768 | &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; | ||
769 | struct atom_clock_dividers dividers; | ||
770 | int ret; | ||
771 | u32 i; | ||
772 | |||
773 | if (table == NULL || table->count == 0) | ||
774 | return 0; | ||
775 | |||
776 | pi->uvd_level_count = 0; | ||
777 | for (i = 0; i < table->count; i++) { | ||
778 | if (pi->high_voltage_t && | ||
779 | (pi->high_voltage_t < table->entries[i].v)) | ||
780 | break; | ||
781 | |||
782 | pi->uvd_level[i].VclkFrequency = cpu_to_be32(table->entries[i].vclk); | ||
783 | pi->uvd_level[i].DclkFrequency = cpu_to_be32(table->entries[i].dclk); | ||
784 | pi->uvd_level[i].MinVddNb = cpu_to_be16(table->entries[i].v); | ||
785 | |||
786 | pi->uvd_level[i].VClkBypassCntl = | ||
787 | (u8)kv_get_clk_bypass(rdev, table->entries[i].vclk); | ||
788 | pi->uvd_level[i].DClkBypassCntl = | ||
789 | (u8)kv_get_clk_bypass(rdev, table->entries[i].dclk); | ||
790 | |||
791 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
792 | table->entries[i].vclk, false, ÷rs); | ||
793 | if (ret) | ||
794 | return ret; | ||
795 | pi->uvd_level[i].VclkDivider = (u8)dividers.post_div; | ||
796 | |||
797 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
798 | table->entries[i].dclk, false, ÷rs); | ||
799 | if (ret) | ||
800 | return ret; | ||
801 | pi->uvd_level[i].DclkDivider = (u8)dividers.post_div; | ||
802 | |||
803 | pi->uvd_level_count++; | ||
804 | } | ||
805 | |||
806 | ret = kv_copy_bytes_to_smc(rdev, | ||
807 | pi->dpm_table_start + | ||
808 | offsetof(SMU7_Fusion_DpmTable, UvdLevelCount), | ||
809 | (u8 *)&pi->uvd_level_count, | ||
810 | sizeof(u8), pi->sram_end); | ||
811 | if (ret) | ||
812 | return ret; | ||
813 | |||
814 | pi->uvd_interval = 1; | ||
815 | |||
816 | ret = kv_copy_bytes_to_smc(rdev, | ||
817 | pi->dpm_table_start + | ||
818 | offsetof(SMU7_Fusion_DpmTable, UVDInterval), | ||
819 | &pi->uvd_interval, | ||
820 | sizeof(u8), pi->sram_end); | ||
821 | if (ret) | ||
822 | return ret; | ||
823 | |||
824 | ret = kv_copy_bytes_to_smc(rdev, | ||
825 | pi->dpm_table_start + | ||
826 | offsetof(SMU7_Fusion_DpmTable, UvdLevel), | ||
827 | (u8 *)&pi->uvd_level, | ||
828 | sizeof(SMU7_Fusion_UvdLevel) * SMU7_MAX_LEVELS_UVD, | ||
829 | pi->sram_end); | ||
830 | |||
831 | return ret; | ||
832 | |||
833 | } | ||
834 | |||
835 | static int kv_populate_vce_table(struct radeon_device *rdev) | ||
836 | { | ||
837 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
838 | int ret; | ||
839 | u32 i; | ||
840 | struct radeon_vce_clock_voltage_dependency_table *table = | ||
841 | &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
842 | struct atom_clock_dividers dividers; | ||
843 | |||
844 | if (table == NULL || table->count == 0) | ||
845 | return 0; | ||
846 | |||
847 | pi->vce_level_count = 0; | ||
848 | for (i = 0; i < table->count; i++) { | ||
849 | if (pi->high_voltage_t && | ||
850 | pi->high_voltage_t < table->entries[i].v) | ||
851 | break; | ||
852 | |||
853 | pi->vce_level[i].Frequency = cpu_to_be32(table->entries[i].evclk); | ||
854 | pi->vce_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); | ||
855 | |||
856 | pi->vce_level[i].ClkBypassCntl = | ||
857 | (u8)kv_get_clk_bypass(rdev, table->entries[i].evclk); | ||
858 | |||
859 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
860 | table->entries[i].evclk, false, ÷rs); | ||
861 | if (ret) | ||
862 | return ret; | ||
863 | pi->vce_level[i].Divider = (u8)dividers.post_div; | ||
864 | |||
865 | pi->vce_level_count++; | ||
866 | } | ||
867 | |||
868 | ret = kv_copy_bytes_to_smc(rdev, | ||
869 | pi->dpm_table_start + | ||
870 | offsetof(SMU7_Fusion_DpmTable, VceLevelCount), | ||
871 | (u8 *)&pi->vce_level_count, | ||
872 | sizeof(u8), | ||
873 | pi->sram_end); | ||
874 | if (ret) | ||
875 | return ret; | ||
876 | |||
877 | pi->vce_interval = 1; | ||
878 | |||
879 | ret = kv_copy_bytes_to_smc(rdev, | ||
880 | pi->dpm_table_start + | ||
881 | offsetof(SMU7_Fusion_DpmTable, VCEInterval), | ||
882 | (u8 *)&pi->vce_interval, | ||
883 | sizeof(u8), | ||
884 | pi->sram_end); | ||
885 | if (ret) | ||
886 | return ret; | ||
887 | |||
888 | ret = kv_copy_bytes_to_smc(rdev, | ||
889 | pi->dpm_table_start + | ||
890 | offsetof(SMU7_Fusion_DpmTable, VceLevel), | ||
891 | (u8 *)&pi->vce_level, | ||
892 | sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_VCE, | ||
893 | pi->sram_end); | ||
894 | |||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | static int kv_populate_samu_table(struct radeon_device *rdev) | ||
899 | { | ||
900 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
901 | struct radeon_clock_voltage_dependency_table *table = | ||
902 | &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; | ||
903 | struct atom_clock_dividers dividers; | ||
904 | int ret; | ||
905 | u32 i; | ||
906 | |||
907 | if (table == NULL || table->count == 0) | ||
908 | return 0; | ||
909 | |||
910 | pi->samu_level_count = 0; | ||
911 | for (i = 0; i < table->count; i++) { | ||
912 | if (pi->high_voltage_t && | ||
913 | pi->high_voltage_t < table->entries[i].v) | ||
914 | break; | ||
915 | |||
916 | pi->samu_level[i].Frequency = cpu_to_be32(table->entries[i].clk); | ||
917 | pi->samu_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); | ||
918 | |||
919 | pi->samu_level[i].ClkBypassCntl = | ||
920 | (u8)kv_get_clk_bypass(rdev, table->entries[i].clk); | ||
921 | |||
922 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
923 | table->entries[i].clk, false, ÷rs); | ||
924 | if (ret) | ||
925 | return ret; | ||
926 | pi->samu_level[i].Divider = (u8)dividers.post_div; | ||
927 | |||
928 | pi->samu_level_count++; | ||
929 | } | ||
930 | |||
931 | ret = kv_copy_bytes_to_smc(rdev, | ||
932 | pi->dpm_table_start + | ||
933 | offsetof(SMU7_Fusion_DpmTable, SamuLevelCount), | ||
934 | (u8 *)&pi->samu_level_count, | ||
935 | sizeof(u8), | ||
936 | pi->sram_end); | ||
937 | if (ret) | ||
938 | return ret; | ||
939 | |||
940 | pi->samu_interval = 1; | ||
941 | |||
942 | ret = kv_copy_bytes_to_smc(rdev, | ||
943 | pi->dpm_table_start + | ||
944 | offsetof(SMU7_Fusion_DpmTable, SAMUInterval), | ||
945 | (u8 *)&pi->samu_interval, | ||
946 | sizeof(u8), | ||
947 | pi->sram_end); | ||
948 | if (ret) | ||
949 | return ret; | ||
950 | |||
951 | ret = kv_copy_bytes_to_smc(rdev, | ||
952 | pi->dpm_table_start + | ||
953 | offsetof(SMU7_Fusion_DpmTable, SamuLevel), | ||
954 | (u8 *)&pi->samu_level, | ||
955 | sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_SAMU, | ||
956 | pi->sram_end); | ||
957 | if (ret) | ||
958 | return ret; | ||
959 | |||
960 | return ret; | ||
961 | } | ||
962 | |||
963 | |||
964 | static int kv_populate_acp_table(struct radeon_device *rdev) | ||
965 | { | ||
966 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
967 | struct radeon_clock_voltage_dependency_table *table = | ||
968 | &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; | ||
969 | struct atom_clock_dividers dividers; | ||
970 | int ret; | ||
971 | u32 i; | ||
972 | |||
973 | if (table == NULL || table->count == 0) | ||
974 | return 0; | ||
975 | |||
976 | pi->acp_level_count = 0; | ||
977 | for (i = 0; i < table->count; i++) { | ||
978 | pi->acp_level[i].Frequency = cpu_to_be32(table->entries[i].clk); | ||
979 | pi->acp_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); | ||
980 | |||
981 | ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, | ||
982 | table->entries[i].clk, false, ÷rs); | ||
983 | if (ret) | ||
984 | return ret; | ||
985 | pi->acp_level[i].Divider = (u8)dividers.post_div; | ||
986 | |||
987 | pi->acp_level_count++; | ||
988 | } | ||
989 | |||
990 | ret = kv_copy_bytes_to_smc(rdev, | ||
991 | pi->dpm_table_start + | ||
992 | offsetof(SMU7_Fusion_DpmTable, AcpLevelCount), | ||
993 | (u8 *)&pi->acp_level_count, | ||
994 | sizeof(u8), | ||
995 | pi->sram_end); | ||
996 | if (ret) | ||
997 | return ret; | ||
998 | |||
999 | pi->acp_interval = 1; | ||
1000 | |||
1001 | ret = kv_copy_bytes_to_smc(rdev, | ||
1002 | pi->dpm_table_start + | ||
1003 | offsetof(SMU7_Fusion_DpmTable, ACPInterval), | ||
1004 | (u8 *)&pi->acp_interval, | ||
1005 | sizeof(u8), | ||
1006 | pi->sram_end); | ||
1007 | if (ret) | ||
1008 | return ret; | ||
1009 | |||
1010 | ret = kv_copy_bytes_to_smc(rdev, | ||
1011 | pi->dpm_table_start + | ||
1012 | offsetof(SMU7_Fusion_DpmTable, AcpLevel), | ||
1013 | (u8 *)&pi->acp_level, | ||
1014 | sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_ACP, | ||
1015 | pi->sram_end); | ||
1016 | if (ret) | ||
1017 | return ret; | ||
1018 | |||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
1022 | static void kv_calculate_dfs_bypass_settings(struct radeon_device *rdev) | ||
1023 | { | ||
1024 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1025 | u32 i; | ||
1026 | struct radeon_clock_voltage_dependency_table *table = | ||
1027 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
1028 | |||
1029 | if (table && table->count) { | ||
1030 | for (i = 0; i < pi->graphics_dpm_level_count; i++) { | ||
1031 | if (pi->caps_enable_dfs_bypass) { | ||
1032 | if (kv_get_clock_difference(table->entries[i].clk, 40000) < 200) | ||
1033 | pi->graphics_level[i].ClkBypassCntl = 3; | ||
1034 | else if (kv_get_clock_difference(table->entries[i].clk, 30000) < 200) | ||
1035 | pi->graphics_level[i].ClkBypassCntl = 2; | ||
1036 | else if (kv_get_clock_difference(table->entries[i].clk, 26600) < 200) | ||
1037 | pi->graphics_level[i].ClkBypassCntl = 7; | ||
1038 | else if (kv_get_clock_difference(table->entries[i].clk , 20000) < 200) | ||
1039 | pi->graphics_level[i].ClkBypassCntl = 6; | ||
1040 | else if (kv_get_clock_difference(table->entries[i].clk , 10000) < 200) | ||
1041 | pi->graphics_level[i].ClkBypassCntl = 8; | ||
1042 | else | ||
1043 | pi->graphics_level[i].ClkBypassCntl = 0; | ||
1044 | } else { | ||
1045 | pi->graphics_level[i].ClkBypassCntl = 0; | ||
1046 | } | ||
1047 | } | ||
1048 | } else { | ||
1049 | struct sumo_sclk_voltage_mapping_table *table = | ||
1050 | &pi->sys_info.sclk_voltage_mapping_table; | ||
1051 | for (i = 0; i < pi->graphics_dpm_level_count; i++) { | ||
1052 | if (pi->caps_enable_dfs_bypass) { | ||
1053 | if (kv_get_clock_difference(table->entries[i].sclk_frequency, 40000) < 200) | ||
1054 | pi->graphics_level[i].ClkBypassCntl = 3; | ||
1055 | else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 30000) < 200) | ||
1056 | pi->graphics_level[i].ClkBypassCntl = 2; | ||
1057 | else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 26600) < 200) | ||
1058 | pi->graphics_level[i].ClkBypassCntl = 7; | ||
1059 | else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 20000) < 200) | ||
1060 | pi->graphics_level[i].ClkBypassCntl = 6; | ||
1061 | else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 10000) < 200) | ||
1062 | pi->graphics_level[i].ClkBypassCntl = 8; | ||
1063 | else | ||
1064 | pi->graphics_level[i].ClkBypassCntl = 0; | ||
1065 | } else { | ||
1066 | pi->graphics_level[i].ClkBypassCntl = 0; | ||
1067 | } | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | static int kv_enable_ulv(struct radeon_device *rdev, bool enable) | ||
1073 | { | ||
1074 | return kv_notify_message_to_smu(rdev, enable ? | ||
1075 | PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV); | ||
1076 | } | ||
1077 | |||
1078 | static void kv_update_current_ps(struct radeon_device *rdev, | ||
1079 | struct radeon_ps *rps) | ||
1080 | { | ||
1081 | struct kv_ps *new_ps = kv_get_ps(rps); | ||
1082 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1083 | |||
1084 | pi->current_rps = *rps; | ||
1085 | pi->current_ps = *new_ps; | ||
1086 | pi->current_rps.ps_priv = &pi->current_ps; | ||
1087 | } | ||
1088 | |||
1089 | static void kv_update_requested_ps(struct radeon_device *rdev, | ||
1090 | struct radeon_ps *rps) | ||
1091 | { | ||
1092 | struct kv_ps *new_ps = kv_get_ps(rps); | ||
1093 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1094 | |||
1095 | pi->requested_rps = *rps; | ||
1096 | pi->requested_ps = *new_ps; | ||
1097 | pi->requested_rps.ps_priv = &pi->requested_ps; | ||
1098 | } | ||
1099 | |||
1100 | int kv_dpm_enable(struct radeon_device *rdev) | ||
1101 | { | ||
1102 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1103 | int ret; | ||
1104 | |||
1105 | ret = kv_process_firmware_header(rdev); | ||
1106 | if (ret) { | ||
1107 | DRM_ERROR("kv_process_firmware_header failed\n"); | ||
1108 | return ret; | ||
1109 | } | ||
1110 | kv_init_fps_limits(rdev); | ||
1111 | kv_init_graphics_levels(rdev); | ||
1112 | ret = kv_program_bootup_state(rdev); | ||
1113 | if (ret) { | ||
1114 | DRM_ERROR("kv_program_bootup_state failed\n"); | ||
1115 | return ret; | ||
1116 | } | ||
1117 | kv_calculate_dfs_bypass_settings(rdev); | ||
1118 | ret = kv_upload_dpm_settings(rdev); | ||
1119 | if (ret) { | ||
1120 | DRM_ERROR("kv_upload_dpm_settings failed\n"); | ||
1121 | return ret; | ||
1122 | } | ||
1123 | ret = kv_populate_uvd_table(rdev); | ||
1124 | if (ret) { | ||
1125 | DRM_ERROR("kv_populate_uvd_table failed\n"); | ||
1126 | return ret; | ||
1127 | } | ||
1128 | ret = kv_populate_vce_table(rdev); | ||
1129 | if (ret) { | ||
1130 | DRM_ERROR("kv_populate_vce_table failed\n"); | ||
1131 | return ret; | ||
1132 | } | ||
1133 | ret = kv_populate_samu_table(rdev); | ||
1134 | if (ret) { | ||
1135 | DRM_ERROR("kv_populate_samu_table failed\n"); | ||
1136 | return ret; | ||
1137 | } | ||
1138 | ret = kv_populate_acp_table(rdev); | ||
1139 | if (ret) { | ||
1140 | DRM_ERROR("kv_populate_acp_table failed\n"); | ||
1141 | return ret; | ||
1142 | } | ||
1143 | kv_program_vc(rdev); | ||
1144 | #if 0 | ||
1145 | kv_initialize_hardware_cac_manager(rdev); | ||
1146 | #endif | ||
1147 | kv_start_am(rdev); | ||
1148 | if (pi->enable_auto_thermal_throttling) { | ||
1149 | ret = kv_enable_auto_thermal_throttling(rdev); | ||
1150 | if (ret) { | ||
1151 | DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | } | ||
1155 | ret = kv_enable_dpm_voltage_scaling(rdev); | ||
1156 | if (ret) { | ||
1157 | DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); | ||
1158 | return ret; | ||
1159 | } | ||
1160 | ret = kv_set_dpm_interval(rdev); | ||
1161 | if (ret) { | ||
1162 | DRM_ERROR("kv_set_dpm_interval failed\n"); | ||
1163 | return ret; | ||
1164 | } | ||
1165 | ret = kv_set_dpm_boot_state(rdev); | ||
1166 | if (ret) { | ||
1167 | DRM_ERROR("kv_set_dpm_boot_state failed\n"); | ||
1168 | return ret; | ||
1169 | } | ||
1170 | ret = kv_enable_ulv(rdev, true); | ||
1171 | if (ret) { | ||
1172 | DRM_ERROR("kv_enable_ulv failed\n"); | ||
1173 | return ret; | ||
1174 | } | ||
1175 | kv_start_dpm(rdev); | ||
1176 | ret = kv_enable_didt(rdev, true); | ||
1177 | if (ret) { | ||
1178 | DRM_ERROR("kv_enable_didt failed\n"); | ||
1179 | return ret; | ||
1180 | } | ||
1181 | ret = kv_enable_smc_cac(rdev, true); | ||
1182 | if (ret) { | ||
1183 | DRM_ERROR("kv_enable_smc_cac failed\n"); | ||
1184 | return ret; | ||
1185 | } | ||
1186 | |||
1187 | if (rdev->irq.installed && | ||
1188 | r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { | ||
1189 | ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); | ||
1190 | if (ret) { | ||
1191 | DRM_ERROR("kv_set_thermal_temperature_range failed\n"); | ||
1192 | return ret; | ||
1193 | } | ||
1194 | rdev->irq.dpm_thermal = true; | ||
1195 | radeon_irq_set(rdev); | ||
1196 | } | ||
1197 | |||
1198 | /* powerdown unused blocks for now */ | ||
1199 | kv_dpm_powergate_acp(rdev, true); | ||
1200 | kv_dpm_powergate_samu(rdev, true); | ||
1201 | kv_dpm_powergate_vce(rdev, true); | ||
1202 | |||
1203 | kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); | ||
1204 | |||
1205 | return ret; | ||
1206 | } | ||
1207 | |||
1208 | void kv_dpm_disable(struct radeon_device *rdev) | ||
1209 | { | ||
1210 | kv_enable_smc_cac(rdev, false); | ||
1211 | kv_enable_didt(rdev, false); | ||
1212 | kv_clear_vc(rdev); | ||
1213 | kv_stop_dpm(rdev); | ||
1214 | kv_enable_ulv(rdev, false); | ||
1215 | kv_reset_am(rdev); | ||
1216 | |||
1217 | kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); | ||
1218 | } | ||
1219 | |||
1220 | #if 0 | ||
1221 | static int kv_write_smc_soft_register(struct radeon_device *rdev, | ||
1222 | u16 reg_offset, u32 value) | ||
1223 | { | ||
1224 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1225 | |||
1226 | return kv_copy_bytes_to_smc(rdev, pi->soft_regs_start + reg_offset, | ||
1227 | (u8 *)&value, sizeof(u16), pi->sram_end); | ||
1228 | } | ||
1229 | |||
1230 | static int kv_read_smc_soft_register(struct radeon_device *rdev, | ||
1231 | u16 reg_offset, u32 *value) | ||
1232 | { | ||
1233 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1234 | |||
1235 | return kv_read_smc_sram_dword(rdev, pi->soft_regs_start + reg_offset, | ||
1236 | value, pi->sram_end); | ||
1237 | } | ||
1238 | #endif | ||
1239 | |||
1240 | static void kv_init_sclk_t(struct radeon_device *rdev) | ||
1241 | { | ||
1242 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1243 | |||
1244 | pi->low_sclk_interrupt_t = 0; | ||
1245 | } | ||
1246 | |||
1247 | static int kv_init_fps_limits(struct radeon_device *rdev) | ||
1248 | { | ||
1249 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1250 | int ret = 0; | ||
1251 | |||
1252 | if (pi->caps_fps) { | ||
1253 | u16 tmp; | ||
1254 | |||
1255 | tmp = 45; | ||
1256 | pi->fps_high_t = cpu_to_be16(tmp); | ||
1257 | ret = kv_copy_bytes_to_smc(rdev, | ||
1258 | pi->dpm_table_start + | ||
1259 | offsetof(SMU7_Fusion_DpmTable, FpsHighT), | ||
1260 | (u8 *)&pi->fps_high_t, | ||
1261 | sizeof(u16), pi->sram_end); | ||
1262 | |||
1263 | tmp = 30; | ||
1264 | pi->fps_low_t = cpu_to_be16(tmp); | ||
1265 | |||
1266 | ret = kv_copy_bytes_to_smc(rdev, | ||
1267 | pi->dpm_table_start + | ||
1268 | offsetof(SMU7_Fusion_DpmTable, FpsLowT), | ||
1269 | (u8 *)&pi->fps_low_t, | ||
1270 | sizeof(u16), pi->sram_end); | ||
1271 | |||
1272 | } | ||
1273 | return ret; | ||
1274 | } | ||
1275 | |||
1276 | static void kv_init_powergate_state(struct radeon_device *rdev) | ||
1277 | { | ||
1278 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1279 | |||
1280 | pi->uvd_power_gated = false; | ||
1281 | pi->vce_power_gated = false; | ||
1282 | pi->samu_power_gated = false; | ||
1283 | pi->acp_power_gated = false; | ||
1284 | |||
1285 | } | ||
1286 | |||
1287 | static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable) | ||
1288 | { | ||
1289 | return kv_notify_message_to_smu(rdev, enable ? | ||
1290 | PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable); | ||
1291 | } | ||
1292 | |||
1293 | #if 0 | ||
1294 | static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable) | ||
1295 | { | ||
1296 | return kv_notify_message_to_smu(rdev, enable ? | ||
1297 | PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable); | ||
1298 | } | ||
1299 | #endif | ||
1300 | |||
1301 | static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable) | ||
1302 | { | ||
1303 | return kv_notify_message_to_smu(rdev, enable ? | ||
1304 | PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable); | ||
1305 | } | ||
1306 | |||
1307 | static int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable) | ||
1308 | { | ||
1309 | return kv_notify_message_to_smu(rdev, enable ? | ||
1310 | PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable); | ||
1311 | } | ||
1312 | |||
1313 | static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) | ||
1314 | { | ||
1315 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1316 | struct radeon_uvd_clock_voltage_dependency_table *table = | ||
1317 | &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; | ||
1318 | int ret; | ||
1319 | |||
1320 | if (!gate) { | ||
1321 | if (!pi->caps_uvd_dpm || table->count || pi->caps_stable_p_state) | ||
1322 | pi->uvd_boot_level = table->count - 1; | ||
1323 | else | ||
1324 | pi->uvd_boot_level = 0; | ||
1325 | |||
1326 | ret = kv_copy_bytes_to_smc(rdev, | ||
1327 | pi->dpm_table_start + | ||
1328 | offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), | ||
1329 | (uint8_t *)&pi->uvd_boot_level, | ||
1330 | sizeof(u8), pi->sram_end); | ||
1331 | if (ret) | ||
1332 | return ret; | ||
1333 | |||
1334 | if (!pi->caps_uvd_dpm || | ||
1335 | pi->caps_stable_p_state) | ||
1336 | kv_send_msg_to_smc_with_parameter(rdev, | ||
1337 | PPSMC_MSG_UVDDPM_SetEnabledMask, | ||
1338 | (1 << pi->uvd_boot_level)); | ||
1339 | } | ||
1340 | |||
1341 | return kv_enable_uvd_dpm(rdev, !gate); | ||
1342 | } | ||
1343 | |||
1344 | #if 0 | ||
1345 | static u8 kv_get_vce_boot_level(struct radeon_device *rdev) | ||
1346 | { | ||
1347 | u8 i; | ||
1348 | struct radeon_vce_clock_voltage_dependency_table *table = | ||
1349 | &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
1350 | |||
1351 | for (i = 0; i < table->count; i++) { | ||
1352 | if (table->entries[i].evclk >= 0) /* XXX */ | ||
1353 | break; | ||
1354 | } | ||
1355 | |||
1356 | return i; | ||
1357 | } | ||
1358 | |||
1359 | static int kv_update_vce_dpm(struct radeon_device *rdev, | ||
1360 | struct radeon_ps *radeon_new_state, | ||
1361 | struct radeon_ps *radeon_current_state) | ||
1362 | { | ||
1363 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1364 | struct radeon_vce_clock_voltage_dependency_table *table = | ||
1365 | &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
1366 | int ret; | ||
1367 | |||
1368 | if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) { | ||
1369 | if (pi->caps_stable_p_state) | ||
1370 | pi->vce_boot_level = table->count - 1; | ||
1371 | else | ||
1372 | pi->vce_boot_level = kv_get_vce_boot_level(rdev); | ||
1373 | |||
1374 | ret = kv_copy_bytes_to_smc(rdev, | ||
1375 | pi->dpm_table_start + | ||
1376 | offsetof(SMU7_Fusion_DpmTable, VceBootLevel), | ||
1377 | (u8 *)&pi->vce_boot_level, | ||
1378 | sizeof(u8), | ||
1379 | pi->sram_end); | ||
1380 | if (ret) | ||
1381 | return ret; | ||
1382 | |||
1383 | if (pi->caps_stable_p_state) | ||
1384 | kv_send_msg_to_smc_with_parameter(rdev, | ||
1385 | PPSMC_MSG_VCEDPM_SetEnabledMask, | ||
1386 | (1 << pi->vce_boot_level)); | ||
1387 | |||
1388 | kv_enable_vce_dpm(rdev, true); | ||
1389 | } else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) { | ||
1390 | kv_enable_vce_dpm(rdev, false); | ||
1391 | } | ||
1392 | |||
1393 | return 0; | ||
1394 | } | ||
1395 | #endif | ||
1396 | |||
1397 | static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate) | ||
1398 | { | ||
1399 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1400 | struct radeon_clock_voltage_dependency_table *table = | ||
1401 | &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; | ||
1402 | int ret; | ||
1403 | |||
1404 | if (!gate) { | ||
1405 | if (pi->caps_stable_p_state) | ||
1406 | pi->samu_boot_level = table->count - 1; | ||
1407 | else | ||
1408 | pi->samu_boot_level = 0; | ||
1409 | |||
1410 | ret = kv_copy_bytes_to_smc(rdev, | ||
1411 | pi->dpm_table_start + | ||
1412 | offsetof(SMU7_Fusion_DpmTable, SamuBootLevel), | ||
1413 | (u8 *)&pi->samu_boot_level, | ||
1414 | sizeof(u8), | ||
1415 | pi->sram_end); | ||
1416 | if (ret) | ||
1417 | return ret; | ||
1418 | |||
1419 | if (pi->caps_stable_p_state) | ||
1420 | kv_send_msg_to_smc_with_parameter(rdev, | ||
1421 | PPSMC_MSG_SAMUDPM_SetEnabledMask, | ||
1422 | (1 << pi->samu_boot_level)); | ||
1423 | } | ||
1424 | |||
1425 | return kv_enable_samu_dpm(rdev, !gate); | ||
1426 | } | ||
1427 | |||
1428 | static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate) | ||
1429 | { | ||
1430 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1431 | struct radeon_clock_voltage_dependency_table *table = | ||
1432 | &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; | ||
1433 | int ret; | ||
1434 | |||
1435 | if (!gate) { | ||
1436 | if (pi->caps_stable_p_state) | ||
1437 | pi->acp_boot_level = table->count - 1; | ||
1438 | else | ||
1439 | pi->acp_boot_level = 0; | ||
1440 | |||
1441 | ret = kv_copy_bytes_to_smc(rdev, | ||
1442 | pi->dpm_table_start + | ||
1443 | offsetof(SMU7_Fusion_DpmTable, AcpBootLevel), | ||
1444 | (u8 *)&pi->acp_boot_level, | ||
1445 | sizeof(u8), | ||
1446 | pi->sram_end); | ||
1447 | if (ret) | ||
1448 | return ret; | ||
1449 | |||
1450 | if (pi->caps_stable_p_state) | ||
1451 | kv_send_msg_to_smc_with_parameter(rdev, | ||
1452 | PPSMC_MSG_ACPDPM_SetEnabledMask, | ||
1453 | (1 << pi->acp_boot_level)); | ||
1454 | } | ||
1455 | |||
1456 | return kv_enable_acp_dpm(rdev, !gate); | ||
1457 | } | ||
1458 | |||
1459 | static void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) | ||
1460 | { | ||
1461 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1462 | |||
1463 | if (pi->uvd_power_gated == gate) | ||
1464 | return; | ||
1465 | |||
1466 | pi->uvd_power_gated = gate; | ||
1467 | |||
1468 | if (gate) { | ||
1469 | kv_update_uvd_dpm(rdev, true); | ||
1470 | if (pi->caps_uvd_pg) | ||
1471 | kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF); | ||
1472 | } else { | ||
1473 | if (pi->caps_uvd_pg) | ||
1474 | kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON); | ||
1475 | kv_update_uvd_dpm(rdev, false); | ||
1476 | } | ||
1477 | } | ||
1478 | |||
1479 | static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate) | ||
1480 | { | ||
1481 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1482 | |||
1483 | if (pi->vce_power_gated == gate) | ||
1484 | return; | ||
1485 | |||
1486 | pi->vce_power_gated = gate; | ||
1487 | |||
1488 | if (gate) { | ||
1489 | if (pi->caps_vce_pg) | ||
1490 | kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF); | ||
1491 | } else { | ||
1492 | if (pi->caps_vce_pg) | ||
1493 | kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); | ||
1494 | } | ||
1495 | } | ||
1496 | |||
1497 | static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate) | ||
1498 | { | ||
1499 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1500 | |||
1501 | if (pi->samu_power_gated == gate) | ||
1502 | return; | ||
1503 | |||
1504 | pi->samu_power_gated = gate; | ||
1505 | |||
1506 | if (gate) { | ||
1507 | kv_update_samu_dpm(rdev, true); | ||
1508 | if (pi->caps_samu_pg) | ||
1509 | kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF); | ||
1510 | } else { | ||
1511 | if (pi->caps_samu_pg) | ||
1512 | kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON); | ||
1513 | kv_update_samu_dpm(rdev, false); | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate) | ||
1518 | { | ||
1519 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1520 | |||
1521 | if (pi->acp_power_gated == gate) | ||
1522 | return; | ||
1523 | |||
1524 | if (rdev->family == CHIP_KABINI) | ||
1525 | return; | ||
1526 | |||
1527 | pi->acp_power_gated = gate; | ||
1528 | |||
1529 | if (gate) { | ||
1530 | kv_update_acp_dpm(rdev, true); | ||
1531 | if (pi->caps_acp_pg) | ||
1532 | kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF); | ||
1533 | } else { | ||
1534 | if (pi->caps_acp_pg) | ||
1535 | kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON); | ||
1536 | kv_update_acp_dpm(rdev, false); | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | static void kv_set_valid_clock_range(struct radeon_device *rdev, | ||
1541 | struct radeon_ps *new_rps) | ||
1542 | { | ||
1543 | struct kv_ps *new_ps = kv_get_ps(new_rps); | ||
1544 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1545 | u32 i; | ||
1546 | struct radeon_clock_voltage_dependency_table *table = | ||
1547 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
1548 | |||
1549 | if (table && table->count) { | ||
1550 | for (i = 0; i < pi->graphics_dpm_level_count; i++) { | ||
1551 | if ((table->entries[i].clk >= new_ps->levels[0].sclk) || | ||
1552 | (i == (pi->graphics_dpm_level_count - 1))) { | ||
1553 | pi->lowest_valid = i; | ||
1554 | break; | ||
1555 | } | ||
1556 | } | ||
1557 | |||
1558 | for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) { | ||
1559 | if ((table->entries[i].clk <= new_ps->levels[new_ps->num_levels -1].sclk) || | ||
1560 | (i == 0)) { | ||
1561 | pi->highest_valid = i; | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | if (pi->lowest_valid > pi->highest_valid) { | ||
1567 | if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) > | ||
1568 | (table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk)) | ||
1569 | pi->highest_valid = pi->lowest_valid; | ||
1570 | else | ||
1571 | pi->lowest_valid = pi->highest_valid; | ||
1572 | } | ||
1573 | } else { | ||
1574 | struct sumo_sclk_voltage_mapping_table *table = | ||
1575 | &pi->sys_info.sclk_voltage_mapping_table; | ||
1576 | |||
1577 | for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) { | ||
1578 | if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk || | ||
1579 | i == (int)(pi->graphics_dpm_level_count - 1)) { | ||
1580 | pi->lowest_valid = i; | ||
1581 | break; | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) { | ||
1586 | if (table->entries[i].sclk_frequency <= | ||
1587 | new_ps->levels[new_ps->num_levels - 1].sclk || | ||
1588 | i == 0) { | ||
1589 | pi->highest_valid = i; | ||
1590 | break; | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | if (pi->lowest_valid > pi->highest_valid) { | ||
1595 | if ((new_ps->levels[0].sclk - | ||
1596 | table->entries[pi->highest_valid].sclk_frequency) > | ||
1597 | (table->entries[pi->lowest_valid].sclk_frequency - | ||
1598 | new_ps->levels[new_ps->num_levels -1].sclk)) | ||
1599 | pi->highest_valid = pi->lowest_valid; | ||
1600 | else | ||
1601 | pi->lowest_valid = pi->highest_valid; | ||
1602 | } | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1606 | static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, | ||
1607 | struct radeon_ps *new_rps) | ||
1608 | { | ||
1609 | struct kv_ps *new_ps = kv_get_ps(new_rps); | ||
1610 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1611 | int ret = 0; | ||
1612 | u8 clk_bypass_cntl; | ||
1613 | |||
1614 | if (pi->caps_enable_dfs_bypass) { | ||
1615 | clk_bypass_cntl = new_ps->need_dfs_bypass ? | ||
1616 | pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0; | ||
1617 | ret = kv_copy_bytes_to_smc(rdev, | ||
1618 | (pi->dpm_table_start + | ||
1619 | offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) + | ||
1620 | (pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) + | ||
1621 | offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)), | ||
1622 | &clk_bypass_cntl, | ||
1623 | sizeof(u8), pi->sram_end); | ||
1624 | } | ||
1625 | |||
1626 | return ret; | ||
1627 | } | ||
1628 | |||
1629 | static int kv_enable_nb_dpm(struct radeon_device *rdev) | ||
1630 | { | ||
1631 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1632 | int ret = 0; | ||
1633 | |||
1634 | if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { | ||
1635 | ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); | ||
1636 | if (ret == 0) | ||
1637 | pi->nb_dpm_enabled = true; | ||
1638 | } | ||
1639 | |||
1640 | return ret; | ||
1641 | } | ||
1642 | |||
1643 | int kv_dpm_pre_set_power_state(struct radeon_device *rdev) | ||
1644 | { | ||
1645 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1646 | struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; | ||
1647 | struct radeon_ps *new_ps = &requested_ps; | ||
1648 | |||
1649 | kv_update_requested_ps(rdev, new_ps); | ||
1650 | |||
1651 | kv_apply_state_adjust_rules(rdev, | ||
1652 | &pi->requested_rps, | ||
1653 | &pi->current_rps); | ||
1654 | |||
1655 | return 0; | ||
1656 | } | ||
1657 | |||
1658 | int kv_dpm_set_power_state(struct radeon_device *rdev) | ||
1659 | { | ||
1660 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1661 | struct radeon_ps *new_ps = &pi->requested_rps; | ||
1662 | /*struct radeon_ps *old_ps = &pi->current_rps;*/ | ||
1663 | int ret; | ||
1664 | |||
1665 | if (rdev->family == CHIP_KABINI) { | ||
1666 | if (pi->enable_dpm) { | ||
1667 | kv_set_valid_clock_range(rdev, new_ps); | ||
1668 | kv_update_dfs_bypass_settings(rdev, new_ps); | ||
1669 | ret = kv_calculate_ds_divider(rdev); | ||
1670 | if (ret) { | ||
1671 | DRM_ERROR("kv_calculate_ds_divider failed\n"); | ||
1672 | return ret; | ||
1673 | } | ||
1674 | kv_calculate_nbps_level_settings(rdev); | ||
1675 | kv_calculate_dpm_settings(rdev); | ||
1676 | kv_force_lowest_valid(rdev); | ||
1677 | kv_enable_new_levels(rdev); | ||
1678 | kv_upload_dpm_settings(rdev); | ||
1679 | kv_program_nbps_index_settings(rdev, new_ps); | ||
1680 | kv_unforce_levels(rdev); | ||
1681 | kv_set_enabled_levels(rdev); | ||
1682 | kv_force_lowest_valid(rdev); | ||
1683 | kv_unforce_levels(rdev); | ||
1684 | #if 0 | ||
1685 | ret = kv_update_vce_dpm(rdev, new_ps, old_ps); | ||
1686 | if (ret) { | ||
1687 | DRM_ERROR("kv_update_vce_dpm failed\n"); | ||
1688 | return ret; | ||
1689 | } | ||
1690 | #endif | ||
1691 | kv_update_uvd_dpm(rdev, false); | ||
1692 | kv_update_sclk_t(rdev); | ||
1693 | } | ||
1694 | } else { | ||
1695 | if (pi->enable_dpm) { | ||
1696 | kv_set_valid_clock_range(rdev, new_ps); | ||
1697 | kv_update_dfs_bypass_settings(rdev, new_ps); | ||
1698 | ret = kv_calculate_ds_divider(rdev); | ||
1699 | if (ret) { | ||
1700 | DRM_ERROR("kv_calculate_ds_divider failed\n"); | ||
1701 | return ret; | ||
1702 | } | ||
1703 | kv_calculate_nbps_level_settings(rdev); | ||
1704 | kv_calculate_dpm_settings(rdev); | ||
1705 | kv_freeze_sclk_dpm(rdev, true); | ||
1706 | kv_upload_dpm_settings(rdev); | ||
1707 | kv_program_nbps_index_settings(rdev, new_ps); | ||
1708 | kv_freeze_sclk_dpm(rdev, false); | ||
1709 | kv_set_enabled_levels(rdev); | ||
1710 | #if 0 | ||
1711 | ret = kv_update_vce_dpm(rdev, new_ps, old_ps); | ||
1712 | if (ret) { | ||
1713 | DRM_ERROR("kv_update_vce_dpm failed\n"); | ||
1714 | return ret; | ||
1715 | } | ||
1716 | #endif | ||
1717 | kv_update_uvd_dpm(rdev, false); | ||
1718 | kv_update_sclk_t(rdev); | ||
1719 | kv_enable_nb_dpm(rdev); | ||
1720 | } | ||
1721 | } | ||
1722 | return 0; | ||
1723 | } | ||
1724 | |||
1725 | void kv_dpm_post_set_power_state(struct radeon_device *rdev) | ||
1726 | { | ||
1727 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1728 | struct radeon_ps *new_ps = &pi->requested_rps; | ||
1729 | |||
1730 | kv_update_current_ps(rdev, new_ps); | ||
1731 | } | ||
1732 | |||
1733 | void kv_dpm_setup_asic(struct radeon_device *rdev) | ||
1734 | { | ||
1735 | sumo_take_smu_control(rdev, true); | ||
1736 | kv_init_powergate_state(rdev); | ||
1737 | kv_init_sclk_t(rdev); | ||
1738 | } | ||
1739 | |||
1740 | void kv_dpm_reset_asic(struct radeon_device *rdev) | ||
1741 | { | ||
1742 | kv_force_lowest_valid(rdev); | ||
1743 | kv_init_graphics_levels(rdev); | ||
1744 | kv_program_bootup_state(rdev); | ||
1745 | kv_upload_dpm_settings(rdev); | ||
1746 | kv_force_lowest_valid(rdev); | ||
1747 | kv_unforce_levels(rdev); | ||
1748 | } | ||
1749 | |||
1750 | //XXX use sumo_dpm_display_configuration_changed | ||
1751 | |||
1752 | static void kv_construct_max_power_limits_table(struct radeon_device *rdev, | ||
1753 | struct radeon_clock_and_voltage_limits *table) | ||
1754 | { | ||
1755 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1756 | |||
1757 | if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) { | ||
1758 | int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1; | ||
1759 | table->sclk = | ||
1760 | pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency; | ||
1761 | table->vddc = | ||
1762 | kv_convert_2bit_index_to_voltage(rdev, | ||
1763 | pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit); | ||
1764 | } | ||
1765 | |||
1766 | table->mclk = pi->sys_info.nbp_memory_clock[0]; | ||
1767 | } | ||
1768 | |||
1769 | static void kv_patch_voltage_values(struct radeon_device *rdev) | ||
1770 | { | ||
1771 | int i; | ||
1772 | struct radeon_uvd_clock_voltage_dependency_table *table = | ||
1773 | &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; | ||
1774 | |||
1775 | if (table->count) { | ||
1776 | for (i = 0; i < table->count; i++) | ||
1777 | table->entries[i].v = | ||
1778 | kv_convert_8bit_index_to_voltage(rdev, | ||
1779 | table->entries[i].v); | ||
1780 | } | ||
1781 | |||
1782 | } | ||
1783 | |||
1784 | static void kv_construct_boot_state(struct radeon_device *rdev) | ||
1785 | { | ||
1786 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1787 | |||
1788 | pi->boot_pl.sclk = pi->sys_info.bootup_sclk; | ||
1789 | pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; | ||
1790 | pi->boot_pl.ds_divider_index = 0; | ||
1791 | pi->boot_pl.ss_divider_index = 0; | ||
1792 | pi->boot_pl.allow_gnb_slow = 1; | ||
1793 | pi->boot_pl.force_nbp_state = 0; | ||
1794 | pi->boot_pl.display_wm = 0; | ||
1795 | pi->boot_pl.vce_wm = 0; | ||
1796 | } | ||
1797 | |||
1798 | static int kv_force_dpm_lowest(struct radeon_device *rdev) | ||
1799 | { | ||
1800 | int ret; | ||
1801 | u32 enable_mask, i; | ||
1802 | |||
1803 | ret = kv_dpm_get_enable_mask(rdev, &enable_mask); | ||
1804 | if (ret) | ||
1805 | return ret; | ||
1806 | |||
1807 | for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { | ||
1808 | if (enable_mask & (1 << i)) | ||
1809 | break; | ||
1810 | } | ||
1811 | |||
1812 | return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); | ||
1813 | } | ||
1814 | |||
1815 | static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev, | ||
1816 | u32 sclk, u32 min_sclk_in_sr) | ||
1817 | { | ||
1818 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1819 | u32 i; | ||
1820 | u32 temp; | ||
1821 | u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ? | ||
1822 | min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK; | ||
1823 | |||
1824 | if (sclk < min) | ||
1825 | return 0; | ||
1826 | |||
1827 | if (!pi->caps_sclk_ds) | ||
1828 | return 0; | ||
1829 | |||
1830 | for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i <= 0; i--) { | ||
1831 | temp = sclk / sumo_get_sleep_divider_from_id(i); | ||
1832 | if ((temp >= min) || (i == 0)) | ||
1833 | break; | ||
1834 | } | ||
1835 | |||
1836 | return (u8)i; | ||
1837 | } | ||
1838 | |||
1839 | static int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit) | ||
1840 | { | ||
1841 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1842 | struct radeon_clock_voltage_dependency_table *table = | ||
1843 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
1844 | int i; | ||
1845 | |||
1846 | if (table && table->count) { | ||
1847 | for (i = table->count - 1; i >= 0; i--) { | ||
1848 | if (pi->high_voltage_t && | ||
1849 | (kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <= | ||
1850 | pi->high_voltage_t)) { | ||
1851 | *limit = i; | ||
1852 | return 0; | ||
1853 | } | ||
1854 | } | ||
1855 | } else { | ||
1856 | struct sumo_sclk_voltage_mapping_table *table = | ||
1857 | &pi->sys_info.sclk_voltage_mapping_table; | ||
1858 | |||
1859 | for (i = table->num_max_dpm_entries - 1; i >= 0; i--) { | ||
1860 | if (pi->high_voltage_t && | ||
1861 | (kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <= | ||
1862 | pi->high_voltage_t)) { | ||
1863 | *limit = i; | ||
1864 | return 0; | ||
1865 | } | ||
1866 | } | ||
1867 | } | ||
1868 | |||
1869 | *limit = 0; | ||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | static void kv_apply_state_adjust_rules(struct radeon_device *rdev, | ||
1874 | struct radeon_ps *new_rps, | ||
1875 | struct radeon_ps *old_rps) | ||
1876 | { | ||
1877 | struct kv_ps *ps = kv_get_ps(new_rps); | ||
1878 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1879 | u32 min_sclk = 10000; /* ??? */ | ||
1880 | u32 sclk, mclk = 0; | ||
1881 | int i, limit; | ||
1882 | bool force_high; | ||
1883 | struct radeon_clock_voltage_dependency_table *table = | ||
1884 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
1885 | u32 stable_p_state_sclk = 0; | ||
1886 | struct radeon_clock_and_voltage_limits *max_limits = | ||
1887 | &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; | ||
1888 | |||
1889 | mclk = max_limits->mclk; | ||
1890 | sclk = min_sclk; | ||
1891 | |||
1892 | if (pi->caps_stable_p_state) { | ||
1893 | stable_p_state_sclk = (max_limits->sclk * 75) / 100; | ||
1894 | |||
1895 | for (i = table->count - 1; i >= 0; i++) { | ||
1896 | if (stable_p_state_sclk >= table->entries[i].clk) { | ||
1897 | stable_p_state_sclk = table->entries[i].clk; | ||
1898 | break; | ||
1899 | } | ||
1900 | } | ||
1901 | |||
1902 | if (i > 0) | ||
1903 | stable_p_state_sclk = table->entries[0].clk; | ||
1904 | |||
1905 | sclk = stable_p_state_sclk; | ||
1906 | } | ||
1907 | |||
1908 | ps->need_dfs_bypass = true; | ||
1909 | |||
1910 | for (i = 0; i < ps->num_levels; i++) { | ||
1911 | if (ps->levels[i].sclk < sclk) | ||
1912 | ps->levels[i].sclk = sclk; | ||
1913 | } | ||
1914 | |||
1915 | if (table && table->count) { | ||
1916 | for (i = 0; i < ps->num_levels; i++) { | ||
1917 | if (pi->high_voltage_t && | ||
1918 | (pi->high_voltage_t < | ||
1919 | kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { | ||
1920 | kv_get_high_voltage_limit(rdev, &limit); | ||
1921 | ps->levels[i].sclk = table->entries[limit].clk; | ||
1922 | } | ||
1923 | } | ||
1924 | } else { | ||
1925 | struct sumo_sclk_voltage_mapping_table *table = | ||
1926 | &pi->sys_info.sclk_voltage_mapping_table; | ||
1927 | |||
1928 | for (i = 0; i < ps->num_levels; i++) { | ||
1929 | if (pi->high_voltage_t && | ||
1930 | (pi->high_voltage_t < | ||
1931 | kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { | ||
1932 | kv_get_high_voltage_limit(rdev, &limit); | ||
1933 | ps->levels[i].sclk = table->entries[limit].sclk_frequency; | ||
1934 | } | ||
1935 | } | ||
1936 | } | ||
1937 | |||
1938 | if (pi->caps_stable_p_state) { | ||
1939 | for (i = 0; i < ps->num_levels; i++) { | ||
1940 | ps->levels[i].sclk = stable_p_state_sclk; | ||
1941 | } | ||
1942 | } | ||
1943 | |||
1944 | pi->video_start = new_rps->dclk || new_rps->vclk; | ||
1945 | |||
1946 | if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == | ||
1947 | ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) | ||
1948 | pi->battery_state = true; | ||
1949 | else | ||
1950 | pi->battery_state = false; | ||
1951 | |||
1952 | if (rdev->family == CHIP_KABINI) { | ||
1953 | ps->dpm0_pg_nb_ps_lo = 0x1; | ||
1954 | ps->dpm0_pg_nb_ps_hi = 0x0; | ||
1955 | ps->dpmx_nb_ps_lo = 0x1; | ||
1956 | ps->dpmx_nb_ps_hi = 0x0; | ||
1957 | } else { | ||
1958 | ps->dpm0_pg_nb_ps_lo = 0x1; | ||
1959 | ps->dpm0_pg_nb_ps_hi = 0x0; | ||
1960 | ps->dpmx_nb_ps_lo = 0x2; | ||
1961 | ps->dpmx_nb_ps_hi = 0x1; | ||
1962 | |||
1963 | if (pi->sys_info.nb_dpm_enable && pi->battery_state) { | ||
1964 | force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || | ||
1965 | pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) || | ||
1966 | pi->disable_nb_ps3_in_battery; | ||
1967 | ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; | ||
1968 | ps->dpm0_pg_nb_ps_hi = 0x2; | ||
1969 | ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3; | ||
1970 | ps->dpmx_nb_ps_hi = 0x2; | ||
1971 | } | ||
1972 | } | ||
1973 | } | ||
1974 | |||
1975 | static void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev, | ||
1976 | u32 index, bool enable) | ||
1977 | { | ||
1978 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1979 | |||
1980 | pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0; | ||
1981 | } | ||
1982 | |||
1983 | static int kv_calculate_ds_divider(struct radeon_device *rdev) | ||
1984 | { | ||
1985 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
1986 | u32 sclk_in_sr = 10000; /* ??? */ | ||
1987 | u32 i; | ||
1988 | |||
1989 | if (pi->lowest_valid > pi->highest_valid) | ||
1990 | return -EINVAL; | ||
1991 | |||
1992 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { | ||
1993 | pi->graphics_level[i].DeepSleepDivId = | ||
1994 | kv_get_sleep_divider_id_from_clock(rdev, | ||
1995 | be32_to_cpu(pi->graphics_level[i].SclkFrequency), | ||
1996 | sclk_in_sr); | ||
1997 | } | ||
1998 | return 0; | ||
1999 | } | ||
2000 | |||
2001 | static int kv_calculate_nbps_level_settings(struct radeon_device *rdev) | ||
2002 | { | ||
2003 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2004 | u32 i; | ||
2005 | bool force_high; | ||
2006 | struct radeon_clock_and_voltage_limits *max_limits = | ||
2007 | &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; | ||
2008 | u32 mclk = max_limits->mclk; | ||
2009 | |||
2010 | if (pi->lowest_valid > pi->highest_valid) | ||
2011 | return -EINVAL; | ||
2012 | |||
2013 | if (rdev->family == CHIP_KABINI) { | ||
2014 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { | ||
2015 | pi->graphics_level[i].GnbSlow = 1; | ||
2016 | pi->graphics_level[i].ForceNbPs1 = 0; | ||
2017 | pi->graphics_level[i].UpH = 0; | ||
2018 | } | ||
2019 | |||
2020 | if (!pi->sys_info.nb_dpm_enable) | ||
2021 | return 0; | ||
2022 | |||
2023 | force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || | ||
2024 | (rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); | ||
2025 | |||
2026 | if (force_high) { | ||
2027 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) | ||
2028 | pi->graphics_level[i].GnbSlow = 0; | ||
2029 | } else { | ||
2030 | if (pi->battery_state) | ||
2031 | pi->graphics_level[0].ForceNbPs1 = 1; | ||
2032 | |||
2033 | pi->graphics_level[1].GnbSlow = 0; | ||
2034 | pi->graphics_level[2].GnbSlow = 0; | ||
2035 | pi->graphics_level[3].GnbSlow = 0; | ||
2036 | pi->graphics_level[4].GnbSlow = 0; | ||
2037 | } | ||
2038 | } else { | ||
2039 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { | ||
2040 | pi->graphics_level[i].GnbSlow = 1; | ||
2041 | pi->graphics_level[i].ForceNbPs1 = 0; | ||
2042 | pi->graphics_level[i].UpH = 0; | ||
2043 | } | ||
2044 | |||
2045 | if (pi->sys_info.nb_dpm_enable && pi->battery_state) { | ||
2046 | pi->graphics_level[pi->lowest_valid].UpH = 0x28; | ||
2047 | pi->graphics_level[pi->lowest_valid].GnbSlow = 0; | ||
2048 | if (pi->lowest_valid != pi->highest_valid) | ||
2049 | pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1; | ||
2050 | } | ||
2051 | } | ||
2052 | return 0; | ||
2053 | } | ||
2054 | |||
2055 | static int kv_calculate_dpm_settings(struct radeon_device *rdev) | ||
2056 | { | ||
2057 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2058 | u32 i; | ||
2059 | |||
2060 | if (pi->lowest_valid > pi->highest_valid) | ||
2061 | return -EINVAL; | ||
2062 | |||
2063 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) | ||
2064 | pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0; | ||
2065 | |||
2066 | return 0; | ||
2067 | } | ||
2068 | |||
2069 | static void kv_init_graphics_levels(struct radeon_device *rdev) | ||
2070 | { | ||
2071 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2072 | u32 i; | ||
2073 | struct radeon_clock_voltage_dependency_table *table = | ||
2074 | &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; | ||
2075 | |||
2076 | if (table && table->count) { | ||
2077 | u32 vid_2bit; | ||
2078 | |||
2079 | pi->graphics_dpm_level_count = 0; | ||
2080 | for (i = 0; i < table->count; i++) { | ||
2081 | if (pi->high_voltage_t && | ||
2082 | (pi->high_voltage_t < | ||
2083 | kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v))) | ||
2084 | break; | ||
2085 | |||
2086 | kv_set_divider_value(rdev, i, table->entries[i].clk); | ||
2087 | vid_2bit = sumo_convert_vid7_to_vid2(rdev, | ||
2088 | &pi->sys_info.vid_mapping_table, | ||
2089 | table->entries[i].v); | ||
2090 | kv_set_vid(rdev, i, vid_2bit); | ||
2091 | kv_set_at(rdev, i, pi->at[i]); | ||
2092 | kv_dpm_power_level_enabled_for_throttle(rdev, i, true); | ||
2093 | pi->graphics_dpm_level_count++; | ||
2094 | } | ||
2095 | } else { | ||
2096 | struct sumo_sclk_voltage_mapping_table *table = | ||
2097 | &pi->sys_info.sclk_voltage_mapping_table; | ||
2098 | |||
2099 | pi->graphics_dpm_level_count = 0; | ||
2100 | for (i = 0; i < table->num_max_dpm_entries; i++) { | ||
2101 | if (pi->high_voltage_t && | ||
2102 | pi->high_voltage_t < | ||
2103 | kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit)) | ||
2104 | break; | ||
2105 | |||
2106 | kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency); | ||
2107 | kv_set_vid(rdev, i, table->entries[i].vid_2bit); | ||
2108 | kv_set_at(rdev, i, pi->at[i]); | ||
2109 | kv_dpm_power_level_enabled_for_throttle(rdev, i, true); | ||
2110 | pi->graphics_dpm_level_count++; | ||
2111 | } | ||
2112 | } | ||
2113 | |||
2114 | for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) | ||
2115 | kv_dpm_power_level_enable(rdev, i, false); | ||
2116 | } | ||
2117 | |||
2118 | static void kv_enable_new_levels(struct radeon_device *rdev) | ||
2119 | { | ||
2120 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2121 | u32 i; | ||
2122 | |||
2123 | for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { | ||
2124 | if (i >= pi->lowest_valid && i <= pi->highest_valid) | ||
2125 | kv_dpm_power_level_enable(rdev, i, true); | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | static int kv_set_enabled_levels(struct radeon_device *rdev) | ||
2130 | { | ||
2131 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2132 | u32 i, new_mask = 0; | ||
2133 | |||
2134 | for (i = pi->lowest_valid; i <= pi->highest_valid; i++) | ||
2135 | new_mask |= (1 << i); | ||
2136 | |||
2137 | return kv_send_msg_to_smc_with_parameter(rdev, | ||
2138 | PPSMC_MSG_SCLKDPM_SetEnabledMask, | ||
2139 | new_mask); | ||
2140 | } | ||
2141 | |||
2142 | static void kv_program_nbps_index_settings(struct radeon_device *rdev, | ||
2143 | struct radeon_ps *new_rps) | ||
2144 | { | ||
2145 | struct kv_ps *new_ps = kv_get_ps(new_rps); | ||
2146 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2147 | u32 nbdpmconfig1; | ||
2148 | |||
2149 | if (rdev->family == CHIP_KABINI) | ||
2150 | return; | ||
2151 | |||
2152 | if (pi->sys_info.nb_dpm_enable) { | ||
2153 | nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1); | ||
2154 | nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | | ||
2155 | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); | ||
2156 | nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) | | ||
2157 | Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) | | ||
2158 | DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) | | ||
2159 | DpmXNbPsHi(new_ps->dpmx_nb_ps_hi)); | ||
2160 | WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1); | ||
2161 | } | ||
2162 | } | ||
2163 | |||
2164 | static int kv_set_thermal_temperature_range(struct radeon_device *rdev, | ||
2165 | int min_temp, int max_temp) | ||
2166 | { | ||
2167 | int low_temp = 0 * 1000; | ||
2168 | int high_temp = 255 * 1000; | ||
2169 | u32 tmp; | ||
2170 | |||
2171 | if (low_temp < min_temp) | ||
2172 | low_temp = min_temp; | ||
2173 | if (high_temp > max_temp) | ||
2174 | high_temp = max_temp; | ||
2175 | if (high_temp < low_temp) { | ||
2176 | DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); | ||
2177 | return -EINVAL; | ||
2178 | } | ||
2179 | |||
2180 | tmp = RREG32_SMC(CG_THERMAL_INT_CTRL); | ||
2181 | tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK); | ||
2182 | tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) | | ||
2183 | DIG_THERM_INTL(49 + (low_temp / 1000))); | ||
2184 | WREG32_SMC(CG_THERMAL_INT_CTRL, tmp); | ||
2185 | |||
2186 | rdev->pm.dpm.thermal.min_temp = low_temp; | ||
2187 | rdev->pm.dpm.thermal.max_temp = high_temp; | ||
2188 | |||
2189 | return 0; | ||
2190 | } | ||
2191 | |||
2192 | union igp_info { | ||
2193 | struct _ATOM_INTEGRATED_SYSTEM_INFO info; | ||
2194 | struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; | ||
2195 | struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; | ||
2196 | struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; | ||
2197 | struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; | ||
2198 | struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; | ||
2199 | }; | ||
2200 | |||
2201 | static int kv_parse_sys_info_table(struct radeon_device *rdev) | ||
2202 | { | ||
2203 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2204 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
2205 | int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); | ||
2206 | union igp_info *igp_info; | ||
2207 | u8 frev, crev; | ||
2208 | u16 data_offset; | ||
2209 | int i; | ||
2210 | |||
2211 | if (atom_parse_data_header(mode_info->atom_context, index, NULL, | ||
2212 | &frev, &crev, &data_offset)) { | ||
2213 | igp_info = (union igp_info *)(mode_info->atom_context->bios + | ||
2214 | data_offset); | ||
2215 | |||
2216 | if (crev != 8) { | ||
2217 | DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); | ||
2218 | return -EINVAL; | ||
2219 | } | ||
2220 | pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); | ||
2221 | pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock); | ||
2222 | pi->sys_info.bootup_nb_voltage_index = | ||
2223 | le16_to_cpu(igp_info->info_8.usBootUpNBVoltage); | ||
2224 | if (igp_info->info_8.ucHtcTmpLmt == 0) | ||
2225 | pi->sys_info.htc_tmp_lmt = 203; | ||
2226 | else | ||
2227 | pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt; | ||
2228 | if (igp_info->info_8.ucHtcHystLmt == 0) | ||
2229 | pi->sys_info.htc_hyst_lmt = 5; | ||
2230 | else | ||
2231 | pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; | ||
2232 | if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { | ||
2233 | DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); | ||
2234 | } | ||
2235 | |||
2236 | if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) | ||
2237 | pi->sys_info.nb_dpm_enable = true; | ||
2238 | else | ||
2239 | pi->sys_info.nb_dpm_enable = false; | ||
2240 | |||
2241 | for (i = 0; i < KV_NUM_NBPSTATES; i++) { | ||
2242 | pi->sys_info.nbp_memory_clock[i] = | ||
2243 | le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]); | ||
2244 | pi->sys_info.nbp_n_clock[i] = | ||
2245 | le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); | ||
2246 | } | ||
2247 | if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & | ||
2248 | SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) | ||
2249 | pi->caps_enable_dfs_bypass = true; | ||
2250 | |||
2251 | sumo_construct_sclk_voltage_mapping_table(rdev, | ||
2252 | &pi->sys_info.sclk_voltage_mapping_table, | ||
2253 | igp_info->info_8.sAvail_SCLK); | ||
2254 | |||
2255 | sumo_construct_vid_mapping_table(rdev, | ||
2256 | &pi->sys_info.vid_mapping_table, | ||
2257 | igp_info->info_8.sAvail_SCLK); | ||
2258 | |||
2259 | kv_construct_max_power_limits_table(rdev, | ||
2260 | &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); | ||
2261 | } | ||
2262 | return 0; | ||
2263 | } | ||
2264 | |||
2265 | union power_info { | ||
2266 | struct _ATOM_POWERPLAY_INFO info; | ||
2267 | struct _ATOM_POWERPLAY_INFO_V2 info_2; | ||
2268 | struct _ATOM_POWERPLAY_INFO_V3 info_3; | ||
2269 | struct _ATOM_PPLIB_POWERPLAYTABLE pplib; | ||
2270 | struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; | ||
2271 | struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; | ||
2272 | }; | ||
2273 | |||
2274 | union pplib_clock_info { | ||
2275 | struct _ATOM_PPLIB_R600_CLOCK_INFO r600; | ||
2276 | struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; | ||
2277 | struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; | ||
2278 | struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; | ||
2279 | }; | ||
2280 | |||
2281 | union pplib_power_state { | ||
2282 | struct _ATOM_PPLIB_STATE v1; | ||
2283 | struct _ATOM_PPLIB_STATE_V2 v2; | ||
2284 | }; | ||
2285 | |||
2286 | static void kv_patch_boot_state(struct radeon_device *rdev, | ||
2287 | struct kv_ps *ps) | ||
2288 | { | ||
2289 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2290 | |||
2291 | ps->num_levels = 1; | ||
2292 | ps->levels[0] = pi->boot_pl; | ||
2293 | } | ||
2294 | |||
2295 | static void kv_parse_pplib_non_clock_info(struct radeon_device *rdev, | ||
2296 | struct radeon_ps *rps, | ||
2297 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, | ||
2298 | u8 table_rev) | ||
2299 | { | ||
2300 | struct kv_ps *ps = kv_get_ps(rps); | ||
2301 | |||
2302 | rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); | ||
2303 | rps->class = le16_to_cpu(non_clock_info->usClassification); | ||
2304 | rps->class2 = le16_to_cpu(non_clock_info->usClassification2); | ||
2305 | |||
2306 | if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { | ||
2307 | rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); | ||
2308 | rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); | ||
2309 | } else { | ||
2310 | rps->vclk = 0; | ||
2311 | rps->dclk = 0; | ||
2312 | } | ||
2313 | |||
2314 | if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { | ||
2315 | rdev->pm.dpm.boot_ps = rps; | ||
2316 | kv_patch_boot_state(rdev, ps); | ||
2317 | } | ||
2318 | if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) | ||
2319 | rdev->pm.dpm.uvd_ps = rps; | ||
2320 | } | ||
2321 | |||
2322 | static void kv_parse_pplib_clock_info(struct radeon_device *rdev, | ||
2323 | struct radeon_ps *rps, int index, | ||
2324 | union pplib_clock_info *clock_info) | ||
2325 | { | ||
2326 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2327 | struct kv_ps *ps = kv_get_ps(rps); | ||
2328 | struct kv_pl *pl = &ps->levels[index]; | ||
2329 | u32 sclk; | ||
2330 | |||
2331 | sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); | ||
2332 | sclk |= clock_info->sumo.ucEngineClockHigh << 16; | ||
2333 | pl->sclk = sclk; | ||
2334 | pl->vddc_index = clock_info->sumo.vddcIndex; | ||
2335 | |||
2336 | ps->num_levels = index + 1; | ||
2337 | |||
2338 | if (pi->caps_sclk_ds) { | ||
2339 | pl->ds_divider_index = 5; | ||
2340 | pl->ss_divider_index = 5; | ||
2341 | } | ||
2342 | } | ||
2343 | |||
2344 | static int kv_parse_power_table(struct radeon_device *rdev) | ||
2345 | { | ||
2346 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
2347 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; | ||
2348 | union pplib_power_state *power_state; | ||
2349 | int i, j, k, non_clock_array_index, clock_array_index; | ||
2350 | union pplib_clock_info *clock_info; | ||
2351 | struct _StateArray *state_array; | ||
2352 | struct _ClockInfoArray *clock_info_array; | ||
2353 | struct _NonClockInfoArray *non_clock_info_array; | ||
2354 | union power_info *power_info; | ||
2355 | int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); | ||
2356 | u16 data_offset; | ||
2357 | u8 frev, crev; | ||
2358 | u8 *power_state_offset; | ||
2359 | struct kv_ps *ps; | ||
2360 | |||
2361 | if (!atom_parse_data_header(mode_info->atom_context, index, NULL, | ||
2362 | &frev, &crev, &data_offset)) | ||
2363 | return -EINVAL; | ||
2364 | power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); | ||
2365 | |||
2366 | state_array = (struct _StateArray *) | ||
2367 | (mode_info->atom_context->bios + data_offset + | ||
2368 | le16_to_cpu(power_info->pplib.usStateArrayOffset)); | ||
2369 | clock_info_array = (struct _ClockInfoArray *) | ||
2370 | (mode_info->atom_context->bios + data_offset + | ||
2371 | le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); | ||
2372 | non_clock_info_array = (struct _NonClockInfoArray *) | ||
2373 | (mode_info->atom_context->bios + data_offset + | ||
2374 | le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); | ||
2375 | |||
2376 | rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * | ||
2377 | state_array->ucNumEntries, GFP_KERNEL); | ||
2378 | if (!rdev->pm.dpm.ps) | ||
2379 | return -ENOMEM; | ||
2380 | power_state_offset = (u8 *)state_array->states; | ||
2381 | rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); | ||
2382 | rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); | ||
2383 | rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); | ||
2384 | for (i = 0; i < state_array->ucNumEntries; i++) { | ||
2385 | power_state = (union pplib_power_state *)power_state_offset; | ||
2386 | non_clock_array_index = power_state->v2.nonClockInfoIndex; | ||
2387 | non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) | ||
2388 | &non_clock_info_array->nonClockInfo[non_clock_array_index]; | ||
2389 | if (!rdev->pm.power_state[i].clock_info) | ||
2390 | return -EINVAL; | ||
2391 | ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); | ||
2392 | if (ps == NULL) { | ||
2393 | kfree(rdev->pm.dpm.ps); | ||
2394 | return -ENOMEM; | ||
2395 | } | ||
2396 | rdev->pm.dpm.ps[i].ps_priv = ps; | ||
2397 | k = 0; | ||
2398 | for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { | ||
2399 | clock_array_index = power_state->v2.clockInfoIndex[j]; | ||
2400 | if (clock_array_index >= clock_info_array->ucNumEntries) | ||
2401 | continue; | ||
2402 | if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) | ||
2403 | break; | ||
2404 | clock_info = (union pplib_clock_info *) | ||
2405 | &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; | ||
2406 | kv_parse_pplib_clock_info(rdev, | ||
2407 | &rdev->pm.dpm.ps[i], k, | ||
2408 | clock_info); | ||
2409 | k++; | ||
2410 | } | ||
2411 | kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], | ||
2412 | non_clock_info, | ||
2413 | non_clock_info_array->ucEntrySize); | ||
2414 | power_state_offset += 2 + power_state->v2.ucNumDPMLevels; | ||
2415 | } | ||
2416 | rdev->pm.dpm.num_ps = state_array->ucNumEntries; | ||
2417 | return 0; | ||
2418 | } | ||
2419 | |||
2420 | int kv_dpm_init(struct radeon_device *rdev) | ||
2421 | { | ||
2422 | struct kv_power_info *pi; | ||
2423 | int ret, i; | ||
2424 | |||
2425 | pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); | ||
2426 | if (pi == NULL) | ||
2427 | return -ENOMEM; | ||
2428 | rdev->pm.dpm.priv = pi; | ||
2429 | |||
2430 | ret = r600_parse_extended_power_table(rdev); | ||
2431 | if (ret) | ||
2432 | return ret; | ||
2433 | |||
2434 | for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) | ||
2435 | pi->at[i] = TRINITY_AT_DFLT; | ||
2436 | |||
2437 | pi->sram_end = SMC_RAM_END; | ||
2438 | |||
2439 | if (rdev->family == CHIP_KABINI) | ||
2440 | pi->high_voltage_t = 4001; | ||
2441 | |||
2442 | pi->enable_nb_dpm = true; | ||
2443 | |||
2444 | pi->caps_power_containment = true; | ||
2445 | pi->caps_cac = true; | ||
2446 | pi->enable_didt = false; | ||
2447 | if (pi->enable_didt) { | ||
2448 | pi->caps_sq_ramping = true; | ||
2449 | pi->caps_db_ramping = true; | ||
2450 | pi->caps_td_ramping = true; | ||
2451 | pi->caps_tcp_ramping = true; | ||
2452 | } | ||
2453 | |||
2454 | pi->caps_sclk_ds = true; | ||
2455 | pi->enable_auto_thermal_throttling = true; | ||
2456 | pi->disable_nb_ps3_in_battery = false; | ||
2457 | pi->bapm_enable = true; | ||
2458 | pi->voltage_drop_t = 0; | ||
2459 | pi->caps_sclk_throttle_low_notification = false; | ||
2460 | pi->caps_fps = false; /* true? */ | ||
2461 | pi->caps_uvd_pg = false; /* XXX */ | ||
2462 | pi->caps_uvd_dpm = true; | ||
2463 | pi->caps_vce_pg = false; | ||
2464 | pi->caps_samu_pg = false; | ||
2465 | pi->caps_acp_pg = false; | ||
2466 | pi->caps_stable_p_state = false; | ||
2467 | |||
2468 | ret = kv_parse_sys_info_table(rdev); | ||
2469 | if (ret) | ||
2470 | return ret; | ||
2471 | |||
2472 | kv_patch_voltage_values(rdev); | ||
2473 | kv_construct_boot_state(rdev); | ||
2474 | |||
2475 | ret = kv_parse_power_table(rdev); | ||
2476 | if (ret) | ||
2477 | return ret; | ||
2478 | |||
2479 | pi->enable_dpm = true; | ||
2480 | |||
2481 | return 0; | ||
2482 | } | ||
2483 | |||
2484 | void kv_dpm_print_power_state(struct radeon_device *rdev, | ||
2485 | struct radeon_ps *rps) | ||
2486 | { | ||
2487 | int i; | ||
2488 | struct kv_ps *ps = kv_get_ps(rps); | ||
2489 | |||
2490 | r600_dpm_print_class_info(rps->class, rps->class2); | ||
2491 | r600_dpm_print_cap_info(rps->caps); | ||
2492 | printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); | ||
2493 | for (i = 0; i < ps->num_levels; i++) { | ||
2494 | struct kv_pl *pl = &ps->levels[i]; | ||
2495 | printk("\t\tpower level %d sclk: %u vddc: %u\n", | ||
2496 | i, pl->sclk, | ||
2497 | kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index)); | ||
2498 | } | ||
2499 | r600_dpm_print_ps_status(rdev, rps); | ||
2500 | } | ||
2501 | |||
2502 | void kv_dpm_fini(struct radeon_device *rdev) | ||
2503 | { | ||
2504 | int i; | ||
2505 | |||
2506 | for (i = 0; i < rdev->pm.dpm.num_ps; i++) { | ||
2507 | kfree(rdev->pm.dpm.ps[i].ps_priv); | ||
2508 | } | ||
2509 | kfree(rdev->pm.dpm.ps); | ||
2510 | kfree(rdev->pm.dpm.priv); | ||
2511 | r600_free_extended_power_table(rdev); | ||
2512 | } | ||
2513 | |||
2514 | void kv_dpm_display_configuration_changed(struct radeon_device *rdev) | ||
2515 | { | ||
2516 | |||
2517 | } | ||
2518 | |||
2519 | u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low) | ||
2520 | { | ||
2521 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2522 | struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps); | ||
2523 | |||
2524 | if (low) | ||
2525 | return requested_state->levels[0].sclk; | ||
2526 | else | ||
2527 | return requested_state->levels[requested_state->num_levels - 1].sclk; | ||
2528 | } | ||
2529 | |||
2530 | u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) | ||
2531 | { | ||
2532 | struct kv_power_info *pi = kv_get_pi(rdev); | ||
2533 | |||
2534 | return pi->sys_info.bootup_uma_clk; | ||
2535 | } | ||
2536 | |||
diff --git a/drivers/gpu/drm/radeon/kv_dpm.h b/drivers/gpu/drm/radeon/kv_dpm.h new file mode 100644 index 000000000000..32bb079572d7 --- /dev/null +++ b/drivers/gpu/drm/radeon/kv_dpm.h | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef __KV_DPM_H__ | ||
24 | #define __KV_DPM_H__ | ||
25 | |||
26 | #define SMU__NUM_SCLK_DPM_STATE 8 | ||
27 | #define SMU__NUM_MCLK_DPM_LEVELS 4 | ||
28 | #define SMU__NUM_LCLK_DPM_LEVELS 8 | ||
29 | #define SMU__NUM_PCIE_DPM_LEVELS 0 /* ??? */ | ||
30 | #include "smu7_fusion.h" | ||
31 | #include "trinity_dpm.h" | ||
32 | #include "ppsmc.h" | ||
33 | |||
34 | #define KV_NUM_NBPSTATES 4 | ||
35 | |||
36 | enum kv_pt_config_reg_type { | ||
37 | KV_CONFIGREG_MMR = 0, | ||
38 | KV_CONFIGREG_SMC_IND, | ||
39 | KV_CONFIGREG_DIDT_IND, | ||
40 | KV_CONFIGREG_CACHE, | ||
41 | KV_CONFIGREG_MAX | ||
42 | }; | ||
43 | |||
44 | struct kv_pt_config_reg { | ||
45 | u32 offset; | ||
46 | u32 mask; | ||
47 | u32 shift; | ||
48 | u32 value; | ||
49 | enum kv_pt_config_reg_type type; | ||
50 | }; | ||
51 | |||
52 | struct kv_lcac_config_values { | ||
53 | u32 block_id; | ||
54 | u32 signal_id; | ||
55 | u32 t; | ||
56 | }; | ||
57 | |||
58 | struct kv_lcac_config_reg { | ||
59 | u32 cntl; | ||
60 | u32 block_mask; | ||
61 | u32 block_shift; | ||
62 | u32 signal_mask; | ||
63 | u32 signal_shift; | ||
64 | u32 t_mask; | ||
65 | u32 t_shift; | ||
66 | u32 enable_mask; | ||
67 | u32 enable_shift; | ||
68 | }; | ||
69 | |||
70 | struct kv_pl { | ||
71 | u32 sclk; | ||
72 | u8 vddc_index; | ||
73 | u8 ds_divider_index; | ||
74 | u8 ss_divider_index; | ||
75 | u8 allow_gnb_slow; | ||
76 | u8 force_nbp_state; | ||
77 | u8 display_wm; | ||
78 | u8 vce_wm; | ||
79 | }; | ||
80 | |||
81 | struct kv_ps { | ||
82 | struct kv_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS]; | ||
83 | u32 num_levels; | ||
84 | bool need_dfs_bypass; | ||
85 | u8 dpm0_pg_nb_ps_lo; | ||
86 | u8 dpm0_pg_nb_ps_hi; | ||
87 | u8 dpmx_nb_ps_lo; | ||
88 | u8 dpmx_nb_ps_hi; | ||
89 | }; | ||
90 | |||
91 | struct kv_sys_info { | ||
92 | u32 bootup_uma_clk; | ||
93 | u32 bootup_sclk; | ||
94 | u32 dentist_vco_freq; | ||
95 | u32 nb_dpm_enable; | ||
96 | u32 nbp_memory_clock[KV_NUM_NBPSTATES]; | ||
97 | u32 nbp_n_clock[KV_NUM_NBPSTATES]; | ||
98 | u16 bootup_nb_voltage_index; | ||
99 | u8 htc_tmp_lmt; | ||
100 | u8 htc_hyst_lmt; | ||
101 | struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table; | ||
102 | struct sumo_vid_mapping_table vid_mapping_table; | ||
103 | u32 uma_channel_number; | ||
104 | }; | ||
105 | |||
106 | struct kv_power_info { | ||
107 | u32 at[SUMO_MAX_HARDWARE_POWERLEVELS]; | ||
108 | u32 voltage_drop_t; | ||
109 | struct kv_sys_info sys_info; | ||
110 | struct kv_pl boot_pl; | ||
111 | bool enable_nb_ps_policy; | ||
112 | bool disable_nb_ps3_in_battery; | ||
113 | bool video_start; | ||
114 | bool battery_state; | ||
115 | u32 lowest_valid; | ||
116 | u32 highest_valid; | ||
117 | u16 high_voltage_t; | ||
118 | bool cac_enabled; | ||
119 | bool bapm_enable; | ||
120 | /* smc offsets */ | ||
121 | u32 sram_end; | ||
122 | u32 dpm_table_start; | ||
123 | u32 soft_regs_start; | ||
124 | /* dpm SMU tables */ | ||
125 | u8 graphics_dpm_level_count; | ||
126 | u8 uvd_level_count; | ||
127 | u8 vce_level_count; | ||
128 | u8 acp_level_count; | ||
129 | u8 samu_level_count; | ||
130 | u16 fps_high_t; | ||
131 | SMU7_Fusion_GraphicsLevel graphics_level[SMU__NUM_SCLK_DPM_STATE]; | ||
132 | SMU7_Fusion_ACPILevel acpi_level; | ||
133 | SMU7_Fusion_UvdLevel uvd_level[SMU7_MAX_LEVELS_UVD]; | ||
134 | SMU7_Fusion_ExtClkLevel vce_level[SMU7_MAX_LEVELS_VCE]; | ||
135 | SMU7_Fusion_ExtClkLevel acp_level[SMU7_MAX_LEVELS_ACP]; | ||
136 | SMU7_Fusion_ExtClkLevel samu_level[SMU7_MAX_LEVELS_SAMU]; | ||
137 | u8 uvd_boot_level; | ||
138 | u8 vce_boot_level; | ||
139 | u8 acp_boot_level; | ||
140 | u8 samu_boot_level; | ||
141 | u8 uvd_interval; | ||
142 | u8 vce_interval; | ||
143 | u8 acp_interval; | ||
144 | u8 samu_interval; | ||
145 | u8 graphics_boot_level; | ||
146 | u8 graphics_interval; | ||
147 | u8 graphics_therm_throttle_enable; | ||
148 | u8 graphics_voltage_change_enable; | ||
149 | u8 graphics_clk_slow_enable; | ||
150 | u8 graphics_clk_slow_divider; | ||
151 | u8 fps_low_t; | ||
152 | u32 low_sclk_interrupt_t; | ||
153 | bool uvd_power_gated; | ||
154 | bool vce_power_gated; | ||
155 | bool acp_power_gated; | ||
156 | bool samu_power_gated; | ||
157 | bool nb_dpm_enabled; | ||
158 | /* flags */ | ||
159 | bool enable_didt; | ||
160 | bool enable_dpm; | ||
161 | bool enable_auto_thermal_throttling; | ||
162 | bool enable_nb_dpm; | ||
163 | /* caps */ | ||
164 | bool caps_cac; | ||
165 | bool caps_power_containment; | ||
166 | bool caps_sq_ramping; | ||
167 | bool caps_db_ramping; | ||
168 | bool caps_td_ramping; | ||
169 | bool caps_tcp_ramping; | ||
170 | bool caps_sclk_throttle_low_notification; | ||
171 | bool caps_fps; | ||
172 | bool caps_uvd_dpm; | ||
173 | bool caps_uvd_pg; | ||
174 | bool caps_vce_pg; | ||
175 | bool caps_samu_pg; | ||
176 | bool caps_acp_pg; | ||
177 | bool caps_stable_p_state; | ||
178 | bool caps_enable_dfs_bypass; | ||
179 | bool caps_sclk_ds; | ||
180 | struct radeon_ps current_rps; | ||
181 | struct kv_ps current_ps; | ||
182 | struct radeon_ps requested_rps; | ||
183 | struct kv_ps requested_ps; | ||
184 | }; | ||
185 | |||
186 | |||
187 | /* kv_smc.c */ | ||
188 | int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id); | ||
189 | int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask); | ||
190 | int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev, | ||
191 | PPSMC_Msg msg, u32 parameter); | ||
192 | int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, | ||
193 | u32 *value, u32 limit); | ||
194 | int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable); | ||
195 | int kv_copy_bytes_to_smc(struct radeon_device *rdev, | ||
196 | u32 smc_start_address, | ||
197 | const u8 *src, u32 byte_count, u32 limit); | ||
198 | |||
199 | #endif | ||
diff --git a/drivers/gpu/drm/radeon/kv_smc.c b/drivers/gpu/drm/radeon/kv_smc.c new file mode 100644 index 000000000000..34a226d7e34a --- /dev/null +++ b/drivers/gpu/drm/radeon/kv_smc.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Alex Deucher | ||
23 | */ | ||
24 | |||
25 | #include "drmP.h" | ||
26 | #include "radeon.h" | ||
27 | #include "cikd.h" | ||
28 | #include "kv_dpm.h" | ||
29 | |||
30 | int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id) | ||
31 | { | ||
32 | u32 i; | ||
33 | u32 tmp = 0; | ||
34 | |||
35 | WREG32(SMC_MESSAGE_0, id & SMC_MSG_MASK); | ||
36 | |||
37 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
38 | if ((RREG32(SMC_RESP_0) & SMC_RESP_MASK) != 0) | ||
39 | break; | ||
40 | udelay(1); | ||
41 | } | ||
42 | tmp = RREG32(SMC_RESP_0) & SMC_RESP_MASK; | ||
43 | |||
44 | if (tmp != 1) { | ||
45 | if (tmp == 0xFF) | ||
46 | return -EINVAL; | ||
47 | else if (tmp == 0xFE) | ||
48 | return -EINVAL; | ||
49 | } | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask) | ||
55 | { | ||
56 | int ret; | ||
57 | |||
58 | ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_SCLKDPM_GetEnabledMask); | ||
59 | |||
60 | if (ret == 0) | ||
61 | *enable_mask = RREG32_SMC(SMC_SYSCON_MSG_ARG_0); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev, | ||
67 | PPSMC_Msg msg, u32 parameter) | ||
68 | { | ||
69 | |||
70 | WREG32(SMC_MSG_ARG_0, parameter); | ||
71 | |||
72 | return kv_notify_message_to_smu(rdev, msg); | ||
73 | } | ||
74 | |||
75 | static int kv_set_smc_sram_address(struct radeon_device *rdev, | ||
76 | u32 smc_address, u32 limit) | ||
77 | { | ||
78 | if (smc_address & 3) | ||
79 | return -EINVAL; | ||
80 | if ((smc_address + 3) > limit) | ||
81 | return -EINVAL; | ||
82 | |||
83 | WREG32(SMC_IND_INDEX_0, smc_address); | ||
84 | WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, | ||
90 | u32 *value, u32 limit) | ||
91 | { | ||
92 | int ret; | ||
93 | |||
94 | ret = kv_set_smc_sram_address(rdev, smc_address, limit); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | |||
98 | *value = RREG32(SMC_IND_DATA_0); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable) | ||
103 | { | ||
104 | if (enable) | ||
105 | return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Enable); | ||
106 | else | ||
107 | return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Disable); | ||
108 | } | ||
109 | |||
110 | int kv_copy_bytes_to_smc(struct radeon_device *rdev, | ||
111 | u32 smc_start_address, | ||
112 | const u8 *src, u32 byte_count, u32 limit) | ||
113 | { | ||
114 | int ret; | ||
115 | u32 data, original_data, addr, extra_shift, t_byte, count, mask; | ||
116 | |||
117 | if ((smc_start_address + byte_count) > limit) | ||
118 | return -EINVAL; | ||
119 | |||
120 | addr = smc_start_address; | ||
121 | t_byte = addr & 3; | ||
122 | |||
123 | /* RMW for the initial bytes */ | ||
124 | if (t_byte != 0) { | ||
125 | addr -= t_byte; | ||
126 | |||
127 | ret = kv_set_smc_sram_address(rdev, addr, limit); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | original_data = RREG32(SMC_IND_DATA_0); | ||
132 | |||
133 | data = 0; | ||
134 | mask = 0; | ||
135 | count = 4; | ||
136 | while (count > 0) { | ||
137 | if (t_byte > 0) { | ||
138 | mask = (mask << 8) | 0xff; | ||
139 | t_byte--; | ||
140 | } else if (byte_count > 0) { | ||
141 | data = (data << 8) + *src++; | ||
142 | byte_count--; | ||
143 | mask <<= 8; | ||
144 | } else { | ||
145 | data <<= 8; | ||
146 | mask = (mask << 8) | 0xff; | ||
147 | } | ||
148 | count--; | ||
149 | } | ||
150 | |||
151 | data |= original_data & mask; | ||
152 | |||
153 | ret = kv_set_smc_sram_address(rdev, addr, limit); | ||
154 | if (ret) | ||
155 | return ret; | ||
156 | |||
157 | WREG32(SMC_IND_DATA_0, data); | ||
158 | |||
159 | addr += 4; | ||
160 | } | ||
161 | |||
162 | while (byte_count >= 4) { | ||
163 | /* SMC address space is BE */ | ||
164 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
165 | |||
166 | ret = kv_set_smc_sram_address(rdev, addr, limit); | ||
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | WREG32(SMC_IND_DATA_0, data); | ||
171 | |||
172 | src += 4; | ||
173 | byte_count -= 4; | ||
174 | addr += 4; | ||
175 | } | ||
176 | |||
177 | /* RMW for the final bytes */ | ||
178 | if (byte_count > 0) { | ||
179 | data = 0; | ||
180 | |||
181 | ret = kv_set_smc_sram_address(rdev, addr, limit); | ||
182 | if (ret) | ||
183 | return ret; | ||
184 | |||
185 | original_data= RREG32(SMC_IND_DATA_0); | ||
186 | |||
187 | extra_shift = 8 * (4 - byte_count); | ||
188 | |||
189 | while (byte_count > 0) { | ||
190 | /* SMC address space is BE */ | ||
191 | data = (data << 8) + *src++; | ||
192 | byte_count--; | ||
193 | } | ||
194 | |||
195 | data <<= extra_shift; | ||
196 | |||
197 | data |= (original_data & ~((~0UL) << extra_shift)); | ||
198 | |||
199 | ret = kv_set_smc_sram_address(rdev, addr, limit); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | |||
203 | WREG32(SMC_IND_DATA_0, data); | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h index b5564a3645d2..6db6e320bc79 100644 --- a/drivers/gpu/drm/radeon/ppsmc.h +++ b/drivers/gpu/drm/radeon/ppsmc.h | |||
@@ -99,11 +99,45 @@ typedef uint8_t PPSMC_Result; | |||
99 | #define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint8_t)0x96) | 99 | #define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint8_t)0x96) |
100 | #define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint8_t)0x97) | 100 | #define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint8_t)0x97) |
101 | 101 | ||
102 | /* KV/KB */ | ||
103 | #define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D) | ||
104 | #define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E) | ||
105 | #define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F) | ||
106 | #define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130) | ||
107 | #define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131) | ||
108 | #define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132) | ||
109 | #define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135) | ||
110 | #define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136) | ||
111 | #define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137) | ||
112 | #define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138) | ||
113 | #define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139) | ||
114 | #define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a) | ||
115 | #define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d) | ||
116 | #define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140) | ||
117 | #define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141) | ||
118 | #define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145) | ||
119 | #define PPSMC_MSG_DPM_Enable ((uint16_t) 0x14e) | ||
120 | #define PPSMC_MSG_DPM_Disable ((uint16_t) 0x14f) | ||
121 | #define PPSMC_MSG_UVDDPM_Enable ((uint16_t) 0x154) | ||
122 | #define PPSMC_MSG_UVDDPM_Disable ((uint16_t) 0x155) | ||
123 | #define PPSMC_MSG_SAMUDPM_Enable ((uint16_t) 0x156) | ||
124 | #define PPSMC_MSG_SAMUDPM_Disable ((uint16_t) 0x157) | ||
125 | #define PPSMC_MSG_ACPDPM_Enable ((uint16_t) 0x158) | ||
126 | #define PPSMC_MSG_ACPDPM_Disable ((uint16_t) 0x159) | ||
127 | #define PPSMC_MSG_VCEDPM_Enable ((uint16_t) 0x15a) | ||
128 | #define PPSMC_MSG_VCEDPM_Disable ((uint16_t) 0x15b) | ||
129 | #define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162) | ||
130 | #define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189) | ||
131 | #define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A) | ||
132 | |||
102 | /* TN */ | 133 | /* TN */ |
103 | #define PPSMC_MSG_DPM_Config ((uint32_t) 0x102) | 134 | #define PPSMC_MSG_DPM_Config ((uint32_t) 0x102) |
104 | #define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104) | 135 | #define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104) |
105 | #define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) | 136 | #define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) |
106 | #define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) | 137 | #define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) |
138 | #define PPSMC_MSG_Voltage_Cntl_Enable ((uint32_t) 0x109) | ||
139 | #define PPSMC_MSG_VCEPowerOFF ((uint32_t) 0x10e) | ||
140 | #define PPSMC_MSG_VCEPowerON ((uint32_t) 0x10f) | ||
107 | #define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) | 141 | #define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) |
108 | #define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) | 142 | #define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) |
109 | #define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124) | 143 | #define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124) |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3a55540fe280..9c83ecfd0eb7 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c | |||
@@ -2610,6 +2610,20 @@ static struct radeon_asic kv_asic = { | |||
2610 | .set_uvd_clocks = &cik_set_uvd_clocks, | 2610 | .set_uvd_clocks = &cik_set_uvd_clocks, |
2611 | .get_temperature = &kv_get_temp, | 2611 | .get_temperature = &kv_get_temp, |
2612 | }, | 2612 | }, |
2613 | .dpm = { | ||
2614 | .init = &kv_dpm_init, | ||
2615 | .setup_asic = &kv_dpm_setup_asic, | ||
2616 | .enable = &kv_dpm_enable, | ||
2617 | .disable = &kv_dpm_disable, | ||
2618 | .pre_set_power_state = &kv_dpm_pre_set_power_state, | ||
2619 | .set_power_state = &kv_dpm_set_power_state, | ||
2620 | .post_set_power_state = &kv_dpm_post_set_power_state, | ||
2621 | .display_configuration_changed = &kv_dpm_display_configuration_changed, | ||
2622 | .fini = &kv_dpm_fini, | ||
2623 | .get_sclk = &kv_dpm_get_sclk, | ||
2624 | .get_mclk = &kv_dpm_get_mclk, | ||
2625 | .print_power_state = &kv_dpm_print_power_state, | ||
2626 | }, | ||
2613 | .pflip = { | 2627 | .pflip = { |
2614 | .pre_page_flip = &evergreen_pre_page_flip, | 2628 | .pre_page_flip = &evergreen_pre_page_flip, |
2615 | .page_flip = &evergreen_page_flip, | 2629 | .page_flip = &evergreen_page_flip, |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index d5c6c5b10edf..68a1a1fb371d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
@@ -750,4 +750,18 @@ void cik_compute_ring_set_wptr(struct radeon_device *rdev, | |||
750 | int ci_get_temp(struct radeon_device *rdev); | 750 | int ci_get_temp(struct radeon_device *rdev); |
751 | int kv_get_temp(struct radeon_device *rdev); | 751 | int kv_get_temp(struct radeon_device *rdev); |
752 | 752 | ||
753 | int kv_dpm_init(struct radeon_device *rdev); | ||
754 | int kv_dpm_enable(struct radeon_device *rdev); | ||
755 | void kv_dpm_disable(struct radeon_device *rdev); | ||
756 | int kv_dpm_pre_set_power_state(struct radeon_device *rdev); | ||
757 | int kv_dpm_set_power_state(struct radeon_device *rdev); | ||
758 | void kv_dpm_post_set_power_state(struct radeon_device *rdev); | ||
759 | void kv_dpm_setup_asic(struct radeon_device *rdev); | ||
760 | void kv_dpm_display_configuration_changed(struct radeon_device *rdev); | ||
761 | void kv_dpm_fini(struct radeon_device *rdev); | ||
762 | u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low); | ||
763 | u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low); | ||
764 | void kv_dpm_print_power_state(struct radeon_device *rdev, | ||
765 | struct radeon_ps *ps); | ||
766 | |||
753 | #endif | 767 | #endif |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1408014dce8f..37d3d343f687 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -1202,6 +1202,8 @@ int radeon_pm_init(struct radeon_device *rdev) | |||
1202 | case CHIP_VERDE: | 1202 | case CHIP_VERDE: |
1203 | case CHIP_OLAND: | 1203 | case CHIP_OLAND: |
1204 | case CHIP_HAINAN: | 1204 | case CHIP_HAINAN: |
1205 | case CHIP_KABINI: | ||
1206 | case CHIP_KAVERI: | ||
1205 | /* DPM requires the RLC, RV770+ dGPU requires SMC */ | 1207 | /* DPM requires the RLC, RV770+ dGPU requires SMC */ |
1206 | if (!rdev->rlc_fw) | 1208 | if (!rdev->rlc_fw) |
1207 | rdev->pm.pm_method = PM_METHOD_PROFILE; | 1209 | rdev->pm.pm_method = PM_METHOD_PROFILE; |
diff --git a/drivers/gpu/drm/radeon/smu7.h b/drivers/gpu/drm/radeon/smu7.h new file mode 100644 index 000000000000..75a380a15292 --- /dev/null +++ b/drivers/gpu/drm/radeon/smu7.h | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef SMU7_H | ||
25 | #define SMU7_H | ||
26 | |||
27 | #pragma pack(push, 1) | ||
28 | |||
29 | #define SMU7_CONTEXT_ID_SMC 1 | ||
30 | #define SMU7_CONTEXT_ID_VBIOS 2 | ||
31 | |||
32 | |||
33 | #define SMU7_CONTEXT_ID_SMC 1 | ||
34 | #define SMU7_CONTEXT_ID_VBIOS 2 | ||
35 | |||
36 | #define SMU7_MAX_LEVELS_VDDC 8 | ||
37 | #define SMU7_MAX_LEVELS_VDDCI 4 | ||
38 | #define SMU7_MAX_LEVELS_MVDD 4 | ||
39 | #define SMU7_MAX_LEVELS_VDDNB 8 | ||
40 | |||
41 | #define SMU7_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE // SCLK + SQ DPM + ULV | ||
42 | #define SMU7_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS // MCLK Levels DPM | ||
43 | #define SMU7_MAX_LEVELS_GIO SMU__NUM_LCLK_DPM_LEVELS // LCLK Levels | ||
44 | #define SMU7_MAX_LEVELS_LINK SMU__NUM_PCIE_DPM_LEVELS // PCIe speed and number of lanes. | ||
45 | #define SMU7_MAX_LEVELS_UVD 8 // VCLK/DCLK levels for UVD. | ||
46 | #define SMU7_MAX_LEVELS_VCE 8 // ECLK levels for VCE. | ||
47 | #define SMU7_MAX_LEVELS_ACP 8 // ACLK levels for ACP. | ||
48 | #define SMU7_MAX_LEVELS_SAMU 8 // SAMCLK levels for SAMU. | ||
49 | #define SMU7_MAX_ENTRIES_SMIO 32 // Number of entries in SMIO table. | ||
50 | |||
51 | #define DPM_NO_LIMIT 0 | ||
52 | #define DPM_NO_UP 1 | ||
53 | #define DPM_GO_DOWN 2 | ||
54 | #define DPM_GO_UP 3 | ||
55 | |||
56 | #define SMU7_FIRST_DPM_GRAPHICS_LEVEL 0 | ||
57 | #define SMU7_FIRST_DPM_MEMORY_LEVEL 0 | ||
58 | |||
59 | #define GPIO_CLAMP_MODE_VRHOT 1 | ||
60 | #define GPIO_CLAMP_MODE_THERM 2 | ||
61 | #define GPIO_CLAMP_MODE_DC 4 | ||
62 | |||
63 | #define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0 | ||
64 | #define SCRATCH_B_TARG_PCIE_INDEX_MASK (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT) | ||
65 | #define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3 | ||
66 | #define SCRATCH_B_CURR_PCIE_INDEX_MASK (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT) | ||
67 | #define SCRATCH_B_TARG_UVD_INDEX_SHIFT 6 | ||
68 | #define SCRATCH_B_TARG_UVD_INDEX_MASK (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT) | ||
69 | #define SCRATCH_B_CURR_UVD_INDEX_SHIFT 9 | ||
70 | #define SCRATCH_B_CURR_UVD_INDEX_MASK (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT) | ||
71 | #define SCRATCH_B_TARG_VCE_INDEX_SHIFT 12 | ||
72 | #define SCRATCH_B_TARG_VCE_INDEX_MASK (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT) | ||
73 | #define SCRATCH_B_CURR_VCE_INDEX_SHIFT 15 | ||
74 | #define SCRATCH_B_CURR_VCE_INDEX_MASK (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT) | ||
75 | #define SCRATCH_B_TARG_ACP_INDEX_SHIFT 18 | ||
76 | #define SCRATCH_B_TARG_ACP_INDEX_MASK (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT) | ||
77 | #define SCRATCH_B_CURR_ACP_INDEX_SHIFT 21 | ||
78 | #define SCRATCH_B_CURR_ACP_INDEX_MASK (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT) | ||
79 | #define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24 | ||
80 | #define SCRATCH_B_TARG_SAMU_INDEX_MASK (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT) | ||
81 | #define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27 | ||
82 | #define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT) | ||
83 | |||
84 | |||
85 | struct SMU7_PIDController | ||
86 | { | ||
87 | uint32_t Ki; | ||
88 | int32_t LFWindupUL; | ||
89 | int32_t LFWindupLL; | ||
90 | uint32_t StatePrecision; | ||
91 | uint32_t LfPrecision; | ||
92 | uint32_t LfOffset; | ||
93 | uint32_t MaxState; | ||
94 | uint32_t MaxLfFraction; | ||
95 | uint32_t StateShift; | ||
96 | }; | ||
97 | |||
98 | typedef struct SMU7_PIDController SMU7_PIDController; | ||
99 | |||
100 | // ------------------------------------------------------------------------------------------------------------------------- | ||
101 | #define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */ | ||
102 | |||
103 | #define SMU7_SCLK_DPM_CONFIG_MASK 0x01 | ||
104 | #define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK 0x02 | ||
105 | #define SMU7_THERMAL_CONTROLLER_CONFIG_MASK 0x04 | ||
106 | #define SMU7_MCLK_DPM_CONFIG_MASK 0x08 | ||
107 | #define SMU7_UVD_DPM_CONFIG_MASK 0x10 | ||
108 | #define SMU7_VCE_DPM_CONFIG_MASK 0x20 | ||
109 | #define SMU7_ACP_DPM_CONFIG_MASK 0x40 | ||
110 | #define SMU7_SAMU_DPM_CONFIG_MASK 0x80 | ||
111 | #define SMU7_PCIEGEN_DPM_CONFIG_MASK 0x100 | ||
112 | |||
113 | #define SMU7_ACP_MCLK_HANDSHAKE_DISABLE 0x00000001 | ||
114 | #define SMU7_ACP_SCLK_HANDSHAKE_DISABLE 0x00000002 | ||
115 | #define SMU7_UVD_MCLK_HANDSHAKE_DISABLE 0x00000100 | ||
116 | #define SMU7_UVD_SCLK_HANDSHAKE_DISABLE 0x00000200 | ||
117 | #define SMU7_VCE_MCLK_HANDSHAKE_DISABLE 0x00010000 | ||
118 | #define SMU7_VCE_SCLK_HANDSHAKE_DISABLE 0x00020000 | ||
119 | |||
120 | struct SMU7_Firmware_Header | ||
121 | { | ||
122 | uint32_t Digest[5]; | ||
123 | uint32_t Version; | ||
124 | uint32_t HeaderSize; | ||
125 | uint32_t Flags; | ||
126 | uint32_t EntryPoint; | ||
127 | uint32_t CodeSize; | ||
128 | uint32_t ImageSize; | ||
129 | |||
130 | uint32_t Rtos; | ||
131 | uint32_t SoftRegisters; | ||
132 | uint32_t DpmTable; | ||
133 | uint32_t FanTable; | ||
134 | uint32_t CacConfigTable; | ||
135 | uint32_t CacStatusTable; | ||
136 | |||
137 | uint32_t mcRegisterTable; | ||
138 | |||
139 | uint32_t mcArbDramTimingTable; | ||
140 | |||
141 | uint32_t PmFuseTable; | ||
142 | uint32_t Globals; | ||
143 | uint32_t Reserved[42]; | ||
144 | uint32_t Signature; | ||
145 | }; | ||
146 | |||
147 | typedef struct SMU7_Firmware_Header SMU7_Firmware_Header; | ||
148 | |||
149 | #define SMU7_FIRMWARE_HEADER_LOCATION 0x20000 | ||
150 | |||
151 | enum DisplayConfig { | ||
152 | PowerDown = 1, | ||
153 | DP54x4, | ||
154 | DP54x2, | ||
155 | DP54x1, | ||
156 | DP27x4, | ||
157 | DP27x2, | ||
158 | DP27x1, | ||
159 | HDMI297, | ||
160 | HDMI162, | ||
161 | LVDS, | ||
162 | DP324x4, | ||
163 | DP324x2, | ||
164 | DP324x1 | ||
165 | }; | ||
166 | |||
167 | #pragma pack(pop) | ||
168 | |||
169 | #endif | ||
170 | |||
diff --git a/drivers/gpu/drm/radeon/smu7_fusion.h b/drivers/gpu/drm/radeon/smu7_fusion.h new file mode 100644 index 000000000000..78ada9ffd508 --- /dev/null +++ b/drivers/gpu/drm/radeon/smu7_fusion.h | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef SMU7_FUSION_H | ||
25 | #define SMU7_FUSION_H | ||
26 | |||
27 | #include "smu7.h" | ||
28 | |||
29 | #pragma pack(push, 1) | ||
30 | |||
31 | #define SMU7_DTE_ITERATIONS 5 | ||
32 | #define SMU7_DTE_SOURCES 5 | ||
33 | #define SMU7_DTE_SINKS 3 | ||
34 | #define SMU7_NUM_CPU_TES 2 | ||
35 | #define SMU7_NUM_GPU_TES 1 | ||
36 | #define SMU7_NUM_NON_TES 2 | ||
37 | |||
38 | // All 'soft registers' should be uint32_t. | ||
39 | struct SMU7_SoftRegisters | ||
40 | { | ||
41 | uint32_t RefClockFrequency; | ||
42 | uint32_t PmTimerP; | ||
43 | uint32_t FeatureEnables; | ||
44 | uint32_t HandshakeDisables; | ||
45 | |||
46 | uint8_t DisplayPhy1Config; | ||
47 | uint8_t DisplayPhy2Config; | ||
48 | uint8_t DisplayPhy3Config; | ||
49 | uint8_t DisplayPhy4Config; | ||
50 | |||
51 | uint8_t DisplayPhy5Config; | ||
52 | uint8_t DisplayPhy6Config; | ||
53 | uint8_t DisplayPhy7Config; | ||
54 | uint8_t DisplayPhy8Config; | ||
55 | |||
56 | uint32_t AverageGraphicsA; | ||
57 | uint32_t AverageMemoryA; | ||
58 | uint32_t AverageGioA; | ||
59 | |||
60 | uint8_t SClkDpmEnabledLevels; | ||
61 | uint8_t MClkDpmEnabledLevels; | ||
62 | uint8_t LClkDpmEnabledLevels; | ||
63 | uint8_t PCIeDpmEnabledLevels; | ||
64 | |||
65 | uint8_t UVDDpmEnabledLevels; | ||
66 | uint8_t SAMUDpmEnabledLevels; | ||
67 | uint8_t ACPDpmEnabledLevels; | ||
68 | uint8_t VCEDpmEnabledLevels; | ||
69 | |||
70 | uint32_t DRAM_LOG_ADDR_H; | ||
71 | uint32_t DRAM_LOG_ADDR_L; | ||
72 | uint32_t DRAM_LOG_PHY_ADDR_H; | ||
73 | uint32_t DRAM_LOG_PHY_ADDR_L; | ||
74 | uint32_t DRAM_LOG_BUFF_SIZE; | ||
75 | uint32_t UlvEnterC; | ||
76 | uint32_t UlvTime; | ||
77 | uint32_t Reserved[3]; | ||
78 | |||
79 | }; | ||
80 | |||
81 | typedef struct SMU7_SoftRegisters SMU7_SoftRegisters; | ||
82 | |||
83 | struct SMU7_Fusion_GraphicsLevel | ||
84 | { | ||
85 | uint32_t MinVddNb; | ||
86 | |||
87 | uint32_t SclkFrequency; | ||
88 | |||
89 | uint8_t Vid; | ||
90 | uint8_t VidOffset; | ||
91 | uint16_t AT; | ||
92 | |||
93 | uint8_t PowerThrottle; | ||
94 | uint8_t GnbSlow; | ||
95 | uint8_t ForceNbPs1; | ||
96 | uint8_t SclkDid; | ||
97 | |||
98 | uint8_t DisplayWatermark; | ||
99 | uint8_t EnabledForActivity; | ||
100 | uint8_t EnabledForThrottle; | ||
101 | uint8_t UpH; | ||
102 | |||
103 | uint8_t DownH; | ||
104 | uint8_t VoltageDownH; | ||
105 | uint8_t DeepSleepDivId; | ||
106 | |||
107 | uint8_t ClkBypassCntl; | ||
108 | |||
109 | uint32_t reserved; | ||
110 | }; | ||
111 | |||
112 | typedef struct SMU7_Fusion_GraphicsLevel SMU7_Fusion_GraphicsLevel; | ||
113 | |||
114 | struct SMU7_Fusion_GIOLevel | ||
115 | { | ||
116 | uint8_t EnabledForActivity; | ||
117 | uint8_t LclkDid; | ||
118 | uint8_t Vid; | ||
119 | uint8_t VoltageDownH; | ||
120 | |||
121 | uint32_t MinVddNb; | ||
122 | |||
123 | uint16_t ResidencyCounter; | ||
124 | uint8_t UpH; | ||
125 | uint8_t DownH; | ||
126 | |||
127 | uint32_t LclkFrequency; | ||
128 | |||
129 | uint8_t ActivityLevel; | ||
130 | uint8_t EnabledForThrottle; | ||
131 | |||
132 | uint8_t ClkBypassCntl; | ||
133 | |||
134 | uint8_t padding; | ||
135 | }; | ||
136 | |||
137 | typedef struct SMU7_Fusion_GIOLevel SMU7_Fusion_GIOLevel; | ||
138 | |||
139 | // UVD VCLK/DCLK state (level) definition. | ||
140 | struct SMU7_Fusion_UvdLevel | ||
141 | { | ||
142 | uint32_t VclkFrequency; | ||
143 | uint32_t DclkFrequency; | ||
144 | uint16_t MinVddNb; | ||
145 | uint8_t VclkDivider; | ||
146 | uint8_t DclkDivider; | ||
147 | |||
148 | uint8_t VClkBypassCntl; | ||
149 | uint8_t DClkBypassCntl; | ||
150 | |||
151 | uint8_t padding[2]; | ||
152 | |||
153 | }; | ||
154 | |||
155 | typedef struct SMU7_Fusion_UvdLevel SMU7_Fusion_UvdLevel; | ||
156 | |||
157 | // Clocks for other external blocks (VCE, ACP, SAMU). | ||
158 | struct SMU7_Fusion_ExtClkLevel | ||
159 | { | ||
160 | uint32_t Frequency; | ||
161 | uint16_t MinVoltage; | ||
162 | uint8_t Divider; | ||
163 | uint8_t ClkBypassCntl; | ||
164 | |||
165 | uint32_t Reserved; | ||
166 | }; | ||
167 | typedef struct SMU7_Fusion_ExtClkLevel SMU7_Fusion_ExtClkLevel; | ||
168 | |||
169 | struct SMU7_Fusion_ACPILevel | ||
170 | { | ||
171 | uint32_t Flags; | ||
172 | uint32_t MinVddNb; | ||
173 | uint32_t SclkFrequency; | ||
174 | uint8_t SclkDid; | ||
175 | uint8_t GnbSlow; | ||
176 | uint8_t ForceNbPs1; | ||
177 | uint8_t DisplayWatermark; | ||
178 | uint8_t DeepSleepDivId; | ||
179 | uint8_t padding[3]; | ||
180 | }; | ||
181 | |||
182 | typedef struct SMU7_Fusion_ACPILevel SMU7_Fusion_ACPILevel; | ||
183 | |||
184 | struct SMU7_Fusion_NbDpm | ||
185 | { | ||
186 | uint8_t DpmXNbPsHi; | ||
187 | uint8_t DpmXNbPsLo; | ||
188 | uint8_t Dpm0PgNbPsHi; | ||
189 | uint8_t Dpm0PgNbPsLo; | ||
190 | uint8_t EnablePsi1; | ||
191 | uint8_t SkipDPM0; | ||
192 | uint8_t SkipPG; | ||
193 | uint8_t Hysteresis; | ||
194 | uint8_t EnableDpmPstatePoll; | ||
195 | uint8_t padding[3]; | ||
196 | }; | ||
197 | |||
198 | typedef struct SMU7_Fusion_NbDpm SMU7_Fusion_NbDpm; | ||
199 | |||
200 | struct SMU7_Fusion_StateInfo | ||
201 | { | ||
202 | uint32_t SclkFrequency; | ||
203 | uint32_t LclkFrequency; | ||
204 | uint32_t VclkFrequency; | ||
205 | uint32_t DclkFrequency; | ||
206 | uint32_t SamclkFrequency; | ||
207 | uint32_t AclkFrequency; | ||
208 | uint32_t EclkFrequency; | ||
209 | uint8_t DisplayWatermark; | ||
210 | uint8_t McArbIndex; | ||
211 | int8_t SclkIndex; | ||
212 | int8_t MclkIndex; | ||
213 | }; | ||
214 | |||
215 | typedef struct SMU7_Fusion_StateInfo SMU7_Fusion_StateInfo; | ||
216 | |||
217 | struct SMU7_Fusion_DpmTable | ||
218 | { | ||
219 | uint32_t SystemFlags; | ||
220 | |||
221 | SMU7_PIDController GraphicsPIDController; | ||
222 | SMU7_PIDController GioPIDController; | ||
223 | |||
224 | uint8_t GraphicsDpmLevelCount; | ||
225 | uint8_t GIOLevelCount; | ||
226 | uint8_t UvdLevelCount; | ||
227 | uint8_t VceLevelCount; | ||
228 | |||
229 | uint8_t AcpLevelCount; | ||
230 | uint8_t SamuLevelCount; | ||
231 | uint16_t FpsHighT; | ||
232 | |||
233 | SMU7_Fusion_GraphicsLevel GraphicsLevel [SMU__NUM_SCLK_DPM_STATE]; | ||
234 | SMU7_Fusion_ACPILevel ACPILevel; | ||
235 | SMU7_Fusion_UvdLevel UvdLevel [SMU7_MAX_LEVELS_UVD]; | ||
236 | SMU7_Fusion_ExtClkLevel VceLevel [SMU7_MAX_LEVELS_VCE]; | ||
237 | SMU7_Fusion_ExtClkLevel AcpLevel [SMU7_MAX_LEVELS_ACP]; | ||
238 | SMU7_Fusion_ExtClkLevel SamuLevel [SMU7_MAX_LEVELS_SAMU]; | ||
239 | |||
240 | uint8_t UvdBootLevel; | ||
241 | uint8_t VceBootLevel; | ||
242 | uint8_t AcpBootLevel; | ||
243 | uint8_t SamuBootLevel; | ||
244 | uint8_t UVDInterval; | ||
245 | uint8_t VCEInterval; | ||
246 | uint8_t ACPInterval; | ||
247 | uint8_t SAMUInterval; | ||
248 | |||
249 | uint8_t GraphicsBootLevel; | ||
250 | uint8_t GraphicsInterval; | ||
251 | uint8_t GraphicsThermThrottleEnable; | ||
252 | uint8_t GraphicsVoltageChangeEnable; | ||
253 | |||
254 | uint8_t GraphicsClkSlowEnable; | ||
255 | uint8_t GraphicsClkSlowDivider; | ||
256 | uint16_t FpsLowT; | ||
257 | |||
258 | uint32_t DisplayCac; | ||
259 | uint32_t LowSclkInterruptT; | ||
260 | |||
261 | uint32_t DRAM_LOG_ADDR_H; | ||
262 | uint32_t DRAM_LOG_ADDR_L; | ||
263 | uint32_t DRAM_LOG_PHY_ADDR_H; | ||
264 | uint32_t DRAM_LOG_PHY_ADDR_L; | ||
265 | uint32_t DRAM_LOG_BUFF_SIZE; | ||
266 | |||
267 | }; | ||
268 | |||
269 | struct SMU7_Fusion_GIODpmTable | ||
270 | { | ||
271 | |||
272 | SMU7_Fusion_GIOLevel GIOLevel [SMU7_MAX_LEVELS_GIO]; | ||
273 | |||
274 | SMU7_PIDController GioPIDController; | ||
275 | |||
276 | uint32_t GIOLevelCount; | ||
277 | |||
278 | uint8_t Enable; | ||
279 | uint8_t GIOVoltageChangeEnable; | ||
280 | uint8_t GIOBootLevel; | ||
281 | uint8_t padding; | ||
282 | uint8_t padding1[2]; | ||
283 | uint8_t TargetState; | ||
284 | uint8_t CurrenttState; | ||
285 | uint8_t ThrottleOnHtc; | ||
286 | uint8_t ThermThrottleStatus; | ||
287 | uint8_t ThermThrottleTempSelect; | ||
288 | uint8_t ThermThrottleEnable; | ||
289 | uint16_t TemperatureLimitHigh; | ||
290 | uint16_t TemperatureLimitLow; | ||
291 | |||
292 | }; | ||
293 | |||
294 | typedef struct SMU7_Fusion_DpmTable SMU7_Fusion_DpmTable; | ||
295 | typedef struct SMU7_Fusion_GIODpmTable SMU7_Fusion_GIODpmTable; | ||
296 | |||
297 | #pragma pack(pop) | ||
298 | |||
299 | #endif | ||
300 | |||