Commit | Line | Data |
---|---|---|
aaa36a97 AD |
1 | /* |
2 | * Copyright 2014 Advanced Micro Devices, Inc. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining a | |
6 | * copy of this software and associated documentation files (the | |
7 | * "Software"), to deal in the Software without restriction, including | |
8 | * without limitation the rights to use, copy, modify, merge, publish, | |
9 | * distribute, sub license, and/or sell copies of the Software, and to | |
10 | * permit persons to whom the Software is furnished to do so, subject to | |
11 | * the following conditions: | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | |
16 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | |
17 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
19 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | |
20 | * | |
21 | * The above copyright notice and this permission notice (including the | |
22 | * next paragraph) shall be included in all copies or substantial portions | |
23 | * of the Software. | |
24 | * | |
25 | * Authors: Christian König <christian.koenig@amd.com> | |
26 | */ | |
27 | ||
28 | #include <linux/firmware.h> | |
29 | #include <drm/drmP.h> | |
30 | #include "amdgpu.h" | |
31 | #include "amdgpu_vce.h" | |
32 | #include "vid.h" | |
33 | #include "vce/vce_3_0_d.h" | |
34 | #include "vce/vce_3_0_sh_mask.h" | |
be4f38e2 AD |
35 | #include "oss/oss_3_0_d.h" |
36 | #include "oss/oss_3_0_sh_mask.h" | |
5bbc553a | 37 | #include "gca/gfx_8_0_d.h" |
6a585777 AD |
38 | #include "smu/smu_7_1_2_d.h" |
39 | #include "smu/smu_7_1_2_sh_mask.h" | |
115933a5 CZ |
40 | #include "gca/gfx_8_0_d.h" |
41 | #include "gca/gfx_8_0_sh_mask.h" | |
42 | ||
5bbc553a LL |
43 | |
44 | #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 | |
45 | #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 | |
edf600da CK |
46 | #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 |
47 | #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 | |
48 | #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 | |
567e6e29 | 49 | #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 |
aaa36a97 | 50 | |
e9822622 LL |
51 | #define VCE_V3_0_FW_SIZE (384 * 1024) |
52 | #define VCE_V3_0_STACK_SIZE (64 * 1024) | |
53 | #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) | |
54 | ||
5bbc553a | 55 | static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); |
aaa36a97 AD |
56 | static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); |
57 | static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); | |
567e6e29 | 58 | static int vce_v3_0_wait_for_idle(void *handle); |
aaa36a97 AD |
59 | |
60 | /** | |
61 | * vce_v3_0_ring_get_rptr - get read pointer | |
62 | * | |
63 | * @ring: amdgpu_ring pointer | |
64 | * | |
65 | * Returns the current hardware read pointer | |
66 | */ | |
67 | static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) | |
68 | { | |
69 | struct amdgpu_device *adev = ring->adev; | |
70 | ||
71 | if (ring == &adev->vce.ring[0]) | |
72 | return RREG32(mmVCE_RB_RPTR); | |
73 | else | |
74 | return RREG32(mmVCE_RB_RPTR2); | |
75 | } | |
76 | ||
77 | /** | |
78 | * vce_v3_0_ring_get_wptr - get write pointer | |
79 | * | |
80 | * @ring: amdgpu_ring pointer | |
81 | * | |
82 | * Returns the current hardware write pointer | |
83 | */ | |
84 | static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) | |
85 | { | |
86 | struct amdgpu_device *adev = ring->adev; | |
87 | ||
88 | if (ring == &adev->vce.ring[0]) | |
89 | return RREG32(mmVCE_RB_WPTR); | |
90 | else | |
91 | return RREG32(mmVCE_RB_WPTR2); | |
92 | } | |
93 | ||
94 | /** | |
95 | * vce_v3_0_ring_set_wptr - set write pointer | |
96 | * | |
97 | * @ring: amdgpu_ring pointer | |
98 | * | |
99 | * Commits the write pointer to the hardware | |
100 | */ | |
101 | static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) | |
102 | { | |
103 | struct amdgpu_device *adev = ring->adev; | |
104 | ||
105 | if (ring == &adev->vce.ring[0]) | |
106 | WREG32(mmVCE_RB_WPTR, ring->wptr); | |
107 | else | |
108 | WREG32(mmVCE_RB_WPTR2, ring->wptr); | |
109 | } | |
110 | ||
0689a570 EH |
111 | static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) |
112 | { | |
f3f0ea95 | 113 | WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0); |
0689a570 EH |
114 | } |
115 | ||
116 | static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, | |
117 | bool gated) | |
118 | { | |
f3f0ea95 | 119 | u32 data; |
f16fe6d3 | 120 | |
0689a570 EH |
121 | /* Set Override to disable Clock Gating */ |
122 | vce_v3_0_override_vce_clock_gating(adev, true); | |
123 | ||
6f906814 TSD |
124 | /* This function enables MGCG which is controlled by firmware. |
125 | With the clocks in the gated state the core is still | |
126 | accessible but the firmware will throttle the clocks on the | |
127 | fly as necessary. | |
128 | */ | |
129 | if (gated) { | |
f3f0ea95 | 130 | data = RREG32(mmVCE_CLOCK_GATING_B); |
0689a570 EH |
131 | data |= 0x1ff; |
132 | data &= ~0xef0000; | |
f3f0ea95 | 133 | WREG32(mmVCE_CLOCK_GATING_B, data); |
0689a570 | 134 | |
f3f0ea95 | 135 | data = RREG32(mmVCE_UENC_CLOCK_GATING); |
0689a570 EH |
136 | data |= 0x3ff000; |
137 | data &= ~0xffc00000; | |
f3f0ea95 | 138 | WREG32(mmVCE_UENC_CLOCK_GATING, data); |
0689a570 | 139 | |
f3f0ea95 | 140 | data = RREG32(mmVCE_UENC_CLOCK_GATING_2); |
0689a570 | 141 | data |= 0x2; |
6f906814 | 142 | data &= ~0x00010000; |
f3f0ea95 | 143 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); |
0689a570 | 144 | |
f3f0ea95 | 145 | data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); |
0689a570 | 146 | data |= 0x37f; |
f3f0ea95 | 147 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); |
0689a570 | 148 | |
f3f0ea95 | 149 | data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); |
0689a570 | 150 | data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | |
f16fe6d3 TSD |
151 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | |
152 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | | |
153 | 0x8; | |
f3f0ea95 | 154 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); |
0689a570 | 155 | } else { |
f3f0ea95 | 156 | data = RREG32(mmVCE_CLOCK_GATING_B); |
0689a570 EH |
157 | data &= ~0x80010; |
158 | data |= 0xe70008; | |
f3f0ea95 | 159 | WREG32(mmVCE_CLOCK_GATING_B, data); |
6f906814 | 160 | |
f3f0ea95 | 161 | data = RREG32(mmVCE_UENC_CLOCK_GATING); |
0689a570 | 162 | data |= 0xffc00000; |
f3f0ea95 | 163 | WREG32(mmVCE_UENC_CLOCK_GATING, data); |
6f906814 | 164 | |
f3f0ea95 | 165 | data = RREG32(mmVCE_UENC_CLOCK_GATING_2); |
0689a570 | 166 | data |= 0x10000; |
f3f0ea95 | 167 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); |
6f906814 | 168 | |
f3f0ea95 | 169 | data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); |
0689a570 | 170 | data &= ~0xffc00000; |
f3f0ea95 | 171 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); |
6f906814 | 172 | |
f3f0ea95 | 173 | data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); |
0689a570 | 174 | data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | |
f16fe6d3 TSD |
175 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | |
176 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | | |
177 | 0x8); | |
f3f0ea95 | 178 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); |
0689a570 EH |
179 | } |
180 | vce_v3_0_override_vce_clock_gating(adev, false); | |
181 | } | |
182 | ||
567e6e29 | 183 | static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) |
184 | { | |
185 | int i, j; | |
567e6e29 | 186 | |
187 | for (i = 0; i < 10; ++i) { | |
188 | for (j = 0; j < 100; ++j) { | |
b7e2e9f7 | 189 | uint32_t status = RREG32(mmVCE_STATUS); |
190 | ||
567e6e29 | 191 | if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) |
192 | return 0; | |
193 | mdelay(10); | |
194 | } | |
195 | ||
196 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); | |
f3f0ea95 | 197 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); |
567e6e29 | 198 | mdelay(10); |
f3f0ea95 | 199 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); |
567e6e29 | 200 | mdelay(10); |
201 | } | |
202 | ||
203 | return -ETIMEDOUT; | |
204 | } | |
205 | ||
aaa36a97 AD |
206 | /** |
207 | * vce_v3_0_start - start VCE block | |
208 | * | |
209 | * @adev: amdgpu_device pointer | |
210 | * | |
211 | * Setup and start the VCE block | |
212 | */ | |
213 | static int vce_v3_0_start(struct amdgpu_device *adev) | |
214 | { | |
215 | struct amdgpu_ring *ring; | |
567e6e29 | 216 | int idx, r; |
217 | ||
218 | ring = &adev->vce.ring[0]; | |
219 | WREG32(mmVCE_RB_RPTR, ring->wptr); | |
220 | WREG32(mmVCE_RB_WPTR, ring->wptr); | |
221 | WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); | |
222 | WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); | |
223 | WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); | |
224 | ||
225 | ring = &adev->vce.ring[1]; | |
226 | WREG32(mmVCE_RB_RPTR2, ring->wptr); | |
227 | WREG32(mmVCE_RB_WPTR2, ring->wptr); | |
228 | WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); | |
229 | WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); | |
230 | WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); | |
5bbc553a LL |
231 | |
232 | mutex_lock(&adev->grbm_idx_mutex); | |
233 | for (idx = 0; idx < 2; ++idx) { | |
6a585777 AD |
234 | if (adev->vce.harvest_config & (1 << idx)) |
235 | continue; | |
236 | ||
f3f0ea95 | 237 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); |
5bbc553a | 238 | vce_v3_0_mc_resume(adev, idx); |
f3f0ea95 | 239 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); |
567e6e29 | 240 | |
3c0ff9f1 LL |
241 | if (adev->asic_type >= CHIP_STONEY) |
242 | WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); | |
243 | else | |
f3f0ea95 | 244 | WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); |
5bbc553a | 245 | |
f3f0ea95 | 246 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); |
567e6e29 | 247 | mdelay(100); |
248 | ||
249 | r = vce_v3_0_firmware_loaded(adev); | |
5bbc553a LL |
250 | |
251 | /* clear BUSY flag */ | |
f3f0ea95 | 252 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); |
aaa36a97 | 253 | |
5bbc553a LL |
254 | if (r) { |
255 | DRM_ERROR("VCE not responding, giving up!!!\n"); | |
256 | mutex_unlock(&adev->grbm_idx_mutex); | |
257 | return r; | |
258 | } | |
259 | } | |
aaa36a97 | 260 | |
f3f0ea95 | 261 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
5bbc553a | 262 | mutex_unlock(&adev->grbm_idx_mutex); |
aaa36a97 | 263 | |
567e6e29 | 264 | return 0; |
265 | } | |
aaa36a97 | 266 | |
567e6e29 | 267 | static int vce_v3_0_stop(struct amdgpu_device *adev) |
268 | { | |
269 | int idx; | |
270 | ||
271 | mutex_lock(&adev->grbm_idx_mutex); | |
272 | for (idx = 0; idx < 2; ++idx) { | |
273 | if (adev->vce.harvest_config & (1 << idx)) | |
274 | continue; | |
275 | ||
f3f0ea95 | 276 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); |
567e6e29 | 277 | |
278 | if (adev->asic_type >= CHIP_STONEY) | |
279 | WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); | |
280 | else | |
f3f0ea95 TSD |
281 | WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0); |
282 | ||
567e6e29 | 283 | /* hold on ECPU */ |
f3f0ea95 | 284 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); |
567e6e29 | 285 | |
286 | /* clear BUSY flag */ | |
f3f0ea95 | 287 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); |
567e6e29 | 288 | |
289 | /* Set Clock-Gating off */ | |
290 | if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) | |
291 | vce_v3_0_set_vce_sw_clock_gating(adev, false); | |
292 | } | |
293 | ||
f3f0ea95 | 294 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
567e6e29 | 295 | mutex_unlock(&adev->grbm_idx_mutex); |
aaa36a97 | 296 | |
aaa36a97 AD |
297 | return 0; |
298 | } | |
299 | ||
6a585777 AD |
300 | #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 |
301 | #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 | |
302 | #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 | |
303 | ||
304 | static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) | |
305 | { | |
306 | u32 tmp; | |
6a585777 | 307 | |
2cc0c0b5 | 308 | /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ |
cfaba566 | 309 | if ((adev->asic_type == CHIP_FIJI) || |
1b4eeea5 | 310 | (adev->asic_type == CHIP_STONEY) || |
2cc0c0b5 FC |
311 | (adev->asic_type == CHIP_POLARIS10) || |
312 | (adev->asic_type == CHIP_POLARIS11)) | |
1dab5f06 | 313 | return AMDGPU_VCE_HARVEST_VCE1; |
188a9bcd AD |
314 | |
315 | /* Tonga and CZ are dual or single pipe */ | |
2f7d10b3 | 316 | if (adev->flags & AMD_IS_APU) |
6a585777 AD |
317 | tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & |
318 | VCE_HARVEST_FUSE_MACRO__MASK) >> | |
319 | VCE_HARVEST_FUSE_MACRO__SHIFT; | |
320 | else | |
321 | tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & | |
322 | CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> | |
323 | CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; | |
324 | ||
325 | switch (tmp) { | |
326 | case 1: | |
1dab5f06 | 327 | return AMDGPU_VCE_HARVEST_VCE0; |
6a585777 | 328 | case 2: |
1dab5f06 | 329 | return AMDGPU_VCE_HARVEST_VCE1; |
6a585777 | 330 | case 3: |
1dab5f06 | 331 | return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; |
6a585777 | 332 | default: |
1dab5f06 | 333 | return 0; |
6a585777 | 334 | } |
6a585777 AD |
335 | } |
336 | ||
5fc3aeeb | 337 | static int vce_v3_0_early_init(void *handle) |
aaa36a97 | 338 | { |
5fc3aeeb | 339 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
340 | ||
6a585777 AD |
341 | adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); |
342 | ||
343 | if ((adev->vce.harvest_config & | |
344 | (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == | |
345 | (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) | |
346 | return -ENOENT; | |
347 | ||
aaa36a97 AD |
348 | vce_v3_0_set_ring_funcs(adev); |
349 | vce_v3_0_set_irq_funcs(adev); | |
350 | ||
351 | return 0; | |
352 | } | |
353 | ||
5fc3aeeb | 354 | static int vce_v3_0_sw_init(void *handle) |
aaa36a97 | 355 | { |
5fc3aeeb | 356 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
aaa36a97 AD |
357 | struct amdgpu_ring *ring; |
358 | int r; | |
359 | ||
360 | /* VCE */ | |
361 | r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); | |
362 | if (r) | |
363 | return r; | |
364 | ||
e9822622 LL |
365 | r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + |
366 | (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); | |
aaa36a97 AD |
367 | if (r) |
368 | return r; | |
369 | ||
370 | r = amdgpu_vce_resume(adev); | |
371 | if (r) | |
372 | return r; | |
373 | ||
374 | ring = &adev->vce.ring[0]; | |
375 | sprintf(ring->name, "vce0"); | |
a3f1cf35 | 376 | r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, |
aaa36a97 AD |
377 | &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); |
378 | if (r) | |
379 | return r; | |
380 | ||
381 | ring = &adev->vce.ring[1]; | |
382 | sprintf(ring->name, "vce1"); | |
a3f1cf35 | 383 | r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, |
aaa36a97 AD |
384 | &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); |
385 | if (r) | |
386 | return r; | |
387 | ||
388 | return r; | |
389 | } | |
390 | ||
5fc3aeeb | 391 | static int vce_v3_0_sw_fini(void *handle) |
aaa36a97 AD |
392 | { |
393 | int r; | |
5fc3aeeb | 394 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
aaa36a97 AD |
395 | |
396 | r = amdgpu_vce_suspend(adev); | |
397 | if (r) | |
398 | return r; | |
399 | ||
400 | r = amdgpu_vce_sw_fini(adev); | |
401 | if (r) | |
402 | return r; | |
403 | ||
404 | return r; | |
405 | } | |
406 | ||
5fc3aeeb | 407 | static int vce_v3_0_hw_init(void *handle) |
aaa36a97 | 408 | { |
691ca86a | 409 | int r, i; |
5fc3aeeb | 410 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
aaa36a97 AD |
411 | |
412 | r = vce_v3_0_start(adev); | |
413 | if (r) | |
414 | return r; | |
415 | ||
691ca86a TSD |
416 | adev->vce.ring[0].ready = false; |
417 | adev->vce.ring[1].ready = false; | |
aaa36a97 | 418 | |
691ca86a TSD |
419 | for (i = 0; i < 2; i++) { |
420 | r = amdgpu_ring_test_ring(&adev->vce.ring[i]); | |
421 | if (r) | |
422 | return r; | |
423 | else | |
424 | adev->vce.ring[i].ready = true; | |
aaa36a97 AD |
425 | } |
426 | ||
427 | DRM_INFO("VCE initialized successfully.\n"); | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
5fc3aeeb | 432 | static int vce_v3_0_hw_fini(void *handle) |
aaa36a97 | 433 | { |
567e6e29 | 434 | int r; |
435 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | |
436 | ||
437 | r = vce_v3_0_wait_for_idle(handle); | |
438 | if (r) | |
439 | return r; | |
440 | ||
441 | return vce_v3_0_stop(adev); | |
aaa36a97 AD |
442 | } |
443 | ||
5fc3aeeb | 444 | static int vce_v3_0_suspend(void *handle) |
aaa36a97 AD |
445 | { |
446 | int r; | |
5fc3aeeb | 447 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
aaa36a97 AD |
448 | |
449 | r = vce_v3_0_hw_fini(adev); | |
450 | if (r) | |
451 | return r; | |
452 | ||
453 | r = amdgpu_vce_suspend(adev); | |
454 | if (r) | |
455 | return r; | |
456 | ||
457 | return r; | |
458 | } | |
459 | ||
5fc3aeeb | 460 | static int vce_v3_0_resume(void *handle) |
aaa36a97 AD |
461 | { |
462 | int r; | |
5fc3aeeb | 463 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
aaa36a97 AD |
464 | |
465 | r = amdgpu_vce_resume(adev); | |
466 | if (r) | |
467 | return r; | |
468 | ||
469 | r = vce_v3_0_hw_init(adev); | |
470 | if (r) | |
471 | return r; | |
472 | ||
473 | return r; | |
474 | } | |
475 | ||
5bbc553a | 476 | static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) |
aaa36a97 AD |
477 | { |
478 | uint32_t offset, size; | |
479 | ||
480 | WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); | |
481 | WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); | |
482 | WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); | |
6f906814 | 483 | WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); |
aaa36a97 AD |
484 | |
485 | WREG32(mmVCE_LMI_CTRL, 0x00398000); | |
486 | WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); | |
487 | WREG32(mmVCE_LMI_SWAP_CNTL, 0); | |
488 | WREG32(mmVCE_LMI_SWAP_CNTL1, 0); | |
489 | WREG32(mmVCE_LMI_VM_CTRL, 0); | |
3c0ff9f1 LL |
490 | if (adev->asic_type >= CHIP_STONEY) { |
491 | WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); | |
492 | WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); | |
493 | WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); | |
494 | } else | |
495 | WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); | |
aaa36a97 | 496 | offset = AMDGPU_VCE_FIRMWARE_OFFSET; |
e9822622 | 497 | size = VCE_V3_0_FW_SIZE; |
aaa36a97 AD |
498 | WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); |
499 | WREG32(mmVCE_VCPU_CACHE_SIZE0, size); | |
500 | ||
5bbc553a LL |
501 | if (idx == 0) { |
502 | offset += size; | |
503 | size = VCE_V3_0_STACK_SIZE; | |
504 | WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); | |
505 | WREG32(mmVCE_VCPU_CACHE_SIZE1, size); | |
506 | offset += size; | |
507 | size = VCE_V3_0_DATA_SIZE; | |
508 | WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); | |
509 | WREG32(mmVCE_VCPU_CACHE_SIZE2, size); | |
510 | } else { | |
511 | offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; | |
512 | size = VCE_V3_0_STACK_SIZE; | |
513 | WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); | |
514 | WREG32(mmVCE_VCPU_CACHE_SIZE1, size); | |
515 | offset += size; | |
516 | size = VCE_V3_0_DATA_SIZE; | |
517 | WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); | |
518 | WREG32(mmVCE_VCPU_CACHE_SIZE2, size); | |
519 | } | |
aaa36a97 AD |
520 | |
521 | WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); | |
f3f0ea95 | 522 | WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); |
aaa36a97 AD |
523 | } |
524 | ||
5fc3aeeb | 525 | static bool vce_v3_0_is_idle(void *handle) |
aaa36a97 | 526 | { |
5fc3aeeb | 527 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
be4f38e2 | 528 | u32 mask = 0; |
be4f38e2 | 529 | |
74af1276 TSD |
530 | mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; |
531 | mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; | |
be4f38e2 AD |
532 | |
533 | return !(RREG32(mmSRBM_STATUS2) & mask); | |
aaa36a97 AD |
534 | } |
535 | ||
5fc3aeeb | 536 | static int vce_v3_0_wait_for_idle(void *handle) |
aaa36a97 AD |
537 | { |
538 | unsigned i; | |
5fc3aeeb | 539 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
be4f38e2 | 540 | |
92988e60 TSD |
541 | for (i = 0; i < adev->usec_timeout; i++) |
542 | if (vce_v3_0_is_idle(handle)) | |
aaa36a97 | 543 | return 0; |
92988e60 | 544 | |
aaa36a97 AD |
545 | return -ETIMEDOUT; |
546 | } | |
547 | ||
ac8e3f30 RZ |
548 | #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ |
549 | #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ | |
550 | #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ | |
551 | #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ | |
552 | VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) | |
115933a5 CZ |
553 | |
554 | static int vce_v3_0_check_soft_reset(void *handle) | |
555 | { | |
556 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | |
557 | u32 srbm_soft_reset = 0; | |
115933a5 | 558 | |
115933a5 CZ |
559 | /* According to VCE team , we should use VCE_STATUS instead |
560 | * SRBM_STATUS.VCE_BUSY bit for busy status checking. | |
561 | * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE | |
562 | * instance's registers are accessed | |
563 | * (0 for 1st instance, 10 for 2nd instance). | |
564 | * | |
565 | *VCE_STATUS | |
566 | *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | | |
567 | *|----+----+-----------+----+----+----+----------+---------+----| | |
568 | *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| | |
569 | * | |
570 | * VCE team suggest use bit 3--bit 6 for busy status check | |
571 | */ | |
9aeb774c | 572 | mutex_lock(&adev->grbm_idx_mutex); |
f3f0ea95 | 573 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); |
115933a5 CZ |
574 | if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { |
575 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); | |
576 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); | |
577 | } | |
f3f0ea95 | 578 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); |
115933a5 CZ |
579 | if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { |
580 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); | |
581 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); | |
582 | } | |
f3f0ea95 | 583 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); |
115933a5 | 584 | |
115933a5 CZ |
585 | if (srbm_soft_reset) { |
586 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; | |
587 | adev->vce.srbm_soft_reset = srbm_soft_reset; | |
588 | } else { | |
589 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; | |
590 | adev->vce.srbm_soft_reset = 0; | |
591 | } | |
9aeb774c | 592 | mutex_unlock(&adev->grbm_idx_mutex); |
115933a5 CZ |
593 | return 0; |
594 | } | |
595 | ||
5fc3aeeb | 596 | static int vce_v3_0_soft_reset(void *handle) |
aaa36a97 | 597 | { |
5fc3aeeb | 598 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
115933a5 CZ |
599 | u32 srbm_soft_reset; |
600 | ||
601 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | |
602 | return 0; | |
603 | srbm_soft_reset = adev->vce.srbm_soft_reset; | |
604 | ||
605 | if (srbm_soft_reset) { | |
606 | u32 tmp; | |
be4f38e2 | 607 | |
115933a5 CZ |
608 | tmp = RREG32(mmSRBM_SOFT_RESET); |
609 | tmp |= srbm_soft_reset; | |
610 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | |
611 | WREG32(mmSRBM_SOFT_RESET, tmp); | |
612 | tmp = RREG32(mmSRBM_SOFT_RESET); | |
613 | ||
614 | udelay(50); | |
615 | ||
616 | tmp &= ~srbm_soft_reset; | |
617 | WREG32(mmSRBM_SOFT_RESET, tmp); | |
618 | tmp = RREG32(mmSRBM_SOFT_RESET); | |
619 | ||
620 | /* Wait a little for things to settle down */ | |
621 | udelay(50); | |
622 | } | |
623 | ||
624 | return 0; | |
625 | } | |
626 | ||
627 | static int vce_v3_0_pre_soft_reset(void *handle) | |
628 | { | |
629 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | |
630 | ||
631 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | |
632 | return 0; | |
633 | ||
634 | mdelay(5); | |
635 | ||
636 | return vce_v3_0_suspend(adev); | |
637 | } | |
638 | ||
639 | ||
640 | static int vce_v3_0_post_soft_reset(void *handle) | |
641 | { | |
642 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | |
643 | ||
644 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | |
645 | return 0; | |
5fc3aeeb | 646 | |
aaa36a97 AD |
647 | mdelay(5); |
648 | ||
115933a5 | 649 | return vce_v3_0_resume(adev); |
aaa36a97 AD |
650 | } |
651 | ||
aaa36a97 AD |
652 | static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, |
653 | struct amdgpu_irq_src *source, | |
654 | unsigned type, | |
655 | enum amdgpu_interrupt_state state) | |
656 | { | |
657 | uint32_t val = 0; | |
658 | ||
659 | if (state == AMDGPU_IRQ_STATE_ENABLE) | |
660 | val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; | |
661 | ||
662 | WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); | |
663 | return 0; | |
664 | } | |
665 | ||
666 | static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, | |
667 | struct amdgpu_irq_src *source, | |
668 | struct amdgpu_iv_entry *entry) | |
669 | { | |
670 | DRM_DEBUG("IH: VCE\n"); | |
d6c29c30 | 671 | |
f3f0ea95 | 672 | WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); |
d6c29c30 | 673 | |
aaa36a97 AD |
674 | switch (entry->src_data) { |
675 | case 0: | |
aaa36a97 | 676 | case 1: |
81da2ede | 677 | amdgpu_fence_process(&adev->vce.ring[entry->src_data]); |
aaa36a97 AD |
678 | break; |
679 | default: | |
680 | DRM_ERROR("Unhandled interrupt: %d %d\n", | |
681 | entry->src_id, entry->src_data); | |
682 | break; | |
683 | } | |
684 | ||
685 | return 0; | |
686 | } | |
687 | ||
ec38f188 RZ |
688 | static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) |
689 | { | |
690 | u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); | |
691 | ||
692 | if (enable) | |
693 | tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; | |
694 | else | |
695 | tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; | |
696 | ||
697 | WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); | |
698 | } | |
699 | ||
5fc3aeeb | 700 | static int vce_v3_0_set_clockgating_state(void *handle, |
701 | enum amd_clockgating_state state) | |
aaa36a97 | 702 | { |
0689a570 EH |
703 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
704 | bool enable = (state == AMD_CG_STATE_GATE) ? true : false; | |
705 | int i; | |
706 | ||
ec38f188 RZ |
707 | if (adev->asic_type == CHIP_POLARIS10) |
708 | vce_v3_set_bypass_mode(adev, enable); | |
709 | ||
e3b04bc7 | 710 | if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) |
0689a570 EH |
711 | return 0; |
712 | ||
713 | mutex_lock(&adev->grbm_idx_mutex); | |
714 | for (i = 0; i < 2; i++) { | |
715 | /* Program VCE Instance 0 or 1 if not harvested */ | |
716 | if (adev->vce.harvest_config & (1 << i)) | |
717 | continue; | |
718 | ||
f3f0ea95 | 719 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); |
0689a570 EH |
720 | |
721 | if (enable) { | |
722 | /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ | |
723 | uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); | |
724 | data &= ~(0xf | 0xff0); | |
725 | data |= ((0x0 << 0) | (0x04 << 4)); | |
726 | WREG32(mmVCE_CLOCK_GATING_A, data); | |
727 | ||
728 | /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ | |
729 | data = RREG32(mmVCE_UENC_CLOCK_GATING); | |
730 | data &= ~(0xf | 0xff0); | |
731 | data |= ((0x0 << 0) | (0x04 << 4)); | |
732 | WREG32(mmVCE_UENC_CLOCK_GATING, data); | |
733 | } | |
734 | ||
735 | vce_v3_0_set_vce_sw_clock_gating(adev, enable); | |
736 | } | |
737 | ||
f3f0ea95 | 738 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
0689a570 EH |
739 | mutex_unlock(&adev->grbm_idx_mutex); |
740 | ||
aaa36a97 AD |
741 | return 0; |
742 | } | |
743 | ||
5fc3aeeb | 744 | static int vce_v3_0_set_powergating_state(void *handle, |
745 | enum amd_powergating_state state) | |
aaa36a97 AD |
746 | { |
747 | /* This doesn't actually powergate the VCE block. | |
748 | * That's done in the dpm code via the SMC. This | |
749 | * just re-inits the block as necessary. The actual | |
750 | * gating still happens in the dpm code. We should | |
751 | * revisit this when there is a cleaner line between | |
752 | * the smc and the hw blocks | |
753 | */ | |
5fc3aeeb | 754 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
755 | ||
e3b04bc7 | 756 | if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) |
808a934f AD |
757 | return 0; |
758 | ||
5fc3aeeb | 759 | if (state == AMD_PG_STATE_GATE) |
aaa36a97 AD |
760 | /* XXX do we need a vce_v3_0_stop()? */ |
761 | return 0; | |
762 | else | |
763 | return vce_v3_0_start(adev); | |
764 | } | |
765 | ||
5fc3aeeb | 766 | const struct amd_ip_funcs vce_v3_0_ip_funcs = { |
88a907d6 | 767 | .name = "vce_v3_0", |
aaa36a97 AD |
768 | .early_init = vce_v3_0_early_init, |
769 | .late_init = NULL, | |
770 | .sw_init = vce_v3_0_sw_init, | |
771 | .sw_fini = vce_v3_0_sw_fini, | |
772 | .hw_init = vce_v3_0_hw_init, | |
773 | .hw_fini = vce_v3_0_hw_fini, | |
774 | .suspend = vce_v3_0_suspend, | |
775 | .resume = vce_v3_0_resume, | |
776 | .is_idle = vce_v3_0_is_idle, | |
777 | .wait_for_idle = vce_v3_0_wait_for_idle, | |
115933a5 CZ |
778 | .check_soft_reset = vce_v3_0_check_soft_reset, |
779 | .pre_soft_reset = vce_v3_0_pre_soft_reset, | |
aaa36a97 | 780 | .soft_reset = vce_v3_0_soft_reset, |
115933a5 | 781 | .post_soft_reset = vce_v3_0_post_soft_reset, |
aaa36a97 AD |
782 | .set_clockgating_state = vce_v3_0_set_clockgating_state, |
783 | .set_powergating_state = vce_v3_0_set_powergating_state, | |
784 | }; | |
785 | ||
786 | static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { | |
787 | .get_rptr = vce_v3_0_ring_get_rptr, | |
788 | .get_wptr = vce_v3_0_ring_get_wptr, | |
789 | .set_wptr = vce_v3_0_ring_set_wptr, | |
790 | .parse_cs = amdgpu_vce_ring_parse_cs, | |
791 | .emit_ib = amdgpu_vce_ring_emit_ib, | |
792 | .emit_fence = amdgpu_vce_ring_emit_fence, | |
aaa36a97 AD |
793 | .test_ring = amdgpu_vce_ring_test_ring, |
794 | .test_ib = amdgpu_vce_ring_test_ib, | |
edff0e28 | 795 | .insert_nop = amdgpu_ring_insert_nop, |
9e5d5309 | 796 | .pad_ib = amdgpu_ring_generic_pad_ib, |
ebff485e CK |
797 | .begin_use = amdgpu_vce_ring_begin_use, |
798 | .end_use = amdgpu_vce_ring_end_use, | |
aaa36a97 AD |
799 | }; |
800 | ||
801 | static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) | |
802 | { | |
803 | adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; | |
804 | adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; | |
805 | } | |
806 | ||
807 | static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { | |
808 | .set = vce_v3_0_set_interrupt_state, | |
809 | .process = vce_v3_0_process_interrupt, | |
810 | }; | |
811 | ||
812 | static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) | |
813 | { | |
814 | adev->vce.irq.num_types = 1; | |
815 | adev->vce.irq.funcs = &vce_v3_0_irq_funcs; | |
816 | }; |