summaryrefslogtreecommitdiff
path: root/bsp/k210
diff options
context:
space:
mode:
authorFu Wei <[email protected]>2020-04-14 14:53:39 +0800
committerFu Wei <[email protected]>2020-04-26 19:51:35 +0800
commit609911bee9c1235151f5328e7dcae9880d6861f6 (patch)
tree13355927c3fc8992addd7446d42405bea8282cd2 /bsp/k210
parentbc7d903ce84003354eca9ecaaff5b414885c037a (diff)
[RISC-V:K210]Add UART1~3 support for K210
This patch adds UART1~3 support for K210, and separates the rt_uart_ops of UARTHS from UART. This patch add configs in Kconfig for configuring the pins of UARTx, please check the sysctl_set_power_mode for the pins in the io_config_init of bsp/k210/driver/drv_io_config.c Signed-off-by: Fu Wei <[email protected]>
Diffstat (limited to 'bsp/k210')
-rw-r--r--bsp/k210/driver/Kconfig39
-rw-r--r--bsp/k210/driver/drv_io_config.c22
-rw-r--r--bsp/k210/driver/drv_uart.c296
3 files changed, 314 insertions, 43 deletions
diff --git a/bsp/k210/driver/Kconfig b/bsp/k210/driver/Kconfig
index 4d38a7c9b2..8acbf5202c 100644
--- a/bsp/k210/driver/Kconfig
+++ b/bsp/k210/driver/Kconfig
@@ -2,17 +2,44 @@ config BSP_USING_UART_HS
bool "Enable High Speed UART"
default y
-config BSP_USING_UART1
- bool "Enable UART1 (GPIO0/1)"
+menu "General Purpose UARTs"
+
+menuconfig BSP_USING_UART1
+ bool "Enable UART1"
default n
+ if BSP_USING_UART1
+ config BSP_UART1_TXD_PIN
+ int "uart1 TXD pin number"
+ default 20
+ config BSP_UART1_RXD_PIN
+ int "uart1 RXD pin number"
+ default 21
+ endif
-config BSP_USING_UART2
- bool "Enable UART2 (GPIO0/1)"
+menuconfig BSP_USING_UART2
+ bool "Enable UART2"
default n
+ if BSP_USING_UART2
+ config BSP_UART2_TXD_PIN
+ int "uart2 TXD pin number"
+ default 28
+ config BSP_UART2_RXD_PIN
+ int "uart2 RXD pin number"
+ default 27
+ endif
-config BSP_USING_UART3
- bool "Enable UART3 (GPIO0/1)"
+menuconfig BSP_USING_UART3
+ bool "Enable UART3"
default n
+ if BSP_USING_UART3
+ config BSP_UART3_TXD_PIN
+ int "uart3 TXD pin number"
+ default 22
+ config BSP_UART3_RXD_PIN
+ int "uart3 RXD pin number"
+ default 23
+ endif
+endmenu
config BSP_USING_I2C1
bool "Enable I2C1 (GPIO0/1)"
diff --git a/bsp/k210/driver/drv_io_config.c b/bsp/k210/driver/drv_io_config.c
index cd0e8f27f6..3098537eae 100644
--- a/bsp/k210/driver/drv_io_config.c
+++ b/bsp/k210/driver/drv_io_config.c
@@ -63,6 +63,18 @@ static struct io_config
#endif
#endif
+#ifdef BSP_USING_UART1
+ IOCONFIG(BSP_UART1_TXD_PIN, FUNC_UART1_TX),
+ IOCONFIG(BSP_UART1_RXD_PIN, FUNC_UART1_RX),
+#endif
+#ifdef BSP_USING_UART2
+ IOCONFIG(BSP_UART2_TXD_PIN, FUNC_UART2_TX),
+ IOCONFIG(BSP_UART2_RXD_PIN, FUNC_UART2_RX),
+#endif
+#ifdef BSP_USING_UART3
+ IOCONFIG(BSP_UART3_TXD_PIN, FUNC_UART3_TX),
+ IOCONFIG(BSP_UART3_RXD_PIN, FUNC_UART3_RX),
+#endif
};
static int print_io_config()
@@ -89,7 +101,15 @@ int io_config_init(void)
sysctl_set_power_mode(SYSCTL_POWER_BANK0, SYSCTL_POWER_V18);
sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18);
sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18);
-
+#ifdef BSP_USING_UART2
+ // for IO-27/28
+ sysctl_set_power_mode(SYSCTL_POWER_BANK4, SYSCTL_POWER_V33);
+#endif
+#if defined(BSP_USING_UART1) || defined(BSP_USING_UART3)
+ // for IO-20~23
+ sysctl_set_power_mode(SYSCTL_POWER_BANK3, SYSCTL_POWER_V33);
+#endif
+
for(i = 0; i < count; i++)
{
fpioa_set_function(io_config[i].io_num, io_config[i].func);
diff --git a/bsp/k210/driver/drv_uart.c b/bsp/k210/driver/drv_uart.c
index 7e22d40c5d..830b14cbbc 100644
--- a/bsp/k210/driver/drv_uart.c
+++ b/bsp/k210/driver/drv_uart.c
@@ -17,10 +17,12 @@
#include <stdio.h>
#include <sysctl.h>
-// #include "uart.h"
+#include "uart.h"
#include "uarths.h"
#include "plic.h"
+#define UART_DEFAULT_BAUDRATE 115200
+
static volatile uarths_t *const _uarths = (volatile uarths_t *)UARTHS_BASE_ADDR;
struct device_uart
@@ -29,22 +31,71 @@ struct device_uart
rt_uint32_t irqno;
};
-static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
+static rt_err_t rt_uarths_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
+static rt_err_t uarths_control(struct rt_serial_device *serial, int cmd, void *arg);
+static int drv_uarths_putc(struct rt_serial_device *serial, char c);
+static int drv_uarths_getc(struct rt_serial_device *serial);
+
+static void uarths_irq_handler(int irqno, void *param);
+
+static rt_err_t rt_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg);
static int drv_uart_putc(struct rt_serial_device *serial, char c);
static int drv_uart_getc(struct rt_serial_device *serial);
static void uart_irq_handler(int irqno, void *param);
+const struct rt_uart_ops _uart_hs_ops =
+{
+ rt_uarths_configure,
+ uarths_control,
+ drv_uarths_putc,
+ drv_uarths_getc,
+ RT_NULL
+};
+
const struct rt_uart_ops _uart_ops =
{
- uart_configure,
+ rt_uart_configure,
uart_control,
drv_uart_putc,
drv_uart_getc,
+ //TODO: add DMA support
RT_NULL
};
+/* START ported from kendryte standalone sdk uart.c */
+#define __UART_BRATE_CONST 16
+
+volatile uart_t* const _uart[3] =
+{
+ (volatile uart_t*)UART1_BASE_ADDR,
+ (volatile uart_t*)UART2_BASE_ADDR,
+ (volatile uart_t*)UART3_BASE_ADDR
+};
+
+void uart_init(uart_device_number_t channel)
+{
+ sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel);
+ sysctl_reset(SYSCTL_RESET_UART1 + channel);
+}
+
+/* END ported from kendryte standalone sdk uart.c */
+static inline uart_device_number_t _get_uart_channel(rt_uint32_t addr)
+{
+ switch (addr)
+ {
+ case UART1_BASE_ADDR:
+ return UART_DEVICE_1;
+ case UART2_BASE_ADDR:
+ return UART_DEVICE_2;
+ case UART3_BASE_ADDR:
+ return UART_DEVICE_3;
+ default:
+ return UART_DEVICE_MAX;
+ }
+}
+
/*
* UART Initiation
*/
@@ -62,7 +113,7 @@ int rt_hw_uart_init(void)
serial = &serial_hs;
uart = &uart_hs;
- serial->ops = &_uart_ops;
+ serial->ops = &_uart_hs_ops;
serial->config = config;
serial->config.baud_rate = 115200;
@@ -86,36 +137,79 @@ int rt_hw_uart_init(void)
serial->ops = &_uart_ops;
serial->config = config;
- serial->config.baud_rate = 115200;
+ serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
uart->hw_base = UART1_BASE_ADDR;
uart->irqno = IRQN_UART1_INTERRUPT;
+ uart_init(UART_DEVICE_1);
+
rt_hw_serial_register(serial,
- "uarths",
+ "uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
}
#endif
#ifdef BSP_USING_UART2
+ {
+ static struct rt_serial_device serial2;
+ static struct device_uart uart2;
+
+ serial = &serial2;
+ uart = &uart2;
+
+ serial->ops = &_uart_ops;
+ serial->config = config;
+ serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
+
+ uart->hw_base = UART2_BASE_ADDR;
+ uart->irqno = IRQN_UART2_INTERRUPT;
+
+ uart_init(UART_DEVICE_2);
+
+ rt_hw_serial_register(serial,
+ "uart2",
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
+ uart);
+ }
#endif
#ifdef BSP_USING_UART3
+ {
+ static struct rt_serial_device serial3;
+ static struct device_uart uart3;
+
+ serial = &serial3;
+ uart = &uart3;
+
+ serial->ops = &_uart_ops;
+ serial->config = config;
+ serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
+
+ uart->hw_base = UART3_BASE_ADDR;
+ uart->irqno = IRQN_UART3_INTERRUPT;
+
+ uart_init(UART_DEVICE_3);
+
+ rt_hw_serial_register(serial,
+ "uart3",
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
+ uart);
+ }
#endif
return 0;
}
/*
- * UART interface
+ * UARTHS interface
*/
-static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+static rt_err_t rt_uarths_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
- rt_uint32_t baud_div;
struct device_uart *uart;
- uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
- uint16_t div = freq / cfg->baud_rate - 1;
+ uint32_t freq_hs = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
+ uint16_t div_hs = freq_hs / cfg->baud_rate - 1;
RT_ASSERT(serial != RT_NULL);
serial->config = *cfg;
@@ -125,7 +219,7 @@ static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_co
if (uart->hw_base == UARTHS_BASE_ADDR)
{
- _uarths->div.div = div;
+ _uarths->div.div = div_hs;
_uarths->txctrl.txen = 1;
_uarths->rxctrl.rxen = 1;
_uarths->txctrl.txcnt = 0;
@@ -137,13 +231,14 @@ static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_co
}
else
{
+ return (-1);
/* other uart */
}
return (RT_EOK);
}
-static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+static rt_err_t uarths_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct device_uart *uart;
@@ -160,7 +255,7 @@ static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg
case RT_DEVICE_CTRL_SET_INT:
/* install interrupt */
- rt_hw_interrupt_install(uart->irqno, uart_irq_handler,
+ rt_hw_interrupt_install(uart->irqno, uarths_irq_handler,
serial, serial->parent.parent.name);
rt_hw_interrupt_umask(uart->irqno);
break;
@@ -169,38 +264,168 @@ static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg
return (RT_EOK);
}
-static int drv_uart_putc(struct rt_serial_device *serial, char c)
+
+static int drv_uarths_putc(struct rt_serial_device *serial, char c)
+{
+ struct device_uart *uart = serial->parent.user_data;
+ RT_ASSERT(uart->hw_base == UARTHS_BASE_ADDR);
+
+ while (_uarths->txdata.full);
+ _uarths->txdata.data = (uint8_t)c;
+
+ return (1);
+}
+
+static int drv_uarths_getc(struct rt_serial_device *serial)
+{
+ struct device_uart *uart = serial->parent.user_data;
+ RT_ASSERT(uart->hw_base == UARTHS_BASE_ADDR);
+
+ uarths_rxdata_t recv = _uarths->rxdata;
+ if (recv.empty)
+ return EOF;
+ else
+ return (recv.data & 0xff);
+ /* Receive Data Available */
+
+ return (-1);
+}
+
+/* UARTHS ISR */
+static void uarths_irq_handler(int irqno, void *param)
+{
+ struct rt_serial_device *serial = (struct rt_serial_device *)param;
+ struct device_uart *uart = serial->parent.user_data;
+ RT_ASSERT(uart->hw_base == UARTHS_BASE_ADDR);
+
+ /* read interrupt status and clear it */
+ if (_uarths->ip.rxwm)
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+}
+
+/*
+ * UART interface
+ */
+static rt_err_t rt_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct device_uart *uart;
+ uart_bitwidth_t data_width = (uart_bitwidth_t)cfg->data_bits ;
+ uart_stopbit_t stopbit = (uart_stopbit_t)cfg->stop_bits;
+ uart_parity_t parity = (uart_parity_t)cfg->parity;
+
+ uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+ uint32_t divisor = freq / (uint32_t)cfg->baud_rate;
+ uint8_t dlh = divisor >> 12;
+ uint8_t dll = (divisor - (dlh << 12)) / __UART_BRATE_CONST;
+ uint8_t dlf = divisor - (dlh << 12) - dll * __UART_BRATE_CONST;
+
+ RT_ASSERT(serial != RT_NULL);
+ serial->config = *cfg;
uart = serial->parent.user_data;
- if (uart->hw_base == UARTHS_BASE_ADDR)
+ RT_ASSERT(uart != RT_NULL);
+
+ uart_device_number_t channel = _get_uart_channel(uart->hw_base);
+ RT_ASSERT(channel != UART_DEVICE_MAX);
+
+ RT_ASSERT(data_width >= 5 && data_width <= 8);
+ if (data_width == 5)
{
- while (_uarths->txdata.full);
- _uarths->txdata.data = (uint8_t)c;
+ RT_ASSERT(stopbit != UART_STOP_2);
}
else
{
- /* other uart */
+ RT_ASSERT(stopbit != UART_STOP_1_5);
}
- return (1);
+ uint32_t stopbit_val = stopbit == UART_STOP_1 ? 0 : 1;
+ uint32_t parity_val;
+ switch (parity)
+ {
+ case UART_PARITY_NONE:
+ parity_val = 0;
+ break;
+ case UART_PARITY_ODD:
+ parity_val = 1;
+ break;
+ case UART_PARITY_EVEN:
+ parity_val = 3;
+ break;
+ default:
+ RT_ASSERT(!"Invalid parity");
+ break;
+ }
+
+ _uart[channel]->LCR |= 1u << 7;
+ _uart[channel]->DLH = dlh;
+ _uart[channel]->DLL = dll;
+ _uart[channel]->DLF = dlf;
+ _uart[channel]->LCR = 0;
+ _uart[channel]->LCR = (data_width - 5) |
+ (stopbit_val << 2) |
+ (parity_val << 3);
+ _uart[channel]->LCR &= ~(1u << 7);
+ _uart[channel]->IER |= 0x80; /* THRE */
+ _uart[channel]->FCR = UART_RECEIVE_FIFO_1 << 6 |
+ UART_SEND_FIFO_8 << 4 |
+ 0x1 << 3 |
+ 0x1;
+
+ return (RT_EOK);
}
-static int drv_uart_getc(struct rt_serial_device *serial)
+static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
- int ret = -1;
- struct device_uart *uart = serial->parent.user_data;
+ struct device_uart *uart;
- if (uart->hw_base == UARTHS_BASE_ADDR)
+ uart = serial->parent.user_data;
+ uart_device_number_t channel = _get_uart_channel(uart->hw_base);
+
+ RT_ASSERT(uart != RT_NULL);
+ RT_ASSERT(channel != UART_DEVICE_MAX);
+
+ switch (cmd)
{
- uarths_rxdata_t recv = _uarths->rxdata;
- if (recv.empty)
- return EOF;
- else
- return (recv.data & 0xff);
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* Disable the UART Interrupt */
+ rt_hw_interrupt_mask(uart->irqno);
+ _uart[channel]->IER &= ~0x1;
+ break;
+
+ case RT_DEVICE_CTRL_SET_INT:
+ /* install interrupt */
+ rt_hw_interrupt_install(uart->irqno, uart_irq_handler,
+ serial, serial->parent.parent.name);
+ rt_hw_interrupt_umask(uart->irqno);
+ _uart[channel]->IER |= 0x1;
+ break;
}
+ return (RT_EOK);
+}
+
+static int drv_uart_putc(struct rt_serial_device *serial, char c)
+{
+ struct device_uart *uart = serial->parent.user_data;
+ uart_device_number_t channel = _get_uart_channel(uart->hw_base);
+ RT_ASSERT(channel != UART_DEVICE_MAX);
+
+ while (_uart[channel]->LSR & (1u << 5));
+ _uart[channel]->THR = c;
+
+ return (1);
+}
+
+static int drv_uart_getc(struct rt_serial_device *serial)
+{
+ struct device_uart *uart = serial->parent.user_data;
+ uart_device_number_t channel = _get_uart_channel(uart->hw_base);
+ RT_ASSERT(channel != UART_DEVICE_MAX);
+
+ if (_uart[channel]->LSR & 1)
+ return (char)(_uart[channel]->RBR & 0xff);
+ else
+ return EOF;
/* Receive Data Available */
return (-1);
@@ -209,21 +434,20 @@ static int drv_uart_getc(struct rt_serial_device *serial)
/* UART ISR */
static void uart_irq_handler(int irqno, void *param)
{
- rt_ubase_t isr;
struct rt_serial_device *serial = (struct rt_serial_device *)param;
struct device_uart *uart = serial->parent.user_data;
+ uart_device_number_t channel = _get_uart_channel(uart->hw_base);
+ RT_ASSERT(channel != UART_DEVICE_MAX);
/* read interrupt status and clear it */
- if (uart->hw_base == UARTHS_BASE_ADDR)
- {
- if (_uarths->ip.rxwm)
- rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
- }
+ if (_uart[channel]->LSR)
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
}
/* WEAK for SDK 0.5.6 */
-RT_WEAK void uart_debug_init(int uart_channel)
+RT_WEAK void uart_debug_init(uart_device_number_t uart_channel)
{
}
+