[dev][uart][pl011] have the uart be data driven
Initialize the uart by passing in the base and irq, as well as a flag specifying if it's the debug uart and should directly put data into the console buffer (if present).
This commit is contained in:
@@ -4,4 +4,6 @@ MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/uart.c
|
||||
|
||||
MODULE_OPTIONS := extra_warnings
|
||||
|
||||
include make/module.mk
|
||||
|
||||
@@ -5,16 +5,14 @@
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <lk/reg.h>
|
||||
#include "include/dev/uart/pl011.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <dev/uart.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/debug.h>
|
||||
#include <platform/qemu-virt.h>
|
||||
#include <target/debugconfig.h>
|
||||
|
||||
/* PL011 implementation */
|
||||
#define UART_DR (0x00)
|
||||
@@ -35,7 +33,16 @@
|
||||
#define RXBUF_SIZE 16
|
||||
#define NUM_UART 1
|
||||
|
||||
static cbuf_t uart_rx_buf[NUM_UART];
|
||||
struct pl011_struct {
|
||||
uintptr_t base_virt;
|
||||
uint32_t irq;
|
||||
|
||||
uint32_t flag;
|
||||
|
||||
cbuf_t uart_rx_buf;
|
||||
};
|
||||
|
||||
static struct pl011_struct uart[NUM_UART];
|
||||
|
||||
static inline void write_uart_reg(uintptr_t base, size_t offset, uint32_t val) {
|
||||
mmio_write32((uint32_t *)(base + offset), val);
|
||||
@@ -54,40 +61,36 @@ static inline void clear_uart_reg_bits(uintptr_t base, size_t offset, uint32_t b
|
||||
}
|
||||
|
||||
static inline uintptr_t uart_to_ptr(unsigned int n) {
|
||||
switch (n) {
|
||||
default:
|
||||
case 0:
|
||||
return UART_BASE;
|
||||
}
|
||||
DEBUG_ASSERT(n < NUM_UART);
|
||||
return uart[n].base_virt;
|
||||
}
|
||||
|
||||
static enum handler_return uart_irq(void *arg) {
|
||||
bool resched = false;
|
||||
uint port = (uintptr_t)arg;
|
||||
uintptr_t base = uart_to_ptr(port);
|
||||
struct pl011_struct *u = (struct pl011_struct *)arg;
|
||||
|
||||
/* read interrupt status and mask */
|
||||
uint32_t isr = read_uart_reg(base, UART_TMIS);
|
||||
uint32_t isr = read_uart_reg(u->base_virt, UART_TMIS);
|
||||
|
||||
if (isr & (1<<4)) { // rxmis
|
||||
cbuf_t *rxbuf = &uart_rx_buf[port];
|
||||
cbuf_t *rxbuf = &uart->uart_rx_buf;
|
||||
|
||||
/* while fifo is not empty, read chars out of it */
|
||||
while ((read_uart_reg(base, UART_TFR) & (1<<4)) == 0) {
|
||||
while ((read_uart_reg(u->base_virt, UART_TFR) & (1<<4)) == 0) {
|
||||
#if CONSOLE_HAS_INPUT_BUFFER
|
||||
if (port == DEBUG_UART) {
|
||||
char c = read_uart_reg(base, UART_DR);
|
||||
if (u->flag & PL011_FLAG_DEBUG_UART) {
|
||||
char c = read_uart_reg(u->base_virt, UART_DR);
|
||||
cbuf_write_char(&console_input_cbuf, c, false);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* if we're out of rx buffer, mask the irq instead of handling it */
|
||||
if (cbuf_space_avail(rxbuf) == 0) {
|
||||
clear_uart_reg_bits(base, UART_IMSC, (1<<4)); // !rxim
|
||||
clear_uart_reg_bits(u->base_virt, UART_IMSC, (1<<4)); // !rxim
|
||||
break;
|
||||
}
|
||||
|
||||
char c = read_uart_reg(base, UART_DR);
|
||||
char c = read_uart_reg(u->base_virt, UART_DR);
|
||||
cbuf_write_char(rxbuf, c, false);
|
||||
}
|
||||
|
||||
@@ -98,37 +101,41 @@ static enum handler_return uart_irq(void *arg) {
|
||||
return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
|
||||
}
|
||||
|
||||
void uart_init(void) {
|
||||
for (size_t i = 0; i < NUM_UART; i++) {
|
||||
uintptr_t base = uart_to_ptr(i);
|
||||
void pl011_init(int port) {
|
||||
uintptr_t base = uart_to_ptr(port);
|
||||
|
||||
// create circular buffer to hold received data
|
||||
cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE);
|
||||
// create circular buffer to hold received data
|
||||
cbuf_initialize(&uart[port].uart_rx_buf, RXBUF_SIZE);
|
||||
|
||||
// assumes interrupts are contiguous
|
||||
register_int_handler(UART0_INT + i, &uart_irq, (void *)i);
|
||||
// assumes interrupts are contiguous
|
||||
register_int_handler(uart[port].irq, &uart_irq, (void *)&uart[port]);
|
||||
|
||||
// clear all irqs
|
||||
write_uart_reg(base, UART_ICR, 0x3ff);
|
||||
// clear all irqs
|
||||
write_uart_reg(base, UART_ICR, 0x3ff);
|
||||
|
||||
// set fifo trigger level
|
||||
write_uart_reg(base, UART_IFLS, 0); // 1/8 rxfifo, 1/8 txfifo
|
||||
// set fifo trigger level
|
||||
write_uart_reg(base, UART_IFLS, 0); // 1/8 rxfifo, 1/8 txfifo
|
||||
|
||||
// enable rx interrupt
|
||||
write_uart_reg(base, UART_IMSC, 1<<4); // rxim
|
||||
// enable rx interrupt
|
||||
write_uart_reg(base, UART_IMSC, 1<<4); // rxim
|
||||
|
||||
// enable receive
|
||||
set_uart_reg_bits(base, UART_CR, (1<<9)); // rxen
|
||||
// enable receive
|
||||
set_uart_reg_bits(base, UART_CR, (1<<9)); // rxen
|
||||
|
||||
// enable interrupt
|
||||
unmask_interrupt(UART0_INT + i);
|
||||
}
|
||||
// enable interrupt
|
||||
unmask_interrupt(uart[port].irq);
|
||||
}
|
||||
|
||||
void uart_init_early(void) {
|
||||
for (size_t i = 0; i < NUM_UART; i++) {
|
||||
write_uart_reg(uart_to_ptr(i), UART_CR, (1<<8)|(1<<0)); // tx_enable, uarten
|
||||
void pl011_init_early(int port, uintptr_t base, uint32_t irq, uint32_t flag) {
|
||||
if (port >= NUM_UART) {
|
||||
return;
|
||||
}
|
||||
|
||||
uart[port].base_virt = base;
|
||||
uart[port].irq = irq;
|
||||
uart[port].flag = flag;
|
||||
|
||||
write_uart_reg(uart[port].base_virt, UART_CR, (1<<8)|(1<<0)); // tx_enable, uarten
|
||||
}
|
||||
|
||||
int uart_putc(int port, char c) {
|
||||
@@ -143,7 +150,7 @@ int uart_putc(int port, char c) {
|
||||
}
|
||||
|
||||
int uart_getc(int port, bool wait) {
|
||||
cbuf_t *rxbuf = &uart_rx_buf[port];
|
||||
cbuf_t *rxbuf = &uart[port].uart_rx_buf;
|
||||
|
||||
char c;
|
||||
if (cbuf_read_char(rxbuf, &c, wait) == 1) {
|
||||
@@ -176,13 +183,13 @@ int uart_pgetc(int port) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uart_flush_tx(int port) {
|
||||
}
|
||||
|
||||
void uart_flush_rx(int port) {
|
||||
}
|
||||
|
||||
// TODO collapse this into the early/regular init routines
|
||||
void uart_init_port(int port, uint baud) {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user