1// Copyright 2018 The Fuchsia Authors
2// Use of this source code is governed by a MIT-style
3// license that can be found in the LICENSE file or at
4// https://opensource.org/licenses/MIT
5
6#include <arch/arm64/periphmap.h>
7#include <dev/interrupt.h>
8#include <dev/uart.h>
9#include <kernel/thread.h>
10#include <lib/cbuf.h>
11#include <lib/debuglog.h>
12#include <pdev/driver.h>
13#include <pdev/uart.h>
14#include <platform/debug.h>
15#include <reg.h>
16#include <stdio.h>
17#include <trace.h>
18#include <zircon/boot/driver-config.h>
19
20// clang-format off
21
22// Registers
23
24#define UART_RBR                    (0x0)   // RX Buffer Register (read-only)
25#define UART_THR                    (0x0)   // TX Buffer Register (write-only)
26#define UART_IER                    (0x4)   // Interrupt Enable Register
27#define UART_IIR                    (0x8)   // Interrupt Identification Register (read-only)
28#define UART_FCR                    (0x8)   // FIFO Control Register (write-only)
29#define UART_LCR                    (0xc)   // Line Control Register
30#define UART_MCR                    (0x10)  // Modem Control Register
31#define UART_LSR                    (0x14)  // Line Status Register
32#define UART_MSR                    (0x18)  // Modem Status Register
33#define UART_SCR                    (0x1c)  // Scratch Register
34#define UART_DLL                    (0x0)   // Divisor Latch LS (Only when LCR.DLAB = 1)
35#define UART_DLM                    (0x4)   // Divisor Latch MS (Only when LCR.DLAB = 1)
36#define UART_EFR                    (0x8)   // Enhanced Feature Register (Only when LCR = 0xbf)
37#define UART_XON1                   (0x10)  // XON1 Char Register (Only when LCR = 0xbf)
38#define UART_XON2                   (0x14)  // XON2 Char Register (Only when LCR = 0xbf)
39#define UART_XOFF1                  (0x18)  // XOFF1 Char Register (Only when LCR = 0xbf)
40#define UART_XOFF2                  (0x1c)  // XOFF2 Char Register (Only when LCR = 0xbf)
41#define UART_AUTOBAUD_EN            (0x20)  // Auto Baud Detect Enable Register
42#define UART_HIGHSPEED              (0x24)  // High Speed Mode Register
43#define UART_SAMPLE_COUNT           (0x28)  // Sample Counter Register
44#define UART_SAMPLE_POINT           (0x2c)  // Sample Point Register
45#define UART_AUTOBAUD_REG           (0x30)  // Auto Baud Monitor Register
46#define UART_RATE_FIX_AD            (0x34)  // Clock Rate Fix Register
47#define UART_AUTOBAUD_SAMPLE        (0x38)  // Auto Baud Sample Register
48#define UART_GUARD                  (0x3c)  // Guard Time Added Register
49#define UART_ESCAPE_DAT             (0x40)  // Escape Character Register
50#define UART_ESCAPE_EN              (0x44)  // Escape Enable Register
51#define UART_SLEEP_EN               (0x48)  // Sleep Enable Register
52#define UART_VFIFO_EN               (0x4c)  // DMA Enable Register
53#define UART_RXTRI_AD               (0x50)  // RX Trigger Address
54
55// IER
56#define UART_IER_ERBFI              (1 << 0)
57#define UART_IER_ETBEI              (1 << 1)
58#define UART_IER_ELSI               (1 << 2)
59#define UART_IER_EDSSI              (1 << 3)
60#define UART_IER_XOFFI              (1 << 5)
61#define UART_IER_RTSI               (1 << 6)
62#define UART_IER_CTSI               (1 << 7)
63#define UART_IIR_NO_INT_PENDING     (0x01)
64
65// IIR
66#define UART_IIR_RLS                (0x06)  // Receiver Line Status
67#define UART_IIR_RDA                (0x04)  // Receive Data Available
68#define UART_IIR_CTI                (0x0C)  // Character Timeout Indicator
69#define UART_IIR_THRE               (0x02)  // Transmit Holding Register Empty
70#define UART_IIR_MS                 (0x00)  // Check Modem Status Register
71#define UART_IIR_SW_FLOW_CTRL       (0x10)  // Receive XOFF characters
72#define UART_IIR_HW_FLOW_CTRL       (0x20)  // CTS or RTS Rising Edge
73#define UART_IIR_FIFO_EN            (0xc0)
74#define UART_IIR_INT_MASK           (0x1f)
75
76// LSR
77#define UART_LSR_DR                 (1 << 0)
78#define UART_LSR_OE                 (1 << 1)
79#define UART_LSR_PE                 (1 << 2)
80#define UART_LSR_FE                 (1 << 3)
81#define UART_LSR_BI                 (1 << 4)
82#define UART_LSR_THRE               (1 << 5)
83#define UART_LSR_TEMT               (1 << 6)
84#define UART_LSR_FIFOERR            (1 << 7)
85
86// clang-format on
87
88#define RXBUF_SIZE 32
89
90// values read from zbi
91static bool initialized = false;
92static vaddr_t uart_base = 0;
93static uint32_t uart_irq = 0;
94static cbuf_t uart_rx_buf;
95
96static bool uart_tx_irq_enabled = false;
97static event_t uart_dputc_event = EVENT_INITIAL_VALUE(uart_dputc_event,
98                                                      true,
99                                                      EVENT_FLAG_AUTOUNSIGNAL);
100
101static spin_lock_t uart_spinlock = SPIN_LOCK_INITIAL_VALUE;
102
103#define UARTREG(reg) (*(volatile uint32_t*)((uart_base) + (reg)))
104
105static void uart_irq_handler(void* arg) {
106    // read interrupt status and mask
107    while (UARTREG(UART_LSR) & UART_LSR_DR) {
108        if (cbuf_space_avail(&uart_rx_buf) == 0) {
109            break;
110        }
111        char c = UARTREG(UART_RBR) & 0xFF;
112        cbuf_write_char(&uart_rx_buf, c);
113    }
114
115    // Signal if anyone is waiting to TX
116    if (UARTREG(UART_LSR) & UART_LSR_THRE) {
117        spin_lock(&uart_spinlock);
118        event_signal(&uart_dputc_event, true);
119        spin_unlock(&uart_spinlock);
120    }
121}
122
123// panic-time getc/putc
124static int mt8167_uart_pputc(char c) {
125    if (!uart_base) {
126        return -1;
127    }
128
129    // spin while fifo is full
130    while (!(UARTREG(UART_LSR) & UART_LSR_THRE))
131        ;
132    UARTREG(UART_THR) = c;
133
134    return 1;
135}
136
137static int mt8167_uart_pgetc(void) {
138    if (!uart_base) {
139        return ZX_ERR_NOT_SUPPORTED;
140    }
141
142    // spin while fifo is empty
143    while (!(UARTREG(UART_LSR) & UART_LSR_DR))
144        ;
145    return UARTREG(UART_RBR);
146}
147
148static int mt8167_uart_getc(bool wait) {
149    if (!uart_base) {
150        return ZX_ERR_NOT_SUPPORTED;
151    }
152
153    if (initialized) {
154        char c;
155        if (cbuf_read_char(&uart_rx_buf, &c, wait) == 1) {
156            return c;
157        }
158        return ZX_ERR_INTERNAL;
159    } else {
160        // Interrupts are not enabled yet. Use panic calls for now
161        return mt8167_uart_pgetc();
162    }
163}
164
165static void mt8167_dputs(const char* str, size_t len,
166                         bool block, bool map_NL) {
167    spin_lock_saved_state_t state;
168    bool copied_CR = false;
169
170    if (!uart_base) {
171        return;
172    }
173    if (!uart_tx_irq_enabled) {
174        block = false;
175    }
176    spin_lock_irqsave(&uart_spinlock, state);
177
178    while (len > 0) {
179        // is FIFO full?
180        while (!(UARTREG(UART_LSR) & UART_LSR_THRE)) {
181            spin_unlock_irqrestore(&uart_spinlock, state);
182            if (block) {
183                event_wait(&uart_dputc_event);
184            } else {
185                arch_spinloop_pause();
186            }
187            spin_lock_irqsave(&uart_spinlock, state);
188        }
189        if (*str == '\n' && map_NL && !copied_CR) {
190            copied_CR = true;
191            mt8167_uart_pputc('\r');
192        } else {
193            copied_CR = false;
194            mt8167_uart_pputc(*str++);
195            len--;
196        }
197    }
198    spin_unlock_irqrestore(&uart_spinlock, state);
199}
200
201static void mt8167_start_panic(void) {
202    uart_tx_irq_enabled = false;
203}
204
205static const struct pdev_uart_ops uart_ops = {
206    .getc = mt8167_uart_getc,
207    .pputc = mt8167_uart_pputc,
208    .pgetc = mt8167_uart_pgetc,
209    .start_panic = mt8167_start_panic,
210    .dputs = mt8167_dputs,
211};
212
213static void mt8167_uart_init(const void* driver_data, uint32_t length) {
214    // create circular buffer to hold received data
215    cbuf_initialize(&uart_rx_buf, RXBUF_SIZE);
216
217    // register uart irq
218    register_int_handler(uart_irq, &uart_irq_handler, NULL);
219
220// TODO: Configure UART interrupt support here
221
222// TODO: Enable interrupt support after we have a way to set the interrupt to active-low
223#if 0
224    if (dlog_bypass() == true)
225        uart_tx_irq_enabled = false;
226    else {
227        // start up tx driven output
228        printf("UART: started IRQ driven TX\n");
229        uart_tx_irq_enabled = true;
230    }
231
232    initialized = true;
233
234    // TODO we will need to talk to the pinmux controller to set the interrupt to active low.
235    // configure_interrupt() doesn't actually support that.
236    configure_interrupt(uart_irq, IRQ_TRIGGER_MODE_LEVEL, IRQ_POLARITY_ACTIVE_LOW);
237    unmask_interrupt(uart_irq);
238#endif
239}
240
241static void mt8167_uart_init_early(const void* driver_data, uint32_t length) {
242    ASSERT(length >= sizeof(dcfg_simple_t));
243    auto driver = static_cast<const dcfg_simple_t*>(driver_data);
244    ASSERT(driver->mmio_phys && driver->irq);
245
246    uart_base = periph_paddr_to_vaddr(driver->mmio_phys);
247    ASSERT(uart_base);
248    uart_irq = driver->irq;
249
250    pdev_register_uart(&uart_ops);
251}
252
253LK_PDEV_INIT(mt8167_uart_init_early, KDRV_MT8167_UART, mt8167_uart_init_early, LK_INIT_LEVEL_PLATFORM_EARLY);
254LK_PDEV_INIT(mt8167_uart_init, KDRV_MT8167_UART, mt8167_uart_init, LK_INIT_LEVEL_PLATFORM);
255