xref: /rk3399_rockchip-uboot/drivers/serial/serial_pxa.c (revision abc20aba1834c321a638b367c18dcce1bb4e232d)
1379be585SJean-Christophe PLAGNIOL-VILLARD /*
2237ce0feSMarek Vasut  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
3237ce0feSMarek Vasut  *
4379be585SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2002
5379be585SJean-Christophe PLAGNIOL-VILLARD  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
6379be585SJean-Christophe PLAGNIOL-VILLARD  *
7379be585SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2002
8379be585SJean-Christophe PLAGNIOL-VILLARD  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
9379be585SJean-Christophe PLAGNIOL-VILLARD  * Marius Groeger <mgroeger@sysgo.de>
10379be585SJean-Christophe PLAGNIOL-VILLARD  *
11379be585SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2002
12379be585SJean-Christophe PLAGNIOL-VILLARD  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
13379be585SJean-Christophe PLAGNIOL-VILLARD  * Alex Zuepke <azu@sysgo.de>
14379be585SJean-Christophe PLAGNIOL-VILLARD  *
15379be585SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
16379be585SJean-Christophe PLAGNIOL-VILLARD  *
17379be585SJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or modify
18379be585SJean-Christophe PLAGNIOL-VILLARD  * it under the terms of the GNU General Public License as published by
19379be585SJean-Christophe PLAGNIOL-VILLARD  * the Free Software Foundation; either version 2 of the License, or
20379be585SJean-Christophe PLAGNIOL-VILLARD  * (at your option) any later version.
21379be585SJean-Christophe PLAGNIOL-VILLARD  *
22379be585SJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
23379be585SJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24379be585SJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25379be585SJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
26379be585SJean-Christophe PLAGNIOL-VILLARD  *
27379be585SJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
28379be585SJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
29379be585SJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30379be585SJean-Christophe PLAGNIOL-VILLARD  *
31379be585SJean-Christophe PLAGNIOL-VILLARD  */
32379be585SJean-Christophe PLAGNIOL-VILLARD 
33379be585SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
34379be585SJean-Christophe PLAGNIOL-VILLARD #include <watchdog.h>
35379be585SJean-Christophe PLAGNIOL-VILLARD #include <serial.h>
36379be585SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/pxa-regs.h>
37237ce0feSMarek Vasut #include <asm/arch/regs-uart.h>
383ba8bf7cSMarek Vasut #include <asm/io.h>
39379be585SJean-Christophe PLAGNIOL-VILLARD 
40379be585SJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR;
41379be585SJean-Christophe PLAGNIOL-VILLARD 
42237ce0feSMarek Vasut /*
43237ce0feSMarek Vasut  * The numbering scheme differs here for PXA25x, PXA27x and PXA3xx so we can
44237ce0feSMarek Vasut  * easily handle enabling of clock.
45237ce0feSMarek Vasut  */
46237ce0feSMarek Vasut #ifdef	CONFIG_CPU_MONAHANS
47237ce0feSMarek Vasut #define	UART_CLK_BASE	CKENA_21_BTUART
48237ce0feSMarek Vasut #define	UART_CLK_REG	CKENA
49237ce0feSMarek Vasut #define	BTUART_INDEX	0
50237ce0feSMarek Vasut #define	FFUART_INDEX	1
51379be585SJean-Christophe PLAGNIOL-VILLARD #define	STUART_INDEX	2
52*abc20abaSMarek Vasut #elif	CONFIG_CPU_PXA25X
53237ce0feSMarek Vasut #define	UART_CLK_BASE	(1 << 4)	/* HWUART */
54237ce0feSMarek Vasut #define	UART_CLK_REG	CKEN
55237ce0feSMarek Vasut #define	HWUART_INDEX	0
56237ce0feSMarek Vasut #define	STUART_INDEX	1
57237ce0feSMarek Vasut #define	FFUART_INDEX	2
58237ce0feSMarek Vasut #define	BTUART_INDEX	3
59237ce0feSMarek Vasut #else	/* PXA27x */
60237ce0feSMarek Vasut #define	UART_CLK_BASE	CKEN5_STUART
61237ce0feSMarek Vasut #define	UART_CLK_REG	CKEN
62237ce0feSMarek Vasut #define	STUART_INDEX	0
63237ce0feSMarek Vasut #define	FFUART_INDEX	1
64237ce0feSMarek Vasut #define	BTUART_INDEX	2
65237ce0feSMarek Vasut #endif
66237ce0feSMarek Vasut 
67237ce0feSMarek Vasut /*
68237ce0feSMarek Vasut  * Only PXA250 has HWUART, to avoid poluting the code with more macros,
69237ce0feSMarek Vasut  * artificially introduce this.
70237ce0feSMarek Vasut  */
71*abc20abaSMarek Vasut #ifndef	CONFIG_CPU_PXA25X
72237ce0feSMarek Vasut #define	HWUART_INDEX	0xff
73237ce0feSMarek Vasut #endif
74379be585SJean-Christophe PLAGNIOL-VILLARD 
75379be585SJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SERIAL_MULTI
76379be585SJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_FFUART)
77379be585SJean-Christophe PLAGNIOL-VILLARD #define UART_INDEX	FFUART_INDEX
78379be585SJean-Christophe PLAGNIOL-VILLARD #elif defined(CONFIG_BTUART)
79379be585SJean-Christophe PLAGNIOL-VILLARD #define UART_INDEX	BTUART_INDEX
80379be585SJean-Christophe PLAGNIOL-VILLARD #elif defined(CONFIG_STUART)
81379be585SJean-Christophe PLAGNIOL-VILLARD #define UART_INDEX	STUART_INDEX
82237ce0feSMarek Vasut #elif defined(CONFIG_HWUART)
83237ce0feSMarek Vasut #define UART_INDEX	HWUART_INDEX
84379be585SJean-Christophe PLAGNIOL-VILLARD #else
85237ce0feSMarek Vasut #error "Please select CONFIG_(FF|BT|ST|HW)UART in board config file."
86379be585SJean-Christophe PLAGNIOL-VILLARD #endif
87379be585SJean-Christophe PLAGNIOL-VILLARD #endif
88379be585SJean-Christophe PLAGNIOL-VILLARD 
89237ce0feSMarek Vasut uint32_t pxa_uart_get_baud_divider(void)
90379be585SJean-Christophe PLAGNIOL-VILLARD {
91379be585SJean-Christophe PLAGNIOL-VILLARD 	if (gd->baudrate == 1200)
92237ce0feSMarek Vasut 		return 768;
93379be585SJean-Christophe PLAGNIOL-VILLARD 	else if (gd->baudrate == 9600)
94237ce0feSMarek Vasut 		return 96;
95379be585SJean-Christophe PLAGNIOL-VILLARD 	else if (gd->baudrate == 19200)
96237ce0feSMarek Vasut 		return 48;
97379be585SJean-Christophe PLAGNIOL-VILLARD 	else if (gd->baudrate == 38400)
98237ce0feSMarek Vasut 		return 24;
99379be585SJean-Christophe PLAGNIOL-VILLARD 	else if (gd->baudrate == 57600)
100237ce0feSMarek Vasut 		return 16;
101379be585SJean-Christophe PLAGNIOL-VILLARD 	else if (gd->baudrate == 115200)
102237ce0feSMarek Vasut 		return 8;
103237ce0feSMarek Vasut 	else	/* Unsupported baudrate */
104237ce0feSMarek Vasut 		return 0;
105237ce0feSMarek Vasut }
106379be585SJean-Christophe PLAGNIOL-VILLARD 
107237ce0feSMarek Vasut struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index)
108237ce0feSMarek Vasut {
109379be585SJean-Christophe PLAGNIOL-VILLARD 	switch (uart_index) {
110237ce0feSMarek Vasut 	case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE;
111237ce0feSMarek Vasut 	case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE;
112237ce0feSMarek Vasut 	case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE;
113237ce0feSMarek Vasut 	case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE;
114379be585SJean-Christophe PLAGNIOL-VILLARD 	default:
115237ce0feSMarek Vasut 		return NULL;
116379be585SJean-Christophe PLAGNIOL-VILLARD 	}
117379be585SJean-Christophe PLAGNIOL-VILLARD }
118379be585SJean-Christophe PLAGNIOL-VILLARD 
119237ce0feSMarek Vasut void pxa_uart_toggle_clock(uint32_t uart_index, int enable)
120237ce0feSMarek Vasut {
121237ce0feSMarek Vasut 	uint32_t clk_reg, clk_offset, reg;
122237ce0feSMarek Vasut 
123237ce0feSMarek Vasut 	clk_reg = UART_CLK_REG;
124237ce0feSMarek Vasut 	clk_offset = UART_CLK_BASE << uart_index;
125237ce0feSMarek Vasut 
126237ce0feSMarek Vasut 	reg = readl(clk_reg);
127237ce0feSMarek Vasut 
128237ce0feSMarek Vasut 	if (enable)
129237ce0feSMarek Vasut 		reg |= clk_offset;
130237ce0feSMarek Vasut 	else
131237ce0feSMarek Vasut 		reg &= ~clk_offset;
132237ce0feSMarek Vasut 
133237ce0feSMarek Vasut 	writel(reg, clk_reg);
134237ce0feSMarek Vasut }
135237ce0feSMarek Vasut 
136237ce0feSMarek Vasut /*
137237ce0feSMarek Vasut  * Enable clock and set baud rate, parity etc.
138237ce0feSMarek Vasut  */
139237ce0feSMarek Vasut void pxa_setbrg_dev(uint32_t uart_index)
140237ce0feSMarek Vasut {
141237ce0feSMarek Vasut 	uint32_t divider = 0;
142237ce0feSMarek Vasut 	struct pxa_uart_regs *uart_regs;
143237ce0feSMarek Vasut 
144237ce0feSMarek Vasut 	divider = pxa_uart_get_baud_divider();
145237ce0feSMarek Vasut 	if (!divider)
146237ce0feSMarek Vasut 		hang();
147237ce0feSMarek Vasut 
148237ce0feSMarek Vasut 	uart_regs = pxa_uart_index_to_regs(uart_index);
149237ce0feSMarek Vasut 	if (!uart_regs)
150237ce0feSMarek Vasut 		hang();
151237ce0feSMarek Vasut 
152237ce0feSMarek Vasut 	pxa_uart_toggle_clock(uart_index, 1);
153237ce0feSMarek Vasut 
154237ce0feSMarek Vasut 	/* Disable interrupts and FIFOs */
155237ce0feSMarek Vasut 	writel(0, &uart_regs->ier);
156237ce0feSMarek Vasut 	writel(0, &uart_regs->fcr);
157237ce0feSMarek Vasut 
158237ce0feSMarek Vasut 	/* Set baud rate */
159237ce0feSMarek Vasut 	writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr);
160237ce0feSMarek Vasut 	writel(divider & 0xff, &uart_regs->dll);
161237ce0feSMarek Vasut 	writel(divider >> 8, &uart_regs->dlh);
162237ce0feSMarek Vasut 	writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr);
163237ce0feSMarek Vasut 
164237ce0feSMarek Vasut 	/* Enable UART */
165237ce0feSMarek Vasut 	writel(IER_UUE, &uart_regs->ier);
166237ce0feSMarek Vasut }
167379be585SJean-Christophe PLAGNIOL-VILLARD 
168379be585SJean-Christophe PLAGNIOL-VILLARD /*
169379be585SJean-Christophe PLAGNIOL-VILLARD  * Initialise the serial port with the given baudrate. The settings
170379be585SJean-Christophe PLAGNIOL-VILLARD  * are always 8 data bits, no parity, 1 stop bit, no start bits.
171379be585SJean-Christophe PLAGNIOL-VILLARD  */
172379be585SJean-Christophe PLAGNIOL-VILLARD int pxa_init_dev(unsigned int uart_index)
173379be585SJean-Christophe PLAGNIOL-VILLARD {
174379be585SJean-Christophe PLAGNIOL-VILLARD 	pxa_setbrg_dev (uart_index);
175237ce0feSMarek Vasut 	return 0;
176379be585SJean-Christophe PLAGNIOL-VILLARD }
177379be585SJean-Christophe PLAGNIOL-VILLARD 
178379be585SJean-Christophe PLAGNIOL-VILLARD /*
179379be585SJean-Christophe PLAGNIOL-VILLARD  * Output a single byte to the serial port.
180379be585SJean-Christophe PLAGNIOL-VILLARD  */
181379be585SJean-Christophe PLAGNIOL-VILLARD void pxa_putc_dev(unsigned int uart_index, const char c)
182379be585SJean-Christophe PLAGNIOL-VILLARD {
183237ce0feSMarek Vasut 	struct pxa_uart_regs *uart_regs;
184379be585SJean-Christophe PLAGNIOL-VILLARD 
185237ce0feSMarek Vasut 	uart_regs = pxa_uart_index_to_regs(uart_index);
186237ce0feSMarek Vasut 	if (!uart_regs)
187237ce0feSMarek Vasut 		hang();
188379be585SJean-Christophe PLAGNIOL-VILLARD 
189237ce0feSMarek Vasut 	while (!(readl(&uart_regs->lsr) & LSR_TEMT))
190237ce0feSMarek Vasut 		WATCHDOG_RESET();
191237ce0feSMarek Vasut 	writel(c, &uart_regs->thr);
192379be585SJean-Christophe PLAGNIOL-VILLARD 
193379be585SJean-Christophe PLAGNIOL-VILLARD 	/* If \n, also do \r */
194379be585SJean-Christophe PLAGNIOL-VILLARD 	if (c == '\n')
195379be585SJean-Christophe PLAGNIOL-VILLARD 		pxa_putc_dev (uart_index,'\r');
196379be585SJean-Christophe PLAGNIOL-VILLARD }
197379be585SJean-Christophe PLAGNIOL-VILLARD 
198379be585SJean-Christophe PLAGNIOL-VILLARD /*
199379be585SJean-Christophe PLAGNIOL-VILLARD  * Read a single byte from the serial port. Returns 1 on success, 0
200379be585SJean-Christophe PLAGNIOL-VILLARD  * otherwise. When the function is succesfull, the character read is
201379be585SJean-Christophe PLAGNIOL-VILLARD  * written into its argument c.
202379be585SJean-Christophe PLAGNIOL-VILLARD  */
203379be585SJean-Christophe PLAGNIOL-VILLARD int pxa_tstc_dev(unsigned int uart_index)
204379be585SJean-Christophe PLAGNIOL-VILLARD {
205237ce0feSMarek Vasut 	struct pxa_uart_regs *uart_regs;
206237ce0feSMarek Vasut 
207237ce0feSMarek Vasut 	uart_regs = pxa_uart_index_to_regs(uart_index);
208237ce0feSMarek Vasut 	if (!uart_regs)
209379be585SJean-Christophe PLAGNIOL-VILLARD 		return -1;
210237ce0feSMarek Vasut 
211237ce0feSMarek Vasut 	return readl(&uart_regs->lsr) & LSR_DR;
212379be585SJean-Christophe PLAGNIOL-VILLARD }
213379be585SJean-Christophe PLAGNIOL-VILLARD 
214379be585SJean-Christophe PLAGNIOL-VILLARD /*
215379be585SJean-Christophe PLAGNIOL-VILLARD  * Read a single byte from the serial port. Returns 1 on success, 0
216379be585SJean-Christophe PLAGNIOL-VILLARD  * otherwise. When the function is succesfull, the character read is
217379be585SJean-Christophe PLAGNIOL-VILLARD  * written into its argument c.
218379be585SJean-Christophe PLAGNIOL-VILLARD  */
219379be585SJean-Christophe PLAGNIOL-VILLARD int pxa_getc_dev(unsigned int uart_index)
220379be585SJean-Christophe PLAGNIOL-VILLARD {
221237ce0feSMarek Vasut 	struct pxa_uart_regs *uart_regs;
222379be585SJean-Christophe PLAGNIOL-VILLARD 
223237ce0feSMarek Vasut 	uart_regs = pxa_uart_index_to_regs(uart_index);
224237ce0feSMarek Vasut 	if (!uart_regs)
225379be585SJean-Christophe PLAGNIOL-VILLARD 		return -1;
226237ce0feSMarek Vasut 
227237ce0feSMarek Vasut 	while (!(readl(&uart_regs->lsr) & LSR_DR))
228237ce0feSMarek Vasut 		WATCHDOG_RESET();
229237ce0feSMarek Vasut 	return readl(&uart_regs->rbr) & 0xff;
230379be585SJean-Christophe PLAGNIOL-VILLARD }
231379be585SJean-Christophe PLAGNIOL-VILLARD 
232237ce0feSMarek Vasut void pxa_puts_dev(unsigned int uart_index, const char *s)
233379be585SJean-Christophe PLAGNIOL-VILLARD {
234237ce0feSMarek Vasut 	while (*s)
235379be585SJean-Christophe PLAGNIOL-VILLARD 		pxa_putc_dev(uart_index, *s++);
236379be585SJean-Christophe PLAGNIOL-VILLARD }
237379be585SJean-Christophe PLAGNIOL-VILLARD 
238237ce0feSMarek Vasut #define	pxa_uart(uart, UART)						\
239237ce0feSMarek Vasut 	int uart##_init(void)						\
240237ce0feSMarek Vasut 	{								\
241237ce0feSMarek Vasut 		return pxa_init_dev(UART##_INDEX);			\
242237ce0feSMarek Vasut 	}								\
243237ce0feSMarek Vasut 									\
244237ce0feSMarek Vasut 	void uart##_setbrg(void)					\
245237ce0feSMarek Vasut 	{								\
246237ce0feSMarek Vasut 		return pxa_setbrg_dev(UART##_INDEX);			\
247237ce0feSMarek Vasut 	}								\
248237ce0feSMarek Vasut 									\
249237ce0feSMarek Vasut 	void uart##_putc(const char c)					\
250237ce0feSMarek Vasut 	{								\
251237ce0feSMarek Vasut 		return pxa_putc_dev(UART##_INDEX, c);			\
252237ce0feSMarek Vasut 	}								\
253237ce0feSMarek Vasut 									\
254237ce0feSMarek Vasut 	void uart##_puts(const char *s)					\
255237ce0feSMarek Vasut 	{								\
256237ce0feSMarek Vasut 		return pxa_puts_dev(UART##_INDEX, s);			\
257237ce0feSMarek Vasut 	}								\
258237ce0feSMarek Vasut 									\
259237ce0feSMarek Vasut 	int uart##_getc(void)						\
260237ce0feSMarek Vasut 	{								\
261237ce0feSMarek Vasut 		return pxa_getc_dev(UART##_INDEX);			\
262237ce0feSMarek Vasut 	}								\
263237ce0feSMarek Vasut 									\
264237ce0feSMarek Vasut 	int uart##_tstc(void)						\
265237ce0feSMarek Vasut 	{								\
266237ce0feSMarek Vasut 		return pxa_tstc_dev(UART##_INDEX);			\
267237ce0feSMarek Vasut 	}								\
268379be585SJean-Christophe PLAGNIOL-VILLARD 
269237ce0feSMarek Vasut #define	pxa_uart_desc(uart)						\
270237ce0feSMarek Vasut 	struct serial_device serial_##uart##_device =			\
271237ce0feSMarek Vasut 	{								\
272237ce0feSMarek Vasut 		"serial_"#uart,						\
273237ce0feSMarek Vasut 		uart##_init,						\
274237ce0feSMarek Vasut 		NULL,							\
275237ce0feSMarek Vasut 		uart##_setbrg,						\
276237ce0feSMarek Vasut 		uart##_getc,						\
277237ce0feSMarek Vasut 		uart##_tstc,						\
278237ce0feSMarek Vasut 		uart##_putc,						\
279237ce0feSMarek Vasut 		uart##_puts,						\
280379be585SJean-Christophe PLAGNIOL-VILLARD 	};
281237ce0feSMarek Vasut 
282237ce0feSMarek Vasut #define	pxa_uart_multi(uart, UART)					\
283237ce0feSMarek Vasut 	pxa_uart(uart, UART)						\
284237ce0feSMarek Vasut 	pxa_uart_desc(uart)
285237ce0feSMarek Vasut 
286237ce0feSMarek Vasut #if defined(CONFIG_HWUART)
287237ce0feSMarek Vasut 	pxa_uart_multi(hwuart, HWUART)
288379be585SJean-Christophe PLAGNIOL-VILLARD #endif
289379be585SJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_STUART)
290237ce0feSMarek Vasut 	pxa_uart_multi(stuart, STUART)
291379be585SJean-Christophe PLAGNIOL-VILLARD #endif
292237ce0feSMarek Vasut #if defined(CONFIG_FFUART)
293237ce0feSMarek Vasut 	pxa_uart_multi(ffuart, FFUART)
294237ce0feSMarek Vasut #endif
295237ce0feSMarek Vasut #if defined(CONFIG_BTUART)
296237ce0feSMarek Vasut 	pxa_uart_multi(btuart, BTUART)
297237ce0feSMarek Vasut #endif
298379be585SJean-Christophe PLAGNIOL-VILLARD 
299379be585SJean-Christophe PLAGNIOL-VILLARD #ifndef	CONFIG_SERIAL_MULTI
300237ce0feSMarek Vasut 	pxa_uart(serial, UART)
301237ce0feSMarek Vasut #endif
302