Line data Source code
1 : /*
2 : * Copyright 2012 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 <dev/pci/drm/drmP.h>
25 : #include "radeon.h"
26 : #include "sumod.h"
27 : #include "sumo_dpm.h"
28 : #include "ppsmc.h"
29 :
30 : #define SUMO_SMU_SERVICE_ROUTINE_PG_INIT 1
31 : #define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY 27
32 : #define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20 20
33 :
34 : struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
35 :
36 0 : static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
37 : {
38 : u32 gfx_int_req;
39 : int i;
40 :
41 0 : for (i = 0; i < rdev->usec_timeout; i++) {
42 0 : if (RREG32(GFX_INT_STATUS) & INT_DONE)
43 : break;
44 0 : udelay(1);
45 : }
46 :
47 0 : gfx_int_req = SERV_INDEX(id) | INT_REQ;
48 0 : WREG32(GFX_INT_REQ, gfx_int_req);
49 :
50 0 : for (i = 0; i < rdev->usec_timeout; i++) {
51 0 : if (RREG32(GFX_INT_REQ) & INT_REQ)
52 : break;
53 0 : udelay(1);
54 : }
55 :
56 0 : for (i = 0; i < rdev->usec_timeout; i++) {
57 0 : if (RREG32(GFX_INT_STATUS) & INT_ACK)
58 : break;
59 0 : udelay(1);
60 : }
61 :
62 0 : for (i = 0; i < rdev->usec_timeout; i++) {
63 0 : if (RREG32(GFX_INT_STATUS) & INT_DONE)
64 : break;
65 0 : udelay(1);
66 : }
67 :
68 : gfx_int_req &= ~INT_REQ;
69 0 : WREG32(GFX_INT_REQ, gfx_int_req);
70 0 : }
71 :
72 0 : void sumo_initialize_m3_arb(struct radeon_device *rdev)
73 : {
74 0 : struct sumo_power_info *pi = sumo_get_pi(rdev);
75 : u32 i;
76 :
77 0 : if (!pi->enable_dynamic_m3_arbiter)
78 0 : return;
79 :
80 0 : for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
81 0 : WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
82 : pi->sys_info.csr_m3_arb_cntl_default[i]);
83 :
84 0 : for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
85 0 : WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
86 : pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
87 :
88 0 : for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
89 0 : WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
90 : pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
91 0 : }
92 :
93 0 : static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
94 : {
95 0 : struct sumo_power_info *pi = sumo_get_pi(rdev);
96 : bool return_code = false;
97 :
98 0 : if (!pi->enable_alt_vddnb)
99 0 : return return_code;
100 :
101 0 : if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
102 0 : if (pi->fw_version >= 0x00010C00)
103 0 : return_code = true;
104 : }
105 :
106 0 : return return_code;
107 0 : }
108 :
109 0 : void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
110 : bool powersaving, bool force_nbps1)
111 : {
112 : u32 param = 0;
113 :
114 0 : if (!sumo_is_alt_vddnb_supported(rdev))
115 0 : return;
116 :
117 0 : if (powersaving)
118 0 : param |= 1;
119 :
120 0 : if (force_nbps1)
121 0 : param |= 2;
122 :
123 0 : WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
124 :
125 0 : sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
126 0 : }
127 :
128 0 : void sumo_smu_pg_init(struct radeon_device *rdev)
129 : {
130 0 : sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
131 0 : }
132 :
133 0 : static u32 sumo_power_of_4(u32 unit)
134 : {
135 : u32 ret = 1;
136 : u32 i;
137 :
138 0 : for (i = 0; i < unit; i++)
139 0 : ret *= 4;
140 :
141 0 : return ret;
142 : }
143 :
144 0 : void sumo_enable_boost_timer(struct radeon_device *rdev)
145 : {
146 0 : struct sumo_power_info *pi = sumo_get_pi(rdev);
147 : u32 period, unit, timer_value;
148 0 : u32 xclk = radeon_get_xclk(rdev);
149 :
150 0 : unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
151 0 : >> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
152 :
153 0 : period = 100 * (xclk / 100 / sumo_power_of_4(unit));
154 :
155 0 : timer_value = (period << 16) | (unit << 4);
156 :
157 0 : WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
158 0 : WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
159 0 : WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
160 0 : WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
161 0 : WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
162 :
163 0 : sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
164 0 : }
165 :
166 0 : void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
167 : {
168 : u32 regoffset = 0;
169 : u32 shift = 0;
170 : u32 mask = 0xFFF;
171 : u32 sclk_dpm_tdp_limit;
172 :
173 0 : switch (index) {
174 : case 0:
175 : regoffset = RCU_SclkDpmTdpLimit01;
176 : shift = 16;
177 0 : break;
178 : case 1:
179 : regoffset = RCU_SclkDpmTdpLimit01;
180 : shift = 0;
181 0 : break;
182 : case 2:
183 : regoffset = RCU_SclkDpmTdpLimit23;
184 : shift = 16;
185 0 : break;
186 : case 3:
187 : regoffset = RCU_SclkDpmTdpLimit23;
188 : shift = 0;
189 0 : break;
190 : case 4:
191 : regoffset = RCU_SclkDpmTdpLimit47;
192 : shift = 16;
193 0 : break;
194 : case 7:
195 : regoffset = RCU_SclkDpmTdpLimit47;
196 : shift = 0;
197 0 : break;
198 : default:
199 : break;
200 : }
201 :
202 0 : sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
203 0 : sclk_dpm_tdp_limit &= ~(mask << shift);
204 0 : sclk_dpm_tdp_limit |= (tdp_limit << shift);
205 0 : WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
206 0 : }
207 :
208 0 : void sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
209 : {
210 0 : u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
211 :
212 0 : boost_disable &= 0xFFFFFFFE;
213 0 : boost_disable |= (enable ? 0 : 1);
214 0 : WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
215 0 : }
216 :
217 0 : u32 sumo_get_running_fw_version(struct radeon_device *rdev)
218 : {
219 0 : return RREG32_RCU(RCU_FW_VERSION);
220 : }
221 :
|