1/*
2 * Copyright 2019, 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 <string.h>
14#include <stdlib.h>
15#include <platsupport/serial.h>
16#include "../../chardev.h"
17
18#define UART_WFIFO  0x0
19#define UART_RFIFO  0x4
20#define UART_STATUS 0xC
21
22#define UART_TX_FULL        BIT(21)
23#define UART_RX_EMPTY       BIT(20)
24
25#define REG_PTR(base, off)     ((volatile uint32_t *)((base) + (off)))
26
27
28int uart_getchar(ps_chardevice_t *d)
29{
30    while ((*REG_PTR(d->vaddr, UART_STATUS) & UART_RX_EMPTY));
31    return *REG_PTR(d->vaddr, UART_RFIFO);
32}
33
34int uart_putchar(ps_chardevice_t *d, int c)
35{
36    while ((*REG_PTR(d->vaddr, UART_STATUS) & UART_TX_FULL));
37
38    /* Add character to the buffer. */
39    *REG_PTR(d->vaddr, UART_WFIFO) = c & 0x7f;
40    if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
41        uart_putchar(d, '\r');
42    }
43
44    return c;
45}
46
47static void uart_handle_irq(ps_chardevice_t *dev)
48{
49    /* nothing to do, interrupts are not used */
50}
51
52int uart_init(const struct dev_defn *defn,
53              const ps_io_ops_t *ops,
54              ps_chardevice_t *dev)
55{
56    memset(dev, 0, sizeof(*dev));
57    char *page_vaddr = chardev_map(defn, ops);
58    if (page_vaddr == NULL) {
59        return -1;
60    }
61
62    void *uart_vaddr;
63    switch (defn->id) {
64    case UART0:
65        uart_vaddr = page_vaddr + UART0_OFFSET;
66        break;
67    case UART1:
68        uart_vaddr = page_vaddr + UART1_OFFSET;
69        break;
70    case UART2:
71        uart_vaddr = page_vaddr + UART2_OFFSET;
72        break;
73    case UART0_AO:
74        uart_vaddr = page_vaddr + UART0_AO_OFFSET;
75        break;
76    case UART2_AO:
77        uart_vaddr = page_vaddr + UART2_AO_OFFSET;
78        break;
79    }
80
81    /* Set up all the  device properties. */
82    dev->id         = defn->id;
83    dev->vaddr      = uart_vaddr;
84    dev->read       = &uart_read;
85    dev->write      = &uart_write;
86    dev->handle_irq = &uart_handle_irq;
87    dev->irqs       = defn->irqs;
88    dev->ioops      = *ops;
89    dev->flags      = SERIAL_AUTO_CR;
90
91    return 0;
92}
93