1fb4d8502Sjsg /*
2fb4d8502Sjsg * Copyright 2013 Advanced Micro Devices, Inc.
3fb4d8502Sjsg * All Rights Reserved.
4fb4d8502Sjsg *
5fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
6fb4d8502Sjsg * copy of this software and associated documentation files (the
7fb4d8502Sjsg * "Software"), to deal in the Software without restriction, including
8fb4d8502Sjsg * without limitation the rights to use, copy, modify, merge, publish,
9fb4d8502Sjsg * distribute, sub license, and/or sell copies of the Software, and to
10fb4d8502Sjsg * permit persons to whom the Software is furnished to do so, subject to
11fb4d8502Sjsg * the following conditions:
12fb4d8502Sjsg *
13fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16fb4d8502Sjsg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17fb4d8502Sjsg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18fb4d8502Sjsg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19fb4d8502Sjsg * USE OR OTHER DEALINGS IN THE SOFTWARE.
20fb4d8502Sjsg *
21fb4d8502Sjsg * The above copyright notice and this permission notice (including the
22fb4d8502Sjsg * next paragraph) shall be included in all copies or substantial portions
23fb4d8502Sjsg * of the Software.
24fb4d8502Sjsg *
25fb4d8502Sjsg * Authors: Christian König <christian.koenig@amd.com>
26fb4d8502Sjsg */
27fb4d8502Sjsg
28fb4d8502Sjsg #include <linux/firmware.h>
29c349dbc7Sjsg
30fb4d8502Sjsg #include "amdgpu.h"
31fb4d8502Sjsg #include "amdgpu_vce.h"
32fb4d8502Sjsg #include "cikd.h"
33fb4d8502Sjsg #include "vce/vce_2_0_d.h"
34fb4d8502Sjsg #include "vce/vce_2_0_sh_mask.h"
35fb4d8502Sjsg #include "smu/smu_7_0_1_d.h"
36fb4d8502Sjsg #include "smu/smu_7_0_1_sh_mask.h"
37fb4d8502Sjsg #include "oss/oss_2_0_d.h"
38fb4d8502Sjsg #include "oss/oss_2_0_sh_mask.h"
39fb4d8502Sjsg
40fb4d8502Sjsg #define VCE_V2_0_FW_SIZE (256 * 1024)
41fb4d8502Sjsg #define VCE_V2_0_STACK_SIZE (64 * 1024)
42fb4d8502Sjsg #define VCE_V2_0_DATA_SIZE (23552 * AMDGPU_MAX_VCE_HANDLES)
43fb4d8502Sjsg #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02
44fb4d8502Sjsg
45fb4d8502Sjsg static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev);
46fb4d8502Sjsg static void vce_v2_0_set_irq_funcs(struct amdgpu_device *adev);
47fb4d8502Sjsg
48fb4d8502Sjsg /**
49fb4d8502Sjsg * vce_v2_0_ring_get_rptr - get read pointer
50fb4d8502Sjsg *
51fb4d8502Sjsg * @ring: amdgpu_ring pointer
52fb4d8502Sjsg *
53fb4d8502Sjsg * Returns the current hardware read pointer
54fb4d8502Sjsg */
vce_v2_0_ring_get_rptr(struct amdgpu_ring * ring)55fb4d8502Sjsg static uint64_t vce_v2_0_ring_get_rptr(struct amdgpu_ring *ring)
56fb4d8502Sjsg {
57fb4d8502Sjsg struct amdgpu_device *adev = ring->adev;
58fb4d8502Sjsg
59fb4d8502Sjsg if (ring->me == 0)
60fb4d8502Sjsg return RREG32(mmVCE_RB_RPTR);
61fb4d8502Sjsg else
62fb4d8502Sjsg return RREG32(mmVCE_RB_RPTR2);
63fb4d8502Sjsg }
64fb4d8502Sjsg
65fb4d8502Sjsg /**
66fb4d8502Sjsg * vce_v2_0_ring_get_wptr - get write pointer
67fb4d8502Sjsg *
68fb4d8502Sjsg * @ring: amdgpu_ring pointer
69fb4d8502Sjsg *
70fb4d8502Sjsg * Returns the current hardware write pointer
71fb4d8502Sjsg */
vce_v2_0_ring_get_wptr(struct amdgpu_ring * ring)72fb4d8502Sjsg static uint64_t vce_v2_0_ring_get_wptr(struct amdgpu_ring *ring)
73fb4d8502Sjsg {
74fb4d8502Sjsg struct amdgpu_device *adev = ring->adev;
75fb4d8502Sjsg
76fb4d8502Sjsg if (ring->me == 0)
77fb4d8502Sjsg return RREG32(mmVCE_RB_WPTR);
78fb4d8502Sjsg else
79fb4d8502Sjsg return RREG32(mmVCE_RB_WPTR2);
80fb4d8502Sjsg }
81fb4d8502Sjsg
82fb4d8502Sjsg /**
83fb4d8502Sjsg * vce_v2_0_ring_set_wptr - set write pointer
84fb4d8502Sjsg *
85fb4d8502Sjsg * @ring: amdgpu_ring pointer
86fb4d8502Sjsg *
87fb4d8502Sjsg * Commits the write pointer to the hardware
88fb4d8502Sjsg */
vce_v2_0_ring_set_wptr(struct amdgpu_ring * ring)89fb4d8502Sjsg static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring)
90fb4d8502Sjsg {
91fb4d8502Sjsg struct amdgpu_device *adev = ring->adev;
92fb4d8502Sjsg
93fb4d8502Sjsg if (ring->me == 0)
94fb4d8502Sjsg WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
95fb4d8502Sjsg else
96fb4d8502Sjsg WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
97fb4d8502Sjsg }
98fb4d8502Sjsg
vce_v2_0_lmi_clean(struct amdgpu_device * adev)99fb4d8502Sjsg static int vce_v2_0_lmi_clean(struct amdgpu_device *adev)
100fb4d8502Sjsg {
101fb4d8502Sjsg int i, j;
102fb4d8502Sjsg
103fb4d8502Sjsg for (i = 0; i < 10; ++i) {
104fb4d8502Sjsg for (j = 0; j < 100; ++j) {
105fb4d8502Sjsg uint32_t status = RREG32(mmVCE_LMI_STATUS);
106fb4d8502Sjsg
107fb4d8502Sjsg if (status & 0x337f)
108fb4d8502Sjsg return 0;
109fb4d8502Sjsg mdelay(10);
110fb4d8502Sjsg }
111fb4d8502Sjsg }
112fb4d8502Sjsg
113fb4d8502Sjsg return -ETIMEDOUT;
114fb4d8502Sjsg }
115fb4d8502Sjsg
vce_v2_0_firmware_loaded(struct amdgpu_device * adev)116fb4d8502Sjsg static int vce_v2_0_firmware_loaded(struct amdgpu_device *adev)
117fb4d8502Sjsg {
118fb4d8502Sjsg int i, j;
119fb4d8502Sjsg
120fb4d8502Sjsg for (i = 0; i < 10; ++i) {
121fb4d8502Sjsg for (j = 0; j < 100; ++j) {
122fb4d8502Sjsg uint32_t status = RREG32(mmVCE_STATUS);
123fb4d8502Sjsg
124fb4d8502Sjsg if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
125fb4d8502Sjsg return 0;
126fb4d8502Sjsg mdelay(10);
127fb4d8502Sjsg }
128fb4d8502Sjsg
129fb4d8502Sjsg DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
130fb4d8502Sjsg WREG32_P(mmVCE_SOFT_RESET,
131fb4d8502Sjsg VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
132fb4d8502Sjsg ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
133fb4d8502Sjsg mdelay(10);
134fb4d8502Sjsg WREG32_P(mmVCE_SOFT_RESET, 0,
135fb4d8502Sjsg ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
136fb4d8502Sjsg mdelay(10);
137fb4d8502Sjsg }
138fb4d8502Sjsg
139fb4d8502Sjsg return -ETIMEDOUT;
140fb4d8502Sjsg }
141fb4d8502Sjsg
vce_v2_0_disable_cg(struct amdgpu_device * adev)142fb4d8502Sjsg static void vce_v2_0_disable_cg(struct amdgpu_device *adev)
143fb4d8502Sjsg {
144fb4d8502Sjsg WREG32(mmVCE_CGTT_CLK_OVERRIDE, 7);
145fb4d8502Sjsg }
146fb4d8502Sjsg
vce_v2_0_init_cg(struct amdgpu_device * adev)147fb4d8502Sjsg static void vce_v2_0_init_cg(struct amdgpu_device *adev)
148fb4d8502Sjsg {
149fb4d8502Sjsg u32 tmp;
150fb4d8502Sjsg
151fb4d8502Sjsg tmp = RREG32(mmVCE_CLOCK_GATING_A);
152fb4d8502Sjsg tmp &= ~0xfff;
153fb4d8502Sjsg tmp |= ((0 << 0) | (4 << 4));
154fb4d8502Sjsg tmp |= 0x40000;
155fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_A, tmp);
156fb4d8502Sjsg
157fb4d8502Sjsg tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
158fb4d8502Sjsg tmp &= ~0xfff;
159fb4d8502Sjsg tmp |= ((0 << 0) | (4 << 4));
160fb4d8502Sjsg WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
161fb4d8502Sjsg
162fb4d8502Sjsg tmp = RREG32(mmVCE_CLOCK_GATING_B);
163fb4d8502Sjsg tmp |= 0x10;
164fb4d8502Sjsg tmp &= ~0x100000;
165fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, tmp);
166fb4d8502Sjsg }
167fb4d8502Sjsg
vce_v2_0_mc_resume(struct amdgpu_device * adev)168fb4d8502Sjsg static void vce_v2_0_mc_resume(struct amdgpu_device *adev)
169fb4d8502Sjsg {
170fb4d8502Sjsg uint32_t size, offset;
171fb4d8502Sjsg
172fb4d8502Sjsg WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
173fb4d8502Sjsg WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
174fb4d8502Sjsg WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
175fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
176fb4d8502Sjsg
177fb4d8502Sjsg WREG32(mmVCE_LMI_CTRL, 0x00398000);
178fb4d8502Sjsg WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
179fb4d8502Sjsg WREG32(mmVCE_LMI_SWAP_CNTL, 0);
180fb4d8502Sjsg WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
181fb4d8502Sjsg WREG32(mmVCE_LMI_VM_CTRL, 0);
182fb4d8502Sjsg
183fb4d8502Sjsg WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
184fb4d8502Sjsg
185fb4d8502Sjsg offset = AMDGPU_VCE_FIRMWARE_OFFSET;
186fb4d8502Sjsg size = VCE_V2_0_FW_SIZE;
187fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
188fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
189fb4d8502Sjsg
190fb4d8502Sjsg offset += size;
191fb4d8502Sjsg size = VCE_V2_0_STACK_SIZE;
192fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
193fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
194fb4d8502Sjsg
195fb4d8502Sjsg offset += size;
196fb4d8502Sjsg size = VCE_V2_0_DATA_SIZE;
197fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
198fb4d8502Sjsg WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
199fb4d8502Sjsg
200fb4d8502Sjsg WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
201fb4d8502Sjsg WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
202fb4d8502Sjsg }
203fb4d8502Sjsg
vce_v2_0_is_idle(void * handle)204fb4d8502Sjsg static bool vce_v2_0_is_idle(void *handle)
205fb4d8502Sjsg {
206fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
207fb4d8502Sjsg
208fb4d8502Sjsg return !(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK);
209fb4d8502Sjsg }
210fb4d8502Sjsg
vce_v2_0_wait_for_idle(void * handle)211fb4d8502Sjsg static int vce_v2_0_wait_for_idle(void *handle)
212fb4d8502Sjsg {
213fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
214fb4d8502Sjsg unsigned i;
215fb4d8502Sjsg
216fb4d8502Sjsg for (i = 0; i < adev->usec_timeout; i++) {
217fb4d8502Sjsg if (vce_v2_0_is_idle(handle))
218fb4d8502Sjsg return 0;
219fb4d8502Sjsg }
220fb4d8502Sjsg return -ETIMEDOUT;
221fb4d8502Sjsg }
222fb4d8502Sjsg
223fb4d8502Sjsg /**
224fb4d8502Sjsg * vce_v2_0_start - start VCE block
225fb4d8502Sjsg *
226fb4d8502Sjsg * @adev: amdgpu_device pointer
227fb4d8502Sjsg *
228fb4d8502Sjsg * Setup and start the VCE block
229fb4d8502Sjsg */
vce_v2_0_start(struct amdgpu_device * adev)230fb4d8502Sjsg static int vce_v2_0_start(struct amdgpu_device *adev)
231fb4d8502Sjsg {
232fb4d8502Sjsg struct amdgpu_ring *ring;
233fb4d8502Sjsg int r;
234fb4d8502Sjsg
235fb4d8502Sjsg /* set BUSY flag */
236fb4d8502Sjsg WREG32_P(mmVCE_STATUS, 1, ~1);
237fb4d8502Sjsg
238fb4d8502Sjsg vce_v2_0_init_cg(adev);
239fb4d8502Sjsg vce_v2_0_disable_cg(adev);
240fb4d8502Sjsg
241fb4d8502Sjsg vce_v2_0_mc_resume(adev);
242fb4d8502Sjsg
243fb4d8502Sjsg ring = &adev->vce.ring[0];
244fb4d8502Sjsg WREG32(mmVCE_RB_RPTR, lower_32_bits(ring->wptr));
245fb4d8502Sjsg WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
246fb4d8502Sjsg WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
247fb4d8502Sjsg WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
248fb4d8502Sjsg WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
249fb4d8502Sjsg
250fb4d8502Sjsg ring = &adev->vce.ring[1];
251fb4d8502Sjsg WREG32(mmVCE_RB_RPTR2, lower_32_bits(ring->wptr));
252fb4d8502Sjsg WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
253fb4d8502Sjsg WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
254fb4d8502Sjsg WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
255fb4d8502Sjsg WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
256fb4d8502Sjsg
257fb4d8502Sjsg WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
258fb4d8502Sjsg WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
259fb4d8502Sjsg mdelay(100);
260fb4d8502Sjsg WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
261fb4d8502Sjsg
262fb4d8502Sjsg r = vce_v2_0_firmware_loaded(adev);
263fb4d8502Sjsg
264fb4d8502Sjsg /* clear BUSY flag */
265fb4d8502Sjsg WREG32_P(mmVCE_STATUS, 0, ~1);
266fb4d8502Sjsg
267fb4d8502Sjsg if (r) {
268fb4d8502Sjsg DRM_ERROR("VCE not responding, giving up!!!\n");
269fb4d8502Sjsg return r;
270fb4d8502Sjsg }
271fb4d8502Sjsg
272fb4d8502Sjsg return 0;
273fb4d8502Sjsg }
274fb4d8502Sjsg
vce_v2_0_stop(struct amdgpu_device * adev)275fb4d8502Sjsg static int vce_v2_0_stop(struct amdgpu_device *adev)
276fb4d8502Sjsg {
277fb4d8502Sjsg int i;
278fb4d8502Sjsg int status;
279fb4d8502Sjsg
280fb4d8502Sjsg if (vce_v2_0_lmi_clean(adev)) {
281fb4d8502Sjsg DRM_INFO("vce is not idle \n");
282fb4d8502Sjsg return 0;
283fb4d8502Sjsg }
284fb4d8502Sjsg
285fb4d8502Sjsg if (vce_v2_0_wait_for_idle(adev)) {
286c349dbc7Sjsg DRM_INFO("VCE is busy, Can't set clock gating");
287fb4d8502Sjsg return 0;
288fb4d8502Sjsg }
289fb4d8502Sjsg
290fb4d8502Sjsg /* Stall UMC and register bus before resetting VCPU */
291fb4d8502Sjsg WREG32_P(mmVCE_LMI_CTRL2, 1 << 8, ~(1 << 8));
292fb4d8502Sjsg
293fb4d8502Sjsg for (i = 0; i < 100; ++i) {
294fb4d8502Sjsg status = RREG32(mmVCE_LMI_STATUS);
295fb4d8502Sjsg if (status & 0x240)
296fb4d8502Sjsg break;
297fb4d8502Sjsg mdelay(1);
298fb4d8502Sjsg }
299fb4d8502Sjsg
300fb4d8502Sjsg WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x80001);
301fb4d8502Sjsg
302fb4d8502Sjsg /* put LMI, VCPU, RBC etc... into reset */
303fb4d8502Sjsg WREG32_P(mmVCE_SOFT_RESET, 1, ~0x1);
304fb4d8502Sjsg
305fb4d8502Sjsg WREG32(mmVCE_STATUS, 0);
306fb4d8502Sjsg
307fb4d8502Sjsg return 0;
308fb4d8502Sjsg }
309fb4d8502Sjsg
vce_v2_0_set_sw_cg(struct amdgpu_device * adev,bool gated)310fb4d8502Sjsg static void vce_v2_0_set_sw_cg(struct amdgpu_device *adev, bool gated)
311fb4d8502Sjsg {
312fb4d8502Sjsg u32 tmp;
313fb4d8502Sjsg
314fb4d8502Sjsg if (gated) {
315fb4d8502Sjsg tmp = RREG32(mmVCE_CLOCK_GATING_B);
316fb4d8502Sjsg tmp |= 0xe70000;
317fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, tmp);
318fb4d8502Sjsg
319fb4d8502Sjsg tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
320fb4d8502Sjsg tmp |= 0xff000000;
321fb4d8502Sjsg WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
322fb4d8502Sjsg
323fb4d8502Sjsg tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
324fb4d8502Sjsg tmp &= ~0x3fc;
325fb4d8502Sjsg WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
326fb4d8502Sjsg
327fb4d8502Sjsg WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
328fb4d8502Sjsg } else {
329fb4d8502Sjsg tmp = RREG32(mmVCE_CLOCK_GATING_B);
330fb4d8502Sjsg tmp |= 0xe7;
331fb4d8502Sjsg tmp &= ~0xe70000;
332fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, tmp);
333fb4d8502Sjsg
334fb4d8502Sjsg tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
335fb4d8502Sjsg tmp |= 0x1fe000;
336fb4d8502Sjsg tmp &= ~0xff000000;
337fb4d8502Sjsg WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
338fb4d8502Sjsg
339fb4d8502Sjsg tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
340fb4d8502Sjsg tmp |= 0x3fc;
341fb4d8502Sjsg WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
342fb4d8502Sjsg }
343fb4d8502Sjsg }
344fb4d8502Sjsg
vce_v2_0_set_dyn_cg(struct amdgpu_device * adev,bool gated)345fb4d8502Sjsg static void vce_v2_0_set_dyn_cg(struct amdgpu_device *adev, bool gated)
346fb4d8502Sjsg {
347fb4d8502Sjsg u32 orig, tmp;
348fb4d8502Sjsg
349fb4d8502Sjsg /* LMI_MC/LMI_UMC always set in dynamic,
350fb4d8502Sjsg * set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {0, 0}
351fb4d8502Sjsg */
352fb4d8502Sjsg tmp = RREG32(mmVCE_CLOCK_GATING_B);
353fb4d8502Sjsg tmp &= ~0x00060006;
354fb4d8502Sjsg
355fb4d8502Sjsg /* Exception for ECPU, IH, SEM, SYS blocks needs to be turned on/off by SW */
356fb4d8502Sjsg if (gated) {
357fb4d8502Sjsg tmp |= 0xe10000;
358fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, tmp);
359fb4d8502Sjsg } else {
360fb4d8502Sjsg tmp |= 0xe1;
361fb4d8502Sjsg tmp &= ~0xe10000;
362fb4d8502Sjsg WREG32(mmVCE_CLOCK_GATING_B, tmp);
363fb4d8502Sjsg }
364fb4d8502Sjsg
365fb4d8502Sjsg orig = tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
366fb4d8502Sjsg tmp &= ~0x1fe000;
367fb4d8502Sjsg tmp &= ~0xff000000;
368fb4d8502Sjsg if (tmp != orig)
369fb4d8502Sjsg WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
370fb4d8502Sjsg
371fb4d8502Sjsg orig = tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
372fb4d8502Sjsg tmp &= ~0x3fc;
373fb4d8502Sjsg if (tmp != orig)
374fb4d8502Sjsg WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
375fb4d8502Sjsg
376fb4d8502Sjsg /* set VCE_UENC_REG_CLOCK_GATING always in dynamic mode */
377fb4d8502Sjsg WREG32(mmVCE_UENC_REG_CLOCK_GATING, 0x00);
378fb4d8502Sjsg
379fb4d8502Sjsg if(gated)
380fb4d8502Sjsg WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
381fb4d8502Sjsg }
382fb4d8502Sjsg
vce_v2_0_enable_mgcg(struct amdgpu_device * adev,bool enable,bool sw_cg)383fb4d8502Sjsg static void vce_v2_0_enable_mgcg(struct amdgpu_device *adev, bool enable,
384fb4d8502Sjsg bool sw_cg)
385fb4d8502Sjsg {
386fb4d8502Sjsg if (enable && (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) {
387fb4d8502Sjsg if (sw_cg)
388fb4d8502Sjsg vce_v2_0_set_sw_cg(adev, true);
389fb4d8502Sjsg else
390fb4d8502Sjsg vce_v2_0_set_dyn_cg(adev, true);
391fb4d8502Sjsg } else {
392fb4d8502Sjsg vce_v2_0_disable_cg(adev);
393fb4d8502Sjsg
394fb4d8502Sjsg if (sw_cg)
395fb4d8502Sjsg vce_v2_0_set_sw_cg(adev, false);
396fb4d8502Sjsg else
397fb4d8502Sjsg vce_v2_0_set_dyn_cg(adev, false);
398fb4d8502Sjsg }
399fb4d8502Sjsg }
400fb4d8502Sjsg
vce_v2_0_early_init(void * handle)401fb4d8502Sjsg static int vce_v2_0_early_init(void *handle)
402fb4d8502Sjsg {
403fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
404fb4d8502Sjsg
405fb4d8502Sjsg adev->vce.num_rings = 2;
406fb4d8502Sjsg
407fb4d8502Sjsg vce_v2_0_set_ring_funcs(adev);
408fb4d8502Sjsg vce_v2_0_set_irq_funcs(adev);
409fb4d8502Sjsg
410fb4d8502Sjsg return 0;
411fb4d8502Sjsg }
412fb4d8502Sjsg
vce_v2_0_sw_init(void * handle)413fb4d8502Sjsg static int vce_v2_0_sw_init(void *handle)
414fb4d8502Sjsg {
415fb4d8502Sjsg struct amdgpu_ring *ring;
416fb4d8502Sjsg int r, i;
417fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
418fb4d8502Sjsg
419fb4d8502Sjsg /* VCE */
420c349dbc7Sjsg r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 167, &adev->vce.irq);
421fb4d8502Sjsg if (r)
422fb4d8502Sjsg return r;
423fb4d8502Sjsg
424fb4d8502Sjsg r = amdgpu_vce_sw_init(adev, VCE_V2_0_FW_SIZE +
425fb4d8502Sjsg VCE_V2_0_STACK_SIZE + VCE_V2_0_DATA_SIZE);
426fb4d8502Sjsg if (r)
427fb4d8502Sjsg return r;
428fb4d8502Sjsg
429fb4d8502Sjsg r = amdgpu_vce_resume(adev);
430fb4d8502Sjsg if (r)
431fb4d8502Sjsg return r;
432fb4d8502Sjsg
433fb4d8502Sjsg for (i = 0; i < adev->vce.num_rings; i++) {
434*1bb76ff1Sjsg enum amdgpu_ring_priority_level hw_prio = amdgpu_vce_get_ring_prio(i);
435*1bb76ff1Sjsg
436fb4d8502Sjsg ring = &adev->vce.ring[i];
437fb4d8502Sjsg snprintf(ring->name, sizeof(ring->name), "vce%d", i);
4385ca02815Sjsg r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0,
439*1bb76ff1Sjsg hw_prio, NULL);
440fb4d8502Sjsg if (r)
441fb4d8502Sjsg return r;
442fb4d8502Sjsg }
443fb4d8502Sjsg
444fb4d8502Sjsg r = amdgpu_vce_entity_init(adev);
445fb4d8502Sjsg
446fb4d8502Sjsg return r;
447fb4d8502Sjsg }
448fb4d8502Sjsg
vce_v2_0_sw_fini(void * handle)449fb4d8502Sjsg static int vce_v2_0_sw_fini(void *handle)
450fb4d8502Sjsg {
451fb4d8502Sjsg int r;
452fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
453fb4d8502Sjsg
454fb4d8502Sjsg r = amdgpu_vce_suspend(adev);
455fb4d8502Sjsg if (r)
456fb4d8502Sjsg return r;
457fb4d8502Sjsg
458fb4d8502Sjsg return amdgpu_vce_sw_fini(adev);
459fb4d8502Sjsg }
460fb4d8502Sjsg
vce_v2_0_hw_init(void * handle)461fb4d8502Sjsg static int vce_v2_0_hw_init(void *handle)
462fb4d8502Sjsg {
463fb4d8502Sjsg int r, i;
464fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
465fb4d8502Sjsg
466fb4d8502Sjsg amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
467fb4d8502Sjsg vce_v2_0_enable_mgcg(adev, true, false);
468fb4d8502Sjsg
469fb4d8502Sjsg for (i = 0; i < adev->vce.num_rings; i++) {
470c349dbc7Sjsg r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
471fb4d8502Sjsg if (r)
472fb4d8502Sjsg return r;
473fb4d8502Sjsg }
474fb4d8502Sjsg
475fb4d8502Sjsg DRM_INFO("VCE initialized successfully.\n");
476fb4d8502Sjsg
477fb4d8502Sjsg return 0;
478fb4d8502Sjsg }
479fb4d8502Sjsg
vce_v2_0_hw_fini(void * handle)480fb4d8502Sjsg static int vce_v2_0_hw_fini(void *handle)
481fb4d8502Sjsg {
4825ca02815Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
4835ca02815Sjsg
4845ca02815Sjsg cancel_delayed_work_sync(&adev->vce.idle_work);
4855ca02815Sjsg
486fb4d8502Sjsg return 0;
487fb4d8502Sjsg }
488fb4d8502Sjsg
vce_v2_0_suspend(void * handle)489fb4d8502Sjsg static int vce_v2_0_suspend(void *handle)
490fb4d8502Sjsg {
491fb4d8502Sjsg int r;
492fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
493fb4d8502Sjsg
4945ca02815Sjsg
4955ca02815Sjsg /*
4965ca02815Sjsg * Proper cleanups before halting the HW engine:
4975ca02815Sjsg * - cancel the delayed idle work
4985ca02815Sjsg * - enable powergating
4995ca02815Sjsg * - enable clockgating
5005ca02815Sjsg * - disable dpm
5015ca02815Sjsg *
5025ca02815Sjsg * TODO: to align with the VCN implementation, move the
5035ca02815Sjsg * jobs for clockgating/powergating/dpm setting to
5045ca02815Sjsg * ->set_powergating_state().
5055ca02815Sjsg */
5065ca02815Sjsg cancel_delayed_work_sync(&adev->vce.idle_work);
5075ca02815Sjsg
5085ca02815Sjsg if (adev->pm.dpm_enabled) {
5095ca02815Sjsg amdgpu_dpm_enable_vce(adev, false);
5105ca02815Sjsg } else {
5115ca02815Sjsg amdgpu_asic_set_vce_clocks(adev, 0, 0);
5125ca02815Sjsg amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
5135ca02815Sjsg AMD_PG_STATE_GATE);
5145ca02815Sjsg amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
5155ca02815Sjsg AMD_CG_STATE_GATE);
5165ca02815Sjsg }
5175ca02815Sjsg
518fb4d8502Sjsg r = vce_v2_0_hw_fini(adev);
519fb4d8502Sjsg if (r)
520fb4d8502Sjsg return r;
521fb4d8502Sjsg
522fb4d8502Sjsg return amdgpu_vce_suspend(adev);
523fb4d8502Sjsg }
524fb4d8502Sjsg
vce_v2_0_resume(void * handle)525fb4d8502Sjsg static int vce_v2_0_resume(void *handle)
526fb4d8502Sjsg {
527fb4d8502Sjsg int r;
528fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
529fb4d8502Sjsg
530fb4d8502Sjsg r = amdgpu_vce_resume(adev);
531fb4d8502Sjsg if (r)
532fb4d8502Sjsg return r;
533fb4d8502Sjsg
534fb4d8502Sjsg return vce_v2_0_hw_init(adev);
535fb4d8502Sjsg }
536fb4d8502Sjsg
vce_v2_0_soft_reset(void * handle)537fb4d8502Sjsg static int vce_v2_0_soft_reset(void *handle)
538fb4d8502Sjsg {
539fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
540fb4d8502Sjsg
541fb4d8502Sjsg WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_VCE, 1);
542fb4d8502Sjsg mdelay(5);
543fb4d8502Sjsg
544fb4d8502Sjsg return vce_v2_0_start(adev);
545fb4d8502Sjsg }
546fb4d8502Sjsg
vce_v2_0_set_interrupt_state(struct amdgpu_device * adev,struct amdgpu_irq_src * source,unsigned type,enum amdgpu_interrupt_state state)547fb4d8502Sjsg static int vce_v2_0_set_interrupt_state(struct amdgpu_device *adev,
548fb4d8502Sjsg struct amdgpu_irq_src *source,
549fb4d8502Sjsg unsigned type,
550fb4d8502Sjsg enum amdgpu_interrupt_state state)
551fb4d8502Sjsg {
552fb4d8502Sjsg uint32_t val = 0;
553fb4d8502Sjsg
554fb4d8502Sjsg if (state == AMDGPU_IRQ_STATE_ENABLE)
555fb4d8502Sjsg val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
556fb4d8502Sjsg
557fb4d8502Sjsg WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
558fb4d8502Sjsg return 0;
559fb4d8502Sjsg }
560fb4d8502Sjsg
vce_v2_0_process_interrupt(struct amdgpu_device * adev,struct amdgpu_irq_src * source,struct amdgpu_iv_entry * entry)561fb4d8502Sjsg static int vce_v2_0_process_interrupt(struct amdgpu_device *adev,
562fb4d8502Sjsg struct amdgpu_irq_src *source,
563fb4d8502Sjsg struct amdgpu_iv_entry *entry)
564fb4d8502Sjsg {
565fb4d8502Sjsg DRM_DEBUG("IH: VCE\n");
566fb4d8502Sjsg switch (entry->src_data[0]) {
567fb4d8502Sjsg case 0:
568fb4d8502Sjsg case 1:
569fb4d8502Sjsg amdgpu_fence_process(&adev->vce.ring[entry->src_data[0]]);
570fb4d8502Sjsg break;
571fb4d8502Sjsg default:
572fb4d8502Sjsg DRM_ERROR("Unhandled interrupt: %d %d\n",
573fb4d8502Sjsg entry->src_id, entry->src_data[0]);
574fb4d8502Sjsg break;
575fb4d8502Sjsg }
576fb4d8502Sjsg
577fb4d8502Sjsg return 0;
578fb4d8502Sjsg }
579fb4d8502Sjsg
vce_v2_0_set_clockgating_state(void * handle,enum amd_clockgating_state state)580fb4d8502Sjsg static int vce_v2_0_set_clockgating_state(void *handle,
581fb4d8502Sjsg enum amd_clockgating_state state)
582fb4d8502Sjsg {
583fb4d8502Sjsg bool gate = false;
584fb4d8502Sjsg bool sw_cg = false;
585fb4d8502Sjsg
586fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
587fb4d8502Sjsg
588fb4d8502Sjsg if (state == AMD_CG_STATE_GATE) {
589fb4d8502Sjsg gate = true;
590fb4d8502Sjsg sw_cg = true;
591fb4d8502Sjsg }
592fb4d8502Sjsg
593fb4d8502Sjsg vce_v2_0_enable_mgcg(adev, gate, sw_cg);
594fb4d8502Sjsg
595fb4d8502Sjsg return 0;
596fb4d8502Sjsg }
597fb4d8502Sjsg
vce_v2_0_set_powergating_state(void * handle,enum amd_powergating_state state)598fb4d8502Sjsg static int vce_v2_0_set_powergating_state(void *handle,
599fb4d8502Sjsg enum amd_powergating_state state)
600fb4d8502Sjsg {
601fb4d8502Sjsg /* This doesn't actually powergate the VCE block.
602fb4d8502Sjsg * That's done in the dpm code via the SMC. This
603fb4d8502Sjsg * just re-inits the block as necessary. The actual
604fb4d8502Sjsg * gating still happens in the dpm code. We should
605fb4d8502Sjsg * revisit this when there is a cleaner line between
606fb4d8502Sjsg * the smc and the hw blocks
607fb4d8502Sjsg */
608fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
609fb4d8502Sjsg
610fb4d8502Sjsg if (state == AMD_PG_STATE_GATE)
611fb4d8502Sjsg return vce_v2_0_stop(adev);
612fb4d8502Sjsg else
613fb4d8502Sjsg return vce_v2_0_start(adev);
614fb4d8502Sjsg }
615fb4d8502Sjsg
616fb4d8502Sjsg static const struct amd_ip_funcs vce_v2_0_ip_funcs = {
617fb4d8502Sjsg .name = "vce_v2_0",
618fb4d8502Sjsg .early_init = vce_v2_0_early_init,
619fb4d8502Sjsg .late_init = NULL,
620fb4d8502Sjsg .sw_init = vce_v2_0_sw_init,
621fb4d8502Sjsg .sw_fini = vce_v2_0_sw_fini,
622fb4d8502Sjsg .hw_init = vce_v2_0_hw_init,
623fb4d8502Sjsg .hw_fini = vce_v2_0_hw_fini,
624fb4d8502Sjsg .suspend = vce_v2_0_suspend,
625fb4d8502Sjsg .resume = vce_v2_0_resume,
626fb4d8502Sjsg .is_idle = vce_v2_0_is_idle,
627fb4d8502Sjsg .wait_for_idle = vce_v2_0_wait_for_idle,
628fb4d8502Sjsg .soft_reset = vce_v2_0_soft_reset,
629fb4d8502Sjsg .set_clockgating_state = vce_v2_0_set_clockgating_state,
630fb4d8502Sjsg .set_powergating_state = vce_v2_0_set_powergating_state,
631fb4d8502Sjsg };
632fb4d8502Sjsg
633fb4d8502Sjsg static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = {
634fb4d8502Sjsg .type = AMDGPU_RING_TYPE_VCE,
635fb4d8502Sjsg .align_mask = 0xf,
636fb4d8502Sjsg .nop = VCE_CMD_NO_OP,
637fb4d8502Sjsg .support_64bit_ptrs = false,
638c349dbc7Sjsg .no_user_fence = true,
639fb4d8502Sjsg .get_rptr = vce_v2_0_ring_get_rptr,
640fb4d8502Sjsg .get_wptr = vce_v2_0_ring_get_wptr,
641fb4d8502Sjsg .set_wptr = vce_v2_0_ring_set_wptr,
642fb4d8502Sjsg .parse_cs = amdgpu_vce_ring_parse_cs,
643fb4d8502Sjsg .emit_frame_size = 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */
644fb4d8502Sjsg .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */
645fb4d8502Sjsg .emit_ib = amdgpu_vce_ring_emit_ib,
646fb4d8502Sjsg .emit_fence = amdgpu_vce_ring_emit_fence,
647fb4d8502Sjsg .test_ring = amdgpu_vce_ring_test_ring,
648fb4d8502Sjsg .test_ib = amdgpu_vce_ring_test_ib,
649fb4d8502Sjsg .insert_nop = amdgpu_ring_insert_nop,
650fb4d8502Sjsg .pad_ib = amdgpu_ring_generic_pad_ib,
651fb4d8502Sjsg .begin_use = amdgpu_vce_ring_begin_use,
652fb4d8502Sjsg .end_use = amdgpu_vce_ring_end_use,
653fb4d8502Sjsg };
654fb4d8502Sjsg
vce_v2_0_set_ring_funcs(struct amdgpu_device * adev)655fb4d8502Sjsg static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev)
656fb4d8502Sjsg {
657fb4d8502Sjsg int i;
658fb4d8502Sjsg
659fb4d8502Sjsg for (i = 0; i < adev->vce.num_rings; i++) {
660fb4d8502Sjsg adev->vce.ring[i].funcs = &vce_v2_0_ring_funcs;
661fb4d8502Sjsg adev->vce.ring[i].me = i;
662fb4d8502Sjsg }
663fb4d8502Sjsg }
664fb4d8502Sjsg
665fb4d8502Sjsg static const struct amdgpu_irq_src_funcs vce_v2_0_irq_funcs = {
666fb4d8502Sjsg .set = vce_v2_0_set_interrupt_state,
667fb4d8502Sjsg .process = vce_v2_0_process_interrupt,
668fb4d8502Sjsg };
669fb4d8502Sjsg
vce_v2_0_set_irq_funcs(struct amdgpu_device * adev)670fb4d8502Sjsg static void vce_v2_0_set_irq_funcs(struct amdgpu_device *adev)
671fb4d8502Sjsg {
672fb4d8502Sjsg adev->vce.irq.num_types = 1;
673fb4d8502Sjsg adev->vce.irq.funcs = &vce_v2_0_irq_funcs;
674fb4d8502Sjsg };
675fb4d8502Sjsg
676fb4d8502Sjsg const struct amdgpu_ip_block_version vce_v2_0_ip_block =
677fb4d8502Sjsg {
678fb4d8502Sjsg .type = AMD_IP_BLOCK_TYPE_VCE,
679fb4d8502Sjsg .major = 2,
680fb4d8502Sjsg .minor = 0,
681fb4d8502Sjsg .rev = 0,
682fb4d8502Sjsg .funcs = &vce_v2_0_ip_funcs,
683fb4d8502Sjsg };
684