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/* $esc:(#include <autoconf.h>) */
14
15$esc:(#ifndef CONFIG_PLAT_KZM)
16
17$esc:(#include <stdint.h>)
18$esc:(#include <stdlib.h>)
19$esc:(#include <string.h>)
20$esc:(#include "platsupport/serial.h")
21$esc:(#include "platsupport/plat/serial.h")
22
23$esc:(#include "chardev.h")
24
25$esc:(#ifndef UART_REF_CLK)
26$esc:(#error "UART_REF_CLK undefined")
27$esc:(#endif)
28
29
30/* Cogent types */
31typedef struct _Machine SysState;
32
33/* The global state */
34struct _Machine {
35    void *priv;
36    ps_chardevice_t *dev;
37};
38
39
40#include "generated.c"
41
42struct imx_uart_regs {
43    uint32_t rxd;      /* 0x000 Receiver Register */
44    uint32_t res0[15];
45    uint32_t txd;      /* 0x040 Transmitter Register */
46    uint32_t res1[15];
47    uint32_t cr1;      /* 0x080 Control Register 1 */
48    uint32_t cr2;      /* 0x084 Control Register 2 */
49    uint32_t cr3;      /* 0x088 Control Register 3 */
50    uint32_t cr4;      /* 0x08C Control Register 4 */
51    uint32_t fcr;      /* 0x090 FIFO Control Register */
52    uint32_t sr1;      /* 0x094 Status Register 1 */
53    uint32_t sr2;      /* 0x098 Status Register 2 */
54    uint32_t esc;      /* 0x09c Escape Character Register */
55    uint32_t tim;      /* 0x0a0 Escape Timer Register */
56    uint32_t bir;      /* 0x0a4 BRM Incremental Register */
57    uint32_t bmr;      /* 0x0a8 BRM Modulator Register */
58    uint32_t brc;      /* 0x0ac Baud Rate Counter Register */
59    uint32_t onems;    /* 0x0b0 One Millisecond Register */
60    uint32_t ts;       /* 0x0b4 Test Register */
61};
62typedef volatile struct imx_uart_regs imx_uart_regs_t;
63
64static inline imx_uart_regs_t *imx_uart_get_priv(ps_chardevice_t *d)
65{
66    return (imx_uart_regs_t *)d->vaddr;
67}
68
69
70/**
71 * Register readers and writers.
72 */
73#define REG_RW_FN(REG)                                                  \
74$ty:((U32, SysState)) $id:(imx_uart_regs_read_##REG)($ty:(SysState) st) \
75{                                                                       \
76    imx_uart_regs_t *regs;                                              \
77    $ty:((U32, SysState)) ret;                                          \
78                                                                        \
79    regs = imx_uart_get_priv(st->dev);                                  \
80    ret.p1 = regs->REG;                                                 \
81    ret.p2 = st;                                                        \
82                                                                        \
83    return ret;                                                         \
84}                                                                       \
85 \
86$ty:((SysState)) imx_uart_regs_write_##REG($ty:((U32, SysState)) args)  \
87{                                                                       \
88    $ty:(SysState) st = args.p2;                                        \
89    imx_uart_regs_t *regs;                                              \
90                                                                        \
91    regs = imx_uart_get_priv(st->dev);                                  \
92    regs->REG = args.p1;                                                \
93                                                                        \
94    return st;                                                          \
95}
96
97REG_RW_FN(rxd)
98REG_RW_FN(txd)
99REG_RW_FN(cr1)
100REG_RW_FN(cr2)
101REG_RW_FN(cr3)
102REG_RW_FN(cr4)
103REG_RW_FN(fcr)
104REG_RW_FN(sr1)
105REG_RW_FN(sr2)
106REG_RW_FN(esc)
107REG_RW_FN(tim)
108REG_RW_FN(bir)
109REG_RW_FN(bmr)
110REG_RW_FN(brc)
111REG_RW_FN(onems)
112REG_RW_FN(ts)
113
114static void uart_handle_irq(ps_chardevice_t* d)
115{
116        /* TODO */
117}
118
119int uart_getchar(ps_chardevice_t* d)
120{
121    $ty:((SysState, U32)) ret;
122    SysState st;
123    uint32_t reg = 0;
124    int c = -1;
125
126    st.dev = d;
127    ret = uart_getchar_cg(&st);
128
129    c = ret.p2;
130
131    return c;
132}
133
134int uart_putchar(ps_chardevice_t* d, int c)
135{
136    imx_uart_regs_t* regs = imx_uart_get_priv(d);
137    if (regs->sr2 & UART_SR2_TXFIFO_EMPTY) {
138        if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
139            uart_putchar(d, '\r');
140        }
141        regs->txd = c;
142        return c;
143    } else {
144        return -1;
145    }
146}
147
148$ty:((SysState)) uart_setup_phase1_ac($ty:((SysState)) state)
149{
150    imx_uart_regs_t* regs = imx_uart_get_priv(state->dev);
151
152    while (!(regs->cr2 & UART_CR2_SRST));
153
154    return state;
155}
156
157int uart_init(const struct dev_defn *defn,
158              const ps_io_ops_t *ops,
159              ps_chardevice_t *dev)
160{
161    imx_uart_regs_t* regs;
162    SysState st;
163    $ty:((SysState)) ret;
164
165    /* Attempt to map the virtual address, assure this works */
166    void* vaddr = chardev_map(defn, ops);
167    if (vaddr == NULL) {
168        return -1;
169    }
170
171    memset(dev, 0, sizeof(*dev));
172
173    /* Set up all the  device properties. */
174    dev->id         = defn->id;
175    dev->vaddr      = (void*)vaddr;
176    dev->read       = &uart_read;
177    dev->write      = &uart_write;
178    dev->handle_irq = &uart_handle_irq;
179    dev->irqs       = defn->irqs;
180    dev->ioops      = *ops;
181    dev->flags      = SERIAL_AUTO_CR;
182
183    st.dev = dev;
184    ret = $exp:uart_setup(&st);
185
186    $escstm:(#ifdef CONFIG_PLAT_IMX6)
187        /* The UART1 on the IMX6 has the problem that the MUX is not correctly set,
188         * and the RX PIN is not routed correctly.
189         */
190        if ((defn->id == IMX_UART1) && mux_sys_valid(&ops->mux_sys)) {
191            if (mux_feature_enable(&ops->mux_sys, MUX_UART1, 0)) {
192                // Failed to configure the mux
193                return -1;
194            }
195        }
196     $escstm:(#endif)
197     return 0;
198}
199
200$esc:(#endif) /* end of !CONFIG_PLAT_KZM */
201