1 /*
2  * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #include <util.h>
8 #include <stdint.h>
9 #include <plat/machine.h>
initIRQController(void)10 BOOT_CODE void initIRQController(void)
11 {
12     /* Disable all interrupts */
13     intc_regs->bfDisableIRQs[0] = 0xffffffff;
14     intc_regs->bfDisableIRQs[1] = 0xffffffff;
15     intc_regs->bfDisableBasicIRQs = 0xffffffff;
16     /* Disable FIQ */
17     intc_regs->FIQ_control &= ~FIQCTRL_FIQ_ENABLE;
18     /* Enable IRQ control for GPU */
19     intc_regs->bfEnableBasicIRQs = BIT(INTERRUPT_BASIC_IRQ_PENDING_REGISTER1 - BASIC_IRQ_OFFSET);
20     intc_regs->bfEnableBasicIRQs = BIT(INTERRUPT_BASIC_IRQ_PENDING_REGISTER2 - BASIC_IRQ_OFFSET);
21 
22     core_regs->coreTimerPrescaler = 0x80000000;
23 }
24 
cpu_initLocalIRQController(void)25 BOOT_CODE void cpu_initLocalIRQController(void) {}
26 
getActiveIRQ(void)27 static inline irq_t getActiveIRQ(void)
28 {
29     uint32_t pending;
30     uint32_t irq;
31     /* Read core interrupt register */
32     pending = core_regs->coreIRQSource[0];
33     /* Mask out invalid bits */
34     pending &= MASK(12);
35     /* If pending == 0 spurious interrupt */
36     if (pending == 0) {
37         return irqInvalid;
38     }
39 
40     /* Get IRQ number */
41     irq = (wordBits - 1 - clzl(pending));
42     if (irq != INTERRUPT_CORE_GPU) {
43         return irq;
44     }
45 
46     /* GPU interrupt */
47     pending = intc_regs->bfIRQBasicPending;
48     pending &= intc_regs->bfEnableBasicIRQs;
49     /* Mask out pending register 0 and 1 */
50     pending &= ~BIT(INTERRUPT_BASIC_IRQ_PENDING_REGISTER1 - BASIC_IRQ_OFFSET);
51     pending &= ~BIT(INTERRUPT_BASIC_IRQ_PENDING_REGISTER2 - BASIC_IRQ_OFFSET);
52     if (pending) {
53         return (wordBits - 1 - clzl(pending)) + BASIC_IRQ_OFFSET;
54     }
55 
56     pending = intc_regs->bfGPUIRQPending[1];
57     pending &= intc_regs->bfEnableIRQs[1];
58     if (pending) {
59         return (wordBits - 1 - clzl(pending)) + 32 + NORMAL_IRQ_OFFSET;
60     }
61     pending = intc_regs->bfGPUIRQPending[0];
62     pending &= intc_regs->bfEnableIRQs[0];
63     if (pending) {
64         return (wordBits - 1 - clzl(pending)) + 0 + NORMAL_IRQ_OFFSET;
65     }
66 
67     return irqInvalid;
68 }
69 
maskInterrupt(bool_t disable,irq_t irq)70 static inline void maskInterrupt(bool_t disable, irq_t irq)
71 {
72     switch (irq) {
73     case INTERRUPT_CORE_CNTPSIRQ :
74     case INTERRUPT_CORE_CNTPNSIRQ:
75     case INTERRUPT_CORE_CNTHPIRQ :
76     case INTERRUPT_CORE_CNTVIRQ  :
77         if (disable) {
78             core_regs->coreTimersIrqCtrl[0] &= ~BIT(irq);
79         } else {
80             core_regs->coreTimersIrqCtrl[0] |= BIT(irq);
81         }
82         return;
83     case INTERRUPT_CORE_MAILBOX_0:
84     case INTERRUPT_CORE_MAILBOX_1:
85     case INTERRUPT_CORE_MAILBOX_2:
86     case INTERRUPT_CORE_MAILBOX_3:
87         if (disable) {
88             core_regs->coreMailboxesIrqCtrl[0] &= ~BIT(irq);
89         } else {
90             core_regs->coreMailboxesIrqCtrl[0] |= BIT(irq);
91         }
92         return;
93     case INTERRUPT_CORE_LOCAL_TIMER:
94         if (disable) {
95             core_regs->localTimerCtl &= ~BIT(LOCAL_TIMER_CTRL_IRQ_BIT);
96         } else {
97             core_regs->localTimerCtl |= BIT(LOCAL_TIMER_CTRL_IRQ_BIT);
98         }
99         return;
100     case INTERRUPT_CORE_GPU:
101     // Not maskable
102     case INTERRUPT_CORE_PMU:
103     // Not currently handled
104     case INTERRUPT_CORE_AXI:
105         // Not currently handled
106         return;
107     default:
108         break;
109     }
110     if (irq < BASIC_IRQ_OFFSET) {
111         // Other invalid irq
112         return;
113     }
114 
115     if (irq < NORMAL_IRQ_OFFSET) {
116         if (disable) {
117             intc_regs->bfDisableBasicIRQs = BIT(irq - BASIC_IRQ_OFFSET);
118         } else {
119             intc_regs->bfEnableBasicIRQs = BIT(irq - BASIC_IRQ_OFFSET);
120         }
121     } else if (irq < maxIRQ) {
122         int normal_irq = irq - NORMAL_IRQ_OFFSET;
123         int index = normal_irq / 32;
124         if (disable) {
125             intc_regs->bfDisableIRQs[index] = BIT(normal_irq % 32);
126         } else {
127             intc_regs->bfEnableIRQs[index] = BIT(normal_irq % 32);
128         }
129     }
130 }
131