Skip to content

Commit

Permalink
Merge pull request #192 from sifive/esat-112
Browse files Browse the repository at this point in the history
Extend uart driver to support interrupt and watermark setting
  • Loading branch information
bsousi5 authored Oct 4, 2019
2 parents 4639e50 + 8231b99 commit b16dbc2
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 3 deletions.
3 changes: 2 additions & 1 deletion metal/drivers/sifive_clic0.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ __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];
Expand Down
84 changes: 84 additions & 0 deletions metal/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

/*!
Expand Down Expand Up @@ -128,4 +136,80 @@ __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
73 changes: 71 additions & 2 deletions src/drivers/sifive_uart0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand All @@ -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) {
Expand All @@ -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);

Expand Down Expand Up @@ -167,6 +226,16 @@ __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 */
Expand Down
19 changes: 19 additions & 0 deletions src/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +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__ 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);

struct metal_uart *metal_uart_get_device(unsigned int device_num) {
#if __METAL_DT_MAX_UARTS > 0
Expand Down

0 comments on commit b16dbc2

Please sign in to comment.