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