Files
lk/platform/qemu-virt-riscv/uart.c
Travis Geiselbrecht ae5200595c [platform][riscv-virt] added support for QEMU's riscv 'virt' machine
The virt machine is a generic target, much like the arm virt machine.
Intended to be simple to use and a good target to run large systems like
linux on. At the moment simply support booting and simple uart and timer
support.
2019-11-02 14:19:36 -07:00

82 lines
1.8 KiB
C

/*
* Copyright (c) 2018 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/reg.h>
#include <lk/trace.h>
#include <lib/cbuf.h>
#include <kernel/thread.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/debug.h>
#include <platform/virt.h>
#include <sys/types.h>
#include "platform_p.h"
// simple 16550 driver for the emulated serial port on qemu riscv virt machine
static volatile uint8_t *const uart_base = (uint8_t *)UART0_BASE;
#define RXBUF_SIZE 128
static char uart_rx_buf_data[RXBUF_SIZE];
static cbuf_t uart_rx_buf;
static inline uint8_t uart_read_8(size_t offset) {
return uart_base[offset];
}
static inline void uart_write_8(size_t offset, uint8_t val) {
uart_base[offset] = val;
}
static enum handler_return uart_irq_handler(void *arg) {
unsigned char c;
bool resched = false;
while (uart_read_8(5) & (1<<0)) {
c = uart_read_8(0);
cbuf_write_char(&uart_rx_buf, c, false);
resched = true;
}
return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
}
void uart_init(void) {
/* finish uart init to get rx going */
cbuf_initialize_etc(&uart_rx_buf, RXBUF_SIZE, uart_rx_buf_data);
register_int_handler(IRQ_UART0, uart_irq_handler, NULL);
uart_write_8(1, 0x1); // enable receive data available interrupt
unmask_interrupt(IRQ_UART0);
}
void uart_putc(char c) {
while ((uart_read_8(5) & (1<<6)) == 0)
;
uart_write_8(0, c);
}
int uart_getc(char *c, bool wait) {
return cbuf_read_char(&uart_rx_buf, c, wait);
}
void platform_dputc(char c) {
if (c == '\n')
platform_dputc('\r');
uart_putc(c);
}
int platform_dgetc(char *c, bool wait) {
int ret = uart_getc(c, wait);
return ret;
}