xref: /rk3399_ARM-atf/drivers/imx/uart/imx_uart.c (revision 598cee482ad6ee712b09b266d2430386312f4de2)
1*598cee48SBryan O'Donoghue /*
2*598cee48SBryan O'Donoghue  * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
3*598cee48SBryan O'Donoghue  *
4*598cee48SBryan O'Donoghue  * SPDX-License-Identifier: BSD-3-Clause
5*598cee48SBryan O'Donoghue  */
6*598cee48SBryan O'Donoghue #include <arch.h>
7*598cee48SBryan O'Donoghue #include <stdint.h>
8*598cee48SBryan O'Donoghue #include <mmio.h>
9*598cee48SBryan O'Donoghue #include <platform_def.h>
10*598cee48SBryan O'Donoghue #include <imx_uart.h>
11*598cee48SBryan O'Donoghue 
12*598cee48SBryan O'Donoghue /* TX/RX FIFO threshold */
13*598cee48SBryan O'Donoghue #define TX_RX_THRESH 2
14*598cee48SBryan O'Donoghue 
15*598cee48SBryan O'Donoghue struct clk_div_factors {
16*598cee48SBryan O'Donoghue 	uint32_t fcr_div;
17*598cee48SBryan O'Donoghue 	uint32_t bmr_div;
18*598cee48SBryan O'Donoghue };
19*598cee48SBryan O'Donoghue 
20*598cee48SBryan O'Donoghue static struct clk_div_factors clk_div[] = {
21*598cee48SBryan O'Donoghue 	{
22*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV1,
23*598cee48SBryan O'Donoghue 		.bmr_div = 1,
24*598cee48SBryan O'Donoghue 	},
25*598cee48SBryan O'Donoghue 	{
26*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV2,
27*598cee48SBryan O'Donoghue 		.bmr_div = 2,
28*598cee48SBryan O'Donoghue 	},
29*598cee48SBryan O'Donoghue 	{
30*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV3,
31*598cee48SBryan O'Donoghue 		.bmr_div = 3,
32*598cee48SBryan O'Donoghue 	},
33*598cee48SBryan O'Donoghue 	{
34*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV4,
35*598cee48SBryan O'Donoghue 		.bmr_div = 4,
36*598cee48SBryan O'Donoghue 	},
37*598cee48SBryan O'Donoghue 	{
38*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV5,
39*598cee48SBryan O'Donoghue 		.bmr_div = 5,
40*598cee48SBryan O'Donoghue 	},
41*598cee48SBryan O'Donoghue 	{
42*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV6,
43*598cee48SBryan O'Donoghue 		.bmr_div = 6,
44*598cee48SBryan O'Donoghue 	},
45*598cee48SBryan O'Donoghue 	{
46*598cee48SBryan O'Donoghue 		.fcr_div = IMX_UART_FCR_RFDIV7,
47*598cee48SBryan O'Donoghue 		.bmr_div = 7,
48*598cee48SBryan O'Donoghue 	},
49*598cee48SBryan O'Donoghue };
50*598cee48SBryan O'Donoghue 
51*598cee48SBryan O'Donoghue static void write_reg(uintptr_t base, uint32_t offset, uint32_t val)
52*598cee48SBryan O'Donoghue {
53*598cee48SBryan O'Donoghue 	mmio_write_32(base + offset, val);
54*598cee48SBryan O'Donoghue }
55*598cee48SBryan O'Donoghue 
56*598cee48SBryan O'Donoghue static uint32_t read_reg(uintptr_t base, uint32_t offset)
57*598cee48SBryan O'Donoghue {
58*598cee48SBryan O'Donoghue 	return mmio_read_32(base + offset);
59*598cee48SBryan O'Donoghue }
60*598cee48SBryan O'Donoghue 
61*598cee48SBryan O'Donoghue int console_core_init(uintptr_t base_addr, unsigned int uart_clk,
62*598cee48SBryan O'Donoghue 		      unsigned int baud_rate)
63*598cee48SBryan O'Donoghue {
64*598cee48SBryan O'Donoghue 	uint32_t val;
65*598cee48SBryan O'Donoghue 	uint8_t clk_idx = 1;
66*598cee48SBryan O'Donoghue 
67*598cee48SBryan O'Donoghue 	/* Reset UART */
68*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_CR2_OFFSET, 0);
69*598cee48SBryan O'Donoghue 	do {
70*598cee48SBryan O'Donoghue 		val = read_reg(base_addr, IMX_UART_CR2_OFFSET);
71*598cee48SBryan O'Donoghue 	} while (!(val & IMX_UART_CR2_SRST));
72*598cee48SBryan O'Donoghue 
73*598cee48SBryan O'Donoghue 	/* Enable UART */
74*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN);
75*598cee48SBryan O'Donoghue 
76*598cee48SBryan O'Donoghue 	/* Ignore RTS, 8N1, enable tx/rx, disable reset */
77*598cee48SBryan O'Donoghue 	val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN |
78*598cee48SBryan O'Donoghue 	       IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST);
79*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_CR2_OFFSET, val);
80*598cee48SBryan O'Donoghue 
81*598cee48SBryan O'Donoghue 	/* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */
82*598cee48SBryan O'Donoghue 	val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL;
83*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_CR3_OFFSET, val);
84*598cee48SBryan O'Donoghue 
85*598cee48SBryan O'Donoghue 	/* Set CTS FIFO trigger to 32 bytes bits 15:10 */
86*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000);
87*598cee48SBryan O'Donoghue 
88*598cee48SBryan O'Donoghue 	/* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */
89*598cee48SBryan O'Donoghue 	val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) |
90*598cee48SBryan O'Donoghue 	      clk_div[clk_idx].fcr_div;
91*598cee48SBryan O'Donoghue 	#ifdef IMX_UART_DTE
92*598cee48SBryan O'Donoghue 		/* Set DTE (bit6 = 1) */
93*598cee48SBryan O'Donoghue 		val |= IMX_UART_FCR_DCEDTE;
94*598cee48SBryan O'Donoghue 	#endif
95*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_FCR_OFFSET, val);
96*598cee48SBryan O'Donoghue 
97*598cee48SBryan O'Donoghue 	/*
98*598cee48SBryan O'Donoghue 	 * The equation for BAUD rate calculation is
99*598cee48SBryan O'Donoghue 	 * RefClk = Supplied clock / FCR_DIVx
100*598cee48SBryan O'Donoghue 	 *
101*598cee48SBryan O'Donoghue 	 * BAUD  =    Refclk
102*598cee48SBryan O'Donoghue 	 *         ------------
103*598cee48SBryan O'Donoghue 	 *       16 x (UBMR + 1/ UBIR + 1)
104*598cee48SBryan O'Donoghue 	 *
105*598cee48SBryan O'Donoghue 	 * We write 0x0f into UBIR to remove the 16 mult
106*598cee48SBryan O'Donoghue 	 * BAUD  =    6000000
107*598cee48SBryan O'Donoghue 	 *         ------------
108*598cee48SBryan O'Donoghue 	 *       16 x (UBMR + 1/ 15 + 1)
109*598cee48SBryan O'Donoghue 	 */
110*598cee48SBryan O'Donoghue 
111*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f);
112*598cee48SBryan O'Donoghue 	val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1;
113*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_BMR_OFFSET, val);
114*598cee48SBryan O'Donoghue 
115*598cee48SBryan O'Donoghue 	return 0;
116*598cee48SBryan O'Donoghue }
117*598cee48SBryan O'Donoghue 
118*598cee48SBryan O'Donoghue /* --------------------------------------------------------
119*598cee48SBryan O'Donoghue  * int console_core_putc(int c, uintptr_t base_addr)
120*598cee48SBryan O'Donoghue  * Function to output a character over the console. It
121*598cee48SBryan O'Donoghue  * returns the character printed on success or -1 on error.
122*598cee48SBryan O'Donoghue  * In : r0 - character to be printed
123*598cee48SBryan O'Donoghue  *      r1 - console base address
124*598cee48SBryan O'Donoghue  * Out : return -1 on error else return character.
125*598cee48SBryan O'Donoghue  * Clobber list : r2
126*598cee48SBryan O'Donoghue  * --------------------------------------------------------
127*598cee48SBryan O'Donoghue  */
128*598cee48SBryan O'Donoghue int console_core_putc(int c, uintptr_t base_addr)
129*598cee48SBryan O'Donoghue {
130*598cee48SBryan O'Donoghue 	uint32_t val;
131*598cee48SBryan O'Donoghue 
132*598cee48SBryan O'Donoghue 	if (c == '\n')
133*598cee48SBryan O'Donoghue 		console_core_putc('\r', base_addr);
134*598cee48SBryan O'Donoghue 
135*598cee48SBryan O'Donoghue 	/* Write data */
136*598cee48SBryan O'Donoghue 	write_reg(base_addr, IMX_UART_TXD_OFFSET, c);
137*598cee48SBryan O'Donoghue 
138*598cee48SBryan O'Donoghue 	/* Wait for transmit */
139*598cee48SBryan O'Donoghue 	do {
140*598cee48SBryan O'Donoghue 		val = read_reg(base_addr, IMX_UART_STAT2_OFFSET);
141*598cee48SBryan O'Donoghue 	} while (!(val & IMX_UART_STAT2_TXDC));
142*598cee48SBryan O'Donoghue 
143*598cee48SBryan O'Donoghue 	return 0;
144*598cee48SBryan O'Donoghue }
145*598cee48SBryan O'Donoghue 
146*598cee48SBryan O'Donoghue /*
147*598cee48SBryan O'Donoghue  * Function to get a character from the console.
148*598cee48SBryan O'Donoghue  * It returns the character grabbed on success
149*598cee48SBryan O'Donoghue  * or -1 on error.
150*598cee48SBryan O'Donoghue  * In : r0 - console base address
151*598cee48SBryan O'Donoghue  * Clobber list : r0, r1
152*598cee48SBryan O'Donoghue  * ---------------------------------------------
153*598cee48SBryan O'Donoghue  */
154*598cee48SBryan O'Donoghue int console_core_getc(uintptr_t base_addr)
155*598cee48SBryan O'Donoghue {
156*598cee48SBryan O'Donoghue 	uint32_t val;
157*598cee48SBryan O'Donoghue 
158*598cee48SBryan O'Donoghue 	val = read_reg(base_addr, IMX_UART_TS_OFFSET);
159*598cee48SBryan O'Donoghue 	if (val & IMX_UART_TS_RXEMPTY)
160*598cee48SBryan O'Donoghue 		return -1;
161*598cee48SBryan O'Donoghue 
162*598cee48SBryan O'Donoghue 	val = read_reg(base_addr, IMX_UART_RXD_OFFSET);
163*598cee48SBryan O'Donoghue 	return (int)(val & 0x000000FF);
164*598cee48SBryan O'Donoghue }
165*598cee48SBryan O'Donoghue 
166*598cee48SBryan O'Donoghue /*
167*598cee48SBryan O'Donoghue  * Function to force a write of all buffered
168*598cee48SBryan O'Donoghue  * data that hasn't been output.
169*598cee48SBryan O'Donoghue  * In : r0 - console base address
170*598cee48SBryan O'Donoghue  * Out : return -1 on error else return 0.
171*598cee48SBryan O'Donoghue  * Clobber list : r0, r1
172*598cee48SBryan O'Donoghue  * ---------------------------------------------
173*598cee48SBryan O'Donoghue  */
174*598cee48SBryan O'Donoghue int console_core_flush(uintptr_t base_addr)
175*598cee48SBryan O'Donoghue {
176*598cee48SBryan O'Donoghue 	return 0;
177*598cee48SBryan O'Donoghue }
178*598cee48SBryan O'Donoghue 
179