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 #define MX8_URXD (0x00)
24 #define MX8_UTXD (0x40)
25 #define MX8_UCR1 (0x80)
26 #define MX8_UCR2 (0x84)
27 #define MX8_UCR3 (0x88)
28 #define MX8_UCR4 (0x8C)
29 #define MX8_UFCR (0x90)
30 #define MX8_USR1 (0x94)
31 #define MX8_USR2 (0x98)
32 #define MX8_UTS (0xB4)
33
34 /* UCR1 Bit Definition */
35 #define UCR1_TRDYEN (1 << 13)
36 #define UCR1_RRDYEN (1 << 9)
37 #define UCR1_UARTEN (1 << 0)
38
39 /* UCR2 Bit Definition */
40 #define UCR2_TXEN (1 << 2)
41 #define UCR2_RXEN (1 << 1)
42 #define UCR2_SRST (1 << 0)
43
44 /* UFCR Bit Definition */
45 #define UFCR_TXTL(x) (x << 10)
46 #define UFCR_RXTL(x) (x << 0)
47 #define UFCR_MASK (0x3f)
48
49 /* USR1 Bit Definition */
50 #define USR1_TRDY (1 << 13)
51 #define USR1_RRDY (1 << 9)
52
53 /* USR2 Bit Definition */
54 #define USR2_TXFE (1 << 14)
55
56 /* UTS Bit Definition */
57 #define UTS_TXEMPTY (1 << 6)
58 #define UTS_RXEMPTY (1 << 5)
59 #define UTS_TXFULL (1 << 4)
60 #define UTS_RXFULL (1 << 3)
61
62 #define RXBUF_SIZE 32
63
64 // clang-format on
65
66 // values read from zbi
67 static bool initialized = false;
68 static vaddr_t uart_base = 0;
69 static uint32_t uart_irq = 0;
70 static cbuf_t uart_rx_buf;
71 // static cbuf_t uart_tx_buf;
72
73 static bool uart_tx_irq_enabled = false;
74 static event_t uart_dputc_event = EVENT_INITIAL_VALUE(uart_dputc_event,
75 true,
76 EVENT_FLAG_AUTOUNSIGNAL);
77
78 static spin_lock_t uart_spinlock = SPIN_LOCK_INITIAL_VALUE;
79
80 #define UARTREG(reg) (*(volatile uint32_t*)((uart_base) + (reg)))
81
uart_irq_handler(void * arg)82 static interrupt_eoi uart_irq_handler(void* arg) {
83 /* read interrupt status and mask */
84 while ((UARTREG(MX8_USR1) & USR1_RRDY)) {
85 if (cbuf_space_avail(&uart_rx_buf) == 0) {
86 break;
87 }
88 char c = UARTREG(MX8_URXD) & 0xFF;
89 cbuf_write_char(&uart_rx_buf, c);
90 }
91
92 /* Signal if anyone is waiting to TX */
93 if (UARTREG(MX8_UCR1) & UCR1_TRDYEN) {
94 spin_lock(&uart_spinlock);
95 if (!(UARTREG(MX8_USR2) & UTS_TXFULL)) {
96 // signal
97 event_signal(&uart_dputc_event, true);
98 }
99 spin_unlock(&uart_spinlock);
100 }
101
102 return IRQ_EOI_DEACTIVATE;
103 }
104
105 /* panic-time getc/putc */
imx_uart_pputc(char c)106 static int imx_uart_pputc(char c) {
107 if (!uart_base) {
108 return -1;
109 }
110
111 /* spin while fifo is full */
112 while (UARTREG(MX8_UTS) & UTS_TXFULL)
113 ;
114 UARTREG(MX8_UTXD) = c;
115
116 return 1;
117 }
118
imx_uart_pgetc()119 static int imx_uart_pgetc() {
120 if (!uart_base) {
121 return ZX_ERR_NOT_SUPPORTED;
122 }
123
124 if ((UARTREG(MX8_UTS) & UTS_RXEMPTY)) {
125 return ZX_ERR_INTERNAL;
126 }
127
128 return UARTREG(MX8_URXD);
129 }
130
imx_uart_getc(bool wait)131 static int imx_uart_getc(bool wait) {
132 if (!uart_base) {
133 return ZX_ERR_NOT_SUPPORTED;
134 }
135
136 if (initialized) {
137 char c;
138 if (cbuf_read_char(&uart_rx_buf, &c, wait) == 1) {
139 return c;
140 }
141 return ZX_ERR_INTERNAL;
142 } else {
143 // Interrupts are not enabled yet. Use panic calls for now
144 return imx_uart_pgetc();
145 }
146 }
147
imx_dputs(const char * str,size_t len,bool block,bool map_NL)148 static void imx_dputs(const char* str, size_t len,
149 bool block, bool map_NL) {
150 spin_lock_saved_state_t state;
151 bool copied_CR = false;
152
153 if (!uart_base) {
154 return;
155 }
156 if (!uart_tx_irq_enabled) {
157 block = false;
158 }
159 spin_lock_irqsave(&uart_spinlock, state);
160
161 while (len > 0) {
162 // is FIFO full?
163 while ((UARTREG(MX8_UTS) & UTS_TXFULL)) {
164 spin_unlock_irqrestore(&uart_spinlock, state);
165 if (block) {
166 event_wait(&uart_dputc_event);
167 } else {
168 arch_spinloop_pause();
169 }
170 spin_lock_irqsave(&uart_spinlock, state);
171 }
172 if (*str == '\n' && map_NL && !copied_CR) {
173 copied_CR = true;
174 imx_uart_pputc('\r');
175 } else {
176 copied_CR = false;
177 imx_uart_pputc(*str++);
178 len--;
179 }
180 }
181 spin_unlock_irqrestore(&uart_spinlock, state);
182 }
183
imx_start_panic()184 static void imx_start_panic() {
185 uart_tx_irq_enabled = false;
186 }
187
188 static const struct pdev_uart_ops uart_ops = {
189 .getc = imx_uart_getc,
190 .pputc = imx_uart_pputc,
191 .pgetc = imx_uart_pgetc,
192 .start_panic = imx_start_panic,
193 .dputs = imx_dputs,
194 };
195
imx_uart_init(const void * driver_data,uint32_t length)196 static void imx_uart_init(const void* driver_data, uint32_t length) {
197 uint32_t regVal;
198
199 // create circular buffer to hold received data
200 cbuf_initialize(&uart_rx_buf, RXBUF_SIZE);
201
202 // register uart irq
203 register_int_handler(uart_irq, &uart_irq_handler, NULL);
204
205 // set rx fifo threshold to 1 character
206 regVal = UARTREG(MX8_UFCR);
207 regVal &= ~UFCR_RXTL(UFCR_MASK);
208 regVal &= ~UFCR_TXTL(UFCR_MASK);
209 regVal |= UFCR_RXTL(1);
210 regVal |= UFCR_TXTL(0x2);
211 UARTREG(MX8_UFCR) = regVal;
212
213 // enable rx interrupt
214 regVal = UARTREG(MX8_UCR1);
215 regVal |= UCR1_RRDYEN;
216 if (dlog_bypass() == false) {
217 // enable tx interrupt
218 regVal |= UCR1_TRDYEN;
219 }
220 UARTREG(MX8_UCR1) = regVal;
221
222 // enable rx and tx transmisster
223 regVal = UARTREG(MX8_UCR2);
224 regVal |= UCR2_RXEN | UCR2_TXEN;
225 UARTREG(MX8_UCR2) = regVal;
226
227 if (dlog_bypass() == true) {
228 uart_tx_irq_enabled = false;
229 } else {
230 /* start up tx driven output */
231 printf("UART: started IRQ driven TX\n");
232 uart_tx_irq_enabled = true;
233 }
234
235 initialized = true;
236
237 // enable interrupts
238 unmask_interrupt(uart_irq);
239 }
240
imx_uart_init_early(const void * driver_data,uint32_t length)241 static void imx_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
253 LK_PDEV_INIT(imx_uart_init_early, KDRV_NXP_IMX_UART, imx_uart_init_early, LK_INIT_LEVEL_PLATFORM_EARLY);
254 LK_PDEV_INIT(imx_uart_init, KDRV_NXP_IMX_UART, imx_uart_init, LK_INIT_LEVEL_PLATFORM);
255