Breakout the console code so it can be reused.
No functional change. Signed-off-by: Michael Neuling <mikey@neuling.org>pull/155/head
parent
8bee4ae3cc
commit
96fbd61de8
@ -0,0 +1,132 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Core UART functions to implement for a port
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint64_t potato_uart_base;
|
||||||
|
|
||||||
|
#define PROC_FREQ 50000000
|
||||||
|
#define UART_FREQ 115200
|
||||||
|
#define UART_BASE 0xc0002000
|
||||||
|
|
||||||
|
#define POTATO_CONSOLE_TX 0x00
|
||||||
|
#define POTATO_CONSOLE_RX 0x08
|
||||||
|
#define POTATO_CONSOLE_STATUS 0x10
|
||||||
|
#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x01
|
||||||
|
#define POTATO_CONSOLE_STATUS_TX_EMPTY 0x02
|
||||||
|
#define POTATO_CONSOLE_STATUS_RX_FULL 0x04
|
||||||
|
#define POTATO_CONSOLE_STATUS_TX_FULL 0x08
|
||||||
|
#define POTATO_CONSOLE_CLOCK_DIV 0x18
|
||||||
|
#define POTATO_CONSOLE_IRQ_EN 0x20
|
||||||
|
|
||||||
|
static uint64_t potato_uart_reg_read(int offset)
|
||||||
|
{
|
||||||
|
uint64_t addr;
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
addr = potato_uart_base + offset;
|
||||||
|
|
||||||
|
val = *(volatile uint64_t *)addr;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void potato_uart_reg_write(int offset, uint64_t val)
|
||||||
|
{
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
addr = potato_uart_base + offset;
|
||||||
|
|
||||||
|
*(volatile uint64_t *)addr = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int potato_uart_rx_empty(void)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
|
||||||
|
|
||||||
|
if (val & POTATO_CONSOLE_STATUS_RX_EMPTY)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int potato_uart_tx_full(void)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
|
||||||
|
|
||||||
|
if (val & POTATO_CONSOLE_STATUS_TX_FULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char potato_uart_read(void)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
val = potato_uart_reg_read(POTATO_CONSOLE_RX);
|
||||||
|
|
||||||
|
return (char)(val & 0x000000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void potato_uart_write(char c)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
val = 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)
|
||||||
|
{
|
||||||
|
potato_uart_base = UART_BASE;
|
||||||
|
|
||||||
|
potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, potato_uart_divisor(PROC_FREQ, UART_FREQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
int getchar(void)
|
||||||
|
{
|
||||||
|
while (potato_uart_rx_empty())
|
||||||
|
/* Do nothing */ ;
|
||||||
|
|
||||||
|
return potato_uart_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void putchar(unsigned char c)
|
||||||
|
{
|
||||||
|
while (potato_uart_tx_full())
|
||||||
|
/* Do Nothing */;
|
||||||
|
|
||||||
|
potato_uart_write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void putstr(const char *str, unsigned long len)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < len; i++) {
|
||||||
|
putchar(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlen(const char *s)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (*s++)
|
||||||
|
len++;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
void potato_uart_init(void);
|
||||||
|
int getchar(void);
|
||||||
|
void putchar(unsigned char c);
|
||||||
|
void putstr(const char *str, unsigned long len);
|
||||||
|
size_t strlen(const char *s);
|
Loading…
Reference in New Issue