1 /*
2 * Copyright (c) 2021 Tokita, Hiroshi <tokita.hiroshi@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @brief Driver for Nuclie's Extended Core Interrupt Controller
9 */
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/arch/cpu.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/device.h>
15 #include <soc.h>
16
17 #include <zephyr/sw_isr_table.h>
18 #include <zephyr/drivers/interrupt_controller/riscv_clic.h>
19
20 #define DT_DRV_COMPAT nuclei_eclic
21
22 union CLICCFG {
23 struct {
24 uint8_t _reserved0 : 1;
25 /** number of interrupt level bits */
26 uint8_t nlbits : 4;
27 uint8_t _reserved1 : 2;
28 uint8_t _reserved2 : 1;
29 } b;
30 uint8_t w;
31 };
32
33 union CLICINFO {
34 struct {
35 /** number of max supported interrupts */
36 uint32_t numint : 13;
37 /** architecture version */
38 uint32_t version : 8;
39 /** supported bits in the clicintctl */
40 uint32_t intctlbits : 4;
41 uint32_t _reserved0 : 7;
42 } b;
43 uint32_t qw;
44 };
45
46 union CLICMTH {
47 uint8_t w;
48 };
49
50 union CLICINTIP {
51 struct {
52 /** Interrupt Pending */
53 uint8_t IP : 1;
54 uint8_t reserved0 : 7;
55 } b;
56 uint8_t w;
57 };
58
59 union CLICINTIE {
60 struct {
61 /** Interrupt Enabled */
62 uint8_t IE : 1;
63 uint8_t reserved0 : 7;
64 } b;
65 uint8_t w;
66 };
67
68 union CLICINTATTR {
69 struct {
70 /** 0: non-vectored 1:vectored */
71 uint8_t shv : 1;
72 /** 0: level 1: rising edge 2: falling edge */
73 uint8_t trg : 2;
74 uint8_t reserved0 : 3;
75 uint8_t reserved1 : 2;
76 } b;
77 uint8_t w;
78 };
79
80 struct CLICCTRL {
81 volatile union CLICINTIP INTIP;
82 volatile union CLICINTIE INTIE;
83 volatile union CLICINTATTR INTATTR;
84 volatile uint8_t INTCTRL;
85 };
86
87 /** ECLIC Mode mask for MTVT CSR Register */
88 #define ECLIC_MODE_MTVEC_Msk 3U
89
90 /** CLIC INTATTR: TRIG Position */
91 #define CLIC_INTATTR_TRIG_Pos 1U
92 /** CLIC INTATTR: TRIG Mask */
93 #define CLIC_INTATTR_TRIG_Msk (0x3UL << CLIC_INTATTR_TRIG_Pos)
94
95 #define ECLIC_CFG (*((volatile union CLICCFG *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 0))))
96 #define ECLIC_INFO (*((volatile union CLICINFO *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 1))))
97 #define ECLIC_MTH (*((volatile union CLICMTH *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 2))))
98 #define ECLIC_CTRL ((volatile struct CLICCTRL *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 3)))
99 #define ECLIC_CTRL_SIZE (DT_REG_SIZE_BY_IDX(DT_NODELABEL(eclic), 3))
100
101 #if CONFIG_3RD_LEVEL_INTERRUPTS
102 #define INTERRUPT_LEVEL 2
103 #elif CONFIG_2ND_LEVEL_INTERRUPTS
104 #define INTERRUPT_LEVEL 1
105 #else
106 #define INTERRUPT_LEVEL 0
107 #endif
108
109 static uint8_t nlbits;
110 static uint8_t intctlbits;
111 static uint8_t max_prio;
112 static uint8_t max_level;
113 static uint8_t intctrl_mask;
114
leftalign8(uint8_t val,uint8_t shift)115 static inline uint8_t leftalign8(uint8_t val, uint8_t shift)
116 {
117 return (val << (8U - shift));
118 }
119
mask8(uint8_t len)120 static inline uint8_t mask8(uint8_t len)
121 {
122 return ((1 << len) - 1) & 0xFFFFU;
123 }
124
125 /**
126 * @brief Enable interrupt
127 */
riscv_clic_irq_enable(uint32_t irq)128 void riscv_clic_irq_enable(uint32_t irq)
129 {
130 ECLIC_CTRL[irq].INTIE.b.IE = 1;
131 }
132
133 /**
134 * @brief Disable interrupt
135 */
riscv_clic_irq_disable(uint32_t irq)136 void riscv_clic_irq_disable(uint32_t irq)
137 {
138 ECLIC_CTRL[irq].INTIE.b.IE = 0;
139 }
140
141 /**
142 * @brief Get enable status of interrupt
143 */
riscv_clic_irq_is_enabled(uint32_t irq)144 int riscv_clic_irq_is_enabled(uint32_t irq)
145 {
146 return ECLIC_CTRL[irq].INTIE.b.IE;
147 }
148
149 /**
150 * @brief Set priority and level of interrupt
151 */
riscv_clic_irq_priority_set(uint32_t irq,uint32_t pri,uint32_t flags)152 void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags)
153 {
154 const uint8_t prio = leftalign8(MIN(pri, max_prio), intctlbits);
155 const uint8_t level = leftalign8(MIN((irq_get_level(irq) - 1), max_level), nlbits);
156 const uint8_t intctrl = (prio | level) | (~intctrl_mask);
157
158 ECLIC_CTRL[irq].INTCTRL = intctrl;
159
160 ECLIC_CTRL[irq].INTATTR.b.shv = 0;
161 ECLIC_CTRL[irq].INTATTR.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk);
162 }
163
nuclei_eclic_init(const struct device * dev)164 static int nuclei_eclic_init(const struct device *dev)
165 {
166 /* check hardware support required interrupt levels */
167 __ASSERT_NO_MSG(ECLIC_INFO.b.intctlbits >= INTERRUPT_LEVEL);
168
169 ECLIC_MTH.w = 0;
170 ECLIC_CFG.w = 0;
171 ECLIC_CFG.b.nlbits = INTERRUPT_LEVEL;
172 for (int i = 0; i < ECLIC_CTRL_SIZE; i++) {
173 ECLIC_CTRL[i] = (struct CLICCTRL) { 0 };
174 }
175
176 csr_write(mtvec, ((csr_read(mtvec) & 0xFFFFFFC0) | ECLIC_MODE_MTVEC_Msk));
177
178 nlbits = ECLIC_CFG.b.nlbits;
179 intctlbits = ECLIC_INFO.b.intctlbits;
180 max_prio = mask8(intctlbits - nlbits);
181 max_level = mask8(nlbits);
182 intctrl_mask = leftalign8(mask8(intctlbits), intctlbits);
183
184 return 0;
185 }
186
187 DEVICE_DT_INST_DEFINE(0, nuclei_eclic_init, NULL, NULL, NULL,
188 PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
189