aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c134
1 files changed, 22 insertions, 112 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
index bab8fab118d6..b5b66c3d1b43 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -116,136 +116,47 @@ static int acp_sw_fini(void *handle)
116 return 0; 116 return 0;
117} 117}
118 118
119/* power off a tile/block within ACP */
120static int acp_suspend_tile(void *cgs_dev, int tile)
121{
122 u32 val = 0;
123 u32 count = 0;
124
125 if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
126 pr_err("Invalid ACP tile : %d to suspend\n", tile);
127 return -1;
128 }
129
130 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile);
131 val &= ACP_TILE_ON_MASK;
132
133 if (val == 0x0) {
134 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG);
135 val = val | (1 << tile);
136 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val);
137 cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG,
138 0x500 + tile);
139
140 count = ACP_TIMEOUT_LOOP;
141 while (true) {
142 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0
143 + tile);
144 val = val & ACP_TILE_ON_MASK;
145 if (val == ACP_TILE_OFF_MASK)
146 break;
147 if (--count == 0) {
148 pr_err("Timeout reading ACP PGFSM status\n");
149 return -ETIMEDOUT;
150 }
151 udelay(100);
152 }
153
154 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG);
155
156 val |= ACP_TILE_OFF_RETAIN_REG_MASK;
157 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val);
158 }
159 return 0;
160}
161
162/* power on a tile/block within ACP */
163static int acp_resume_tile(void *cgs_dev, int tile)
164{
165 u32 val = 0;
166 u32 count = 0;
167
168 if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
169 pr_err("Invalid ACP tile to resume\n");
170 return -1;
171 }
172
173 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile);
174 val = val & ACP_TILE_ON_MASK;
175
176 if (val != 0x0) {
177 cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG,
178 0x600 + tile);
179 count = ACP_TIMEOUT_LOOP;
180 while (true) {
181 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0
182 + tile);
183 val = val & ACP_TILE_ON_MASK;
184 if (val == 0x0)
185 break;
186 if (--count == 0) {
187 pr_err("Timeout reading ACP PGFSM status\n");
188 return -ETIMEDOUT;
189 }
190 udelay(100);
191 }
192 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG);
193 if (tile == ACP_TILE_P1)
194 val = val & (ACP_TILE_P1_MASK);
195 else if (tile == ACP_TILE_P2)
196 val = val & (ACP_TILE_P2_MASK);
197
198 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val);
199 }
200 return 0;
201}
202
203struct acp_pm_domain { 119struct acp_pm_domain {
204 void *cgs_dev; 120 void *adev;
205 struct generic_pm_domain gpd; 121 struct generic_pm_domain gpd;
206}; 122};
207 123
208static int acp_poweroff(struct generic_pm_domain *genpd) 124static int acp_poweroff(struct generic_pm_domain *genpd)
209{ 125{
210 int i, ret;
211 struct acp_pm_domain *apd; 126 struct acp_pm_domain *apd;
127 struct amdgpu_device *adev;
212 128
213 apd = container_of(genpd, struct acp_pm_domain, gpd); 129 apd = container_of(genpd, struct acp_pm_domain, gpd);
214 if (apd != NULL) { 130 if (apd != NULL) {
215 /* Donot return abruptly if any of power tile fails to suspend. 131 adev = apd->adev;
216 * Log it and continue powering off other tile 132 /* call smu to POWER GATE ACP block
217 */ 133 * smu will
218 for (i = 4; i >= 0 ; i--) { 134 * 1. turn off the acp clock
219 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); 135 * 2. power off the acp tiles
220 if (ret) 136 * 3. check and enter ulv state
221 pr_err("ACP tile %d tile suspend failed\n", i); 137 */
222 } 138 if (adev->powerplay.pp_funcs->set_powergating_by_smu)
139 amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
223 } 140 }
224 return 0; 141 return 0;
225} 142}
226 143
227static int acp_poweron(struct generic_pm_domain *genpd) 144static int acp_poweron(struct generic_pm_domain *genpd)
228{ 145{
229 int i, ret;
230 struct acp_pm_domain *apd; 146 struct acp_pm_domain *apd;
147 struct amdgpu_device *adev;
231 148
232 apd = container_of(genpd, struct acp_pm_domain, gpd); 149 apd = container_of(genpd, struct acp_pm_domain, gpd);
233 if (apd != NULL) { 150 if (apd != NULL) {
234 for (i = 0; i < 2; i++) { 151 adev = apd->adev;
235 ret = acp_resume_tile(apd->cgs_dev, ACP_TILE_P1 + i); 152 /* call smu to UNGATE ACP block
236 if (ret) { 153 * smu will
237 pr_err("ACP tile %d resume failed\n", i); 154 * 1. exit ulv
238 break; 155 * 2. turn on acp clock
239 } 156 * 3. power on acp tiles
240 } 157 */
241 158 if (adev->powerplay.pp_funcs->set_powergating_by_smu)
242 /* Disable DSPs which are not going to be used */ 159 amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
243 for (i = 0; i < 3; i++) {
244 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_DSP0 + i);
245 /* Continue suspending other DSP, even if one fails */
246 if (ret)
247 pr_err("ACP DSP %d suspend failed\n", i);
248 }
249 } 160 }
250 return 0; 161 return 0;
251} 162}
@@ -311,7 +222,7 @@ static int acp_hw_init(void *handle)
311 adev->acp.acp_genpd->gpd.power_on = acp_poweron; 222 adev->acp.acp_genpd->gpd.power_on = acp_poweron;
312 223
313 224
314 adev->acp.acp_genpd->cgs_dev = adev->acp.cgs_device; 225 adev->acp.acp_genpd->adev = adev;
315 226
316 pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false); 227 pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false);
317 228
@@ -430,7 +341,6 @@ static int acp_hw_init(void *handle)
430 if (r) 341 if (r)
431 return r; 342 return r;
432 343
433
434 for (i = 0; i < ACP_DEVS ; i++) { 344 for (i = 0; i < ACP_DEVS ; i++) {
435 dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); 345 dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i);
436 r = pm_genpd_add_device(&adev->acp.acp_genpd->gpd, dev); 346 r = pm_genpd_add_device(&adev->acp.acp_genpd->gpd, dev);