blob: 1371049de2780b9be907322149e47c524ef2d7ef [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
TsiChung Liewf6afe722007-06-18 13:50:13 -05002/*
TsiChungLiew36d5b1a2007-07-05 23:17:36 -05003 * (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
TsiChung Liewf6afe722007-06-18 13:50:13 -05004 * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
5 *
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +02006 * Modified to add device model (DM) support
7 * (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it>
TsiChung Liewf6afe722007-06-18 13:50:13 -05008 */
9
10/*
11 * Minimal serial functions needed to use one of the uart ports
12 * as serial console interface.
13 */
14
15#include <common.h>
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020016#include <dm.h>
17#include <dm/platform_data/serial_coldfire.h>
Alison Wang234151a2012-10-18 16:54:38 +000018#include <serial.h>
19#include <linux/compiler.h>
TsiChungLiew36d5b1a2007-07-05 23:17:36 -050020#include <asm/immap.h>
21#include <asm/uart.h>
TsiChung Liewf6afe722007-06-18 13:50:13 -050022
23DECLARE_GLOBAL_DATA_PTR;
24
TsiChung Liewb0c37e52010-03-09 19:24:43 -060025extern void uart_port_conf(int port);
TsiChungLiew74634c82007-08-05 03:55:21 -050026
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020027static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
TsiChung Liewf6afe722007-06-18 13:50:13 -050028{
TsiChung Liewf6afe722007-06-18 13:50:13 -050029 u32 counter;
30
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020031 uart_port_conf(port_idx);
TsiChungLiew74634c82007-08-05 03:55:21 -050032
TsiChung Liewf6afe722007-06-18 13:50:13 -050033 /* write to SICR: SIM2 = uart mode,dcd does not affect rx */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020034 writeb(UART_UCR_RESET_RX, &uart->ucr);
35 writeb(UART_UCR_RESET_TX, &uart->ucr);
36 writeb(UART_UCR_RESET_ERROR, &uart->ucr);
37 writeb(UART_UCR_RESET_MR, &uart->ucr);
TsiChung Liewf6afe722007-06-18 13:50:13 -050038 __asm__("nop");
39
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020040 writeb(0, &uart->uimr);
TsiChung Liewf6afe722007-06-18 13:50:13 -050041
42 /* write to CSR: RX/TX baud rate from timers */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020043 writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
TsiChung Liewf6afe722007-06-18 13:50:13 -050044
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020045 writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
46 writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
TsiChung Liewf6afe722007-06-18 13:50:13 -050047
48 /* Setting up BaudRate */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020049 counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
50 counter = counter / baudrate;
TsiChung Liewf6afe722007-06-18 13:50:13 -050051
52 /* write to CTUR: divide counter upper byte */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020053 writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
TsiChung Liewf6afe722007-06-18 13:50:13 -050054 /* write to CTLR: divide counter lower byte */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020055 writeb((u8)(counter & 0x00ff), &uart->ubg2);
TsiChung Liewf6afe722007-06-18 13:50:13 -050056
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020057 writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
TsiChung Liewf6afe722007-06-18 13:50:13 -050058
59 return (0);
60}
61
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020062static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
63{
64 u32 counter;
65
66 /* Setting up BaudRate */
67 counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
68 counter = counter / baudrate;
69
70 /* write to CTUR: divide counter upper byte */
71 writeb(((counter & 0xff00) >> 8), &uart->ubg1);
72 /* write to CTLR: divide counter lower byte */
73 writeb((counter & 0x00ff), &uart->ubg2);
74
75 writeb(UART_UCR_RESET_RX, &uart->ucr);
76 writeb(UART_UCR_RESET_TX, &uart->ucr);
77
78 writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
79}
80
81#ifndef CONFIG_DM_SERIAL
82
83static int mcf_serial_init(void)
84{
85 uart_t *uart_base;
86 int port_idx;
87
88 uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
89 port_idx = CONFIG_SYS_UART_PORT;
90
91 return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
92}
93
Marek Vasut96e8ff62012-09-13 16:51:38 +020094static void mcf_serial_putc(const char c)
TsiChung Liewf6afe722007-06-18 13:50:13 -050095{
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +020096 uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
TsiChung Liewf6afe722007-06-18 13:50:13 -050097
98 if (c == '\n')
99 serial_putc('\r');
100
101 /* Wait for last character to go. */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200102 while (!(readb(&uart->usr) & UART_USR_TXRDY))
103 ;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500104
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200105 writeb(c, &uart->utb);
TsiChung Liewf6afe722007-06-18 13:50:13 -0500106}
107
Marek Vasut96e8ff62012-09-13 16:51:38 +0200108static int mcf_serial_getc(void)
TsiChung Liewf6afe722007-06-18 13:50:13 -0500109{
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200110 uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500111
112 /* Wait for a character to arrive. */
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200113 while (!(readb(&uart->usr) & UART_USR_RXRDY))
114 ;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500115
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200116 return readb(&uart->urb);
TsiChung Liewf6afe722007-06-18 13:50:13 -0500117}
118
Marek Vasut96e8ff62012-09-13 16:51:38 +0200119static void mcf_serial_setbrg(void)
TsiChung Liewf6afe722007-06-18 13:50:13 -0500120{
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200121 uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500122
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200123 mcf_serial_setbrg_common(uart, gd->baudrate);
124}
TsiChung Liewf6afe722007-06-18 13:50:13 -0500125
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200126static int mcf_serial_tstc(void)
127{
128 uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500129
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200130 return readb(&uart->usr) & UART_USR_RXRDY;
TsiChung Liewf6afe722007-06-18 13:50:13 -0500131}
Marek Vasut96e8ff62012-09-13 16:51:38 +0200132
Marek Vasut96e8ff62012-09-13 16:51:38 +0200133static struct serial_device mcf_serial_drv = {
134 .name = "mcf_serial",
135 .start = mcf_serial_init,
136 .stop = NULL,
137 .setbrg = mcf_serial_setbrg,
138 .putc = mcf_serial_putc,
Marek Vasutd9c64492012-10-06 14:07:02 +0000139 .puts = default_serial_puts,
Marek Vasut96e8ff62012-09-13 16:51:38 +0200140 .getc = mcf_serial_getc,
141 .tstc = mcf_serial_tstc,
142};
143
144void mcf_serial_initialize(void)
145{
146 serial_register(&mcf_serial_drv);
147}
148
149__weak struct serial_device *default_serial_console(void)
150{
151 return &mcf_serial_drv;
152}
angelo@sysam.itb2d1e2a2016-04-27 21:51:13 +0200153
154#endif
155
156#ifdef CONFIG_DM_SERIAL
157
158static int coldfire_serial_probe(struct udevice *dev)
159{
160 struct coldfire_serial_platdata *plat = dev->platdata;
161
162 return mcf_serial_init_common((uart_t *)plat->base,
163 plat->port, plat->baudrate);
164}
165
166static int coldfire_serial_putc(struct udevice *dev, const char ch)
167{
168 struct coldfire_serial_platdata *plat = dev->platdata;
169 uart_t *uart = (uart_t *)plat->base;
170
171 /* Wait for last character to go. */
172 if (!(readb(&uart->usr) & UART_USR_TXRDY))
173 return -EAGAIN;
174
175 writeb(ch, &uart->utb);
176
177 return 0;
178}
179
180static int coldfire_serial_getc(struct udevice *dev)
181{
182 struct coldfire_serial_platdata *plat = dev->platdata;
183 uart_t *uart = (uart_t *)(plat->base);
184
185 /* Wait for a character to arrive. */
186 if (!(readb(&uart->usr) & UART_USR_RXRDY))
187 return -EAGAIN;
188
189 return readb(&uart->urb);
190}
191
192int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
193{
194 struct coldfire_serial_platdata *plat = dev->platdata;
195 uart_t *uart = (uart_t *)(plat->base);
196
197 mcf_serial_setbrg_common(uart, baudrate);
198
199 return 0;
200}
201
202static int coldfire_serial_pending(struct udevice *dev, bool input)
203{
204 struct coldfire_serial_platdata *plat = dev->platdata;
205 uart_t *uart = (uart_t *)(plat->base);
206
207 if (input)
208 return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
209 else
210 return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
211
212 return 0;
213}
214
215static const struct dm_serial_ops coldfire_serial_ops = {
216 .putc = coldfire_serial_putc,
217 .pending = coldfire_serial_pending,
218 .getc = coldfire_serial_getc,
219 .setbrg = coldfire_serial_setbrg,
220};
221
222U_BOOT_DRIVER(serial_coldfire) = {
223 .name = "serial_coldfire",
224 .id = UCLASS_SERIAL,
225 .probe = coldfire_serial_probe,
226 .ops = &coldfire_serial_ops,
227 .flags = DM_FLAG_PRE_RELOC,
228};
229#endif