1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <stdlib.h>
14#include <platsupport/serial.h>
15#include <platsupport/plat/serial.h>
16#include "serial.h"
17#include <string.h>
18
19#define REG_PTR(base, off)     ((volatile uint32_t *)((base) + (off)))
20
21/* When DLAB=1, MU_IO is a baud rate register.
22 * Otherwise, write to TX, read to RX */
23#define MU_IO       0x40
24/* When DLAB=1, MU_IIR is a baud rate register.
25 * Otherwise IRQ enable */
26#define MU_IIR      0x44
27#define MU_IER      0x48
28#define MU_LCR      0x4C
29#define MU_MCR      0x50
30#define MU_LSR      0x54
31#define MU_MSR      0x58
32#define MU_SCRATCH  0x5C
33#define MU_CNTL     0x60
34
35/* This bit is set if the transmit FIFO can accept at least one byte.*/
36#define MU_LSR_TXEMPTY   BIT(5)
37/* This bit is set if the transmit FIFO is empty and the
38 * transmitter is idle. (Finished shifting out the last bit). */
39#define MU_LSR_TXIDLE    BIT(6)
40#define MU_LSR_RXOVERRUN BIT(1)
41#define MU_LSR_DATAREADY BIT(0)
42
43#define MU_LCR_DLAB      BIT(7)
44#define MU_LCR_BREAK     BIT(6)
45#define MU_LCR_DATASIZE  BIT(0)
46
47static void
48uart_handle_irq(ps_chardevice_t* d UNUSED)
49{
50}
51
52int uart_putchar(ps_chardevice_t* d, int c)
53{
54    while ( !(*REG_PTR(d->vaddr, MU_LSR) & MU_LSR_TXIDLE) );
55    *REG_PTR(d->vaddr, MU_IO) = (c & 0xff);
56
57    return 0;
58}
59
60int uart_getchar(ps_chardevice_t* d UNUSED)
61{
62    while ( !(*REG_PTR(d->vaddr, MU_LSR) & MU_LSR_DATAREADY) );
63    return *REG_PTR(d->vaddr, MU_IO);
64}
65
66int uart_init(const struct dev_defn* defn,
67              const ps_io_ops_t* ops,
68              ps_chardevice_t* dev)
69{
70    /* Attempt to map the virtual address, assure this works */
71    void* vaddr = chardev_map(defn, ops);
72    memset(dev, 0, sizeof(*dev));
73    if (vaddr == NULL) {
74        return -1;
75    }
76
77    /* Set up all the  device properties. */
78    dev->id         = defn->id;
79    dev->vaddr      = (void*)vaddr;
80    dev->read       = &uart_read;
81    dev->write      = &uart_write;
82    dev->handle_irq = &uart_handle_irq;
83    dev->irqs       = defn->irqs;
84    dev->ioops      = *ops;
85    dev->flags      = SERIAL_AUTO_CR;
86
87    return 0;
88}
89