mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-19 17:48:33 -04:00
Starting point for IAR RISC-V project created some time ago - checking in now so it can be completed - currently work in progress.
This commit is contained in:
parent
5352cb4f45
commit
72af51cd86
16 changed files with 5179 additions and 0 deletions
172
FreeRTOS/Demo/RISC-V_RV32_SiFive_IAR/SiFive_code/riscv_plic0.c
Normal file
172
FreeRTOS/Demo/RISC-V_RV32_SiFive_IAR/SiFive_code/riscv_plic0.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* Copyright 2018 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_RISCV_PLIC0
|
||||
|
||||
#include <metal/io.h>
|
||||
#include <metal/shutdown.h>
|
||||
#include <metal/drivers/riscv_plic0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
unsigned int __metal_plic0_claim_interrupt (struct __metal_driver_riscv_plic0 *plic)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_CLAIM));
|
||||
}
|
||||
|
||||
void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
|
||||
unsigned int id)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_CLAIM)) = id;
|
||||
}
|
||||
|
||||
void __metal_plic0_set_threshold(struct __metal_driver_riscv_plic0 *plic,
|
||||
unsigned int threshold)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
|
||||
}
|
||||
|
||||
void __metal_plic0_set_priority(struct __metal_driver_riscv_plic0 *plic,
|
||||
int id, unsigned int priority)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 +
|
||||
METAL_RISCV_PLIC0_ENABLE_BASE +
|
||||
(id >> METAL_PLIC_SOURCE_SHIFT) * 4));
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_ENABLE_BASE +
|
||||
((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) =
|
||||
enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK)))
|
||||
: (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK)));
|
||||
}
|
||||
|
||||
void __metal_plic0_default_handler (int id, void *priv) {
|
||||
metal_shutdown(300);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
|
||||
plic->metal_exint_table[idx](idx,
|
||||
plic->metal_exdata_table[idx].exint_data);
|
||||
}
|
||||
|
||||
__metal_plic0_complete_interrupt(plic, idx);
|
||||
}
|
||||
|
||||
void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
|
||||
{
|
||||
struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
|
||||
|
||||
if ( !plic->init_done ) {
|
||||
int num_interrupts, line;
|
||||
struct metal_interrupt *intc;
|
||||
|
||||
for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) {
|
||||
num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller);
|
||||
intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent);
|
||||
line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent);
|
||||
|
||||
/* Initialize ist parent controller, aka cpu_intc. */
|
||||
intc->vtable->interrupt_init(intc);
|
||||
|
||||
for (int i = 0; i < num_interrupts; i++) {
|
||||
__metal_plic0_enable(plic, i, METAL_DISABLE);
|
||||
__metal_plic0_set_priority(plic, 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);
|
||||
|
||||
/* Register plic (ext) interrupt with with parent controller */
|
||||
intc->vtable->interrupt_register(intc, line, NULL, plic);
|
||||
/* Register plic handler for dispatching its device interrupts */
|
||||
intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic);
|
||||
/* Enable plic (ext) interrupt with with parent controller */
|
||||
intc->vtable->interrupt_enable(intc, line);
|
||||
}
|
||||
plic->init_done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
|
||||
int id, metal_interrupt_handler_t isr,
|
||||
void *priv)
|
||||
{
|
||||
struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
|
||||
|
||||
if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isr) {
|
||||
__metal_plic0_set_priority(plic ,id, 2);
|
||||
plic->metal_exint_table[id] = isr;
|
||||
plic->metal_exdata_table[id].exint_data = priv;
|
||||
} else {
|
||||
__metal_plic0_set_priority(plic, id, 1);
|
||||
plic->metal_exint_table[id] = __metal_plic0_default_handler;
|
||||
plic->metal_exdata_table[id].sub_int = priv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
|
||||
|
||||
if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
__metal_plic0_enable(plic, id, METAL_ENABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
|
||||
|
||||
if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
|
||||
return -1;
|
||||
}
|
||||
__metal_plic0_enable(plic, id, METAL_DISABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
|
||||
.plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init,
|
||||
.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,
|
||||
};
|
||||
|
||||
#endif /* METAL_RISCV_PLIC0 */
|
151
FreeRTOS/Demo/RISC-V_RV32_SiFive_IAR/SiFive_code/sifive_uart0.c
Normal file
151
FreeRTOS/Demo/RISC-V_RV32_SiFive_IAR/SiFive_code/sifive_uart0.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
/* Copyright 2018 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_UART0
|
||||
|
||||
#include <metal/drivers/sifive_uart0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
/* TXDATA Fields */
|
||||
#define UART_TXEN (1 << 0)
|
||||
#define UART_TXFULL (1 << 31)
|
||||
|
||||
/* RXDATA Fields */
|
||||
#define UART_RXEN (1 << 0)
|
||||
#define UART_RXEMPTY (1 << 31)
|
||||
|
||||
/* TXCTRL Fields */
|
||||
#define UART_NSTOP (1 << 1)
|
||||
#define UART_TXCNT(count) ((0x7 & count) << 16)
|
||||
|
||||
/* IP Fields */
|
||||
#define UART_TXWM (1 << 0)
|
||||
|
||||
#define UART_REG(offset) (((unsigned long)control_base + offset))
|
||||
#define UART_REGB(offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)UART_REG(offset)))
|
||||
#define UART_REGW(offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)UART_REG(offset)))
|
||||
|
||||
struct metal_interrupt *
|
||||
__metal_driver_sifive_uart0_interrupt_controller(struct metal_uart *uart)
|
||||
{
|
||||
return __metal_driver_sifive_uart0_interrupt_parent(uart);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
|
||||
while ((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL) != 0) { }
|
||||
UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, unsigned char *c)
|
||||
{
|
||||
uint32_t ch = UART_RXEMPTY;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
|
||||
while (ch & UART_RXEMPTY) {
|
||||
ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);
|
||||
}
|
||||
*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;
|
||||
return uart->baud_rate;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud_rate)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = (void *)guart;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(guart);
|
||||
struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
|
||||
|
||||
uart->baud_rate = baud_rate;
|
||||
|
||||
if (clock != NULL) {
|
||||
long clock_rate = clock->vtable->get_rate_hz(clock);
|
||||
UART_REGW(METAL_SIFIVE_UART0_DIV) = clock_rate / baud_rate - 1;
|
||||
UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXEN;
|
||||
UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXEN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pre_rate_change_callback(void *priv)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = priv;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv);
|
||||
struct metal_clock *clock = __metal_driver_sifive_uart0_clock((struct metal_uart *)priv);
|
||||
|
||||
/* Detect when the TXDATA is empty by setting the transmit watermark count
|
||||
* to one and waiting until an interrupt is pending */
|
||||
|
||||
UART_REGW(METAL_SIFIVE_UART0_TXCTRL) &= ~(UART_TXCNT(0x7));
|
||||
UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXCNT(1);
|
||||
|
||||
while((UART_REGW(METAL_SIFIVE_UART0_IP) & UART_TXWM) == 0) ;
|
||||
|
||||
/* When the TXDATA clears, the UART is still shifting out the last byte.
|
||||
* Calculate the time we must drain to finish transmitting and then wait
|
||||
* that long. */
|
||||
|
||||
long bits_per_symbol = (UART_REGW(METAL_SIFIVE_UART0_TXCTRL) & (1 << 1)) ? 9 : 10;
|
||||
long clk_freq = clock->vtable->get_rate_hz(clock);
|
||||
long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate;
|
||||
|
||||
for(volatile long x = 0; x < cycles_to_wait; x++)
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
static void post_rate_change_callback(void *priv)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = priv;
|
||||
metal_uart_set_baud_rate(&uart->uart, uart->baud_rate);
|
||||
}
|
||||
|
||||
void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = (void *)(guart);
|
||||
struct metal_clock *clock = __metal_driver_sifive_uart0_clock(guart);
|
||||
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);
|
||||
}
|
||||
|
||||
metal_uart_set_baud_rate(&(uart->uart), baud_rate);
|
||||
|
||||
if (pinmux != NULL) {
|
||||
long pinmux_output_selector = __metal_driver_sifive_uart0_pinmux_output_selector(guart);
|
||||
long pinmux_source_selector = __metal_driver_sifive_uart0_pinmux_source_selector(guart);
|
||||
pinmux->gpio.vtable->enable_io(
|
||||
(struct metal_gpio *) pinmux,
|
||||
pinmux_output_selector,
|
||||
pinmux_source_selector
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = {
|
||||
.uart.init = __metal_driver_sifive_uart0_init,
|
||||
.uart.putc = __metal_driver_sifive_uart0_putc,
|
||||
.uart.getc = __metal_driver_sifive_uart0_getc,
|
||||
.uart.get_baud_rate = __metal_driver_sifive_uart0_get_baud_rate,
|
||||
.uart.set_baud_rate = __metal_driver_sifive_uart0_set_baud_rate,
|
||||
.uart.controller_interrupt = __metal_driver_sifive_uart0_interrupt_controller,
|
||||
.uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id,
|
||||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_UART0 */
|
Loading…
Add table
Add a link
Reference in a new issue