blob: 3304c1add1335280f0cc26ed0f1306d81a741522 [file] [log] [blame]
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +08001/*
2 * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7#include <stdio.h>
8#include "interrupt_control.h"
9#include "common.h"
10#include "riscv_encoding.h"
11#include "register.h"
12
13 // Configure PMP to make all the address space accesable and executable
14void eclic_init ( uint32_t num_irq )
15{
16
17 typedef volatile uint32_t vuint32_t;
18
19 //clear cfg register
20 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET) = 0;
21
22 //clear minthresh register
23 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET) = 0;
24
25 //clear all IP/IE/ATTR/CTRL bits for all interrupt sources
26 vuint32_t * ptr;
27
28 vuint32_t * base = (vuint32_t*)(ECLIC_ADDR_BASE + ECLIC_INT_IP_OFFSET);
29 vuint32_t * upper = (vuint32_t*)(base + num_irq*4);
30
31 for (ptr = base; ptr < upper; ptr=ptr+4) {
32 *ptr = 0;
33 }
34
35 clean_int_src();
36}
37
38void print_eclic(void)
39{
40 typedef volatile uint32_t vuint32_t;
41
42 vuint32_t * ptr = (vuint32_t*)(ECLIC_ADDR_BASE + ECLIC_INT_IP_OFFSET + 7*4);
43
44 printf("\nTIME=0x%lx\n",*ptr);
45}
46
47
48void eclic_enable_interrupt (uint32_t source) {
49 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IE_OFFSET+source*4) = 1;
50}
51
52void eclic_disable_interrupt (uint32_t source){
53 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IE_OFFSET+source*4) = 0;
54}
55
56void eclic_set_pending(uint32_t source){
57 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IP_OFFSET+source*4) = 1;
58}
59
60void eclic_clear_pending(uint32_t source){
61 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IP_OFFSET+source*4) = 0;
62}
63
64void eclic_set_intctrl (uint32_t source, uint8_t intctrl){
65 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_CTRL_OFFSET+source*4) = intctrl;
66}
67
68uint8_t eclic_get_intctrl (uint32_t source){
69 return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_CTRL_OFFSET+source*4);
70}
71
72void eclic_set_intattr (uint32_t source, uint8_t intattr){
73 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_ATTR_OFFSET+source*4) = intattr;
74}
75
76uint8_t eclic_get_intattr (uint32_t source){
77 return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_ATTR_OFFSET+source*4);
78}
79
80void eclic_set_cliccfg (uint8_t cliccfg){
81 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET) = cliccfg;
82}
83
84uint8_t eclic_get_cliccfg (void){
85 return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET);
86}
87
88void eclic_set_mth (uint8_t mth){
89 *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET) = mth;
90}
91
92uint8_t eclic_get_mth (void){
93 return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET);
94}
95
96//sets nlbits
97void eclic_set_nlbits(uint8_t nlbits) {
98 //shift nlbits to correct position
99 uint8_t nlbits_shifted = nlbits << ECLIC_CFG_NLBITS_LSB;
100
101 //read the current cliccfg
102 uint8_t old_cliccfg = eclic_get_cliccfg();
103 uint8_t new_cliccfg = (old_cliccfg & (~ECLIC_CFG_NLBITS_MASK)) | (ECLIC_CFG_NLBITS_MASK & nlbits_shifted);
104
105 eclic_set_cliccfg(new_cliccfg);
106}
107
108//get nlbits
109uint8_t eclic_get_nlbits(void) {
110 //extract nlbits
111 uint8_t nlbits = eclic_get_cliccfg();
112 nlbits = (nlbits & ECLIC_CFG_NLBITS_MASK) >> ECLIC_CFG_NLBITS_LSB;
113 return nlbits;
114}
115
116//sets an interrupt level based encoding of nlbits and CLICINTCTLBITS
117void eclic_set_irq_lvl(uint32_t source, uint8_t lvl) {
118 //extract nlbits
119 uint8_t nlbits = eclic_get_nlbits();
120 if (nlbits > CLICINTCTLBITS) {
121 nlbits = CLICINTCTLBITS;
122 }
123
124 //shift lvl right to mask off unused bits
125 lvl = lvl >> (8-nlbits);
126 //shift lvl into correct bit position
127 lvl = lvl << (8-nlbits);
128
129 //write to clicintctrl
130 uint8_t current_intctrl = eclic_get_intctrl(source);
131 //shift intctrl left to mask off unused bits
132 current_intctrl = current_intctrl << nlbits;
133 //shift intctrl into correct bit position
134 current_intctrl = current_intctrl >> nlbits;
135
136 eclic_set_intctrl(source, (current_intctrl | lvl));
137}
138
139//gets an interrupt level based encoding of nlbits
140uint8_t eclic_get_irq_lvl(uint32_t source) {
141 //extract nlbits
142 uint8_t nlbits = eclic_get_nlbits();
143 if (nlbits > CLICINTCTLBITS) {
144 nlbits = CLICINTCTLBITS;
145 }
146
147 uint8_t intctrl = eclic_get_intctrl(source);
148
149 //shift intctrl
150 intctrl = intctrl >> (8-nlbits);
151 //shift intctrl
152 uint8_t lvl = intctrl << (8-nlbits);
153
154 return lvl;
155}
156
157void eclic_set_irq_lvl_abs(uint32_t source, uint8_t lvl_abs) {
158 //extract nlbits
159 uint8_t nlbits = eclic_get_nlbits();
160 if (nlbits > CLICINTCTLBITS) {
161 nlbits = CLICINTCTLBITS;
162 }
163
164 //shift lvl_abs into correct bit position
165 uint8_t lvl = lvl_abs << (8-nlbits);
166
167 //write to clicintctrl
168 uint8_t current_intctrl = eclic_get_intctrl(source);
169 //shift intctrl left to mask off unused bits
170 current_intctrl = current_intctrl << nlbits;
171 //shift intctrl into correct bit position
172 current_intctrl = current_intctrl >> nlbits;
173
174 eclic_set_intctrl(source, (current_intctrl | lvl));
175}
176
177uint8_t eclic_get_irq_lvl_abs(uint32_t source) {
178 //extract nlbits
179 uint8_t nlbits = eclic_get_nlbits();
180 if (nlbits > CLICINTCTLBITS) {
181 nlbits = CLICINTCTLBITS;
182 }
183
184 uint8_t intctrl = eclic_get_intctrl(source);
185
186 //shift intctrl
187 intctrl = intctrl >> (8-nlbits);
188 //shift intctrl
189 uint8_t lvl_abs = intctrl;
190
191 return lvl_abs;
192}
193
194void eclic_set_irq_pri(uint32_t source, uint8_t pri) {
195 //extract nlbits
196 uint8_t nlbits = eclic_get_nlbits();
197 if (nlbits > CLICINTCTLBITS) {
198 nlbits = CLICINTCTLBITS;
199 }
200
201 //write to clicintctrl
202 uint8_t current_intctrl = eclic_get_intctrl(source);
203 //shift intctrl left to mask off unused bits
204 current_intctrl = current_intctrl >> (8 - nlbits);
205 //shift intctrl into correct bit position
206 current_intctrl = current_intctrl << (8 - nlbits);
207
208 eclic_set_intctrl(source, (current_intctrl | pri));
209}
210
211void eclic_mode_enable(void) {
212 uint32_t mtvec_value = read_csr(mtvec);
213 mtvec_value = mtvec_value & 0xFFFFFFC0;
214 mtvec_value = mtvec_value | 0x00000003;
215 write_csr(mtvec,mtvec_value);
216}
217
218//sets vector-mode or non-vector mode
219void eclic_set_vmode(uint32_t source) {
220 //read the current attr
221 uint8_t old_intattr = eclic_get_intattr(source);
222 // Keep other bits unchanged and only set the LSB bit
223 uint8_t new_intattr = (old_intattr | 0x1);
224
225 eclic_set_intattr(source,new_intattr);
226}
227
228void eclic_set_nonvmode(uint32_t source) {
229 //read the current attr
230 uint8_t old_intattr = eclic_get_intattr(source);
231 // Keep other bits unchanged and only clear the LSB bit
232 uint8_t new_intattr = (old_intattr & (~0x1));
233
234 eclic_set_intattr(source,new_intattr);
235}
236
237//sets interrupt as level sensitive
238//Bit 1, trig[0], is defined as "edge-triggered" (0: level-triggered, 1: edge-triggered);
239//Bit 2, trig[1], is defined as "negative-edge" (0: positive-edge, 1: negative-edge).
240
241void eclic_set_level_trig(uint32_t source) {
242 //read the current attr
243 uint8_t old_intattr = eclic_get_intattr(source);
244 // Keep other bits unchanged and only clear the bit 1
245 uint8_t new_intattr = (old_intattr & (~0x2));
246
247 eclic_set_intattr(source,new_intattr);
248}
249
250void eclic_set_posedge_trig(uint32_t source) {
251 //read the current attr
252 uint8_t old_intattr = eclic_get_intattr(source);
253 // Keep other bits unchanged and only set the bit 1
254 uint8_t new_intattr = (old_intattr | 0x2);
255 // Keep other bits unchanged and only clear the bit 2
256 new_intattr = (new_intattr & (~0x4));
257
258 eclic_set_intattr(source,new_intattr);
259}
260
261void eclic_set_negedge_trig(uint32_t source) {
262 //read the current attr
263 uint8_t old_intattr = eclic_get_intattr(source);
264 // Keep other bits unchanged and only set the bit 1
265 uint8_t new_intattr = (old_intattr | 0x2);
266 // Keep other bits unchanged and only set the bit 2
267 new_intattr = (new_intattr | 0x4);
268
269 eclic_set_intattr(source,new_intattr);
270}
271
272extern void core_wfe(void);
273void wfe(void) {
274 core_wfe();
275}
276
277void clean_int_src(void)
278{
279 for (uint32_t i=0; i<8; i++)
280 REG32(AOCPU_IRQ_SEL0 + i*4) = 0;
281}
282
283int int_src_sel(uint32_t ulIrq, uint32_t src)
284{
285 uint32_t index;
286
287 if (ulIrq < ECLIC_INTERNAL_NUM_INTERRUPTS ||
288 ulIrq > ECLIC_NUM_INTERRUPTS) {
289 printf("Error ulIrq!\n");
290 return -1;
291 }
292
293 if (src > 0xff) {
294 printf("Error src!\n");
295 return -2;
296 }
297
298 ulIrq -= ECLIC_INTERNAL_NUM_INTERRUPTS;
299
300 index = ulIrq/4;
301 REG32(AOCPU_IRQ_SEL0 + index*4) &= ~(0xff << (ulIrq%4)*8);
302 REG32(AOCPU_IRQ_SEL0 + index*4) |= src << (ulIrq%4)*8;
303 return 0;
304}
305
306int int_src_clean(uint32_t ulIrq)
307{
308 uint32_t index;
309
310 if (ulIrq < ECLIC_INTERNAL_NUM_INTERRUPTS ||
311 ulIrq > ECLIC_NUM_INTERRUPTS) {
312 printf("Error ulIrq!\n");
313 return -1;
314 }
315
316 ulIrq -= ECLIC_INTERNAL_NUM_INTERRUPTS;
317
318 index = ulIrq/4;
319 REG32(AOCPU_IRQ_SEL0 + index*4) &= ~(0xff << (ulIrq%4)*8);
320 return 0;
321}
322
323/*Just for external interrupt source.
324 *Because int_src_sel() just support external select
325 */
326int eclic_map_interrupt(uint32_t ulIrq, uint32_t src)
327{
328 uint8_t val;
329
330 if (int_src_sel(ulIrq, src)) {
331 printf("Enable %ld irq, %ld src fail!\n", ulIrq, src);
332 return -1;
333 }
334
335 val = eclic_get_intattr (ulIrq);
336 val |= ECLIC_INT_ATTR_MACH_MODE;
337 /*Use edge trig interrupt default*/
338 val |= ECLIC_INT_ATTR_TRIG_EDGE;
339 eclic_set_intattr(ulIrq, val);
340 //eclic_enable_interrupt(ulIrq);
341 return 0;
342}
343
344uint32_t eclic_interrupt_inner[SOC_ECLIC_NUM_INTERRUPTS] = {0};
345extern uint32_t vector_base;
346
347int RegisterIrq(uint32_t int_num, uint32_t int_priority, function_ptr_t handler) {
348 int irq = 0;
349
350 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
351 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == 0)
352 break;
353 }
354 if (eclic_map_interrupt(irq, int_num) < 0) {
355 printf("eclic map error.\n");
356 return -1;
357 }
358 eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] = int_num;
359
360 *(&vector_base + irq) = (uint32_t)handler;
361 eclic_set_irq_pri(irq, int_priority);
362
363 return 0;
364}
365
366int UnRegisterIrq(uint32_t ulIrq)
367{
368 int irq = 0;
369 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
370 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == ulIrq)
371 break;
372 }
373 if (irq > ECLIC_NUM_INTERRUPTS) {
374 printf("Error ulIrq!\n");
375 return -1;
376 } else {
377 if (int_src_clean(irq)) {
378 printf("unregister %ld irq, %ld src fail!\n", ulIrq, irq);
379 return -1;
380 }
381 eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] = 0;
382 *(&vector_base + irq) = 0;
383 }
384 return 0;
385}
386
387int EnableIrq(uint32_t ulIrq)
388{
389 int irq = 0;
390 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
391 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == ulIrq)
392 break;
393 }
394 if (irq > ECLIC_NUM_INTERRUPTS) {
395 printf("Error ulIrq!\n");
396 return -1;
397 } else {
398 eclic_enable_interrupt(irq);
399 }
400 return 0;
401}
402
403int DisableIrq(uint32_t ulIrq)
404{
405 int irq = 0;
406 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
407 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == ulIrq)
408 break;
409 }
410 if (irq > ECLIC_NUM_INTERRUPTS) {
411 printf("Error ulIrq!\n");
412 return -1;
413 } else {
414 eclic_disable_interrupt(irq);
415 }
416 return 0;
417}
418
419int SetIrqPriority(uint32_t ulIrq, uint32_t ulProi)
420{
421 int irq = 0;
422 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
423 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == ulIrq)
424 break;
425 }
426 if (irq > ECLIC_NUM_INTERRUPTS) {
427 printf("Error ulIrq!\n");
428 return -1;
429 } else {
430 eclic_set_irq_pri(irq, ulProi);
431 }
432 return 0;
433}
434
435int ClearPendingIrq(uint32_t ulIrq)
436{
437 int irq = 0;
438 for (irq = ECLIC_INTERNAL_NUM_INTERRUPTS; irq <= ECLIC_NUM_INTERRUPTS; irq ++) {
439 if (eclic_interrupt_inner[irq - ECLIC_INTERNAL_NUM_INTERRUPTS] == ulIrq)
440 break;
441 }
442 if (irq > ECLIC_NUM_INTERRUPTS) {
443 printf("Error ulIrq!\n");
444 return -1;
445 } else {
446 eclic_clear_pending(irq);
447 }
448 return 0;
449}