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