1 /*
2  * Copyright (c) 2018 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include "platform_p.h"
9 
10 #include <assert.h>
11 #include <lk/err.h>
12 #include <lk/debug.h>
13 #include <lk/reg.h>
14 #include <lk/trace.h>
15 #include <kernel/debug.h>
16 #include <kernel/thread.h>
17 #include <platform/interrupts.h>
18 #include <platform/sifive.h>
19 
20 #define LOCAL_TRACE 0
21 
22 // Driver for PLIC implementation in SiFive E and U boards
23 
24 #define PLIC_PRIORITY(irq) (PLIC_BASE + 4 * (irq))
25 #define PLIC_PENDING(irq)  (PLIC_BASE + 0x1000 + (4 * ((irq) / 32)))
26 #define PLIC_ENABLE(irq, hart)      (PLIC_BASE + 0x2000 + (0x80 * PLIC_HART_IDX(hart)) + (4 * ((irq) / 32)))
27 #define PLIC_THRESHOLD(hart)        (PLIC_BASE + 0x200000 + (0x1000 * PLIC_HART_IDX(hart)))
28 #define PLIC_COMPLETE(hart)         (PLIC_BASE + 0x200004 + (0x1000 * PLIC_HART_IDX(hart)))
29 #define PLIC_CLAIM(hart)            PLIC_COMPLETE(hart)
30 
31 static struct int_handlers {
32     int_handler handler;
33     void *arg;
34 } handlers[SIFIVE_NUM_IRQS];
35 
plic_early_init(void)36 void plic_early_init(void) {
37     // mask all irqs and set their priority to 1
38     for (int i = 1; i < SIFIVE_NUM_IRQS; i++) {
39         *REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
40         *REG32(PLIC_PRIORITY(i)) = 1;
41     }
42 
43     // set global priority threshold to 0
44     *REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
45 }
46 
plic_init(void)47 void plic_init(void) {
48 }
49 
mask_interrupt(unsigned int vector)50 status_t mask_interrupt(unsigned int vector) {
51     *REG32(PLIC_ENABLE(vector, riscv_current_hart())) &= ~(1 << (vector % 32));
52     return NO_ERROR;
53 }
54 
unmask_interrupt(unsigned int vector)55 status_t unmask_interrupt(unsigned int vector) {
56     *REG32(PLIC_ENABLE(vector, riscv_current_hart())) |= (1 << (vector % 32));
57     return NO_ERROR;
58 }
59 
register_int_handler(unsigned int vector,int_handler handler,void * arg)60 void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
61     LTRACEF("vector %u handler %p arg %p\n", vector, handler, arg);
62 
63     DEBUG_ASSERT(vector < SIFIVE_NUM_IRQS);
64 
65     handlers[vector].handler = handler;
66     handlers[vector].arg = arg;
67 }
68 
riscv_platform_irq(void)69 enum handler_return riscv_platform_irq(void) {
70     // see what irq triggered it
71     uint32_t vector = *REG32(PLIC_CLAIM(riscv_current_hart()));
72     LTRACEF("vector %u\n", vector);
73 
74     if (unlikely(vector == 0)) {
75         // nothing pending
76         return INT_NO_RESCHEDULE;
77     }
78 
79     THREAD_STATS_INC(interrupts);
80     KEVLOG_IRQ_ENTER(vector);
81 
82     enum handler_return ret = INT_NO_RESCHEDULE;
83     if (handlers[vector].handler) {
84         ret = handlers[vector].handler(handlers[vector].arg);
85     }
86 
87     // ack the interrupt
88     *REG32(PLIC_COMPLETE(riscv_current_hart())) = vector;
89 
90     KEVLOG_IRQ_EXIT(vector);
91 
92     return ret;
93 }
94 
95