2 * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
6 * file: pe_serial.c Polled-mode UART0 driver for S3c2410 and PL011.
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>
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>
25 #elif defined __arm64__
26 #include <pexpert/arm/consistent_debug.h>
27 #include <pexpert/arm64/board_config.h>
28 #include <arm64/proc_reg.h>
31 struct pe_serial_functions
{
32 void (*uart_init
) (void);
33 void (*uart_set_baud_rate
) (int unit
, uint32_t baud_rate
);
40 static struct pe_serial_functions
*gPESF
;
42 static int uart_initted
= 0; /* 1 if init'ed */
44 static vm_offset_t uart_base
;
46 /*****************************************************************************/
50 static int32_t dt_pclk
= -1;
51 static int32_t dt_sampling
= -1;
52 static int32_t dt_ubrdiv
= -1;
55 ln2410_uart_init(void)
57 uint32_t ucon0
= 0x405; /* NCLK, No interrupts, No DMA - just polled */
59 rULCON0
= 0x03; /* 81N, not IR */
61 // Override with pclk dt entry
63 ucon0
= ucon0
& ~0x400;
66 rUMCON0
= 0x00; /* Clear Flow Control */
68 gPESF
->uart_set_baud_rate(0, 115200);
70 rUFCON0
= 0x03; /* Clear & Enable FIFOs */
71 rUMCON0
= 0x01; /* Assert RTS on UART0 */
75 ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
)
78 uint32_t uart_clock
= 0;
79 uint32_t sample_rate
= 16;
86 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.fix_frequency_hz
;
89 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.prf_frequency_hz
;
91 if (dt_sampling
!= -1) {
92 // Use the sampling rate specified in the Device Tree
93 sample_rate
= dt_sampling
& 0xf;
96 if (dt_ubrdiv
!= -1) {
97 // Use the ubrdiv specified in the Device Tree
98 div
= dt_ubrdiv
& 0xffff;
100 // Calculate ubrdiv. UBRDIV = (SourceClock / (BPS * Sample Rate)) - 1
101 div
= uart_clock
/ (baud_rate
* sample_rate
);
103 uint32_t actual_baud
= uart_clock
/ ((div
+ 0) * sample_rate
);
104 uint32_t baud_low
= uart_clock
/ ((div
+ 1) * sample_rate
);
106 // Adjust div to get the closest target baudrate
107 if ((baud_rate
- baud_low
) > (actual_baud
- baud_rate
))
111 // Sample Rate [19:16], UBRDIV [15:0]
112 rUBRDIV0
= ((16 - sample_rate
) << 16) | div
;
118 return rUTRSTAT0
& 0x04;
123 rUTXH0
= (unsigned)(c
& 0xff);
128 return rUTRSTAT0
& 0x01;
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
};
142 /*****************************************************************************/
151 "mrc p14, 0, %0, c0, c5\n"
156 panic_unimplemented();
161 write_dtr(unsigned int c
)
165 "mcr p14, 0, %0, c0, c5\n"
171 panic_unimplemented();
179 return !(arm_debug_read_dscr() & ARM_DBGDSCR_TXFULL
);
182 panic_unimplemented();
197 return arm_debug_read_dscr() & ARM_DBGDSCR_RXFULL
;
200 panic_unimplemented();
211 static struct pe_serial_functions dcc_serial_functions
= {
213 dcc_tr0
, dcc_td0
, dcc_rr0
, dcc_rd0
};
215 /*****************************************************************************/
219 #define CPU_CACHELINE_SIZE (1 << MMU_CLINE)
222 #define SHMCON_NAME "AP-xnu"
225 #define SHMCON_MAGIC 'SHMC'
226 #define SHMCON_VERSION 2
229 #define INBUF_SIZE (panic_size / 16)
230 #define FULL_ALIGNMENT (64)
232 #define FLAG_CACHELINE_32 1
233 #define FLAG_CACHELINE_64 2
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]
241 /* TODO: get from device tree/target */
242 #define NUM_CHILDREN 5
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)))
247 #define MAX(a,b) ((a) > (b) ? (a) : (b))
248 #define MIN(a,b) ((a) < (b) ? (a) : (b))
250 #define shmcon_barrier() do {__asm__ volatile("dmb ish" : : : "memory");} while(0)
252 struct shm_buffer_info
{
258 struct shmcon_header
{
261 uint8_t children
; /* number of child entries in child_ent */
263 uint64_t buf_paddr
[2]; /* Physical address for buffers (in, out) */
267 /* Slave-modified data - invalidate before read */
268 uint32_t sidx
[2] __attribute__((aligned (FULL_ALIGNMENT
))); /* In head, out tail */
270 /* Master-modified data - clean after write */
271 uint32_t midx
[2] __attribute__((aligned (FULL_ALIGNMENT
))); /* In tail, out head */
273 uint64_t child
[0]; /* Physical address of child header pointers */
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;
283 static void shmcon_set_baud_rate(__unused
int unit
, __unused
uint32_t baud_rate
)
288 static int shmcon_tr0(void)
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
];
295 WRAP_INCR(len
, head
);
301 /* Full. Is this buffer being serviced? */
302 if (full_timeout
== 0) {
303 full_timeout
= mach_absolute_time() + grace
;
306 if (full_timeout
> mach_absolute_time())
309 /* Timeout - slave not really there or not keeping up */
314 shmcon
->tail_out
= tail
;
320 static void shmcon_td0(int c
)
322 uint32_t head
= shmcon
->head_out
;
323 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
325 shmbuf
[CBUF_OUT
][head
] = (uint8_t)c
;
326 WRAP_INCR(len
, head
);
328 shmcon
->head_out
= head
;
331 static int shmcon_rr0(void)
333 if (shmcon
->tail_in
== shmcon
->head_in
)
338 static int shmcon_rd0(void)
341 uint32_t tail
= shmcon
->tail_in
;
342 uint32_t len
= shmcon
->buf_len
[CBUF_IN
];
344 c
= shmbuf
[CBUF_IN
][tail
];
345 WRAP_INCR(len
, tail
);
347 shmcon
->tail_in
= tail
;
351 static void shmcon_init(void)
355 volatile struct shm_buffer_info
*end
;
356 size_t i
, header_size
;
358 vm_offset_t pa_panic_base
, panic_size
, va_buffer_base
, va_buffer_end
;
360 if (kSuccess
!= DTLookupEntry(0, "pram", &entry
))
363 if (kSuccess
!= DTGetProperty(entry
, "reg", (void **)®_prop
, &size
))
366 pa_panic_base
= reg_prop
[0];
367 panic_size
= reg_prop
[1];
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
));
374 if ((shmcon
->magic
== SHMCON_MAGIC
) && (shmcon
->version
== SHMCON_VERSION
)) {
375 vm_offset_t pa_buffer_base
, pa_buffer_end
;
377 pa_buffer_base
= ml_vtophys(va_buffer_base
);
378 pa_buffer_end
= ml_vtophys(va_buffer_end
);
380 /* Resume previous console session */
381 for (i
= 0; i
< 2; i
++) {
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 */
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
);
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
;
406 if ((uintptr_t)(shmbuf
[1] + shmcon
->buf_len
[1]) > (uintptr_t)shmbuf
[0])
407 goto validation_failure
;
409 shmcon
->tail_in
= shmcon
->head_in
; /* Clear input buffer */
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
++) {
421 shmcon
->buf_paddr
[i
] = (uintptr_t)ml_vtophys((vm_offset_t
)shmbuf
[i
]);
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;
433 shmcon
->magic
= SHMCON_MAGIC
;
435 end
= (volatile struct shm_buffer_info
*)va_buffer_end
;
436 end
->base
= pa_panic_base
;
439 end
->magic
= SHMCON_MAGIC
;
440 #ifdef SHMCON_THROTTLED
441 grace
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
444 PE_consistent_debug_register(kDbgIdConsoleHeaderAP
, pa_panic_base
, panic_size
);
447 static struct pe_serial_functions shmcon_serial_functions
=
449 .uart_init
= shmcon_init
,
450 .uart_set_baud_rate
= shmcon_set_baud_rate
,
457 int pe_shmcon_set_child(uint64_t paddr
, uint32_t entry
)
462 if (shmcon
->children
>= entry
)
465 shmcon
->child
[entry
] = paddr
;
471 /*****************************************************************************/
476 // Allow a 30ms stall of wall clock time before DockFIFO starts dropping characters
477 #define DOCKFIFO_WR_MAX_STALL_US (30*1000)
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
;
485 //=======================
487 //=======================
489 static int dockfifo_drain_on_stall()
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.
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
498 (void)rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1);
499 prev_dockfifo_spaces
++;
506 static int dockfifo_uart_tr0(void)
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.
514 prev_dockfifo_drained_time
= mach_absolute_time();
516 prev_dockfifo_spaces
= spaces
;
518 return spaces
|| dockfifo_drain_on_stall();
522 static void dockfifo_uart_td0(int c
)
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.
529 static int dockfifo_uart_rr0(void)
531 return rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 0) & 0x7f;
534 static int dockfifo_uart_rd0(void)
536 return (int)((rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1) >> 8) & 0xff);
539 static void dockfifo_uart_init(void)
541 nanoseconds_to_absolutetime(DOCKFIFO_WR_MAX_STALL_US
* 1000, &dockfifo_stall_grace
);
543 // Disable autodraining of the FIFO. We now purely manage it in software.
544 rDOCKFIFO_DRAIN(DOCKFIFO_UART_WRITE
) = 0;
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;
551 static struct pe_serial_functions dockfifo_uart_serial_functions
=
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
561 #endif /* DOCKFIFO_UART */
563 /*****************************************************************************/
565 #ifdef DOCKCHANNEL_UART
566 #define DOCKCHANNEL_WR_MAX_STALL_US (30*1000)
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
;
575 //=======================
577 //=======================
579 static int dockchannel_drain_on_stall()
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.
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
588 (void)rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
589 prev_dockchannel_spaces
++;
595 static int dockchannel_uart_tr0(void)
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();
605 prev_dockchannel_spaces
= spaces
;
607 return spaces
|| dockchannel_drain_on_stall();
609 // Returns spaces in dockchannel fifo
610 return (rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & 0x1ff);
614 static void dockchannel_uart_td0(int c
)
616 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL
) = (unsigned)(c
& 0xff);
618 prev_dockchannel_spaces
--; // After writing a byte we have one fewer space than previously expected.
622 static int dockchannel_uart_rr0(void)
624 return rDOCKCHANNELS_DEV_RDATA0(DOCKCHANNEL_UART_CHANNEL
) & 0x7f;
627 static int dockchannel_uart_rd0(void)
629 return (int)((rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
)>> 8) & 0xff);
632 static void dockchannel_uart_init(void)
635 nanoseconds_to_absolutetime(DOCKCHANNEL_WR_MAX_STALL_US
* NSEC_PER_USEC
, &dockchannel_stall_grace
);
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;
645 rDOCKCHANNELS_DEV_DRAIN_CFG(DOCKCHANNEL_UART_CHANNEL
) = max_dockchannel_drain_period
;
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
);
652 static struct pe_serial_functions dockchannel_uart_serial_functions
=
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
662 #endif /* DOCKCHANNEL_UART */
664 /****************************************************************************/
666 vm_offset_t pi3_gpio_base_vaddr
;
667 vm_offset_t pi3_aux_base_vaddr
;
668 static int pi3_uart_tr0(void)
670 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x20;
673 static void pi3_uart_td0(int c
)
675 BCM2837_PUT32(BCM2837_AUX_MU_IO_REG_V
, (uint32_t) c
);
678 static int pi3_uart_rr0(void)
680 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x01;
683 static int pi3_uart_rd0(void)
685 return (int) BCM2837_GET32(BCM2837_AUX_MU_IO_REG_V
) & 0xff;
688 static void pi3_uart_init(void)
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);
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));
709 BCM2837_PUT32(BCM2837_FSEL_REG(14), i
);
711 BCM2837_PUT32(BCM2837_GPPUD_V
, 0);
713 // Barrier before AP spinning for 150 cycles
714 __builtin_arm_isb(ISB_SY
);
716 for(i
= 0; i
< 150; i
++) {
717 asm volatile("add x0, x0, xzr");
720 __builtin_arm_isb(ISB_SY
);
722 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
,(1 << 14) | (1 << 15));
724 __builtin_arm_isb(ISB_SY
);
726 for(i
= 0; i
< 150; i
++) {
727 asm volatile("add x0, x0, xzr");
730 __builtin_arm_isb(ISB_SY
);
732 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, 0);
734 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 3);
737 static struct pe_serial_functions pi3_uart_serial_functions
=
739 .uart_init
= pi3_uart_init
,
740 .uart_set_baud_rate
= NULL
,
747 #endif /* PI3_UART */
748 /*****************************************************************************/
752 DTEntry entryP
= NULL
;
753 uint32_t prop_size
, dccmode
;
754 vm_offset_t soc_base
;
756 uint32_t *prop_value
= NULL
;
757 char *serial_compat
= 0;
762 uint32_t no_dockfifo_uart
;
764 #ifdef DOCKCHANNEL_UART
765 uint32_t no_dockchannel_uart
;
771 if (uart_initted
&& gPESF
) {
773 kprintf("reinit serial\n");
778 if (PE_parse_boot_argn("dcc", &dccmode
, sizeof (dccmode
))) {
779 gPESF
= &dcc_serial_functions
;
785 if (PE_parse_boot_argn("jcon", &jconmode
, sizeof jconmode
)) {
786 gPESF
= &shmcon_serial_functions
;
794 #pragma unused(prop_value)
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
;
804 #endif /* PI3_UART */
806 soc_base
= pe_arm_get_soc_base_phys();
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 **)®_prop
, &prop_size
);
817 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
822 gPESF
= &dockfifo_uart_serial_functions
;
827 #endif /* DOCKFIFO_UART */
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 **)®_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;
850 // If no dockchannel-uart is found in the device tree, fall back
851 // to looking for the traditional UART serial console.
853 #endif /* DOCKCHANNEL_UART */
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".
860 if (DTFindEntry("boot-console", NULL
, &entryP
) == kSuccess
) {
861 DTGetProperty(entryP
, "reg", (void **)®_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 **)®_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 **)®_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
);
877 if (NULL
!= entryP
) {
878 DTGetProperty(entryP
, "pclk", (void **)&prop_value
, &prop_size
);
879 if (prop_value
) dt_pclk
= *prop_value
;
882 DTGetProperty(entryP
, "sampling", (void **)&prop_value
, &prop_size
);
883 if (prop_value
) dt_sampling
= *prop_value
;
886 DTGetProperty(entryP
, "ubrdiv", (void **)&prop_value
, &prop_size
);
887 if (prop_value
) dt_ubrdiv
= *prop_value
;
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
;
915 while (!gPESF
->tr0()); /* Wait until THR is empty. */
922 { /* returns -1 if no data available */
925 return -1; /* Receive data read */