xref: /rk3399_rockchip-uboot/drivers/serial/mcfuart.c (revision 08ca213acadef61748dc62d48b0f5c4bed8b8c2d)
12bd806feSTsiChungLiew /*
22bd806feSTsiChungLiew  * (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
32bd806feSTsiChungLiew  * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
42bd806feSTsiChungLiew  *
5*e27802afSangelo@sysam.it  * Modified to add device model (DM) support
6*e27802afSangelo@sysam.it  * (C) Copyright 2015  Angelo Dureghello <angelo@sysam.it>
7*e27802afSangelo@sysam.it  *
81a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
92bd806feSTsiChungLiew  */
102bd806feSTsiChungLiew 
112bd806feSTsiChungLiew /*
122bd806feSTsiChungLiew  * Minimal serial functions needed to use one of the uart ports
132bd806feSTsiChungLiew  * as serial console interface.
142bd806feSTsiChungLiew  */
152bd806feSTsiChungLiew 
162bd806feSTsiChungLiew #include <common.h>
17*e27802afSangelo@sysam.it #include <dm.h>
18*e27802afSangelo@sysam.it #include <dm/platform_data/serial_coldfire.h>
1939c7a263SAlison Wang #include <serial.h>
2039c7a263SAlison Wang #include <linux/compiler.h>
212bd806feSTsiChungLiew #include <asm/immap.h>
222bd806feSTsiChungLiew #include <asm/uart.h>
232bd806feSTsiChungLiew 
242bd806feSTsiChungLiew DECLARE_GLOBAL_DATA_PTR;
252bd806feSTsiChungLiew 
26fa9da596STsiChung Liew extern void uart_port_conf(int port);
278d1d66afSTsiChungLiew 
mcf_serial_init_common(uart_t * uart,int port_idx,int baudrate)28*e27802afSangelo@sysam.it static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
292bd806feSTsiChungLiew {
302bd806feSTsiChungLiew 	u32 counter;
312bd806feSTsiChungLiew 
32*e27802afSangelo@sysam.it 	uart_port_conf(port_idx);
338d1d66afSTsiChungLiew 
342bd806feSTsiChungLiew 	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
35*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_RX, &uart->ucr);
36*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_TX, &uart->ucr);
37*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_ERROR, &uart->ucr);
38*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_MR, &uart->ucr);
392bd806feSTsiChungLiew 	__asm__("nop");
402bd806feSTsiChungLiew 
41*e27802afSangelo@sysam.it 	writeb(0, &uart->uimr);
422bd806feSTsiChungLiew 
432bd806feSTsiChungLiew 	/* write to CSR: RX/TX baud rate from timers */
44*e27802afSangelo@sysam.it 	writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
452bd806feSTsiChungLiew 
46*e27802afSangelo@sysam.it 	writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
47*e27802afSangelo@sysam.it 	writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
482bd806feSTsiChungLiew 
492bd806feSTsiChungLiew 	/* Setting up BaudRate */
50*e27802afSangelo@sysam.it 	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
51*e27802afSangelo@sysam.it 	counter = counter / baudrate;
522bd806feSTsiChungLiew 
532bd806feSTsiChungLiew 	/* write to CTUR: divide counter upper byte */
54*e27802afSangelo@sysam.it 	writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
552bd806feSTsiChungLiew 	/* write to CTLR: divide counter lower byte */
56*e27802afSangelo@sysam.it 	writeb((u8)(counter & 0x00ff), &uart->ubg2);
572bd806feSTsiChungLiew 
58*e27802afSangelo@sysam.it 	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
592bd806feSTsiChungLiew 
602bd806feSTsiChungLiew 	return (0);
612bd806feSTsiChungLiew }
622bd806feSTsiChungLiew 
mcf_serial_setbrg_common(uart_t * uart,int baudrate)63*e27802afSangelo@sysam.it static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
64*e27802afSangelo@sysam.it {
65*e27802afSangelo@sysam.it 	u32 counter;
66*e27802afSangelo@sysam.it 
67*e27802afSangelo@sysam.it 	/* Setting up BaudRate */
68*e27802afSangelo@sysam.it 	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
69*e27802afSangelo@sysam.it 	counter = counter / baudrate;
70*e27802afSangelo@sysam.it 
71*e27802afSangelo@sysam.it 	/* write to CTUR: divide counter upper byte */
72*e27802afSangelo@sysam.it 	writeb(((counter & 0xff00) >> 8), &uart->ubg1);
73*e27802afSangelo@sysam.it 	/* write to CTLR: divide counter lower byte */
74*e27802afSangelo@sysam.it 	writeb((counter & 0x00ff), &uart->ubg2);
75*e27802afSangelo@sysam.it 
76*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_RX, &uart->ucr);
77*e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_TX, &uart->ucr);
78*e27802afSangelo@sysam.it 
79*e27802afSangelo@sysam.it 	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
80*e27802afSangelo@sysam.it }
81*e27802afSangelo@sysam.it 
82*e27802afSangelo@sysam.it #ifndef CONFIG_DM_SERIAL
83*e27802afSangelo@sysam.it 
mcf_serial_init(void)84*e27802afSangelo@sysam.it static int mcf_serial_init(void)
85*e27802afSangelo@sysam.it {
86*e27802afSangelo@sysam.it 	uart_t *uart_base;
87*e27802afSangelo@sysam.it 	int port_idx;
88*e27802afSangelo@sysam.it 
89*e27802afSangelo@sysam.it 	uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
90*e27802afSangelo@sysam.it 	port_idx = CONFIG_SYS_UART_PORT;
91*e27802afSangelo@sysam.it 
92*e27802afSangelo@sysam.it 	return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
93*e27802afSangelo@sysam.it }
94*e27802afSangelo@sysam.it 
mcf_serial_putc(const char c)95abaef69fSMarek Vasut static void mcf_serial_putc(const char c)
962bd806feSTsiChungLiew {
97*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
982bd806feSTsiChungLiew 
992bd806feSTsiChungLiew 	if (c == '\n')
1002bd806feSTsiChungLiew 		serial_putc('\r');
1012bd806feSTsiChungLiew 
1022bd806feSTsiChungLiew 	/* Wait for last character to go. */
103*e27802afSangelo@sysam.it 	while (!(readb(&uart->usr) & UART_USR_TXRDY))
104*e27802afSangelo@sysam.it 		;
1052bd806feSTsiChungLiew 
106*e27802afSangelo@sysam.it 	writeb(c, &uart->utb);
1072bd806feSTsiChungLiew }
1082bd806feSTsiChungLiew 
mcf_serial_getc(void)109abaef69fSMarek Vasut static int mcf_serial_getc(void)
1102bd806feSTsiChungLiew {
111*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1122bd806feSTsiChungLiew 
1132bd806feSTsiChungLiew 	/* Wait for a character to arrive. */
114*e27802afSangelo@sysam.it 	while (!(readb(&uart->usr) & UART_USR_RXRDY))
115*e27802afSangelo@sysam.it 		;
1162bd806feSTsiChungLiew 
117*e27802afSangelo@sysam.it 	return readb(&uart->urb);
1182bd806feSTsiChungLiew }
1192bd806feSTsiChungLiew 
mcf_serial_setbrg(void)120abaef69fSMarek Vasut static void mcf_serial_setbrg(void)
1212bd806feSTsiChungLiew {
122*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1232bd806feSTsiChungLiew 
124*e27802afSangelo@sysam.it 	mcf_serial_setbrg_common(uart, gd->baudrate);
125*e27802afSangelo@sysam.it }
1262bd806feSTsiChungLiew 
mcf_serial_tstc(void)127*e27802afSangelo@sysam.it static int mcf_serial_tstc(void)
128*e27802afSangelo@sysam.it {
129*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1302bd806feSTsiChungLiew 
131*e27802afSangelo@sysam.it 	return readb(&uart->usr) & UART_USR_RXRDY;
1322bd806feSTsiChungLiew }
133abaef69fSMarek Vasut 
134abaef69fSMarek Vasut static struct serial_device mcf_serial_drv = {
135abaef69fSMarek Vasut 	.name	= "mcf_serial",
136abaef69fSMarek Vasut 	.start	= mcf_serial_init,
137abaef69fSMarek Vasut 	.stop	= NULL,
138abaef69fSMarek Vasut 	.setbrg	= mcf_serial_setbrg,
139abaef69fSMarek Vasut 	.putc	= mcf_serial_putc,
140ec3fd689SMarek Vasut 	.puts	= default_serial_puts,
141abaef69fSMarek Vasut 	.getc	= mcf_serial_getc,
142abaef69fSMarek Vasut 	.tstc	= mcf_serial_tstc,
143abaef69fSMarek Vasut };
144abaef69fSMarek Vasut 
mcf_serial_initialize(void)145abaef69fSMarek Vasut void mcf_serial_initialize(void)
146abaef69fSMarek Vasut {
147abaef69fSMarek Vasut 	serial_register(&mcf_serial_drv);
148abaef69fSMarek Vasut }
149abaef69fSMarek Vasut 
default_serial_console(void)150abaef69fSMarek Vasut __weak struct serial_device *default_serial_console(void)
151abaef69fSMarek Vasut {
152abaef69fSMarek Vasut 	return &mcf_serial_drv;
153abaef69fSMarek Vasut }
154*e27802afSangelo@sysam.it 
155*e27802afSangelo@sysam.it #endif
156*e27802afSangelo@sysam.it 
157*e27802afSangelo@sysam.it #ifdef CONFIG_DM_SERIAL
158*e27802afSangelo@sysam.it 
coldfire_serial_probe(struct udevice * dev)159*e27802afSangelo@sysam.it static int coldfire_serial_probe(struct udevice *dev)
160*e27802afSangelo@sysam.it {
161*e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
162*e27802afSangelo@sysam.it 
163*e27802afSangelo@sysam.it 	return mcf_serial_init_common((uart_t *)plat->base,
164*e27802afSangelo@sysam.it 						plat->port, plat->baudrate);
165*e27802afSangelo@sysam.it }
166*e27802afSangelo@sysam.it 
coldfire_serial_putc(struct udevice * dev,const char ch)167*e27802afSangelo@sysam.it static int coldfire_serial_putc(struct udevice *dev, const char ch)
168*e27802afSangelo@sysam.it {
169*e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
170*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)plat->base;
171*e27802afSangelo@sysam.it 
172*e27802afSangelo@sysam.it 	/* Wait for last character to go. */
173*e27802afSangelo@sysam.it 	if (!(readb(&uart->usr) & UART_USR_TXRDY))
174*e27802afSangelo@sysam.it 		return -EAGAIN;
175*e27802afSangelo@sysam.it 
176*e27802afSangelo@sysam.it 	writeb(ch, &uart->utb);
177*e27802afSangelo@sysam.it 
178*e27802afSangelo@sysam.it 	return 0;
179*e27802afSangelo@sysam.it }
180*e27802afSangelo@sysam.it 
coldfire_serial_getc(struct udevice * dev)181*e27802afSangelo@sysam.it static int coldfire_serial_getc(struct udevice *dev)
182*e27802afSangelo@sysam.it {
183*e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
184*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
185*e27802afSangelo@sysam.it 
186*e27802afSangelo@sysam.it 	/* Wait for a character to arrive. */
187*e27802afSangelo@sysam.it 	if (!(readb(&uart->usr) & UART_USR_RXRDY))
188*e27802afSangelo@sysam.it 		return -EAGAIN;
189*e27802afSangelo@sysam.it 
190*e27802afSangelo@sysam.it 	return readb(&uart->urb);
191*e27802afSangelo@sysam.it }
192*e27802afSangelo@sysam.it 
coldfire_serial_setbrg(struct udevice * dev,int baudrate)193*e27802afSangelo@sysam.it int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
194*e27802afSangelo@sysam.it {
195*e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
196*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
197*e27802afSangelo@sysam.it 
198*e27802afSangelo@sysam.it 	mcf_serial_setbrg_common(uart, baudrate);
199*e27802afSangelo@sysam.it 
200*e27802afSangelo@sysam.it 	return 0;
201*e27802afSangelo@sysam.it }
202*e27802afSangelo@sysam.it 
coldfire_serial_pending(struct udevice * dev,bool input)203*e27802afSangelo@sysam.it static int coldfire_serial_pending(struct udevice *dev, bool input)
204*e27802afSangelo@sysam.it {
205*e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
206*e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
207*e27802afSangelo@sysam.it 
208*e27802afSangelo@sysam.it 	if (input)
209*e27802afSangelo@sysam.it 		return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
210*e27802afSangelo@sysam.it 	else
211*e27802afSangelo@sysam.it 		return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
212*e27802afSangelo@sysam.it 
213*e27802afSangelo@sysam.it 	return 0;
214*e27802afSangelo@sysam.it }
215*e27802afSangelo@sysam.it 
216*e27802afSangelo@sysam.it static const struct dm_serial_ops coldfire_serial_ops = {
217*e27802afSangelo@sysam.it 	.putc = coldfire_serial_putc,
218*e27802afSangelo@sysam.it 	.pending = coldfire_serial_pending,
219*e27802afSangelo@sysam.it 	.getc = coldfire_serial_getc,
220*e27802afSangelo@sysam.it 	.setbrg = coldfire_serial_setbrg,
221*e27802afSangelo@sysam.it };
222*e27802afSangelo@sysam.it 
223*e27802afSangelo@sysam.it U_BOOT_DRIVER(serial_coldfire) = {
224*e27802afSangelo@sysam.it 	.name = "serial_coldfire",
225*e27802afSangelo@sysam.it 	.id = UCLASS_SERIAL,
226*e27802afSangelo@sysam.it 	.probe = coldfire_serial_probe,
227*e27802afSangelo@sysam.it 	.ops = &coldfire_serial_ops,
228*e27802afSangelo@sysam.it 	.flags = DM_FLAG_PRE_RELOC,
229*e27802afSangelo@sysam.it };
230*e27802afSangelo@sysam.it #endif
231