1178476Sjb/*
2178476Sjb * Copyright 2014, General Dynamics C4 Systems
3178476Sjb *
4178476Sjb * SPDX-License-Identifier: GPL-2.0-only
5178476Sjb */
6178476Sjb
7178476Sjb#pragma once
8178476Sjb
9178476Sjb#include <config.h>
10178476Sjb#include <basic_types.h>
11178476Sjb#include <machine/interrupt.h>
12178476Sjb
13178476Sjbenum irqNumbers {
14178476Sjb    irqInvalid = 255
15178476Sjb};
16178476Sjb
17178476Sjb/* Memory map for AVIC (Advanced Vectored Interrupt Controller). */
18178476Sjbvolatile struct avic_map {
19178476Sjb    uint32_t intctl;
20178476Sjb    uint32_t nimask;
21178476Sjb    uint32_t intennum;
22178476Sjb    uint32_t intdisnum;
23178476Sjb    uint32_t intenableh;
24178476Sjb    uint32_t intenablel;
25178476Sjb    uint32_t inttypeh;
26178476Sjb    uint32_t inttypel;
27178476Sjb    uint32_t nipriority[8];
28178476Sjb    uint32_t nivecsr;
29178476Sjb    uint32_t fivecsr;
30178476Sjb    uint32_t intsrch;
31178476Sjb    uint32_t intsrcl;
32178476Sjb    uint32_t intfrch;
33178476Sjb    uint32_t intfrcl;
34178476Sjb    uint32_t nipndh;
35178476Sjb    uint32_t nipndl;
36178476Sjb    uint32_t fipndh;
37178476Sjb    uint32_t fipndl;
38178476Sjb    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