2 * Copyright 2020 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
24 #include <linux/pci.h>
27 #include "amdgpu_ih.h"
30 #include "oss/osssys_4_2_0_offset.h"
31 #include "oss/osssys_4_2_0_sh_mask.h"
33 #include "soc15_common.h"
34 #include "vega20_ih.h"
36 #define MAX_REARM_RETRY 10
38 #define mmIH_CHICKEN_ALDEBARAN 0x18d
39 #define mmIH_CHICKEN_ALDEBARAN_BASE_IDX 0
41 static void vega20_ih_set_interrupt_funcs(struct amdgpu_device
*adev
);
44 * vega20_ih_init_register_offset - Initialize register offset for ih rings
46 * @adev: amdgpu_device pointer
48 * Initialize register offset ih rings (VEGA20).
50 static void vega20_ih_init_register_offset(struct amdgpu_device
*adev
)
52 struct amdgpu_ih_regs
*ih_regs
;
54 if (adev
->irq
.ih
.ring_size
) {
55 ih_regs
= &adev
->irq
.ih
.ih_regs
;
56 ih_regs
->ih_rb_base
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE
);
57 ih_regs
->ih_rb_base_hi
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE_HI
);
58 ih_regs
->ih_rb_cntl
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_CNTL
);
59 ih_regs
->ih_rb_wptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_WPTR
);
60 ih_regs
->ih_rb_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_RPTR
);
61 ih_regs
->ih_doorbell_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_DOORBELL_RPTR
);
62 ih_regs
->ih_rb_wptr_addr_lo
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_WPTR_ADDR_LO
);
63 ih_regs
->ih_rb_wptr_addr_hi
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_WPTR_ADDR_HI
);
64 ih_regs
->psp_reg_id
= PSP_REG_IH_RB_CNTL
;
67 if (adev
->irq
.ih1
.ring_size
) {
68 ih_regs
= &adev
->irq
.ih1
.ih_regs
;
69 ih_regs
->ih_rb_base
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE_RING1
);
70 ih_regs
->ih_rb_base_hi
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE_HI_RING1
);
71 ih_regs
->ih_rb_cntl
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_CNTL_RING1
);
72 ih_regs
->ih_rb_wptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_WPTR_RING1
);
73 ih_regs
->ih_rb_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_RPTR_RING1
);
74 ih_regs
->ih_doorbell_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_DOORBELL_RPTR_RING1
);
75 ih_regs
->psp_reg_id
= PSP_REG_IH_RB_CNTL_RING1
;
78 if (adev
->irq
.ih2
.ring_size
) {
79 ih_regs
= &adev
->irq
.ih2
.ih_regs
;
80 ih_regs
->ih_rb_base
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE_RING2
);
81 ih_regs
->ih_rb_base_hi
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_BASE_HI_RING2
);
82 ih_regs
->ih_rb_cntl
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_CNTL_RING2
);
83 ih_regs
->ih_rb_wptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_WPTR_RING2
);
84 ih_regs
->ih_rb_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_RB_RPTR_RING2
);
85 ih_regs
->ih_doorbell_rptr
= SOC15_REG_OFFSET(OSSSYS
, 0, mmIH_DOORBELL_RPTR_RING2
);
86 ih_regs
->psp_reg_id
= PSP_REG_IH_RB_CNTL_RING2
;
91 * vega20_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
93 * @adev: amdgpu_device pointer
94 * @ih: amdgpu_ih_ring pointer
95 * @enable: true - enable the interrupts, false - disable the interrupts
97 * Toggle the interrupt ring buffer (VEGA20)
99 static int vega20_ih_toggle_ring_interrupts(struct amdgpu_device
*adev
,
100 struct amdgpu_ih_ring
*ih
,
103 struct amdgpu_ih_regs
*ih_regs
;
106 ih_regs
= &ih
->ih_regs
;
108 tmp
= RREG32(ih_regs
->ih_rb_cntl
);
109 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, RB_ENABLE
, (enable
? 1 : 0));
110 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, RB_GPU_TS_ENABLE
, 1);
112 /* enable_intr field is only valid in ring0 */
113 if (ih
== &adev
->irq
.ih
)
114 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, ENABLE_INTR
, (enable
? 1 : 0));
115 if (amdgpu_sriov_vf(adev
)) {
116 if (psp_reg_program(&adev
->psp
, ih_regs
->psp_reg_id
, tmp
)) {
117 dev_err(adev
->dev
, "PSP program IH_RB_CNTL failed!\n");
121 WREG32(ih_regs
->ih_rb_cntl
, tmp
);
127 /* set rptr, wptr to 0 */
128 WREG32(ih_regs
->ih_rb_rptr
, 0);
129 WREG32(ih_regs
->ih_rb_wptr
, 0);
138 * vega20_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
140 * @adev: amdgpu_device pointer
141 * @enable: enable or disable interrupt ring buffers
143 * Toggle all the available interrupt ring buffers (VEGA20).
145 static int vega20_ih_toggle_interrupts(struct amdgpu_device
*adev
, bool enable
)
147 struct amdgpu_ih_ring
*ih
[] = {&adev
->irq
.ih
, &adev
->irq
.ih1
, &adev
->irq
.ih2
};
151 for (i
= 0; i
< ARRAY_SIZE(ih
); i
++) {
152 if (ih
[i
]->ring_size
) {
153 r
= vega20_ih_toggle_ring_interrupts(adev
, ih
[i
], enable
);
162 static uint32_t vega20_ih_rb_cntl(struct amdgpu_ih_ring
*ih
, uint32_t ih_rb_cntl
)
164 int rb_bufsz
= order_base_2(ih
->ring_size
/ 4);
166 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
,
167 MC_SPACE
, ih
->use_bus_addr
? 1 : 4);
168 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
,
169 WPTR_OVERFLOW_CLEAR
, 1);
170 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
,
171 WPTR_OVERFLOW_ENABLE
, 1);
172 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
, RB_SIZE
, rb_bufsz
);
173 /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register
174 * value is written to memory
176 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
,
177 WPTR_WRITEBACK_ENABLE
, 1);
178 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
, MC_SNOOP
, 1);
179 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
, MC_RO
, 0);
180 ih_rb_cntl
= REG_SET_FIELD(ih_rb_cntl
, IH_RB_CNTL
, MC_VMID
, 0);
185 static uint32_t vega20_ih_doorbell_rptr(struct amdgpu_ih_ring
*ih
)
187 u32 ih_doorbell_rtpr
= 0;
189 if (ih
->use_doorbell
) {
190 ih_doorbell_rtpr
= REG_SET_FIELD(ih_doorbell_rtpr
,
191 IH_DOORBELL_RPTR
, OFFSET
,
193 ih_doorbell_rtpr
= REG_SET_FIELD(ih_doorbell_rtpr
,
197 ih_doorbell_rtpr
= REG_SET_FIELD(ih_doorbell_rtpr
,
201 return ih_doorbell_rtpr
;
205 * vega20_ih_enable_ring - enable an ih ring buffer
207 * @adev: amdgpu_device pointer
208 * @ih: amdgpu_ih_ring pointer
210 * Enable an ih ring buffer (VEGA20)
212 static int vega20_ih_enable_ring(struct amdgpu_device
*adev
,
213 struct amdgpu_ih_ring
*ih
)
215 struct amdgpu_ih_regs
*ih_regs
;
218 ih_regs
= &ih
->ih_regs
;
220 /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
221 WREG32(ih_regs
->ih_rb_base
, ih
->gpu_addr
>> 8);
222 WREG32(ih_regs
->ih_rb_base_hi
, (ih
->gpu_addr
>> 40) & 0xff);
224 tmp
= RREG32(ih_regs
->ih_rb_cntl
);
225 tmp
= vega20_ih_rb_cntl(ih
, tmp
);
226 if (ih
== &adev
->irq
.ih
)
227 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, RPTR_REARM
, !!adev
->irq
.msi_enabled
);
228 if (ih
== &adev
->irq
.ih1
)
229 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, RB_FULL_DRAIN_ENABLE
, 1);
230 if (amdgpu_sriov_vf(adev
)) {
231 if (psp_reg_program(&adev
->psp
, ih_regs
->psp_reg_id
, tmp
)) {
232 dev_err(adev
->dev
, "PSP program IH_RB_CNTL failed!\n");
236 WREG32(ih_regs
->ih_rb_cntl
, tmp
);
239 if (ih
== &adev
->irq
.ih
) {
240 /* set the ih ring 0 writeback address whether it's enabled or not */
241 WREG32(ih_regs
->ih_rb_wptr_addr_lo
, lower_32_bits(ih
->wptr_addr
));
242 WREG32(ih_regs
->ih_rb_wptr_addr_hi
, upper_32_bits(ih
->wptr_addr
) & 0xFFFF);
245 /* set rptr, wptr to 0 */
246 WREG32(ih_regs
->ih_rb_wptr
, 0);
247 WREG32(ih_regs
->ih_rb_rptr
, 0);
249 WREG32(ih_regs
->ih_doorbell_rptr
, vega20_ih_doorbell_rptr(ih
));
255 * vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring
257 * @adev: amdgpu_device pointer
259 * Reroute VMC and UMC interrupts on primary ih ring to
260 * ih ring 1 so they won't lose when bunches of page faults
261 * interrupts overwhelms the interrupt handler(VEGA20)
263 static void vega20_ih_reroute_ih(struct amdgpu_device
*adev
)
267 /* vega20 ih reroute will go through psp this
268 * function is used for newer asics starting arcturus
270 if (adev
->asic_type
>= CHIP_ARCTURUS
) {
271 /* Reroute to IH ring 1 for VMC */
272 WREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_INDEX
, 0x12);
273 tmp
= RREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_DATA
);
274 tmp
= REG_SET_FIELD(tmp
, IH_CLIENT_CFG_DATA
, CLIENT_TYPE
, 1);
275 tmp
= REG_SET_FIELD(tmp
, IH_CLIENT_CFG_DATA
, RING_ID
, 1);
276 WREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_DATA
, tmp
);
278 /* Reroute IH ring 1 for UTCL2 */
279 WREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_INDEX
, 0x1B);
280 tmp
= RREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_DATA
);
281 tmp
= REG_SET_FIELD(tmp
, IH_CLIENT_CFG_DATA
, RING_ID
, 1);
282 WREG32_SOC15(OSSSYS
, 0, mmIH_CLIENT_CFG_DATA
, tmp
);
287 * vega20_ih_irq_init - init and enable the interrupt ring
289 * @adev: amdgpu_device pointer
291 * Allocate a ring buffer for the interrupt controller,
292 * enable the RLC, disable interrupts, enable the IH
293 * ring buffer and enable it (VI).
294 * Called at device load and reume.
295 * Returns 0 for success, errors for failure.
297 static int vega20_ih_irq_init(struct amdgpu_device
*adev
)
299 struct amdgpu_ih_ring
*ih
[] = {&adev
->irq
.ih
, &adev
->irq
.ih1
, &adev
->irq
.ih2
};
305 ret
= vega20_ih_toggle_interrupts(adev
, false);
309 adev
->nbio
.funcs
->ih_control(adev
);
311 if (adev
->asic_type
== CHIP_ARCTURUS
&&
312 adev
->firmware
.load_type
== AMDGPU_FW_LOAD_DIRECT
) {
313 ih_chicken
= RREG32_SOC15(OSSSYS
, 0, mmIH_CHICKEN
);
314 if (adev
->irq
.ih
.use_bus_addr
) {
315 ih_chicken
= REG_SET_FIELD(ih_chicken
, IH_CHICKEN
,
316 MC_SPACE_GPA_ENABLE
, 1);
318 WREG32_SOC15(OSSSYS
, 0, mmIH_CHICKEN
, ih_chicken
);
321 /* psp firmware won't program IH_CHICKEN for aldebaran
322 * driver needs to program it properly according to
323 * MC_SPACE type in IH_RB_CNTL */
324 if (adev
->asic_type
== CHIP_ALDEBARAN
) {
325 ih_chicken
= RREG32_SOC15(OSSSYS
, 0, mmIH_CHICKEN_ALDEBARAN
);
326 if (adev
->irq
.ih
.use_bus_addr
) {
327 ih_chicken
= REG_SET_FIELD(ih_chicken
, IH_CHICKEN
,
328 MC_SPACE_GPA_ENABLE
, 1);
330 WREG32_SOC15(OSSSYS
, 0, mmIH_CHICKEN_ALDEBARAN
, ih_chicken
);
333 for (i
= 0; i
< ARRAY_SIZE(ih
); i
++) {
334 if (ih
[i
]->ring_size
) {
336 vega20_ih_reroute_ih(adev
);
337 ret
= vega20_ih_enable_ring(adev
, ih
[i
]);
343 pci_set_master(adev
->pdev
);
345 /* enable interrupts */
346 ret
= vega20_ih_toggle_interrupts(adev
, true);
350 if (adev
->irq
.ih_soft
.ring_size
)
351 adev
->irq
.ih_soft
.enabled
= true;
357 * vega20_ih_irq_disable - disable interrupts
359 * @adev: amdgpu_device pointer
361 * Disable interrupts on the hw (VEGA20).
363 static void vega20_ih_irq_disable(struct amdgpu_device
*adev
)
365 vega20_ih_toggle_interrupts(adev
, false);
367 /* Wait and acknowledge irq */
372 * vega20_ih_get_wptr - get the IH ring buffer wptr
374 * @adev: amdgpu_device pointer
375 * @ih: amdgpu_ih_ring pointer
377 * Get the IH ring buffer wptr from either the register
378 * or the writeback memory buffer (VEGA20). Also check for
379 * ring buffer overflow and deal with it.
380 * Returns the value of the wptr.
382 static u32
vega20_ih_get_wptr(struct amdgpu_device
*adev
,
383 struct amdgpu_ih_ring
*ih
)
386 struct amdgpu_ih_regs
*ih_regs
;
388 if (ih
== &adev
->irq
.ih
|| ih
== &adev
->irq
.ih_soft
) {
389 /* Only ring0 supports writeback. On other rings fall back
390 * to register-based code with overflow checking below.
391 * ih_soft ring doesn't have any backing hardware registers,
392 * update wptr and return.
394 wptr
= le32_to_cpu(*ih
->wptr_cpu
);
396 if (!REG_GET_FIELD(wptr
, IH_RB_WPTR
, RB_OVERFLOW
))
400 ih_regs
= &ih
->ih_regs
;
402 /* Double check that the overflow wasn't already cleared. */
403 wptr
= RREG32_NO_KIQ(ih_regs
->ih_rb_wptr
);
404 if (!REG_GET_FIELD(wptr
, IH_RB_WPTR
, RB_OVERFLOW
))
407 wptr
= REG_SET_FIELD(wptr
, IH_RB_WPTR
, RB_OVERFLOW
, 0);
409 /* When a ring buffer overflow happen start parsing interrupt
410 * from the last not overwritten vector (wptr + 32). Hopefully
411 * this should allow us to catchup.
413 tmp
= (wptr
+ 32) & ih
->ptr_mask
;
414 dev_warn(adev
->dev
, "IH ring buffer overflow "
415 "(0x%08X, 0x%08X, 0x%08X)\n",
416 wptr
, ih
->rptr
, tmp
);
419 tmp
= RREG32_NO_KIQ(ih_regs
->ih_rb_cntl
);
420 tmp
= REG_SET_FIELD(tmp
, IH_RB_CNTL
, WPTR_OVERFLOW_CLEAR
, 1);
421 WREG32_NO_KIQ(ih_regs
->ih_rb_cntl
, tmp
);
424 return (wptr
& ih
->ptr_mask
);
428 * vega20_ih_irq_rearm - rearm IRQ if lost
430 * @adev: amdgpu_device pointer
431 * @ih: amdgpu_ih_ring pointer
434 static void vega20_ih_irq_rearm(struct amdgpu_device
*adev
,
435 struct amdgpu_ih_ring
*ih
)
439 struct amdgpu_ih_regs
*ih_regs
;
441 ih_regs
= &ih
->ih_regs
;
443 /* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
444 for (i
= 0; i
< MAX_REARM_RETRY
; i
++) {
445 v
= RREG32_NO_KIQ(ih_regs
->ih_rb_rptr
);
446 if ((v
< ih
->ring_size
) && (v
!= ih
->rptr
))
447 WDOORBELL32(ih
->doorbell_index
, ih
->rptr
);
454 * vega20_ih_set_rptr - set the IH ring buffer rptr
456 * @adev: amdgpu_device pointer
457 * @ih: amdgpu_ih_ring pointer
459 * Set the IH ring buffer rptr.
461 static void vega20_ih_set_rptr(struct amdgpu_device
*adev
,
462 struct amdgpu_ih_ring
*ih
)
464 struct amdgpu_ih_regs
*ih_regs
;
466 if (ih
== &adev
->irq
.ih_soft
)
469 if (ih
->use_doorbell
) {
470 /* XXX check if swapping is necessary on BE */
471 *ih
->rptr_cpu
= ih
->rptr
;
472 WDOORBELL32(ih
->doorbell_index
, ih
->rptr
);
474 if (amdgpu_sriov_vf(adev
))
475 vega20_ih_irq_rearm(adev
, ih
);
477 ih_regs
= &ih
->ih_regs
;
478 WREG32(ih_regs
->ih_rb_rptr
, ih
->rptr
);
483 * vega20_ih_self_irq - dispatch work for ring 1 and 2
485 * @adev: amdgpu_device pointer
486 * @source: irq source
487 * @entry: IV with WPTR update
489 * Update the WPTR from the IV and schedule work to handle the entries.
491 static int vega20_ih_self_irq(struct amdgpu_device
*adev
,
492 struct amdgpu_irq_src
*source
,
493 struct amdgpu_iv_entry
*entry
)
495 switch (entry
->ring_id
) {
497 schedule_work(&adev
->irq
.ih1_work
);
500 schedule_work(&adev
->irq
.ih2_work
);
507 static const struct amdgpu_irq_src_funcs vega20_ih_self_irq_funcs
= {
508 .process
= vega20_ih_self_irq
,
511 static void vega20_ih_set_self_irq_funcs(struct amdgpu_device
*adev
)
513 adev
->irq
.self_irq
.num_types
= 0;
514 adev
->irq
.self_irq
.funcs
= &vega20_ih_self_irq_funcs
;
517 static int vega20_ih_early_init(void *handle
)
519 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
521 vega20_ih_set_interrupt_funcs(adev
);
522 vega20_ih_set_self_irq_funcs(adev
);
526 static int vega20_ih_sw_init(void *handle
)
528 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
531 r
= amdgpu_irq_add_id(adev
, SOC15_IH_CLIENTID_IH
, 0,
532 &adev
->irq
.self_irq
);
536 r
= amdgpu_ih_ring_init(adev
, &adev
->irq
.ih
, 256 * 1024, true);
540 adev
->irq
.ih
.use_doorbell
= true;
541 adev
->irq
.ih
.doorbell_index
= adev
->doorbell_index
.ih
<< 1;
543 r
= amdgpu_ih_ring_init(adev
, &adev
->irq
.ih1
, PAGE_SIZE
, true);
547 adev
->irq
.ih1
.use_doorbell
= true;
548 adev
->irq
.ih1
.doorbell_index
= (adev
->doorbell_index
.ih
+ 1) << 1;
550 r
= amdgpu_ih_ring_init(adev
, &adev
->irq
.ih2
, PAGE_SIZE
, true);
554 adev
->irq
.ih2
.use_doorbell
= true;
555 adev
->irq
.ih2
.doorbell_index
= (adev
->doorbell_index
.ih
+ 2) << 1;
557 /* initialize ih control registers offset */
558 vega20_ih_init_register_offset(adev
);
560 r
= amdgpu_ih_ring_init(adev
, &adev
->irq
.ih_soft
, PAGE_SIZE
, true);
564 r
= amdgpu_irq_init(adev
);
569 static int vega20_ih_sw_fini(void *handle
)
571 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
573 amdgpu_irq_fini_sw(adev
);
578 static int vega20_ih_hw_init(void *handle
)
581 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
583 r
= vega20_ih_irq_init(adev
);
590 static int vega20_ih_hw_fini(void *handle
)
592 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
594 vega20_ih_irq_disable(adev
);
599 static int vega20_ih_suspend(void *handle
)
601 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
603 return vega20_ih_hw_fini(adev
);
606 static int vega20_ih_resume(void *handle
)
608 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
610 return vega20_ih_hw_init(adev
);
613 static bool vega20_ih_is_idle(void *handle
)
619 static int vega20_ih_wait_for_idle(void *handle
)
625 static int vega20_ih_soft_reset(void *handle
)
632 static void vega20_ih_update_clockgating_state(struct amdgpu_device
*adev
,
635 uint32_t data
, def
, field_val
;
637 if (adev
->cg_flags
& AMD_CG_SUPPORT_IH_CG
) {
638 def
= data
= RREG32_SOC15(OSSSYS
, 0, mmIH_CLK_CTRL
);
639 field_val
= enable
? 0 : 1;
640 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
641 IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE
, field_val
);
642 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
643 IH_BUFFER_MEM_CLK_SOFT_OVERRIDE
, field_val
);
644 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
645 DBUS_MUX_CLK_SOFT_OVERRIDE
, field_val
);
646 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
647 OSSSYS_SHARE_CLK_SOFT_OVERRIDE
, field_val
);
648 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
649 LIMIT_SMN_CLK_SOFT_OVERRIDE
, field_val
);
650 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
651 DYN_CLK_SOFT_OVERRIDE
, field_val
);
652 data
= REG_SET_FIELD(data
, IH_CLK_CTRL
,
653 REG_CLK_SOFT_OVERRIDE
, field_val
);
655 WREG32_SOC15(OSSSYS
, 0, mmIH_CLK_CTRL
, data
);
659 static int vega20_ih_set_clockgating_state(void *handle
,
660 enum amd_clockgating_state state
)
662 struct amdgpu_device
*adev
= (struct amdgpu_device
*)handle
;
664 vega20_ih_update_clockgating_state(adev
,
665 state
== AMD_CG_STATE_GATE
);
670 static int vega20_ih_set_powergating_state(void *handle
,
671 enum amd_powergating_state state
)
676 const struct amd_ip_funcs vega20_ih_ip_funcs
= {
678 .early_init
= vega20_ih_early_init
,
680 .sw_init
= vega20_ih_sw_init
,
681 .sw_fini
= vega20_ih_sw_fini
,
682 .hw_init
= vega20_ih_hw_init
,
683 .hw_fini
= vega20_ih_hw_fini
,
684 .suspend
= vega20_ih_suspend
,
685 .resume
= vega20_ih_resume
,
686 .is_idle
= vega20_ih_is_idle
,
687 .wait_for_idle
= vega20_ih_wait_for_idle
,
688 .soft_reset
= vega20_ih_soft_reset
,
689 .set_clockgating_state
= vega20_ih_set_clockgating_state
,
690 .set_powergating_state
= vega20_ih_set_powergating_state
,
693 static const struct amdgpu_ih_funcs vega20_ih_funcs
= {
694 .get_wptr
= vega20_ih_get_wptr
,
695 .decode_iv
= amdgpu_ih_decode_iv_helper
,
696 .decode_iv_ts
= amdgpu_ih_decode_iv_ts_helper
,
697 .set_rptr
= vega20_ih_set_rptr
700 static void vega20_ih_set_interrupt_funcs(struct amdgpu_device
*adev
)
702 adev
->irq
.ih_funcs
= &vega20_ih_funcs
;
705 const struct amdgpu_ip_block_version vega20_ih_ip_block
=
707 .type
= AMD_IP_BLOCK_TYPE_IH
,
711 .funcs
= &vega20_ih_ip_funcs
,