From c76127fadeb72c8e8791a3e0c5c9486270d53504 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Sun, 6 May 2012 19:30:03 -0500 Subject: [PATCH] arm uart: First work towards Amba serial driver * Move Raspberry Pi board over to Amba driver * Add initial set of registers and values * Few small style cleanups --- .../arm/board/raspberry_pi/board_config.h | 4 +- headers/private/kernel/arch/arm/uart.h | 1 + headers/private/kernel/arch/arm/uart_pl011.h | 95 ++++++++++++++++ src/system/boot/arch/arm/Jamfile | 8 +- .../boot/platform/raspberrypi_arm/serial.cpp | 3 +- src/system/kernel/arch/arm/Jamfile | 1 + src/system/kernel/arch/arm/uart.cpp | 17 ++- src/system/kernel/arch/arm/uart_8250.cpp | 6 +- src/system/kernel/arch/arm/uart_pl011.cpp | 105 ++++++++++++++++++ 9 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 headers/private/kernel/arch/arm/uart_pl011.h create mode 100644 src/system/kernel/arch/arm/uart_pl011.cpp diff --git a/headers/private/kernel/arch/arm/board/raspberry_pi/board_config.h b/headers/private/kernel/arch/arm/board/raspberry_pi/board_config.h index e1d11a5ebc..626dadf3e8 100644 --- a/headers/private/kernel/arch/arm/board/raspberry_pi/board_config.h +++ b/headers/private/kernel/arch/arm/board/raspberry_pi/board_config.h @@ -16,10 +16,10 @@ #include // UART Settings -#define BOARD_UART_8250 1 +#define BOARD_UART_AMBA_PL011 1 #define BOARD_UART1_BASE UART0_BASE -#define BOARD_UART2_BASE UART1_BASE +#define BOARD_UART2_BASE UART1_BASE + 0x40 #define BOARD_UART3_BASE 0 #define BOARD_UART_DEBUG BOARD_UART2_BASE diff --git a/headers/private/kernel/arch/arm/uart.h b/headers/private/kernel/arch/arm/uart.h index 48004e45f5..4a4691b951 100644 --- a/headers/private/kernel/arch/arm/uart.h +++ b/headers/private/kernel/arch/arm/uart.h @@ -12,6 +12,7 @@ #include #include "uart_8250.h" +#include "uart_pl011.h" #ifdef __cplusplus diff --git a/headers/private/kernel/arch/arm/uart_pl011.h b/headers/private/kernel/arch/arm/uart_pl011.h new file mode 100644 index 0000000000..b09b373b1f --- /dev/null +++ b/headers/private/kernel/arch/arm/uart_pl011.h @@ -0,0 +1,95 @@ +/* + * Copyright 2011-2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck, kallisti5@unixzen.com + */ +#ifndef __DEV_UART_PL011_H +#define __DEV_UART_PL011_H + + +#include + + +#define PL01x_DR 0x00 // Data read or written +#define PL01x_RSR 0x04 // Receive status, read +#define PL01x_ECR 0x04 // Error clear, write +#define PL010_LCRH 0x08 // Line control, high +#define PL010_LCRM 0x0C // Line control, middle +#define PL010_LCRL 0x10 // Line control, low +#define PL010_CR 0x14 // Control +#define PL01x_FR 0x18 // Flag (r/o) +#define PL010_IIR 0x1C // Interrupt ID (r) +#define PL010_ICR 0x1C // Interrupt clear (w) +#define PL01x_ILPR 0x20 // IrDA low power +#define PL011_IBRD 0x24 // Interrupt baud rate divisor +#define PL011_FBRD 0x28 // Fractional baud rate divisor +#define PL011_LCRH 0x2C // Line control +#define PL011_CR 0x30 // Control +#define PL011_IFLS 0x34 // Interrupt fifo level +#define PL011_IMSC 0x38 // Interrupt mask +#define PL011_RIS 0x3C // Raw interrupt +#define PL011_MIS 0x40 // Masked interrupt +#define PL011_ICR 0x44 // Interrupt clear +#define PL011_DMACR 0x48 // DMA control register + +#define PL011_DR_OE (1 << 11) +#define PL011_DR_BE (1 << 10) +#define PL011_DR_PE (1 << 9) +#define PL011_DR_FE (1 << 8) + +#define PL01x_RSR_OE 0x08 +#define PL01x_RSR_BE 0x04 +#define PL01x_RSR_PE 0x02 +#define PL01x_RSR_FE 0x01 + +#define PL011_FR_RI 0x100 +#define PL011_FR_TXFE 0x080 +#define PL011_FR_RXFF 0x040 +#define PL01x_FR_TXFF 0x020 +#define PL01x_FR_RXFE 0x010 +#define PL01x_FR_BUSY 0x008 +#define PL01x_FR_DCD 0x004 +#define PL01x_FR_DSR 0x002 +#define PL01x_FR_CTS 0x001 +#define PL01x_FR_TMSK (PL01x_FR_TXFF | PL01x_FR_BUSY) + +#define PL011_CR_CTSEN 0x8000 // CTS flow control +#define PL011_CR_RTSEN 0x4000 // RTS flow control +#define PL011_CR_OUT2 0x2000 // OUT2 +#define PL011_CR_OUT1 0x1000 // OUT1 +#define PL011_CR_RTS 0x0800 // RTS +#define PL011_CR_DTR 0x0400 // DTR +#define PL011_CR_RXE 0x0200 // Receive enable +#define PL011_CR_TXE 0x0100 // Transmit enable +#define PL011_CR_LBR 0x0080 // Loopback enable +#define PL011_CR_RTIE 0x0040 +#define PL011_CR_TIE 0x0020 +#define PL011_CR_RIE 0x0010 +#define PL011_CR_MSIE 0x0008 +#define PL011_CR_IIRLP 0x0004 // SIR low power mode +#define PL011_CR_SIREN 0x0002 // SIR enable +#define PL011_CR_UARTEN 0x0001 // UART enable + +// TODO: Other PL01x registers + values? + + +#ifdef __cplusplus +extern "C" { +#endif + + +void uart_pl011_init_port(addr_t base, uint baud); +void uart_pl011_init_early(void); +void uart_pl011_init(addr_t base); +int uart_pl011_putchar(addr_t base, char c); +int uart_pl011_getchar(addr_t base, bool wait); +void uart_pl011_flush_tx(addr_t base); +void uart_pl011_flush_rx(addr_t base); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/system/boot/arch/arm/Jamfile b/src/system/boot/arch/arm/Jamfile index dc172cb19e..9f66dce061 100644 --- a/src/system/boot/arch/arm/Jamfile +++ b/src/system/boot/arch/arm/Jamfile @@ -18,7 +18,7 @@ local kernelLibArchObjects = KernelMergeObject boot_arch_$(TARGET_ARCH).o : uart.cpp uart_8250.cpp -# uart_amba101.cpp + uart_pl011.cpp arch_elf.cpp arch_video.cpp arch_video_920.cpp @@ -30,8 +30,8 @@ KernelMergeObject boot_arch_$(TARGET_ARCH).o : $(kernelLibArchObjects) ; -SEARCH on [ FGristFiles arch_elf.cpp uart.cpp uart_8250.cpp ] - = [ FDirName $(HAIKU_TOP) src system kernel arch $(TARGET_ARCH) ] ; +SEARCH on [ FGristFiles arch_elf.cpp uart.cpp uart_8250.cpp uart_pl011.cpp ] + = [ FDirName $(HAIKU_TOP) src system kernel arch $(TARGET_ARCH) ] ; SEARCH on [ FGristFiles $(librootArchObjects) ] - = [ FDirName $(HAIKU_TOP) src system libroot posix string arch $(TARGET_ARCH) ] ; + = [ FDirName $(HAIKU_TOP) src system libroot posix string arch $(TARGET_ARCH) ] ; diff --git a/src/system/boot/platform/raspberrypi_arm/serial.cpp b/src/system/boot/platform/raspberrypi_arm/serial.cpp index 797d06395c..243dc64958 100644 --- a/src/system/boot/platform/raspberrypi_arm/serial.cpp +++ b/src/system/boot/platform/raspberrypi_arm/serial.cpp @@ -93,6 +93,7 @@ serial_init(void) serial_enable(); - serial_putc('S'); + serial_putc('!'); + serial_puts("SER INIT", 8); } diff --git a/src/system/kernel/arch/arm/Jamfile b/src/system/kernel/arch/arm/Jamfile index af0832f0bb..2a10ddd8b8 100644 --- a/src/system/kernel/arch/arm/Jamfile +++ b/src/system/kernel/arch/arm/Jamfile @@ -30,6 +30,7 @@ KernelMergeObject kernel_arch_arm.o : arch_asm.S uart.cpp uart_8250.cpp + uart_pl011.cpp # paging arm_physical_page_mapper.cpp diff --git a/src/system/kernel/arch/arm/uart.cpp b/src/system/kernel/arch/arm/uart.cpp index 7f4cc4a6f9..5269a979b0 100644 --- a/src/system/kernel/arch/arm/uart.cpp +++ b/src/system/kernel/arch/arm/uart.cpp @@ -58,15 +58,14 @@ uart_create(void) uart->getchar = uart_8250_getchar; uart->flush_tx = uart_8250_flush_tx; uart->flush_rx = uart_8250_flush_rx; - #elif defined(BOARD_UART_AMBA) - #error BOARD_UART_AMBA is Incomplete! - uart->init = uart_amba_init; - uart->init_early = uart_amba_init_early; - uart->init_port = uart_amba_init_port; - uart->putchar = uart_amba_putchar; - uart->getchar = uart_amba_getchar; - uart->flush_tx = uart_amba_flush_tx; - uart->flush_rx = uart_amba_flush_rx; + #elif defined(BOARD_UART_AMBA_PL011) + uart->init = uart_pl011_init; + uart->init_early = uart_pl011_init_early; + uart->init_port = uart_pl011_init_port; + uart->putchar = uart_pl011_putchar; + uart->getchar = uart_pl011_getchar; + uart->flush_tx = uart_pl011_flush_tx; + uart->flush_rx = uart_pl011_flush_rx; #else #error Unknown UART Type (or no UART provided) #endif diff --git a/src/system/kernel/arch/arm/uart_8250.cpp b/src/system/kernel/arch/arm/uart_8250.cpp index ea12b5d5c2..f17c02095c 100644 --- a/src/system/kernel/arch/arm/uart_8250.cpp +++ b/src/system/kernel/arch/arm/uart_8250.cpp @@ -32,14 +32,16 @@ #define UART_SHIFT 2 -static inline void write_8250(addr_t base, uint reg, unsigned char data) +static inline void +write_8250(addr_t base, uint reg, unsigned char data) { *(volatile unsigned char *)(base + (reg << UART_SHIFT)) = data; } -static inline unsigned char read_8250(addr_t base, uint reg) +static inline unsigned char +read_8250(addr_t base, uint reg) { return *(volatile unsigned char *)(base + (reg << UART_SHIFT)); } diff --git a/src/system/kernel/arch/arm/uart_pl011.cpp b/src/system/kernel/arch/arm/uart_pl011.cpp new file mode 100644 index 0000000000..52b2af1906 --- /dev/null +++ b/src/system/kernel/arch/arm/uart_pl011.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2011-2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck, kallisti5@unixzen.com + */ + + +#include +#include +#include +#include +//#include + + +static inline void +write_pl011(addr_t base, uint reg, unsigned char data) +{ + *(volatile unsigned char *)(base + reg) = data; +} + + +static inline unsigned char +read_pl011(addr_t base, uint reg) +{ + return *(volatile unsigned char *)(base + reg); +} + + +void +uart_pl011_init_port(addr_t base, uint baud) +{ +} + + +void +uart_pl011_init_early(void) +{ + // Perform special hardware UART configuration +} + + +void +uart_pl011_init(addr_t base) +{ + // TODO: Enable clock producer? + // TODO: Clear pending error and receive interrupts + + // Provoke TX FIFO into asserting + unsigned char cr = PL011_CR_UARTEN | PL011_CR_TXE | PL011_IFLS; + write_pl011(base, PL011_CR, cr); + write_pl011(base, PL011_FBRD, 0); + write_pl011(base, PL011_IBRD, 1); + + // TODO: For arm vendor, st different rx vs tx + write_pl011(base, PL011_LCRH, 0); + + write_pl011(base, PL01x_DR, 0); + + while (read_pl011(base, PL01x_FR) & PL01x_FR_BUSY); + // Wait for xmit + + // Write baud divider + #if 0 + write_pl011(base, PL011_FBRD, div & 0x3F); + write_pl011(base, PL011_IBRD, div >> 6); + #endif +} + + +int +uart_pl011_putchar(addr_t base, char c) +{ + write_pl011(base, PL01x_DR, (unsigned int)c); + + while (read_pl011(base, PL01x_FR) & PL01x_FR_TXFF); + // wait for the last char to get out + + return 0; +} + + +/* returns -1 if no data available */ +int +uart_pl011_getchar(addr_t base, bool wait) +{ + #warning ARM Amba PL011 UART incomplete + return -1; +} + + +void +uart_pl011_flush_tx(addr_t base) +{ + while (read_pl011(base, PL01x_FR) & PL01x_FR_TXFF); + // wait for the last char to get out +} + + +void +uart_pl011_flush_rx(addr_t base) +{ + #warning ARM Amba PL011 UART incomplete +}