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 <libkern/section_keywords.h>
14 #include <mach/mach_time.h>
15 #include <machine/atomic.h>
16 #include <machine/machine_routines.h>
17 #include <pexpert/pexpert.h>
18 #include <pexpert/protos.h>
19 #include <pexpert/device_tree.h>
21 #include <arm/caches_internal.h>
22 #include <arm/machine_routines.h>
23 #include <arm/proc_reg.h>
24 #include <pexpert/arm/board_config.h>
26 #elif defined __arm64__
27 #include <pexpert/arm/consistent_debug.h>
28 #include <pexpert/arm64/board_config.h>
29 #include <arm64/proc_reg.h>
32 #include <machine/pal_hibernate.h>
33 #endif /* HIBERNATION */
35 struct pe_serial_functions
{
36 void (*uart_init
) (void);
37 void (*uart_set_baud_rate
) (int unit
, uint32_t baud_rate
);
42 struct pe_serial_functions
*next
;
45 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
*) gPESF
= NULL
;
47 static int uart_initted
= 0; /* 1 if init'ed */
48 static vm_offset_t uart_base
= 0;
50 /*****************************************************************************/
54 static int32_t dt_pclk
= -1;
55 static int32_t dt_sampling
= -1;
56 static int32_t dt_ubrdiv
= -1;
58 static void ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
);
61 ln2410_uart_init(void)
63 uint32_t ucon0
= 0x405; /* NCLK, No interrupts, No DMA - just polled */
65 rULCON0
= 0x03; /* 81N, not IR */
67 // Override with pclk dt entry
69 ucon0
= ucon0
& ~0x400;
73 rUMCON0
= 0x00; /* Clear Flow Control */
75 ln2410_uart_set_baud_rate(0, 115200);
77 rUFCON0
= 0x03; /* Clear & Enable FIFOs */
78 rUMCON0
= 0x01; /* Assert RTS on UART0 */
82 ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
)
85 uint32_t uart_clock
= 0;
86 uint32_t sample_rate
= 16;
88 if (baud_rate
< 300) {
94 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.fix_frequency_hz
;
97 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.prf_frequency_hz
;
100 if (dt_sampling
!= -1) {
101 // Use the sampling rate specified in the Device Tree
102 sample_rate
= dt_sampling
& 0xf;
105 if (dt_ubrdiv
!= -1) {
106 // Use the ubrdiv specified in the Device Tree
107 div
= dt_ubrdiv
& 0xffff;
109 // Calculate ubrdiv. UBRDIV = (SourceClock / (BPS * Sample Rate)) - 1
110 div
= uart_clock
/ (baud_rate
* sample_rate
);
112 uint32_t actual_baud
= uart_clock
/ ((div
+ 0) * sample_rate
);
113 uint32_t baud_low
= uart_clock
/ ((div
+ 1) * sample_rate
);
115 // Adjust div to get the closest target baudrate
116 if ((baud_rate
- baud_low
) > (actual_baud
- baud_rate
)) {
121 // Sample Rate [19:16], UBRDIV [15:0]
122 rUBRDIV0
= ((16 - sample_rate
) << 16) | div
;
128 return rUTRSTAT0
& 0x04;
133 rUTXH0
= (unsigned)(c
& 0xff);
138 return rUTRSTAT0
& 0x01;
146 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) ln2410_serial_functions
=
148 .uart_init
= ln2410_uart_init
,
149 .uart_set_baud_rate
= ln2410_uart_set_baud_rate
,
158 /*****************************************************************************/
171 "mrc p14, 0, %0, c0, c5\n"
176 panic_unimplemented();
181 write_dtr(unsigned int c
)
185 "mcr p14, 0, %0, c0, c5\n"
191 panic_unimplemented();
199 return !(arm_debug_read_dscr() & ARM_DBGDSCR_TXFULL
);
202 panic_unimplemented();
217 return arm_debug_read_dscr() & ARM_DBGDSCR_RXFULL
;
220 panic_unimplemented();
231 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) dcc_serial_functions
=
233 .uart_init
= dcc_uart_init
,
234 .uart_set_baud_rate
= NULL
,
241 /*****************************************************************************/
245 #define CPU_CACHELINE_SIZE (1 << MMU_CLINE)
248 #define SHMCON_NAME "AP-xnu"
251 #define SHMCON_MAGIC 'SHMC'
252 #define SHMCON_VERSION 2
255 #define INBUF_SIZE (panic_size / 16)
256 #define FULL_ALIGNMENT (64)
258 #define FLAG_CACHELINE_32 1
259 #define FLAG_CACHELINE_64 2
261 /* Defines to clarify the master/slave fields' use as circular buffer pointers */
262 #define head_in sidx[CBUF_IN]
263 #define tail_in midx[CBUF_IN]
264 #define head_out midx[CBUF_OUT]
265 #define tail_out sidx[CBUF_OUT]
267 /* TODO: get from device tree/target */
268 #define NUM_CHILDREN 5
270 #define WRAP_INCR(len, x) do{ (x)++; if((x) >= (len)) (x) = 0; } while(0)
271 #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
273 #define MAX(a, b) ((a) > (b) ? (a) : (b))
274 #define MIN(a, b) ((a) < (b) ? (a) : (b))
276 #define shmcon_barrier() do {__asm__ volatile("dmb ish" : : : "memory");} while(0)
278 struct shm_buffer_info
{
284 struct shmcon_header
{
287 uint8_t children
; /* number of child entries in child_ent */
289 uint64_t buf_paddr
[2]; /* Physical address for buffers (in, out) */
293 /* Slave-modified data - invalidate before read */
294 uint32_t sidx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In head, out tail */
296 /* Master-modified data - clean after write */
297 uint32_t midx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In tail, out head */
299 uint64_t child
[0]; /* Physical address of child header pointers */
302 static volatile struct shmcon_header
*shmcon
= NULL
;
303 static volatile uint8_t *shmbuf
[2];
304 #ifdef SHMCON_THROTTLED
305 static uint64_t grace
= 0;
306 static uint64_t full_timeout
= 0;
310 shmcon_set_baud_rate(__unused
int unit
, __unused
uint32_t baud_rate
)
318 #ifdef SHMCON_THROTTLED
319 uint32_t head
= shmcon
->head_out
;
320 uint32_t tail
= shmcon
->tail_out
;
321 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
323 WRAP_INCR(len
, head
);
329 /* Full. Is this buffer being serviced? */
330 if (full_timeout
== 0) {
331 full_timeout
= mach_absolute_time() + grace
;
334 if (full_timeout
> mach_absolute_time()) {
338 /* Timeout - slave not really there or not keeping up */
344 shmcon
->tail_out
= tail
;
353 uint32_t head
= shmcon
->head_out
;
354 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
356 shmbuf
[CBUF_OUT
][head
] = (uint8_t)c
;
357 WRAP_INCR(len
, head
);
359 shmcon
->head_out
= head
;
365 if (shmcon
->tail_in
== shmcon
->head_in
) {
375 uint32_t tail
= shmcon
->tail_in
;
376 uint32_t len
= shmcon
->buf_len
[CBUF_IN
];
378 c
= shmbuf
[CBUF_IN
][tail
];
379 WRAP_INCR(len
, tail
);
381 shmcon
->tail_in
= tail
;
389 uintptr_t const *reg_prop
;
390 volatile struct shm_buffer_info
*end
;
391 size_t i
, header_size
;
393 vm_offset_t pa_panic_base
, panic_size
, va_buffer_base
, va_buffer_end
;
395 if (kSuccess
!= SecureDTLookupEntry(0, "pram", &entry
)) {
399 if (kSuccess
!= SecureDTGetProperty(entry
, "reg", (void const **)®_prop
, &size
)) {
403 pa_panic_base
= reg_prop
[0];
404 panic_size
= reg_prop
[1];
406 shmcon
= (struct shmcon_header
*)ml_map_high_window(pa_panic_base
, panic_size
);
407 header_size
= sizeof(*shmcon
) + (NUM_CHILDREN
* sizeof(shmcon
->child
[0]));
408 va_buffer_base
= ROUNDUP((uintptr_t)(shmcon
) + header_size
, CPU_CACHELINE_SIZE
);
409 va_buffer_end
= (uintptr_t)shmcon
+ panic_size
- (sizeof(*end
));
411 if ((shmcon
->magic
== SHMCON_MAGIC
) && (shmcon
->version
== SHMCON_VERSION
)) {
412 vm_offset_t pa_buffer_base
, pa_buffer_end
;
414 pa_buffer_base
= ml_vtophys(va_buffer_base
);
415 pa_buffer_end
= ml_vtophys(va_buffer_end
);
417 /* Resume previous console session */
418 for (i
= 0; i
< 2; i
++) {
422 pa_buf
= (uintptr_t)shmcon
->buf_paddr
[i
];
423 len
= shmcon
->buf_len
[i
];
424 /* Validate buffers */
425 if ((pa_buf
< pa_buffer_base
) ||
426 (pa_buf
>= pa_buffer_end
) ||
427 ((pa_buf
+ len
) > pa_buffer_end
) ||
428 (shmcon
->midx
[i
] >= len
) || /* Index out of bounds */
429 (shmcon
->sidx
[i
] >= len
) ||
430 (pa_buf
!= ROUNDUP(pa_buf
, CPU_CACHELINE_SIZE
)) || /* Unaligned pa_buffer */
432 (len
> (pa_buffer_end
- pa_buffer_base
)) ||
433 (shmcon
->children
!= NUM_CHILDREN
)) {
434 goto validation_failure
;
436 /* Compute the VA offset of the buffer */
437 shmbuf
[i
] = (uint8_t *)(uintptr_t)shmcon
+ ((uintptr_t)pa_buf
- (uintptr_t)pa_panic_base
);
439 /* Check that buffers don't overlap */
440 if ((uintptr_t)shmbuf
[0] < (uintptr_t)shmbuf
[1]) {
441 if ((uintptr_t)(shmbuf
[0] + shmcon
->buf_len
[0]) > (uintptr_t)shmbuf
[1]) {
442 goto validation_failure
;
445 if ((uintptr_t)(shmbuf
[1] + shmcon
->buf_len
[1]) > (uintptr_t)shmbuf
[0]) {
446 goto validation_failure
;
449 shmcon
->tail_in
= shmcon
->head_in
; /* Clear input buffer */
455 shmcon
->buf_len
[CBUF_IN
] = (uint32_t)INBUF_SIZE
;
456 shmbuf
[CBUF_IN
] = (uint8_t *)va_buffer_base
;
457 shmbuf
[CBUF_OUT
] = (uint8_t *)ROUNDUP(va_buffer_base
+ INBUF_SIZE
, CPU_CACHELINE_SIZE
);
458 for (i
= 0; i
< 2; i
++) {
461 shmcon
->buf_paddr
[i
] = (uintptr_t)ml_vtophys((vm_offset_t
)shmbuf
[i
]);
463 shmcon
->buf_len
[CBUF_OUT
] = (uint32_t)(va_buffer_end
- (uintptr_t)shmbuf
[CBUF_OUT
]);
464 shmcon
->version
= SHMCON_VERSION
;
465 #pragma clang diagnostic push
466 #pragma clang diagnostic ignored "-Wcast-qual"
467 memset((void *)shmcon
->name
, ' ', sizeof(shmcon
->name
));
468 memcpy((void *)shmcon
->name
, SHMCON_NAME
, MIN(sizeof(shmcon
->name
), strlen(SHMCON_NAME
)));
469 #pragma clang diagnostic pop
470 for (i
= 0; i
< NUM_CHILDREN
; i
++) {
471 shmcon
->child
[0] = 0;
474 shmcon
->magic
= SHMCON_MAGIC
;
476 end
= (volatile struct shm_buffer_info
*)va_buffer_end
;
477 end
->base
= pa_panic_base
;
480 end
->magic
= SHMCON_MAGIC
;
481 #ifdef SHMCON_THROTTLED
482 grace
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
485 PE_consistent_debug_register(kDbgIdConsoleHeaderAP
, pa_panic_base
, panic_size
);
488 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) shmcon_serial_functions
=
490 .uart_init
= shmcon_init
,
491 .uart_set_baud_rate
= shmcon_set_baud_rate
,
499 pe_shmcon_set_child(uint64_t paddr
, uint32_t entry
)
501 if (shmcon
== NULL
) {
505 if (shmcon
->children
>= entry
) {
509 shmcon
->child
[entry
] = paddr
;
515 /*****************************************************************************/
517 #ifdef DOCKCHANNEL_UART
518 #define DOCKCHANNEL_WR_MAX_STALL_US (30*1000)
520 static vm_offset_t dock_agent_base
;
521 static uint32_t max_dockchannel_drain_period
;
522 static bool use_sw_drain
;
523 static uint32_t dock_wstat_mask
;
524 static uint64_t prev_dockchannel_drained_time
; // Last time we've seen the DockChannel drained by an external agent
525 static uint64_t prev_dockchannel_spaces
; // Previous w_stat level of the DockChannel.
526 static uint64_t dockchannel_stall_grace
;
527 static vm_offset_t dockchannel_uart_base
= 0;
529 //=======================
531 //=======================
534 dockchannel_drain_on_stall()
536 // Called when DockChannel runs out of spaces.
537 // Check if the DockChannel reader has stalled. If so, empty the DockChannel ourselves.
538 // Return number of bytes drained.
540 if ((mach_absolute_time() - prev_dockchannel_drained_time
) >= dockchannel_stall_grace
) {
541 // It's been more than DOCKCHANEL_WR_MAX_STALL_US and nobody read from the FIFO
543 (void)rDOCKCHANNELS_DOCK_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
544 os_atomic_inc(&prev_dockchannel_spaces
, relaxed
);
551 dockchannel_uart_tr0(void)
554 uint32_t spaces
= rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & dock_wstat_mask
;
555 if (spaces
> prev_dockchannel_spaces
) {
556 // More spaces showed up. That can only mean someone read the FIFO.
557 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
558 // we can only give them the benefit of the doubt.
559 prev_dockchannel_drained_time
= mach_absolute_time();
561 prev_dockchannel_spaces
= spaces
;
563 return spaces
|| dockchannel_drain_on_stall();
565 // Returns spaces in dockchannel fifo
566 return rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & dock_wstat_mask
;
571 dockchannel_uart_td0(int c
)
573 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL
) = (unsigned)(c
& 0xff);
575 os_atomic_dec(&prev_dockchannel_spaces
, relaxed
); // After writing a byte we have one fewer space than previously expected.
580 dockchannel_uart_rr0(void)
582 return rDOCKCHANNELS_DEV_RDATA0(DOCKCHANNEL_UART_CHANNEL
) & 0x7f;
586 dockchannel_uart_rd0(void)
588 return (int)((rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
) >> 8) & 0xff);
592 dockchannel_uart_clear_intr(void)
594 rDOCKCHANNELS_AGENT_AP_INTR_CTRL
&= ~(0x3);
595 rDOCKCHANNELS_AGENT_AP_INTR_STATUS
|= 0x3;
596 rDOCKCHANNELS_AGENT_AP_ERR_INTR_CTRL
&= ~(0x3);
597 rDOCKCHANNELS_AGENT_AP_ERR_INTR_STATUS
|= 0x3;
601 dockchannel_uart_init(void)
604 nanoseconds_to_absolutetime(DOCKCHANNEL_WR_MAX_STALL_US
* NSEC_PER_USEC
, &dockchannel_stall_grace
);
607 // Clear all interrupt enable and status bits
608 dockchannel_uart_clear_intr();
611 rDOCKCHANNELS_DEV_DRAIN_CFG(DOCKCHANNEL_UART_CHANNEL
) = max_dockchannel_drain_period
;
613 // Drain timer doesn't get loaded with value from drain period register if fifo
614 // is already full. Drop a character from the fifo.
615 rDOCKCHANNELS_DOCK_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
618 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) dockchannel_uart_serial_functions
=
620 .uart_init
= dockchannel_uart_init
,
621 .uart_set_baud_rate
= NULL
,
622 .tr0
= dockchannel_uart_tr0
,
623 .td0
= dockchannel_uart_td0
,
624 .rr0
= dockchannel_uart_rr0
,
625 .rd0
= dockchannel_uart_rd0
628 #endif /* DOCKCHANNEL_UART */
630 /****************************************************************************/
632 static vm_offset_t pi3_gpio_base_vaddr
= 0;
633 static vm_offset_t pi3_aux_base_vaddr
= 0;
637 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x20;
643 BCM2837_PUT32(BCM2837_AUX_MU_IO_REG_V
, (uint32_t) c
);
649 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x01;
655 return (int) BCM2837_GET32(BCM2837_AUX_MU_IO_REG_V
) & 0xff;
664 // Reset mini uart registers
665 BCM2837_PUT32(BCM2837_AUX_ENABLES_V
, 1);
666 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 0);
667 BCM2837_PUT32(BCM2837_AUX_MU_LCR_REG_V
, 3);
668 BCM2837_PUT32(BCM2837_AUX_MU_MCR_REG_V
, 0);
669 BCM2837_PUT32(BCM2837_AUX_MU_IER_REG_V
, 0);
670 BCM2837_PUT32(BCM2837_AUX_MU_IIR_REG_V
, 0xC6);
671 BCM2837_PUT32(BCM2837_AUX_MU_BAUD_REG_V
, 270);
673 i
= (uint32_t)BCM2837_FSEL_REG(14);
674 // Configure GPIOs 14 & 15 for alternate function 5
675 i
&= ~(BCM2837_FSEL_MASK(14));
676 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(14));
677 i
&= ~(BCM2837_FSEL_MASK(15));
678 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(15));
680 BCM2837_PUT32(BCM2837_FSEL_REG(14), i
);
682 BCM2837_PUT32(BCM2837_GPPUD_V
, 0);
684 // Barrier before AP spinning for 150 cycles
685 __builtin_arm_isb(ISB_SY
);
687 for (i
= 0; i
< 150; i
++) {
688 asm volatile ("add x0, x0, xzr");
691 __builtin_arm_isb(ISB_SY
);
693 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, (1 << 14) | (1 << 15));
695 __builtin_arm_isb(ISB_SY
);
697 for (i
= 0; i
< 150; i
++) {
698 asm volatile ("add x0, x0, xzr");
701 __builtin_arm_isb(ISB_SY
);
703 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, 0);
705 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 3);
708 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) pi3_uart_serial_functions
=
710 .uart_init
= pi3_uart_init
,
711 .uart_set_baud_rate
= NULL
,
718 #endif /* PI3_UART */
720 /*****************************************************************************/
723 /*****************************************************************************/
726 register_serial_functions(struct pe_serial_functions
*fns
)
735 DTEntry entryP
= NULL
;
737 vm_offset_t soc_base
;
738 uintptr_t const *reg_prop
;
739 uint32_t const *prop_value __unused
= NULL
;
740 char const *serial_compat __unused
= 0;
743 struct pe_serial_functions
*fns
= gPESF
;
746 while (fns
!= NULL
) {
750 kprintf("reinit serial\n");
755 if (PE_parse_boot_argn("dcc", &dccmode
, sizeof(dccmode
))) {
756 register_serial_functions(&dcc_serial_functions
);
759 uint32_t jconmode
= 0;
760 if (PE_parse_boot_argn("jcon", &jconmode
, sizeof jconmode
)) {
761 register_serial_functions(&shmcon_serial_functions
);
765 soc_base
= pe_arm_get_soc_base_phys();
772 if (SecureDTFindEntry("name", "gpio", &entryP
) == kSuccess
) {
773 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
774 pi3_gpio_base_vaddr
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
776 if (SecureDTFindEntry("name", "aux", &entryP
) == kSuccess
) {
777 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
778 pi3_aux_base_vaddr
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
780 if ((pi3_gpio_base_vaddr
!= 0) && (pi3_aux_base_vaddr
!= 0)) {
781 register_serial_functions(&pi3_uart_serial_functions
);
783 #endif /* PI3_UART */
786 #ifdef DOCKCHANNEL_UART
787 uint32_t no_dockchannel_uart
= 0;
788 if (SecureDTFindEntry("name", "dockchannel-uart", &entryP
) == kSuccess
) {
789 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
790 // Should be two reg entries
791 if (prop_size
/ sizeof(uintptr_t) != 4) {
792 panic("Malformed dockchannel-uart property");
794 dockchannel_uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
795 dock_agent_base
= ml_io_map(soc_base
+ *(reg_prop
+ 2), *(reg_prop
+ 3));
796 PE_parse_boot_argn("no-dockfifo-uart", &no_dockchannel_uart
, sizeof(no_dockchannel_uart
));
797 // Keep the old name for boot-arg
798 if (no_dockchannel_uart
== 0) {
799 register_serial_functions(&dockchannel_uart_serial_functions
);
800 SecureDTGetProperty(entryP
, "max-aop-clk", (void const **)&prop_value
, &prop_size
);
801 max_dockchannel_drain_period
= (uint32_t)((prop_value
)? (*prop_value
* 0.03) : DOCKCHANNEL_DRAIN_PERIOD
);
803 SecureDTGetProperty(entryP
, "enable-sw-drain", (void const **)&prop_value
, &prop_size
);
804 use_sw_drain
= (prop_value
)? *prop_value
: 0;
806 SecureDTGetProperty(entryP
, "dock-wstat-mask", (void const **)&prop_value
, &prop_size
);
807 dock_wstat_mask
= (prop_value
)? *prop_value
: 0x1ff;
809 dockchannel_uart_clear_intr();
811 // If no dockchannel-uart is found in the device tree, fall back
812 // to looking for the traditional UART serial console.
815 #endif /* DOCKCHANNEL_UART */
818 * The boot serial port should have a property named "boot-console".
819 * If we don't find it there, look for "uart0" and "uart1".
822 if (SecureDTFindEntry("boot-console", NULL
, &entryP
) == kSuccess
) {
823 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
824 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
825 if (serial_compat
== 0) {
826 SecureDTGetProperty(entryP
, "compatible", (void const **)&serial_compat
, &prop_size
);
828 } else if (SecureDTFindEntry("name", "uart0", &entryP
) == kSuccess
) {
829 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
830 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
831 if (serial_compat
== 0) {
832 SecureDTGetProperty(entryP
, "compatible", (void const **)&serial_compat
, &prop_size
);
834 } else if (SecureDTFindEntry("name", "uart1", &entryP
) == kSuccess
) {
835 SecureDTGetProperty(entryP
, "reg", (void const **)®_prop
, &prop_size
);
836 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
837 if (serial_compat
== 0) {
838 SecureDTGetProperty(entryP
, "compatible", (void const **)&serial_compat
, &prop_size
);
842 if (NULL
!= entryP
) {
843 SecureDTGetProperty(entryP
, "pclk", (void const **)&prop_value
, &prop_size
);
845 dt_pclk
= *prop_value
;
849 SecureDTGetProperty(entryP
, "sampling", (void const **)&prop_value
, &prop_size
);
851 dt_sampling
= *prop_value
;
855 SecureDTGetProperty(entryP
, "ubrdiv", (void const **)&prop_value
, &prop_size
);
857 dt_ubrdiv
= *prop_value
;
862 if (!strcmp(serial_compat
, "uart,16550")) {
863 register_serial_functions(&ln2410_serial_functions
);
864 } else if (!strcmp(serial_compat
, "uart-16550")) {
865 register_serial_functions(&ln2410_serial_functions
);
866 } else if (!strcmp(serial_compat
, "uart,s5i3000")) {
867 register_serial_functions(&ln2410_serial_functions
);
868 } else if (!strcmp(serial_compat
, "uart-1,samsung")) {
869 register_serial_functions(&ln2410_serial_functions
);
879 while (fns
!= NULL
) {
885 /* hibernation needs to know the UART register addresses since it can't directly use this serial driver */
886 if (dockchannel_uart_base
) {
887 gHibernateGlobals
.dockChannelRegBase
= ml_vtophys(dockchannel_uart_base
);
888 gHibernateGlobals
.dockChannelWstatMask
= dock_wstat_mask
;
891 gHibernateGlobals
.hibUartRegBase
= ml_vtophys(uart_base
);
893 #endif /* HIBERNATION */
903 struct pe_serial_functions
*fns
= gPESF
;
904 while (fns
!= NULL
) {
905 while (!fns
->tr0()) {
906 #if __arm64__ /* on arm64, we have a WFE timeout, so no need to hot-poll here */
909 ; /* Wait until THR is empty. */
918 { /* returns -1 if no data available */
919 struct pe_serial_functions
*fns
= gPESF
;
920 while (fns
!= NULL
) {