Skip to content

Commit d419e49

Browse files
committed
drivers: interrupt_controller: Xilinx AXI Interrupt Controller Driver
Internal references: FWRIVERHD-4976,FWRIVERHD-4981 Signed-off-by: Alp Sayin <alpsayin@gmail.com>
1 parent a8af0c3 commit d419e49

File tree

5 files changed

+266
-0
lines changed

5 files changed

+266
-0
lines changed

drivers/interrupt_controller/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c)
3434
zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c)
3535
zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c)
3636
zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c)
37+
zephyr_library_sources_ifdef(CONFIG_XLNX_INTC intc_xlnx.c)
3738

3839
if(CONFIG_INTEL_VTD_ICTL)
3940
zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include)

drivers/interrupt_controller/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,6 @@ source "drivers/interrupt_controller/Kconfig.xmc4xxx"
100100

101101
source "drivers/interrupt_controller/Kconfig.nxp_pint"
102102

103+
source "drivers/interrupt_controller/Kconfig.xlnx"
104+
103105
endmenu
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright (c) 2023 Advanced Micro Devices, Inc. (AMD)
2+
# Copyright (c) 2023 Alp Sayin <alpsayin@gmail.com>
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
6+
if MICROBLAZE
7+
8+
config XLNX_INTC
9+
bool
10+
help
11+
The AXI Interrupt Controller (INTC) works with MICROBLAZE processor.
12+
13+
menu "AXI Interrupt Controller Optional Registers"
14+
depends on XLNX_INTC
15+
16+
config XLNX_INTC_USE_IPR
17+
bool "Use Interrupt Pending Register"
18+
help
19+
Each bit in this register is the logical AND of the bits in the ISR and the IER.
20+
This is an optional read-only register. Don't choose to use it if it doesn't exist.
21+
22+
config XLNX_INTC_USE_SIE
23+
bool "Use Set Interrupt Enables Register"
24+
help
25+
Writing a 1 to a bit location in SIE sets the corresponding bit in the IER.
26+
This is an optional write-only register. Don't choose to use it if it doesn't exist.
27+
28+
config XLNX_INTC_USE_CIE
29+
bool "Use Clear Interrupt Enables Register"
30+
help
31+
Writing a 1 to a bit location in CIE clears the corresponding bit in the IER.
32+
This is an optional write-only register. Don't choose to use it if it doesn't exist.
33+
34+
config XLNX_INTC_USE_IVR
35+
bool "Use Interrupt Vector Register"
36+
help
37+
The IVR contains the ordinal value of the highest priority, enabled, and active interrupt input.
38+
The IVR acts as an index to the correct Interrupt Vector Address.
39+
This is an optional read-only register. Don't choose to use it if it doesn't exist.
40+
41+
config XLNX_INTC_INITIALIZE_IVAR_REGISTERS
42+
bool "Initialize Interrupt Vector Address Registers"
43+
help
44+
The IVAR contains the addresses for fast-interrupts. This flag enables initializing all
45+
the address registers to point them to default interrupt handler which is `0x10` for Microblaze.
46+
47+
endmenu
48+
49+
endif # MICROBLAZE
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright (c) 2023 Advanced Micro Devices, Inc. (AMD)
3+
* Copyright (c) 2023 Alp Sayin <alpsayin@gmail.com>
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
/*
9+
* This file implements AXI Interrupt Controller (INTC)
10+
* For more details about the INTC see PG 099
11+
*
12+
* The functionality has been based on intc_v3_12 package
13+
*
14+
* Right now the implementation:
15+
* - does not support fast interrupt mode
16+
* - does not support Cascade mode
17+
* - does not support XIN_SVC_SGL_ISR_OPTION
18+
*/
19+
20+
#include <errno.h>
21+
#include <zephyr/sys/__assert.h>
22+
#include <zephyr/devicetree.h>
23+
#include <zephyr/init.h>
24+
#include <zephyr/sys/atomic.h>
25+
#include <zephyr/sys_clock.h>
26+
#include <zephyr/arch/cpu.h>
27+
#include <soc.h>
28+
29+
#define DT_DRV_COMPAT xlnx_intc
30+
31+
#define SOC_INTC_DEVICE_ID 0
32+
33+
#define BASE_ADDRESS DT_INST_REG_ADDR(SOC_INTC_DEVICE_ID)
34+
#define INTC_REG(offset) (uint32_t *)(BASE_ADDRESS + offset)
35+
36+
#define xlnx_intc_read(offset) sys_read32(BASE_ADDRESS + offset)
37+
#define xlnx_intc_write(data, offset) sys_write32(data, BASE_ADDRESS + offset)
38+
39+
#define XIN_SVC_SGL_ISR_OPTION 1UL
40+
#define XIN_SVC_ALL_ISRS_OPTION 2UL
41+
42+
#define XIN_ISR_OFFSET 0 /* Interrupt Status Register */
43+
#define XIN_IPR_OFFSET 4 /* Interrupt Pending Register */
44+
#define XIN_IER_OFFSET 8 /* Interrupt Enable Register */
45+
#define XIN_IAR_OFFSET 12 /* Interrupt Acknowledge Register */
46+
#define XIN_SIE_OFFSET 16 /* Set Interrupt Enable Register */
47+
#define XIN_CIE_OFFSET 20 /* Clear Interrupt Enable Register */
48+
#define XIN_IVR_OFFSET 24 /* Interrupt Vector Register */
49+
#define XIN_MER_OFFSET 28 /* Master Enable Register */
50+
#define XIN_IMR_OFFSET 32 /* Interrupt Mode Register , this is present only for Fast Interrupt */
51+
#define XIN_IVAR_OFFSET \
52+
0x100 /* Interrupt Vector Address Register , this is present only for Fast Interrupt */
53+
54+
/* Bit definitions for the bits of the MER register */
55+
56+
#define XIN_INT_MASTER_ENABLE_MASK 0x1UL
57+
#define XIN_INT_HARDWARE_ENABLE_MASK 0x2UL /* once set cannot be cleared */
58+
59+
#define MICROBLAZE_INTERRUPT_VECTOR_ADDRESS 0x10 /* set it to standard interrupt vector */
60+
61+
struct xlnx_intc_state {
62+
bool is_ready; /**< Device is initialized and ready */
63+
bool is_started; /**< Device has been started */
64+
};
65+
66+
static struct xlnx_intc_state intc_state = {
67+
.is_ready = false,
68+
.is_started = false,
69+
};
70+
71+
uint32_t xlnx_intc_irq_get_enabled(void)
72+
{
73+
return xlnx_intc_read(XIN_IER_OFFSET);
74+
}
75+
76+
uint32_t xlnx_intc_get_status_register(void)
77+
{
78+
return xlnx_intc_read(XIN_ISR_OFFSET);
79+
}
80+
81+
uint32_t xlnx_intc_irq_pending(void)
82+
{
83+
#if defined(CONFIG_XLNX_INTC_USE_IPR)
84+
return xlnx_intc_read(XIN_IPR_OFFSET);
85+
#else
86+
uint32_t enabled = xlnx_intc_irq_get_enabled();
87+
uint32_t interrupt_status_register = xlnx_intc_get_status_register();
88+
89+
return enabled & interrupt_status_register;
90+
#endif
91+
}
92+
93+
uint32_t xlnx_intc_irq_pending_vector(void)
94+
{
95+
#if defined(CONFIG_XLNX_INTC_USE_IVR)
96+
return xlnx_intc_read(XIN_IVR_OFFSET);
97+
#else
98+
return find_lsb_set(xlnx_intc_irq_pending()) - 1;
99+
#endif
100+
}
101+
102+
void xlnx_intc_irq_enable(uint32_t irq)
103+
{
104+
__ASSERT_NO_MSG(irq < 32);
105+
106+
uint32_t mask = BIT(irq);
107+
108+
#if defined(CONFIG_XLNX_INTC_USE_SIE)
109+
xlnx_intc_write(mask, XIN_SIE_OFFSET);
110+
#else
111+
atomic_or((atomic_t *)INTC_REG(XIN_IER_OFFSET), mask);
112+
#endif /* CONFIG_XLNX_INTC_USE_SIE */
113+
}
114+
115+
void xlnx_intc_irq_disable(uint32_t irq)
116+
{
117+
__ASSERT_NO_MSG(irq < 32);
118+
119+
uint32_t mask = BIT(irq);
120+
121+
#if defined(CONFIG_XLNX_INTC_USE_CIE)
122+
xlnx_intc_write(mask, XIN_CIE_OFFSET);
123+
#else
124+
atomic_and((atomic_t *)INTC_REG(XIN_IER_OFFSET), ~mask);
125+
#endif /* CONFIG_XLNX_INTC_USE_CIE */
126+
}
127+
128+
void xlnx_intc_irq_acknowledge(uint32_t mask)
129+
{
130+
xlnx_intc_write(mask, XIN_IAR_OFFSET);
131+
}
132+
133+
int32_t xlnx_intc_controller_init(uint16_t device_id)
134+
{
135+
if (intc_state.is_started == true) {
136+
return -EEXIST;
137+
}
138+
139+
/*
140+
* Disable IRQ output signal
141+
* Disable all interrupt sources
142+
* Acknowledge all sources
143+
* Disable fast interrupt mode
144+
*/
145+
xlnx_intc_write(0, XIN_MER_OFFSET);
146+
xlnx_intc_write(0, XIN_IER_OFFSET);
147+
xlnx_intc_write(0xFFFFFFFF, XIN_IAR_OFFSET);
148+
149+
#if defined(CONFIG_XLNX_INTC_INITIALIZE_IVAR_REGISTERS)
150+
xlnx_intc_write(0, XIN_IMR_OFFSET);
151+
152+
for (int idx = 0; idx < 32; idx++) {
153+
xlnx_intc_write(0x10, XIN_IVAR_OFFSET + (idx * 4));
154+
}
155+
#endif
156+
157+
intc_state.is_ready = true;
158+
159+
return 0;
160+
}
161+
162+
int32_t xlnx_intc_irq_start(void)
163+
{
164+
if (intc_state.is_started != false) {
165+
return -EEXIST;
166+
}
167+
if (intc_state.is_ready != true) {
168+
return -ENOENT;
169+
}
170+
171+
intc_state.is_started = true;
172+
173+
uint32_t enable_mask = (XIN_INT_MASTER_ENABLE_MASK | XIN_INT_HARDWARE_ENABLE_MASK);
174+
175+
xlnx_intc_write(enable_mask, XIN_MER_OFFSET);
176+
177+
return 0;
178+
}
179+
180+
static int xlnx_intc_interrupt_init(void)
181+
{
182+
int32_t status = xlnx_intc_controller_init(SOC_INTC_DEVICE_ID);
183+
184+
if (status != 0) {
185+
return status;
186+
}
187+
188+
status = xlnx_intc_irq_start();
189+
190+
return status;
191+
}
192+
193+
SYS_INIT(xlnx_intc_interrupt_init, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2023 Advanced Micro Devices, Inc. (AMD)
2+
# Copyright (c) 2023 Alp Sayin <alpsayin@gmail.com>
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
6+
description: Xilinx AXI Interrupt Controller
7+
8+
compatible: "xlnx,intc"
9+
10+
include: [interrupt-controller.yaml, base.yaml]
11+
12+
properties:
13+
reg:
14+
required: true
15+
16+
"#interrupt-cells":
17+
const: 2
18+
19+
interrupt-cells:
20+
- irq
21+
- priority

0 commit comments

Comments
 (0)