[platform][sifive] add a GPIO driver and switch the target setup to it
This commit is contained in:
109
platform/sifive/gpio.c
Normal file
109
platform/sifive/gpio.c
Normal file
@@ -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 <lk/err.h>
|
||||||
|
#include <lk/reg.h>
|
||||||
|
#include <lk/trace.h>
|
||||||
|
#include <kernel/thread.h>
|
||||||
|
#include <platform.h>
|
||||||
|
#include <platform/interrupts.h>
|
||||||
|
#include <platform/debug.h>
|
||||||
|
#include <platform/sifive.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dev/gpio.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "platform_p.h"
|
#include "platform_p.h"
|
||||||
|
|
||||||
void platform_early_init(void) {
|
void platform_early_init(void) {
|
||||||
|
gpio_early_init();
|
||||||
|
|
||||||
sifive_uart_early_init();
|
sifive_uart_early_init();
|
||||||
|
|
||||||
plic_early_init();
|
plic_early_init();
|
||||||
@@ -24,6 +26,7 @@ void platform_early_init(void) {
|
|||||||
|
|
||||||
void platform_init(void) {
|
void platform_init(void) {
|
||||||
plic_init();
|
plic_init();
|
||||||
|
gpio_init();
|
||||||
sifive_uart_init();
|
sifive_uart_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,7 @@ void sifive_uart_init(void);
|
|||||||
void plic_early_init(void);
|
void plic_early_init(void);
|
||||||
void plic_init(void);
|
void plic_init(void);
|
||||||
|
|
||||||
|
void gpio_early_init(void);
|
||||||
|
void gpio_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ ARCH := riscv
|
|||||||
SUBARCH ?= 32
|
SUBARCH ?= 32
|
||||||
VARIANT ?= sifive_e
|
VARIANT ?= sifive_e
|
||||||
|
|
||||||
|
MODULE_DEPS += dev/gpio
|
||||||
MODULE_DEPS += lib/cbuf
|
MODULE_DEPS += lib/cbuf
|
||||||
|
|
||||||
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
||||||
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
MODULE_SRCS += $(LOCAL_DIR)/plic.c
|
||||||
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
||||||
|
MODULE_SRCS += $(LOCAL_DIR)/gpio.c
|
||||||
|
|
||||||
ROMBASE ?= 0x20400000 # if running from rom, start here
|
ROMBASE ?= 0x20400000 # if running from rom, start here
|
||||||
MEMBASE ?= 0x80000000
|
MEMBASE ?= 0x80000000
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#define PLIC_BASE 0x0c000000
|
#define PLIC_BASE 0x0c000000
|
||||||
#define UART0_BASE 0x10010000
|
#define UART0_BASE 0x10010000
|
||||||
#define UART1_BASE 0x10011000
|
#define UART1_BASE 0x10011000
|
||||||
|
#define GPIO_BASE 0x10060000
|
||||||
|
|
||||||
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
||||||
#define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0)
|
#define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0)
|
||||||
|
|||||||
@@ -7,16 +7,33 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define SIFIVE_IRQ_WATCHDOG 1
|
||||||
|
#define SIFIVE_IRQ_RTC 2
|
||||||
#define SIFIVE_IRQ_UART0 3
|
#define SIFIVE_IRQ_UART0 3
|
||||||
#define SIFIVE_IRQ_UART1 4
|
#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 CLINT_BASE 0x02000000
|
||||||
#define PLIC_BASE 0x0c000000
|
#define PLIC_BASE 0x0c000000
|
||||||
|
#define AON_BASE 0x10000000
|
||||||
#define PRCI_BASE 0x10008000
|
#define PRCI_BASE 0x10008000
|
||||||
|
#define OTP_BASE 0x10010000
|
||||||
#define GPIO_BASE 0x10012000
|
#define GPIO_BASE 0x10012000
|
||||||
#define UART0_BASE 0x10013000
|
#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_VALUE 0
|
||||||
#define GPIO_REG_INPUT_EN 1
|
#define GPIO_REG_INPUT_EN 1
|
||||||
@@ -26,3 +43,6 @@
|
|||||||
#define GPIO_REG_IOF_SEL 15
|
#define GPIO_REG_IOF_SEL 15
|
||||||
|
|
||||||
#define PLIC_HART_IDX(hart) 0
|
#define PLIC_HART_IDX(hart) 0
|
||||||
|
|
||||||
|
#define GPIO_AF0 (1U << 16)
|
||||||
|
#define GPIO_AF1 (1U << 17)
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#include <target.h>
|
#include <target.h>
|
||||||
#include <arch/arch_ops.h>
|
#include <arch/arch_ops.h>
|
||||||
#include <platform/sifive.h>
|
#include <platform/sifive.h>
|
||||||
|
#include <dev/gpio.h>
|
||||||
|
|
||||||
static volatile unsigned int *const prci_base = (unsigned int *)PRCI_BASE;
|
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_GREEN 19
|
||||||
#define GPIO_LED_BLUE 21
|
#define GPIO_LED_BLUE 21
|
||||||
@@ -28,33 +28,35 @@ void target_early_init(void) {
|
|||||||
|
|
||||||
// lfclock is a 32768Hz crystal, strapped externally
|
// lfclock is a 32768Hz crystal, strapped externally
|
||||||
|
|
||||||
// io function enable for pin 16/17, no IOF for all others
|
// set up all the gpios
|
||||||
gpio_base[14] = (3<<16);
|
for (uint i = 0; i < 32; i++) {
|
||||||
|
switch (i) {
|
||||||
|
// default to input
|
||||||
|
default: gpio_config(i, GPIO_INPUT); break;
|
||||||
|
|
||||||
// turn our LED gpios off
|
// uart0
|
||||||
gpio_base[GPIO_REG_PORT] |= (1u << GPIO_LED_GREEN) | (1u << GPIO_LED_BLUE) | (1u << GPIO_LED_RED);
|
case 16: gpio_config(i, GPIO_AF0); break;
|
||||||
|
case 17: gpio_config(i, GPIO_AF0); break;
|
||||||
|
|
||||||
// set the led gpios to output
|
// set the led gpios to output and default to off
|
||||||
gpio_base[GPIO_REG_OUTPUT_EN] |= (1u << GPIO_LED_GREEN) | (1u << GPIO_LED_BLUE) | (1u << GPIO_LED_RED);
|
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) {
|
void target_set_debug_led(unsigned int led, bool on) {
|
||||||
uint val = 0;
|
unsigned int gpio;
|
||||||
if (led == 0) {
|
|
||||||
val = 1u << GPIO_LED_GREEN;
|
switch (led) {
|
||||||
} else if (led == 1) {
|
default:
|
||||||
val = 1u << GPIO_LED_RED;
|
case 0: gpio = GPIO_LED_GREEN; break;
|
||||||
} else if (led == 2) {
|
case 1: gpio = GPIO_LED_RED; break;
|
||||||
val = 1u << GPIO_LED_BLUE;
|
case 2: gpio = GPIO_LED_BLUE; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set and clear the LED gpios using atomic instructions
|
gpio_set(gpio, on ? 1 : 0);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void target_init(void) {
|
void target_init(void) {
|
||||||
|
|||||||
Reference in New Issue
Block a user