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 struct pe_serial_functions
{
33 void (*uart_init
) (void);
34 void (*uart_set_baud_rate
) (int unit
, uint32_t baud_rate
);
39 struct pe_serial_functions
*next
;
42 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
*) gPESF
= NULL
;
44 static int uart_initted
= 0; /* 1 if init'ed */
45 static vm_offset_t uart_base
= 0;
47 /*****************************************************************************/
51 static int32_t dt_pclk
= -1;
52 static int32_t dt_sampling
= -1;
53 static int32_t dt_ubrdiv
= -1;
55 static void ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
);
58 ln2410_uart_init(void)
60 uint32_t ucon0
= 0x405; /* NCLK, No interrupts, No DMA - just polled */
62 rULCON0
= 0x03; /* 81N, not IR */
64 // Override with pclk dt entry
66 ucon0
= ucon0
& ~0x400;
70 rUMCON0
= 0x00; /* Clear Flow Control */
72 ln2410_uart_set_baud_rate(0, 115200);
74 rUFCON0
= 0x03; /* Clear & Enable FIFOs */
75 rUMCON0
= 0x01; /* Assert RTS on UART0 */
79 ln2410_uart_set_baud_rate(__unused
int unit
, uint32_t baud_rate
)
82 uint32_t uart_clock
= 0;
83 uint32_t sample_rate
= 16;
85 if (baud_rate
< 300) {
91 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.fix_frequency_hz
;
94 uart_clock
= (uint32_t)gPEClockFrequencyInfo
.prf_frequency_hz
;
97 if (dt_sampling
!= -1) {
98 // Use the sampling rate specified in the Device Tree
99 sample_rate
= dt_sampling
& 0xf;
102 if (dt_ubrdiv
!= -1) {
103 // Use the ubrdiv specified in the Device Tree
104 div
= dt_ubrdiv
& 0xffff;
106 // Calculate ubrdiv. UBRDIV = (SourceClock / (BPS * Sample Rate)) - 1
107 div
= uart_clock
/ (baud_rate
* sample_rate
);
109 uint32_t actual_baud
= uart_clock
/ ((div
+ 0) * sample_rate
);
110 uint32_t baud_low
= uart_clock
/ ((div
+ 1) * sample_rate
);
112 // Adjust div to get the closest target baudrate
113 if ((baud_rate
- baud_low
) > (actual_baud
- baud_rate
)) {
118 // Sample Rate [19:16], UBRDIV [15:0]
119 rUBRDIV0
= ((16 - sample_rate
) << 16) | div
;
125 return rUTRSTAT0
& 0x04;
130 rUTXH0
= (unsigned)(c
& 0xff);
135 return rUTRSTAT0
& 0x01;
143 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) ln2410_serial_functions
=
145 .uart_init
= ln2410_uart_init
,
146 .uart_set_baud_rate
= ln2410_uart_set_baud_rate
,
155 /*****************************************************************************/
168 "mrc p14, 0, %0, c0, c5\n"
173 panic_unimplemented();
178 write_dtr(unsigned int c
)
182 "mcr p14, 0, %0, c0, c5\n"
188 panic_unimplemented();
196 return !(arm_debug_read_dscr() & ARM_DBGDSCR_TXFULL
);
199 panic_unimplemented();
214 return arm_debug_read_dscr() & ARM_DBGDSCR_RXFULL
;
217 panic_unimplemented();
228 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) dcc_serial_functions
=
230 .uart_init
= dcc_uart_init
,
231 .uart_set_baud_rate
= NULL
,
238 /*****************************************************************************/
242 #define CPU_CACHELINE_SIZE (1 << MMU_CLINE)
245 #define SHMCON_NAME "AP-xnu"
248 #define SHMCON_MAGIC 'SHMC'
249 #define SHMCON_VERSION 2
252 #define INBUF_SIZE (panic_size / 16)
253 #define FULL_ALIGNMENT (64)
255 #define FLAG_CACHELINE_32 1
256 #define FLAG_CACHELINE_64 2
258 /* Defines to clarify the master/slave fields' use as circular buffer pointers */
259 #define head_in sidx[CBUF_IN]
260 #define tail_in midx[CBUF_IN]
261 #define head_out midx[CBUF_OUT]
262 #define tail_out sidx[CBUF_OUT]
264 /* TODO: get from device tree/target */
265 #define NUM_CHILDREN 5
267 #define WRAP_INCR(len, x) do{ (x)++; if((x) >= (len)) (x) = 0; } while(0)
268 #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
270 #define MAX(a, b) ((a) > (b) ? (a) : (b))
271 #define MIN(a, b) ((a) < (b) ? (a) : (b))
273 #define shmcon_barrier() do {__asm__ volatile("dmb ish" : : : "memory");} while(0)
275 struct shm_buffer_info
{
281 struct shmcon_header
{
284 uint8_t children
; /* number of child entries in child_ent */
286 uint64_t buf_paddr
[2]; /* Physical address for buffers (in, out) */
290 /* Slave-modified data - invalidate before read */
291 uint32_t sidx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In head, out tail */
293 /* Master-modified data - clean after write */
294 uint32_t midx
[2] __attribute__((aligned(FULL_ALIGNMENT
))); /* In tail, out head */
296 uint64_t child
[0]; /* Physical address of child header pointers */
299 static volatile struct shmcon_header
*shmcon
= NULL
;
300 static volatile uint8_t *shmbuf
[2];
301 #ifdef SHMCON_THROTTLED
302 static uint64_t grace
= 0;
303 static uint64_t full_timeout
= 0;
307 shmcon_set_baud_rate(__unused
int unit
, __unused
uint32_t baud_rate
)
315 #ifdef SHMCON_THROTTLED
316 uint32_t head
= shmcon
->head_out
;
317 uint32_t tail
= shmcon
->tail_out
;
318 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
320 WRAP_INCR(len
, head
);
326 /* Full. Is this buffer being serviced? */
327 if (full_timeout
== 0) {
328 full_timeout
= mach_absolute_time() + grace
;
331 if (full_timeout
> mach_absolute_time()) {
335 /* Timeout - slave not really there or not keeping up */
341 shmcon
->tail_out
= tail
;
350 uint32_t head
= shmcon
->head_out
;
351 uint32_t len
= shmcon
->buf_len
[CBUF_OUT
];
353 shmbuf
[CBUF_OUT
][head
] = (uint8_t)c
;
354 WRAP_INCR(len
, head
);
356 shmcon
->head_out
= head
;
362 if (shmcon
->tail_in
== shmcon
->head_in
) {
372 uint32_t tail
= shmcon
->tail_in
;
373 uint32_t len
= shmcon
->buf_len
[CBUF_IN
];
375 c
= shmbuf
[CBUF_IN
][tail
];
376 WRAP_INCR(len
, tail
);
378 shmcon
->tail_in
= tail
;
387 volatile struct shm_buffer_info
*end
;
388 size_t i
, header_size
;
390 vm_offset_t pa_panic_base
, panic_size
, va_buffer_base
, va_buffer_end
;
392 if (kSuccess
!= DTLookupEntry(0, "pram", &entry
)) {
396 if (kSuccess
!= DTGetProperty(entry
, "reg", (void **)®_prop
, &size
)) {
400 pa_panic_base
= reg_prop
[0];
401 panic_size
= reg_prop
[1];
403 shmcon
= (struct shmcon_header
*)ml_map_high_window(pa_panic_base
, panic_size
);
404 header_size
= sizeof(*shmcon
) + (NUM_CHILDREN
* sizeof(shmcon
->child
[0]));
405 va_buffer_base
= ROUNDUP((uintptr_t)(shmcon
) + header_size
, CPU_CACHELINE_SIZE
);
406 va_buffer_end
= (uintptr_t)shmcon
+ panic_size
- (sizeof(*end
));
408 if ((shmcon
->magic
== SHMCON_MAGIC
) && (shmcon
->version
== SHMCON_VERSION
)) {
409 vm_offset_t pa_buffer_base
, pa_buffer_end
;
411 pa_buffer_base
= ml_vtophys(va_buffer_base
);
412 pa_buffer_end
= ml_vtophys(va_buffer_end
);
414 /* Resume previous console session */
415 for (i
= 0; i
< 2; i
++) {
419 pa_buf
= (uintptr_t)shmcon
->buf_paddr
[i
];
420 len
= shmcon
->buf_len
[i
];
421 /* Validate buffers */
422 if ((pa_buf
< pa_buffer_base
) ||
423 (pa_buf
>= pa_buffer_end
) ||
424 ((pa_buf
+ len
) > pa_buffer_end
) ||
425 (shmcon
->midx
[i
] >= len
) || /* Index out of bounds */
426 (shmcon
->sidx
[i
] >= len
) ||
427 (pa_buf
!= ROUNDUP(pa_buf
, CPU_CACHELINE_SIZE
)) || /* Unaligned pa_buffer */
429 (len
> (pa_buffer_end
- pa_buffer_base
)) ||
430 (shmcon
->children
!= NUM_CHILDREN
)) {
431 goto validation_failure
;
433 /* Compute the VA offset of the buffer */
434 shmbuf
[i
] = (uint8_t *)(uintptr_t)shmcon
+ ((uintptr_t)pa_buf
- (uintptr_t)pa_panic_base
);
436 /* Check that buffers don't overlap */
437 if ((uintptr_t)shmbuf
[0] < (uintptr_t)shmbuf
[1]) {
438 if ((uintptr_t)(shmbuf
[0] + shmcon
->buf_len
[0]) > (uintptr_t)shmbuf
[1]) {
439 goto validation_failure
;
442 if ((uintptr_t)(shmbuf
[1] + shmcon
->buf_len
[1]) > (uintptr_t)shmbuf
[0]) {
443 goto validation_failure
;
446 shmcon
->tail_in
= shmcon
->head_in
; /* Clear input buffer */
452 shmcon
->buf_len
[CBUF_IN
] = (uint32_t)INBUF_SIZE
;
453 shmbuf
[CBUF_IN
] = (uint8_t *)va_buffer_base
;
454 shmbuf
[CBUF_OUT
] = (uint8_t *)ROUNDUP(va_buffer_base
+ INBUF_SIZE
, CPU_CACHELINE_SIZE
);
455 for (i
= 0; i
< 2; i
++) {
458 shmcon
->buf_paddr
[i
] = (uintptr_t)ml_vtophys((vm_offset_t
)shmbuf
[i
]);
460 shmcon
->buf_len
[CBUF_OUT
] = (uint32_t)(va_buffer_end
- (uintptr_t)shmbuf
[CBUF_OUT
]);
461 shmcon
->version
= SHMCON_VERSION
;
462 #pragma clang diagnostic push
463 #pragma clang diagnostic ignored "-Wcast-qual"
464 memset((void *)shmcon
->name
, ' ', sizeof(shmcon
->name
));
465 memcpy((void *)shmcon
->name
, SHMCON_NAME
, MIN(sizeof(shmcon
->name
), strlen(SHMCON_NAME
)));
466 #pragma clang diagnostic pop
467 for (i
= 0; i
< NUM_CHILDREN
; i
++) {
468 shmcon
->child
[0] = 0;
471 shmcon
->magic
= SHMCON_MAGIC
;
473 end
= (volatile struct shm_buffer_info
*)va_buffer_end
;
474 end
->base
= pa_panic_base
;
477 end
->magic
= SHMCON_MAGIC
;
478 #ifdef SHMCON_THROTTLED
479 grace
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
482 PE_consistent_debug_register(kDbgIdConsoleHeaderAP
, pa_panic_base
, panic_size
);
485 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) shmcon_serial_functions
=
487 .uart_init
= shmcon_init
,
488 .uart_set_baud_rate
= shmcon_set_baud_rate
,
496 pe_shmcon_set_child(uint64_t paddr
, uint32_t entry
)
498 if (shmcon
== NULL
) {
502 if (shmcon
->children
>= entry
) {
506 shmcon
->child
[entry
] = paddr
;
512 /*****************************************************************************/
517 // Allow a 30ms stall of wall clock time before DockFIFO starts dropping characters
518 #define DOCKFIFO_WR_MAX_STALL_US (30*1000)
520 static uint64_t prev_dockfifo_drained_time
; // Last time we've seen the DockFIFO drained by an external agent
521 static uint64_t prev_dockfifo_spaces
; // Previous w_stat level of the DockFIFO.
522 static uint32_t dockfifo_capacity
;
523 static uint64_t dockfifo_stall_grace
;
525 static vm_offset_t dockfifo_uart_base
= 0;
527 //=======================
529 //=======================
532 dockfifo_drain_on_stall()
534 // Called when DockFIFO runs out of spaces.
535 // Check if the DockFIFO reader has stalled. If so, empty the DockFIFO ourselves.
536 // Return number of bytes drained.
538 if (mach_absolute_time() - prev_dockfifo_drained_time
>= dockfifo_stall_grace
) {
539 // It's been more than DOCKFIFO_WR_MAX_STALL_US and nobody read from the FIFO
541 (void)rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1);
542 os_atomic_inc(&prev_dockfifo_spaces
, relaxed
);
550 dockfifo_uart_tr0(void)
552 uint32_t spaces
= rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE
) & 0xffff;
553 if (spaces
>= dockfifo_capacity
|| spaces
> prev_dockfifo_spaces
) {
554 // More spaces showed up. That can only mean someone read the FIFO.
555 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
556 // we can only give them the benefit of the doubt.
558 prev_dockfifo_drained_time
= mach_absolute_time();
560 prev_dockfifo_spaces
= spaces
;
562 return spaces
|| dockfifo_drain_on_stall();
566 dockfifo_uart_td0(int c
)
568 rDOCKFIFO_W_DATA(DOCKFIFO_UART_WRITE
, 1) = (unsigned)(c
& 0xff);
569 os_atomic_dec(&prev_dockfifo_spaces
, relaxed
); // After writing a byte we have one fewer space than previously expected.
573 dockfifo_uart_rr0(void)
575 return rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 0) & 0x7f;
579 dockfifo_uart_rd0(void)
581 return (int)((rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ
, 1) >> 8) & 0xff);
585 dockfifo_uart_init(void)
587 nanoseconds_to_absolutetime(DOCKFIFO_WR_MAX_STALL_US
* 1000, &dockfifo_stall_grace
);
589 // Disable autodraining of the FIFO. We now purely manage it in software.
590 rDOCKFIFO_DRAIN(DOCKFIFO_UART_WRITE
) = 0;
592 // Empty the DockFIFO by draining it until OCCUPANCY is 0, then measure its capacity
593 while (rDOCKFIFO_R_DATA(DOCKFIFO_UART_WRITE
, 3) & 0x7F) {
596 dockfifo_capacity
= rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE
) & 0xffff;
599 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) dockfifo_uart_serial_functions
=
601 .uart_init
= dockfifo_uart_init
,
602 .uart_set_baud_rate
= NULL
,
603 .tr0
= dockfifo_uart_tr0
,
604 .td0
= dockfifo_uart_td0
,
605 .rr0
= dockfifo_uart_rr0
,
606 .rd0
= dockfifo_uart_rd0
609 #endif /* DOCKFIFO_UART */
611 /*****************************************************************************/
613 #ifdef DOCKCHANNEL_UART
614 #define DOCKCHANNEL_WR_MAX_STALL_US (30*1000)
616 static vm_offset_t dock_agent_base
;
617 static uint32_t max_dockchannel_drain_period
;
618 static bool use_sw_drain
;
619 static uint64_t prev_dockchannel_drained_time
; // Last time we've seen the DockChannel drained by an external agent
620 static uint64_t prev_dockchannel_spaces
; // Previous w_stat level of the DockChannel.
621 static uint64_t dockchannel_stall_grace
;
622 static vm_offset_t dockchannel_uart_base
= 0;
624 //=======================
626 //=======================
629 dockchannel_drain_on_stall()
631 // Called when DockChannel runs out of spaces.
632 // Check if the DockChannel reader has stalled. If so, empty the DockChannel ourselves.
633 // Return number of bytes drained.
635 if ((mach_absolute_time() - prev_dockchannel_drained_time
) >= dockchannel_stall_grace
) {
636 // It's been more than DOCKCHANEL_WR_MAX_STALL_US and nobody read from the FIFO
638 (void)rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
639 os_atomic_inc(&prev_dockchannel_spaces
, relaxed
);
646 dockchannel_uart_tr0(void)
649 uint32_t spaces
= rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & 0x1ff;
650 if (spaces
> prev_dockchannel_spaces
) {
651 // More spaces showed up. That can only mean someone read the FIFO.
652 // Note that if the DockFIFO is empty we cannot tell if someone is listening,
653 // we can only give them the benefit of the doubt.
654 prev_dockchannel_drained_time
= mach_absolute_time();
656 prev_dockchannel_spaces
= spaces
;
658 return spaces
|| dockchannel_drain_on_stall();
660 // Returns spaces in dockchannel fifo
661 return rDOCKCHANNELS_DEV_WSTAT(DOCKCHANNEL_UART_CHANNEL
) & 0x1ff;
666 dockchannel_uart_td0(int c
)
668 rDOCKCHANNELS_DEV_WDATA1(DOCKCHANNEL_UART_CHANNEL
) = (unsigned)(c
& 0xff);
670 os_atomic_dec(&prev_dockchannel_spaces
, relaxed
); // After writing a byte we have one fewer space than previously expected.
675 dockchannel_uart_rr0(void)
677 return rDOCKCHANNELS_DEV_RDATA0(DOCKCHANNEL_UART_CHANNEL
) & 0x7f;
681 dockchannel_uart_rd0(void)
683 return (int)((rDOCKCHANNELS_DEV_RDATA1(DOCKCHANNEL_UART_CHANNEL
) >> 8) & 0xff);
687 dockchannel_uart_clear_intr(void)
689 rDOCKCHANNELS_AGENT_AP_INTR_CTRL
&= ~(0x3);
690 rDOCKCHANNELS_AGENT_AP_INTR_STATUS
|= 0x3;
691 rDOCKCHANNELS_AGENT_AP_ERR_INTR_CTRL
&= ~(0x3);
692 rDOCKCHANNELS_AGENT_AP_ERR_INTR_STATUS
|= 0x3;
696 dockchannel_uart_init(void)
699 nanoseconds_to_absolutetime(DOCKCHANNEL_WR_MAX_STALL_US
* NSEC_PER_USEC
, &dockchannel_stall_grace
);
702 // Clear all interrupt enable and status bits
703 dockchannel_uart_clear_intr();
706 rDOCKCHANNELS_DEV_DRAIN_CFG(DOCKCHANNEL_UART_CHANNEL
) = max_dockchannel_drain_period
;
708 // Drain timer doesn't get loaded with value from drain period register if fifo
709 // is already full. Drop a character from the fifo.
710 rDOCKCHANNELS_DOCK_RDATA1(DOCKCHANNEL_UART_CHANNEL
);
713 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) dockchannel_uart_serial_functions
=
715 .uart_init
= dockchannel_uart_init
,
716 .uart_set_baud_rate
= NULL
,
717 .tr0
= dockchannel_uart_tr0
,
718 .td0
= dockchannel_uart_td0
,
719 .rr0
= dockchannel_uart_rr0
,
720 .rd0
= dockchannel_uart_rd0
723 #endif /* DOCKCHANNEL_UART */
725 /****************************************************************************/
727 vm_offset_t pi3_gpio_base_vaddr
= 0;
728 vm_offset_t pi3_aux_base_vaddr
= 0;
732 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x20;
738 BCM2837_PUT32(BCM2837_AUX_MU_IO_REG_V
, (uint32_t) c
);
744 return (int) BCM2837_GET32(BCM2837_AUX_MU_LSR_REG_V
) & 0x01;
750 return (int) BCM2837_GET32(BCM2837_AUX_MU_IO_REG_V
) & 0xff;
759 // Reset mini uart registers
760 BCM2837_PUT32(BCM2837_AUX_ENABLES_V
, 1);
761 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 0);
762 BCM2837_PUT32(BCM2837_AUX_MU_LCR_REG_V
, 3);
763 BCM2837_PUT32(BCM2837_AUX_MU_MCR_REG_V
, 0);
764 BCM2837_PUT32(BCM2837_AUX_MU_IER_REG_V
, 0);
765 BCM2837_PUT32(BCM2837_AUX_MU_IIR_REG_V
, 0xC6);
766 BCM2837_PUT32(BCM2837_AUX_MU_BAUD_REG_V
, 270);
768 i
= BCM2837_FSEL_REG(14);
769 // Configure GPIOs 14 & 15 for alternate function 5
770 i
&= ~(BCM2837_FSEL_MASK(14));
771 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(14));
772 i
&= ~(BCM2837_FSEL_MASK(15));
773 i
|= (BCM2837_FSEL_ALT5
<< BCM2837_FSEL_OFFS(15));
775 BCM2837_PUT32(BCM2837_FSEL_REG(14), i
);
777 BCM2837_PUT32(BCM2837_GPPUD_V
, 0);
779 // Barrier before AP spinning for 150 cycles
780 __builtin_arm_isb(ISB_SY
);
782 for (i
= 0; i
< 150; i
++) {
783 asm volatile ("add x0, x0, xzr");
786 __builtin_arm_isb(ISB_SY
);
788 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, (1 << 14) | (1 << 15));
790 __builtin_arm_isb(ISB_SY
);
792 for (i
= 0; i
< 150; i
++) {
793 asm volatile ("add x0, x0, xzr");
796 __builtin_arm_isb(ISB_SY
);
798 BCM2837_PUT32(BCM2837_GPPUDCLK0_V
, 0);
800 BCM2837_PUT32(BCM2837_AUX_MU_CNTL_REG_V
, 3);
803 SECURITY_READ_ONLY_LATE(static struct pe_serial_functions
) pi3_uart_serial_functions
=
805 .uart_init
= pi3_uart_init
,
806 .uart_set_baud_rate
= NULL
,
813 #endif /* PI3_UART */
814 /*****************************************************************************/
817 register_serial_functions(struct pe_serial_functions
*fns
)
826 DTEntry entryP
= NULL
;
828 vm_offset_t soc_base
;
830 uint32_t *prop_value __unused
= NULL
;
831 char *serial_compat __unused
= 0;
834 struct pe_serial_functions
*fns
= gPESF
;
837 while (fns
!= NULL
) {
841 kprintf("reinit serial\n");
846 if (PE_parse_boot_argn("dcc", &dccmode
, sizeof(dccmode
))) {
847 register_serial_functions(&dcc_serial_functions
);
850 uint32_t jconmode
= 0;
851 if (PE_parse_boot_argn("jcon", &jconmode
, sizeof jconmode
)) {
852 register_serial_functions(&shmcon_serial_functions
);
856 soc_base
= pe_arm_get_soc_base_phys();
863 if (DTFindEntry("name", "gpio", &entryP
) == kSuccess
) {
864 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
865 pi3_gpio_base_vaddr
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
867 if (DTFindEntry("name", "aux", &entryP
) == kSuccess
) {
868 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
869 pi3_aux_base_vaddr
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
871 if ((pi3_gpio_base_vaddr
!= 0) && (pi3_aux_base_vaddr
!= 0)) {
872 register_serial_functions(&pi3_uart_serial_functions
);
874 #endif /* PI3_UART */
877 uint32_t no_dockfifo_uart
= 0;
878 PE_parse_boot_argn("no-dockfifo-uart", &no_dockfifo_uart
, sizeof(no_dockfifo_uart
));
879 if (no_dockfifo_uart
== 0) {
880 if (DTFindEntry("name", "dockfifo-uart", &entryP
) == kSuccess
) {
881 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
882 dockfifo_uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
883 register_serial_functions(&dockfifo_uart_serial_functions
);
886 #endif /* DOCKFIFO_UART */
888 #ifdef DOCKCHANNEL_UART
889 uint32_t no_dockchannel_uart
= 0;
890 if (DTFindEntry("name", "dockchannel-uart", &entryP
) == kSuccess
) {
891 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
892 // Should be two reg entries
893 if (prop_size
/ sizeof(uintptr_t) != 4) {
894 panic("Malformed dockchannel-uart property");
896 dockchannel_uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
897 dock_agent_base
= ml_io_map(soc_base
+ *(reg_prop
+ 2), *(reg_prop
+ 3));
898 PE_parse_boot_argn("no-dockfifo-uart", &no_dockchannel_uart
, sizeof(no_dockchannel_uart
));
899 // Keep the old name for boot-arg
900 if (no_dockchannel_uart
== 0) {
901 register_serial_functions(&dockchannel_uart_serial_functions
);
902 DTGetProperty(entryP
, "max-aop-clk", (void **)&prop_value
, &prop_size
);
903 max_dockchannel_drain_period
= (uint32_t)((prop_value
)? (*prop_value
* 0.03) : DOCKCHANNEL_DRAIN_PERIOD
);
904 DTGetProperty(entryP
, "enable-sw-drain", (void **)&prop_value
, &prop_size
);
905 use_sw_drain
= (prop_value
)? *prop_value
: 0;
907 dockchannel_uart_clear_intr();
909 // If no dockchannel-uart is found in the device tree, fall back
910 // to looking for the traditional UART serial console.
913 #endif /* DOCKCHANNEL_UART */
916 * The boot serial port should have a property named "boot-console".
917 * If we don't find it there, look for "uart0" and "uart1".
920 if (DTFindEntry("boot-console", NULL
, &entryP
) == kSuccess
) {
921 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
922 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
923 if (serial_compat
== 0) {
924 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
926 } else if (DTFindEntry("name", "uart0", &entryP
) == kSuccess
) {
927 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
928 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
929 if (serial_compat
== 0) {
930 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
932 } else if (DTFindEntry("name", "uart1", &entryP
) == kSuccess
) {
933 DTGetProperty(entryP
, "reg", (void **)®_prop
, &prop_size
);
934 uart_base
= ml_io_map(soc_base
+ *reg_prop
, *(reg_prop
+ 1));
935 if (serial_compat
== 0) {
936 DTGetProperty(entryP
, "compatible", (void **)&serial_compat
, &prop_size
);
940 if (NULL
!= entryP
) {
941 DTGetProperty(entryP
, "pclk", (void **)&prop_value
, &prop_size
);
943 dt_pclk
= *prop_value
;
947 DTGetProperty(entryP
, "sampling", (void **)&prop_value
, &prop_size
);
949 dt_sampling
= *prop_value
;
953 DTGetProperty(entryP
, "ubrdiv", (void **)&prop_value
, &prop_size
);
955 dt_ubrdiv
= *prop_value
;
958 if (!strcmp(serial_compat
, "uart,16550")) {
959 register_serial_functions(&ln2410_serial_functions
);
960 } else if (!strcmp(serial_compat
, "uart-16550")) {
961 register_serial_functions(&ln2410_serial_functions
);
962 } else if (!strcmp(serial_compat
, "uart,s5i3000")) {
963 register_serial_functions(&ln2410_serial_functions
);
964 } else if (!strcmp(serial_compat
, "uart-1,samsung")) {
965 register_serial_functions(&ln2410_serial_functions
);
974 while (fns
!= NULL
) {
987 struct pe_serial_functions
*fns
= gPESF
;
988 while (fns
!= NULL
) {
989 while (!fns
->tr0()) {
990 ; /* Wait until THR is empty. */
999 { /* returns -1 if no data available */
1000 struct pe_serial_functions
*fns
= gPESF
;
1001 while (fns
!= NULL
) {