xref: /rk3399_ARM-atf/drivers/ti/uart/aarch32/16550_console.S (revision 6f78eb5cf0c111f91bea4f43b14530169c2df3c9)
1*6f78eb5cSHeiko Stuebner/*
2*6f78eb5cSHeiko Stuebner * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3*6f78eb5cSHeiko Stuebner *
4*6f78eb5cSHeiko Stuebner * SPDX-License-Identifier: BSD-3-Clause
5*6f78eb5cSHeiko Stuebner */
6*6f78eb5cSHeiko Stuebner
7*6f78eb5cSHeiko Stuebner#include <arch.h>
8*6f78eb5cSHeiko Stuebner#include <asm_macros.S>
9*6f78eb5cSHeiko Stuebner#include <assert_macros.S>
10*6f78eb5cSHeiko Stuebner#include <console_macros.S>
11*6f78eb5cSHeiko Stuebner#include <drivers/ti/uart/uart_16550.h>
12*6f78eb5cSHeiko Stuebner
13*6f78eb5cSHeiko Stuebner	/*
14*6f78eb5cSHeiko Stuebner	 * "core" functions are low-level implementations that don't require
15*6f78eb5cSHeiko Stuebner	 * writable memory and are thus safe to call in BL1 crash context.
16*6f78eb5cSHeiko Stuebner	 */
17*6f78eb5cSHeiko Stuebner	.globl console_16550_core_init
18*6f78eb5cSHeiko Stuebner	.globl console_16550_core_putc
19*6f78eb5cSHeiko Stuebner	.globl console_16550_core_getc
20*6f78eb5cSHeiko Stuebner	.globl console_16550_core_flush
21*6f78eb5cSHeiko Stuebner
22*6f78eb5cSHeiko Stuebner	.globl console_16550_putc
23*6f78eb5cSHeiko Stuebner	.globl console_16550_getc
24*6f78eb5cSHeiko Stuebner	.globl console_16550_flush
25*6f78eb5cSHeiko Stuebner
26*6f78eb5cSHeiko Stuebner	/* -----------------------------------------------
27*6f78eb5cSHeiko Stuebner	 * int console_16550_core_init(uintptr_t base_addr,
28*6f78eb5cSHeiko Stuebner	 * unsigned int uart_clk, unsigned int baud_rate)
29*6f78eb5cSHeiko Stuebner	 * Function to initialize the console without a
30*6f78eb5cSHeiko Stuebner	 * C Runtime to print debug information. This
31*6f78eb5cSHeiko Stuebner	 * function will be accessed by console_init and
32*6f78eb5cSHeiko Stuebner	 * crash reporting.
33*6f78eb5cSHeiko Stuebner	 * In: r0 - console base address
34*6f78eb5cSHeiko Stuebner	 *     r1 - Uart clock in Hz
35*6f78eb5cSHeiko Stuebner	 *     r2 - Baud rate
36*6f78eb5cSHeiko Stuebner	 * Out: return 1 on success, 0 on error
37*6f78eb5cSHeiko Stuebner	 * Clobber list : r1, r2, r3
38*6f78eb5cSHeiko Stuebner	 * -----------------------------------------------
39*6f78eb5cSHeiko Stuebner	 */
40*6f78eb5cSHeiko Stuebnerfunc console_16550_core_init
41*6f78eb5cSHeiko Stuebner	/* Check the input base address */
42*6f78eb5cSHeiko Stuebner	cmp	r0, #0
43*6f78eb5cSHeiko Stuebner	beq	init_fail
44*6f78eb5cSHeiko Stuebner	/* Check baud rate and uart clock for sanity */
45*6f78eb5cSHeiko Stuebner	cmp	r1, #0
46*6f78eb5cSHeiko Stuebner	beq	init_fail
47*6f78eb5cSHeiko Stuebner	cmp	r2, #0
48*6f78eb5cSHeiko Stuebner	beq	init_fail
49*6f78eb5cSHeiko Stuebner
50*6f78eb5cSHeiko Stuebner	/* Program the baudrate */
51*6f78eb5cSHeiko Stuebner	/* Divisor =  Uart clock / (16 * baudrate) */
52*6f78eb5cSHeiko Stuebner	lsl	r2, r2, #4
53*6f78eb5cSHeiko Stuebner	udiv	r2, r1, r2
54*6f78eb5cSHeiko Stuebner	and	r1, r2, #0xff		/* w1 = DLL */
55*6f78eb5cSHeiko Stuebner	lsr	r2, r2, #8
56*6f78eb5cSHeiko Stuebner	and	r2, r2, #0xff		/* w2 = DLLM */
57*6f78eb5cSHeiko Stuebner	ldr	r3, [r0, #UARTLCR]
58*6f78eb5cSHeiko Stuebner	orr	r3, r3, #UARTLCR_DLAB
59*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTLCR]	/* enable DLL, DLLM programming */
60*6f78eb5cSHeiko Stuebner	str	r1, [r0, #UARTDLL]	/* program DLL */
61*6f78eb5cSHeiko Stuebner	str	r2, [r0, #UARTDLLM]	/* program DLLM */
62*6f78eb5cSHeiko Stuebner	mov	r2, #~UARTLCR_DLAB
63*6f78eb5cSHeiko Stuebner	and	r3, r3, r2
64*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTLCR]	/* disable DLL, DLLM programming */
65*6f78eb5cSHeiko Stuebner
66*6f78eb5cSHeiko Stuebner	/* 8n1 */
67*6f78eb5cSHeiko Stuebner	mov	r3, #3
68*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTLCR]
69*6f78eb5cSHeiko Stuebner	/* no interrupt */
70*6f78eb5cSHeiko Stuebner	mov	r3, #0
71*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTIER]
72*6f78eb5cSHeiko Stuebner#ifdef TI_16550_MDR_QUIRK
73*6f78eb5cSHeiko Stuebner	/* UART must be enabled on some platforms via the MDR register */
74*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTMDR1]
75*6f78eb5cSHeiko Stuebner#endif /* TI_16550_MDR_QUIRK */
76*6f78eb5cSHeiko Stuebner	/* enable fifo, DMA */
77*6f78eb5cSHeiko Stuebner	mov	r3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN)
78*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTFCR]
79*6f78eb5cSHeiko Stuebner	/* DTR + RTS */
80*6f78eb5cSHeiko Stuebner	mov	r3, #3
81*6f78eb5cSHeiko Stuebner	str	r3, [r0, #UARTMCR]
82*6f78eb5cSHeiko Stuebner	mov	r0, #1
83*6f78eb5cSHeiko Stuebner	bx	lr
84*6f78eb5cSHeiko Stuebnerinit_fail:
85*6f78eb5cSHeiko Stuebner	mov	r0, #0
86*6f78eb5cSHeiko Stuebner	bx	lr
87*6f78eb5cSHeiko Stuebnerendfunc console_16550_core_init
88*6f78eb5cSHeiko Stuebner
89*6f78eb5cSHeiko Stuebner	.globl console_16550_register
90*6f78eb5cSHeiko Stuebner
91*6f78eb5cSHeiko Stuebner	/* -------------------------------------------------------
92*6f78eb5cSHeiko Stuebner	 * int console_stm32_register(uintptr_t baseaddr,
93*6f78eb5cSHeiko Stuebner	 *     uint32_t clock, uint32_t baud,
94*6f78eb5cSHeiko Stuebner	 *     struct console_stm32 *console);
95*6f78eb5cSHeiko Stuebner	 * Function to initialize and register a new STM32
96*6f78eb5cSHeiko Stuebner	 * console. Storage passed in for the console struct
97*6f78eb5cSHeiko Stuebner	 * *must* be persistent (i.e. not from the stack).
98*6f78eb5cSHeiko Stuebner	 * In: r0 - UART register base address
99*6f78eb5cSHeiko Stuebner	 *     r1 - UART clock in Hz
100*6f78eb5cSHeiko Stuebner	 *     r2 - Baud rate
101*6f78eb5cSHeiko Stuebner	 *     r3 - pointer to empty console_stm32 struct
102*6f78eb5cSHeiko Stuebner	 * Out: return 1 on success, 0 on error
103*6f78eb5cSHeiko Stuebner	 * Clobber list : r0, r1, r2
104*6f78eb5cSHeiko Stuebner	 * -------------------------------------------------------
105*6f78eb5cSHeiko Stuebner	 */
106*6f78eb5cSHeiko Stuebnerfunc console_16550_register
107*6f78eb5cSHeiko Stuebner	push	{r4, lr}
108*6f78eb5cSHeiko Stuebner	mov	r4, r3
109*6f78eb5cSHeiko Stuebner	cmp	r4, #0
110*6f78eb5cSHeiko Stuebner	beq	register_fail
111*6f78eb5cSHeiko Stuebner	str	r0, [r4, #CONSOLE_T_16550_BASE]
112*6f78eb5cSHeiko Stuebner
113*6f78eb5cSHeiko Stuebner	bl	console_16550_core_init
114*6f78eb5cSHeiko Stuebner	cmp	r0, #0
115*6f78eb5cSHeiko Stuebner	beq	register_fail
116*6f78eb5cSHeiko Stuebner
117*6f78eb5cSHeiko Stuebner	mov	r0, r4
118*6f78eb5cSHeiko Stuebner	pop	{r4, lr}
119*6f78eb5cSHeiko Stuebner	finish_console_register 16550 putc=1, getc=1, flush=1
120*6f78eb5cSHeiko Stuebner
121*6f78eb5cSHeiko Stuebnerregister_fail:
122*6f78eb5cSHeiko Stuebner	pop	{r4, pc}
123*6f78eb5cSHeiko Stuebnerendfunc console_16550_register
124*6f78eb5cSHeiko Stuebner
125*6f78eb5cSHeiko Stuebner	/* --------------------------------------------------------
126*6f78eb5cSHeiko Stuebner	 * int console_16550_core_putc(int c, uintptr_t base_addr)
127*6f78eb5cSHeiko Stuebner	 * Function to output a character over the console. It
128*6f78eb5cSHeiko Stuebner	 * returns the character printed on success or -1 on error.
129*6f78eb5cSHeiko Stuebner	 * In : r0 - character to be printed
130*6f78eb5cSHeiko Stuebner	 *      r1 - console base address
131*6f78eb5cSHeiko Stuebner	 * Out : return -1 on error else return character.
132*6f78eb5cSHeiko Stuebner	 * Clobber list : r2
133*6f78eb5cSHeiko Stuebner	 * --------------------------------------------------------
134*6f78eb5cSHeiko Stuebner	 */
135*6f78eb5cSHeiko Stuebnerfunc console_16550_core_putc
136*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
137*6f78eb5cSHeiko Stuebner	cmp	r1, #0
138*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
139*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
140*6f78eb5cSHeiko Stuebner
141*6f78eb5cSHeiko Stuebner	/* Prepend '\r' to '\n' */
142*6f78eb5cSHeiko Stuebner	cmp	r0, #0xA
143*6f78eb5cSHeiko Stuebner	bne	2f
144*6f78eb5cSHeiko Stuebner	/* Check if the transmit FIFO is full */
145*6f78eb5cSHeiko Stuebner1:	ldr	r2, [r1, #UARTLSR]
146*6f78eb5cSHeiko Stuebner	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
147*6f78eb5cSHeiko Stuebner	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
148*6f78eb5cSHeiko Stuebner	bne	1b
149*6f78eb5cSHeiko Stuebner	mov	r2, #0xD		/* '\r' */
150*6f78eb5cSHeiko Stuebner	str	r2, [r1, #UARTTX]
151*6f78eb5cSHeiko Stuebner
152*6f78eb5cSHeiko Stuebner	/* Check if the transmit FIFO is full */
153*6f78eb5cSHeiko Stuebner2:	ldr	r2, [r1, #UARTLSR]
154*6f78eb5cSHeiko Stuebner	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
155*6f78eb5cSHeiko Stuebner	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
156*6f78eb5cSHeiko Stuebner	bne	2b
157*6f78eb5cSHeiko Stuebner	str	r0, [r1, #UARTTX]
158*6f78eb5cSHeiko Stuebner	bx	lr
159*6f78eb5cSHeiko Stuebnerendfunc console_16550_core_putc
160*6f78eb5cSHeiko Stuebner
161*6f78eb5cSHeiko Stuebner	/* --------------------------------------------------------
162*6f78eb5cSHeiko Stuebner	 * int console_16550_putc(int c, console_16550_t *console)
163*6f78eb5cSHeiko Stuebner	 * Function to output a character over the console. It
164*6f78eb5cSHeiko Stuebner	 * returns the character printed on success or -1 on error.
165*6f78eb5cSHeiko Stuebner	 * In : r0 - character to be printed
166*6f78eb5cSHeiko Stuebner	 *      r1 - pointer to console_t structure
167*6f78eb5cSHeiko Stuebner	 * Out : return -1 on error else return character.
168*6f78eb5cSHeiko Stuebner	 * Clobber list : r2
169*6f78eb5cSHeiko Stuebner	 * --------------------------------------------------------
170*6f78eb5cSHeiko Stuebner	 */
171*6f78eb5cSHeiko Stuebnerfunc console_16550_putc
172*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
173*6f78eb5cSHeiko Stuebner	cmp	r1, #0
174*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
175*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
176*6f78eb5cSHeiko Stuebner	ldr	r1, [r1, #CONSOLE_T_16550_BASE]
177*6f78eb5cSHeiko Stuebner	b	console_16550_core_putc
178*6f78eb5cSHeiko Stuebnerendfunc console_16550_putc
179*6f78eb5cSHeiko Stuebner
180*6f78eb5cSHeiko Stuebner	/* ---------------------------------------------
181*6f78eb5cSHeiko Stuebner	 * int console_16550_core_getc(uintptr_t base_addr)
182*6f78eb5cSHeiko Stuebner	 * Function to get a character from the console.
183*6f78eb5cSHeiko Stuebner	 * It returns the character grabbed on success
184*6f78eb5cSHeiko Stuebner	 * or -1 on if no character is available.
185*6f78eb5cSHeiko Stuebner	 * In :  r0 - console base address
186*6f78eb5cSHeiko Stuebner	 * Clobber list : r0, r1
187*6f78eb5cSHeiko Stuebner	 * ---------------------------------------------
188*6f78eb5cSHeiko Stuebner	 */
189*6f78eb5cSHeiko Stuebnerfunc console_16550_core_getc
190*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
191*6f78eb5cSHeiko Stuebner	cmp	r0, #0
192*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
193*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
194*6f78eb5cSHeiko Stuebner
195*6f78eb5cSHeiko Stuebner	/* Check if the receive FIFO is empty */
196*6f78eb5cSHeiko Stuebner1:	ldr	r1, [r0, #UARTLSR]
197*6f78eb5cSHeiko Stuebner	tst	r1, #UARTLSR_RDR_BIT
198*6f78eb5cSHeiko Stuebner	beq	no_char
199*6f78eb5cSHeiko Stuebner	ldr	r1, [r0, #UARTRX]
200*6f78eb5cSHeiko Stuebner	mov	r0, r1
201*6f78eb5cSHeiko Stuebner	bx	lr
202*6f78eb5cSHeiko Stuebnerno_char:
203*6f78eb5cSHeiko Stuebner	mov	r0, #ERROR_NO_PENDING_CHAR
204*6f78eb5cSHeiko Stuebner	bx	lr
205*6f78eb5cSHeiko Stuebnerendfunc console_16550_core_getc
206*6f78eb5cSHeiko Stuebner
207*6f78eb5cSHeiko Stuebner	/* ---------------------------------------------
208*6f78eb5cSHeiko Stuebner	 * int console_16550_getc(console_16550_t *console)
209*6f78eb5cSHeiko Stuebner	 * Function to get a character from the console.
210*6f78eb5cSHeiko Stuebner	 * It returns the character grabbed on success
211*6f78eb5cSHeiko Stuebner	 * or -1 on if no character is available.
212*6f78eb5cSHeiko Stuebner	 * In :  r0 - pointer to console_t stucture
213*6f78eb5cSHeiko Stuebner	 * Out : r0 - character if available, else -1
214*6f78eb5cSHeiko Stuebner	 * Clobber list : r0, r1
215*6f78eb5cSHeiko Stuebner	 * ---------------------------------------------
216*6f78eb5cSHeiko Stuebner	 */
217*6f78eb5cSHeiko Stuebnerfunc console_16550_getc
218*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
219*6f78eb5cSHeiko Stuebner	cmp	r0, #0
220*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
221*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
222*6f78eb5cSHeiko Stuebner	ldr	r0, [r0, #CONSOLE_T_16550_BASE]
223*6f78eb5cSHeiko Stuebner	b	console_16550_core_getc
224*6f78eb5cSHeiko Stuebnerendfunc console_16550_getc
225*6f78eb5cSHeiko Stuebner
226*6f78eb5cSHeiko Stuebner	/* ---------------------------------------------
227*6f78eb5cSHeiko Stuebner	 * int console_16550_core_flush(uintptr_t base_addr)
228*6f78eb5cSHeiko Stuebner	 * Function to force a write of all buffered
229*6f78eb5cSHeiko Stuebner	 * data that hasn't been output.
230*6f78eb5cSHeiko Stuebner	 * In : r0 - console base address
231*6f78eb5cSHeiko Stuebner	 * Out : return -1 on error else return 0.
232*6f78eb5cSHeiko Stuebner	 * Clobber list : r0, r1
233*6f78eb5cSHeiko Stuebner	 * ---------------------------------------------
234*6f78eb5cSHeiko Stuebner	 */
235*6f78eb5cSHeiko Stuebnerfunc console_16550_core_flush
236*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
237*6f78eb5cSHeiko Stuebner	cmp	r0, #0
238*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
239*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
240*6f78eb5cSHeiko Stuebner
241*6f78eb5cSHeiko Stuebner	/* Loop until the transmit FIFO is empty */
242*6f78eb5cSHeiko Stuebner1:	ldr	r1, [r0, #UARTLSR]
243*6f78eb5cSHeiko Stuebner	and	r1, r1, #(UARTLSR_TEMT | UARTLSR_THRE)
244*6f78eb5cSHeiko Stuebner	cmp	r1, #(UARTLSR_TEMT | UARTLSR_THRE)
245*6f78eb5cSHeiko Stuebner	bne	1b
246*6f78eb5cSHeiko Stuebner
247*6f78eb5cSHeiko Stuebner	mov	r0, #0
248*6f78eb5cSHeiko Stuebner	bx	lr
249*6f78eb5cSHeiko Stuebnerendfunc console_16550_core_flush
250*6f78eb5cSHeiko Stuebner
251*6f78eb5cSHeiko Stuebner	/* ---------------------------------------------
252*6f78eb5cSHeiko Stuebner	 * int console_16550_flush(console_pl011_t *console)
253*6f78eb5cSHeiko Stuebner	 * Function to force a write of all buffered
254*6f78eb5cSHeiko Stuebner	 * data that hasn't been output.
255*6f78eb5cSHeiko Stuebner	 * In : r0 - pointer to console_t structure
256*6f78eb5cSHeiko Stuebner	 * Out : return -1 on error else return 0.
257*6f78eb5cSHeiko Stuebner	 * Clobber list : r0, r1
258*6f78eb5cSHeiko Stuebner	 * ---------------------------------------------
259*6f78eb5cSHeiko Stuebner	 */
260*6f78eb5cSHeiko Stuebnerfunc console_16550_flush
261*6f78eb5cSHeiko Stuebner#if ENABLE_ASSERTIONS
262*6f78eb5cSHeiko Stuebner	cmp	r0, #0
263*6f78eb5cSHeiko Stuebner	ASM_ASSERT(ne)
264*6f78eb5cSHeiko Stuebner#endif /* ENABLE_ASSERTIONS */
265*6f78eb5cSHeiko Stuebner	ldr	r0, [r0, #CONSOLE_T_16550_BASE]
266*6f78eb5cSHeiko Stuebner	b	console_16550_core_flush
267*6f78eb5cSHeiko Stuebnerendfunc console_16550_flush
268