diff options
Diffstat (limited to 'FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers')
25 files changed, 1731 insertions, 204 deletions
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c index a1219e01e..92c61d023 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-clock.c @@ -25,3 +25,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = { }; #endif /* METAL_FIXED_CLOCK */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c index 2e0624652..57d83af87 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/fixed-factor-clock.c @@ -30,3 +30,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = { .clock.set_rate_hz = __metal_driver_fixed_factor_clock_set_rate_hz, }; #endif /* METAL_FIXED_FACTOR_CLOCK */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c index f1814d365..d0488b317 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_clint0.c @@ -76,11 +76,15 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller, void *priv) { int rc = -1; - + metal_vector_mode mode = __metal_controller_interrupt_vector_mode(); struct metal_interrupt *intc = NULL; struct metal_interrupt *cpu_intc = _get_cpu_intc(); int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller); + if ( (mode != METAL_VECTOR_MODE) && (mode != METAL_DIRECT_MODE) ) { + return rc; + } + for(int i = 0; i < num_interrupts; i++) { int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i); intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i); @@ -97,6 +101,41 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller, return rc; } +int __metal_driver_riscv_clint0_vector_register (struct metal_interrupt *controller, + int id, metal_interrupt_vector_handler_t isr, + void *priv) +{ + /* Not supported. User can override the 'weak' handler with their own */ + int rc = -1; + return rc; +} + +metal_vector_mode __metal_driver_riscv_clint0_get_vector_mode (struct metal_interrupt *controller) +{ + return __metal_controller_interrupt_vector_mode(); +} + +int __metal_driver_riscv_clint0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode) +{ + int rc = -1; + struct metal_interrupt *intc = _get_cpu_intc(); + + if (intc) { + /* Valid vector modes are VECTOR and DIRECT, anything else is invalid (-1) */ + switch (mode) { + case METAL_VECTOR_MODE: + case METAL_DIRECT_MODE: + rc = intc->vtable->interrupt_set_vector_mode(intc, mode); + break; + case METAL_HARDWARE_VECTOR_MODE: + case METAL_SELECTIVE_NONVECTOR_MODE: + case METAL_SELECTIVE_VECTOR_MODE: + break; + } + } + return rc; +} + int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int id) { int rc = -1; @@ -120,6 +159,8 @@ int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int rc = intc->vtable->interrupt_enable(intc, id); } } + + return rc; } int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id) @@ -145,6 +186,8 @@ int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int rc = intc->vtable->interrupt_disable(intc, id); } } + + return rc; } int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller, @@ -206,13 +249,35 @@ int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *control return rc; } +int __metal_driver_riscv_clint0_clear_interrupt (struct metal_interrupt *controller, int id) +{ + int hartid = metal_cpu_get_current_hartid(); + return __metal_driver_riscv_clint0_command_request(controller, + METAL_SOFTWARE_IPI_CLEAR, &hartid); +} + +int __metal_driver_riscv_clint0_set_interrupt (struct metal_interrupt *controller, int id) +{ + int hartid = metal_cpu_get_current_hartid(); + return __metal_driver_riscv_clint0_command_request(controller, + METAL_SOFTWARE_IPI_SET, &hartid); +} + + __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_clint0) = { .clint_vtable.interrupt_init = __metal_driver_riscv_clint0_init, .clint_vtable.interrupt_register = __metal_driver_riscv_clint0_register, + .clint_vtable.interrupt_vector_register = __metal_driver_riscv_clint0_vector_register, .clint_vtable.interrupt_enable = __metal_driver_riscv_clint0_enable, .clint_vtable.interrupt_disable = __metal_driver_riscv_clint0_disable, + .clint_vtable.interrupt_get_vector_mode = __metal_driver_riscv_clint0_get_vector_mode, + .clint_vtable.interrupt_set_vector_mode = __metal_driver_riscv_clint0_set_vector_mode, + .clint_vtable.interrupt_clear = __metal_driver_riscv_clint0_clear_interrupt, + .clint_vtable.interrupt_set = __metal_driver_riscv_clint0_set_interrupt, .clint_vtable.command_request = __metal_driver_riscv_clint0_command_request, .clint_vtable.mtimecmp_set = __metal_driver_riscv_clint0_mtimecmp_set, }; #endif /* METAL_RISCV_CLINT0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c index 88175eb18..b693f312a 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_cpu.c @@ -6,6 +6,7 @@ #include <metal/shutdown.h> #include <metal/machine.h> +extern void __metal_vector_table(); unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu); int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time); @@ -20,7 +21,7 @@ struct metal_cpu *__metal_driver_cpu_get(int hartid) uintptr_t __metal_myhart_id (void) { uintptr_t myhart; - asm volatile ("csrr %0, mhartid" : "=r"(myhart)); + __asm__ volatile ("csrr %0, mhartid" : "=r"(myhart)); return myhart; } @@ -34,54 +35,54 @@ void __metal_zero_memory (unsigned char *base, unsigned int size) void __metal_interrupt_global_enable (void) { uintptr_t m; - asm volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); + __asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); } void __metal_interrupt_global_disable (void) { uintptr_t m; - asm volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); + __asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT)); } void __metal_interrupt_software_enable (void) { uintptr_t m; - asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); } void __metal_interrupt_software_disable (void) { uintptr_t m; - asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW)); } void __metal_interrupt_timer_enable (void) { uintptr_t m; - asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); } void __metal_interrupt_timer_disable (void) { uintptr_t m; - asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR)); } void __metal_interrupt_external_enable (void) { uintptr_t m; - asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); } void __metal_interrupt_external_disable (void) { unsigned long m; - asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT)); } void __metal_interrupt_local_enable (int id) { uintptr_t b = 1 << id; uintptr_t m; - asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b)); + __asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b)); } void __metal_interrupt_local_disable (int id) { uintptr_t b = 1 << id; uintptr_t m; - asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b)); + __asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b)); } void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) { @@ -92,12 +93,31 @@ void __metal_default_interrupt_handler (int id, void *priv) { metal_shutdown(200); } +/* The metal_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_interrupt_vector_handler (void) { + metal_shutdown(300); +} + +/* The metal_software_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_SW].handler(METAL_INTERRUPT_ID_SW, priv); + } +} + void __metal_default_sw_handler (int id, void *priv) { uintptr_t mcause; struct __metal_driver_riscv_cpu_intc *intc; struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; - asm volatile ("csrr %0, mcause" : "=r"(mcause)); + __asm__ volatile ("csrr %0, mcause" : "=r"(mcause)); if ( cpu ) { intc = (struct __metal_driver_riscv_cpu_intc *) __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); @@ -105,6 +125,20 @@ void __metal_default_sw_handler (int id, void *priv) { } } +/* The metal_timer_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_TMR].handler(METAL_INTERRUPT_ID_TMR, priv); + } +} + void __metal_default_timer_handler (int id, void *priv) { struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id()); unsigned long long time = __metal_driver_cpu_mtime_get(cpu); @@ -113,6 +147,20 @@ void __metal_default_timer_handler (int id, void *priv) { __metal_driver_cpu_mtimecmp_set(cpu, time + 10); } +/* The metal_external_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_EXT].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_EXT].handler(METAL_INTERRUPT_ID_EXT, priv); + } +} + void __metal_exception_handler(void) __attribute__((interrupt, aligned(128))); void __metal_exception_handler (void) { int id; @@ -121,17 +169,17 @@ void __metal_exception_handler (void) { struct __metal_driver_riscv_cpu_intc *intc; struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; - asm volatile ("csrr %0, mcause" : "=r"(mcause)); - asm volatile ("csrr %0, mepc" : "=r"(mepc)); - asm volatile ("csrr %0, mtval" : "=r"(mtval)); - asm volatile ("csrr %0, mtvec" : "=r"(mtvec)); + __asm__ volatile ("csrr %0, mcause" : "=r"(mcause)); + __asm__ volatile ("csrr %0, mepc" : "=r"(mepc)); + __asm__ volatile ("csrr %0, mtval" : "=r"(mtval)); + __asm__ volatile ("csrr %0, mtvec" : "=r"(mtvec)); if ( cpu ) { intc = (struct __metal_driver_riscv_cpu_intc *) __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); id = mcause & METAL_MCAUSE_CAUSE; if (mcause & METAL_MCAUSE_INTR) { - if ((id < METAL_INTERRUPT_ID_LC0) || + if ((id < METAL_INTERRUPT_ID_CSW) || ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) { priv = intc->metal_int_table[id].exint_data; intc->metal_int_table[id].handler(id, priv); @@ -141,9 +189,9 @@ void __metal_exception_handler (void) { uintptr_t mtvt; metal_interrupt_handler_t mtvt_handler; - asm volatile ("csrr %0, mtvt" : "=r"(mtvt)); + __asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt)); priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; - mtvt_handler = (metal_interrupt_handler_t)mtvt; + mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt; mtvt_handler(id, priv); return; } @@ -153,28 +201,271 @@ void __metal_exception_handler (void) { } } +/* The metal_lc0_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC0].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC0].handler(METAL_INTERRUPT_ID_LC0, priv); + } +} + +/* The metal_lc1_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC1].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC1].handler(METAL_INTERRUPT_ID_LC1, priv); + } +} + +/* The metal_lc2_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC2].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC2].handler(METAL_INTERRUPT_ID_LC2, priv); + } +} + +/* The metal_lc3_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC3].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC3].handler(METAL_INTERRUPT_ID_LC3, priv); + } +} + +/* The metal_lc4_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC4].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC4].handler(METAL_INTERRUPT_ID_LC4, priv); + } +} + +/* The metal_lc5_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC5].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC5].handler(METAL_INTERRUPT_ID_LC5, priv); + } +} + +/* The metal_lc6_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC6].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC6].handler(METAL_INTERRUPT_ID_LC6, priv); + } +} + +/* The metal_lc7_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC7].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC7].handler(METAL_INTERRUPT_ID_LC7, priv); + } +} + +/* The metal_lc8_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC8].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC8].handler(METAL_INTERRUPT_ID_LC8, priv); + } +} + +/* The metal_lc9_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC9].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC9].handler(METAL_INTERRUPT_ID_LC9, priv); + } +} + +/* The metal_lc10_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC10].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC10].handler(METAL_INTERRUPT_ID_LC10, priv); + } +} + +/* The metal_lc11_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC11].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC11].handler(METAL_INTERRUPT_ID_LC11, priv); + } +} + +/* The metal_lc12_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC12].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC12].handler(METAL_INTERRUPT_ID_LC12, priv); + } +} + +/* The metal_lc13_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC13].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC13].handler(METAL_INTERRUPT_ID_LC13, priv); + } +} + +/* The metal_lc14_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC14].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC14].handler(METAL_INTERRUPT_ID_LC14, priv); + } +} + +/* The metal_lc15_interrupt_vector_handler() function can be redefined. */ +void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler (void) { + void *priv; + struct __metal_driver_riscv_cpu_intc *intc; + struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()]; + + if ( cpu ) { + intc = (struct __metal_driver_riscv_cpu_intc *) + __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu); + priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC15].exint_data; + intc->metal_int_table[METAL_INTERRUPT_ID_LC15].handler(METAL_INTERRUPT_ID_LC15, priv); + } +} + +metal_vector_mode __metal_controller_interrupt_vector_mode (void) +{ + uintptr_t val; + + asm volatile ("csrr %0, mtvec" : "=r"(val)); + val &= METAL_MTVEC_MASK; + + switch (val) { + case METAL_MTVEC_CLIC: + return METAL_SELECTIVE_VECTOR_MODE; + case METAL_MTVEC_CLIC_VECTORED: + return METAL_HARDWARE_VECTOR_MODE; + case METAL_MTVEC_VECTORED: + return METAL_VECTOR_MODE; + } + return METAL_DIRECT_MODE; +} + void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table) { uintptr_t trap_entry, val; - asm volatile ("csrr %0, mtvec" : "=r"(val)); + __asm__ volatile ("csrr %0, mtvec" : "=r"(val)); val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED); trap_entry = (uintptr_t)vec_table; switch (mode) { + case METAL_SELECTIVE_NONVECTOR_MODE: case METAL_SELECTIVE_VECTOR_MODE: - asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC)); - asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC)); + __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC)); break; case METAL_HARDWARE_VECTOR_MODE: - asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC_VECTORED)); - asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED)); + __asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED)); break; case METAL_VECTOR_MODE: - asm volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED)); break; case METAL_DIRECT_MODE: - asm volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED)); + __asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED)); break; } } @@ -270,7 +561,7 @@ int __metal_local_interrupt_enable (struct metal_interrupt *controller, __metal_interrupt_local_disable(id); } break; - defaut: + default: rc = -1; } return rc; @@ -295,25 +586,25 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt if ( !intc->init_done ) { /* Disable and clear all interrupt sources */ - asm volatile ("csrc mie, %0" :: "r"(-1)); - asm volatile ("csrc mip, %0" :: "r"(-1)); + __asm__ volatile ("csrc mie, %0" :: "r"(-1)); + __asm__ volatile ("csrc mip, %0" :: "r"(-1)); /* Read the misa CSR to determine if the delegation registers exist */ uintptr_t misa; - asm volatile ("csrr %0, misa" : "=r" (misa)); + __asm__ volatile ("csrr %0, misa" : "=r" (misa)); /* The delegation CSRs exist if user mode interrupts (N extension) or * supervisor mode (S extension) are supported */ if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) { /* Disable interrupt and exception delegation */ - asm volatile ("csrc mideleg, %0" :: "r"(-1)); - asm volatile ("csrc medeleg, %0" :: "r"(-1)); + __asm__ volatile ("csrc mideleg, %0" :: "r"(-1)); + __asm__ volatile ("csrc medeleg, %0" :: "r"(-1)); } /* The satp CSR exists if supervisor mode (S extension) is supported */ if(misa & METAL_ISA_S_EXTENSIONS) { /* Clear the entire CSR to make sure that satp.MODE = 0 */ - asm volatile ("csrc satp, %0" :: "r"(-1)); + __asm__ volatile ("csrc satp, %0" :: "r"(-1)); } /* Default to use direct interrupt, setup sw cb table*/ @@ -325,12 +616,12 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt for (int i = 0; i < METAL_MAX_ME; i++) { intc->metal_exception_table[i] = __metal_default_exception_handler; } - __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler); - asm volatile ("csrr %0, misa" : "=r"(val)); + __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler); + __asm__ volatile ("csrr %0, misa" : "=r"(val)); if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) { /* Floating point architecture, so turn on FP register saving*/ - asm volatile ("csrr %0, mstatus" : "=r"(val)); - asm volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT)); + __asm__ volatile ("csrr %0, mstatus" : "=r"(val)); + __asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT)); } intc->init_done = 1; } @@ -380,7 +671,7 @@ int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrup intc->metal_int_table[id].handler = __metal_default_interrupt_handler; intc->metal_int_table[id].sub_int = priv; break; - defaut: + default: rc = -12; } } @@ -406,11 +697,11 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int if (id == METAL_INTERRUPT_ID_BASE) { if (mode == METAL_DIRECT_MODE) { - __metal_controller_interrupt_vector(mode, &__metal_exception_handler); + __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler); return 0; } if (mode == METAL_VECTOR_MODE) { - __metal_controller_interrupt_vector(mode, &intc->metal_mtvec_table); + __metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table); return 0; } } @@ -420,10 +711,30 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller, int id) { + if (id == METAL_INTERRUPT_ID_BASE) { + __metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler); + return 0; + } + return -1; +} + +metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller) +{ + return __metal_controller_interrupt_vector_mode(); +} + +int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller, + metal_vector_mode mode) +{ struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller); + ( void ) intc; - if (id == METAL_INTERRUPT_ID_BASE) { - __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler); + if (mode == METAL_DIRECT_MODE) { + __metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler); + return 0; + } + if (mode == METAL_VECTOR_MODE) { + __metal_controller_interrupt_vector(mode, (void *)__metal_vector_table); return 0; } return -1; @@ -436,25 +747,23 @@ int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt return 0; } -extern inline int __metal_controller_interrupt_is_selective_vectored(void); - /* CPU driver !!! */ -unsigned long long __metal_driver_cpu_timer_get(struct metal_cpu *cpu) +unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu) { unsigned long long val = 0; #if __riscv_xlen == 32 unsigned long hi, hi1, lo; - asm volatile ("csrr %0, mcycleh" : "=r"(hi)); - asm volatile ("csrr %0, mcycle" : "=r"(lo)); - asm volatile ("csrr %0, mcycleh" : "=r"(hi1)); + __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi)); + __asm__ volatile ("csrr %0, mcycle" : "=r"(lo)); + __asm__ volatile ("csrr %0, mcycleh" : "=r"(hi1)); if (hi == hi1) { val = ((unsigned long long)hi << 32) | lo; } #else - asm volatile ("csrr %0, mcycle" : "=r"(val)); + __asm__ volatile ("csrr %0, mcycle" : "=r"(val)); #endif return val; @@ -477,7 +786,6 @@ unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu) struct metal_interrupt *tmr_intc; struct __metal_driver_riscv_cpu_intc *intc = (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); - struct __metal_driver_cpu *_cpu = (void *)cpu; if (intc) { tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int; @@ -495,7 +803,6 @@ int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long t struct metal_interrupt *tmr_intc; struct __metal_driver_riscv_cpu_intc *intc = (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); - struct __metal_driver_cpu *_cpu = (void *)cpu; if (intc) { tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int; @@ -517,7 +824,7 @@ __metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu) #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE return __METAL_DT_SIFIVE_CLIC0_HANDLE; #else -#warning "There is no interrupt controller for Timer interrupt" +#pragma message("There is no interrupt controller for Timer interrupt") return NULL; #endif #endif @@ -537,7 +844,7 @@ __metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu) #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE return __METAL_DT_SIFIVE_CLIC0_HANDLE; #else -#warning "There is no interrupt controller for Software interrupt" +#pragma message("There is no interrupt controller for Software interrupt") return NULL; #endif #endif @@ -554,7 +861,6 @@ int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid) struct metal_interrupt *sw_intc; struct __metal_driver_riscv_cpu_intc *intc = (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); - struct __metal_driver_cpu *_cpu = (void *)cpu; if (intc) { sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; @@ -572,7 +878,6 @@ int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid) struct metal_interrupt *sw_intc; struct __metal_driver_riscv_cpu_intc *intc = (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); - struct __metal_driver_cpu *_cpu = (void *)cpu; if (intc) { sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; @@ -590,7 +895,6 @@ int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid) struct metal_interrupt *sw_intc; struct __metal_driver_riscv_cpu_intc *intc = (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu); - struct __metal_driver_cpu *_cpu = (void *)cpu; if (intc) { sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int; @@ -642,35 +946,40 @@ int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode, int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc) { - /* Per ISA compressed instruction has last two bits of opcode set */ - return (*(unsigned short*)epc & 3) ? 4 : 2; + /** + * Per ISA compressed instruction has last two bits of opcode set. + * The encoding '00' '01' '10' are used for compressed instruction. + * Only enconding '11' isn't regarded as compressed instruction (>16b). + */ + return ((*(unsigned short*)epc & METAL_INSN_LENGTH_MASK) + == METAL_INSN_NOT_COMPRESSED) ? 4 : 2; } uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu) { uintptr_t mepc; - asm volatile ("csrr %0, mepc" : "=r"(mepc)); + __asm__ volatile ("csrr %0, mepc" : "=r"(mepc)); return mepc; } int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc) { - asm volatile ("csrw mepc, %0" :: "r"(mepc)); + __asm__ volatile ("csrw mepc, %0" :: "r"(mepc)); return 0; } __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = { - .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init, + .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init, .controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register, .controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable, .controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable, - .controller_vtable.interrupt_vector_enable = __metal_driver_riscv_cpu_controller_interrupt_enable_vector, - .controller_vtable.interrupt_vector_disable = __metal_driver_riscv_cpu_controller_interrupt_disable_vector, + .controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode, + .controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode, .controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request, }; __METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = { - .cpu_vtable.timer_get = __metal_driver_cpu_timer_get, + .cpu_vtable.mcycle_get = __metal_driver_cpu_mcycle_get, .cpu_vtable.timebase_get = __metal_driver_cpu_timebase_get, .cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get, .cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set, diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c index ed9782450..3272f1c66 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.c @@ -25,30 +25,47 @@ void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic, METAL_RISCV_PLIC0_CLAIM)) = id; } -void __metal_plic0_set_threshold(struct __metal_driver_riscv_plic0 *plic, - unsigned int threshold) +int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold) { - unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_PLIC0_THRESHOLD)) = threshold; + return 0; } -void __metal_plic0_set_priority(struct __metal_driver_riscv_plic0 *plic, - int id, unsigned int priority) +unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller) { - unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); - int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)plic); + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_THRESHOLD)); +} + +int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller); + unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller); if ( (max_priority) && (priority < max_priority) ) { __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_RISCV_PLIC0_PRIORITY_BASE + (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority; + return 0; } + return -1; +} + +unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id) +{ + unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + + METAL_RISCV_PLIC0_PRIORITY_BASE + + (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))); } void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable) { unsigned int current; - unsigned long hartid = __metal_myhart_id(); unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic); current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + @@ -69,7 +86,7 @@ void __metal_plic0_handler (int id, void *priv) { struct __metal_driver_riscv_plic0 *plic = priv; unsigned int idx = __metal_plic0_claim_interrupt(plic); - int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic); + unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic); if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) { plic->metal_exint_table[idx](idx, @@ -97,13 +114,13 @@ void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller) for (int i = 0; i < num_interrupts; i++) { __metal_plic0_enable(plic, i, METAL_DISABLE); - __metal_plic0_set_priority(plic, i, 0); + __metal_plic0_set_priority(controller, i, 0); plic->metal_exint_table[i] = NULL; plic->metal_exdata_table[i].sub_int = NULL; plic->metal_exdata_table[i].exint_data = NULL; } - __metal_plic0_set_threshold(plic, 0); + __metal_plic0_set_threshold(controller, 0); /* Register plic (ext) interrupt with with parent controller */ intc->vtable->interrupt_register(intc, line, NULL, plic); @@ -127,11 +144,11 @@ int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller, } if (isr) { - __metal_plic0_set_priority(plic ,id, 2); + __metal_plic0_set_priority(controller, id, 2); plic->metal_exint_table[id] = isr; plic->metal_exdata_table[id].exint_data = priv; } else { - __metal_plic0_set_priority(plic, id, 1); + __metal_plic0_set_priority(controller, id, 1); plic->metal_exint_table[id] = __metal_plic0_default_handler; plic->metal_exdata_table[id].sub_int = priv; } @@ -167,6 +184,12 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = { .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register, .plic_vtable.interrupt_enable = __metal_driver_riscv_plic0_enable, .plic_vtable.interrupt_disable = __metal_driver_riscv_plic0_disable, + .plic_vtable.interrupt_get_threshold = __metal_plic0_get_threshold, + .plic_vtable.interrupt_set_threshold = __metal_plic0_set_threshold, + .plic_vtable.interrupt_get_priority = __metal_plic0_get_priority, + .plic_vtable.interrupt_set_priority = __metal_plic0_set_priority, }; #endif /* METAL_RISCV_PLIC0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c new file mode 100644 index 000000000..6f8723735 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_ccache0.c @@ -0,0 +1,84 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_CCACHE0 + +#include <stdint.h> +#include <metal/io.h> +#include <metal/drivers/sifive_ccache0.h> +#include <metal/machine.h> + +#define L2_CONFIG_WAYS_SHIFT 8 +#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) + +void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways); + +static void metal_driver_sifive_ccache0_init(void) __attribute__((constructor)); +static void metal_driver_sifive_ccache0_init(void) +{ +#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE + /* Get the handle for the L2 cache controller */ + struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE; + if(!l2) { + return; + } + + /* Get the number of available ways per bank */ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2); + uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG)); + ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); + + /* Enable all the ways */ + __metal_driver_sifive_ccache0_init(l2, ways); +#endif +} + +void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways) +{ + metal_cache_set_enabled_ways(l2, ways); +} + +int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache) +{ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache); + + uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)); + + /* The stored number is the index, so add one */ + return (0xFF & way_enable) + 1; +} + +int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, int ways) +{ + unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache); + + /* We can't decrease the number of enabled ways */ + if(metal_cache_get_enabled_ways(cache) > ways) { + return -2; + } + + /* The stored value is the index, so subtract one */ + uint32_t value = 0xFF & (ways - 1); + + /* Set the number of enabled ways */ + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = value; + + /* Make sure the number of ways was set correctly */ + if(metal_cache_get_enabled_ways(cache) != ways) { + return -3; + } + + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = { + .cache.init = __metal_driver_sifive_ccache0_init, + .cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways, + .cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways, +}; + +#endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c index 3f213847d..12c3dac06 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c @@ -11,12 +11,6 @@ #include <metal/drivers/sifive_clic0.h> #include <metal/machine.h> -typedef enum metal_priv_mode_ { - METAL_PRIV_M_MODE = 0, - METAL_PRIV_MU_MODE = 1, - METAL_PRIV_MSU_MODE = 2 -} metal_priv_mode; - typedef enum metal_clic_vector_{ METAL_CLIC_NONVECTOR = 0, METAL_CLIC_VECTORED = 1 @@ -30,17 +24,20 @@ struct __metal_clic_cfg { }; const struct __metal_clic_cfg __metal_clic_defaultcfg = { - .nmbits = METAL_PRIV_M_MODE, + .nmbits = METAL_INTR_PRIV_M_MODE, .nlbits = 0, .nvbit = METAL_CLIC_NONVECTOR }; +void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64))); + +void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64))); + struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic, struct __metal_clic_cfg *cfg) { volatile unsigned char val; struct __metal_clic_cfg cliccfg; - uintptr_t hartid = __metal_myhart_id(); unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); if ( cfg ) { @@ -80,7 +77,7 @@ int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, return 0; } -int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, int level) +int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level) { uint8_t mask, nmmask, nlmask, val; struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); @@ -102,7 +99,7 @@ int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, return 0; } -int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id) +unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id) { int level; uint8_t mask, val, freebits, nlbits; @@ -185,7 +182,7 @@ int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *cl return priority; } -int __metal_clic0_interrupt_set_vector (struct __metal_driver_sifive_clic0 *clic, int id, int enable) +int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable) { uint8_t mask, val; unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); @@ -272,36 +269,102 @@ int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id) { + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); - if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) { + if (id < num_subinterrupts) { + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE; + return 0; } - return 0; + return -1; } int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id) { + unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic); int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); - if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) { + if (id < num_subinterrupts) { + __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base + + METAL_SIFIVE_CLIC0_MMODE_APERTURE + + METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE; + return 0; + } + return -1; +} + +int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + switch (mode) { + case METAL_SELECTIVE_NONVECTOR_MODE: + cfg.nvbit = METAL_CLIC_NONVECTOR; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + case METAL_SELECTIVE_VECTOR_MODE: + cfg.nvbit = METAL_CLIC_VECTORED; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + case METAL_HARDWARE_VECTOR_MODE: + cfg.nvbit = METAL_CLIC_VECTORED; + __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); + break; + default: + return -1; } + __metal_clic0_configuration(clic, &cfg); return 0; } -void __metal_clic0_configure_privilege (struct __metal_driver_sifive_clic0 *clic, metal_priv_mode priv) +metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + metal_vector_mode mode = __metal_controller_interrupt_vector_mode(); + + if (mode == METAL_SELECTIVE_VECTOR_MODE) { + if (cfg.nvbit) { + return METAL_SELECTIVE_VECTOR_MODE; + } else { + return METAL_SELECTIVE_NONVECTOR_MODE; + } + } else { + return mode; + } +} + +int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv) { struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); cfg.nmbits = priv; __metal_clic0_configuration(clic, &cfg); + return 0; } -void __metal_clic0_configure_level (struct __metal_driver_sifive_clic0 *clic, int level) +metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic) { struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); - cfg.nlbits = level; + return cfg.nmbits; +} + +int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + cfg.nlbits = level & 0xF; __metal_clic0_configuration(clic, &cfg); + return 0; +} + +int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic) +{ + struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL); + + return cfg.nlbits; } unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic) @@ -338,16 +401,13 @@ int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller, return 0; } -void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64))); void __metal_clic0_handler (int id, void *priv) { - int idx; struct __metal_driver_sifive_clic0 *clic = priv; int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic); - idx = id - METAL_INTERRUPT_ID_LC0; - if ( (idx < num_subinterrupts) && (clic->metal_mtvt_table[idx]) ) { - clic->metal_mtvt_table[idx](id, clic->metal_exint_table[idx].exint_data); + if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) { + clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data); } } @@ -355,6 +415,10 @@ void __metal_clic0_default_handler (int id, void *priv) { metal_shutdown(300); } +void __metal_clic0_default_vector_handler (void) { + metal_shutdown(400); +} + void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller) { struct __metal_driver_sifive_clic0 *clic = @@ -368,8 +432,8 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller) /* Initialize ist parent controller, aka cpu_intc. */ intc->vtable->interrupt_init(intc); - __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE, - &__metal_clic0_handler); + __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE, + &clic->metal_mtvt_table); /* * Register its interrupts with with parent controller, @@ -389,8 +453,10 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller) level = (1 << cfg.nlbits) - 1; num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); - for (int i = 0; i < num_subinterrupts; i++) { + clic->metal_mtvt_table[0] = &__metal_clic0_handler; + for (int i = 1; i < num_subinterrupts; i++) { clic->metal_mtvt_table[i] = NULL; + clic->metal_exint_table[i].handler = NULL; clic->metal_exint_table[i].sub_int = NULL; clic->metal_exint_table[i].exint_data = NULL; __metal_clic0_interrupt_disable(clic, i); @@ -403,31 +469,71 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller) int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller, int id, metal_interrupt_handler_t isr, void *priv) -{ +{ int rc = -1; int num_subinterrupts; struct __metal_driver_sifive_clic0 *clic = (struct __metal_driver_sifive_clic0 *)(controller); struct metal_interrupt *intc = __metal_driver_sifive_clic0_interrupt_parent(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); + + if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) && + (__metal_clic0_interrupt_is_vectored(clic, id)) ) || + (mode == METAL_HARDWARE_VECTOR_MODE) || + (mode == METAL_VECTOR_MODE) || + (mode == METAL_DIRECT_MODE) ) { + return rc; + } /* Register its interrupts with parent controller */ - if ( id < METAL_INTERRUPT_ID_LC0) { + if (id < METAL_INTERRUPT_ID_CSW) { return intc->vtable->interrupt_register(intc, id, isr, priv); } - - /* + + /* * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0 - * Reset the IDs to reflects this. + * Reset the IDs to reflects this. */ - id -= METAL_INTERRUPT_ID_LC0; num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); if (id < num_subinterrupts) { if ( isr) { + clic->metal_exint_table[id].handler = isr; + clic->metal_exint_table[id].exint_data = priv; + } else { + clic->metal_exint_table[id].handler = __metal_clic0_default_handler; + clic->metal_exint_table[id].sub_int = priv; + } + rc = 0; + } + return rc; +} + +int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller, + int id, metal_interrupt_vector_handler_t isr, + void *priv) +{ + int rc = -1; + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + struct metal_interrupt *intc = + __metal_driver_sifive_clic0_interrupt_parent(controller); + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); + + if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) { + return rc; + } + if ((mode == METAL_SELECTIVE_VECTOR_MODE) && + (__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) { + return rc; + } + if (id < num_subinterrupts) { + if ( isr) { clic->metal_mtvt_table[id] = isr; clic->metal_exint_table[id].exint_data = priv; } else { - clic->metal_mtvt_table[id] = __metal_clic0_default_handler; + clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler; clic->metal_exint_table[id].sub_int = priv; } rc = 0; @@ -449,31 +555,20 @@ int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int return __metal_clic0_interrupt_disable(clic, id); } -int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, - int id, metal_vector_mode mode) +int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id) { - int num_subinterrupts; + int rc = -1; + int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); struct __metal_driver_sifive_clic0 *clic = (struct __metal_driver_sifive_clic0 *)(controller); + metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic); - if (id == METAL_INTERRUPT_ID_BASE) { - if (mode == METAL_SELECTIVE_VECTOR_MODE) { - __metal_controller_interrupt_vector(mode, &__metal_clic0_handler); - return 0; - } - if (mode == METAL_HARDWARE_VECTOR_MODE) { - __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table); - return 0; - } + if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) { + return rc; } - num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); - if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) { - if ((mode == METAL_SELECTIVE_VECTOR_MODE) && - __metal_controller_interrupt_is_selective_vectored()) { - __metal_clic0_interrupt_set_vector(clic, id, METAL_ENABLE); - return 0; - } - + if (id < num_subinterrupts) { + __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE); + return 0; } return -1; } @@ -484,20 +579,84 @@ int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt struct __metal_driver_sifive_clic0 *clic = (struct __metal_driver_sifive_clic0 *)(controller); - if (id == METAL_INTERRUPT_ID_BASE) { - __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE, &__metal_clic0_handler); - return 0; - } num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller); - if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) { - if (__metal_controller_interrupt_is_selective_vectored()) { - __metal_clic0_interrupt_set_vector(clic, id, METAL_DISABLE); - return 0; - } + if (id < num_subinterrupts) { + __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE); + return 0; } return -1; } +metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_vector_mode(clic); +} + +int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_vector_mode(clic, mode); +} + +metal_intr_priv_mode __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_privilege(clic); +} + +int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_privilege(clic, priv); +} + +unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_get_level(clic); +} + +int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_configure_set_level(clic, level); +} + +unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_get_priority(clic, id); +} + +int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_set_priority(clic, id, priority); +} + +int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_clear(clic, id); +} + +int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id) +{ + struct __metal_driver_sifive_clic0 *clic = + (struct __metal_driver_sifive_clic0 *)(controller); + return __metal_clic0_interrupt_set(clic, id); +} + int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller, int command, void *data) { @@ -553,12 +712,25 @@ int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *control __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = { .clic_vtable.interrupt_init = __metal_driver_sifive_clic0_init, .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register, + .clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register, .clic_vtable.interrupt_enable = __metal_driver_sifive_clic0_enable, .clic_vtable.interrupt_disable = __metal_driver_sifive_clic0_disable, .clic_vtable.interrupt_vector_enable = __metal_driver_sifive_clic0_enable_interrupt_vector, .clic_vtable.interrupt_vector_disable = __metal_driver_sifive_clic0_disable_interrupt_vector, + .clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode, + .clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode, + .clic_vtable.interrupt_get_privilege = __metal_driver_sifive_clic0_get_privilege, + .clic_vtable.interrupt_set_privilege = __metal_driver_sifive_clic0_set_privilege, + .clic_vtable.interrupt_get_threshold = __metal_driver_sifive_clic0_get_threshold, + .clic_vtable.interrupt_set_threshold = __metal_driver_sifive_clic0_set_threshold, + .clic_vtable.interrupt_get_priority = __metal_driver_sifive_clic0_get_priority, + .clic_vtable.interrupt_set_priority = __metal_driver_sifive_clic0_set_priority, + .clic_vtable.interrupt_clear = __metal_driver_sifive_clic0_clear_interrupt, + .clic_vtable.interrupt_set = __metal_driver_sifive_clic0_set_interrupt, .clic_vtable.command_request = __metal_driver_sifive_clic0_command_request, .clic_vtable.mtimecmp_set = __metal_driver_sifive_clic0_mtimecmp_set, }; #endif /* METAL_SIFIVE_CLIC0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c index 14ce2fae6..61af8d314 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfrosc.c @@ -23,9 +23,9 @@ long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_cloc __metal_driver_sifive_fe310_g000_prci_vtable(); long cfg = vtable->get_reg(config_base, config_offset); - if (cfg & CONFIG_ENABLE == 0) + if ((cfg & CONFIG_ENABLE) == 0) return -1; - if (cfg & CONFIG_READY == 0) + if ((cfg & CONFIG_READY) == 0) return -1; return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1); } @@ -40,3 +40,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = { .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz, }; #endif /* METAL_SIFIVE_FE310_G000_HFROSC */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c index dbe467487..9ed7a0bf3 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_hfxosc.c @@ -21,9 +21,9 @@ long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_cloc __metal_driver_sifive_fe310_g000_prci_vtable(); long cfg = vtable->get_reg(config_base, config_offset); - if (cfg & CONFIG_ENABLE == 0) + if ((cfg & CONFIG_ENABLE) == 0) return -1; - if (cfg & CONFIG_READY == 0) + if ((cfg & CONFIG_READY) == 0) return -1; return metal_clock_get_rate_hz(ref); } @@ -39,3 +39,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = { }; #endif /* METAL_SIFIVE_FE310_G000_HFXOSC */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c new file mode 100644 index 000000000..324382b9d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_lfrosc.c @@ -0,0 +1,53 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FE310_G000_LFROSC + +#include <metal/drivers/sifive_fe310-g000_lfrosc.h> +#include <metal/machine.h> + +/* LFROSCCFG */ +#define METAL_LFROSCCFG_DIV_MASK 0x3F +#define METAL_LFROSCCFG_TRIM_SHIFT 16 +#define METAL_LFROSCCFG_TRIM_MASK (0x1F << METAL_LFROSCCFG_TRIM_SHIFT) +#define METAL_LFROSCCFG_EN (1 << 30) +#define METAL_LFROSCCFG_RDY (1 << 31) + +/* LFCLKMUX */ +#define METAL_LFCLKMUX_SEL 1 +#define METAL_LFCLKMUX_EXT_MUX_STATUS (1 << 31) + +#define LFROSC_REGW(addr) (__METAL_ACCESS_ONCE((__metal_io_u32 *)addr)) + +long __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(const struct metal_clock *clock) +{ + struct metal_clock *internal_ref = __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(clock); + struct metal_clock *external_ref = __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(clock); + + unsigned long int cfg_reg = __metal_driver_sifive_fe310_g000_lfrosc_config_reg(clock); + unsigned long int mux_reg = __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(clock); + + if(LFROSC_REGW(mux_reg) & METAL_LFCLKMUX_EXT_MUX_STATUS) { + return metal_clock_get_rate_hz(external_ref); + } + + const unsigned long int div = (LFROSC_REGW(cfg_reg) & METAL_LFROSCCFG_DIV_MASK) + 1; + + return metal_clock_get_rate_hz(internal_ref) / div; +} + +long __metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz(struct metal_clock *clock, long rate) +{ + return __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(clock); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc) = { + .clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz, + .clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz, +}; +#endif /* METAL_SIFIVE_FE310_G000_LFROSC */ + +typedef int no_empty_translation_units; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c index c91328565..2ca468f43 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c @@ -133,7 +133,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31 * Returns: * - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency * - the output frequency, in hertz */ -static long get_pll_config_freq(long pll_input_rate, const struct pll_config_t *config) +static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config) { if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate) return PLL_CONFIG_NOT_VALID; @@ -162,8 +162,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31 __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset); /* If the PLL clock has had a _pre_rate_change_callback configured, call it */ - if(pll->clock._pre_rate_change_callback != NULL) - pll->clock._pre_rate_change_callback(pll->clock._pre_rate_change_callback_priv); + _metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback); /* If we're running off of the PLL, switch off before we start configuring it*/ if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0) @@ -179,8 +178,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31 pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate); /* If the PLL clock has had a rate_change_callback configured, call it */ - if(pll->clock._post_rate_change_callback != NULL) - pll->clock._post_rate_change_callback(pll->clock._post_rate_change_callback_priv); + _metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback); } long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock) @@ -358,3 +356,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = { }; #endif /* METAL_SIFIVE_FE310_G000_PLL */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c index 4b402a27a..1236eca3b 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_prci.c @@ -24,3 +24,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = { }; #endif /* METAL_SIFIVE_FE310_G000_PRCI */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c index 5e66b6cda..aafc6e5e3 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fu540-c000_l2.c @@ -2,25 +2,32 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_FU540_C000_L2 + +#include <stdint.h> +#include <metal/io.h> #include <metal/drivers/sifive_fu540-c000_l2.h> +#include <metal/machine.h> #define L2_CONFIG_WAYS_SHIFT 8 #define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) -#ifdef CONFIG_SIFIVE_FU540_C000_L2 +void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways); static void metal_driver_sifive_fu540_c000_l2_init(void) __attribute__((constructor)); static void metal_driver_sifive_fu540_c000_l2_init(void) { #ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE /* Get the handle for the L2 cache controller */ - struct __metal_driver_sifive_fu540_c000_l2 *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE; + struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE; if(!l2) { return; } /* Get the number of available ways per bank */ - uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_CONFIG)); + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(l2); + uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG)); ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); /* Enable all the ways */ @@ -35,12 +42,9 @@ void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways) int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache) { - struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache; - if(!l2) { - return -1; - } + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache); - uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE)); + uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)); /* The stored number is the index, so add one */ return (0xFF & way_enable) + 1; @@ -48,10 +52,7 @@ int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cac int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways) { - struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache; - if(!l2) { - return -1; - } + unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache); /* We can't decrease the number of enabled ways */ if(metal_cache_get_enabled_ways(cache) > ways) { @@ -62,7 +63,7 @@ int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cac uint32_t value = 0xFF & (ways - 1); /* Set the number of enabled ways */ - __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE)) = value; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value; /* Make sure the number of ways was set correctly */ if(metal_cache_get_enabled_ways(cache) != ways) { @@ -79,3 +80,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = { }; #endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c index 59f6fbe48..0d56bafef 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_global-external-interrupts0.c @@ -84,6 +84,50 @@ int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interru return rc; } +int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller, + unsigned int threshold) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + if (intc) { + return intc->vtable->interrupt_set_threshold(intc, threshold); + } + return -1; +} + +unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + if (intc) { + return intc->vtable->interrupt_get_threshold(intc); + } + return 0; +} + +int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller, + int id, unsigned int priority) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + if (intc) { + return intc->vtable->interrupt_set_priority(intc, id, priority); + } + return -1; +} + +unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id) +{ + struct metal_interrupt *intc = + __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); + + if (intc) { + return intc->vtable->interrupt_get_priority(intc, id); + } + return 0; +} + int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller, int command, void *data) { @@ -113,8 +157,13 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0) .global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register, .global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable, .global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable, + .global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold, + .global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold, + .global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority, + .global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority, .global0_vtable.command_request = __metal_driver_sifive_global_external_command_request, }; #endif +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c index fbb6c92a7..923fe2711 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-buttons.c @@ -53,3 +53,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = { }; #endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c index 68f72d5bd..a6b627458 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-leds.c @@ -81,3 +81,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = { }; #endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c index b9302529d..fa0a819f1 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio-switches.c @@ -52,3 +52,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = { }; #endif + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c index 55ff458bf..9ebbea03c 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_gpio0.c @@ -9,6 +9,15 @@ #include <metal/io.h> #include <metal/machine.h> +int __metal_driver_sifive_gpio0_enable_input(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) |= source; + + return 0; +} + int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long source) { long base = __metal_driver_sifive_gpio0_base(ggpio); @@ -18,6 +27,13 @@ int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long sou return 0; } +long __metal_driver_sifive_gpio0_input(struct metal_gpio *ggpio) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_VALUE)); +} + long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio) { long base = __metal_driver_sifive_gpio0_base(ggpio); @@ -25,6 +41,16 @@ long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio) return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT)); } + +int __metal_driver_sifive_gpio0_disable_output(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) &= ~source; + + return 0; +} + int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source) { long base = __metal_driver_sifive_gpio0_base(ggpio); @@ -72,14 +98,124 @@ int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source, return 0; } +int __metal_driver_sifive_gpio0_disable_io(struct metal_gpio *ggpio, long source) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) &= ~source; + + return 0; +} + +int __metal_driver_sifive_gpio0_config_int(struct metal_gpio *ggpio, long source, int intr_type) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + switch (intr_type) + { + case METAL_GPIO_INT_DISABLE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) &= ~source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) &= ~source; + break; + case METAL_GPIO_INT_RISING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + break; + case METAL_GPIO_INT_FALLING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + break; + case METAL_GPIO_INT_BOTH_EDGE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + break; + case METAL_GPIO_INT_HIGH: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + break; + case METAL_GPIO_INT_LOW: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + case METAL_GPIO_INT_BOTH_LEVEL: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + case METAL_GPIO_INT_MAX: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source; + break; + } + return 0; +} + +int __metal_driver_sifive_gpio0_clear_int(struct metal_gpio *ggpio, long source, int intr_type) +{ + long base = __metal_driver_sifive_gpio0_base(ggpio); + + switch (intr_type) + { + case METAL_GPIO_INT_RISING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + break; + case METAL_GPIO_INT_FALLING: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + break; + case METAL_GPIO_INT_BOTH_EDGE: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + break; + case METAL_GPIO_INT_HIGH: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + break; + case METAL_GPIO_INT_LOW: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + case METAL_GPIO_INT_BOTH_LEVEL: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + case METAL_GPIO_INT_MAX: + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source; + __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source; + break; + } + return 0; +} + +struct metal_interrupt * +__metal_driver_gpio_interrupt_controller(struct metal_gpio *gpio) +{ + return __metal_driver_sifive_gpio0_interrupt_parent(gpio); +} + +int __metal_driver_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin) +{ + int irq; + irq = __metal_driver_sifive_gpio0_interrupt_lines(gpio, pin); + return irq; +} + __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_gpio0) = { - .gpio.disable_input = __metal_driver_sifive_gpio0_disable_input, - .gpio.output = __metal_driver_sifive_gpio0_output, - .gpio.enable_output = __metal_driver_sifive_gpio0_enable_output, - .gpio.output_set = __metal_driver_sifive_gpio0_output_set, - .gpio.output_clear = __metal_driver_sifive_gpio0_output_clear, - .gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle, - .gpio.enable_io = __metal_driver_sifive_gpio0_enable_io, + .gpio.disable_input = __metal_driver_sifive_gpio0_disable_input, + .gpio.enable_input = __metal_driver_sifive_gpio0_enable_input, + .gpio.input = __metal_driver_sifive_gpio0_input, + .gpio.output = __metal_driver_sifive_gpio0_output, + .gpio.disable_output = __metal_driver_sifive_gpio0_disable_output, + .gpio.enable_output = __metal_driver_sifive_gpio0_enable_output, + .gpio.output_set = __metal_driver_sifive_gpio0_output_set, + .gpio.output_clear = __metal_driver_sifive_gpio0_output_clear, + .gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle, + .gpio.enable_io = __metal_driver_sifive_gpio0_enable_io, + .gpio.disable_io = __metal_driver_sifive_gpio0_disable_io, + .gpio.config_int = __metal_driver_sifive_gpio0_config_int, + .gpio.clear_int = __metal_driver_sifive_gpio0_clear_int, + .gpio.interrupt_controller = __metal_driver_gpio_interrupt_controller, + .gpio.get_interrupt_id = __metal_driver_gpio_get_interrupt_id, }; #endif /* METAL_SIFIVE_GPIO0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c index d205957ad..1c34ca447 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_local-external-interrupts0.c @@ -82,6 +82,33 @@ int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrup return rc; } +int __metal_driver_sifive_local_external_interrupt_set_threshold(struct metal_interrupt *controller, + unsigned int threshold) +{ + /* Core controller does not support threshold configuration */ + return -1; +} + +unsigned int __metal_driver_sifive_local_external_interrupt_get_threshold(struct metal_interrupt *controller) +{ + /* Core controller does not support threshold configuration */ + return 0; +} + + +int __metal_driver_sifive_local_external_interrupt_set_priority(struct metal_interrupt *controller, + int id, unsigned int priority) +{ + /* Core controller does not support priority configuration */ + return -1; +} + +unsigned int __metal_driver_sifive_local_external_interrupt_get_priority(struct metal_interrupt *controller, int id) +{ + /* Core controller does not support priority configuration */ + return 0; +} + int __metal_driver_sifive_local_external_command_request (struct metal_interrupt *controller, int command, void *data) { @@ -111,7 +138,14 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) = .local0_vtable.interrupt_register = __metal_driver_sifive_local_external_interrupt_register, .local0_vtable.interrupt_enable = __metal_driver_sifive_local_external_interrupt_enable, .local0_vtable.interrupt_disable = __metal_driver_sifive_local_external_interrupt_disable, + .local0_vtable.interrupt_get_threshold = __metal_driver_sifive_local_external_interrupt_get_threshold, + .local0_vtable.interrupt_set_threshold = __metal_driver_sifive_local_external_interrupt_set_threshold, + .local0_vtable.interrupt_get_priority = __metal_driver_sifive_local_external_interrupt_get_priority, + .local0_vtable.interrupt_set_priority = __metal_driver_sifive_local_external_interrupt_set_priority, .local0_vtable.command_request = __metal_driver_sifive_local_external_command_request, }; #endif + +typedef int no_empty_translation_units; + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c new file mode 100644 index 000000000..79b81e7bf --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c @@ -0,0 +1,121 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_RTC0 + +#include <metal/drivers/sifive_rtc0.h> +#include <metal/machine.h> + +#include <limits.h> + +/* RTCCFG */ +#define METAL_RTCCFG_RTCSCALE_MASK 0xF +#define METAL_RTCCFG_ENALWAYS (1 << 12) +#define METAL_RTCCFG_IP0 (1 << 28) + +/* RTCCMP0 */ +#define METAL_RTCCMP0_MAX UINT32_MAX + +#define RTC_REG(base, offset) (((unsigned long)base + offset)) +#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset))) + +uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) { + const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc); + return metal_clock_get_rate_hz(clock); +} + +uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) { + const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc); + return metal_clock_get_rate_hz(clock); +} + +uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK; + + return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift); +} + +uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */ + uint32_t shift = 0; + uint64_t comp_shifted = compare; + while (comp_shifted > METAL_RTCCMP0_MAX) { + shift += 1; + comp_shifted = comp_shifted >> shift; + } + + /* Set the value of rtccfg.scale */ + uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG); + cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK); + cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift); + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg; + + /* Set the value of rtccmp0 */ + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted; + + return __metal_driver_sifive_rtc0_get_compare(rtc); +} + +uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI); + count <<= 32; + count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO); + + return count; +} + +uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32)); + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count); + + return __metal_driver_sifive_rtc0_get_count(rtc); +} + +int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) { + const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc); + + switch (option) { + default: + case METAL_RTC_STOP: + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS); + break; + case METAL_RTC_RUN: + RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS; + break; + } + + return 0; +} + +struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) { + return __metal_driver_sifive_rtc0_interrupt_parent(rtc); +} + +int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) { + return __metal_driver_sifive_rtc0_interrupt_line(rtc); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = { + .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate, + .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate, + .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare, + .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare, + .rtc.get_count = __metal_driver_sifive_rtc0_get_count, + .rtc.set_count = __metal_driver_sifive_rtc0_set_count, + .rtc.run = __metal_driver_sifive_rtc0_run, + .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt, + .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id, +}; + +#endif + diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c index fd9bc5e91..2a346354f 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_spi0.c @@ -7,6 +7,7 @@ #include <metal/drivers/sifive_spi0.h> #include <metal/io.h> #include <metal/machine.h> +#include <metal/time.h> #include <time.h> /* Register fields */ @@ -54,19 +55,25 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi); /* Set protocol */ METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK); - switch(config->protocol) { - case METAL_SPI_SINGLE: - METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; - break; - case METAL_SPI_DUAL: + switch (config->protocol) { + case METAL_SPI_SINGLE: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + case METAL_SPI_DUAL: + if (config->multi_wire == MULTI_WIRE_ALL) METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL; - break; - case METAL_SPI_QUAD: + else + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + case METAL_SPI_QUAD: + if (config->multi_wire == MULTI_WIRE_ALL) METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD; - break; - default: - /* Unsupported value */ - return -1; + else + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE; + break; + default: + /* Unsupported value */ + return -1; } /* Set Polarity */ @@ -107,7 +114,7 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp } /* Set CS line */ - METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = config->csid; + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = 1 << (config->csid); /* Toggle off memory-mapped SPI flash mode, toggle on programmable IO mode * It seems that with this line uncommented, the debugger cannot have access @@ -121,6 +128,28 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp return 0; } +static void spi_mode_switch(struct __metal_driver_sifive_spi0 *spi, + struct metal_spi_config *config, + unsigned int trans_stage) { + long control_base = + __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi); + + if (config->multi_wire == trans_stage) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK); + switch (config->protocol) { + case METAL_SPI_DUAL: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL; + break; + case METAL_SPI_QUAD: + METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD; + break; + default: + /* Unsupported value */ + return; + } + } +} + int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi, struct metal_spi_config *config, size_t len, @@ -130,6 +159,7 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi, struct __metal_driver_sifive_spi0 *spi = (void *)gspi; long control_base = __metal_driver_sifive_spi0_control_base(gspi); int rc = 0; + size_t i = 0; rc = configure_spi(spi, config); if(rc != 0) { @@ -145,7 +175,97 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi, /* Declare time_t variables to break out of infinite while loop */ time_t endwait; - for(int i = 0; i < len; i++) { + for (i = 0; i < config->cmd_num; i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + + return 1; + } + } + + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* switch to Dual/Quad mode */ + spi_mode_switch(spi, config, MULTI_WIRE_ADDR_DATA); + + /* Send Addr data */ + for (; i < (config->cmd_num + config->addr_num); i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + + return 1; + } + } + + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* Send Dummy data */ + for (; i < (config->cmd_num + config->addr_num + config->dummy_num); i++) { + + while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL) + ; + + if (tx_buf) { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i]; + } else { + METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0; + } + + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; + + while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & + METAL_SPI_RXDATA_EMPTY) { + if (metal_time() > endwait) { + METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= + ~(METAL_SPI_CSMODE_MASK); + return 1; + } + } + if (rx_buf) { + rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK); + } + } + + /* switch to Dual/Quad mode */ + spi_mode_switch(spi, config, MULTI_WIRE_DATA_ONLY); + + for (; i < len; i++) { /* Master send bytes to the slave */ /* Wait for TXFIFO to not be full */ @@ -164,10 +284,10 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi, /* Wait for RXFIFO to not be empty, but break the nested loops if timeout * this timeout method needs refining, preferably taking into account * the device specs */ - endwait = time(NULL) + METAL_SPI_RXDATA_TIMEOUT; + endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT; while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) { - if (time(NULL) > endwait) { + if (metal_time() > endwait) { /* If timeout, deassert the CS */ METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK); @@ -227,18 +347,19 @@ int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_ra return 0; } -static void pre_rate_change_callback(void *priv) +static void pre_rate_change_callback_func(void *priv) { long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)priv); /* Detect when the TXDATA is empty by setting the transmit watermark count - * to zero and waiting until an interrupt is pending */ + * to one and waiting until an interrupt is pending (indicating an empty TXFIFO) */ METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) &= ~(METAL_SPI_TXMARK_MASK); + METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) |= (METAL_SPI_TXMARK_MASK & 1); while((METAL_SPI_REGW(METAL_SIFIVE_SPI0_IP) & METAL_SPI_TXWM) == 0) ; } -static void post_rate_change_callback(void *priv) +static void post_rate_change_callback_func(void *priv) { struct __metal_driver_sifive_spi0 *spi = priv; metal_spi_set_baud_rate(&spi->spi, spi->baud_rate); @@ -251,8 +372,13 @@ void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate) struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi); if(clock != NULL) { - metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, spi); - metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, spi); + spi->pre_rate_change_callback.callback = &pre_rate_change_callback_func; + spi->pre_rate_change_callback.priv = spi; + metal_clock_register_pre_rate_change_callback(clock, &(spi->pre_rate_change_callback)); + + spi->post_rate_change_callback.callback = &post_rate_change_callback_func; + spi->post_rate_change_callback.priv = spi; + metal_clock_register_post_rate_change_callback(clock, &(spi->post_rate_change_callback)); } metal_spi_set_baud_rate(&(spi->spi), baud_rate); @@ -275,3 +401,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = { .spi.set_baud_rate = __metal_driver_sifive_spi0_set_baud_rate, }; #endif /* METAL_SIFIVE_SPI0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c index 4ef0aa861..79deebbf5 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_test0.c @@ -5,15 +5,17 @@ #ifdef METAL_SIFIVE_TEST0 +#include <metal/machine.h> + +#include <stdint.h> + #include <metal/drivers/sifive_test0.h> #include <metal/io.h> -#include <stdint.h> -#include <metal/machine.h> void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn)); void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) { - long base = __metal_driver_sifive_test0_base(); + long base = __metal_driver_sifive_test0_base(sd); uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333); while (1) { __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_TEST0_FINISHER_OFFSET)) = out; @@ -24,3 +26,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_test0) = { .shutdown.exit = &__metal_driver_sifive_test0_exit, }; #endif /* METAL_SIFIVE_TEST0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c new file mode 100644 index 000000000..8b63fbd28 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_trace.c @@ -0,0 +1,95 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_TRACE + +#include <metal/drivers/sifive_trace.h> +#include <metal/machine.h> + +#define TRACE_REG(offset) (((unsigned long)base + (offset))) +#define TRACE_REG8(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset))) +#define TRACE_REG16(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset))) +#define TRACE_REG32(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset))) + +static void write_itc_uint32(struct metal_uart *trace, uint32_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data; +} + +static void write_itc_uint16(struct metal_uart *trace, uint16_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data; +} + +static void write_itc_uint8(struct metal_uart *trace, uint8_t data) { + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data; +} + +int __metal_driver_sifive_trace_putc(struct metal_uart *trace, + unsigned char c) { + static uint32_t buffer = 0; + static int bytes_in_buffer = 0; + + buffer |= (((uint32_t)c) << (bytes_in_buffer * 8)); + + bytes_in_buffer += 1; + + if (bytes_in_buffer >= 4) { + write_itc_uint32(trace, buffer); + + buffer = 0; + bytes_in_buffer = 0; + } else if ((c == '\n') || (c == '\r')) { // partial write + switch (bytes_in_buffer) { + case 3: // do a full word write + write_itc_uint16(trace, (uint16_t)(buffer)); + write_itc_uint8(trace, (uint8_t)(buffer >> 16)); + break; + case 2: // do a 16 bit write + write_itc_uint16(trace, (uint16_t)buffer); + break; + case 1: // do a 1 byte write + write_itc_uint8(trace, (uint8_t)buffer); + break; + } + + buffer = 0; + bytes_in_buffer = 0; + } + + return (int)c; +} + +void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) { + // The only init we do here is to make sure ITC 0 is enabled. It is up to + // Freedom Studio or other mechanisms to make sure tracing is enabled. If we + // try to enable tracing here, it will likely conflict with Freedom Studio, + // and they will just fight with each other. + + long base = __metal_driver_sifive_trace_base(trace); + + TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = { + .uart.init = __metal_driver_sifive_trace_init, + .uart.putc = __metal_driver_sifive_trace_putc, + .uart.getc = NULL, + + .uart.get_baud_rate = NULL, + .uart.set_baud_rate = NULL, + + .uart.controller_interrupt = NULL, + .uart.get_interrupt_id = NULL, +}; + +#endif /* METAL_SIFIVE_TRACE */ diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c index 46971ec79..2e8098aa7 100644 --- a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_uart0.c @@ -38,27 +38,42 @@ int __metal_driver_sifive_uart0_get_interrupt_id(struct metal_uart *uart) return (__metal_driver_sifive_uart0_interrupt_line(uart) + METAL_INTERRUPT_ID_GL0); } -int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, unsigned char c) + +int __metal_driver_sifive_uart0_txready(struct metal_uart *uart) +{ + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL)); +} + + +int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c) { long control_base = __metal_driver_sifive_uart0_control_base(uart); - while ((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL) != 0) { } + while (!__metal_driver_sifive_uart0_txready(uart)) { + /* wait */ + } UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c; return 0; } -int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, unsigned char *c) + +int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c) { - uint32_t ch = UART_RXEMPTY; + uint32_t ch; long control_base = __metal_driver_sifive_uart0_control_base(uart); - - while (ch & UART_RXEMPTY) { - ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA); + /* No seperate status register, we get status and the byte at same time */ + ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);; + if( ch & UART_RXEMPTY ){ + *c = -1; /* aka: EOF in most of the world */ + } else { + *c = ch & 0x0ff; } - *c = ch & 0xff; return 0; } + int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart) { struct __metal_driver_sifive_uart0 *uart = (void *)guart; @@ -82,7 +97,7 @@ int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud return 0; } -static void pre_rate_change_callback(void *priv) +static void pre_rate_change_callback_func(void *priv) { struct __metal_driver_sifive_uart0 *uart = priv; long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv); @@ -105,10 +120,10 @@ static void pre_rate_change_callback(void *priv) long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate; for(volatile long x = 0; x < cycles_to_wait; x++) - asm("nop"); + __asm__("nop"); } -static void post_rate_change_callback(void *priv) +static void post_rate_change_callback_func(void *priv) { struct __metal_driver_sifive_uart0 *uart = priv; metal_uart_set_baud_rate(&uart->uart, uart->baud_rate); @@ -121,8 +136,13 @@ void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate) struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart); if(clock != NULL) { - metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, guart); - metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, guart); + uart->pre_rate_change_callback.callback = &pre_rate_change_callback_func; + uart->pre_rate_change_callback.priv = guart; + metal_clock_register_pre_rate_change_callback(clock, &(uart->pre_rate_change_callback)); + + uart->post_rate_change_callback.callback = &post_rate_change_callback_func; + uart->post_rate_change_callback.priv = guart; + metal_clock_register_post_rate_change_callback(clock, &(uart->post_rate_change_callback)); } metal_uart_set_baud_rate(&(uart->uart), baud_rate); @@ -149,3 +169,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = { }; #endif /* METAL_SIFIVE_UART0 */ + +typedef int no_empty_translation_units; diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c new file mode 100644 index 000000000..1a6cf362e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_wdog0.c @@ -0,0 +1,213 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <metal/machine/platform.h> + +#ifdef METAL_SIFIVE_WDOG0 + +#include <metal/drivers/sifive_uart0.h> +#include <metal/machine.h> + +#include <limits.h> + +/* WDOGCFG */ +#define METAL_WDOGCFG_SCALE_MASK 7 +#define METAL_WDOGCFG_RSTEN (1 << 8) +#define METAL_WDOGCFG_ZEROCMP (1 << 9) +#define METAL_WDOGCFG_ENALWAYS (1 << 12) +#define METAL_WDOGCFG_COREAWAKE (1 << 13) +#define METAL_WDOGCFG_IP (1 << 28) + +/* WDOGCMP */ +#define METAL_WDOGCMP_MASK 0xFFFF + +#define WDOG_REG(base, offset) (((unsigned long)base + offset)) +#define WDOG_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)WDOG_REG(base, offset))) +#define WDOG_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)WDOG_REG(base, offset))) + +/* All writes to watchdog registers must be precedded by a write of + * a magic number to WDOGKEY */ +#define WDOG_UNLOCK(base) (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGKEY) = METAL_SIFIVE_WDOG0_MAGIC_KEY) + +/* Unlock the watchdog and then perform a register access */ +#define WDOG_UNLOCK_REGW(base, offset) \ + WDOG_UNLOCK(base);\ + WDOG_REGW(base, offset) + +int __metal_driver_sifive_wdog0_feed(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGFEED) = METAL_SIFIVE_WDOG0_MAGIC_FOOD; + + return 0; +} + +long int __metal_driver_sifive_wdog0_get_rate(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog); + + const long int clock_rate = metal_clock_get_rate_hz(clock); + + if (clock_rate == 0) + return -1; + + const unsigned int scale = (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) & METAL_WDOGCFG_SCALE_MASK); + + return clock_rate / (1 << scale); +} + +long int __metal_driver_sifive_wdog0_set_rate(const struct metal_watchdog *const wdog, const long int rate) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog); + + const long int clock_rate = metal_clock_get_rate_hz(clock); + + if (rate >= clock_rate) { + /* We can't scale the rate above the driving clock. Clear the scale + * field and return the driving clock rate */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK); + return clock_rate; + } + + /* Look for the closest scale value */ + long min_diff = LONG_MAX; + unsigned int min_scale = 0; + for (int i = 0; i < METAL_WDOGCFG_SCALE_MASK; i++) { + const long int new_rate = clock_rate / (1 << i); + + long int diff = rate - new_rate; + if (diff < 0) + diff *= -1; + + if (diff < min_diff) { + min_diff = diff; + min_scale = i; + } + } + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK); + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= (METAL_WDOGCFG_SCALE_MASK & min_scale); + + return clock_rate / (1 << min_scale); +} + +long int __metal_driver_sifive_wdog0_get_timeout(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + return (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) & METAL_WDOGCMP_MASK); +} + +long int __metal_driver_sifive_wdog0_set_timeout(const struct metal_watchdog *const wdog, const long int timeout) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Cap the timeout at the max value */ + const long int set_timeout = timeout > METAL_WDOGCMP_MASK ? METAL_WDOGCMP_MASK : timeout; + + /* If we edit the timeout value in-place by masking the compare value to 0 and + * then writing it, we cause a spurious interrupt because the compare value + * is temporarily 0. Instead, read the value into a local variable, modify it + * there, and then write the whole register back */ + uint32_t wdogcmp = WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP); + + wdogcmp &= ~(METAL_WDOGCMP_MASK); + wdogcmp |= set_timeout; + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) = wdogcmp; + + return set_timeout; +} + +int __metal_driver_sifive_wdog0_set_result(const struct metal_watchdog *const wdog, + const enum metal_watchdog_result result) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Turn off reset enable and counter reset */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_RSTEN | METAL_WDOGCFG_ZEROCMP); + + switch (result) { + default: + case METAL_WATCHDOG_NO_RESULT: + break; + case METAL_WATCHDOG_INTERRUPT: + /* Reset counter to zero after match */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ZEROCMP; + break; + case METAL_WATCHDOG_FULL_RESET: + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_RSTEN; + break; + } + + return 0; +} + +int __metal_driver_sifive_wdog0_run(const struct metal_watchdog *const wdog, + const enum metal_watchdog_run_option option) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_ENALWAYS | METAL_WDOGCFG_COREAWAKE); + + switch (option) { + default: + case METAL_WATCHDOG_STOP: + break; + case METAL_WATCHDOG_RUN_ALWAYS: + /* Feed the watchdog before starting to reset counter */ + __metal_driver_sifive_wdog0_feed(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ENALWAYS; + break; + case METAL_WATCHDOG_RUN_AWAKE: + /* Feed the watchdog before starting to reset counter */ + __metal_driver_sifive_wdog0_feed(wdog); + + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_COREAWAKE; + break; + } + + return 0; +} + +struct metal_interrupt *__metal_driver_sifive_wdog0_get_interrupt(const struct metal_watchdog *const wdog) +{ + return __metal_driver_sifive_wdog0_interrupt_parent(wdog); +} + +int __metal_driver_sifive_wdog0_get_interrupt_id(const struct metal_watchdog *const wdog) +{ + return __metal_driver_sifive_wdog0_interrupt_line(wdog); +} + +int __metal_driver_sifive_wdog0_clear_interrupt(const struct metal_watchdog *const wdog) +{ + const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog); + + /* Clear the interrupt pending bit */ + WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_IP); + + return 0; +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_wdog0) = { + .watchdog.feed = __metal_driver_sifive_wdog0_feed, + .watchdog.get_rate = __metal_driver_sifive_wdog0_get_rate, + .watchdog.set_rate = __metal_driver_sifive_wdog0_set_rate, + .watchdog.get_timeout = __metal_driver_sifive_wdog0_get_timeout, + .watchdog.set_timeout = __metal_driver_sifive_wdog0_set_timeout, + .watchdog.set_result = __metal_driver_sifive_wdog0_set_result, + .watchdog.run = __metal_driver_sifive_wdog0_run, + .watchdog.get_interrupt = __metal_driver_sifive_wdog0_get_interrupt, + .watchdog.get_interrupt_id = __metal_driver_sifive_wdog0_get_interrupt_id, + .watchdog.clear_interrupt = __metal_driver_sifive_wdog0_clear_interrupt, +}; + +#endif /* METAL_SIFIVE_WDOG0 */ + +typedef int no_empty_translation_units; + |