1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <autoconf.h>
10#include <stdint.h>
11#include <machine/interrupt.h>
12
13/* Shift positions for GICD_SGIR register */
14#define GICD_SGIR_SGIINTID_SHIFT          0
15#define GICD_SGIR_CPUTARGETLIST_SHIFT     16
16#define GICD_SGIR_TARGETLISTFILTER_SHIFT  24
17
18/* Special IRQ's */
19#define SPECIAL_IRQ_START 1020u
20#define IRQ_NONE          1023u
21
22/* CPU specific IRQ's */
23#define SGI_START         0u
24#define PPI_START         16u
25
26/* Shared Peripheral Interrupts */
27#define SPI_START         32u
28
29#define NUM_PPI SPI_START
30#define HW_IRQ_IS_SGI(irq) ((irq) < PPI_START)
31#define HW_IRQ_IS_PPI(irq) ((irq) < NUM_PPI)
32
33#if defined ENABLE_SMP_SUPPORT
34/* In this case irq_t is a struct with an hw irq field and target core field.
35 * The following macros convert between (target_core, hw_irq) <-> irq_t <-> cnode index.
36 * IRQ_IS_PPI returns true if hw_irq < 32 which is a property of the GIC.
37 * The layout of IRQs into the CNode are all of PPI's for each core first, followed
38 * by the global interrupts.  Examples:
39 *   core: 0, irq: 12 -> index 12.
40 *   core: 2, irq: 16 -> (2 * 32) + 12
41 *   core: 1, irq: 33, (4 total cores) -> (4 * 32) + (33-32).
42 */
43#define IRQ_IS_PPI(_irq) (HW_IRQ_IS_PPI(_irq.irq))
44#define CORE_IRQ_TO_IRQT(tgt, _irq) ((irq_t){.irq = (_irq), .target_core = (tgt)})
45#define IRQT_TO_IDX(_irq) (HW_IRQ_IS_PPI(_irq.irq) ? \
46                                 (irq.target_core)*NUM_PPI + (_irq.irq) : \
47                                 (CONFIG_MAX_NUM_NODES-1)*NUM_PPI + (_irq.irq))
48
49#define IDX_TO_IRQT(idx) (((idx) < NUM_PPI*CONFIG_MAX_NUM_NODES) ? \
50                        CORE_IRQ_TO_IRQT((idx) / NUM_PPI, (idx) - ((idx)/NUM_PPI)*NUM_PPI): \
51                        CORE_IRQ_TO_IRQT(0, (idx) - (CONFIG_MAX_NUM_NODES-1)*NUM_PPI))
52#define IRQT_TO_CORE(irqt) (irqt.target_core)
53#define IRQT_TO_IRQ(irqt) (irqt.irq)
54irq_t irqInvalid = CORE_IRQ_TO_IRQT(-1, -1);
55
56#else
57#define IRQ_IS_PPI(irq) HW_IRQ_IS_PPI(irq)
58irq_t irqInvalid = (uint16_t) -1;
59#endif
60
61/* Setters/getters helpers for hardware irqs */
62#define IRQ_REG(IRQ) ((IRQ) >> 5u)
63#define IRQ_BIT(IRQ) ((IRQ) & 0x1f)
64#define IS_IRQ_VALID(X) (((X) & IRQ_MASK) < SPECIAL_IRQ_START)
65
66/*
67 * The only sane way to get an GIC IRQ number that can be properly
68 * ACKED later is through the int_ack register. Unfortunately, reading
69 * this register changes the interrupt state to pending so future
70 * reads will not return the same value For this reason, we have a
71 * global variable to store the IRQ number.
72 */
73extern word_t active_irq[CONFIG_MAX_NUM_NODES];
74
75static inline void handleSpuriousIRQ(void)
76{
77}
78
79void initIRQController(void);
80
81
82