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;
67 rUMCON0
= 0x00; /* Clear Flow Control */
69 gPESF
->uart_set_baud_rate(0, 115200);
71 rUFCON0
= 0x03; /* Clear & Enable FIFOs */
72 rUMCON0
= 0x01; /* Assert RTS on UART0 */
76 ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
)
79 uint32_t uart_clock
= 0;
80 uint32_t sample_rate
= 16;
82 if (baud_rate
< 300) {
88 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.fix_frequency_hz
;
91 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.prf_frequency_hz
;
94 if (dt_sampling
!= -1) {
95 // Use the sampling rate specified in the Device Tree
96 sample_rate
= dt_sampling
& 0xf;
99 if (dt_ubrdiv
!= -1) {
100 // Use the ubrdiv specified in the Device Tree
101 div
= dt_ubrdiv
& 0xffff;
103 // Calculate ubrdiv. UBRDIV = (SourceClock / (BPS * Sample Rate)) - 1
104 div
= uart_clock
/ (baud_rate
* sample_rate
);
106 uint32_t actual_baud
= uart_clock
/ ((div
+ 0) * sample_rate
);
107 uint32_t baud_low
= uart_clock
/ ((div
+ 1) * sample_rate
);
109 // Adjust div to get the closest target baudrate
110 if ((baud_rate
- baud_low
) > (actual_baud
- baud_rate
)) {
115 // Sample Rate [19:16], UBRDIV [15:0]
116 rUBRDIV0
= ((16 - sample_rate
) << 16) | div
;
122 return rUTRSTAT0
& 0x04;
127 rUTXH0
= (unsigned)(c
& 0xff);
132 return rUTRSTAT0
& 0x01;
140 static struct pe_serial_functions ln2410_serial_functions
= {
141 ln2410_uart_init
, ln2410_uart_set_baud_rate
,
142 ln2410_tr0
, ln2410_td0
, ln2410_rr0
, ln2410_rd0
147 /*****************************************************************************/
156 "mrc p14, 0, %0, c0, c5\n"
161 panic_unimplemented();
166 write_dtr(unsigned int c
)
170 "mcr p14, 0, %0, c0, c5\n"
176 panic_unimplemented();
184 return !(arm_debug_read_dscr() & ARM_DBGDSCR_TXFULL
);
187 panic_unimplemented();
202 return arm_debug_read_dscr() & ARM_DBGDSCR_RXFULL
;
205 panic_unimplemented();
216 static struct pe_serial_functions dcc_serial_functions
= {
218 dcc_tr0
, dcc_td0
, dcc_rr0
, dcc_rd0
221 /*****************************************************************************/
225 #define CPU_CACHELINE_SIZE (1 << MMU_CLINE)
228 #define SHMCON_NAME "AP-xnu"
231 #define SHMCON_MAGIC 'SHMC'
232 #define SHMCON_VERSION 2
235 #define INBUF_SIZE (panic_size / 16)
236 #define FULL_ALIGNMENT (64)
238 #define FLAG_CACHELINE_32 1
239 #define FLAG_CACHELINE_64 2
241 /* Defines to clarify the master/slave fields' use as circular buffer pointers */
242 #define head_in sidx[CBUF_IN]
243 #define tail_in midx[CBUF_IN]
244 #define head_out midx[CBUF_OUT]
245 #define tail_out sidx[CBUF_OUT]
247 /* TODO: get from device tree/target */
248 #define NUM_CHILDREN 5
250 #define WRAP_INCR(len, x) do{ (x)++; if((x) >= (len)) (x) = 0; } while(0)
251 #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
253 #define MAX(a, b) ((a) > (b) ? (a) : (b))
254 #define MIN(a, b) ((a) < (b) ? (a) : (b))
256 #define shmcon_barrier() do {__asm__ volatile("dmb ish" : : : "memory");} while(0)
258 struct shm_buffer_info
{
264 struct shmcon_header
{
267 uint8_t children
; /* number of child entries in child_ent */
269 uint64_t buf_paddr
[2]; /* Physical address for buffers (in, out) */
273 /* Slave-modified data - invalidate before read */
274 uint32_t sidx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In head, out tail */
276 /* Master-modified data - clean after write */
277 uint32_t midx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In tail, out head */
279 uint64_t child
[0]; /* Physical address of child header pointers */
282 static volatile struct shmcon_header
*shmcon
= NULL
;
283 static volatile uint8_t *shmbuf
[2];
284 #ifdef SHMCON_THROTTLED
285 static uint64_t grace
= 0;
286 static uint64_t full_timeout
= 0;
290 shmcon_set_baud_rate(__unused
int unit
, __unused
uint32_t baud_rate
)
298 #ifdef SHMCON_THROTTLED
299 uint32_t head
= shmcon
->head_out
;
300 uint32_t tail
= shmcon
->tail_out
;
301 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
303 WRAP_INCR(len
, head
);
309 /* Full. Is this buffer being serviced? */
310 if (full_timeout
== 0) {
311 full_timeout
= mach_absolute_time() + grace
;
314 if (full_timeout
> mach_absolute_time()) {
318 /* Timeout - slave not really there or not keeping up */
324 shmcon
->tail_out
= tail
;
333 uint32_t head
= shmcon
->head_out
;
334 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
336 shmbuf
[CBUF_OUT
][head
] = (uint8_t)c
;
337 WRAP_INCR(len
, head
);
339 shmcon
->head_out
= head
;
345 if (shmcon
->tail_in
== shmcon
->head_in
) {
355 uint32_t tail
= shmcon
->tail_in
;
356 uint32_t len
= shmcon
->buf_len
[CBUF_IN
];
358 c
= shmbuf
[CBUF_IN
][tail
];
359 WRAP_INCR(len
, tail
);
361 shmcon
->tail_in
= tail
;
370 volatile struct shm_buffer_info
*end
;
371 size_t i
, header_size
;
373 vm_offset_t pa_panic_base
, panic_size
, va_buffer_base
, va_buffer_end
;
375 if (kSuccess
!= DTLookupEntry(0, "pram", &entry
)) {
379 if (kSuccess
!= DTGetProperty(entry
, "reg", (void **)®_prop
, &size
)) {
383 pa_panic_base
= reg_prop
[0];
384 panic_size
= reg_prop
[1];
386 shmcon
= (struct shmcon_header
*)ml_map_high_window(pa_panic_base
, panic_size
);
387 header_size
= sizeof(*shmcon
) + (NUM_CHILDREN
* sizeof(shmcon
->child
[0]));
388 va_buffer_base
= ROUNDUP((uintptr_t)(shmcon
) + header_size
, CPU_CACHELINE_SIZE
);
389 va_buffer_end
= (uintptr_t)shmcon
+ panic_size
- (sizeof(*end
));
391 if ((shmcon
->magic
== SHMCON_MAGIC
) && (shmcon
->version
== SHMCON_VERSION
)) {
392 vm_offset_t pa_buffer_base
, pa_buffer_end
;
394 pa_buffer_base
= ml_vtophys(va_buffer_base
);
395 pa_buffer_end
= ml_vtophys(va_buffer_end
);
397 /* Resume previous console session */
398 for (i
= 0; i
< 2; i
++) {
402 pa_buf
= (uintptr_t)shmcon
->buf_paddr
[i
];
403 len
= shmcon
->buf_len
[i
];
404 /* Validate buffers */
405 if ((pa_buf
< pa_buffer_base
) ||
406 (pa_buf
>= pa_buffer_end
) ||
407 ((pa_buf
+ len
) > pa_buffer_end
) ||
408 (shmcon
->midx
[i
] >= len
) || /* Index out of bounds */
409 (shmcon
->sidx
[i
] >= len
) ||
410 (pa_buf
!= ROUNDUP(pa_buf
, CPU_CACHELINE_SIZE
)) || /* Unaligned pa_buffer */
412 (len
> (pa_buffer_end
- pa_buffer_base
)) ||
413 (shmcon
->children
!= NUM_CHILDREN
)) {
414 goto validation_failure
;
416 /* Compute the VA offset of the buffer */
417 shmbuf
[i
] = (uint8_t *)(uintptr_t)shmcon
+ ((uintptr_t)pa_buf
- (uintptr_t)pa_panic_base
);
419 /* Check that buffers don't overlap */
420 if ((uintptr_t)shmbuf
[0] < (uintptr_t)shmbuf
[1]) {
421 if ((uintptr_t)(shmbuf
[0] + shmcon
->buf_len
[0]) > (uintptr_t)shmbuf
[1]) {
422 goto validation_failure
;
425 if ((uintptr_t)(shmbuf
[1] + shmcon
->buf_len
[1]) > (uintptr_t)shmbuf
[0]) {
426 goto validation_failure
;
429 shmcon
->tail_in
= shmcon
->head_in
; /* Clear input buffer */
435 shmcon
->buf_len
[CBUF_IN
] = (uint32_t)INBUF_SIZE
;
436 shmbuf
[CBUF_IN
] = (uint8_t *)va_buffer_base
;
437 shmbuf
[CBUF_OUT
] = (uint8_t *)ROUNDUP(va_buffer_base
+ INBUF_SIZE
, CPU_CACHELINE_SIZE
);
438 for (i
= 0; i
< 2; i
++) {
441 shmcon
->buf_paddr
[i
] = (uintptr_t)ml_vtophys((vm_offset_t
)shmbuf
[i
]);
443 shmcon
->buf_len
[CBUF_OUT
] = (uint32_t)(va_buffer_end
- (uintptr_t)shmbuf
[CBUF_OUT
]);
444 shmcon
->version
= SHMCON_VERSION
;
445 #pragma clang diagnostic push
446 #pragma clang diagnostic ignored "-Wcast-qual"
447 memset((void *)shmcon
->name
, ' ', sizeof(shmcon
->name
));
448 memcpy((void *)shmcon
->name
, SHMCON_NAME
, MIN(sizeof(shmcon
->name
), strlen(SHMCON_NAME
)));
449 #pragma clang diagnostic pop
450 for (i
= 0; i
< NUM_CHILDREN
; i
++) {
451 shmcon
->child
[0] = 0;
454 shmcon
->magic
= SHMCON_MAGIC
;
456 end
= (volatile struct shm_buffer_info
*)va_buffer_end
;
457 end
->base
= pa_panic_base
;
460 end
->magic
= SHMCON_MAGIC
;
461 #ifdef SHMCON_THROTTLED
462 grace
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
465 PE_consistent_debug_register(kDbgIdConsoleHeaderAP
, pa_panic_base
, panic_size
);
468 static struct pe_serial_functions shmcon_serial_functions
=
470 .uart_init
= shmcon_init
,
471 .uart_set_baud_rate
= shmcon_set_baud_rate
,
479 pe_shmcon_set_child(uint64_t paddr
, uint32_t entry
)
481 if (shmcon
== NULL
) {
485 if (shmcon
->children
>= entry
) {
489 shmcon
->child
[entry
] = paddr
;
495 /*****************************************************************************/
500 // Allow a 30ms stall of wall clock time before DockFIFO starts dropping characters
501 #define DOCKFIFO_WR_MAX_STALL_US (30*1000)
503 static uint64_t prev_dockfifo_drained_time
; // Last time we've seen the DockFIFO drained by an external agent
504 static uint64_t prev_dockfifo_spaces
; // Previous w_stat level of the DockFIFO.
505 static uint32_t dockfifo_capacity
;
506 static uint64_t dockfifo_stall_grace
;
509 //=======================
511 //=======================
514 dockfifo_drain_on_stall()
516 // Called when DockFIFO runs out of spaces.
517 // Check if the DockFIFO reader has stalled. If so, empty the DockFIFO ourselves.
518 // Return number of bytes drained.
520 if (mach_absolute_time() - prev_dockfifo_drained_time
>= dockfifo_stall_grace
) {
521 // It's been more than DOCKFIFO_WR_MAX_STALL_US and nobody read from the FIFO
523 (void)rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1);
524 prev_dockfifo_spaces
++;
532 dockfifo_uart_tr0(void)
534 uint32_t spaces
= rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE
) & 0xffff;
535 if (spaces
>= dockfifo_capacity
|| spaces
> prev_dockfifo_spaces
) {
536 // More spaces showed up. That can only mean someone read the FIFO.
537 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
538 // we can only give them the benefit of the doubt.
540 prev_dockfifo_drained_time
= mach_absolute_time();
542 prev_dockfifo_spaces
= spaces
;
544 return spaces
|| dockfifo_drain_on_stall();
548 dockfifo_uart_td0(int c
)
550 rDOCKFIFO_W_DATA(DOCKFIFO_UART_WRITE
, 1) = (unsigned)(c
& 0xff);
551 prev_dockfifo_spaces
--; // After writing a byte we have one fewer space than previously expected.
555 dockfifo_uart_rr0(void)
557 return rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 0) & 0x7f;
561 dockfifo_uart_rd0(void)
563 return (int)((rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1) >> 8) & 0xff);
567 dockfifo_uart_init(void)
569 nanoseconds_to_absolutetime(DOCKFIFO_WR_MAX_STALL_US
* 1000, &dockfifo_stall_grace
);
571 // Disable autodraining of the FIFO. We now purely manage it in software.
572 rDOCKFIFO_DRAIN(DOCKFIFO_UART_WRITE
) = 0;
574 // Empty the DockFIFO by draining it until OCCUPANCY is 0, then measure its capacity
575 while (rDOCKFIFO_R_DATA(DOCKFIFO_UART_WRITE
, 3) & 0x7F) {
578 dockfifo_capacity
= rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE
) & 0xffff;
581 static struct pe_serial_functions dockfifo_uart_serial_functions
=
583 .uart_init
= dockfifo_uart_init
,
584 .uart_set_baud_rate
= NULL
,
585 .tr0
= dockfifo_uart_tr0
,
586 .td0
= dockfifo_uart_td0
,
587 .rr0
= dockfifo_uart_rr0
,
588 .rd0
= dockfifo_uart_rd0
591 #endif /* DOCKFIFO_UART */
593 /*****************************************************************************/
595 #ifdef DOCKCHANNEL_UART
596 #define DOCKCHANNEL_WR_MAX_STALL_US (30*1000)
598 static vm_offset_t dock_agent_base
;
599 static uint32_t max_dockchannel_drain_period
;
600 static bool use_sw_drain
;
601 static uint64_t prev_dockchannel_drained_time
; // Last time we've seen the DockChannel drained by an external agent
602 static uint64_t prev_dockchannel_spaces
; // Previous w_stat level of the DockChannel.
603 static uint64_t dockchannel_stall_grace
;
605 //=======================
607 //=======================
610 dockchannel_drain_on_stall()
612 // Called when DockChannel runs out of spaces.
613 // Check if the DockChannel reader has stalled. If so, empty the DockChannel ourselves.
614 // Return number of bytes drained.
616 if ((mach_absolute_time() - prev_dockchannel_drained_time
) >= dockchannel_stall_grace
) {
617 // It's been more than DOCKCHANEL_WR_MAX_STALL_US and nobody read from the FIFO
619 (void)rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
620 prev_dockchannel_spaces
++;
627 dockchannel_uart_tr0(void)
630 uint32_t spaces
= rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & 0x1ff;
631 if (spaces
> prev_dockchannel_spaces
) {
632 // More spaces showed up. That can only mean someone read the FIFO.
633 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
634 // we can only give them the benefit of the doubt.
635 prev_dockchannel_drained_time
= mach_absolute_time();
637 prev_dockchannel_spaces
= spaces
;
639 return spaces
|| dockchannel_drain_on_stall();
641 // Returns spaces in dockchannel fifo
642 return rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & 0x1ff;
647 dockchannel_uart_td0(int c
)
649 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL
) = (unsigned)(c
& 0xff);
651 prev_dockchannel_spaces
--; // After writing a byte we have one fewer space than previously expected.
656 dockchannel_uart_rr0(void)
658 return rDOCKCHANNELS_DEV_RDATA0(DOCKCHANNEL_UART_CHANNEL
) & 0x7f;
662 dockchannel_uart_rd0(void)
664 return (int)((rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
) >> 8) & 0xff);
668 dockchannel_uart_init(void)
671 nanoseconds_to_absolutetime(DOCKCHANNEL_WR_MAX_STALL_US
* NSEC_PER_USEC
, &dockchannel_stall_grace
);
674 // Clear all interrupt enable and status bits
675 rDOCKCHANNELS_AGENT_AP_INTR_CTRL
&= ~(0x3);
676 rDOCKCHANNELS_AGENT_AP_INTR_STATUS
|= 0x3;
677 rDOCKCHANNELS_AGENT_AP_ERR_INTR_CTRL
&= ~(0x3);
678 rDOCKCHANNELS_AGENT_AP_ERR_INTR_STATUS
|= 0x3;
681 rDOCKCHANNELS_DEV_DRAIN_CFG(DOCKCHANNEL_UART_CHANNEL
) = max_dockchannel_drain_period
;
683 // Drain timer doesn't get loaded with value from drain period register if fifo
684 // is already full. Drop a character from the fifo.
685 rDOCKCHANNELS_DOCK_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
688 static struct pe_serial_functions dockchannel_uart_serial_functions
=
690 .uart_init
= dockchannel_uart_init
,
691 .uart_set_baud_rate
= NULL
,
692 .tr0
= dockchannel_uart_tr0
,
693 .td0
= dockchannel_uart_td0
,
694 .rr0
= dockchannel_uart_rr0
,
695 .rd0
= dockchannel_uart_rd0
698 #endif /* DOCKCHANNEL_UART */
700 /****************************************************************************/
702 vm_offset_t pi3_gpio_base_vaddr
;
703 vm_offset_t pi3_aux_base_vaddr
;
707 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x20;
713 BCM2837_PUT32(BCM2837_AUX_MU_IO_REG_V
, (uint32_t) c
);
719 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x01;
725 return (int) BCM2837_GET32(BCM2837_AUX_MU_IO_REG_V
) & 0xff;
734 // Reset mini uart registers
735 BCM2837_PUT32(BCM2837_AUX_ENABLES_V
, 1);
736 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 0);
737 BCM2837_PUT32(BCM2837_AUX_MU_LCR_REG_V
, 3);
738 BCM2837_PUT32(BCM2837_AUX_MU_MCR_REG_V
, 0);
739 BCM2837_PUT32(BCM2837_AUX_MU_IER_REG_V
, 0);
740 BCM2837_PUT32(BCM2837_AUX_MU_IIR_REG_V
, 0xC6);
741 BCM2837_PUT32(BCM2837_AUX_MU_BAUD_REG_V
, 270);
743 i
= BCM2837_FSEL_REG(14);
744 // Configure GPIOs 14 & 15 for alternate function 5
745 i
&= ~(BCM2837_FSEL_MASK(14));
746 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(14));
747 i
&= ~(BCM2837_FSEL_MASK(15));
748 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(15));
750 BCM2837_PUT32(BCM2837_FSEL_REG(14), i
);
752 BCM2837_PUT32(BCM2837_GPPUD_V
, 0);
754 // Barrier before AP spinning for 150 cycles
755 __builtin_arm_isb(ISB_SY
);
757 for (i
= 0; i
< 150; i
++) {
758 asm volatile ("add x0, x0, xzr");
761 __builtin_arm_isb(ISB_SY
);
763 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, (1 << 14) | (1 << 15));
765 __builtin_arm_isb(ISB_SY
);
767 for (i
= 0; i
< 150; i
++) {
768 asm volatile ("add x0, x0, xzr");
771 __builtin_arm_isb(ISB_SY
);
773 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, 0);
775 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 3);
778 static struct pe_serial_functions pi3_uart_serial_functions
=
780 .uart_init
= pi3_uart_init
,
781 .uart_set_baud_rate
= NULL
,
788 #endif /* PI3_UART */
789 /*****************************************************************************/
793 DTEntry entryP
= NULL
;
794 uint32_t prop_size
, dccmode
;
795 vm_offset_t soc_base
;
797 uint32_t *prop_value
= NULL
;
798 char *serial_compat
= 0;
803 uint32_t no_dockfifo_uart
;
805 #ifdef DOCKCHANNEL_UART
806 uint32_t no_dockchannel_uart
;
812 if (uart_initted
&& gPESF
) {
814 kprintf("reinit serial\n");
819 if (PE_parse_boot_argn("dcc", &dccmode
, sizeof(dccmode
))) {
820 gPESF
= &dcc_serial_functions
;
826 if (PE_parse_boot_argn("jcon", &jconmode
, sizeof jconmode
)) {
827 gPESF
= &shmcon_serial_functions
;
835 #pragma unused(prop_value)
837 if (PE_parse_boot_argn("-pi3", &is_pi3
, sizeof(is_pi3
))) { // FIXME: remove the not operator after boot args are set up.
838 pi3_gpio_base_vaddr
= ml_io_map((vm_offset_t
)BCM2837_GPIO_BASE
, BCM2837_GPIO_SIZE
);
839 pi3_aux_base_vaddr
= ml_io_map((vm_offset_t
)BCM2837_AUX_BASE
, BCM2837_AUX_SIZE
);
840 gPESF
= &pi3_uart_serial_functions
;
845 #endif /* PI3_UART */
847 soc_base
= pe_arm_get_soc_base_phys();
854 no_dockfifo_uart
= 0;
855 PE_parse_boot_argn("no-dockfifo-uart", &no_dockfifo_uart
, sizeof(no_dockfifo_uart
));
856 if (no_dockfifo_uart
== 0) {
857 if (DTFindEntry("name", "dockfifo-uart", &entryP
) == kSuccess
) {
858 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
859 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
863 gPESF
= &dockfifo_uart_serial_functions
;
868 #endif /* DOCKFIFO_UART */
870 #ifdef DOCKCHANNEL_UART
871 no_dockchannel_uart
= 0;
872 // Keep the old name for boot-arg
873 PE_parse_boot_argn("no-dockfifo-uart", &no_dockchannel_uart
, sizeof(no_dockchannel_uart
));
874 if (no_dockchannel_uart
== 0) {
875 if (DTFindEntry("name", "dockchannel-uart", &entryP
) == kSuccess
) {
876 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
877 // Should be two reg entries
878 if (prop_size
/ sizeof(uintptr_t) != 4) {
879 panic("Malformed dockchannel-uart property");
881 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
882 dock_agent_base
= ml_io_map(soc_base
+ *(reg_prop
+ 2), *(reg_prop
+ 3));
883 gPESF
= &dockchannel_uart_serial_functions
;
884 DTGetProperty(entryP
, "max-aop-clk", (void **)&prop_value
, &prop_size
);
885 max_dockchannel_drain_period
= (uint32_t)((prop_value
)? (*prop_value
* 0.03) : DOCKCHANNEL_DRAIN_PERIOD
);
886 DTGetProperty(entryP
, "enable-sw-drain", (void **)&prop_value
, &prop_size
);
887 use_sw_drain
= (prop_value
)? *prop_value
: 0;
892 // If no dockchannel-uart is found in the device tree, fall back
893 // to looking for the traditional UART serial console.
895 #endif /* DOCKCHANNEL_UART */
898 * The boot serial port should have a property named "boot-console".
899 * If we don't find it there, look for "uart0" and "uart1".
902 if (DTFindEntry("boot-console", NULL
, &entryP
) == kSuccess
) {
903 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
904 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
905 if (serial_compat
== 0) {
906 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
908 } else if (DTFindEntry("name", "uart0", &entryP
) == kSuccess
) {
909 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
910 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
911 if (serial_compat
== 0) {
912 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
914 } else if (DTFindEntry("name", "uart1", &entryP
) == kSuccess
) {
915 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
916 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
917 if (serial_compat
== 0) {
918 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
922 if (NULL
!= entryP
) {
923 DTGetProperty(entryP
, "pclk", (void **)&prop_value
, &prop_size
);
925 dt_pclk
= *prop_value
;
929 DTGetProperty(entryP
, "sampling", (void **)&prop_value
, &prop_size
);
931 dt_sampling
= *prop_value
;
935 DTGetProperty(entryP
, "ubrdiv", (void **)&prop_value
, &prop_size
);
937 dt_ubrdiv
= *prop_value
;
940 if (!strcmp(serial_compat
, "uart,16550")) {
941 gPESF
= &ln2410_serial_functions
;
942 } else if (!strcmp(serial_compat
, "uart-16550")) {
943 gPESF
= &ln2410_serial_functions
;
944 } else if (!strcmp(serial_compat
, "uart,s5i3000")) {
945 gPESF
= &ln2410_serial_functions
;
946 } else if (!strcmp(serial_compat
, "uart-1,samsung")) {
947 gPESF
= &ln2410_serial_functions
;
949 #elif defined (ARM_BOARD_CONFIG_MV88F6710)
950 if (!strcmp(serial_compat
, "uart16x50,mmio")) {
951 gPESF
= &uart16x50_serial_functions
;
969 while (!gPESF
->tr0()) {
970 ; /* Wait until THR is empty. */
978 { /* returns -1 if no data available */
981 return -1; /* Receive data read */