diff --git a/platform/sifive/gpio.c b/platform/sifive/gpio.c new file mode 100644 index 00000000..a1dad95b --- /dev/null +++ b/platform/sifive/gpio.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile unsigned int *const gpio_base = (unsigned int *)GPIO_BASE; + +#define GPIO_REG_VALUE 0 +#define GPIO_REG_INPUT_EN 1 +#define GPIO_REG_OUTPUT_EN 2 +#define GPIO_REG_PORT 3 +#define GPIO_REG_PUE 4 +#define GPIO_REG_DS 5 +#define GPIO_REG_RISE_IE 6 +#define GPIO_REG_RISE_IP 7 +#define GPIO_REG_FALL_IE 8 +#define GPIO_REG_FALL_IP 9 +#define GPIO_REG_HIGH_IE 10 +#define GPIO_REG_HIGH_IP 11 +#define GPIO_REG_LOW_IE 12 +#define GPIO_REG_LOW_IP 13 +#define GPIO_REG_IOF_EN 14 +#define GPIO_REG_IOF_SEL 15 + +void gpio_early_init(void) {} +void gpio_init(void) {} + +__ALWAYS_INLINE +static inline void gpio_reg_bit_set(unsigned int reg, unsigned nr, bool set) { + if (set) { + __atomic_fetch_or(&gpio_base[reg], (1U << nr), __ATOMIC_RELAXED); + } else { + __atomic_fetch_and(&gpio_base[reg], ~(1U << nr), __ATOMIC_RELAXED); + } +} + +int gpio_config(unsigned nr, unsigned flags) { + if (nr >= 32) { + return ERR_INVALID_ARGS; + } + +#if PLATFORM_SIFIVE_E + // the alternate function feature only exists on the embedded variant + if (flags & GPIO_AF0) { // alternate function 0 + gpio_reg_bit_set(GPIO_REG_IOF_SEL, nr, 0); + gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 1); + } else if (flags & GPIO_AF0) { // alternate function 1 + gpio_reg_bit_set(GPIO_REG_IOF_SEL, nr, 1); + gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 1); + } else +#endif // PLATFORM_SIFIVE_E + { + if (flags & GPIO_INPUT) { + gpio_reg_bit_set(GPIO_REG_INPUT_EN, nr, 1); + } + if (flags & GPIO_OUTPUT) { + gpio_reg_bit_set(GPIO_REG_OUTPUT_EN, nr, 1); + } + if (flags & GPIO_PULLUP) { + gpio_reg_bit_set(GPIO_REG_PUE, nr, 1); + } else { + gpio_reg_bit_set(GPIO_REG_PUE, nr, 0); + } + +#if PLATFORM_SIFIVE_E + // clear the alternate function + gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 0); +#endif // PLATFORM_SIFIVE_E + } + + return 0; +} + +void gpio_set(unsigned nr, unsigned on) { + if (nr >= 32) { + return; + } + + // set and clear the LED gpios using atomic instructions + // polarity is inverted + if (on) { + gpio_reg_bit_set(GPIO_REG_PORT, nr, 0); + } else { + gpio_reg_bit_set(GPIO_REG_PORT, nr, 1); + } +} + +int gpio_get(unsigned nr) { + if (nr >= 32) { + return ERR_INVALID_ARGS; + } + + unsigned int val = gpio_base[GPIO_REG_VALUE] & (1U << nr); + return val ? 1 : 0; +} + diff --git a/platform/sifive/platform.c b/platform/sifive/platform.c index 76d69ad0..434ceafd 100644 --- a/platform/sifive/platform.c +++ b/platform/sifive/platform.c @@ -17,6 +17,8 @@ #include "platform_p.h" void platform_early_init(void) { + gpio_early_init(); + sifive_uart_early_init(); plic_early_init(); @@ -24,6 +26,7 @@ void platform_early_init(void) { void platform_init(void) { plic_init(); + gpio_init(); sifive_uart_init(); } diff --git a/platform/sifive/platform_p.h b/platform/sifive/platform_p.h index 03a2d7cb..b8a942e1 100644 --- a/platform/sifive/platform_p.h +++ b/platform/sifive/platform_p.h @@ -17,4 +17,7 @@ void sifive_uart_init(void); void plic_early_init(void); void plic_init(void); +void gpio_early_init(void); +void gpio_init(void); + diff --git a/platform/sifive/rules.mk b/platform/sifive/rules.mk index b2fc6e8e..342462cd 100644 --- a/platform/sifive/rules.mk +++ b/platform/sifive/rules.mk @@ -6,11 +6,13 @@ ARCH := riscv SUBARCH ?= 32 VARIANT ?= sifive_e +MODULE_DEPS += dev/gpio MODULE_DEPS += lib/cbuf MODULE_SRCS += $(LOCAL_DIR)/platform.c MODULE_SRCS += $(LOCAL_DIR)/plic.c MODULE_SRCS += $(LOCAL_DIR)/uart.c +MODULE_SRCS += $(LOCAL_DIR)/gpio.c ROMBASE ?= 0x20400000 # if running from rom, start here MEMBASE ?= 0x80000000 diff --git a/target/qemu-sifive-u/include/platform/sifive.h b/target/qemu-sifive-u/include/platform/sifive.h index c05ba0f3..08c8fe01 100644 --- a/target/qemu-sifive-u/include/platform/sifive.h +++ b/target/qemu-sifive-u/include/platform/sifive.h @@ -16,6 +16,7 @@ #define PLIC_BASE 0x0c000000 #define UART0_BASE 0x10010000 #define UART1_BASE 0x10011000 +#define GPIO_BASE 0x10060000 #if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET #define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0) diff --git a/target/sifive-e/include/platform/sifive.h b/target/sifive-e/include/platform/sifive.h index edaf65ce..7cc920ae 100644 --- a/target/sifive-e/include/platform/sifive.h +++ b/target/sifive-e/include/platform/sifive.h @@ -7,16 +7,33 @@ */ #pragma once +#define SIFIVE_IRQ_WATCHDOG 1 +#define SIFIVE_IRQ_RTC 2 #define SIFIVE_IRQ_UART0 3 #define SIFIVE_IRQ_UART1 4 +#define SIFIVE_IRQ_QSPI0 5 +#define SIFIVE_IRQ_QSPI1 6 +#define SIFIVE_IRQ_QSPI2 7 +#define SIFIVE_IRQ_GPIO_BASE 8 +#define SIFIVE_IRQ_GPIO(n) (SIFIVE_IRQ_GPIO_BASE+(n)) +#define SIFIVE_IRQ_PWM_BASE 40 -#define SIFIVE_NUM_IRQS 127 +#define SIFIVE_NUM_IRQS 64 #define CLINT_BASE 0x02000000 #define PLIC_BASE 0x0c000000 +#define AON_BASE 0x10000000 #define PRCI_BASE 0x10008000 +#define OTP_BASE 0x10010000 #define GPIO_BASE 0x10012000 #define UART0_BASE 0x10013000 +#define QSPI0_BASE 0x10014000 +#define PWM0_BASE 0x10015000 +#define UART1_BASE 0x10023000 +#define QSPI1_BASE 0x10024000 +#define PWM1_BASE 0x10025000 +#define QSPI2_BASE 0x10034000 +#define PWM2_BASE 0x10035000 #define GPIO_REG_VALUE 0 #define GPIO_REG_INPUT_EN 1 @@ -26,3 +43,6 @@ #define GPIO_REG_IOF_SEL 15 #define PLIC_HART_IDX(hart) 0 + +#define GPIO_AF0 (1U << 16) +#define GPIO_AF1 (1U << 17) diff --git a/target/sifive-e/target.c b/target/sifive-e/target.c index 48134ec3..39719027 100644 --- a/target/sifive-e/target.c +++ b/target/sifive-e/target.c @@ -9,9 +9,9 @@ #include #include #include +#include static volatile unsigned int *const prci_base = (unsigned int *)PRCI_BASE; -static volatile unsigned int *const gpio_base = (unsigned int *)GPIO_BASE; #define GPIO_LED_GREEN 19 #define GPIO_LED_BLUE 21 @@ -28,33 +28,35 @@ void target_early_init(void) { // lfclock is a 32768Hz crystal, strapped externally - // io function enable for pin 16/17, no IOF for all others - gpio_base[14] = (3<<16); + // set up all the gpios + for (uint i = 0; i < 32; i++) { + switch (i) { + // default to input + default: gpio_config(i, GPIO_INPUT); break; - // turn our LED gpios off - gpio_base[GPIO_REG_PORT] |= (1u << GPIO_LED_GREEN) | (1u << GPIO_LED_BLUE) | (1u << GPIO_LED_RED); + // uart0 + case 16: gpio_config(i, GPIO_AF0); break; + case 17: gpio_config(i, GPIO_AF0); break; - // set the led gpios to output - gpio_base[GPIO_REG_OUTPUT_EN] |= (1u << GPIO_LED_GREEN) | (1u << GPIO_LED_BLUE) | (1u << GPIO_LED_RED); + // set the led gpios to output and default to off + case GPIO_LED_GREEN: gpio_set(i, 0); gpio_config(i, GPIO_OUTPUT); break; + case GPIO_LED_RED: gpio_set(i, 0); gpio_config(i, GPIO_OUTPUT); break; + case GPIO_LED_BLUE: gpio_set(i, 0); gpio_config(i, GPIO_OUTPUT); break; + } + } } void target_set_debug_led(unsigned int led, bool on) { - uint val = 0; - if (led == 0) { - val = 1u << GPIO_LED_GREEN; - } else if (led == 1) { - val = 1u << GPIO_LED_RED; - } else if (led == 2) { - val = 1u << GPIO_LED_BLUE; + unsigned int gpio; + + switch (led) { + default: + case 0: gpio = GPIO_LED_GREEN; break; + case 1: gpio = GPIO_LED_RED; break; + case 2: gpio = GPIO_LED_BLUE; break; } - // set and clear the LED gpios using atomic instructions - // polarity is inverted - if (on) { - __atomic_fetch_and((int *)&gpio_base[GPIO_REG_PORT], ~val, __ATOMIC_RELAXED); - } else { - __atomic_fetch_or((int *)&gpio_base[GPIO_REG_PORT], val, __ATOMIC_RELAXED); - } + gpio_set(gpio, on ? 1 : 0); } void target_init(void) {