From 2598762fe03412be9e72cbb0f2a201774e2ae146 Mon Sep 17 00:00:00 2001 From: Bunnaroath Sou Date: Tue, 1 Oct 2019 18:40:46 -0700 Subject: [PATCH 1/2] Uart driver interrupt support --- metal/drivers/sifive_clic0.h | 2 +- metal/uart.h | 82 ++++++++++++++++++++++++++++++++++++ src/drivers/sifive_uart0.c | 71 ++++++++++++++++++++++++++++++- src/uart.c | 11 +++++ 4 files changed, 163 insertions(+), 3 deletions(-) diff --git a/metal/drivers/sifive_clic0.h b/metal/drivers/sifive_clic0.h index ab170fc9..25394412 100644 --- a/metal/drivers/sifive_clic0.h +++ b/metal/drivers/sifive_clic0.h @@ -34,7 +34,7 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0) struct __metal_driver_sifive_clic0 { struct metal_interrupt controller; int init_done; - int pad[14]; + struct {} __attribute__ ((aligned (64))); metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS]; __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS]; diff --git a/metal/uart.h b/metal/uart.h index e83aaed0..47443dfc 100644 --- a/metal/uart.h +++ b/metal/uart.h @@ -23,6 +23,14 @@ struct metal_uart_vtable { int (*set_baud_rate)(struct metal_uart *uart, int baud_rate); struct metal_interrupt *(*controller_interrupt)(struct metal_uart *uart); int (*get_interrupt_id)(struct metal_uart *uart); + int (*tx_interrupt_enable)(struct metal_uart *uart); + int (*tx_interrupt_disable)(struct metal_uart *uart); + int (*rx_interrupt_enable)(struct metal_uart *uart); + int (*rx_interrupt_disable)(struct metal_uart *uart); + int (*set_tx_watermark)(struct metal_uart *uart, size_t length); + size_t (*get_tx_watermark)(struct metal_uart *uart); + int (*set_rx_watermark)(struct metal_uart *uart, size_t length); + size_t (*get_rx_watermark)(struct metal_uart *uart); }; /*! @@ -123,4 +131,78 @@ __inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); } +/*! + * @brief Enable the UART transmit interrupt + * @param uart The UART device handle + * @return 0 upon success + */ +__inline__ int metal_uart_transmit_interrupt_enable(struct metal_uart *uart) { + return uart->vtable->tx_interrupt_enable(uart); +} + +/*! + * @brief Disable the UART transmit interrupt + * @param uart The UART device handle + * @return 0 upon success + */ +__inline__ int metal_uart_transmit_interrupt_disable(struct metal_uart *uart) { + return uart->vtable->tx_interrupt_disable(uart); +} + +/*! + * @brief Enable the UART receive interrupt + * @param uart The UART device handle + * @return 0 upon success + */ +__inline__ int metal_uart_receive_interrupt_enable(struct metal_uart *uart) { + return uart->vtable->rx_interrupt_enable(uart); +} + +/*! + * @brief Disable the UART receive interrupt + * @param uart The UART device handle + * @return 0 upon success + */ +__inline__ int metal_uart_receive_interrupt_disable(struct metal_uart *uart) { + return uart->vtable->rx_interrupt_disable(uart); +} + +/*! + * @brief Set the transmit watermark level of the UART controller + * @param uart The UART device handle + * @param level The UART transmit watermark level + * @return 0 upon success + */ +__inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, size_t level) { + return uart->vtable->set_tx_watermark(uart, level); +} + +/*! + * @brief Get the transmit watermark level of the UART controller + * @param uart The UART device handle + * @return The UART transmit watermark level + */ +__inline__ size_t metal_uart_get_transmit_watermark(struct metal_uart *uart) { + return uart->vtable->get_tx_watermark(uart); +} + +/*! + * @brief Set the receive watermark level of the UART controller + * @param uart The UART device handle + * @param level The UART transmit watermark level + * @return 0 upon success + */ +__inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, size_t level) { + return uart->vtable->set_rx_watermark(uart, level); +} + +/*! + * @brief Get the receive watermark level of the UART controller + * @param uart The UART device handle + * @return The UART transmit watermark level + */ +__inline__ size_t metal_uart_get_receive_watermark(struct metal_uart *uart) { + return uart->vtable->get_rx_watermark(uart); +} + #endif diff --git a/src/drivers/sifive_uart0.c b/src/drivers/sifive_uart0.c index e98582dc..16ac1a44 100644 --- a/src/drivers/sifive_uart0.c +++ b/src/drivers/sifive_uart0.c @@ -20,8 +20,12 @@ #define UART_NSTOP (1 << 1) #define UART_TXCNT(count) ((0x7 & count) << 16) +/* RXCTRL Fields */ +#define UART_RXCNT(count) ((0x7 & count) << 16) + /* IP Fields */ #define UART_TXWM (1 << 0) +#define UART_RXWM (1 << 1) #define UART_REG(offset) (((unsigned long)control_base + offset)) #define UART_REGB(offset) \ @@ -35,8 +39,35 @@ __metal_driver_sifive_uart0_interrupt_controller(struct metal_uart *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); + return __metal_driver_sifive_uart0_interrupt_line(uart); +} + +int __metal_driver_sifive_uart0_tx_interrupt_enable(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_IE) |= UART_TXWM; + return 0; +} + +int __metal_driver_sifive_uart0_tx_interrupt_disable(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_IE) &= ~UART_TXWM; + return 0; +} + +int __metal_driver_sifive_uart0_rx_interrupt_enable(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_IE) |= UART_RXWM; + return 0; +} + +int __metal_driver_sifive_uart0_rx_interrupt_disable(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_IE) &= ~UART_RXWM; + return 0; } int __metal_driver_sifive_uart0_txready(struct metal_uart *uart) { @@ -45,6 +76,34 @@ int __metal_driver_sifive_uart0_txready(struct metal_uart *uart) { return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL)); } +int __metal_driver_sifive_uart0_set_tx_watermark(struct metal_uart *uart, + size_t level) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_TXCTRL) |= UART_TXCNT(level); + return 0; +} + +size_t __metal_driver_sifive_uart0_get_tx_watermark(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + return ((UART_REGW(METAL_SIFIVE_UART0_TXCTRL) >> 16) & 0x7); +} + +int __metal_driver_sifive_uart0_set_rx_watermark(struct metal_uart *uart, + size_t level) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXCNT(level); + return 0; +} + +size_t __metal_driver_sifive_uart0_get_rx_watermark(struct metal_uart *uart) { + long control_base = __metal_driver_sifive_uart0_control_base(uart); + + return ((UART_REGW(METAL_SIFIVE_UART0_RXCTRL) >> 16) & 0x7); +} + int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c) { long control_base = __metal_driver_sifive_uart0_control_base(uart); @@ -167,6 +226,14 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = { .uart.controller_interrupt = __metal_driver_sifive_uart0_interrupt_controller, .uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id, + .uart.tx_interrupt_enable = __metal_driver_sifive_uart0_tx_interrupt_enable, + .uart.tx_interrupt_disable = __metal_driver_sifive_uart0_tx_interrupt_disable, + .uart.rx_interrupt_enable = __metal_driver_sifive_uart0_rx_interrupt_enable, + .uart.rx_interrupt_disable = __metal_driver_sifive_uart0_rx_interrupt_disable, + .uart.set_tx_watermark = __metal_driver_sifive_uart0_set_tx_watermark, + .uart.get_tx_watermark = __metal_driver_sifive_uart0_get_tx_watermark, + .uart.set_rx_watermark = __metal_driver_sifive_uart0_set_rx_watermark, + .uart.get_rx_watermark = __metal_driver_sifive_uart0_get_rx_watermark, }; #endif /* METAL_SIFIVE_UART0 */ diff --git a/src/uart.c b/src/uart.c index fad237bb..32591193 100644 --- a/src/uart.c +++ b/src/uart.c @@ -10,3 +10,14 @@ extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c); extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart); extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate); +extern __inline__ struct metal_interrupt* metal_uart_interrupt_controller( + struct metal_uart *uart); +extern __inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart); +extern __inline__ int metal_uart_transmit_interrupt_enable(struct metal_uart *uart); +extern __inline__ int metal_uart_transmit_interrupt_disable(struct metal_uart *uart); +extern __inline__ int metal_uart_receive_interrupt_enable(struct metal_uart *uart); +extern __inline__ int metal_uart_receive_interrupt_disable(struct metal_uart *uart); +extern __inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, size_t level); +extern __inline__ size_t metal_uart_get_transmit_watermark(struct metal_uart *uart); +extern __inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, size_t level); +extern __inline__ size_t metal_uart_get_receive_watermark(struct metal_uart *uart); From 8231b9950bb6539f307877dd331f9b78805124c1 Mon Sep 17 00:00:00 2001 From: Bunnaroath Sou Date: Fri, 4 Oct 2019 10:52:08 -0700 Subject: [PATCH 2/2] Fix formating --- metal/drivers/sifive_clic0.h | 3 ++- metal/uart.h | 6 ++++-- src/drivers/sifive_uart0.c | 8 +++++--- src/uart.c | 28 ++++++++++++++++++---------- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/metal/drivers/sifive_clic0.h b/metal/drivers/sifive_clic0.h index 25394412..9306816f 100644 --- a/metal/drivers/sifive_clic0.h +++ b/metal/drivers/sifive_clic0.h @@ -34,7 +34,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0) struct __metal_driver_sifive_clic0 { struct metal_interrupt controller; int init_done; - struct {} __attribute__ ((aligned (64))); + struct { + } __attribute__((aligned(64))); metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS]; __metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS]; diff --git a/metal/uart.h b/metal/uart.h index d389c314..856970ac 100644 --- a/metal/uart.h +++ b/metal/uart.h @@ -178,7 +178,8 @@ __inline__ int metal_uart_receive_interrupt_disable(struct metal_uart *uart) { * @param level The UART transmit watermark level * @return 0 upon success */ -__inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, size_t level) { +__inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, + size_t level) { return uart->vtable->set_tx_watermark(uart, level); } @@ -197,7 +198,8 @@ __inline__ size_t metal_uart_get_transmit_watermark(struct metal_uart *uart) { * @param level The UART transmit watermark level * @return 0 upon success */ -__inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, size_t level) { +__inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, + size_t level) { return uart->vtable->set_rx_watermark(uart, level); } diff --git a/src/drivers/sifive_uart0.c b/src/drivers/sifive_uart0.c index 16ac1a44..90986f00 100644 --- a/src/drivers/sifive_uart0.c +++ b/src/drivers/sifive_uart0.c @@ -93,7 +93,7 @@ size_t __metal_driver_sifive_uart0_get_tx_watermark(struct metal_uart *uart) { int __metal_driver_sifive_uart0_set_rx_watermark(struct metal_uart *uart, size_t level) { long control_base = __metal_driver_sifive_uart0_control_base(uart); - + UART_REGW(METAL_SIFIVE_UART0_RXCTRL) |= UART_RXCNT(level); return 0; } @@ -227,9 +227,11 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = { __metal_driver_sifive_uart0_interrupt_controller, .uart.get_interrupt_id = __metal_driver_sifive_uart0_get_interrupt_id, .uart.tx_interrupt_enable = __metal_driver_sifive_uart0_tx_interrupt_enable, - .uart.tx_interrupt_disable = __metal_driver_sifive_uart0_tx_interrupt_disable, + .uart.tx_interrupt_disable = + __metal_driver_sifive_uart0_tx_interrupt_disable, .uart.rx_interrupt_enable = __metal_driver_sifive_uart0_rx_interrupt_enable, - .uart.rx_interrupt_disable = __metal_driver_sifive_uart0_rx_interrupt_disable, + .uart.rx_interrupt_disable = + __metal_driver_sifive_uart0_rx_interrupt_disable, .uart.set_tx_watermark = __metal_driver_sifive_uart0_set_tx_watermark, .uart.get_tx_watermark = __metal_driver_sifive_uart0_get_tx_watermark, .uart.set_rx_watermark = __metal_driver_sifive_uart0_set_rx_watermark, diff --git a/src/uart.c b/src/uart.c index 573b3c84..753e5b43 100644 --- a/src/uart.c +++ b/src/uart.c @@ -11,17 +11,25 @@ extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c); extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart); extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate); -extern __inline__ struct metal_interrupt* metal_uart_interrupt_controller( - struct metal_uart *uart); +extern __inline__ struct metal_interrupt * +metal_uart_interrupt_controller(struct metal_uart *uart); extern __inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart); -extern __inline__ int metal_uart_transmit_interrupt_enable(struct metal_uart *uart); -extern __inline__ int metal_uart_transmit_interrupt_disable(struct metal_uart *uart); -extern __inline__ int metal_uart_receive_interrupt_enable(struct metal_uart *uart); -extern __inline__ int metal_uart_receive_interrupt_disable(struct metal_uart *uart); -extern __inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, size_t level); -extern __inline__ size_t metal_uart_get_transmit_watermark(struct metal_uart *uart); -extern __inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, size_t level); -extern __inline__ size_t metal_uart_get_receive_watermark(struct metal_uart *uart); +extern __inline__ int +metal_uart_transmit_interrupt_enable(struct metal_uart *uart); +extern __inline__ int +metal_uart_transmit_interrupt_disable(struct metal_uart *uart); +extern __inline__ int +metal_uart_receive_interrupt_enable(struct metal_uart *uart); +extern __inline__ int +metal_uart_receive_interrupt_disable(struct metal_uart *uart); +extern __inline__ int metal_uart_set_transmit_watermark(struct metal_uart *uart, + size_t level); +extern __inline__ size_t +metal_uart_get_transmit_watermark(struct metal_uart *uart); +extern __inline__ int metal_uart_set_receive_watermark(struct metal_uart *uart, + size_t level); +extern __inline__ size_t +metal_uart_get_receive_watermark(struct metal_uart *uart); struct metal_uart *metal_uart_get_device(unsigned int device_num) { #if __METAL_DT_MAX_UARTS > 0