1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <config.h>
10#include <basic_types.h>
11#include <machine/interrupt.h>
12
13enum irqNumbers {
14    irqInvalid = 255
15};
16
17/* Memory map for AVIC (Advanced Vectored Interrupt Controller). */
18volatile struct avic_map {
19    uint32_t intctl;
20    uint32_t nimask;
21    uint32_t intennum;
22    uint32_t intdisnum;
23    uint32_t intenableh;
24    uint32_t intenablel;
25    uint32_t inttypeh;
26    uint32_t inttypel;
27    uint32_t nipriority[8];
28    uint32_t nivecsr;
29    uint32_t fivecsr;
30    uint32_t intsrch;
31    uint32_t intsrcl;
32    uint32_t intfrch;
33    uint32_t intfrcl;
34    uint32_t nipndh;
35    uint32_t nipndl;
36    uint32_t fipndh;
37    uint32_t fipndl;
38    uint32_t vector[64];
39} *avic = (volatile void *)AVIC_PPTR;
40
41/* Reading the IRQ number from the nivecsr register also
42 * acks the interrupt. To allow the active irq to be read
43 * multiple times per interrupt received, we store the
44 * current active IRQ in a global variable.
45 */
46extern irq_t active_irq;
47
48/* Get the active IRQ number from the AVIC.  Returns 0xff if
49 * there isn't one. Note this is also known as irqInvalid */
50static inline irq_t getActiveIRQ(void)
51{
52    if (active_irq == irqInvalid) {
53        /* Read the IRQ number from the IRQ controller.
54         * This has the side-effect of acking the interrupt.
55         * Reading from this register after acking the
56         * interrupt will yield an invalid IRQ number, so
57         * we save the IRQ number in a global variable to
58         * allow multiple successive calls to this function.
59         */
60        active_irq = (avic->nivecsr >> 16) & 0xff;
61    }
62
63    return active_irq;
64}
65
66/* Check for pending IRQ */
67static inline bool_t isIRQPending(void)
68{
69    return getActiveIRQ() != irqInvalid;
70}
71
72/* Enable or disable irq according to the 'disable' flag. */
73static inline void maskInterrupt(bool_t disable, irq_t irq)
74{
75    if (disable) {
76        avic->intdisnum = irq;
77    } else {
78        avic->intennum = irq;
79    }
80}
81
82static inline void ackInterrupt(irq_t irq)
83{
84    /* The interrupt was acked when the IRQ number was read from
85     * the IRQ controller in getActiveIRQ. Here we reset the
86     * global active IRQ number so the next call to getActiveIRQ
87     * will read the IRQ number from the IRQ controller.
88     */
89    active_irq = irqInvalid;
90}
91
92static inline void handleSpuriousIRQ(void)
93{
94    /* do nothing */
95}
96
97