xref: /openbmc/u-boot/drivers/serial/serial_zynq.c (revision 194846f3)
1*194846f3SMichal Simek /*
2*194846f3SMichal Simek  * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
3*194846f3SMichal Simek  * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
4*194846f3SMichal Simek  *
5*194846f3SMichal Simek  * See file CREDITS for list of people who contributed to this
6*194846f3SMichal Simek  * project.
7*194846f3SMichal Simek  *
8*194846f3SMichal Simek  * This program is free software; you can redistribute it and/or
9*194846f3SMichal Simek  * modify it under the terms of the GNU General Public License as
10*194846f3SMichal Simek  * published by the Free Software Foundation; either version 2 of
11*194846f3SMichal Simek  * the License, or (at your option) any later version.
12*194846f3SMichal Simek  *
13*194846f3SMichal Simek  * This program is distributed in the hope that it will be useful,
14*194846f3SMichal Simek  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*194846f3SMichal Simek  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*194846f3SMichal Simek  * GNU General Public License for more details.
17*194846f3SMichal Simek  *
18*194846f3SMichal Simek  * You should have received a copy of the GNU General Public License
19*194846f3SMichal Simek  * along with this program; if not, write to the Free Software
20*194846f3SMichal Simek  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21*194846f3SMichal Simek  * MA 02111-1307 USA
22*194846f3SMichal Simek  */
23*194846f3SMichal Simek 
24*194846f3SMichal Simek #include <common.h>
25*194846f3SMichal Simek #include <watchdog.h>
26*194846f3SMichal Simek #include <asm/io.h>
27*194846f3SMichal Simek #include <linux/compiler.h>
28*194846f3SMichal Simek #include <serial.h>
29*194846f3SMichal Simek 
30*194846f3SMichal Simek #define ZYNQ_UART_SR_TXFULL	0x00000010 /* TX FIFO full */
31*194846f3SMichal Simek #define ZYNQ_UART_SR_RXEMPTY	0x00000002 /* RX FIFO empty */
32*194846f3SMichal Simek 
33*194846f3SMichal Simek #define ZYNQ_UART_CR_TX_EN	0x00000010 /* TX enabled */
34*194846f3SMichal Simek #define ZYNQ_UART_CR_RX_EN	0x00000004 /* RX enabled */
35*194846f3SMichal Simek #define ZYNQ_UART_CR_TXRST	0x00000002 /* TX logic reset */
36*194846f3SMichal Simek #define ZYNQ_UART_CR_RXRST	0x00000001 /* RX logic reset */
37*194846f3SMichal Simek 
38*194846f3SMichal Simek #define ZYNQ_UART_MR_PARITY_NONE	0x00000020  /* No parity mode */
39*194846f3SMichal Simek 
40*194846f3SMichal Simek /* Some clock/baud constants */
41*194846f3SMichal Simek #define ZYNQ_UART_BDIV	15 /* Default/reset BDIV value */
42*194846f3SMichal Simek #define ZYNQ_UART_BASECLK	3125000L /* master / (bdiv + 1) */
43*194846f3SMichal Simek 
44*194846f3SMichal Simek struct uart_zynq {
45*194846f3SMichal Simek 	u32 control; /* Control Register [8:0] */
46*194846f3SMichal Simek 	u32 mode; /* Mode Register [10:0] */
47*194846f3SMichal Simek 	u32 reserved1[4];
48*194846f3SMichal Simek 	u32 baud_rate_gen; /* Baud Rate Generator [15:0] */
49*194846f3SMichal Simek 	u32 reserved2[4];
50*194846f3SMichal Simek 	u32 channel_sts; /* Channel Status [11:0] */
51*194846f3SMichal Simek 	u32 tx_rx_fifo; /* FIFO [15:0] or [7:0] */
52*194846f3SMichal Simek 	u32 baud_rate_divider; /* Baud Rate Divider [7:0] */
53*194846f3SMichal Simek };
54*194846f3SMichal Simek 
55*194846f3SMichal Simek static struct uart_zynq *uart_zynq_ports[2] = {
56*194846f3SMichal Simek #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
57*194846f3SMichal Simek 	[0] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR0,
58*194846f3SMichal Simek #endif
59*194846f3SMichal Simek #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
60*194846f3SMichal Simek 	[1] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR1,
61*194846f3SMichal Simek #endif
62*194846f3SMichal Simek };
63*194846f3SMichal Simek 
64*194846f3SMichal Simek struct uart_zynq_params {
65*194846f3SMichal Simek 	u32 baudrate;
66*194846f3SMichal Simek 	u32 clock;
67*194846f3SMichal Simek };
68*194846f3SMichal Simek 
69*194846f3SMichal Simek static struct uart_zynq_params uart_zynq_ports_param[2] = {
70*194846f3SMichal Simek #if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE0) && defined(CONFIG_ZYNQ_SERIAL_CLOCK0)
71*194846f3SMichal Simek 	[0].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE0,
72*194846f3SMichal Simek 	[0].clock = CONFIG_ZYNQ_SERIAL_CLOCK0,
73*194846f3SMichal Simek #endif
74*194846f3SMichal Simek #if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE1) && defined(CONFIG_ZYNQ_SERIAL_CLOCK1)
75*194846f3SMichal Simek 	[1].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE1,
76*194846f3SMichal Simek 	[1].clock = CONFIG_ZYNQ_SERIAL_CLOCK1,
77*194846f3SMichal Simek #endif
78*194846f3SMichal Simek };
79*194846f3SMichal Simek 
80*194846f3SMichal Simek /* Set up the baud rate in gd struct */
81*194846f3SMichal Simek static void uart_zynq_serial_setbrg(const int port)
82*194846f3SMichal Simek {
83*194846f3SMichal Simek 	/* Calculation results. */
84*194846f3SMichal Simek 	unsigned int calc_bauderror, bdiv, bgen;
85*194846f3SMichal Simek 	unsigned long calc_baud = 0;
86*194846f3SMichal Simek 	unsigned long baud = uart_zynq_ports_param[port].baudrate;
87*194846f3SMichal Simek 	unsigned long clock = uart_zynq_ports_param[port].clock;
88*194846f3SMichal Simek 	struct uart_zynq *regs = uart_zynq_ports[port];
89*194846f3SMichal Simek 
90*194846f3SMichal Simek 	/*                master clock
91*194846f3SMichal Simek 	 * Baud rate = ------------------
92*194846f3SMichal Simek 	 *              bgen * (bdiv + 1)
93*194846f3SMichal Simek 	 *
94*194846f3SMichal Simek 	 * Find acceptable values for baud generation.
95*194846f3SMichal Simek 	 */
96*194846f3SMichal Simek 	for (bdiv = 4; bdiv < 255; bdiv++) {
97*194846f3SMichal Simek 		bgen = clock / (baud * (bdiv + 1));
98*194846f3SMichal Simek 		if (bgen < 2 || bgen > 65535)
99*194846f3SMichal Simek 			continue;
100*194846f3SMichal Simek 
101*194846f3SMichal Simek 		calc_baud = clock / (bgen * (bdiv + 1));
102*194846f3SMichal Simek 
103*194846f3SMichal Simek 		/*
104*194846f3SMichal Simek 		 * Use first calculated baudrate with
105*194846f3SMichal Simek 		 * an acceptable (<3%) error
106*194846f3SMichal Simek 		 */
107*194846f3SMichal Simek 		if (baud > calc_baud)
108*194846f3SMichal Simek 			calc_bauderror = baud - calc_baud;
109*194846f3SMichal Simek 		else
110*194846f3SMichal Simek 			calc_bauderror = calc_baud - baud;
111*194846f3SMichal Simek 		if (((calc_bauderror * 100) / baud) < 3)
112*194846f3SMichal Simek 			break;
113*194846f3SMichal Simek 	}
114*194846f3SMichal Simek 
115*194846f3SMichal Simek 	writel(bdiv, &regs->baud_rate_divider);
116*194846f3SMichal Simek 	writel(bgen, &regs->baud_rate_gen);
117*194846f3SMichal Simek }
118*194846f3SMichal Simek 
119*194846f3SMichal Simek /* Initialize the UART, with...some settings. */
120*194846f3SMichal Simek static int uart_zynq_serial_init(const int port)
121*194846f3SMichal Simek {
122*194846f3SMichal Simek 	struct uart_zynq *regs = uart_zynq_ports[port];
123*194846f3SMichal Simek 
124*194846f3SMichal Simek 	if (!regs)
125*194846f3SMichal Simek 		return -1;
126*194846f3SMichal Simek 
127*194846f3SMichal Simek 	/* RX/TX enabled & reset */
128*194846f3SMichal Simek 	writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
129*194846f3SMichal Simek 					ZYNQ_UART_CR_RXRST, &regs->control);
130*194846f3SMichal Simek 	writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
131*194846f3SMichal Simek 	uart_zynq_serial_setbrg(port);
132*194846f3SMichal Simek 
133*194846f3SMichal Simek 	return 0;
134*194846f3SMichal Simek }
135*194846f3SMichal Simek 
136*194846f3SMichal Simek static void uart_zynq_serial_putc(const char c, const int port)
137*194846f3SMichal Simek {
138*194846f3SMichal Simek 	struct uart_zynq *regs = uart_zynq_ports[port];
139*194846f3SMichal Simek 
140*194846f3SMichal Simek 	while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
141*194846f3SMichal Simek 		WATCHDOG_RESET();
142*194846f3SMichal Simek 
143*194846f3SMichal Simek 	if (c == '\n') {
144*194846f3SMichal Simek 		writel('\r', &regs->tx_rx_fifo);
145*194846f3SMichal Simek 		while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
146*194846f3SMichal Simek 			WATCHDOG_RESET();
147*194846f3SMichal Simek 	}
148*194846f3SMichal Simek 	writel(c, &regs->tx_rx_fifo);
149*194846f3SMichal Simek }
150*194846f3SMichal Simek 
151*194846f3SMichal Simek static void uart_zynq_serial_puts(const char *s, const int port)
152*194846f3SMichal Simek {
153*194846f3SMichal Simek 	while (*s)
154*194846f3SMichal Simek 		uart_zynq_serial_putc(*s++, port);
155*194846f3SMichal Simek }
156*194846f3SMichal Simek 
157*194846f3SMichal Simek static int uart_zynq_serial_tstc(const int port)
158*194846f3SMichal Simek {
159*194846f3SMichal Simek 	struct uart_zynq *regs = uart_zynq_ports[port];
160*194846f3SMichal Simek 
161*194846f3SMichal Simek 	return (readl(&regs->channel_sts) & ZYNQ_UART_SR_RXEMPTY) == 0;
162*194846f3SMichal Simek }
163*194846f3SMichal Simek 
164*194846f3SMichal Simek static int uart_zynq_serial_getc(const int port)
165*194846f3SMichal Simek {
166*194846f3SMichal Simek 	struct uart_zynq *regs = uart_zynq_ports[port];
167*194846f3SMichal Simek 
168*194846f3SMichal Simek 	while (!uart_zynq_serial_tstc(port))
169*194846f3SMichal Simek 		WATCHDOG_RESET();
170*194846f3SMichal Simek 	return readl(&regs->tx_rx_fifo);
171*194846f3SMichal Simek }
172*194846f3SMichal Simek 
173*194846f3SMichal Simek #if !defined(CONFIG_SERIAL_MULTI)
174*194846f3SMichal Simek int serial_init(void)
175*194846f3SMichal Simek {
176*194846f3SMichal Simek 	return uart_zynq_serial_init(0);
177*194846f3SMichal Simek }
178*194846f3SMichal Simek 
179*194846f3SMichal Simek void serial_setbrg(void)
180*194846f3SMichal Simek {
181*194846f3SMichal Simek 	uart_zynq_serial_setbrg(0);
182*194846f3SMichal Simek }
183*194846f3SMichal Simek 
184*194846f3SMichal Simek void serial_putc(const char c)
185*194846f3SMichal Simek {
186*194846f3SMichal Simek 	uart_zynq_serial_putc(c, 0);
187*194846f3SMichal Simek }
188*194846f3SMichal Simek 
189*194846f3SMichal Simek void serial_puts(const char *s)
190*194846f3SMichal Simek {
191*194846f3SMichal Simek 	uart_zynq_serial_puts(s, 0);
192*194846f3SMichal Simek }
193*194846f3SMichal Simek 
194*194846f3SMichal Simek int serial_getc(void)
195*194846f3SMichal Simek {
196*194846f3SMichal Simek 	return uart_zynq_serial_getc(0);
197*194846f3SMichal Simek }
198*194846f3SMichal Simek 
199*194846f3SMichal Simek int serial_tstc(void)
200*194846f3SMichal Simek {
201*194846f3SMichal Simek 	return uart_zynq_serial_tstc(0);
202*194846f3SMichal Simek }
203*194846f3SMichal Simek #else
204*194846f3SMichal Simek /* Multi serial device functions */
205*194846f3SMichal Simek #define DECLARE_PSSERIAL_FUNCTIONS(port) \
206*194846f3SMichal Simek 	int uart_zynq##port##_init(void) \
207*194846f3SMichal Simek 				{ return uart_zynq_serial_init(port); } \
208*194846f3SMichal Simek 	void uart_zynq##port##_setbrg(void) \
209*194846f3SMichal Simek 				{ return uart_zynq_serial_setbrg(port); } \
210*194846f3SMichal Simek 	int uart_zynq##port##_getc(void) \
211*194846f3SMichal Simek 				{ return uart_zynq_serial_getc(port); } \
212*194846f3SMichal Simek 	int uart_zynq##port##_tstc(void) \
213*194846f3SMichal Simek 				{ return uart_zynq_serial_tstc(port); } \
214*194846f3SMichal Simek 	void uart_zynq##port##_putc(const char c) \
215*194846f3SMichal Simek 				{ uart_zynq_serial_putc(c, port); } \
216*194846f3SMichal Simek 	void uart_zynq##port##_puts(const char *s) \
217*194846f3SMichal Simek 				{ uart_zynq_serial_puts(s, port); }
218*194846f3SMichal Simek 
219*194846f3SMichal Simek /* Serial device descriptor */
220*194846f3SMichal Simek #define INIT_PSSERIAL_STRUCTURE(port, __name) {	\
221*194846f3SMichal Simek 	  .name   = __name,			\
222*194846f3SMichal Simek 	  .init   = uart_zynq##port##_init,	\
223*194846f3SMichal Simek 	  .uninit = NULL,			\
224*194846f3SMichal Simek 	  .setbrg = uart_zynq##port##_setbrg,	\
225*194846f3SMichal Simek 	  .getc   = uart_zynq##port##_getc,	\
226*194846f3SMichal Simek 	  .tstc   = uart_zynq##port##_tstc,	\
227*194846f3SMichal Simek 	  .putc   = uart_zynq##port##_putc,	\
228*194846f3SMichal Simek 	  .puts   = uart_zynq##port##_puts,	\
229*194846f3SMichal Simek }
230*194846f3SMichal Simek 
231*194846f3SMichal Simek DECLARE_PSSERIAL_FUNCTIONS(0);
232*194846f3SMichal Simek struct serial_device uart_zynq_serial0_device =
233*194846f3SMichal Simek 	INIT_PSSERIAL_STRUCTURE(0, "ttyPS0");
234*194846f3SMichal Simek DECLARE_PSSERIAL_FUNCTIONS(1);
235*194846f3SMichal Simek struct serial_device uart_zynq_serial1_device =
236*194846f3SMichal Simek 	INIT_PSSERIAL_STRUCTURE(1, "ttyPS1");
237*194846f3SMichal Simek 
238*194846f3SMichal Simek __weak struct serial_device *default_serial_console(void)
239*194846f3SMichal Simek {
240*194846f3SMichal Simek 	if (uart_zynq_ports[0])
241*194846f3SMichal Simek 		return &uart_zynq_serial0_device;
242*194846f3SMichal Simek 	if (uart_zynq_ports[1])
243*194846f3SMichal Simek 		return &uart_zynq_serial1_device;
244*194846f3SMichal Simek 
245*194846f3SMichal Simek 	return NULL;
246*194846f3SMichal Simek }
247*194846f3SMichal Simek #endif
248