xref: /rk3399_rockchip-uboot/drivers/serial/atmel_usart.c (revision 0f65f48b6480ea18497675b30e5463dfd0c60cbe)
11378df79SJean-Christophe PLAGNIOL-VILLARD /*
21378df79SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2004-2006 Atmel Corporation
31378df79SJean-Christophe PLAGNIOL-VILLARD  *
4125637c5SAndreas Bießmann  * Modified to support C structur SoC access by
5125637c5SAndreas Bießmann  * Andreas Bießmann <biessmann@corscience.de>
6125637c5SAndreas Bießmann  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
81378df79SJean-Christophe PLAGNIOL-VILLARD  */
91378df79SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
10*0f65f48bSSimon Glass #include <dm.h>
11*0f65f48bSSimon Glass #include <errno.h>
12843a2654SJean-Christophe PLAGNIOL-VILLARD #include <watchdog.h>
13cfba4573SMarek Vasut #include <serial.h>
14cfba4573SMarek Vasut #include <linux/compiler.h>
151378df79SJean-Christophe PLAGNIOL-VILLARD 
161378df79SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
17*0f65f48bSSimon Glass #ifdef CONFIG_DM_SERIAL
18*0f65f48bSSimon Glass #include <asm/arch/atmel_serial.h>
19*0f65f48bSSimon Glass #endif
201378df79SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h>
21329f0f52SReinhard Meyer #include <asm/arch/hardware.h>
221378df79SJean-Christophe PLAGNIOL-VILLARD 
231378df79SJean-Christophe PLAGNIOL-VILLARD #include "atmel_usart.h"
241378df79SJean-Christophe PLAGNIOL-VILLARD 
251378df79SJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR;
261378df79SJean-Christophe PLAGNIOL-VILLARD 
2762137fc0SSimon Glass static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
2862137fc0SSimon Glass 					 int baudrate)
291378df79SJean-Christophe PLAGNIOL-VILLARD {
301378df79SJean-Christophe PLAGNIOL-VILLARD 	unsigned long divisor;
311378df79SJean-Christophe PLAGNIOL-VILLARD 	unsigned long usart_hz;
321378df79SJean-Christophe PLAGNIOL-VILLARD 
331378df79SJean-Christophe PLAGNIOL-VILLARD 	/*
341378df79SJean-Christophe PLAGNIOL-VILLARD 	 *              Master Clock
351378df79SJean-Christophe PLAGNIOL-VILLARD 	 * Baud Rate = --------------
361378df79SJean-Christophe PLAGNIOL-VILLARD 	 *                16 * CD
371378df79SJean-Christophe PLAGNIOL-VILLARD 	 */
3862137fc0SSimon Glass 	usart_hz = get_usart_clk_rate(id);
3962137fc0SSimon Glass 	divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
40125637c5SAndreas Bießmann 	writel(USART3_BF(CD, divisor), &usart->brgr);
411378df79SJean-Christophe PLAGNIOL-VILLARD }
421378df79SJean-Christophe PLAGNIOL-VILLARD 
4362137fc0SSimon Glass static void atmel_serial_init_internal(atmel_usart3_t *usart)
441378df79SJean-Christophe PLAGNIOL-VILLARD {
451f4faeddSXu, Hong 	/*
461f4faeddSXu, Hong 	 * Just in case: drain transmitter register
471f4faeddSXu, Hong 	 * 1000us is enough for baudrate >= 9600
481f4faeddSXu, Hong 	 */
491f4faeddSXu, Hong 	if (!(readl(&usart->csr) & USART3_BIT(TXEMPTY)))
501f4faeddSXu, Hong 		__udelay(1000);
511f4faeddSXu, Hong 
52125637c5SAndreas Bießmann 	writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
5362137fc0SSimon Glass }
541378df79SJean-Christophe PLAGNIOL-VILLARD 
5562137fc0SSimon Glass static void atmel_serial_activate(atmel_usart3_t *usart)
5662137fc0SSimon Glass {
57125637c5SAndreas Bießmann 	writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
581378df79SJean-Christophe PLAGNIOL-VILLARD 			   | USART3_BF(USCLKS, USART3_USCLKS_MCK)
591378df79SJean-Christophe PLAGNIOL-VILLARD 			   | USART3_BF(CHRL, USART3_CHRL_8)
601378df79SJean-Christophe PLAGNIOL-VILLARD 			   | USART3_BF(PAR, USART3_PAR_NONE)
61125637c5SAndreas Bießmann 			   | USART3_BF(NBSTOP, USART3_NBSTOP_1)),
62125637c5SAndreas Bießmann 			   &usart->mr);
631f4faeddSXu, Hong 	writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
641f4faeddSXu, Hong 	/* 100us is enough for the new settings to be settled */
651f4faeddSXu, Hong 	__udelay(100);
6662137fc0SSimon Glass }
6762137fc0SSimon Glass 
68*0f65f48bSSimon Glass #ifndef CONFIG_DM_SERIAL
6962137fc0SSimon Glass static void atmel_serial_setbrg(void)
7062137fc0SSimon Glass {
7162137fc0SSimon Glass 	atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
7262137fc0SSimon Glass 				     CONFIG_USART_ID, gd->baudrate);
7362137fc0SSimon Glass }
7462137fc0SSimon Glass 
7562137fc0SSimon Glass static int atmel_serial_init(void)
7662137fc0SSimon Glass {
7762137fc0SSimon Glass 	atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
7862137fc0SSimon Glass 
7962137fc0SSimon Glass 	atmel_serial_init_internal(usart);
8062137fc0SSimon Glass 	serial_setbrg();
8162137fc0SSimon Glass 	atmel_serial_activate(usart);
821378df79SJean-Christophe PLAGNIOL-VILLARD 
831378df79SJean-Christophe PLAGNIOL-VILLARD 	return 0;
841378df79SJean-Christophe PLAGNIOL-VILLARD }
851378df79SJean-Christophe PLAGNIOL-VILLARD 
86cfba4573SMarek Vasut static void atmel_serial_putc(char c)
871378df79SJean-Christophe PLAGNIOL-VILLARD {
88329f0f52SReinhard Meyer 	atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
89125637c5SAndreas Bießmann 
901378df79SJean-Christophe PLAGNIOL-VILLARD 	if (c == '\n')
911378df79SJean-Christophe PLAGNIOL-VILLARD 		serial_putc('\r');
921378df79SJean-Christophe PLAGNIOL-VILLARD 
93125637c5SAndreas Bießmann 	while (!(readl(&usart->csr) & USART3_BIT(TXRDY)));
94125637c5SAndreas Bießmann 	writel(c, &usart->thr);
951378df79SJean-Christophe PLAGNIOL-VILLARD }
961378df79SJean-Christophe PLAGNIOL-VILLARD 
97cfba4573SMarek Vasut static int atmel_serial_getc(void)
981378df79SJean-Christophe PLAGNIOL-VILLARD {
99329f0f52SReinhard Meyer 	atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
100125637c5SAndreas Bießmann 
101125637c5SAndreas Bießmann 	while (!(readl(&usart->csr) & USART3_BIT(RXRDY)))
102843a2654SJean-Christophe PLAGNIOL-VILLARD 		 WATCHDOG_RESET();
103125637c5SAndreas Bießmann 	return readl(&usart->rhr);
1041378df79SJean-Christophe PLAGNIOL-VILLARD }
1051378df79SJean-Christophe PLAGNIOL-VILLARD 
106cfba4573SMarek Vasut static int atmel_serial_tstc(void)
1071378df79SJean-Christophe PLAGNIOL-VILLARD {
108329f0f52SReinhard Meyer 	atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
109125637c5SAndreas Bießmann 	return (readl(&usart->csr) & USART3_BIT(RXRDY)) != 0;
1101378df79SJean-Christophe PLAGNIOL-VILLARD }
111cfba4573SMarek Vasut 
112cfba4573SMarek Vasut static struct serial_device atmel_serial_drv = {
113cfba4573SMarek Vasut 	.name	= "atmel_serial",
114cfba4573SMarek Vasut 	.start	= atmel_serial_init,
115cfba4573SMarek Vasut 	.stop	= NULL,
116cfba4573SMarek Vasut 	.setbrg	= atmel_serial_setbrg,
117cfba4573SMarek Vasut 	.putc	= atmel_serial_putc,
118ec3fd689SMarek Vasut 	.puts	= default_serial_puts,
119cfba4573SMarek Vasut 	.getc	= atmel_serial_getc,
120cfba4573SMarek Vasut 	.tstc	= atmel_serial_tstc,
121cfba4573SMarek Vasut };
122cfba4573SMarek Vasut 
123cfba4573SMarek Vasut void atmel_serial_initialize(void)
124cfba4573SMarek Vasut {
125cfba4573SMarek Vasut 	serial_register(&atmel_serial_drv);
126cfba4573SMarek Vasut }
127cfba4573SMarek Vasut 
128cfba4573SMarek Vasut __weak struct serial_device *default_serial_console(void)
129cfba4573SMarek Vasut {
130cfba4573SMarek Vasut 	return &atmel_serial_drv;
131cfba4573SMarek Vasut }
132*0f65f48bSSimon Glass #endif
133*0f65f48bSSimon Glass 
134*0f65f48bSSimon Glass #ifdef CONFIG_DM_SERIAL
135*0f65f48bSSimon Glass 
136*0f65f48bSSimon Glass struct atmel_serial_priv {
137*0f65f48bSSimon Glass 	atmel_usart3_t *usart;
138*0f65f48bSSimon Glass };
139*0f65f48bSSimon Glass 
140*0f65f48bSSimon Glass int atmel_serial_setbrg(struct udevice *dev, int baudrate)
141*0f65f48bSSimon Glass {
142*0f65f48bSSimon Glass 	struct atmel_serial_priv *priv = dev_get_priv(dev);
143*0f65f48bSSimon Glass 
144*0f65f48bSSimon Glass 	atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate);
145*0f65f48bSSimon Glass 	atmel_serial_activate(priv->usart);
146*0f65f48bSSimon Glass 
147*0f65f48bSSimon Glass 	return 0;
148*0f65f48bSSimon Glass }
149*0f65f48bSSimon Glass 
150*0f65f48bSSimon Glass static int atmel_serial_getc(struct udevice *dev)
151*0f65f48bSSimon Glass {
152*0f65f48bSSimon Glass 	struct atmel_serial_priv *priv = dev_get_priv(dev);
153*0f65f48bSSimon Glass 
154*0f65f48bSSimon Glass 	if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY)))
155*0f65f48bSSimon Glass 		return -EAGAIN;
156*0f65f48bSSimon Glass 
157*0f65f48bSSimon Glass 	return readl(&priv->usart->rhr);
158*0f65f48bSSimon Glass }
159*0f65f48bSSimon Glass 
160*0f65f48bSSimon Glass static int atmel_serial_putc(struct udevice *dev, const char ch)
161*0f65f48bSSimon Glass {
162*0f65f48bSSimon Glass 	struct atmel_serial_priv *priv = dev_get_priv(dev);
163*0f65f48bSSimon Glass 
164*0f65f48bSSimon Glass 	if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY)))
165*0f65f48bSSimon Glass 		return -EAGAIN;
166*0f65f48bSSimon Glass 
167*0f65f48bSSimon Glass 	writel(ch, &priv->usart->thr);
168*0f65f48bSSimon Glass 
169*0f65f48bSSimon Glass 	return 0;
170*0f65f48bSSimon Glass }
171*0f65f48bSSimon Glass 
172*0f65f48bSSimon Glass static int atmel_serial_pending(struct udevice *dev, bool input)
173*0f65f48bSSimon Glass {
174*0f65f48bSSimon Glass 	struct atmel_serial_priv *priv = dev_get_priv(dev);
175*0f65f48bSSimon Glass 	uint32_t csr = readl(&priv->usart->csr);
176*0f65f48bSSimon Glass 
177*0f65f48bSSimon Glass 	if (input)
178*0f65f48bSSimon Glass 		return csr & USART3_BIT(RXRDY) ? 1 : 0;
179*0f65f48bSSimon Glass 	else
180*0f65f48bSSimon Glass 		return csr & USART3_BIT(TXEMPTY) ? 0 : 1;
181*0f65f48bSSimon Glass }
182*0f65f48bSSimon Glass 
183*0f65f48bSSimon Glass static const struct dm_serial_ops atmel_serial_ops = {
184*0f65f48bSSimon Glass 	.putc = atmel_serial_putc,
185*0f65f48bSSimon Glass 	.pending = atmel_serial_pending,
186*0f65f48bSSimon Glass 	.getc = atmel_serial_getc,
187*0f65f48bSSimon Glass 	.setbrg = atmel_serial_setbrg,
188*0f65f48bSSimon Glass };
189*0f65f48bSSimon Glass 
190*0f65f48bSSimon Glass static int atmel_serial_probe(struct udevice *dev)
191*0f65f48bSSimon Glass {
192*0f65f48bSSimon Glass 	struct atmel_serial_platdata *plat = dev->platdata;
193*0f65f48bSSimon Glass 	struct atmel_serial_priv *priv = dev_get_priv(dev);
194*0f65f48bSSimon Glass 
195*0f65f48bSSimon Glass 	priv->usart = (atmel_usart3_t *)plat->base_addr;
196*0f65f48bSSimon Glass 	atmel_serial_init_internal(priv->usart);
197*0f65f48bSSimon Glass 
198*0f65f48bSSimon Glass 	return 0;
199*0f65f48bSSimon Glass }
200*0f65f48bSSimon Glass 
201*0f65f48bSSimon Glass U_BOOT_DRIVER(serial_atmel) = {
202*0f65f48bSSimon Glass 	.name	= "serial_atmel",
203*0f65f48bSSimon Glass 	.id	= UCLASS_SERIAL,
204*0f65f48bSSimon Glass 	.probe = atmel_serial_probe,
205*0f65f48bSSimon Glass 	.ops	= &atmel_serial_ops,
206*0f65f48bSSimon Glass 	.flags = DM_FLAG_PRE_RELOC,
207*0f65f48bSSimon Glass 	.priv_auto_alloc_size	= sizeof(struct atmel_serial_priv),
208*0f65f48bSSimon Glass };
209*0f65f48bSSimon Glass #endif
210