xref: /openbmc/u-boot/drivers/serial/mcfuart.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22bd806feSTsiChungLiew /*
32bd806feSTsiChungLiew  * (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
42bd806feSTsiChungLiew  * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
52bd806feSTsiChungLiew  *
6e27802afSangelo@sysam.it  * Modified to add device model (DM) support
7e27802afSangelo@sysam.it  * (C) Copyright 2015  Angelo Dureghello <angelo@sysam.it>
82bd806feSTsiChungLiew  */
92bd806feSTsiChungLiew 
102bd806feSTsiChungLiew /*
112bd806feSTsiChungLiew  * Minimal serial functions needed to use one of the uart ports
122bd806feSTsiChungLiew  * as serial console interface.
132bd806feSTsiChungLiew  */
142bd806feSTsiChungLiew 
152bd806feSTsiChungLiew #include <common.h>
16e27802afSangelo@sysam.it #include <dm.h>
17e27802afSangelo@sysam.it #include <dm/platform_data/serial_coldfire.h>
1839c7a263SAlison Wang #include <serial.h>
1939c7a263SAlison Wang #include <linux/compiler.h>
202bd806feSTsiChungLiew #include <asm/immap.h>
212bd806feSTsiChungLiew #include <asm/uart.h>
222bd806feSTsiChungLiew 
232bd806feSTsiChungLiew DECLARE_GLOBAL_DATA_PTR;
242bd806feSTsiChungLiew 
25fa9da596STsiChung Liew extern void uart_port_conf(int port);
268d1d66afSTsiChungLiew 
mcf_serial_init_common(uart_t * uart,int port_idx,int baudrate)27e27802afSangelo@sysam.it static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
282bd806feSTsiChungLiew {
292bd806feSTsiChungLiew 	u32 counter;
302bd806feSTsiChungLiew 
31e27802afSangelo@sysam.it 	uart_port_conf(port_idx);
328d1d66afSTsiChungLiew 
332bd806feSTsiChungLiew 	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
34e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_RX, &uart->ucr);
35e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_TX, &uart->ucr);
36e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_ERROR, &uart->ucr);
37e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_MR, &uart->ucr);
382bd806feSTsiChungLiew 	__asm__("nop");
392bd806feSTsiChungLiew 
40e27802afSangelo@sysam.it 	writeb(0, &uart->uimr);
412bd806feSTsiChungLiew 
422bd806feSTsiChungLiew 	/* write to CSR: RX/TX baud rate from timers */
43e27802afSangelo@sysam.it 	writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
442bd806feSTsiChungLiew 
45e27802afSangelo@sysam.it 	writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
46e27802afSangelo@sysam.it 	writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
472bd806feSTsiChungLiew 
482bd806feSTsiChungLiew 	/* Setting up BaudRate */
49e27802afSangelo@sysam.it 	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
50e27802afSangelo@sysam.it 	counter = counter / baudrate;
512bd806feSTsiChungLiew 
522bd806feSTsiChungLiew 	/* write to CTUR: divide counter upper byte */
53e27802afSangelo@sysam.it 	writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
542bd806feSTsiChungLiew 	/* write to CTLR: divide counter lower byte */
55e27802afSangelo@sysam.it 	writeb((u8)(counter & 0x00ff), &uart->ubg2);
562bd806feSTsiChungLiew 
57e27802afSangelo@sysam.it 	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
582bd806feSTsiChungLiew 
592bd806feSTsiChungLiew 	return (0);
602bd806feSTsiChungLiew }
612bd806feSTsiChungLiew 
mcf_serial_setbrg_common(uart_t * uart,int baudrate)62e27802afSangelo@sysam.it static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
63e27802afSangelo@sysam.it {
64e27802afSangelo@sysam.it 	u32 counter;
65e27802afSangelo@sysam.it 
66e27802afSangelo@sysam.it 	/* Setting up BaudRate */
67e27802afSangelo@sysam.it 	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
68e27802afSangelo@sysam.it 	counter = counter / baudrate;
69e27802afSangelo@sysam.it 
70e27802afSangelo@sysam.it 	/* write to CTUR: divide counter upper byte */
71e27802afSangelo@sysam.it 	writeb(((counter & 0xff00) >> 8), &uart->ubg1);
72e27802afSangelo@sysam.it 	/* write to CTLR: divide counter lower byte */
73e27802afSangelo@sysam.it 	writeb((counter & 0x00ff), &uart->ubg2);
74e27802afSangelo@sysam.it 
75e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_RX, &uart->ucr);
76e27802afSangelo@sysam.it 	writeb(UART_UCR_RESET_TX, &uart->ucr);
77e27802afSangelo@sysam.it 
78e27802afSangelo@sysam.it 	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
79e27802afSangelo@sysam.it }
80e27802afSangelo@sysam.it 
81e27802afSangelo@sysam.it #ifndef CONFIG_DM_SERIAL
82e27802afSangelo@sysam.it 
mcf_serial_init(void)83e27802afSangelo@sysam.it static int mcf_serial_init(void)
84e27802afSangelo@sysam.it {
85e27802afSangelo@sysam.it 	uart_t *uart_base;
86e27802afSangelo@sysam.it 	int port_idx;
87e27802afSangelo@sysam.it 
88e27802afSangelo@sysam.it 	uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
89e27802afSangelo@sysam.it 	port_idx = CONFIG_SYS_UART_PORT;
90e27802afSangelo@sysam.it 
91e27802afSangelo@sysam.it 	return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
92e27802afSangelo@sysam.it }
93e27802afSangelo@sysam.it 
mcf_serial_putc(const char c)94abaef69fSMarek Vasut static void mcf_serial_putc(const char c)
952bd806feSTsiChungLiew {
96e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
972bd806feSTsiChungLiew 
982bd806feSTsiChungLiew 	if (c == '\n')
992bd806feSTsiChungLiew 		serial_putc('\r');
1002bd806feSTsiChungLiew 
1012bd806feSTsiChungLiew 	/* Wait for last character to go. */
102e27802afSangelo@sysam.it 	while (!(readb(&uart->usr) & UART_USR_TXRDY))
103e27802afSangelo@sysam.it 		;
1042bd806feSTsiChungLiew 
105e27802afSangelo@sysam.it 	writeb(c, &uart->utb);
1062bd806feSTsiChungLiew }
1072bd806feSTsiChungLiew 
mcf_serial_getc(void)108abaef69fSMarek Vasut static int mcf_serial_getc(void)
1092bd806feSTsiChungLiew {
110e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1112bd806feSTsiChungLiew 
1122bd806feSTsiChungLiew 	/* Wait for a character to arrive. */
113e27802afSangelo@sysam.it 	while (!(readb(&uart->usr) & UART_USR_RXRDY))
114e27802afSangelo@sysam.it 		;
1152bd806feSTsiChungLiew 
116e27802afSangelo@sysam.it 	return readb(&uart->urb);
1172bd806feSTsiChungLiew }
1182bd806feSTsiChungLiew 
mcf_serial_setbrg(void)119abaef69fSMarek Vasut static void mcf_serial_setbrg(void)
1202bd806feSTsiChungLiew {
121e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1222bd806feSTsiChungLiew 
123e27802afSangelo@sysam.it 	mcf_serial_setbrg_common(uart, gd->baudrate);
124e27802afSangelo@sysam.it }
1252bd806feSTsiChungLiew 
mcf_serial_tstc(void)126e27802afSangelo@sysam.it static int mcf_serial_tstc(void)
127e27802afSangelo@sysam.it {
128e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
1292bd806feSTsiChungLiew 
130e27802afSangelo@sysam.it 	return readb(&uart->usr) & UART_USR_RXRDY;
1312bd806feSTsiChungLiew }
132abaef69fSMarek Vasut 
133abaef69fSMarek Vasut static struct serial_device mcf_serial_drv = {
134abaef69fSMarek Vasut 	.name	= "mcf_serial",
135abaef69fSMarek Vasut 	.start	= mcf_serial_init,
136abaef69fSMarek Vasut 	.stop	= NULL,
137abaef69fSMarek Vasut 	.setbrg	= mcf_serial_setbrg,
138abaef69fSMarek Vasut 	.putc	= mcf_serial_putc,
139ec3fd689SMarek Vasut 	.puts	= default_serial_puts,
140abaef69fSMarek Vasut 	.getc	= mcf_serial_getc,
141abaef69fSMarek Vasut 	.tstc	= mcf_serial_tstc,
142abaef69fSMarek Vasut };
143abaef69fSMarek Vasut 
mcf_serial_initialize(void)144abaef69fSMarek Vasut void mcf_serial_initialize(void)
145abaef69fSMarek Vasut {
146abaef69fSMarek Vasut 	serial_register(&mcf_serial_drv);
147abaef69fSMarek Vasut }
148abaef69fSMarek Vasut 
default_serial_console(void)149abaef69fSMarek Vasut __weak struct serial_device *default_serial_console(void)
150abaef69fSMarek Vasut {
151abaef69fSMarek Vasut 	return &mcf_serial_drv;
152abaef69fSMarek Vasut }
153e27802afSangelo@sysam.it 
154e27802afSangelo@sysam.it #endif
155e27802afSangelo@sysam.it 
156e27802afSangelo@sysam.it #ifdef CONFIG_DM_SERIAL
157e27802afSangelo@sysam.it 
coldfire_serial_probe(struct udevice * dev)158e27802afSangelo@sysam.it static int coldfire_serial_probe(struct udevice *dev)
159e27802afSangelo@sysam.it {
160e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
161e27802afSangelo@sysam.it 
162e27802afSangelo@sysam.it 	return mcf_serial_init_common((uart_t *)plat->base,
163e27802afSangelo@sysam.it 						plat->port, plat->baudrate);
164e27802afSangelo@sysam.it }
165e27802afSangelo@sysam.it 
coldfire_serial_putc(struct udevice * dev,const char ch)166e27802afSangelo@sysam.it static int coldfire_serial_putc(struct udevice *dev, const char ch)
167e27802afSangelo@sysam.it {
168e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
169e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)plat->base;
170e27802afSangelo@sysam.it 
171e27802afSangelo@sysam.it 	/* Wait for last character to go. */
172e27802afSangelo@sysam.it 	if (!(readb(&uart->usr) & UART_USR_TXRDY))
173e27802afSangelo@sysam.it 		return -EAGAIN;
174e27802afSangelo@sysam.it 
175e27802afSangelo@sysam.it 	writeb(ch, &uart->utb);
176e27802afSangelo@sysam.it 
177e27802afSangelo@sysam.it 	return 0;
178e27802afSangelo@sysam.it }
179e27802afSangelo@sysam.it 
coldfire_serial_getc(struct udevice * dev)180e27802afSangelo@sysam.it static int coldfire_serial_getc(struct udevice *dev)
181e27802afSangelo@sysam.it {
182e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
183e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
184e27802afSangelo@sysam.it 
185e27802afSangelo@sysam.it 	/* Wait for a character to arrive. */
186e27802afSangelo@sysam.it 	if (!(readb(&uart->usr) & UART_USR_RXRDY))
187e27802afSangelo@sysam.it 		return -EAGAIN;
188e27802afSangelo@sysam.it 
189e27802afSangelo@sysam.it 	return readb(&uart->urb);
190e27802afSangelo@sysam.it }
191e27802afSangelo@sysam.it 
coldfire_serial_setbrg(struct udevice * dev,int baudrate)192e27802afSangelo@sysam.it int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
193e27802afSangelo@sysam.it {
194e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
195e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
196e27802afSangelo@sysam.it 
197e27802afSangelo@sysam.it 	mcf_serial_setbrg_common(uart, baudrate);
198e27802afSangelo@sysam.it 
199e27802afSangelo@sysam.it 	return 0;
200e27802afSangelo@sysam.it }
201e27802afSangelo@sysam.it 
coldfire_serial_pending(struct udevice * dev,bool input)202e27802afSangelo@sysam.it static int coldfire_serial_pending(struct udevice *dev, bool input)
203e27802afSangelo@sysam.it {
204e27802afSangelo@sysam.it 	struct coldfire_serial_platdata *plat = dev->platdata;
205e27802afSangelo@sysam.it 	uart_t *uart = (uart_t *)(plat->base);
206e27802afSangelo@sysam.it 
207e27802afSangelo@sysam.it 	if (input)
208e27802afSangelo@sysam.it 		return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
209e27802afSangelo@sysam.it 	else
210e27802afSangelo@sysam.it 		return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
211e27802afSangelo@sysam.it 
212e27802afSangelo@sysam.it 	return 0;
213e27802afSangelo@sysam.it }
214e27802afSangelo@sysam.it 
215e27802afSangelo@sysam.it static const struct dm_serial_ops coldfire_serial_ops = {
216e27802afSangelo@sysam.it 	.putc = coldfire_serial_putc,
217e27802afSangelo@sysam.it 	.pending = coldfire_serial_pending,
218e27802afSangelo@sysam.it 	.getc = coldfire_serial_getc,
219e27802afSangelo@sysam.it 	.setbrg = coldfire_serial_setbrg,
220e27802afSangelo@sysam.it };
221e27802afSangelo@sysam.it 
222e27802afSangelo@sysam.it U_BOOT_DRIVER(serial_coldfire) = {
223e27802afSangelo@sysam.it 	.name = "serial_coldfire",
224e27802afSangelo@sysam.it 	.id = UCLASS_SERIAL,
225e27802afSangelo@sysam.it 	.probe = coldfire_serial_probe,
226e27802afSangelo@sysam.it 	.ops = &coldfire_serial_ops,
227e27802afSangelo@sysam.it 	.flags = DM_FLAG_PRE_RELOC,
228e27802afSangelo@sysam.it };
229e27802afSangelo@sysam.it #endif
230