blob: bba81082413e7bbb94e39155c479547ec2c22f09 [file] [log] [blame]
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
#include <stdlib.h>
#include <platsupport/serial.h>
#include <platsupport/plat/serial.h>
#include "serial.h"
#include <string.h>
#define REG_PTR(base, off) ((volatile uint32_t *)((base) + (off)))
/* When DLAB=1, MU_IO is a baud rate register.
* Otherwise, write to TX, read to RX */
#define MU_IO 0x40
/* When DLAB=1, MU_IIR is a baud rate register.
* Otherwise IRQ enable */
#define MU_IIR 0x44
#define MU_IER 0x48
#define MU_LCR 0x4C
#define MU_MCR 0x50
#define MU_LSR 0x54
#define MU_MSR 0x58
#define MU_SCRATCH 0x5C
#define MU_CNTL 0x60
/* This bit is set if the transmit FIFO can accept at least one byte.*/
#define MU_LSR_TXEMPTY BIT(5)
/* This bit is set if the transmit FIFO is empty and the
* transmitter is idle. (Finished shifting out the last bit). */
#define MU_LSR_TXIDLE BIT(6)
#define MU_LSR_RXOVERRUN BIT(1)
#define MU_LSR_DATAREADY BIT(0)
#define MU_LCR_DLAB BIT(7)
#define MU_LCR_BREAK BIT(6)
#define MU_LCR_DATASIZE BIT(0)
static void
uart_handle_irq(ps_chardevice_t* d UNUSED)
{
}
int uart_putchar(ps_chardevice_t* d, int c)
{
while ( !(*REG_PTR(d->vaddr, MU_LSR) & MU_LSR_TXIDLE) );
*REG_PTR(d->vaddr, MU_IO) = (c & 0xff);
return 0;
}
int uart_getchar(ps_chardevice_t* d UNUSED)
{
while ( !(*REG_PTR(d->vaddr, MU_LSR) & MU_LSR_DATAREADY) );
return *REG_PTR(d->vaddr, MU_IO);
}
int uart_init(const struct dev_defn* defn,
const ps_io_ops_t* ops,
ps_chardevice_t* dev)
{
/* Attempt to map the virtual address, assure this works */
void* vaddr = chardev_map(defn, ops);
memset(dev, 0, sizeof(*dev));
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;
return 0;
}