]> git.saurik.com Git - apple/xnu.git/blob - pexpert/arm/pe_serial.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / pexpert / arm / pe_serial.c
1 /*
2 * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
3 */
4
5 /*
6 * file: pe_serial.c Polled-mode UART0 driver for S3c2410 and PL011.
7 */
8
9
10 #include <kern/clock.h>
11 #include <kern/debug.h>
12 #include <libkern/OSBase.h>
13 #include <mach/mach_time.h>
14 #include <machine/atomic.h>
15 #include <machine/machine_routines.h>
16 #include <pexpert/pexpert.h>
17 #include <pexpert/protos.h>
18 #include <pexpert/device_tree.h>
19 #if defined __arm__
20 #include <arm/caches_internal.h>
21 #include <arm/machine_routines.h>
22 #include <arm/proc_reg.h>
23 #include <pexpert/arm/board_config.h>
24 #include <vm/pmap.h>
25 #elif defined __arm64__
26 #include <pexpert/arm/consistent_debug.h>
27 #include <pexpert/arm64/board_config.h>
28 #include <arm64/proc_reg.h>
29 #endif
30
31 struct pe_serial_functions {
32 void (*uart_init) (void);
33 void (*uart_set_baud_rate) (int unit, uint32_t baud_rate);
34 int (*tr0) (void);
35 void (*td0) (int c);
36 int (*rr0) (void);
37 int (*rd0) (void);
38 };
39
40 static struct pe_serial_functions *gPESF;
41
42 static int uart_initted = 0; /* 1 if init'ed */
43
44 static vm_offset_t uart_base;
45
46 /*****************************************************************************/
47
48 #ifdef S3CUART
49
50 static int32_t dt_pclk = -1;
51 static int32_t dt_sampling = -1;
52 static int32_t dt_ubrdiv = -1;
53
54 static void
55 ln2410_uart_init(void)
56 {
57 uint32_t ucon0 = 0x405; /* NCLK, No interrupts, No DMA - just polled */
58
59 rULCON0 = 0x03; /* 81N, not IR */
60
61 // Override with pclk dt entry
62 if (dt_pclk != -1)
63 ucon0 = ucon0 & ~0x400;
64
65 rUCON0 = ucon0;
66 rUMCON0 = 0x00; /* Clear Flow Control */
67
68 gPESF->uart_set_baud_rate(0, 115200);
69
70 rUFCON0 = 0x03; /* Clear & Enable FIFOs */
71 rUMCON0 = 0x01; /* Assert RTS on UART0 */
72 }
73
74 static void
75 ln2410_uart_set_baud_rate(__unused int unit, uint32_t baud_rate)
76 {
77 uint32_t div = 0;
78 uint32_t uart_clock = 0;
79 uint32_t sample_rate = 16;
80
81 if (baud_rate < 300)
82 baud_rate = 9600;
83
84 if (rUCON0 & 0x400)
85 // NCLK
86 uart_clock = (uint32_t)gPEClockFrequencyInfo.fix_frequency_hz;
87 else
88 // PCLK
89 uart_clock = (uint32_t)gPEClockFrequencyInfo.prf_frequency_hz;
90
91 if (dt_sampling != -1) {
92 // Use the sampling rate specified in the Device Tree
93 sample_rate = dt_sampling & 0xf;
94 }
95
96 if (dt_ubrdiv != -1) {
97 // Use the ubrdiv specified in the Device Tree
98 div = dt_ubrdiv & 0xffff;
99 } else {
100 // Calculate ubrdiv. UBRDIV = (SourceClock / (BPS * Sample Rate)) - 1
101 div = uart_clock / (baud_rate * sample_rate);
102
103 uint32_t actual_baud = uart_clock / ((div + 0) * sample_rate);
104 uint32_t baud_low = uart_clock / ((div + 1) * sample_rate);
105
106 // Adjust div to get the closest target baudrate
107 if ((baud_rate - baud_low) > (actual_baud - baud_rate))
108 div--;
109 }
110
111 // Sample Rate [19:16], UBRDIV [15:0]
112 rUBRDIV0 = ((16 - sample_rate) << 16) | div;
113 }
114
115 static int
116 ln2410_tr0(void)
117 {
118 return rUTRSTAT0 & 0x04;
119 }
120 static void
121 ln2410_td0(int c)
122 {
123 rUTXH0 = (unsigned)(c & 0xff);
124 }
125 static int
126 ln2410_rr0(void)
127 {
128 return rUTRSTAT0 & 0x01;
129 }
130 static int
131 ln2410_rd0(void)
132 {
133 return (int)rURXH0;
134 }
135
136 static struct pe_serial_functions ln2410_serial_functions = {
137 ln2410_uart_init, ln2410_uart_set_baud_rate,
138 ln2410_tr0, ln2410_td0, ln2410_rr0, ln2410_rd0};
139
140 #endif /* S3CUART */
141
142 /*****************************************************************************/
143
144
145 static unsigned int
146 read_dtr(void)
147 {
148 #ifdef __arm__
149 unsigned int c;
150 __asm__ volatile(
151 "mrc p14, 0, %0, c0, c5\n"
152 : "=r"(c));
153 return c;
154 #else
155 /* ARM64_TODO */
156 panic_unimplemented();
157 return 0;
158 #endif
159 }
160 static void
161 write_dtr(unsigned int c)
162 {
163 #ifdef __arm__
164 __asm__ volatile(
165 "mcr p14, 0, %0, c0, c5\n"
166 :
167 :"r"(c));
168 #else
169 /* ARM64_TODO */
170 (void)c;
171 panic_unimplemented();
172 #endif
173 }
174
175 static int
176 dcc_tr0(void)
177 {
178 #ifdef __arm__
179 return !(arm_debug_read_dscr() & ARM_DBGDSCR_TXFULL);
180 #else
181 /* ARM64_TODO */
182 panic_unimplemented();
183 return 0;
184 #endif
185 }
186
187 static void
188 dcc_td0(int c)
189 {
190 write_dtr(c);
191 }
192
193 static int
194 dcc_rr0(void)
195 {
196 #ifdef __arm__
197 return arm_debug_read_dscr() & ARM_DBGDSCR_RXFULL;
198 #else
199 /* ARM64_TODO */
200 panic_unimplemented();
201 return 0;
202 #endif
203 }
204
205 static int
206 dcc_rd0(void)
207 {
208 return read_dtr();
209 }
210
211 static struct pe_serial_functions dcc_serial_functions = {
212 NULL, NULL,
213 dcc_tr0, dcc_td0, dcc_rr0, dcc_rd0};
214
215 /*****************************************************************************/
216
217 #ifdef SHMCON
218
219 #define CPU_CACHELINE_SIZE (1 << MMU_CLINE)
220
221 #ifndef SHMCON_NAME
222 #define SHMCON_NAME "AP-xnu"
223 #endif
224
225 #define SHMCON_MAGIC 'SHMC'
226 #define SHMCON_VERSION 2
227 #define CBUF_IN 0
228 #define CBUF_OUT 1
229 #define INBUF_SIZE (panic_size / 16)
230 #define FULL_ALIGNMENT (64)
231
232 #define FLAG_CACHELINE_32 1
233 #define FLAG_CACHELINE_64 2
234
235 /* Defines to clarify the master/slave fields' use as circular buffer pointers */
236 #define head_in sidx[CBUF_IN]
237 #define tail_in midx[CBUF_IN]
238 #define head_out midx[CBUF_OUT]
239 #define tail_out sidx[CBUF_OUT]
240
241 /* TODO: get from device tree/target */
242 #define NUM_CHILDREN 5
243
244 #define WRAP_INCR(len, x) do{ (x)++; if((x) >= (len)) (x) = 0; } while(0)
245 #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
246
247 #define MAX(a,b) ((a) > (b) ? (a) : (b))
248 #define MIN(a,b) ((a) < (b) ? (a) : (b))
249
250 #define shmcon_barrier() do {__asm__ volatile("dmb ish" : : : "memory");} while(0)
251
252 struct shm_buffer_info {
253 uint64_t base;
254 uint32_t unused;
255 uint32_t magic;
256 };
257
258 struct shmcon_header {
259 uint32_t magic;
260 uint8_t version;
261 uint8_t children; /* number of child entries in child_ent */
262 uint16_t flags;
263 uint64_t buf_paddr[2]; /* Physical address for buffers (in, out) */
264 uint32_t buf_len[2];
265 uint8_t name[8];
266
267 /* Slave-modified data - invalidate before read */
268 uint32_t sidx[2] __attribute__((aligned (FULL_ALIGNMENT))); /* In head, out tail */
269
270 /* Master-modified data - clean after write */
271 uint32_t midx[2] __attribute__((aligned (FULL_ALIGNMENT))); /* In tail, out head */
272
273 uint64_t child[0]; /* Physical address of child header pointers */
274 };
275
276 static volatile struct shmcon_header *shmcon = NULL;
277 static volatile uint8_t *shmbuf[2];
278 #ifdef SHMCON_THROTTLED
279 static uint64_t grace = 0;
280 static uint64_t full_timeout = 0;
281 #endif
282
283 static void shmcon_set_baud_rate(__unused int unit, __unused uint32_t baud_rate)
284 {
285 return;
286 }
287
288 static int shmcon_tr0(void)
289 {
290 #ifdef SHMCON_THROTTLED
291 uint32_t head = shmcon->head_out;
292 uint32_t tail = shmcon->tail_out;
293 uint32_t len = shmcon->buf_len[CBUF_OUT];
294
295 WRAP_INCR(len, head);
296 if (head != tail) {
297 full_timeout = 0;
298 return 1;
299 }
300
301 /* Full. Is this buffer being serviced? */
302 if (full_timeout == 0) {
303 full_timeout = mach_absolute_time() + grace;
304 return 0;
305 }
306 if (full_timeout > mach_absolute_time())
307 return 0;
308
309 /* Timeout - slave not really there or not keeping up */
310 tail += (len / 4);
311 if (tail >= len)
312 tail -= len;
313 shmcon_barrier();
314 shmcon->tail_out = tail;
315 full_timeout = 0;
316 #endif
317 return 1;
318 }
319
320 static void shmcon_td0(int c)
321 {
322 uint32_t head = shmcon->head_out;
323 uint32_t len = shmcon->buf_len[CBUF_OUT];
324
325 shmbuf[CBUF_OUT][head] = (uint8_t)c;
326 WRAP_INCR(len, head);
327 shmcon_barrier();
328 shmcon->head_out = head;
329 }
330
331 static int shmcon_rr0(void)
332 {
333 if (shmcon->tail_in == shmcon->head_in)
334 return 0;
335 return 1;
336 }
337
338 static int shmcon_rd0(void)
339 {
340 int c;
341 uint32_t tail = shmcon->tail_in;
342 uint32_t len = shmcon->buf_len[CBUF_IN];
343
344 c = shmbuf[CBUF_IN][tail];
345 WRAP_INCR(len, tail);
346 shmcon_barrier();
347 shmcon->tail_in = tail;
348 return c;
349 }
350
351 static void shmcon_init(void)
352 {
353 DTEntry entry;
354 uintptr_t *reg_prop;
355 volatile struct shm_buffer_info *end;
356 size_t i, header_size;
357 unsigned int size;
358 vm_offset_t pa_panic_base, panic_size, va_buffer_base, va_buffer_end;
359
360 if (kSuccess != DTLookupEntry(0, "pram", &entry))
361 return;
362
363 if (kSuccess != DTGetProperty(entry, "reg", (void **)&reg_prop, &size))
364 return;
365
366 pa_panic_base = reg_prop[0];
367 panic_size = reg_prop[1];
368
369 shmcon = (struct shmcon_header *)ml_map_high_window(pa_panic_base, panic_size);
370 header_size = sizeof(*shmcon) + (NUM_CHILDREN * sizeof(shmcon->child[0]));
371 va_buffer_base = ROUNDUP((uintptr_t)(shmcon) + header_size, CPU_CACHELINE_SIZE);
372 va_buffer_end = (uintptr_t)shmcon + panic_size - (sizeof(*end));
373
374 if ((shmcon->magic == SHMCON_MAGIC) && (shmcon->version == SHMCON_VERSION)) {
375 vm_offset_t pa_buffer_base, pa_buffer_end;
376
377 pa_buffer_base = ml_vtophys(va_buffer_base);
378 pa_buffer_end = ml_vtophys(va_buffer_end);
379
380 /* Resume previous console session */
381 for (i = 0; i < 2; i++) {
382 vm_offset_t pa_buf;
383 uint32_t len;
384
385 pa_buf = (uintptr_t)shmcon->buf_paddr[i];
386 len = shmcon->buf_len[i];
387 /* Validate buffers */
388 if ((pa_buf < pa_buffer_base) ||
389 (pa_buf >= pa_buffer_end) ||
390 ((pa_buf + len) > pa_buffer_end) ||
391 (shmcon->midx[i] >= len) || /* Index out of bounds */
392 (shmcon->sidx[i] >= len) ||
393 (pa_buf != ROUNDUP(pa_buf, CPU_CACHELINE_SIZE)) || /* Unaligned pa_buffer */
394 (len < 1024) ||
395 (len > (pa_buffer_end - pa_buffer_base)) ||
396 (shmcon->children != NUM_CHILDREN))
397 goto validation_failure;
398 /* Compute the VA offset of the buffer */
399 shmbuf[i] = (uint8_t *)(uintptr_t)shmcon + ((uintptr_t)pa_buf - (uintptr_t)pa_panic_base);
400 }
401 /* Check that buffers don't overlap */
402 if ((uintptr_t)shmbuf[0] < (uintptr_t)shmbuf[1]) {
403 if ((uintptr_t)(shmbuf[0] + shmcon->buf_len[0]) > (uintptr_t)shmbuf[1])
404 goto validation_failure;
405 } else {
406 if ((uintptr_t)(shmbuf[1] + shmcon->buf_len[1]) > (uintptr_t)shmbuf[0])
407 goto validation_failure;
408 }
409 shmcon->tail_in = shmcon->head_in; /* Clear input buffer */
410 shmcon_barrier();
411 } else {
412 validation_failure:
413 shmcon->magic = 0;
414 shmcon_barrier();
415 shmcon->buf_len[CBUF_IN] = (uint32_t)INBUF_SIZE;
416 shmbuf[CBUF_IN] = (uint8_t *)va_buffer_base;
417 shmbuf[CBUF_OUT] = (uint8_t *)ROUNDUP(va_buffer_base + INBUF_SIZE, CPU_CACHELINE_SIZE);
418 for (i = 0; i < 2; i++) {
419 shmcon->midx[i] = 0;
420 shmcon->sidx[i] = 0;
421 shmcon->buf_paddr[i] = (uintptr_t)ml_vtophys((vm_offset_t)shmbuf[i]);
422 }
423 shmcon->buf_len[CBUF_OUT] = (uint32_t)(va_buffer_end - (uintptr_t)shmbuf[CBUF_OUT]);
424 shmcon->version = SHMCON_VERSION;
425 #pragma clang diagnostic push
426 #pragma clang diagnostic ignored "-Wcast-qual"
427 memset((void *)shmcon->name, ' ', sizeof(shmcon->name));
428 memcpy((void *)shmcon->name, SHMCON_NAME, MIN(sizeof(shmcon->name), strlen(SHMCON_NAME)));
429 #pragma clang diagnostic pop
430 for (i = 0; i < NUM_CHILDREN; i++)
431 shmcon->child[0] = 0;
432 shmcon_barrier();
433 shmcon->magic = SHMCON_MAGIC;
434 }
435 end = (volatile struct shm_buffer_info *)va_buffer_end;
436 end->base = pa_panic_base;
437 end->unused = 0;
438 shmcon_barrier();
439 end->magic = SHMCON_MAGIC;
440 #ifdef SHMCON_THROTTLED
441 grace = gPEClockFrequencyInfo.timebase_frequency_hz;
442 #endif
443
444 PE_consistent_debug_register(kDbgIdConsoleHeaderAP, pa_panic_base, panic_size);
445 }
446
447 static struct pe_serial_functions shmcon_serial_functions =
448 {
449 .uart_init = shmcon_init,
450 .uart_set_baud_rate = shmcon_set_baud_rate,
451 .tr0 = shmcon_tr0,
452 .td0 = shmcon_td0,
453 .rr0 = shmcon_rr0,
454 .rd0 = shmcon_rd0
455 };
456
457 int pe_shmcon_set_child(uint64_t paddr, uint32_t entry)
458 {
459 if (shmcon == NULL)
460 return -1;
461
462 if (shmcon->children >= entry)
463 return -1;
464
465 shmcon->child[entry] = paddr;
466 return 0;
467 }
468
469 #endif /* SHMCON */
470
471 /*****************************************************************************/
472
473 #ifdef DOCKFIFO_UART
474
475
476 // Allow a 30ms stall of wall clock time before DockFIFO starts dropping characters
477 #define DOCKFIFO_WR_MAX_STALL_US (30*1000)
478
479 static uint64_t prev_dockfifo_drained_time; // Last time we've seen the DockFIFO drained by an external agent
480 static uint64_t prev_dockfifo_spaces; // Previous w_stat level of the DockFIFO.
481 static uint32_t dockfifo_capacity;
482 static uint64_t dockfifo_stall_grace;
483
484
485 //=======================
486 // Local funtions
487 //=======================
488
489 static int dockfifo_drain_on_stall()
490 {
491 // Called when DockFIFO runs out of spaces.
492 // Check if the DockFIFO reader has stalled. If so, empty the DockFIFO ourselves.
493 // Return number of bytes drained.
494
495 if (mach_absolute_time() - prev_dockfifo_drained_time >= dockfifo_stall_grace) {
496 // It's been more than DOCKFIFO_WR_MAX_STALL_US and nobody read from the FIFO
497 // Drop a character.
498 (void)rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 1);
499 prev_dockfifo_spaces++;
500 return 1;
501 }
502 return 0;
503 }
504
505
506 static int dockfifo_uart_tr0(void)
507 {
508 uint32_t spaces = rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE) & 0xffff;
509 if (spaces >= dockfifo_capacity || spaces > prev_dockfifo_spaces) {
510 // More spaces showed up. That can only mean someone read the FIFO.
511 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
512 // we can only give them the benefit of the doubt.
513
514 prev_dockfifo_drained_time = mach_absolute_time();
515 }
516 prev_dockfifo_spaces = spaces;
517
518 return spaces || dockfifo_drain_on_stall();
519
520 }
521
522 static void dockfifo_uart_td0(int c)
523 {
524 rDOCKFIFO_W_DATA(DOCKFIFO_UART_WRITE, 1) = (unsigned)(c & 0xff);
525 prev_dockfifo_spaces--; // After writing a byte we have one fewer space than previously expected.
526
527 }
528
529 static int dockfifo_uart_rr0(void)
530 {
531 return rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 0) & 0x7f;
532 }
533
534 static int dockfifo_uart_rd0(void)
535 {
536 return (int)((rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 1) >> 8) & 0xff);
537 }
538
539 static void dockfifo_uart_init(void)
540 {
541 nanoseconds_to_absolutetime(DOCKFIFO_WR_MAX_STALL_US * 1000, &dockfifo_stall_grace);
542
543 // Disable autodraining of the FIFO. We now purely manage it in software.
544 rDOCKFIFO_DRAIN(DOCKFIFO_UART_WRITE) = 0;
545
546 // Empty the DockFIFO by draining it until OCCUPANCY is 0, then measure its capacity
547 while (rDOCKFIFO_R_DATA(DOCKFIFO_UART_WRITE, 3) & 0x7F);
548 dockfifo_capacity = rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE) & 0xffff;
549 }
550
551 static struct pe_serial_functions dockfifo_uart_serial_functions =
552 {
553 .uart_init = dockfifo_uart_init,
554 .uart_set_baud_rate = NULL,
555 .tr0 = dockfifo_uart_tr0,
556 .td0 = dockfifo_uart_td0,
557 .rr0 = dockfifo_uart_rr0,
558 .rd0 = dockfifo_uart_rd0
559 };
560
561 #endif /* DOCKFIFO_UART */
562
563 /*****************************************************************************/
564
565 #ifdef DOCKCHANNEL_UART
566 #define DOCKCHANNEL_WR_MAX_STALL_US (30*1000)
567
568 static vm_offset_t dock_agent_base;
569 static uint32_t max_dockchannel_drain_period;
570 static bool use_sw_drain;
571 static uint64_t prev_dockchannel_drained_time; // Last time we've seen the DockChannel drained by an external agent
572 static uint64_t prev_dockchannel_spaces; // Previous w_stat level of the DockChannel.
573 static uint64_t dockchannel_stall_grace;
574
575 //=======================
576 // Local funtions
577 //=======================
578
579 static int dockchannel_drain_on_stall()
580 {
581 // Called when DockChannel runs out of spaces.
582 // Check if the DockChannel reader has stalled. If so, empty the DockChannel ourselves.
583 // Return number of bytes drained.
584
585 if ((mach_absolute_time() - prev_dockchannel_drained_time) >= dockchannel_stall_grace) {
586 // It's been more than DOCKCHANEL_WR_MAX_STALL_US and nobody read from the FIFO
587 // Drop a character.
588 (void)rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL);
589 prev_dockchannel_spaces++;
590 return 1;
591 }
592 return 0;
593 }
594
595 static int dockchannel_uart_tr0(void)
596 {
597 if (use_sw_drain) {
598 uint32_t spaces = rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL) & 0x1ff;
599 if (spaces > prev_dockchannel_spaces) {
600 // More spaces showed up. That can only mean someone read the FIFO.
601 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
602 // we can only give them the benefit of the doubt.
603 prev_dockchannel_drained_time = mach_absolute_time();
604 }
605 prev_dockchannel_spaces = spaces;
606
607 return spaces || dockchannel_drain_on_stall();
608 } else {
609 // Returns spaces in dockchannel fifo
610 return (rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL) & 0x1ff);
611 }
612 }
613
614 static void dockchannel_uart_td0(int c)
615 {
616 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL) = (unsigned)(c & 0xff);
617 if (use_sw_drain) {
618 prev_dockchannel_spaces--; // After writing a byte we have one fewer space than previously expected.
619 }
620 }
621
622 static int dockchannel_uart_rr0(void)
623 {
624 return rDOCKCHANNELS_DEV_RDATA0(DOCKCHANNEL_UART_CHANNEL) & 0x7f;
625 }
626
627 static int dockchannel_uart_rd0(void)
628 {
629 return (int)((rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL)>> 8) & 0xff);
630 }
631
632 static void dockchannel_uart_init(void)
633 {
634 if (use_sw_drain) {
635 nanoseconds_to_absolutetime(DOCKCHANNEL_WR_MAX_STALL_US * NSEC_PER_USEC, &dockchannel_stall_grace);
636 }
637
638 // Clear all interrupt enable and status bits
639 rDOCKCHANNELS_AGENT_AP_INTR_CTRL &= ~(0x3);
640 rDOCKCHANNELS_AGENT_AP_INTR_STATUS |= 0x3;
641 rDOCKCHANNELS_AGENT_AP_ERR_INTR_CTRL &= ~(0x3);
642 rDOCKCHANNELS_AGENT_AP_ERR_INTR_STATUS |= 0x3;
643
644 // Setup DRAIN timer
645 rDOCKCHANNELS_DEV_DRAIN_CFG(DOCKCHANNEL_UART_CHANNEL) = max_dockchannel_drain_period;
646
647 // Drain timer doesn't get loaded with value from drain period register if fifo
648 // is already full. Drop a character from the fifo.
649 rDOCKCHANNELS_DOCK_RDATA1(DOCKCHANNEL_UART_CHANNEL);
650 }
651
652 static struct pe_serial_functions dockchannel_uart_serial_functions =
653 {
654 .uart_init = dockchannel_uart_init,
655 .uart_set_baud_rate = NULL,
656 .tr0 = dockchannel_uart_tr0,
657 .td0 = dockchannel_uart_td0,
658 .rr0 = dockchannel_uart_rr0,
659 .rd0 = dockchannel_uart_rd0
660 };
661
662 #endif /* DOCKCHANNEL_UART */
663
664 /****************************************************************************/
665 #ifdef PI3_UART
666 vm_offset_t pi3_gpio_base_vaddr;
667 vm_offset_t pi3_aux_base_vaddr;
668 static int pi3_uart_tr0(void)
669 {
670 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V) & 0x20;
671 }
672
673 static void pi3_uart_td0(int c)
674 {
675 BCM2837_PUT32(BCM2837_AUX_MU_IO_REG_V, (uint32_t) c);
676 }
677
678 static int pi3_uart_rr0(void)
679 {
680 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V) & 0x01;
681 }
682
683 static int pi3_uart_rd0(void)
684 {
685 return (int) BCM2837_GET32(BCM2837_AUX_MU_IO_REG_V) & 0xff;
686 }
687
688 static void pi3_uart_init(void)
689 {
690 // Scratch variable
691 uint32_t i;
692
693 // Reset mini uart registers
694 BCM2837_PUT32(BCM2837_AUX_ENABLES_V, 1);
695 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V, 0);
696 BCM2837_PUT32(BCM2837_AUX_MU_LCR_REG_V, 3);
697 BCM2837_PUT32(BCM2837_AUX_MU_MCR_REG_V, 0);
698 BCM2837_PUT32(BCM2837_AUX_MU_IER_REG_V, 0);
699 BCM2837_PUT32(BCM2837_AUX_MU_IIR_REG_V, 0xC6);
700 BCM2837_PUT32(BCM2837_AUX_MU_BAUD_REG_V, 270);
701
702 i = BCM2837_FSEL_REG(14);
703 // Configure GPIOs 14 & 15 for alternate function 5
704 i &= ~(BCM2837_FSEL_MASK(14));
705 i |= (BCM2837_FSEL_ALT5 << BCM2837_FSEL_OFFS(14));
706 i &= ~(BCM2837_FSEL_MASK(15));
707 i |= (BCM2837_FSEL_ALT5 << BCM2837_FSEL_OFFS(15));
708
709 BCM2837_PUT32(BCM2837_FSEL_REG(14), i);
710
711 BCM2837_PUT32(BCM2837_GPPUD_V, 0);
712
713 // Barrier before AP spinning for 150 cycles
714 __builtin_arm_isb(ISB_SY);
715
716 for(i = 0; i < 150; i++) {
717 asm volatile("add x0, x0, xzr");
718 }
719
720 __builtin_arm_isb(ISB_SY);
721
722 BCM2837_PUT32(BCM2837_GPPUDCLK0_V,(1 << 14) | (1 << 15));
723
724 __builtin_arm_isb(ISB_SY);
725
726 for(i = 0; i < 150; i++) {
727 asm volatile("add x0, x0, xzr");
728 }
729
730 __builtin_arm_isb(ISB_SY);
731
732 BCM2837_PUT32(BCM2837_GPPUDCLK0_V, 0);
733
734 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V, 3);
735 }
736
737 static struct pe_serial_functions pi3_uart_serial_functions =
738 {
739 .uart_init = pi3_uart_init,
740 .uart_set_baud_rate = NULL,
741 .tr0 = pi3_uart_tr0,
742 .td0 = pi3_uart_td0,
743 .rr0 = pi3_uart_rr0,
744 .rd0 = pi3_uart_rd0
745 };
746
747 #endif /* PI3_UART */
748 /*****************************************************************************/
749 int
750 serial_init(void)
751 {
752 DTEntry entryP = NULL;
753 uint32_t prop_size, dccmode;
754 vm_offset_t soc_base;
755 uintptr_t *reg_prop;
756 uint32_t *prop_value = NULL;
757 char *serial_compat = 0;
758 #ifdef SHMCON
759 uint32_t jconmode;
760 #endif
761 #ifdef DOCKFIFO_UART
762 uint32_t no_dockfifo_uart;
763 #endif
764 #ifdef DOCKCHANNEL_UART
765 uint32_t no_dockchannel_uart;
766 #endif
767 #ifdef PI3_UART
768 uint32_t is_pi3;
769 #endif
770
771 if (uart_initted && gPESF) {
772 gPESF->uart_init();
773 kprintf("reinit serial\n");
774 return 1;
775 }
776
777 dccmode = 0;
778 if (PE_parse_boot_argn("dcc", &dccmode, sizeof (dccmode))) {
779 gPESF = &dcc_serial_functions;
780 uart_initted = 1;
781 return 1;
782 }
783 #ifdef SHMCON
784 jconmode = 0;
785 if (PE_parse_boot_argn("jcon", &jconmode, sizeof jconmode)) {
786 gPESF = &shmcon_serial_functions;
787 gPESF->uart_init();
788 uart_initted = 1;
789 return 1;
790 }
791 #endif /* SHMCON */
792
793 #ifdef PI3_UART
794 #pragma unused(prop_value)
795 is_pi3 = 0;
796 if (PE_parse_boot_argn("-pi3", &is_pi3, sizeof(is_pi3))) { // FIXME: remove the not operator after boot args are set up.
797 pi3_gpio_base_vaddr = ml_io_map((vm_offset_t)BCM2837_GPIO_BASE, BCM2837_GPIO_SIZE);
798 pi3_aux_base_vaddr = ml_io_map((vm_offset_t)BCM2837_AUX_BASE, BCM2837_AUX_SIZE);
799 gPESF = &pi3_uart_serial_functions;
800 gPESF->uart_init();
801 uart_initted = 1;
802 return 1;
803 }
804 #endif /* PI3_UART */
805
806 soc_base = pe_arm_get_soc_base_phys();
807
808 if (soc_base == 0)
809 return 0;
810
811 #ifdef DOCKFIFO_UART
812 no_dockfifo_uart = 0;
813 PE_parse_boot_argn("no-dockfifo-uart", &no_dockfifo_uart, sizeof(no_dockfifo_uart));
814 if (no_dockfifo_uart == 0) {
815 if (DTFindEntry("name", "dockfifo-uart", &entryP) == kSuccess) {
816 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
817 uart_base = ml_io_map(soc_base + *reg_prop, *(reg_prop + 1));
818 }
819 else {
820 return 0;
821 }
822 gPESF = &dockfifo_uart_serial_functions;
823 gPESF->uart_init();
824 uart_initted = 1;
825 return 1;
826 }
827 #endif /* DOCKFIFO_UART */
828
829 #ifdef DOCKCHANNEL_UART
830 no_dockchannel_uart = 0;
831 // Keep the old name for boot-arg
832 PE_parse_boot_argn("no-dockfifo-uart", &no_dockchannel_uart, sizeof(no_dockchannel_uart));
833 if (no_dockchannel_uart == 0) {
834 if (DTFindEntry("name", "dockchannel-uart", &entryP) == kSuccess) {
835 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
836 // Should be two reg entries
837 if (prop_size/sizeof(uintptr_t) != 4)
838 panic("Malformed dockchannel-uart property");
839 uart_base = ml_io_map(soc_base + *reg_prop, *(reg_prop + 1));
840 dock_agent_base = ml_io_map(soc_base + *(reg_prop + 2), *(reg_prop + 3));
841 gPESF = &dockchannel_uart_serial_functions;
842 DTGetProperty(entryP, "max-aop-clk", (void **)&prop_value, &prop_size);
843 max_dockchannel_drain_period = (uint32_t)((prop_value)? (*prop_value * 0.03) : DOCKCHANNEL_DRAIN_PERIOD);
844 DTGetProperty(entryP, "enable-sw-drain", (void **)&prop_value, &prop_size);
845 use_sw_drain = (prop_value)? *prop_value : 0;
846 gPESF->uart_init();
847 uart_initted = 1;
848 return 1;
849 }
850 // If no dockchannel-uart is found in the device tree, fall back
851 // to looking for the traditional UART serial console.
852 }
853 #endif /* DOCKCHANNEL_UART */
854
855 /*
856 * The boot serial port should have a property named "boot-console".
857 * If we don't find it there, look for "uart0" and "uart1".
858 */
859
860 if (DTFindEntry("boot-console", NULL, &entryP) == kSuccess) {
861 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
862 uart_base = ml_io_map(soc_base + *reg_prop, *(reg_prop + 1));
863 if (serial_compat == 0)
864 DTGetProperty(entryP, "compatible", (void **)&serial_compat, &prop_size);
865 } else if (DTFindEntry("name", "uart0", &entryP) == kSuccess) {
866 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
867 uart_base = ml_io_map(soc_base + *reg_prop, *(reg_prop + 1));
868 if (serial_compat == 0)
869 DTGetProperty(entryP, "compatible", (void **)&serial_compat, &prop_size);
870 } else if (DTFindEntry("name", "uart1", &entryP) == kSuccess) {
871 DTGetProperty(entryP, "reg", (void **)&reg_prop, &prop_size);
872 uart_base = ml_io_map(soc_base + *reg_prop, *(reg_prop + 1));
873 if (serial_compat == 0)
874 DTGetProperty(entryP, "compatible", (void **)&serial_compat, &prop_size);
875 }
876 #ifdef S3CUART
877 if (NULL != entryP) {
878 DTGetProperty(entryP, "pclk", (void **)&prop_value, &prop_size);
879 if (prop_value) dt_pclk = *prop_value;
880
881 prop_value = NULL;
882 DTGetProperty(entryP, "sampling", (void **)&prop_value, &prop_size);
883 if (prop_value) dt_sampling = *prop_value;
884
885 prop_value = NULL;
886 DTGetProperty(entryP, "ubrdiv", (void **)&prop_value, &prop_size);
887 if (prop_value) dt_ubrdiv = *prop_value;
888 }
889 if (!strcmp(serial_compat, "uart,16550"))
890 gPESF = &ln2410_serial_functions;
891 else if (!strcmp(serial_compat, "uart-16550"))
892 gPESF = &ln2410_serial_functions;
893 else if (!strcmp(serial_compat, "uart,s5i3000"))
894 gPESF = &ln2410_serial_functions;
895 else if (!strcmp(serial_compat, "uart-1,samsung"))
896 gPESF = &ln2410_serial_functions;
897 #elif defined (ARM_BOARD_CONFIG_MV88F6710)
898 if (!strcmp(serial_compat, "uart16x50,mmio"))
899 gPESF = &uart16x50_serial_functions;
900 #endif
901 else
902 return 0;
903
904 gPESF->uart_init();
905
906 uart_initted = 1;
907
908 return 1;
909 }
910
911 void
912 uart_putc(char c)
913 {
914 if (uart_initted) {
915 while (!gPESF->tr0()); /* Wait until THR is empty. */
916 gPESF->td0(c);
917 }
918 }
919
920 int
921 uart_getc(void)
922 { /* returns -1 if no data available */
923 if (uart_initted) {
924 if (!gPESF->rr0())
925 return -1; /* Receive data read */
926 return gPESF->rd0();
927 }
928 return -1;
929 }