]>
Commit | Line | Data |
---|---|---|
8e585f02 | 1 | /* |
2bd806fe | 2 | * (C) Copyright 2004-2007 Freescale Semiconductor, Inc. |
8e585f02 TL |
3 | * TsiChung Liew, Tsi-Chung.Liew@freescale.com. |
4 | * | |
e27802af | 5 | * Modified to add device model (DM) support |
6 | * (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it> | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
8e585f02 TL |
9 | */ |
10 | ||
11 | /* | |
12 | * Minimal serial functions needed to use one of the uart ports | |
13 | * as serial console interface. | |
14 | */ | |
15 | ||
16 | #include <common.h> | |
e27802af | 17 | #include <dm.h> |
18 | #include <dm/platform_data/serial_coldfire.h> | |
39c7a263 AW |
19 | #include <serial.h> |
20 | #include <linux/compiler.h> | |
2bd806fe TL |
21 | #include <asm/immap.h> |
22 | #include <asm/uart.h> | |
8e585f02 TL |
23 | |
24 | DECLARE_GLOBAL_DATA_PTR; | |
25 | ||
fa9da596 | 26 | extern void uart_port_conf(int port); |
8d1d66af | 27 | |
e27802af | 28 | static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate) |
8e585f02 | 29 | { |
8e585f02 TL |
30 | u32 counter; |
31 | ||
e27802af | 32 | uart_port_conf(port_idx); |
8d1d66af | 33 | |
8e585f02 | 34 | /* write to SICR: SIM2 = uart mode,dcd does not affect rx */ |
e27802af | 35 | writeb(UART_UCR_RESET_RX, &uart->ucr); |
36 | writeb(UART_UCR_RESET_TX, &uart->ucr); | |
37 | writeb(UART_UCR_RESET_ERROR, &uart->ucr); | |
38 | writeb(UART_UCR_RESET_MR, &uart->ucr); | |
8e585f02 TL |
39 | __asm__("nop"); |
40 | ||
e27802af | 41 | writeb(0, &uart->uimr); |
8e585f02 TL |
42 | |
43 | /* write to CSR: RX/TX baud rate from timers */ | |
e27802af | 44 | writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr); |
8e585f02 | 45 | |
e27802af | 46 | writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr); |
47 | writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr); | |
8e585f02 TL |
48 | |
49 | /* Setting up BaudRate */ | |
e27802af | 50 | counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2)); |
51 | counter = counter / baudrate; | |
8e585f02 TL |
52 | |
53 | /* write to CTUR: divide counter upper byte */ | |
e27802af | 54 | writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1); |
8e585f02 | 55 | /* write to CTLR: divide counter lower byte */ |
e27802af | 56 | writeb((u8)(counter & 0x00ff), &uart->ubg2); |
8e585f02 | 57 | |
e27802af | 58 | writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr); |
8e585f02 TL |
59 | |
60 | return (0); | |
61 | } | |
62 | ||
e27802af | 63 | static void mcf_serial_setbrg_common(uart_t *uart, int baudrate) |
64 | { | |
65 | u32 counter; | |
66 | ||
67 | /* Setting up BaudRate */ | |
68 | counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2)); | |
69 | counter = counter / baudrate; | |
70 | ||
71 | /* write to CTUR: divide counter upper byte */ | |
72 | writeb(((counter & 0xff00) >> 8), &uart->ubg1); | |
73 | /* write to CTLR: divide counter lower byte */ | |
74 | writeb((counter & 0x00ff), &uart->ubg2); | |
75 | ||
76 | writeb(UART_UCR_RESET_RX, &uart->ucr); | |
77 | writeb(UART_UCR_RESET_TX, &uart->ucr); | |
78 | ||
79 | writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr); | |
80 | } | |
81 | ||
82 | #ifndef CONFIG_DM_SERIAL | |
83 | ||
84 | static int mcf_serial_init(void) | |
85 | { | |
86 | uart_t *uart_base; | |
87 | int port_idx; | |
88 | ||
89 | uart_base = (uart_t *)CONFIG_SYS_UART_BASE; | |
90 | port_idx = CONFIG_SYS_UART_PORT; | |
91 | ||
92 | return mcf_serial_init_common(uart_base, port_idx, gd->baudrate); | |
93 | } | |
94 | ||
abaef69f | 95 | static void mcf_serial_putc(const char c) |
8e585f02 | 96 | { |
e27802af | 97 | uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; |
8e585f02 TL |
98 | |
99 | if (c == '\n') | |
100 | serial_putc('\r'); | |
101 | ||
102 | /* Wait for last character to go. */ | |
e27802af | 103 | while (!(readb(&uart->usr) & UART_USR_TXRDY)) |
104 | ; | |
8e585f02 | 105 | |
e27802af | 106 | writeb(c, &uart->utb); |
8e585f02 TL |
107 | } |
108 | ||
abaef69f | 109 | static int mcf_serial_getc(void) |
8e585f02 | 110 | { |
e27802af | 111 | uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; |
8e585f02 TL |
112 | |
113 | /* Wait for a character to arrive. */ | |
e27802af | 114 | while (!(readb(&uart->usr) & UART_USR_RXRDY)) |
115 | ; | |
8e585f02 | 116 | |
e27802af | 117 | return readb(&uart->urb); |
8e585f02 TL |
118 | } |
119 | ||
abaef69f | 120 | static void mcf_serial_setbrg(void) |
8e585f02 | 121 | { |
e27802af | 122 | uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; |
8e585f02 | 123 | |
e27802af | 124 | mcf_serial_setbrg_common(uart, gd->baudrate); |
125 | } | |
8e585f02 | 126 | |
e27802af | 127 | static int mcf_serial_tstc(void) |
128 | { | |
129 | uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; | |
8e585f02 | 130 | |
e27802af | 131 | return readb(&uart->usr) & UART_USR_RXRDY; |
8e585f02 | 132 | } |
abaef69f | 133 | |
abaef69f MV |
134 | static struct serial_device mcf_serial_drv = { |
135 | .name = "mcf_serial", | |
136 | .start = mcf_serial_init, | |
137 | .stop = NULL, | |
138 | .setbrg = mcf_serial_setbrg, | |
139 | .putc = mcf_serial_putc, | |
ec3fd689 | 140 | .puts = default_serial_puts, |
abaef69f MV |
141 | .getc = mcf_serial_getc, |
142 | .tstc = mcf_serial_tstc, | |
143 | }; | |
144 | ||
145 | void mcf_serial_initialize(void) | |
146 | { | |
147 | serial_register(&mcf_serial_drv); | |
148 | } | |
149 | ||
150 | __weak struct serial_device *default_serial_console(void) | |
151 | { | |
152 | return &mcf_serial_drv; | |
153 | } | |
e27802af | 154 | |
155 | #endif | |
156 | ||
157 | #ifdef CONFIG_DM_SERIAL | |
158 | ||
159 | static int coldfire_serial_probe(struct udevice *dev) | |
160 | { | |
161 | struct coldfire_serial_platdata *plat = dev->platdata; | |
162 | ||
163 | return mcf_serial_init_common((uart_t *)plat->base, | |
164 | plat->port, plat->baudrate); | |
165 | } | |
166 | ||
167 | static int coldfire_serial_putc(struct udevice *dev, const char ch) | |
168 | { | |
169 | struct coldfire_serial_platdata *plat = dev->platdata; | |
170 | uart_t *uart = (uart_t *)plat->base; | |
171 | ||
172 | /* Wait for last character to go. */ | |
173 | if (!(readb(&uart->usr) & UART_USR_TXRDY)) | |
174 | return -EAGAIN; | |
175 | ||
176 | writeb(ch, &uart->utb); | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | static int coldfire_serial_getc(struct udevice *dev) | |
182 | { | |
183 | struct coldfire_serial_platdata *plat = dev->platdata; | |
184 | uart_t *uart = (uart_t *)(plat->base); | |
185 | ||
186 | /* Wait for a character to arrive. */ | |
187 | if (!(readb(&uart->usr) & UART_USR_RXRDY)) | |
188 | return -EAGAIN; | |
189 | ||
190 | return readb(&uart->urb); | |
191 | } | |
192 | ||
193 | int coldfire_serial_setbrg(struct udevice *dev, int baudrate) | |
194 | { | |
195 | struct coldfire_serial_platdata *plat = dev->platdata; | |
196 | uart_t *uart = (uart_t *)(plat->base); | |
197 | ||
198 | mcf_serial_setbrg_common(uart, baudrate); | |
199 | ||
200 | return 0; | |
201 | } | |
202 | ||
203 | static int coldfire_serial_pending(struct udevice *dev, bool input) | |
204 | { | |
205 | struct coldfire_serial_platdata *plat = dev->platdata; | |
206 | uart_t *uart = (uart_t *)(plat->base); | |
207 | ||
208 | if (input) | |
209 | return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0; | |
210 | else | |
211 | return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1; | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | static const struct dm_serial_ops coldfire_serial_ops = { | |
217 | .putc = coldfire_serial_putc, | |
218 | .pending = coldfire_serial_pending, | |
219 | .getc = coldfire_serial_getc, | |
220 | .setbrg = coldfire_serial_setbrg, | |
221 | }; | |
222 | ||
223 | U_BOOT_DRIVER(serial_coldfire) = { | |
224 | .name = "serial_coldfire", | |
225 | .id = UCLASS_SERIAL, | |
226 | .probe = coldfire_serial_probe, | |
227 | .ops = &coldfire_serial_ops, | |
228 | .flags = DM_FLAG_PRE_RELOC, | |
229 | }; | |
230 | #endif |