|
|
|
@ -5,22 +5,29 @@
@@ -5,22 +5,29 @@
|
|
|
|
|
#include "microwatt_soc.h" |
|
|
|
|
#include "io.h" |
|
|
|
|
|
|
|
|
|
#define UART_FREQ 115200 |
|
|
|
|
#define UART_BAUDS 115200 |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
* Core UART functions to implement for a port |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static uint64_t potato_uart_base; |
|
|
|
|
bool uart_is_std; |
|
|
|
|
|
|
|
|
|
static uint64_t uart_base; |
|
|
|
|
|
|
|
|
|
static unsigned long uart_divisor(unsigned long uart_freq, unsigned long bauds) |
|
|
|
|
{ |
|
|
|
|
return uart_freq / (bauds * 16); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uint64_t potato_uart_reg_read(int offset) |
|
|
|
|
{ |
|
|
|
|
return readq(potato_uart_base + offset); |
|
|
|
|
return readq(uart_base + offset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void potato_uart_reg_write(int offset, uint64_t val) |
|
|
|
|
{ |
|
|
|
|
writeq(val, potato_uart_base + offset); |
|
|
|
|
writeq(val, uart_base + offset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int potato_uart_rx_empty(void) |
|
|
|
@ -65,22 +72,13 @@ static void potato_uart_write(char c)
@@ -65,22 +72,13 @@ static void potato_uart_write(char c)
|
|
|
|
|
potato_uart_reg_write(POTATO_CONSOLE_TX, val); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static unsigned long potato_uart_divisor(unsigned long proc_freq, unsigned long uart_freq) |
|
|
|
|
{ |
|
|
|
|
return proc_freq / (uart_freq * 16) - 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void potato_uart_init(void) |
|
|
|
|
static void potato_uart_init(uint64_t uart_freq) |
|
|
|
|
{ |
|
|
|
|
uint64_t proc_freq; |
|
|
|
|
|
|
|
|
|
potato_uart_base = UART_BASE; |
|
|
|
|
proc_freq = readq(SYSCON_BASE + SYS_REG_CLKINFO) & SYS_REG_CLKINFO_FREQ_MASK; |
|
|
|
|
|
|
|
|
|
potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, potato_uart_divisor(proc_freq, UART_FREQ)); |
|
|
|
|
unsigned long div = uart_divisor(uart_freq, UART_BAUDS) - 1; |
|
|
|
|
potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, div); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void potato_uart_set_irq_en(bool rx_irq, bool tx_irq) |
|
|
|
|
static void potato_uart_set_irq_en(bool rx_irq, bool tx_irq) |
|
|
|
|
{ |
|
|
|
|
uint64_t en = 0; |
|
|
|
|
|
|
|
|
@ -91,25 +89,76 @@ void potato_uart_set_irq_en(bool rx_irq, bool tx_irq)
@@ -91,25 +89,76 @@ void potato_uart_set_irq_en(bool rx_irq, bool tx_irq)
|
|
|
|
|
potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN, en); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void potato_uart_irq_dis(void) |
|
|
|
|
static bool std_uart_rx_empty(void) |
|
|
|
|
{ |
|
|
|
|
potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN, 0x00); |
|
|
|
|
return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_DR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int getchar(void) |
|
|
|
|
static uint8_t std_uart_read(void) |
|
|
|
|
{ |
|
|
|
|
while (potato_uart_rx_empty()) |
|
|
|
|
/* Do nothing */ ; |
|
|
|
|
return readb(uart_base + UART_REG_RX); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return potato_uart_read(); |
|
|
|
|
static bool std_uart_tx_full(void) |
|
|
|
|
{ |
|
|
|
|
return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_THRE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int putchar(int c) |
|
|
|
|
static void std_uart_write(uint8_t c) |
|
|
|
|
{ |
|
|
|
|
while (potato_uart_tx_full()) |
|
|
|
|
/* Do Nothing */; |
|
|
|
|
writeb(c, uart_base + UART_REG_TX); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void std_uart_set_irq_en(bool rx_irq, bool tx_irq) |
|
|
|
|
{ |
|
|
|
|
uint8_t ier = 0; |
|
|
|
|
|
|
|
|
|
potato_uart_write(c); |
|
|
|
|
if (tx_irq) |
|
|
|
|
ier |= UART_REG_IER_THRI; |
|
|
|
|
if (rx_irq) |
|
|
|
|
ier |= UART_REG_IER_RDI; |
|
|
|
|
writeb(ier, uart_base + UART_REG_IER); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void std_uart_init(uint64_t uart_freq) |
|
|
|
|
{ |
|
|
|
|
unsigned long div = uart_divisor(uart_freq, UART_BAUDS); |
|
|
|
|
|
|
|
|
|
writeb(UART_REG_LCR_DLAB, uart_base + UART_REG_LCR); |
|
|
|
|
writeb(div & 0xff, uart_base + UART_REG_DLL); |
|
|
|
|
writeb(div >> 8, uart_base + UART_REG_DLM); |
|
|
|
|
writeb(UART_REG_LCR_8BIT, uart_base + UART_REG_LCR); |
|
|
|
|
writeb(UART_REG_MCR_DTR | |
|
|
|
|
UART_REG_MCR_RTS, uart_base + UART_REG_MCR); |
|
|
|
|
writeb(UART_REG_FCR_EN_FIFO | |
|
|
|
|
UART_REG_FCR_CLR_RCVR | |
|
|
|
|
UART_REG_FCR_CLR_XMIT, uart_base + UART_REG_FCR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int getchar(void) |
|
|
|
|
{ |
|
|
|
|
if (uart_is_std) { |
|
|
|
|
while (std_uart_rx_empty()) |
|
|
|
|
/* Do nothing */ ; |
|
|
|
|
return std_uart_read(); |
|
|
|
|
} else { |
|
|
|
|
while (potato_uart_rx_empty()) |
|
|
|
|
/* Do nothing */ ; |
|
|
|
|
return potato_uart_read(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int putchar(int c) |
|
|
|
|
{ |
|
|
|
|
if (uart_is_std) { |
|
|
|
|
while(std_uart_tx_full()) |
|
|
|
|
/* Do Nothing */; |
|
|
|
|
std_uart_write(c); |
|
|
|
|
} else { |
|
|
|
|
while (potato_uart_tx_full()) |
|
|
|
|
/* Do Nothing */; |
|
|
|
|
potato_uart_write(c); |
|
|
|
|
} |
|
|
|
|
return c; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -140,10 +189,35 @@ size_t strlen(const char *s)
@@ -140,10 +189,35 @@ size_t strlen(const char *s)
|
|
|
|
|
|
|
|
|
|
void console_init(void) |
|
|
|
|
{ |
|
|
|
|
potato_uart_init(); |
|
|
|
|
uint64_t sys_info; |
|
|
|
|
uint64_t proc_freq; |
|
|
|
|
uint64_t uart_info = 0; |
|
|
|
|
uint64_t uart_freq = 0; |
|
|
|
|
|
|
|
|
|
proc_freq = readq(SYSCON_BASE + SYS_REG_CLKINFO) & SYS_REG_CLKINFO_FREQ_MASK; |
|
|
|
|
sys_info = readq(SYSCON_BASE + SYS_REG_INFO); |
|
|
|
|
|
|
|
|
|
if (sys_info & SYS_REG_INFO_HAS_LARGE_SYSCON) { |
|
|
|
|
uart_info = readq(SYSCON_BASE + SYS_REG_UART0_INFO); |
|
|
|
|
uart_freq = uart_info & 0xffffffff; |
|
|
|
|
} |
|
|
|
|
if (uart_freq == 0) |
|
|
|
|
uart_freq = proc_freq; |
|
|
|
|
|
|
|
|
|
uart_base = UART_BASE; |
|
|
|
|
if (uart_info & SYS_REG_UART_IS_16550) { |
|
|
|
|
uart_is_std = true; |
|
|
|
|
std_uart_init(proc_freq); |
|
|
|
|
} else { |
|
|
|
|
uart_is_std = false; |
|
|
|
|
potato_uart_init(proc_freq); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void console_set_irq_en(bool rx_irq, bool tx_irq) |
|
|
|
|
{ |
|
|
|
|
potato_uart_set_irq_en(rx_irq, tx_irq); |
|
|
|
|
if (uart_is_std) |
|
|
|
|
std_uart_set_irq_en(rx_irq, tx_irq); |
|
|
|
|
else |
|
|
|
|
potato_uart_set_irq_en(rx_irq, tx_irq); |
|
|
|
|
} |
|
|
|
|