arm uart: Convert new uart code to classes

* This makes things a little more flexible and
  the interface to use the uarts cleaner.
* May want to make a generic Uart wrapper
  class in uart.h / uart.cpp and call drivers
  as needed from there.
This commit is contained in:
Alexander von Gluck IV
2012-05-08 22:17:03 -05:00
parent 58f3387d56
commit 78004f1677
9 changed files with 163 additions and 199 deletions
+1 -25
View File
@@ -15,32 +15,8 @@
#include "uart_pl011.h" #include "uart_pl011.h"
#ifdef __cplusplus
extern "C" {
#endif
struct uart_info {
addr_t base;
// Pointers to functions based on port type
void (*init)(addr_t base);
void (*init_early)(void);
void (*init_port)(addr_t base, uint baud);
int (*putchar)(addr_t base, char c);
int (*getchar)(addr_t base, bool wait);
void (*flush_tx)(addr_t base);
void (*flush_rx)(addr_t base);
};
uart_info* uart_create(void);
void uart_destroy();
addr_t uart_base_port(int port); addr_t uart_base_port(int port);
addr_t uart_debug_port(void); addr_t uart_base_debug();
#ifdef __cplusplus
}
#endif
#endif #endif
+24 -17
View File
@@ -24,24 +24,31 @@
#define __DEV_UART_8250_H #define __DEV_UART_8250_H
#include <SupportDefs.h>
#include <sys/types.h> #include <sys/types.h>
#ifdef __cplusplus class Uart8250 {
extern "C" { public:
#endif Uart8250(addr_t base);
~Uart8250();
void uart_8250_init_port(addr_t base, uint baud); void InitEarly();
void uart_8250_init_early(void); void Init();
void uart_8250_init(addr_t base); void InitPort(uint32 baud);
int uart_8250_putchar(addr_t base, char c);
int uart_8250_getchar(addr_t base, bool wait); int PutChar(char c);
void uart_8250_flush_tx(addr_t base); int GetChar(bool wait);
void uart_8250_flush_rx(addr_t base);
void FlushTx();
void FlushRx();
#ifdef __cplusplus
} private:
#endif void WriteUart(uint32 reg, unsigned char data);
unsigned char ReadUart(uint32 reg);
addr_t fUARTBase;
};
#endif #endif
+24 -17
View File
@@ -10,6 +10,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <SupportDefs.h>
#define PL01x_DR 0x00 // Data read or written #define PL01x_DR 0x00 // Data read or written
@@ -86,21 +87,27 @@
// TODO: Other PL01x registers + values? // TODO: Other PL01x registers + values?
#ifdef __cplusplus class UartPL011 {
extern "C" { public:
#endif UartPL011(addr_t base);
~UartPL011();
void uart_pl011_init_port(addr_t base, uint baud); void InitEarly();
void uart_pl011_init_early(void); void Init();
void uart_pl011_init(addr_t base); void InitPort(uint32 baud);
int uart_pl011_putchar(addr_t base, char c);
int uart_pl011_getchar(addr_t base, bool wait); int PutChar(char c);
void uart_pl011_flush_tx(addr_t base); int GetChar(bool wait);
void uart_pl011_flush_rx(addr_t base);
void FlushTx();
void FlushRx();
#ifdef __cplusplus
} private:
#endif void WriteUart(uint32 reg, unsigned char data);
unsigned char ReadUart(uint32 reg);
addr_t fUARTBase;
};
#endif #endif
@@ -17,7 +17,7 @@
#include <string.h> #include <string.h>
struct uart_info* gUARTInfo; UartPL011* gUART;
static int32 sSerialEnabled = 0; static int32 sSerialEnabled = 0;
static char sBuffer[16384]; static char sBuffer[16384];
@@ -27,8 +27,7 @@ static uint32 sBufferPosition;
static void static void
serial_putc(char c) serial_putc(char c)
{ {
if (gUARTInfo != NULL) gUART->PutChar(c);
gUARTInfo->putchar(gUARTInfo->base, c);
} }
@@ -81,16 +80,11 @@ serial_cleanup(void)
extern "C" void extern "C" void
serial_init(void) serial_init(void)
{ {
gUARTInfo = uart_create(); gUART = new UartPL011(uart_base_debug());
if (gUARTInfo == NULL) { gUART->InitEarly();
// TODO: Notify user somehow. gUART->Init();
return; gUART->InitPort(9600);
}
gUARTInfo->init_early();
gUARTInfo->init_port(gUARTInfo->base, 9600);
//gUARTInfo->init(gUARTInfo->base);
serial_enable(); serial_enable();
+6 -11
View File
@@ -16,7 +16,7 @@
#include <string.h> #include <string.h>
struct uart_info* gUARTInfo; gUart8250* gUART;
static int32 sSerialEnabled = 0; static int32 sSerialEnabled = 0;
static char sBuffer[16384]; static char sBuffer[16384];
@@ -26,7 +26,7 @@ static uint32 sBufferPosition;
static void static void
serial_putc(char c) serial_putc(char c)
{ {
gUARTInfo->putchar(gUARTInfo->base, c); gUART->PutChar(c);
} }
@@ -67,9 +67,9 @@ serial_enable(void)
{ {
/* should already be initialized by U-Boot */ /* should already be initialized by U-Boot */
/* /*
gUARTInfo->init_early(); gUART->InitEarly();
gUARTInfo->init(gUARTInfo->base); gUART->Init();
gUARTInfo->init_port(gUARTInfo->base, 9600); gUART->InitPort(9600);
*/ */
sSerialEnabled++; sSerialEnabled++;
} }
@@ -93,12 +93,7 @@ extern "C" void
serial_init(void) serial_init(void)
{ {
// Setup information on uart // Setup information on uart
gUARTInfo = uart_create(); gUART = new Uart8250(uart_base_debug());
if (gUARTInfo == NULL) {
// TODO: Notify user somehow.
return;
}
serial_enable(); serial_enable();
} }
@@ -19,7 +19,11 @@
#include <string.h> #include <string.h>
struct uart_info* gUART; #if defined(BOARD_UART_AMBA_PL011)
UartPL011* gArchDebugUART;
#else
Uart8250* gArchDebugUART;
#endif
void void
@@ -60,18 +64,14 @@ arch_debug_serial_try_getchar(void)
char char
arch_debug_serial_getchar(void) arch_debug_serial_getchar(void)
{ {
if (gUART->getchar != NULL) return gArchDebugUART->GetChar(false);
return gUART->getchar(gUART->base, false);
return 0;
} }
void void
arch_debug_serial_putchar(const char c) arch_debug_serial_putchar(const char c)
{ {
if (gUART->putchar != NULL) gArchDebugUART->PutChar(c);
gUART->putchar(gUART->base, c);
} }
@@ -96,12 +96,13 @@ arch_debug_serial_early_boot_message(const char *string)
status_t status_t
arch_debug_console_init(kernel_args *args) arch_debug_console_init(kernel_args *args)
{ {
gUART = uart_create(); #if defined(BOARD_UART_AMBA_PL011)
gArchDebugUART = new UartPL011(uart_base_debug());
#else
gArchDebugUART = new Uart8250(uart_base_debug());
#endif
if (gUART == NULL) gArchDebugUART->InitEarly();
return B_ERROR;
gUART->init_early();
return B_OK; return B_OK;
} }
+1 -41
View File
@@ -12,7 +12,6 @@
#include <board_config.h> #include <board_config.h>
#include <debug.h> #include <debug.h>
#include <stdlib.h> #include <stdlib.h>
//#include <target/debugconfig.h> //#include <target/debugconfig.h>
@@ -20,7 +19,7 @@
addr_t addr_t
uart_base_debug(void) uart_base_debug()
{ {
return DEBUG_UART; return DEBUG_UART;
} }
@@ -40,42 +39,3 @@ uart_base_port(int port)
return uart_base_debug(); return uart_base_debug();
} }
uart_info*
uart_create(void)
{
struct uart_info* uart;
uart = (uart_info*)malloc(sizeof(uart_info));
uart->base = uart_base_debug();
#if defined(BOARD_UART_8250)
uart->init = uart_8250_init;
uart->init_early = uart_8250_init_early;
uart->init_port = uart_8250_init_port;
uart->putchar = uart_8250_putchar;
uart->getchar = uart_8250_getchar;
uart->flush_tx = uart_8250_flush_tx;
uart->flush_rx = uart_8250_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
return uart;
}
void
uart_destroy(uart_info* uart)
{
free(uart);
}
+47 -35
View File
@@ -32,18 +32,30 @@
#define UART_SHIFT 2 #define UART_SHIFT 2
static inline void Uart8250::Uart8250(addr_t base)
write_8250(addr_t base, uint reg, unsigned char data) :
fUARTBase(base)
{ {
*(volatile unsigned char *)(base + (reg << UART_SHIFT)) }
Uart8250::~Uart8250()
{
}
void
Uart8250::WriteUart(uint32 reg, unsigned char data)
{
*(volatile unsigned char *)(fUARTBase + (reg << UART_SHIFT))
= data; = data;
} }
static inline unsigned char unsigned char
read_8250(addr_t base, uint reg) Uart8250::ReadUart(uint32 reg)
{ {
return *(volatile unsigned char *)(base + (reg << UART_SHIFT)); return *(volatile unsigned char *)(fUARTBase + (reg << UART_SHIFT));
} }
@@ -81,36 +93,36 @@ read_8250(addr_t base, uint reg)
void void
uart_8250_init_port(addr_t base, uint baud) Uart8250::InitPort(uint32 baud)
{ {
uint16 baudDivisor = BOARD_UART_CLOCK / (16 * baud); uint16 baudDivisor = BOARD_UART_CLOCK / (16 * baud);
// Write standard uart settings // Write standard uart settings
write_8250(base, UART_LCR, LCR_8N1); WriteUart(UART_LCR, LCR_8N1);
// 8N1 // 8N1
write_8250(base, UART_IER, 0); WriteUart(UART_IER, 0);
// Disable interrupt // Disable interrupt
write_8250(base, UART_FCR, 0); WriteUart(UART_FCR, 0);
// Disable FIFO // Disable FIFO
write_8250(base, UART_MCR, MCR_DTR | MCR_RTS); WriteUart(UART_MCR, MCR_DTR | MCR_RTS);
// DTR / RTS // DTR / RTS
// Gain access to, and program baud divisor // Gain access to, and program baud divisor
unsigned char buffer = read_8250(base, UART_LCR); unsigned char buffer = ReadUart(UART_LCR);
write_8250(base, UART_LCR, buffer | LCR_BKSE); WriteUart(UART_LCR, buffer | LCR_BKSE);
write_8250(base, UART_DLL, baudDivisor & 0xff); WriteUart(UART_DLL, baudDivisor & 0xff);
write_8250(base, UART_DLH, (baudDivisor >> 8) & 0xff); WriteUart(UART_DLH, (baudDivisor >> 8) & 0xff);
write_8250(base, UART_LCR, buffer & ~LCR_BKSE); WriteUart(UART_LCR, buffer & ~LCR_BKSE);
// write_8250(base, UART_MDR1, 0); // UART 16x mode // WriteUart(UART_MDR1, 0); // UART 16x mode
// write_8250(base, UART_LCR, 0xBF); // config mode B // WriteUart(UART_LCR, 0xBF); // config mode B
// write_8250(base, UART_EFR, (1<<7)|(1<<6)); // hw flow control // WriteUart(UART_EFR, (1<<7)|(1<<6)); // hw flow control
// write_8250(base, UART_LCR, LCR_8N1); // operational mode // WriteUart(UART_LCR, LCR_8N1); // operational mode
} }
void void
uart_8250_init_early(void) Uart8250::InitEarly()
{ {
// Perform special hardware UART configuration // Perform special hardware UART configuration
@@ -133,51 +145,51 @@ uart_8250_init_early(void)
void void
uart_8250_init(addr_t base) Uart8250::Init()
{ {
uart_8250_init_port(base, 115200); InitPort(115200);
} }
int int
uart_8250_putchar(addr_t base, char c) Uart8250::PutChar(char c)
{ {
while (!(read_8250(base, UART_LSR) & (1<<6))); while (!(ReadUart(UART_LSR) & (1<<6)));
// wait for the last char to get out // wait for the last char to get out
write_8250(base, UART_THR, c); WriteUart(UART_THR, c);
return 0; return 0;
} }
/* returns -1 if no data available */ /* returns -1 if no data available */
int int
uart_8250_getchar(addr_t base, bool wait) Uart8250::GetChar(bool wait)
{ {
if (wait) { if (wait) {
while (!(read_8250(base, UART_LSR) & (1<<0))); while (!(ReadUart(UART_LSR) & (1<<0)));
// wait for data to show up in the rx fifo // wait for data to show up in the rx fifo
} else { } else {
if (!(read_8250(base, UART_LSR) & (1<<0))) if (!(ReadUart(UART_LSR) & (1<<0)))
return -1; return -1;
} }
return read_8250(base, UART_RHR); return ReadUart(UART_RHR);
} }
void void
uart_8250_flush_tx(addr_t base) Uart8250::FlushTx()
{ {
while (!(read_8250(base, UART_LSR) & (1<<6))); while (!(ReadUart(UART_LSR) & (1<<6)));
// wait for the last char to get out // wait for the last char to get out
} }
void void
uart_8250_flush_rx(addr_t base) Uart8250::FlushRx()
{ {
// empty the rx fifo // empty the rx fifo
while (read_8250(base, UART_LSR) & (1<<0)) { while (ReadUart(UART_LSR) & (1<<0)) {
volatile char c = read_8250(base, UART_RHR); volatile char c = ReadUart(UART_RHR);
(void)c; (void)c;
} }
} }
+41 -29
View File
@@ -14,22 +14,34 @@
//#include <target/debugconfig.h> //#include <target/debugconfig.h>
static inline void UartPL011::UartPL011(addr_t base)
write_pl011(addr_t base, uint reg, unsigned char data) :
fUARTBase(base)
{ {
*(volatile unsigned char *)(base + reg) = data;
} }
static inline unsigned char UartPL011::~UartPL011()
read_pl011(addr_t base, uint reg)
{ {
return *(volatile unsigned char *)(base + reg);
} }
void void
uart_pl011_init_port(addr_t base, uint baud) UartPL011::WriteUart(uint32 reg, unsigned char data)
{
*(volatile unsigned char *)(fUARTBase + reg) = data;
}
unsigned char
UartPL011::ReadUart(uint32 reg)
{
return *(volatile unsigned char *)(fUARTBase + reg);
}
void
UartPL011::InitPort(uint32 baud)
{ {
uint16 clockDiv uint16 clockDiv
= (baud > BOARD_UART_CLOCK / 16) ? 8 : 4; = (baud > BOARD_UART_CLOCK / 16) ? 8 : 4;
@@ -39,25 +51,25 @@ uart_pl011_init_port(addr_t base, uint baud)
// Disable everything // Disable everything
unsigned char originalCR unsigned char originalCR
= read_pl011(base, PL011_CR); = ReadUart(PL011_CR);
write_pl011(base, PL011_CR, 0); WriteUart(PL011_CR, 0);
// Set baud divisor // Set baud divisor
write_pl011(base, PL011_FBRD, baudDivisor & 0x3f); WriteUart(PL011_FBRD, baudDivisor & 0x3f);
write_pl011(base, PL011_IBRD, baudDivisor >> 6); WriteUart(PL011_IBRD, baudDivisor >> 6);
// Set LCR // Set LCR
write_pl011(base, PL011_LCRH, lcr); WriteUart(PL011_LCRH, lcr);
// Disable auto RTS / CTS in original CR // Disable auto RTS / CTS in original CR
originalCR &= ~(PL011_CR_CTSEN | PL011_CR_RTSEN); originalCR &= ~(PL011_CR_CTSEN | PL011_CR_RTSEN);
write_pl011(base, PL011_CR, originalCR); WriteUart(PL011_CR, originalCR);
} }
void void
uart_pl011_init_early(void) UartPL011::InitEarly()
{ {
// Perform special hardware UART configuration // Perform special hardware UART configuration
// Raspberry Pi: Early setup handled by gpio_init in platform code // Raspberry Pi: Early setup handled by gpio_init in platform code
@@ -65,33 +77,33 @@ uart_pl011_init_early(void)
void void
uart_pl011_init(addr_t base) UartPL011::Init()
{ {
// TODO: Enable clock producer? // TODO: Enable clock producer?
// TODO: Clear pending error and receive interrupts // TODO: Clear pending error and receive interrupts
// Provoke TX FIFO into asserting // Provoke TX FIFO into asserting
unsigned char cr = PL011_CR_UARTEN | PL011_CR_TXE | PL011_IFLS; uint32 cr = PL011_CR_UARTEN | PL011_CR_TXE | PL011_IFLS;
write_pl011(base, PL011_CR, cr); WriteUart(PL011_CR, cr);
write_pl011(base, PL011_FBRD, 0); WriteUart(PL011_FBRD, 0);
write_pl011(base, PL011_IBRD, 1); WriteUart(PL011_IBRD, 1);
// TODO: For arm vendor, st different rx vs tx // TODO: For arm vendor, st different rx vs tx
write_pl011(base, PL011_LCRH, 0); WriteUart(PL011_LCRH, 0);
write_pl011(base, PL01x_DR, 0); WriteUart(PL01x_DR, 0);
while (read_pl011(base, PL01x_FR) & PL01x_FR_BUSY); while (ReadUart(PL01x_FR) & PL01x_FR_BUSY);
// Wait for xmit // Wait for xmit
} }
int int
uart_pl011_putchar(addr_t base, char c) UartPL011::PutChar(char c)
{ {
write_pl011(base, PL01x_DR, (unsigned int)c); WriteUart(PL01x_DR, (unsigned int)c);
while (read_pl011(base, PL01x_FR) & PL01x_FR_TXFF); while (ReadUart(PL01x_FR) & PL01x_FR_TXFF);
// wait for the last char to get out // wait for the last char to get out
return 0; return 0;
@@ -100,7 +112,7 @@ uart_pl011_putchar(addr_t base, char c)
/* returns -1 if no data available */ /* returns -1 if no data available */
int int
uart_pl011_getchar(addr_t base, bool wait) UartPL011::GetChar(bool wait)
{ {
#warning ARM Amba PL011 UART incomplete #warning ARM Amba PL011 UART incomplete
return -1; return -1;
@@ -108,15 +120,15 @@ uart_pl011_getchar(addr_t base, bool wait)
void void
uart_pl011_flush_tx(addr_t base) UartPL011::FlushTx()
{ {
while (read_pl011(base, PL01x_FR) & PL01x_FR_TXFF); while (ReadUart(PL01x_FR) & PL01x_FR_TXFF);
// wait for the last char to get out // wait for the last char to get out
} }
void void
uart_pl011_flush_rx(addr_t base) UartPL011::FlushRx()
{ {
#warning ARM Amba PL011 UART incomplete #warning ARM Amba PL011 UART incomplete
} }