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 <autoconf.h>
14
15#include <stdlib.h>
16#include <platsupport/serial.h>
17#include <platsupport/plat/serial.h>
18#include <string.h>
19
20#include "../../chardev.h"
21
22#define UART_TX_DATA_MASK  0xFF
23#define UART_TX_DATA_FULL  BIT(31)
24
25#define UART_RX_DATA_MASK   0xFF
26#define UART_RX_DATA_EMPTY  BIT(31)
27
28#define UART_TX_INT_EN     BIT(0)
29#define UART_RX_INT_EN     BIT(1)
30
31#define UART_TX_INT_PEND     BIT(0)
32#define UART_RX_INT_PEND     BIT(1)
33#define UART_BAUD_DIVISOR 4340
34struct uart {
35    uint32_t txdata;
36    uint32_t rxdata;
37    uint32_t txctrl;
38    uint32_t rxctrl;
39    uint32_t ie;
40    uint32_t ip;
41    uint32_t div;
42};
43typedef volatile struct uart uart_regs_t;
44
45static inline uart_regs_t*
46uart_get_priv(ps_chardevice_t *d)
47{
48    return (uart_regs_t*)d->vaddr;
49}
50
51int uart_getchar(ps_chardevice_t *d)
52{
53    uart_regs_t* regs = uart_get_priv(d);
54    uint32_t reg = regs->rxdata;
55    int c = -1;
56
57    if (!(reg & UART_RX_DATA_EMPTY)) {
58        c = reg & UART_RX_DATA_MASK;
59    }
60    return c;
61}
62
63int uart_putchar(ps_chardevice_t* d, int c)
64{
65    uart_regs_t* regs = uart_get_priv(d);
66    if (!(regs->txdata & UART_TX_DATA_FULL)) {
67        if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
68            regs->txdata = '\r' & UART_TX_DATA_MASK;
69            while(regs->txdata & UART_TX_DATA_FULL) {}
70        }
71        regs->txdata = c & UART_TX_DATA_MASK;
72        return c;
73    } else {
74        return -1;
75    }
76}
77
78static void
79uart_handle_irq(ps_chardevice_t* d UNUSED)
80{
81    // IRQs are cleared when the TX/RX watermark conditions are no longer met
82    // so there is nothing to do here.
83}
84
85int uart_init(const struct dev_defn* defn,
86              const ps_io_ops_t* ops,
87              ps_chardevice_t* dev)
88{
89    uart_regs_t* regs;
90    /* Attempt to map the virtual address, assure this works */
91    void* vaddr = chardev_map(defn, ops);
92    if (vaddr == NULL) {
93        return -1;
94    }
95
96    memset(dev, 0, sizeof(*dev));
97
98    /* Set up all the  device properties. */
99    dev->id         = defn->id;
100    dev->vaddr      = (void*)vaddr;
101    dev->read       = &uart_read;
102    dev->write      = &uart_write;
103    dev->handle_irq = &uart_handle_irq;
104    dev->irqs       = defn->irqs;
105    dev->ioops      = *ops;
106    dev->flags      = SERIAL_AUTO_CR;
107
108    regs = uart_get_priv(dev);
109
110    /*
111     * Enable TX and RX and don't set any watermark levels.
112     * 0 watermark on RX indicates an IRQ when more than 0 chars in RX buffer
113     * O watermark on TX indicates no IRQ (less than 0 chars in TX buffer)
114     */
115    regs->txctrl = 0x00001;
116    regs->rxctrl = 0x00001;
117    /* Enable RX IRQs.  We don't enable TX IRQs as we don't expect any. */
118    regs->ie = 0x2;
119
120    if (regs->div != UART_BAUD_DIVISOR) {
121        ZF_LOGW("Warning: We require a target baud of 115200 and assume an input clk freq 500MHz.");
122        ZF_LOGW("Warning: However an incorrect divisor is set: %d, expected %d", regs->div, UART_BAUD_DIVISOR);
123    }
124
125    return 0;
126}
127