Rev 5271 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5271 | Rev 6104 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright 2013 Advanced Micro Devices, Inc. |
2 | * Copyright 2013 Advanced Micro Devices, Inc. |
3 | * |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
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 |
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: |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
12 | * all copies or substantial portions of the Software. |
13 | * |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
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, |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
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 |
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, |
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 |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
21 | * |
22 | * Authors: Christian König |
22 | * Authors: Christian König |
23 | */ |
23 | */ |
- | 24 | ||
24 | 25 | #include |
|
25 | #include |
26 | #include |
26 | #include "radeon.h" |
27 | #include "radeon.h" |
27 | #include "radeon_asic.h" |
28 | #include "radeon_asic.h" |
28 | #include "r600d.h" |
29 | #include "r600d.h" |
29 | 30 | ||
30 | /** |
31 | /** |
31 | * uvd_v1_0_get_rptr - get read pointer |
32 | * uvd_v1_0_get_rptr - get read pointer |
32 | * |
33 | * |
33 | * @rdev: radeon_device pointer |
34 | * @rdev: radeon_device pointer |
34 | * @ring: radeon_ring pointer |
35 | * @ring: radeon_ring pointer |
35 | * |
36 | * |
36 | * Returns the current hardware read pointer |
37 | * Returns the current hardware read pointer |
37 | */ |
38 | */ |
38 | uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev, |
39 | uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev, |
39 | struct radeon_ring *ring) |
40 | struct radeon_ring *ring) |
40 | { |
41 | { |
41 | return RREG32(UVD_RBC_RB_RPTR); |
42 | return RREG32(UVD_RBC_RB_RPTR); |
42 | } |
43 | } |
43 | 44 | ||
44 | /** |
45 | /** |
45 | * uvd_v1_0_get_wptr - get write pointer |
46 | * uvd_v1_0_get_wptr - get write pointer |
46 | * |
47 | * |
47 | * @rdev: radeon_device pointer |
48 | * @rdev: radeon_device pointer |
48 | * @ring: radeon_ring pointer |
49 | * @ring: radeon_ring pointer |
49 | * |
50 | * |
50 | * Returns the current hardware write pointer |
51 | * Returns the current hardware write pointer |
51 | */ |
52 | */ |
52 | uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, |
53 | uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, |
53 | struct radeon_ring *ring) |
54 | struct radeon_ring *ring) |
54 | { |
55 | { |
55 | return RREG32(UVD_RBC_RB_WPTR); |
56 | return RREG32(UVD_RBC_RB_WPTR); |
56 | } |
57 | } |
57 | 58 | ||
58 | /** |
59 | /** |
59 | * uvd_v1_0_set_wptr - set write pointer |
60 | * uvd_v1_0_set_wptr - set write pointer |
60 | * |
61 | * |
61 | * @rdev: radeon_device pointer |
62 | * @rdev: radeon_device pointer |
62 | * @ring: radeon_ring pointer |
63 | * @ring: radeon_ring pointer |
63 | * |
64 | * |
64 | * Commits the write pointer to the hardware |
65 | * Commits the write pointer to the hardware |
65 | */ |
66 | */ |
66 | void uvd_v1_0_set_wptr(struct radeon_device *rdev, |
67 | void uvd_v1_0_set_wptr(struct radeon_device *rdev, |
67 | struct radeon_ring *ring) |
68 | struct radeon_ring *ring) |
68 | { |
69 | { |
69 | WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
70 | WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
70 | } |
71 | } |
71 | 72 | ||
72 | /** |
73 | /** |
73 | * uvd_v1_0_fence_emit - emit an fence & trap command |
74 | * uvd_v1_0_fence_emit - emit an fence & trap command |
74 | * |
75 | * |
75 | * @rdev: radeon_device pointer |
76 | * @rdev: radeon_device pointer |
76 | * @fence: fence to emit |
77 | * @fence: fence to emit |
77 | * |
78 | * |
78 | * Write a fence and a trap command to the ring. |
79 | * Write a fence and a trap command to the ring. |
79 | */ |
80 | */ |
80 | void uvd_v1_0_fence_emit(struct radeon_device *rdev, |
81 | void uvd_v1_0_fence_emit(struct radeon_device *rdev, |
81 | struct radeon_fence *fence) |
82 | struct radeon_fence *fence) |
82 | { |
83 | { |
83 | struct radeon_ring *ring = &rdev->ring[fence->ring]; |
84 | struct radeon_ring *ring = &rdev->ring[fence->ring]; |
84 | uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; |
85 | uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; |
85 | 86 | ||
86 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
87 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
87 | radeon_ring_write(ring, addr & 0xffffffff); |
88 | radeon_ring_write(ring, addr & 0xffffffff); |
88 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
89 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
89 | radeon_ring_write(ring, fence->seq); |
90 | radeon_ring_write(ring, fence->seq); |
90 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
91 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
91 | radeon_ring_write(ring, 0); |
92 | radeon_ring_write(ring, 0); |
92 | 93 | ||
93 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
94 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
94 | radeon_ring_write(ring, 0); |
95 | radeon_ring_write(ring, 0); |
95 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
96 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
96 | radeon_ring_write(ring, 0); |
97 | radeon_ring_write(ring, 0); |
97 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
98 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
98 | radeon_ring_write(ring, 2); |
99 | radeon_ring_write(ring, 2); |
99 | return; |
100 | return; |
100 | } |
101 | } |
101 | 102 | ||
102 | /** |
103 | /** |
103 | * uvd_v1_0_resume - memory controller programming |
104 | * uvd_v1_0_resume - memory controller programming |
104 | * |
105 | * |
105 | * @rdev: radeon_device pointer |
106 | * @rdev: radeon_device pointer |
106 | * |
107 | * |
107 | * Let the UVD memory controller know it's offsets |
108 | * Let the UVD memory controller know it's offsets |
108 | */ |
109 | */ |
109 | int uvd_v1_0_resume(struct radeon_device *rdev) |
110 | int uvd_v1_0_resume(struct radeon_device *rdev) |
110 | { |
111 | { |
111 | uint64_t addr; |
112 | uint64_t addr; |
112 | uint32_t size; |
113 | uint32_t size; |
113 | int r; |
114 | int r; |
114 | 115 | ||
115 | r = radeon_uvd_resume(rdev); |
116 | r = radeon_uvd_resume(rdev); |
116 | if (r) |
117 | if (r) |
117 | return r; |
118 | return r; |
118 | 119 | ||
119 | /* programm the VCPU memory controller bits 0-27 */ |
120 | /* programm the VCPU memory controller bits 0-27 */ |
120 | addr = (rdev->uvd.gpu_addr >> 3) + 16; |
121 | addr = (rdev->uvd.gpu_addr >> 3) + 16; |
121 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3; |
122 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3; |
122 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
123 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
123 | WREG32(UVD_VCPU_CACHE_SIZE0, size); |
124 | WREG32(UVD_VCPU_CACHE_SIZE0, size); |
124 | 125 | ||
125 | addr += size; |
126 | addr += size; |
126 | size = RADEON_UVD_STACK_SIZE >> 3; |
127 | size = RADEON_UVD_STACK_SIZE >> 3; |
127 | WREG32(UVD_VCPU_CACHE_OFFSET1, addr); |
128 | WREG32(UVD_VCPU_CACHE_OFFSET1, addr); |
128 | WREG32(UVD_VCPU_CACHE_SIZE1, size); |
129 | WREG32(UVD_VCPU_CACHE_SIZE1, size); |
129 | 130 | ||
130 | addr += size; |
131 | addr += size; |
131 | size = RADEON_UVD_HEAP_SIZE >> 3; |
132 | size = RADEON_UVD_HEAP_SIZE >> 3; |
132 | WREG32(UVD_VCPU_CACHE_OFFSET2, addr); |
133 | WREG32(UVD_VCPU_CACHE_OFFSET2, addr); |
133 | WREG32(UVD_VCPU_CACHE_SIZE2, size); |
134 | WREG32(UVD_VCPU_CACHE_SIZE2, size); |
134 | 135 | ||
135 | /* bits 28-31 */ |
136 | /* bits 28-31 */ |
136 | addr = (rdev->uvd.gpu_addr >> 28) & 0xF; |
137 | addr = (rdev->uvd.gpu_addr >> 28) & 0xF; |
137 | WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); |
138 | WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); |
138 | 139 | ||
139 | /* bits 32-39 */ |
140 | /* bits 32-39 */ |
140 | addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; |
141 | addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; |
141 | WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); |
142 | WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); |
142 | 143 | ||
143 | WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr)); |
144 | WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr)); |
144 | 145 | ||
145 | return 0; |
146 | return 0; |
146 | } |
147 | } |
147 | 148 | ||
148 | /** |
149 | /** |
149 | * uvd_v1_0_init - start and test UVD block |
150 | * uvd_v1_0_init - start and test UVD block |
150 | * |
151 | * |
151 | * @rdev: radeon_device pointer |
152 | * @rdev: radeon_device pointer |
152 | * |
153 | * |
153 | * Initialize the hardware, boot up the VCPU and do some testing |
154 | * Initialize the hardware, boot up the VCPU and do some testing |
154 | */ |
155 | */ |
155 | int uvd_v1_0_init(struct radeon_device *rdev) |
156 | int uvd_v1_0_init(struct radeon_device *rdev) |
156 | { |
157 | { |
157 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
158 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
158 | uint32_t tmp; |
159 | uint32_t tmp; |
159 | int r; |
160 | int r; |
160 | 161 | ||
161 | /* raise clocks while booting up the VCPU */ |
162 | /* raise clocks while booting up the VCPU */ |
162 | if (rdev->family < CHIP_RV740) |
163 | if (rdev->family < CHIP_RV740) |
163 | radeon_set_uvd_clocks(rdev, 10000, 10000); |
164 | radeon_set_uvd_clocks(rdev, 10000, 10000); |
164 | else |
165 | else |
165 | radeon_set_uvd_clocks(rdev, 53300, 40000); |
166 | radeon_set_uvd_clocks(rdev, 53300, 40000); |
166 | 167 | ||
167 | r = uvd_v1_0_start(rdev); |
168 | r = uvd_v1_0_start(rdev); |
168 | if (r) |
169 | if (r) |
169 | goto done; |
170 | goto done; |
170 | 171 | ||
171 | ring->ready = true; |
172 | ring->ready = true; |
172 | r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); |
173 | r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); |
173 | if (r) { |
174 | if (r) { |
174 | ring->ready = false; |
175 | ring->ready = false; |
175 | goto done; |
176 | goto done; |
176 | } |
177 | } |
177 | 178 | ||
178 | r = radeon_ring_lock(rdev, ring, 10); |
179 | r = radeon_ring_lock(rdev, ring, 10); |
179 | if (r) { |
180 | if (r) { |
180 | DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r); |
181 | DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r); |
181 | goto done; |
182 | goto done; |
182 | } |
183 | } |
183 | 184 | ||
184 | tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); |
185 | tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); |
185 | radeon_ring_write(ring, tmp); |
186 | radeon_ring_write(ring, tmp); |
186 | radeon_ring_write(ring, 0xFFFFF); |
187 | radeon_ring_write(ring, 0xFFFFF); |
187 | 188 | ||
188 | tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); |
189 | tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); |
189 | radeon_ring_write(ring, tmp); |
190 | radeon_ring_write(ring, tmp); |
190 | radeon_ring_write(ring, 0xFFFFF); |
191 | radeon_ring_write(ring, 0xFFFFF); |
191 | 192 | ||
192 | tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); |
193 | tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); |
193 | radeon_ring_write(ring, tmp); |
194 | radeon_ring_write(ring, tmp); |
194 | radeon_ring_write(ring, 0xFFFFF); |
195 | radeon_ring_write(ring, 0xFFFFF); |
195 | 196 | ||
196 | /* Clear timeout status bits */ |
197 | /* Clear timeout status bits */ |
197 | radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0)); |
198 | radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0)); |
198 | radeon_ring_write(ring, 0x8); |
199 | radeon_ring_write(ring, 0x8); |
199 | 200 | ||
200 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); |
201 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); |
201 | radeon_ring_write(ring, 3); |
202 | radeon_ring_write(ring, 3); |
202 | 203 | ||
203 | radeon_ring_unlock_commit(rdev, ring, false); |
204 | radeon_ring_unlock_commit(rdev, ring, false); |
204 | 205 | ||
205 | done: |
206 | done: |
206 | /* lower clocks again */ |
207 | /* lower clocks again */ |
207 | radeon_set_uvd_clocks(rdev, 0, 0); |
208 | radeon_set_uvd_clocks(rdev, 0, 0); |
208 | 209 | ||
209 | if (!r) { |
210 | if (!r) { |
210 | switch (rdev->family) { |
211 | switch (rdev->family) { |
211 | case CHIP_RV610: |
212 | case CHIP_RV610: |
212 | case CHIP_RV630: |
213 | case CHIP_RV630: |
213 | case CHIP_RV620: |
214 | case CHIP_RV620: |
214 | /* 64byte granularity workaround */ |
215 | /* 64byte granularity workaround */ |
215 | WREG32(MC_CONFIG, 0); |
216 | WREG32(MC_CONFIG, 0); |
216 | WREG32(MC_CONFIG, 1 << 4); |
217 | WREG32(MC_CONFIG, 1 << 4); |
217 | WREG32(RS_DQ_RD_RET_CONF, 0x3f); |
218 | WREG32(RS_DQ_RD_RET_CONF, 0x3f); |
218 | WREG32(MC_CONFIG, 0x1f); |
219 | WREG32(MC_CONFIG, 0x1f); |
219 | 220 | ||
220 | /* fall through */ |
221 | /* fall through */ |
221 | case CHIP_RV670: |
222 | case CHIP_RV670: |
222 | case CHIP_RV635: |
223 | case CHIP_RV635: |
223 | 224 | ||
224 | /* write clean workaround */ |
225 | /* write clean workaround */ |
225 | WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10); |
226 | WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10); |
226 | break; |
227 | break; |
227 | 228 | ||
228 | default: |
229 | default: |
229 | /* TODO: Do we need more? */ |
230 | /* TODO: Do we need more? */ |
230 | break; |
231 | break; |
231 | } |
232 | } |
232 | 233 | ||
233 | DRM_INFO("UVD initialized successfully.\n"); |
234 | DRM_INFO("UVD initialized successfully.\n"); |
234 | } |
235 | } |
235 | 236 | ||
236 | return r; |
237 | return r; |
237 | } |
238 | } |
238 | 239 | ||
239 | /** |
240 | /** |
240 | * uvd_v1_0_fini - stop the hardware block |
241 | * uvd_v1_0_fini - stop the hardware block |
241 | * |
242 | * |
242 | * @rdev: radeon_device pointer |
243 | * @rdev: radeon_device pointer |
243 | * |
244 | * |
244 | * Stop the UVD block, mark ring as not ready any more |
245 | * Stop the UVD block, mark ring as not ready any more |
245 | */ |
246 | */ |
246 | void uvd_v1_0_fini(struct radeon_device *rdev) |
247 | void uvd_v1_0_fini(struct radeon_device *rdev) |
247 | { |
248 | { |
248 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
249 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
249 | 250 | ||
250 | uvd_v1_0_stop(rdev); |
251 | uvd_v1_0_stop(rdev); |
251 | ring->ready = false; |
252 | ring->ready = false; |
252 | } |
253 | } |
253 | 254 | ||
254 | /** |
255 | /** |
255 | * uvd_v1_0_start - start UVD block |
256 | * uvd_v1_0_start - start UVD block |
256 | * |
257 | * |
257 | * @rdev: radeon_device pointer |
258 | * @rdev: radeon_device pointer |
258 | * |
259 | * |
259 | * Setup and start the UVD block |
260 | * Setup and start the UVD block |
260 | */ |
261 | */ |
261 | int uvd_v1_0_start(struct radeon_device *rdev) |
262 | int uvd_v1_0_start(struct radeon_device *rdev) |
262 | { |
263 | { |
263 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
264 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
264 | uint32_t rb_bufsz; |
265 | uint32_t rb_bufsz; |
265 | int i, j, r; |
266 | int i, j, r; |
266 | 267 | ||
267 | /* disable byte swapping */ |
268 | /* disable byte swapping */ |
268 | u32 lmi_swap_cntl = 0; |
269 | u32 lmi_swap_cntl = 0; |
269 | u32 mp_swap_cntl = 0; |
270 | u32 mp_swap_cntl = 0; |
270 | 271 | ||
271 | /* disable clock gating */ |
272 | /* disable clock gating */ |
272 | WREG32(UVD_CGC_GATE, 0); |
273 | WREG32(UVD_CGC_GATE, 0); |
273 | 274 | ||
274 | /* disable interupt */ |
275 | /* disable interupt */ |
275 | WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); |
276 | WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); |
276 | 277 | ||
277 | /* Stall UMC and register bus before resetting VCPU */ |
278 | /* Stall UMC and register bus before resetting VCPU */ |
278 | WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
279 | WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
279 | WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
280 | WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
280 | mdelay(1); |
281 | mdelay(1); |
281 | 282 | ||
282 | /* put LMI, VCPU, RBC etc... into reset */ |
283 | /* put LMI, VCPU, RBC etc... into reset */ |
283 | WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | |
284 | WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | |
284 | LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | |
285 | LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | |
285 | CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET); |
286 | CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET); |
286 | mdelay(5); |
287 | mdelay(5); |
287 | 288 | ||
288 | /* take UVD block out of reset */ |
289 | /* take UVD block out of reset */ |
289 | WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD); |
290 | WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD); |
290 | mdelay(5); |
291 | mdelay(5); |
291 | 292 | ||
292 | /* initialize UVD memory controller */ |
293 | /* initialize UVD memory controller */ |
293 | WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | |
294 | WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | |
294 | (1 << 21) | (1 << 9) | (1 << 20)); |
295 | (1 << 21) | (1 << 9) | (1 << 20)); |
295 | 296 | ||
296 | #ifdef __BIG_ENDIAN |
297 | #ifdef __BIG_ENDIAN |
297 | /* swap (8 in 32) RB and IB */ |
298 | /* swap (8 in 32) RB and IB */ |
298 | lmi_swap_cntl = 0xa; |
299 | lmi_swap_cntl = 0xa; |
299 | mp_swap_cntl = 0; |
300 | mp_swap_cntl = 0; |
300 | #endif |
301 | #endif |
301 | WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl); |
302 | WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl); |
302 | WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl); |
303 | WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl); |
303 | 304 | ||
304 | WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); |
305 | WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); |
305 | WREG32(UVD_MPC_SET_MUXA1, 0x0); |
306 | WREG32(UVD_MPC_SET_MUXA1, 0x0); |
306 | WREG32(UVD_MPC_SET_MUXB0, 0x40c2040); |
307 | WREG32(UVD_MPC_SET_MUXB0, 0x40c2040); |
307 | WREG32(UVD_MPC_SET_MUXB1, 0x0); |
308 | WREG32(UVD_MPC_SET_MUXB1, 0x0); |
308 | WREG32(UVD_MPC_SET_ALU, 0); |
309 | WREG32(UVD_MPC_SET_ALU, 0); |
309 | WREG32(UVD_MPC_SET_MUX, 0x88); |
310 | WREG32(UVD_MPC_SET_MUX, 0x88); |
310 | 311 | ||
311 | /* take all subblocks out of reset, except VCPU */ |
312 | /* take all subblocks out of reset, except VCPU */ |
312 | WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
313 | WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
313 | mdelay(5); |
314 | mdelay(5); |
314 | 315 | ||
315 | /* enable VCPU clock */ |
316 | /* enable VCPU clock */ |
316 | WREG32(UVD_VCPU_CNTL, 1 << 9); |
317 | WREG32(UVD_VCPU_CNTL, 1 << 9); |
317 | 318 | ||
318 | /* enable UMC */ |
319 | /* enable UMC */ |
319 | WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
320 | WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
320 | 321 | ||
321 | WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
322 | WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
322 | 323 | ||
323 | /* boot up the VCPU */ |
324 | /* boot up the VCPU */ |
324 | WREG32(UVD_SOFT_RESET, 0); |
325 | WREG32(UVD_SOFT_RESET, 0); |
325 | mdelay(10); |
326 | mdelay(10); |
326 | 327 | ||
327 | for (i = 0; i < 10; ++i) { |
328 | for (i = 0; i < 10; ++i) { |
328 | uint32_t status; |
329 | uint32_t status; |
329 | for (j = 0; j < 100; ++j) { |
330 | for (j = 0; j < 100; ++j) { |
330 | status = RREG32(UVD_STATUS); |
331 | status = RREG32(UVD_STATUS); |
331 | if (status & 2) |
332 | if (status & 2) |
332 | break; |
333 | break; |
333 | mdelay(10); |
334 | mdelay(10); |
334 | } |
335 | } |
335 | r = 0; |
336 | r = 0; |
336 | if (status & 2) |
337 | if (status & 2) |
337 | break; |
338 | break; |
338 | 339 | ||
339 | DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); |
340 | DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); |
340 | WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET); |
341 | WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET); |
341 | mdelay(10); |
342 | mdelay(10); |
342 | WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET); |
343 | WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET); |
343 | mdelay(10); |
344 | mdelay(10); |
344 | r = -1; |
345 | r = -1; |
345 | } |
346 | } |
346 | 347 | ||
347 | if (r) { |
348 | if (r) { |
348 | DRM_ERROR("UVD not responding, giving up!!!\n"); |
349 | DRM_ERROR("UVD not responding, giving up!!!\n"); |
349 | return r; |
350 | return r; |
350 | } |
351 | } |
351 | 352 | ||
352 | /* enable interupt */ |
353 | /* enable interupt */ |
353 | WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); |
354 | WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); |
354 | 355 | ||
355 | /* force RBC into idle state */ |
356 | /* force RBC into idle state */ |
356 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
357 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
357 | 358 | ||
358 | /* Set the write pointer delay */ |
359 | /* Set the write pointer delay */ |
359 | WREG32(UVD_RBC_RB_WPTR_CNTL, 0); |
360 | WREG32(UVD_RBC_RB_WPTR_CNTL, 0); |
360 | 361 | ||
361 | /* programm the 4GB memory segment for rptr and ring buffer */ |
362 | /* programm the 4GB memory segment for rptr and ring buffer */ |
362 | WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | |
363 | WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | |
363 | (0x7 << 16) | (0x1 << 31)); |
364 | (0x7 << 16) | (0x1 << 31)); |
364 | 365 | ||
365 | /* Initialize the ring buffer's read and write pointers */ |
366 | /* Initialize the ring buffer's read and write pointers */ |
366 | WREG32(UVD_RBC_RB_RPTR, 0x0); |
367 | WREG32(UVD_RBC_RB_RPTR, 0x0); |
367 | 368 | ||
368 | ring->wptr = RREG32(UVD_RBC_RB_RPTR); |
369 | ring->wptr = RREG32(UVD_RBC_RB_RPTR); |
369 | WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
370 | WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
370 | 371 | ||
371 | /* set the ring address */ |
372 | /* set the ring address */ |
372 | WREG32(UVD_RBC_RB_BASE, ring->gpu_addr); |
373 | WREG32(UVD_RBC_RB_BASE, ring->gpu_addr); |
373 | 374 | ||
374 | /* Set ring buffer size */ |
375 | /* Set ring buffer size */ |
375 | rb_bufsz = order_base_2(ring->ring_size); |
376 | rb_bufsz = order_base_2(ring->ring_size); |
376 | rb_bufsz = (0x1 << 8) | rb_bufsz; |
377 | rb_bufsz = (0x1 << 8) | rb_bufsz; |
377 | WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f); |
378 | WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f); |
378 | 379 | ||
379 | return 0; |
380 | return 0; |
380 | } |
381 | } |
381 | 382 | ||
382 | /** |
383 | /** |
383 | * uvd_v1_0_stop - stop UVD block |
384 | * uvd_v1_0_stop - stop UVD block |
384 | * |
385 | * |
385 | * @rdev: radeon_device pointer |
386 | * @rdev: radeon_device pointer |
386 | * |
387 | * |
387 | * stop the UVD block |
388 | * stop the UVD block |
388 | */ |
389 | */ |
389 | void uvd_v1_0_stop(struct radeon_device *rdev) |
390 | void uvd_v1_0_stop(struct radeon_device *rdev) |
390 | { |
391 | { |
391 | /* force RBC into idle state */ |
392 | /* force RBC into idle state */ |
392 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
393 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
393 | 394 | ||
394 | /* Stall UMC and register bus before resetting VCPU */ |
395 | /* Stall UMC and register bus before resetting VCPU */ |
395 | WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
396 | WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
396 | WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
397 | WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
397 | mdelay(1); |
398 | mdelay(1); |
398 | 399 | ||
399 | /* put VCPU into reset */ |
400 | /* put VCPU into reset */ |
400 | WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
401 | WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
401 | mdelay(5); |
402 | mdelay(5); |
402 | 403 | ||
403 | /* disable VCPU clock */ |
404 | /* disable VCPU clock */ |
404 | WREG32(UVD_VCPU_CNTL, 0x0); |
405 | WREG32(UVD_VCPU_CNTL, 0x0); |
405 | 406 | ||
406 | /* Unstall UMC and register bus */ |
407 | /* Unstall UMC and register bus */ |
407 | WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
408 | WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
408 | WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
409 | WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
409 | } |
410 | } |
410 | 411 | ||
411 | /** |
412 | /** |
412 | * uvd_v1_0_ring_test - register write test |
413 | * uvd_v1_0_ring_test - register write test |
413 | * |
414 | * |
414 | * @rdev: radeon_device pointer |
415 | * @rdev: radeon_device pointer |
415 | * @ring: radeon_ring pointer |
416 | * @ring: radeon_ring pointer |
416 | * |
417 | * |
417 | * Test if we can successfully write to the context register |
418 | * Test if we can successfully write to the context register |
418 | */ |
419 | */ |
419 | int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) |
420 | int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) |
420 | { |
421 | { |
421 | uint32_t tmp = 0; |
422 | uint32_t tmp = 0; |
422 | unsigned i; |
423 | unsigned i; |
423 | int r; |
424 | int r; |
424 | 425 | ||
425 | WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD); |
426 | WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD); |
426 | r = radeon_ring_lock(rdev, ring, 3); |
427 | r = radeon_ring_lock(rdev, ring, 3); |
427 | if (r) { |
428 | if (r) { |
428 | DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", |
429 | DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", |
429 | ring->idx, r); |
430 | ring->idx, r); |
430 | return r; |
431 | return r; |
431 | } |
432 | } |
432 | radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); |
433 | radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); |
433 | radeon_ring_write(ring, 0xDEADBEEF); |
434 | radeon_ring_write(ring, 0xDEADBEEF); |
434 | radeon_ring_unlock_commit(rdev, ring, false); |
435 | radeon_ring_unlock_commit(rdev, ring, false); |
435 | for (i = 0; i < rdev->usec_timeout; i++) { |
436 | for (i = 0; i < rdev->usec_timeout; i++) { |
436 | tmp = RREG32(UVD_CONTEXT_ID); |
437 | tmp = RREG32(UVD_CONTEXT_ID); |
437 | if (tmp == 0xDEADBEEF) |
438 | if (tmp == 0xDEADBEEF) |
438 | break; |
439 | break; |
439 | DRM_UDELAY(1); |
440 | DRM_UDELAY(1); |
440 | } |
441 | } |
441 | 442 | ||
442 | if (i < rdev->usec_timeout) { |
443 | if (i < rdev->usec_timeout) { |
443 | DRM_INFO("ring test on %d succeeded in %d usecs\n", |
444 | DRM_INFO("ring test on %d succeeded in %d usecs\n", |
444 | ring->idx, i); |
445 | ring->idx, i); |
445 | } else { |
446 | } else { |
446 | DRM_ERROR("radeon: ring %d test failed (0x%08X)\n", |
447 | DRM_ERROR("radeon: ring %d test failed (0x%08X)\n", |
447 | ring->idx, tmp); |
448 | ring->idx, tmp); |
448 | r = -EINVAL; |
449 | r = -EINVAL; |
449 | } |
450 | } |
450 | return r; |
451 | return r; |
451 | } |
452 | } |
452 | 453 | ||
453 | /** |
454 | /** |
454 | * uvd_v1_0_semaphore_emit - emit semaphore command |
455 | * uvd_v1_0_semaphore_emit - emit semaphore command |
455 | * |
456 | * |
456 | * @rdev: radeon_device pointer |
457 | * @rdev: radeon_device pointer |
457 | * @ring: radeon_ring pointer |
458 | * @ring: radeon_ring pointer |
458 | * @semaphore: semaphore to emit commands for |
459 | * @semaphore: semaphore to emit commands for |
459 | * @emit_wait: true if we should emit a wait command |
460 | * @emit_wait: true if we should emit a wait command |
460 | * |
461 | * |
461 | * Emit a semaphore command (either wait or signal) to the UVD ring. |
462 | * Emit a semaphore command (either wait or signal) to the UVD ring. |
462 | */ |
463 | */ |
463 | bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, |
464 | bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, |
464 | struct radeon_ring *ring, |
465 | struct radeon_ring *ring, |
465 | struct radeon_semaphore *semaphore, |
466 | struct radeon_semaphore *semaphore, |
466 | bool emit_wait) |
467 | bool emit_wait) |
467 | { |
468 | { |
468 | uint64_t addr = semaphore->gpu_addr; |
469 | /* disable semaphores for UVD V1 hardware */ |
469 | - | ||
470 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); |
- | |
471 | radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); |
- | |
472 | - | ||
473 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); |
- | |
474 | radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); |
- | |
475 | - | ||
476 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); |
- | |
477 | radeon_ring_write(ring, emit_wait ? 1 : 0); |
- | |
478 | - | ||
479 | return true; |
470 | return false; |
480 | } |
471 | } |
481 | 472 | ||
482 | /** |
473 | /** |
483 | * uvd_v1_0_ib_execute - execute indirect buffer |
474 | * uvd_v1_0_ib_execute - execute indirect buffer |
484 | * |
475 | * |
485 | * @rdev: radeon_device pointer |
476 | * @rdev: radeon_device pointer |
486 | * @ib: indirect buffer to execute |
477 | * @ib: indirect buffer to execute |
487 | * |
478 | * |
488 | * Write ring commands to execute the indirect buffer |
479 | * Write ring commands to execute the indirect buffer |
489 | */ |
480 | */ |
490 | void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
481 | void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
491 | { |
482 | { |
492 | struct radeon_ring *ring = &rdev->ring[ib->ring]; |
483 | struct radeon_ring *ring = &rdev->ring[ib->ring]; |
493 | 484 | ||
494 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0)); |
485 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0)); |
495 | radeon_ring_write(ring, ib->gpu_addr); |
486 | radeon_ring_write(ring, ib->gpu_addr); |
496 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0)); |
487 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0)); |
497 | radeon_ring_write(ring, ib->length_dw); |
488 | radeon_ring_write(ring, ib->length_dw); |
498 | } |
489 | } |
499 | 490 | ||
500 | /** |
491 | /** |
501 | * uvd_v1_0_ib_test - test ib execution |
492 | * uvd_v1_0_ib_test - test ib execution |
502 | * |
493 | * |
503 | * @rdev: radeon_device pointer |
494 | * @rdev: radeon_device pointer |
504 | * @ring: radeon_ring pointer |
495 | * @ring: radeon_ring pointer |
505 | * |
496 | * |
506 | * Test if we can successfully execute an IB |
497 | * Test if we can successfully execute an IB |
507 | */ |
498 | */ |
508 | int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
499 | int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
509 | { |
500 | { |
510 | struct radeon_fence *fence = NULL; |
501 | struct radeon_fence *fence = NULL; |
511 | int r; |
502 | int r; |
512 | 503 | ||
513 | if (rdev->family < CHIP_RV740) |
504 | if (rdev->family < CHIP_RV740) |
514 | r = radeon_set_uvd_clocks(rdev, 10000, 10000); |
505 | r = radeon_set_uvd_clocks(rdev, 10000, 10000); |
515 | else |
506 | else |
516 | r = radeon_set_uvd_clocks(rdev, 53300, 40000); |
507 | r = radeon_set_uvd_clocks(rdev, 53300, 40000); |
517 | if (r) { |
508 | if (r) { |
518 | DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r); |
509 | DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r); |
519 | return r; |
510 | return r; |
520 | } |
511 | } |
521 | 512 | ||
522 | r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); |
513 | r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); |
523 | if (r) { |
514 | if (r) { |
524 | DRM_ERROR("radeon: failed to get create msg (%d).\n", r); |
515 | DRM_ERROR("radeon: failed to get create msg (%d).\n", r); |
525 | goto error; |
516 | goto error; |
526 | } |
517 | } |
527 | 518 | ||
528 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence); |
519 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence); |
529 | if (r) { |
520 | if (r) { |
530 | DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); |
521 | DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); |
531 | goto error; |
522 | goto error; |
532 | } |
523 | } |
533 | 524 | ||
534 | r = radeon_fence_wait(fence, false); |
525 | r = radeon_fence_wait(fence, false); |
535 | if (r) { |
526 | if (r) { |
536 | DRM_ERROR("radeon: fence wait failed (%d).\n", r); |
527 | DRM_ERROR("radeon: fence wait failed (%d).\n", r); |
537 | goto error; |
528 | goto error; |
538 | } |
529 | } |
539 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); |
530 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); |
540 | error: |
531 | error: |
541 | radeon_fence_unref(&fence); |
532 | radeon_fence_unref(&fence); |
542 | radeon_set_uvd_clocks(rdev, 0, 0); |
533 | radeon_set_uvd_clocks(rdev, 0, 0); |
543 | return r; |
534 | return r; |
544 | }>>>><>><>><>><>><>><>><>><>><>><>1,><1,>>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>>><>><>><>><> |
535 | }>>>><>><>><>><>><>><>><>><>><>><>1,><1,>>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>>><>><>><>><> |