From eead95707586966c4a3c95325abead478dc4e4bf Mon Sep 17 00:00:00 2001 From: Michael Bishop Date: Sun, 11 Oct 2020 14:53:19 -0300 Subject: [PATCH] [dev][uart][pl011] Move to common driver merges the qemu and bcm28xx versions of the uart driver together fixed a bug that was present in the qemu version, that only reveals itself on real hw increase the fifo level interrupt to 7/8 to get more bytes/irq under high load fixes issue #272 --- dev/pl011/include/dev/pl011.h | 4 + dev/pl011/rules.mk | 7 + {platform/qemu-virt-arm => dev/pl011}/uart.c | 61 +++++---- platform/bcm28xx/include/platform/bcm28xx.h | 17 +++ platform/bcm28xx/platform.c | 12 +- platform/bcm28xx/rules.mk | 4 +- platform/bcm28xx/uart.c | 135 ------------------- platform/qemu-virt-arm/platform.c | 5 +- platform/qemu-virt-arm/rules.mk | 2 +- target/rpi2/include/target/debugconfig.h | 0 target/rpi3/include/target/debugconfig.h | 0 11 files changed, 74 insertions(+), 173 deletions(-) create mode 100644 dev/pl011/include/dev/pl011.h create mode 100644 dev/pl011/rules.mk rename {platform/qemu-virt-arm => dev/pl011}/uart.c (71%) delete mode 100644 platform/bcm28xx/uart.c create mode 100644 target/rpi2/include/target/debugconfig.h create mode 100644 target/rpi3/include/target/debugconfig.h diff --git a/dev/pl011/include/dev/pl011.h b/dev/pl011/include/dev/pl011.h new file mode 100644 index 000000000..99bb12914 --- /dev/null +++ b/dev/pl011/include/dev/pl011.h @@ -0,0 +1,4 @@ +#pragma once + +void pl011_uart_init(int irq, int nr, uintptr_t base); +void pl011_uart_init_early(int nr, uintptr_t base); diff --git a/dev/pl011/rules.mk b/dev/pl011/rules.mk new file mode 100644 index 000000000..f2be9d688 --- /dev/null +++ b/dev/pl011/rules.mk @@ -0,0 +1,7 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += $(LOCAL_DIR)/uart.c + +include make/module.mk diff --git a/platform/qemu-virt-arm/uart.c b/dev/pl011/uart.c similarity index 71% rename from platform/qemu-virt-arm/uart.c rename to dev/pl011/uart.c index 9dfb25a7e..a9849242a 100644 --- a/platform/qemu-virt-arm/uart.c +++ b/dev/pl011/uart.c @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include /* PL011 implementation */ #define UART_DR (0x00) @@ -37,24 +37,22 @@ #define NUM_UART 1 static cbuf_t uart_rx_buf[NUM_UART]; +static uintptr_t uart_base[NUM_UART]; static inline uintptr_t uart_to_ptr(unsigned int n) { - switch (n) { - default: - case 0: - return UART_BASE; - } + return uart_base[n]; } static enum handler_return uart_irq(void *arg) { bool resched = false; - uint port = (uintptr_t)arg; + uint port = (uint)arg; uintptr_t base = uart_to_ptr(port); /* read interrupt status and mask */ uint32_t isr = UARTREG(base, UART_TMIS); - if (isr & (1<<4)) { // rxmis + if (isr & ((1<<6) | (1<<4))) { // rtmis, rxmis + UARTREG(base, UART_ICR) = (1<<4); cbuf_t *rxbuf = &uart_rx_buf[port]; /* while fifo is not empty, read chars out of it */ @@ -83,37 +81,38 @@ 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_uart_init(int irq, int nr, uintptr_t base) { + assert(nr < NUM_UART); + uart_base[nr] = base; + // create circular buffer to hold received data + cbuf_initialize(&uart_rx_buf[nr], RXBUF_SIZE); - // create circular buffer to hold received data - cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE); + // assumes interrupts are contiguous + register_int_handler(irq, &uart_irq, (void *)nr); - // assumes interrupts are contiguous - register_int_handler(UART0_INT + i, &uart_irq, (void *)i); + // clear all irqs + UARTREG(base, UART_ICR) = 0x3ff; - // clear all irqs - UARTREG(base, UART_ICR) = 0x3ff; + UARTREG(base, UART_LCRH) = (3<<5) // 8bit mode + | (1<<4); // fifo enable - // set fifo trigger level - UARTREG(base, UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo + // set fifo trigger level + UARTREG(base, UART_IFLS) = 4 << 3; // 7/8 rxfifo, 1/8 txfifo - // enable rx interrupt - UARTREG(base, UART_IMSC) = (1<<4); // rxim + // enable rx interrupt + UARTREG(base, UART_IMSC) = (1<<6)|(1<<4); // rtim, rxim - // enable receive - UARTREG(base, UART_CR) |= (1<<9); // rxen + // enable receive + UARTREG(base, UART_CR) |= (1<<9)|(1<<8)|(1<<0); // rxen, tx_enable, uarten - // enable interrupt - unmask_interrupt(UART0_INT + i); - } + // enable interrupt + unmask_interrupt(irq); } -void uart_init_early(void) { - for (size_t i = 0; i < NUM_UART; i++) { - UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten - } +void pl011_uart_init_early(int nr, uintptr_t base) { + assert(nr < NUM_UART); + uart_base[nr] = base; + UARTREG(uart_to_ptr(nr), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten } int uart_putc(int port, char c) { @@ -132,7 +131,7 @@ int uart_getc(int port, bool wait) { char c; if (cbuf_read_char(rxbuf, &c, wait) == 1) { - UARTREG(uart_to_ptr(port), UART_IMSC) = (1<<4); // rxim + UARTREG(uart_to_ptr(port), UART_IMSC) |= (1<<4); // rxim return c; } diff --git a/platform/bcm28xx/include/platform/bcm28xx.h b/platform/bcm28xx/include/platform/bcm28xx.h index f4b06f06e..f9f79ac17 100644 --- a/platform/bcm28xx/include/platform/bcm28xx.h +++ b/platform/bcm28xx/include/platform/bcm28xx.h @@ -36,7 +36,15 @@ #define PCM_CLOCK_BASE (BCM_PERIPH_BASE_VIRT + 0x101098) #define RNG_BASE (BCM_PERIPH_BASE_VIRT + 0x104000) #define GPIO_BASE (BCM_PERIPH_BASE_VIRT + 0x200000) + +// all PL011 uarts, 2-5 only exist on BCM2828/pi4/VC6 +// all share the same INTERRUPT_VC_UART #define UART0_BASE (BCM_PERIPH_BASE_VIRT + 0x201000) +#define UART2_BASE (BCM_PERIPH_BASE_VIRT + 0x201400) +#define UART3_BASE (BCM_PERIPH_BASE_VIRT + 0x201600) +#define UART4_BASE (BCM_PERIPH_BASE_VIRT + 0x201800) +#define UART5_BASE (BCM_PERIPH_BASE_VIRT + 0x201a00) + #define MMCI0_BASE (BCM_PERIPH_BASE_VIRT + 0x202000) #define I2S_BASE (BCM_PERIPH_BASE_VIRT + 0x203000) #define SPI0_BASE (BCM_PERIPH_BASE_VIRT + 0x204000) @@ -175,6 +183,15 @@ /* GPIO */ +#define GPIO_IN 0 +#define GPIO_OUT 1 +#define GPIO_ALT5 2 +#define GPIO_ALT4 3 +#define GPIO_ALT0 4 +#define GPIO_ALT1 5 +#define GPIO_ALT2 6 +#define GPIO_ALT3 7 + #define GPIO_GPFSEL0 (GPIO_BASE + 0x00) #define GPIO_GPFSEL1 (GPIO_BASE + 0x04) #define GPIO_GPFSEL2 (GPIO_BASE + 0x08) diff --git a/platform/bcm28xx/platform.c b/platform/bcm28xx/platform.c index e2c62efb5..703a4cb18 100644 --- a/platform/bcm28xx/platform.c +++ b/platform/bcm28xx/platform.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -108,7 +109,7 @@ void platform_init_mmu_mappings(void) { } void platform_early_init(void) { - uart_init_early(); + pl011_uart_init_early(0, UART0_BASE); intc_init(); @@ -195,7 +196,14 @@ void platform_early_init(void) { } void platform_init(void) { - uart_init(); + pl011_uart_init(INTERRUPT_VC_UART, 0, UART0_BASE); +#if BCM2838 + pl011_uart_init(INTERRUPT_VC_UART, 2, UART2_BASE); + pl011_uart_init(INTERRUPT_VC_UART, 3, UART3_BASE); + pl011_uart_init(INTERRUPT_VC_UART, 4, UART4_BASE); + pl011_uart_init(INTERRUPT_VC_UART, 5, UART5_BASE); +#endif + #if BCM2837 init_framebuffer(); #endif diff --git a/platform/bcm28xx/rules.mk b/platform/bcm28xx/rules.mk index 8f2910360..6994066ba 100644 --- a/platform/bcm28xx/rules.mk +++ b/platform/bcm28xx/rules.mk @@ -42,8 +42,8 @@ SMP_CPU_ID_BITS := 8 GLOBAL_DEFINES += \ BCM2836=1 -MODULE_SRCS += \ - $(LOCAL_DIR)/uart.c +MODULES += \ + dev/pl011 else ifeq ($(TARGET),rpi3) ARCH := arm64 diff --git a/platform/bcm28xx/uart.c b/platform/bcm28xx/uart.c deleted file mode 100644 index 914a52977..000000000 --- a/platform/bcm28xx/uart.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2015 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 -#include -#include -#include -#include -#include -#include -#include - -/* TODO: extract this into a generic PL011 driver */ - -/* PL011 implementation */ -#define UART_DR (0x00) -#define UART_RSR (0x04) -#define UART_TFR (0x18) -#define UART_ILPR (0x20) -#define UART_IBRD (0x24) -#define UART_FBRD (0x28) -#define UART_LCRH (0x2c) -#define UART_CR (0x30) -#define UART_IFLS (0x34) -#define UART_IMSC (0x38) -#define UART_TRIS (0x3c) -#define UART_TMIS (0x40) -#define UART_ICR (0x44) -#define UART_DMACR (0x48) - -#define UARTREG(base, reg) (*REG32((base) + (reg))) - -#define RXBUF_SIZE 16 -#define NUM_UART 1 - -static cbuf_t uart_rx_buf[NUM_UART]; - -static inline uintptr_t uart_to_ptr(unsigned int n) { - switch (n) { - default: - case 0: - return UART0_BASE; - } -} - -static enum handler_return uart_irq(void *arg) { - bool resched = false; - uint port = (uint)arg; - uintptr_t base = uart_to_ptr(port); - - /* read interrupt status and mask */ - uint32_t isr = UARTREG(base, UART_TMIS); - - if (isr & ((1<<6) | (1<<4))) { // rtmis, rxmis - UARTREG(base, UART_ICR) = (1<<4); - cbuf_t *rxbuf = &uart_rx_buf[port]; - - /* while fifo is not empty, read chars out of it */ - while ((UARTREG(base, UART_TFR) & (1<<4)) == 0) { - char c = UARTREG(base, UART_DR); - cbuf_write_char(rxbuf, c, false); - - resched = true; - } - } - - return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; -} - -void uart_init(void) { - for (size_t i = 0; i < NUM_UART; i++) { - // create circular buffer to hold received data - cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE); - - // assumes interrupts are contiguous - register_int_handler(INTERRUPT_VC_UART + i, &uart_irq, (void *)i); - - // clear all irqs - UARTREG(uart_to_ptr(i), UART_ICR) = 0x3ff; - - // set fifo trigger level - UARTREG(uart_to_ptr(i), UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo - - // enable rx interrupt - UARTREG(uart_to_ptr(i), UART_IMSC) = (1<<6)|(1<<4); // rtim, rxim - - // enable receive - UARTREG(uart_to_ptr(i), UART_CR) |= (1<<9); // rxen - - // enable interrupt - unmask_interrupt(INTERRUPT_VC_UART + i); - } -} - -void uart_init_early(void) { - for (size_t i = 0; i < NUM_UART; i++) { - UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten - } -} - -int uart_putc(int port, char c) { - uintptr_t base = uart_to_ptr(port); - - /* spin while fifo is full */ - while (UARTREG(base, UART_TFR) & (1<<5)) - ; - UARTREG(base, UART_DR) = c; - - return 1; -} - -int uart_getc(int port, bool wait) { - cbuf_t *rxbuf = &uart_rx_buf[port]; - - char c; - if (cbuf_read_char(rxbuf, &c, wait) == 1) - return c; - - return -1; -} - -void uart_flush_tx(int port) { -} - -void uart_flush_rx(int port) { -} - -void uart_init_port(int port, uint baud) { -} - - diff --git a/platform/qemu-virt-arm/platform.c b/platform/qemu-virt-arm/platform.c index f9af72b03..4db586027 100644 --- a/platform/qemu-virt-arm/platform.c +++ b/platform/qemu-virt-arm/platform.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ void platform_early_init(void) { arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 0); - uart_init_early(); + pl011_uart_init_early(0, UART_BASE); int cpu_count = 0; bool found_mem = false; @@ -152,7 +153,7 @@ void platform_early_init(void) { } void platform_init(void) { - uart_init(); + pl011_uart_init(UART0_INT, 0, UART_BASE); /* detect any virtio devices */ uint virtio_irqs[NUM_VIRTIO_TRANSPORTS]; diff --git a/platform/qemu-virt-arm/rules.mk b/platform/qemu-virt-arm/rules.mk index ee130274e..23baa7840 100644 --- a/platform/qemu-virt-arm/rules.mk +++ b/platform/qemu-virt-arm/rules.mk @@ -19,7 +19,6 @@ MODULE_SRCS += \ $(LOCAL_DIR)/debug.c \ $(LOCAL_DIR)/platform.c \ $(LOCAL_DIR)/secondary_boot.S \ - $(LOCAL_DIR)/uart.c MEMBASE := 0x40000000 MEMSIZE ?= 0x08000000 # 512MB @@ -33,6 +32,7 @@ MODULE_DEPS += \ dev/virtio/block \ dev/virtio/gpu \ dev/virtio/net \ + dev/pl011 \ GLOBAL_DEFINES += \ MEMBASE=$(MEMBASE) \ diff --git a/target/rpi2/include/target/debugconfig.h b/target/rpi2/include/target/debugconfig.h new file mode 100644 index 000000000..e69de29bb diff --git a/target/rpi3/include/target/debugconfig.h b/target/rpi3/include/target/debugconfig.h new file mode 100644 index 000000000..e69de29bb