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