blob: 92cd3886523b78378ead807586bd7ad31f134f54 [file] [log] [blame]
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <string.h>
#include <stdlib.h>
#include <platsupport/serial.h>
#include "../../chardev.h"
#define UART_WFIFO 0x0
#define UART_RFIFO 0x4
#define UART_STATUS 0xC
#define UART_TX_FULL BIT(21)
#define UART_RX_EMPTY BIT(20)
#define REG_PTR(base, off) ((volatile uint32_t *)((base) + (off)))
int uart_getchar(ps_chardevice_t *d)
{
while ((*REG_PTR(d->vaddr, UART_STATUS) & UART_RX_EMPTY));
return *REG_PTR(d->vaddr, UART_RFIFO);
}
int uart_putchar(ps_chardevice_t *d, int c)
{
while ((*REG_PTR(d->vaddr, UART_STATUS) & UART_TX_FULL));
/* Add character to the buffer. */
*REG_PTR(d->vaddr, UART_WFIFO) = c & 0x7f;
if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
uart_putchar(d, '\r');
}
return c;
}
static void uart_handle_irq(ps_chardevice_t *dev)
{
/* nothing to do, interrupts are not used */
}
int uart_init(const struct dev_defn *defn,
const ps_io_ops_t *ops,
ps_chardevice_t *dev)
{
memset(dev, 0, sizeof(*dev));
char *page_vaddr = chardev_map(defn, ops);
if (page_vaddr == NULL) {
return -1;
}
void *uart_vaddr;
switch (defn->id) {
case UART0:
uart_vaddr = page_vaddr + UART0_OFFSET;
break;
case UART1:
uart_vaddr = page_vaddr + UART1_OFFSET;
break;
case UART2:
uart_vaddr = page_vaddr + UART2_OFFSET;
break;
case UART0_AO:
uart_vaddr = page_vaddr + UART0_AO_OFFSET;
break;
case UART2_AO:
uart_vaddr = page_vaddr + UART2_AO_OFFSET;
break;
}
/* Set up all the device properties. */
dev->id = defn->id;
dev->vaddr = uart_vaddr;
dev->read = &uart_read;
dev->write = &uart_write;
dev->handle_irq = &uart_handle_irq;
dev->irqs = defn->irqs;
dev->ioops = *ops;
dev->flags = SERIAL_AUTO_CR;
return 0;
}