blob: e9f30d70b02a2bb64e8d5726ca7ecc1a743f9efd [file] [log] [blame]
/*
* Copyright 2017, 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 RHR_MASK MASK(8)
#define UARTDR 0x000
#define UARTFR 0x018
#define UARTIMSC 0x038
#define UARTICR 0x044
#define PL011_UARTFR_TXFF BIT(5)
#define PL011_UARTFR_RXFE BIT(4)
#define REG_PTR(base, off) ((volatile uint32_t *)((base) + (off)))
int uart_getchar(ps_chardevice_t *d)
{
int ch = EOF;
if ((*REG_PTR(d->vaddr, UARTFR) & PL011_UARTFR_RXFE) == 0) {
ch = *REG_PTR(d->vaddr, UARTDR) & RHR_MASK;
}
return ch;
}
int uart_putchar(ps_chardevice_t* d, int c)
{
while ((*REG_PTR(d->vaddr, UARTFR) & PL011_UARTFR_TXFF) != 0);
*REG_PTR(d->vaddr, UARTDR) = c;
if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
uart_putchar(d, '\r');
}
return c;
}
static void
uart_handle_irq(ps_chardevice_t* dev)
{
*REG_PTR(dev->vaddr, UARTICR) = 0x7f0;
}
int uart_init(const struct dev_defn* defn,
const ps_io_ops_t* ops,
ps_chardevice_t* dev)
{
memset(dev, 0, sizeof(*dev));
void* vaddr = chardev_map(defn, ops);
if (vaddr == NULL) {
return -1;
}
/* Set up all the device properties. */
dev->id = defn->id;
dev->vaddr = (void*)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;
*REG_PTR(dev->vaddr, UARTIMSC) = 0x50;
return 0;
}