diff options
Diffstat (limited to 'drivers/serial/cpm_uart')
-rw-r--r-- | drivers/serial/cpm_uart/Makefile | 11 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart.h | 89 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 1177 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm1.c | 290 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm1.h | 45 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.c | 328 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.h | 45 |
7 files changed, 1985 insertions, 0 deletions
diff --git a/drivers/serial/cpm_uart/Makefile b/drivers/serial/cpm_uart/Makefile new file mode 100644 index 000000000000..e072724ea754 --- /dev/null +++ b/drivers/serial/cpm_uart/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the Motorola 8xx FEC ethernet controller | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o | ||
6 | |||
7 | # Select the correct platform objects. | ||
8 | cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o | ||
9 | cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o | ||
10 | |||
11 | cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h new file mode 100644 index 000000000000..5f6187baad86 --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart.h | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports | ||
5 | * | ||
6 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | ||
7 | * | ||
8 | */ | ||
9 | #ifndef CPM_UART_H | ||
10 | #define CPM_UART_H | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | |||
14 | #if defined(CONFIG_CPM2) | ||
15 | #include "cpm_uart_cpm2.h" | ||
16 | #elif defined(CONFIG_8xx) | ||
17 | #include "cpm_uart_cpm1.h" | ||
18 | #endif | ||
19 | |||
20 | #define SERIAL_CPM_MAJOR 204 | ||
21 | #define SERIAL_CPM_MINOR 46 | ||
22 | |||
23 | #define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC) | ||
24 | #define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING) | ||
25 | #define FLAG_DISCARDING 0x00000004 /* when set, don't discard */ | ||
26 | #define FLAG_SMC 0x00000002 | ||
27 | #define FLAG_CONSOLE 0x00000001 | ||
28 | |||
29 | #define UART_SMC1 0 | ||
30 | #define UART_SMC2 1 | ||
31 | #define UART_SCC1 2 | ||
32 | #define UART_SCC2 3 | ||
33 | #define UART_SCC3 4 | ||
34 | #define UART_SCC4 5 | ||
35 | |||
36 | #define UART_NR 6 | ||
37 | |||
38 | #define RX_NUM_FIFO 4 | ||
39 | #define RX_BUF_SIZE 32 | ||
40 | #define TX_NUM_FIFO 4 | ||
41 | #define TX_BUF_SIZE 32 | ||
42 | |||
43 | struct uart_cpm_port { | ||
44 | struct uart_port port; | ||
45 | u16 rx_nrfifos; | ||
46 | u16 rx_fifosize; | ||
47 | u16 tx_nrfifos; | ||
48 | u16 tx_fifosize; | ||
49 | smc_t *smcp; | ||
50 | smc_uart_t *smcup; | ||
51 | scc_t *sccp; | ||
52 | scc_uart_t *sccup; | ||
53 | volatile cbd_t *rx_bd_base; | ||
54 | volatile cbd_t *rx_cur; | ||
55 | volatile cbd_t *tx_bd_base; | ||
56 | volatile cbd_t *tx_cur; | ||
57 | unsigned char *tx_buf; | ||
58 | unsigned char *rx_buf; | ||
59 | u32 flags; | ||
60 | void (*set_lineif)(struct uart_cpm_port *); | ||
61 | u8 brg; | ||
62 | uint dp_addr; | ||
63 | void *mem_addr; | ||
64 | dma_addr_t dma_addr; | ||
65 | /* helpers */ | ||
66 | int baud; | ||
67 | int bits; | ||
68 | /* Keep track of 'odd' SMC2 wirings */ | ||
69 | int is_portb; | ||
70 | }; | ||
71 | |||
72 | extern int cpm_uart_port_map[UART_NR]; | ||
73 | extern int cpm_uart_nr; | ||
74 | extern struct uart_cpm_port cpm_uart_ports[UART_NR]; | ||
75 | |||
76 | /* these are located in their respective files */ | ||
77 | void cpm_line_cr_cmd(int line, int cmd); | ||
78 | int cpm_uart_init_portdesc(void); | ||
79 | int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); | ||
80 | void cpm_uart_freebuf(struct uart_cpm_port *pinfo); | ||
81 | |||
82 | void smc1_lineif(struct uart_cpm_port *pinfo); | ||
83 | void smc2_lineif(struct uart_cpm_port *pinfo); | ||
84 | void scc1_lineif(struct uart_cpm_port *pinfo); | ||
85 | void scc2_lineif(struct uart_cpm_port *pinfo); | ||
86 | void scc3_lineif(struct uart_cpm_port *pinfo); | ||
87 | void scc4_lineif(struct uart_cpm_port *pinfo); | ||
88 | |||
89 | #endif /* CPM_UART_H */ | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c new file mode 100644 index 000000000000..29db677d4284 --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart_core.c | |||
@@ -0,0 +1,1177 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart.c | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports; core driver | ||
5 | * | ||
6 | * Based on arch/ppc/cpm2_io/uart.c by Dan Malek | ||
7 | * Based on ppc8xx.c by Thomas Gleixner | ||
8 | * Based on drivers/serial/amba.c by Russell King | ||
9 | * | ||
10 | * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2) | ||
11 | * Pantelis Antoniou (panto@intracom.gr) (CPM1) | ||
12 | * | ||
13 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | ||
14 | * (C) 2004 Intracom, S.A. | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/config.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/tty.h> | ||
35 | #include <linux/ioport.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/serial.h> | ||
38 | #include <linux/console.h> | ||
39 | #include <linux/sysrq.h> | ||
40 | #include <linux/device.h> | ||
41 | #include <linux/bootmem.h> | ||
42 | #include <linux/dma-mapping.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | #include <asm/irq.h> | ||
46 | #include <asm/delay.h> | ||
47 | |||
48 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | ||
49 | #define SUPPORT_SYSRQ | ||
50 | #endif | ||
51 | |||
52 | #include <linux/serial_core.h> | ||
53 | #include <linux/kernel.h> | ||
54 | |||
55 | #include "cpm_uart.h" | ||
56 | |||
57 | /***********************************************************************/ | ||
58 | |||
59 | /* Track which ports are configured as uarts */ | ||
60 | int cpm_uart_port_map[UART_NR]; | ||
61 | /* How many ports did we config as uarts */ | ||
62 | int cpm_uart_nr; | ||
63 | |||
64 | /**************************************************************/ | ||
65 | |||
66 | static int cpm_uart_tx_pump(struct uart_port *port); | ||
67 | static void cpm_uart_init_smc(struct uart_cpm_port *pinfo); | ||
68 | static void cpm_uart_init_scc(struct uart_cpm_port *pinfo); | ||
69 | static void cpm_uart_initbd(struct uart_cpm_port *pinfo); | ||
70 | |||
71 | /**************************************************************/ | ||
72 | |||
73 | /* | ||
74 | * Check, if transmit buffers are processed | ||
75 | */ | ||
76 | static unsigned int cpm_uart_tx_empty(struct uart_port *port) | ||
77 | { | ||
78 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
79 | volatile cbd_t *bdp = pinfo->tx_bd_base; | ||
80 | int ret = 0; | ||
81 | |||
82 | while (1) { | ||
83 | if (bdp->cbd_sc & BD_SC_READY) | ||
84 | break; | ||
85 | |||
86 | if (bdp->cbd_sc & BD_SC_WRAP) { | ||
87 | ret = TIOCSER_TEMT; | ||
88 | break; | ||
89 | } | ||
90 | bdp++; | ||
91 | } | ||
92 | |||
93 | pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
99 | { | ||
100 | /* Whee. Do nothing. */ | ||
101 | } | ||
102 | |||
103 | static unsigned int cpm_uart_get_mctrl(struct uart_port *port) | ||
104 | { | ||
105 | /* Whee. Do nothing. */ | ||
106 | return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Stop transmitter | ||
111 | */ | ||
112 | static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop) | ||
113 | { | ||
114 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
115 | volatile smc_t *smcp = pinfo->smcp; | ||
116 | volatile scc_t *sccp = pinfo->sccp; | ||
117 | |||
118 | pr_debug("CPM uart[%d]:stop tx\n", port->line); | ||
119 | |||
120 | if (IS_SMC(pinfo)) | ||
121 | smcp->smc_smcm &= ~SMCM_TX; | ||
122 | else | ||
123 | sccp->scc_sccm &= ~UART_SCCM_TX; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Start transmitter | ||
128 | */ | ||
129 | static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start) | ||
130 | { | ||
131 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
132 | volatile smc_t *smcp = pinfo->smcp; | ||
133 | volatile scc_t *sccp = pinfo->sccp; | ||
134 | |||
135 | pr_debug("CPM uart[%d]:start tx\n", port->line); | ||
136 | |||
137 | if (IS_SMC(pinfo)) { | ||
138 | if (smcp->smc_smcm & SMCM_TX) | ||
139 | return; | ||
140 | } else { | ||
141 | if (sccp->scc_sccm & UART_SCCM_TX) | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | if (cpm_uart_tx_pump(port) != 0) { | ||
146 | if (IS_SMC(pinfo)) | ||
147 | smcp->smc_smcm |= SMCM_TX; | ||
148 | else | ||
149 | sccp->scc_sccm |= UART_SCCM_TX; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Stop receiver | ||
155 | */ | ||
156 | static void cpm_uart_stop_rx(struct uart_port *port) | ||
157 | { | ||
158 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
159 | volatile smc_t *smcp = pinfo->smcp; | ||
160 | volatile scc_t *sccp = pinfo->sccp; | ||
161 | |||
162 | pr_debug("CPM uart[%d]:stop rx\n", port->line); | ||
163 | |||
164 | if (IS_SMC(pinfo)) | ||
165 | smcp->smc_smcm &= ~SMCM_RX; | ||
166 | else | ||
167 | sccp->scc_sccm &= ~UART_SCCM_RX; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Enable Modem status interrupts | ||
172 | */ | ||
173 | static void cpm_uart_enable_ms(struct uart_port *port) | ||
174 | { | ||
175 | pr_debug("CPM uart[%d]:enable ms\n", port->line); | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Generate a break. | ||
180 | */ | ||
181 | static void cpm_uart_break_ctl(struct uart_port *port, int break_state) | ||
182 | { | ||
183 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
184 | int line = pinfo - cpm_uart_ports; | ||
185 | |||
186 | pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, | ||
187 | break_state); | ||
188 | |||
189 | if (break_state) | ||
190 | cpm_line_cr_cmd(line, CPM_CR_STOP_TX); | ||
191 | else | ||
192 | cpm_line_cr_cmd(line, CPM_CR_RESTART_TX); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Transmit characters, refill buffer descriptor, if possible | ||
197 | */ | ||
198 | static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs) | ||
199 | { | ||
200 | pr_debug("CPM uart[%d]:TX INT\n", port->line); | ||
201 | |||
202 | cpm_uart_tx_pump(port); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Receive characters | ||
207 | */ | ||
208 | static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) | ||
209 | { | ||
210 | int i; | ||
211 | unsigned char ch, *cp; | ||
212 | struct tty_struct *tty = port->info->tty; | ||
213 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
214 | volatile cbd_t *bdp; | ||
215 | u16 status; | ||
216 | unsigned int flg; | ||
217 | |||
218 | pr_debug("CPM uart[%d]:RX INT\n", port->line); | ||
219 | |||
220 | /* Just loop through the closed BDs and copy the characters into | ||
221 | * the buffer. | ||
222 | */ | ||
223 | bdp = pinfo->rx_cur; | ||
224 | for (;;) { | ||
225 | /* get status */ | ||
226 | status = bdp->cbd_sc; | ||
227 | /* If this one is empty, return happy */ | ||
228 | if (status & BD_SC_EMPTY) | ||
229 | break; | ||
230 | |||
231 | /* get number of characters, and check spce in flip-buffer */ | ||
232 | i = bdp->cbd_datlen; | ||
233 | |||
234 | /* If we have not enough room in tty flip buffer, then we try | ||
235 | * later, which will be the next rx-interrupt or a timeout | ||
236 | */ | ||
237 | if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) { | ||
238 | tty->flip.work.func((void *)tty); | ||
239 | if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) { | ||
240 | printk(KERN_WARNING "TTY_DONT_FLIP set\n"); | ||
241 | return; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* get pointer */ | ||
246 | cp = (unsigned char *)bus_to_virt(bdp->cbd_bufaddr); | ||
247 | |||
248 | /* loop through the buffer */ | ||
249 | while (i-- > 0) { | ||
250 | ch = *cp++; | ||
251 | port->icount.rx++; | ||
252 | flg = TTY_NORMAL; | ||
253 | |||
254 | if (status & | ||
255 | (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) | ||
256 | goto handle_error; | ||
257 | if (uart_handle_sysrq_char(port, ch, regs)) | ||
258 | continue; | ||
259 | |||
260 | error_return: | ||
261 | *tty->flip.char_buf_ptr++ = ch; | ||
262 | *tty->flip.flag_buf_ptr++ = flg; | ||
263 | tty->flip.count++; | ||
264 | |||
265 | } /* End while (i--) */ | ||
266 | |||
267 | /* This BD is ready to be used again. Clear status. get next */ | ||
268 | bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); | ||
269 | bdp->cbd_sc |= BD_SC_EMPTY; | ||
270 | |||
271 | if (bdp->cbd_sc & BD_SC_WRAP) | ||
272 | bdp = pinfo->rx_bd_base; | ||
273 | else | ||
274 | bdp++; | ||
275 | } /* End for (;;) */ | ||
276 | |||
277 | /* Write back buffer pointer */ | ||
278 | pinfo->rx_cur = (volatile cbd_t *) bdp; | ||
279 | |||
280 | /* activate BH processing */ | ||
281 | tty_flip_buffer_push(tty); | ||
282 | |||
283 | return; | ||
284 | |||
285 | /* Error processing */ | ||
286 | |||
287 | handle_error: | ||
288 | /* Statistics */ | ||
289 | if (status & BD_SC_BR) | ||
290 | port->icount.brk++; | ||
291 | if (status & BD_SC_PR) | ||
292 | port->icount.parity++; | ||
293 | if (status & BD_SC_FR) | ||
294 | port->icount.frame++; | ||
295 | if (status & BD_SC_OV) | ||
296 | port->icount.overrun++; | ||
297 | |||
298 | /* Mask out ignored conditions */ | ||
299 | status &= port->read_status_mask; | ||
300 | |||
301 | /* Handle the remaining ones */ | ||
302 | if (status & BD_SC_BR) | ||
303 | flg = TTY_BREAK; | ||
304 | else if (status & BD_SC_PR) | ||
305 | flg = TTY_PARITY; | ||
306 | else if (status & BD_SC_FR) | ||
307 | flg = TTY_FRAME; | ||
308 | |||
309 | /* overrun does not affect the current character ! */ | ||
310 | if (status & BD_SC_OV) { | ||
311 | ch = 0; | ||
312 | flg = TTY_OVERRUN; | ||
313 | /* We skip this buffer */ | ||
314 | /* CHECK: Is really nothing senseful there */ | ||
315 | /* ASSUMPTION: it contains nothing valid */ | ||
316 | i = 0; | ||
317 | } | ||
318 | #ifdef SUPPORT_SYSRQ | ||
319 | port->sysrq = 0; | ||
320 | #endif | ||
321 | goto error_return; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Asynchron mode interrupt handler | ||
326 | */ | ||
327 | static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) | ||
328 | { | ||
329 | u8 events; | ||
330 | struct uart_port *port = (struct uart_port *)data; | ||
331 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
332 | volatile smc_t *smcp = pinfo->smcp; | ||
333 | volatile scc_t *sccp = pinfo->sccp; | ||
334 | |||
335 | pr_debug("CPM uart[%d]:IRQ\n", port->line); | ||
336 | |||
337 | if (IS_SMC(pinfo)) { | ||
338 | events = smcp->smc_smce; | ||
339 | if (events & SMCM_BRKE) | ||
340 | uart_handle_break(port); | ||
341 | if (events & SMCM_RX) | ||
342 | cpm_uart_int_rx(port, regs); | ||
343 | if (events & SMCM_TX) | ||
344 | cpm_uart_int_tx(port, regs); | ||
345 | smcp->smc_smce = events; | ||
346 | } else { | ||
347 | events = sccp->scc_scce; | ||
348 | if (events & UART_SCCM_BRKE) | ||
349 | uart_handle_break(port); | ||
350 | if (events & UART_SCCM_RX) | ||
351 | cpm_uart_int_rx(port, regs); | ||
352 | if (events & UART_SCCM_TX) | ||
353 | cpm_uart_int_tx(port, regs); | ||
354 | sccp->scc_scce = events; | ||
355 | } | ||
356 | return (events) ? IRQ_HANDLED : IRQ_NONE; | ||
357 | } | ||
358 | |||
359 | static int cpm_uart_startup(struct uart_port *port) | ||
360 | { | ||
361 | int retval; | ||
362 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
363 | |||
364 | pr_debug("CPM uart[%d]:startup\n", port->line); | ||
365 | |||
366 | /* Install interrupt handler. */ | ||
367 | retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port); | ||
368 | if (retval) | ||
369 | return retval; | ||
370 | |||
371 | /* Startup rx-int */ | ||
372 | if (IS_SMC(pinfo)) { | ||
373 | pinfo->smcp->smc_smcm |= SMCM_RX; | ||
374 | pinfo->smcp->smc_smcmr |= SMCMR_REN; | ||
375 | } else { | ||
376 | pinfo->sccp->scc_sccm |= UART_SCCM_RX; | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Shutdown the uart | ||
384 | */ | ||
385 | static void cpm_uart_shutdown(struct uart_port *port) | ||
386 | { | ||
387 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
388 | int line = pinfo - cpm_uart_ports; | ||
389 | |||
390 | pr_debug("CPM uart[%d]:shutdown\n", port->line); | ||
391 | |||
392 | /* free interrupt handler */ | ||
393 | free_irq(port->irq, port); | ||
394 | |||
395 | /* If the port is not the console, disable Rx and Tx. */ | ||
396 | if (!(pinfo->flags & FLAG_CONSOLE)) { | ||
397 | /* Stop uarts */ | ||
398 | if (IS_SMC(pinfo)) { | ||
399 | volatile smc_t *smcp = pinfo->smcp; | ||
400 | smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
401 | smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); | ||
402 | } else { | ||
403 | volatile scc_t *sccp = pinfo->sccp; | ||
404 | sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
405 | sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); | ||
406 | } | ||
407 | |||
408 | /* Shut them really down and reinit buffer descriptors */ | ||
409 | cpm_line_cr_cmd(line, CPM_CR_STOP_TX); | ||
410 | cpm_uart_initbd(pinfo); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | static void cpm_uart_set_termios(struct uart_port *port, | ||
415 | struct termios *termios, struct termios *old) | ||
416 | { | ||
417 | int baud; | ||
418 | unsigned long flags; | ||
419 | u16 cval, scval, prev_mode; | ||
420 | int bits, sbits; | ||
421 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
422 | volatile smc_t *smcp = pinfo->smcp; | ||
423 | volatile scc_t *sccp = pinfo->sccp; | ||
424 | |||
425 | pr_debug("CPM uart[%d]:set_termios\n", port->line); | ||
426 | |||
427 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | ||
428 | |||
429 | /* Character length programmed into the mode register is the | ||
430 | * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, | ||
431 | * 1 or 2 stop bits, minus 1. | ||
432 | * The value 'bits' counts this for us. | ||
433 | */ | ||
434 | cval = 0; | ||
435 | scval = 0; | ||
436 | |||
437 | /* byte size */ | ||
438 | switch (termios->c_cflag & CSIZE) { | ||
439 | case CS5: | ||
440 | bits = 5; | ||
441 | break; | ||
442 | case CS6: | ||
443 | bits = 6; | ||
444 | break; | ||
445 | case CS7: | ||
446 | bits = 7; | ||
447 | break; | ||
448 | case CS8: | ||
449 | bits = 8; | ||
450 | break; | ||
451 | /* Never happens, but GCC is too dumb to figure it out */ | ||
452 | default: | ||
453 | bits = 8; | ||
454 | break; | ||
455 | } | ||
456 | sbits = bits - 5; | ||
457 | |||
458 | if (termios->c_cflag & CSTOPB) { | ||
459 | cval |= SMCMR_SL; /* Two stops */ | ||
460 | scval |= SCU_PSMR_SL; | ||
461 | bits++; | ||
462 | } | ||
463 | |||
464 | if (termios->c_cflag & PARENB) { | ||
465 | cval |= SMCMR_PEN; | ||
466 | scval |= SCU_PSMR_PEN; | ||
467 | bits++; | ||
468 | if (!(termios->c_cflag & PARODD)) { | ||
469 | cval |= SMCMR_PM_EVEN; | ||
470 | scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * Set up parity check flag | ||
476 | */ | ||
477 | #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) | ||
478 | |||
479 | port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); | ||
480 | if (termios->c_iflag & INPCK) | ||
481 | port->read_status_mask |= BD_SC_FR | BD_SC_PR; | ||
482 | if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK)) | ||
483 | port->read_status_mask |= BD_SC_BR; | ||
484 | |||
485 | /* | ||
486 | * Characters to ignore | ||
487 | */ | ||
488 | port->ignore_status_mask = 0; | ||
489 | if (termios->c_iflag & IGNPAR) | ||
490 | port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; | ||
491 | if (termios->c_iflag & IGNBRK) { | ||
492 | port->ignore_status_mask |= BD_SC_BR; | ||
493 | /* | ||
494 | * If we're ignore parity and break indicators, ignore | ||
495 | * overruns too. (For real raw support). | ||
496 | */ | ||
497 | if (termios->c_iflag & IGNPAR) | ||
498 | port->ignore_status_mask |= BD_SC_OV; | ||
499 | } | ||
500 | /* | ||
501 | * !!! ignore all characters if CREAD is not set | ||
502 | */ | ||
503 | if ((termios->c_cflag & CREAD) == 0) | ||
504 | port->read_status_mask &= ~BD_SC_EMPTY; | ||
505 | |||
506 | spin_lock_irqsave(&port->lock, flags); | ||
507 | |||
508 | /* Start bit has not been added (so don't, because we would just | ||
509 | * subtract it later), and we need to add one for the number of | ||
510 | * stops bits (there is always at least one). | ||
511 | */ | ||
512 | bits++; | ||
513 | if (IS_SMC(pinfo)) { | ||
514 | /* Set the mode register. We want to keep a copy of the | ||
515 | * enables, because we want to put them back if they were | ||
516 | * present. | ||
517 | */ | ||
518 | prev_mode = smcp->smc_smcmr; | ||
519 | smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; | ||
520 | smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); | ||
521 | } else { | ||
522 | sccp->scc_psmr = (sbits << 12) | scval; | ||
523 | } | ||
524 | |||
525 | cpm_set_brg(pinfo->brg - 1, baud); | ||
526 | spin_unlock_irqrestore(&port->lock, flags); | ||
527 | |||
528 | } | ||
529 | |||
530 | static const char *cpm_uart_type(struct uart_port *port) | ||
531 | { | ||
532 | pr_debug("CPM uart[%d]:uart_type\n", port->line); | ||
533 | |||
534 | return port->type == PORT_CPM ? "CPM UART" : NULL; | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * verify the new serial_struct (for TIOCSSERIAL). | ||
539 | */ | ||
540 | static int cpm_uart_verify_port(struct uart_port *port, | ||
541 | struct serial_struct *ser) | ||
542 | { | ||
543 | int ret = 0; | ||
544 | |||
545 | pr_debug("CPM uart[%d]:verify_port\n", port->line); | ||
546 | |||
547 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) | ||
548 | ret = -EINVAL; | ||
549 | if (ser->irq < 0 || ser->irq >= NR_IRQS) | ||
550 | ret = -EINVAL; | ||
551 | if (ser->baud_base < 9600) | ||
552 | ret = -EINVAL; | ||
553 | return ret; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * Transmit characters, refill buffer descriptor, if possible | ||
558 | */ | ||
559 | static int cpm_uart_tx_pump(struct uart_port *port) | ||
560 | { | ||
561 | volatile cbd_t *bdp; | ||
562 | unsigned char *p; | ||
563 | int count; | ||
564 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
565 | struct circ_buf *xmit = &port->info->xmit; | ||
566 | |||
567 | /* Handle xon/xoff */ | ||
568 | if (port->x_char) { | ||
569 | /* Pick next descriptor and fill from buffer */ | ||
570 | bdp = pinfo->tx_cur; | ||
571 | |||
572 | p = bus_to_virt(bdp->cbd_bufaddr); | ||
573 | *p++ = xmit->buf[xmit->tail]; | ||
574 | bdp->cbd_datlen = 1; | ||
575 | bdp->cbd_sc |= BD_SC_READY; | ||
576 | /* Get next BD. */ | ||
577 | if (bdp->cbd_sc & BD_SC_WRAP) | ||
578 | bdp = pinfo->tx_bd_base; | ||
579 | else | ||
580 | bdp++; | ||
581 | pinfo->tx_cur = bdp; | ||
582 | |||
583 | port->icount.tx++; | ||
584 | port->x_char = 0; | ||
585 | return 1; | ||
586 | } | ||
587 | |||
588 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | ||
589 | cpm_uart_stop_tx(port, 0); | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | /* Pick next descriptor and fill from buffer */ | ||
594 | bdp = pinfo->tx_cur; | ||
595 | |||
596 | while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { | ||
597 | count = 0; | ||
598 | p = bus_to_virt(bdp->cbd_bufaddr); | ||
599 | while (count < pinfo->tx_fifosize) { | ||
600 | *p++ = xmit->buf[xmit->tail]; | ||
601 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
602 | port->icount.tx++; | ||
603 | count++; | ||
604 | if (xmit->head == xmit->tail) | ||
605 | break; | ||
606 | } | ||
607 | bdp->cbd_datlen = count; | ||
608 | bdp->cbd_sc |= BD_SC_READY; | ||
609 | /* Get next BD. */ | ||
610 | if (bdp->cbd_sc & BD_SC_WRAP) | ||
611 | bdp = pinfo->tx_bd_base; | ||
612 | else | ||
613 | bdp++; | ||
614 | } | ||
615 | pinfo->tx_cur = bdp; | ||
616 | |||
617 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
618 | uart_write_wakeup(port); | ||
619 | |||
620 | if (uart_circ_empty(xmit)) { | ||
621 | cpm_uart_stop_tx(port, 0); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | return 1; | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * init buffer descriptors | ||
630 | */ | ||
631 | static void cpm_uart_initbd(struct uart_cpm_port *pinfo) | ||
632 | { | ||
633 | int i; | ||
634 | u8 *mem_addr; | ||
635 | volatile cbd_t *bdp; | ||
636 | |||
637 | pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); | ||
638 | |||
639 | /* Set the physical address of the host memory | ||
640 | * buffers in the buffer descriptors, and the | ||
641 | * virtual address for us to work with. | ||
642 | */ | ||
643 | mem_addr = pinfo->mem_addr; | ||
644 | bdp = pinfo->rx_cur = pinfo->rx_bd_base; | ||
645 | for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { | ||
646 | bdp->cbd_bufaddr = virt_to_bus(mem_addr); | ||
647 | bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; | ||
648 | mem_addr += pinfo->rx_fifosize; | ||
649 | } | ||
650 | |||
651 | bdp->cbd_bufaddr = virt_to_bus(mem_addr); | ||
652 | bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; | ||
653 | |||
654 | /* Set the physical address of the host memory | ||
655 | * buffers in the buffer descriptors, and the | ||
656 | * virtual address for us to work with. | ||
657 | */ | ||
658 | mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); | ||
659 | bdp = pinfo->tx_cur = pinfo->tx_bd_base; | ||
660 | for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { | ||
661 | bdp->cbd_bufaddr = virt_to_bus(mem_addr); | ||
662 | bdp->cbd_sc = BD_SC_INTRPT; | ||
663 | mem_addr += pinfo->tx_fifosize; | ||
664 | } | ||
665 | |||
666 | bdp->cbd_bufaddr = virt_to_bus(mem_addr); | ||
667 | bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; | ||
668 | } | ||
669 | |||
670 | static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) | ||
671 | { | ||
672 | int line = pinfo - cpm_uart_ports; | ||
673 | volatile scc_t *scp; | ||
674 | volatile scc_uart_t *sup; | ||
675 | |||
676 | pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); | ||
677 | |||
678 | scp = pinfo->sccp; | ||
679 | sup = pinfo->sccup; | ||
680 | |||
681 | /* Store address */ | ||
682 | pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE; | ||
683 | pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE; | ||
684 | |||
685 | /* Set up the uart parameters in the | ||
686 | * parameter ram. | ||
687 | */ | ||
688 | |||
689 | cpm_set_scc_fcr(sup); | ||
690 | |||
691 | sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize; | ||
692 | sup->scc_maxidl = pinfo->rx_fifosize; | ||
693 | sup->scc_brkcr = 1; | ||
694 | sup->scc_parec = 0; | ||
695 | sup->scc_frmec = 0; | ||
696 | sup->scc_nosec = 0; | ||
697 | sup->scc_brkec = 0; | ||
698 | sup->scc_uaddr1 = 0; | ||
699 | sup->scc_uaddr2 = 0; | ||
700 | sup->scc_toseq = 0; | ||
701 | sup->scc_char1 = 0x8000; | ||
702 | sup->scc_char2 = 0x8000; | ||
703 | sup->scc_char3 = 0x8000; | ||
704 | sup->scc_char4 = 0x8000; | ||
705 | sup->scc_char5 = 0x8000; | ||
706 | sup->scc_char6 = 0x8000; | ||
707 | sup->scc_char7 = 0x8000; | ||
708 | sup->scc_char8 = 0x8000; | ||
709 | sup->scc_rccm = 0xc0ff; | ||
710 | |||
711 | /* Send the CPM an initialize command. | ||
712 | */ | ||
713 | cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); | ||
714 | |||
715 | /* Set UART mode, 8 bit, no parity, one stop. | ||
716 | * Enable receive and transmit. | ||
717 | */ | ||
718 | scp->scc_gsmrh = 0; | ||
719 | scp->scc_gsmrl = | ||
720 | (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); | ||
721 | |||
722 | /* Enable rx interrupts and clear all pending events. */ | ||
723 | scp->scc_sccm = 0; | ||
724 | scp->scc_scce = 0xffff; | ||
725 | scp->scc_dsr = 0x7e7e; | ||
726 | scp->scc_psmr = 0x3000; | ||
727 | |||
728 | scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
729 | } | ||
730 | |||
731 | static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) | ||
732 | { | ||
733 | int line = pinfo - cpm_uart_ports; | ||
734 | volatile smc_t *sp; | ||
735 | volatile smc_uart_t *up; | ||
736 | |||
737 | pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); | ||
738 | |||
739 | sp = pinfo->smcp; | ||
740 | up = pinfo->smcup; | ||
741 | |||
742 | /* Store address */ | ||
743 | pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE; | ||
744 | pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE; | ||
745 | |||
746 | /* | ||
747 | * In case SMC1 is being relocated... | ||
748 | */ | ||
749 | #if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) | ||
750 | up->smc_rbptr = pinfo->smcup->smc_rbase; | ||
751 | up->smc_tbptr = pinfo->smcup->smc_tbase; | ||
752 | up->smc_rstate = 0; | ||
753 | up->smc_tstate = 0; | ||
754 | up->smc_brkcr = 1; /* number of break chars */ | ||
755 | up->smc_brkec = 0; | ||
756 | #endif | ||
757 | |||
758 | /* Set up the uart parameters in the | ||
759 | * parameter ram. | ||
760 | */ | ||
761 | cpm_set_smc_fcr(up); | ||
762 | |||
763 | /* Using idle charater time requires some additional tuning. */ | ||
764 | up->smc_mrblr = pinfo->rx_fifosize; | ||
765 | up->smc_maxidl = pinfo->rx_fifosize; | ||
766 | up->smc_brkcr = 1; | ||
767 | |||
768 | cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); | ||
769 | |||
770 | /* Set UART mode, 8 bit, no parity, one stop. | ||
771 | * Enable receive and transmit. | ||
772 | */ | ||
773 | sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | ||
774 | |||
775 | /* Enable only rx interrupts clear all pending events. */ | ||
776 | sp->smc_smcm = 0; | ||
777 | sp->smc_smce = 0xff; | ||
778 | |||
779 | sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); | ||
780 | } | ||
781 | |||
782 | /* | ||
783 | * Initialize port. This is called from early_console stuff | ||
784 | * so we have to be careful here ! | ||
785 | */ | ||
786 | static int cpm_uart_request_port(struct uart_port *port) | ||
787 | { | ||
788 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
789 | int ret; | ||
790 | |||
791 | pr_debug("CPM uart[%d]:request port\n", port->line); | ||
792 | |||
793 | if (pinfo->flags & FLAG_CONSOLE) | ||
794 | return 0; | ||
795 | |||
796 | /* | ||
797 | * Setup any port IO, connect any baud rate generators, | ||
798 | * etc. This is expected to be handled by board | ||
799 | * dependant code | ||
800 | */ | ||
801 | if (pinfo->set_lineif) | ||
802 | pinfo->set_lineif(pinfo); | ||
803 | |||
804 | if (IS_SMC(pinfo)) { | ||
805 | pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); | ||
806 | pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
807 | } else { | ||
808 | pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); | ||
809 | pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
810 | } | ||
811 | |||
812 | ret = cpm_uart_allocbuf(pinfo, 0); | ||
813 | |||
814 | if (ret) | ||
815 | return ret; | ||
816 | |||
817 | cpm_uart_initbd(pinfo); | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static void cpm_uart_release_port(struct uart_port *port) | ||
823 | { | ||
824 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; | ||
825 | |||
826 | if (!(pinfo->flags & FLAG_CONSOLE)) | ||
827 | cpm_uart_freebuf(pinfo); | ||
828 | } | ||
829 | |||
830 | /* | ||
831 | * Configure/autoconfigure the port. | ||
832 | */ | ||
833 | static void cpm_uart_config_port(struct uart_port *port, int flags) | ||
834 | { | ||
835 | pr_debug("CPM uart[%d]:config_port\n", port->line); | ||
836 | |||
837 | if (flags & UART_CONFIG_TYPE) { | ||
838 | port->type = PORT_CPM; | ||
839 | cpm_uart_request_port(port); | ||
840 | } | ||
841 | } | ||
842 | static struct uart_ops cpm_uart_pops = { | ||
843 | .tx_empty = cpm_uart_tx_empty, | ||
844 | .set_mctrl = cpm_uart_set_mctrl, | ||
845 | .get_mctrl = cpm_uart_get_mctrl, | ||
846 | .stop_tx = cpm_uart_stop_tx, | ||
847 | .start_tx = cpm_uart_start_tx, | ||
848 | .stop_rx = cpm_uart_stop_rx, | ||
849 | .enable_ms = cpm_uart_enable_ms, | ||
850 | .break_ctl = cpm_uart_break_ctl, | ||
851 | .startup = cpm_uart_startup, | ||
852 | .shutdown = cpm_uart_shutdown, | ||
853 | .set_termios = cpm_uart_set_termios, | ||
854 | .type = cpm_uart_type, | ||
855 | .release_port = cpm_uart_release_port, | ||
856 | .request_port = cpm_uart_request_port, | ||
857 | .config_port = cpm_uart_config_port, | ||
858 | .verify_port = cpm_uart_verify_port, | ||
859 | }; | ||
860 | |||
861 | struct uart_cpm_port cpm_uart_ports[UART_NR] = { | ||
862 | [UART_SMC1] = { | ||
863 | .port = { | ||
864 | .irq = SMC1_IRQ, | ||
865 | .ops = &cpm_uart_pops, | ||
866 | .iotype = SERIAL_IO_MEM, | ||
867 | .lock = SPIN_LOCK_UNLOCKED, | ||
868 | }, | ||
869 | .flags = FLAG_SMC, | ||
870 | .tx_nrfifos = TX_NUM_FIFO, | ||
871 | .tx_fifosize = TX_BUF_SIZE, | ||
872 | .rx_nrfifos = RX_NUM_FIFO, | ||
873 | .rx_fifosize = RX_BUF_SIZE, | ||
874 | .set_lineif = smc1_lineif, | ||
875 | }, | ||
876 | [UART_SMC2] = { | ||
877 | .port = { | ||
878 | .irq = SMC2_IRQ, | ||
879 | .ops = &cpm_uart_pops, | ||
880 | .iotype = SERIAL_IO_MEM, | ||
881 | .lock = SPIN_LOCK_UNLOCKED, | ||
882 | }, | ||
883 | .flags = FLAG_SMC, | ||
884 | .tx_nrfifos = TX_NUM_FIFO, | ||
885 | .tx_fifosize = TX_BUF_SIZE, | ||
886 | .rx_nrfifos = RX_NUM_FIFO, | ||
887 | .rx_fifosize = RX_BUF_SIZE, | ||
888 | .set_lineif = smc2_lineif, | ||
889 | #ifdef CONFIG_SERIAL_CPM_ALT_SMC2 | ||
890 | .is_portb = 1, | ||
891 | #endif | ||
892 | }, | ||
893 | [UART_SCC1] = { | ||
894 | .port = { | ||
895 | .irq = SCC1_IRQ, | ||
896 | .ops = &cpm_uart_pops, | ||
897 | .iotype = SERIAL_IO_MEM, | ||
898 | .lock = SPIN_LOCK_UNLOCKED, | ||
899 | }, | ||
900 | .tx_nrfifos = TX_NUM_FIFO, | ||
901 | .tx_fifosize = TX_BUF_SIZE, | ||
902 | .rx_nrfifos = RX_NUM_FIFO, | ||
903 | .rx_fifosize = RX_BUF_SIZE, | ||
904 | .set_lineif = scc1_lineif, | ||
905 | }, | ||
906 | [UART_SCC2] = { | ||
907 | .port = { | ||
908 | .irq = SCC2_IRQ, | ||
909 | .ops = &cpm_uart_pops, | ||
910 | .iotype = SERIAL_IO_MEM, | ||
911 | .lock = SPIN_LOCK_UNLOCKED, | ||
912 | }, | ||
913 | .tx_nrfifos = TX_NUM_FIFO, | ||
914 | .tx_fifosize = TX_BUF_SIZE, | ||
915 | .rx_nrfifos = RX_NUM_FIFO, | ||
916 | .rx_fifosize = RX_BUF_SIZE, | ||
917 | .set_lineif = scc2_lineif, | ||
918 | }, | ||
919 | [UART_SCC3] = { | ||
920 | .port = { | ||
921 | .irq = SCC3_IRQ, | ||
922 | .ops = &cpm_uart_pops, | ||
923 | .iotype = SERIAL_IO_MEM, | ||
924 | .lock = SPIN_LOCK_UNLOCKED, | ||
925 | }, | ||
926 | .tx_nrfifos = TX_NUM_FIFO, | ||
927 | .tx_fifosize = TX_BUF_SIZE, | ||
928 | .rx_nrfifos = RX_NUM_FIFO, | ||
929 | .rx_fifosize = RX_BUF_SIZE, | ||
930 | .set_lineif = scc3_lineif, | ||
931 | }, | ||
932 | [UART_SCC4] = { | ||
933 | .port = { | ||
934 | .irq = SCC4_IRQ, | ||
935 | .ops = &cpm_uart_pops, | ||
936 | .iotype = SERIAL_IO_MEM, | ||
937 | .lock = SPIN_LOCK_UNLOCKED, | ||
938 | }, | ||
939 | .tx_nrfifos = TX_NUM_FIFO, | ||
940 | .tx_fifosize = TX_BUF_SIZE, | ||
941 | .rx_nrfifos = RX_NUM_FIFO, | ||
942 | .rx_fifosize = RX_BUF_SIZE, | ||
943 | .set_lineif = scc4_lineif, | ||
944 | }, | ||
945 | }; | ||
946 | |||
947 | #ifdef CONFIG_SERIAL_CPM_CONSOLE | ||
948 | /* | ||
949 | * Print a string to the serial port trying not to disturb | ||
950 | * any possible real use of the port... | ||
951 | * | ||
952 | * Note that this is called with interrupts already disabled | ||
953 | */ | ||
954 | static void cpm_uart_console_write(struct console *co, const char *s, | ||
955 | u_int count) | ||
956 | { | ||
957 | struct uart_cpm_port *pinfo = | ||
958 | &cpm_uart_ports[cpm_uart_port_map[co->index]]; | ||
959 | unsigned int i; | ||
960 | volatile cbd_t *bdp, *bdbase; | ||
961 | volatile unsigned char *cp; | ||
962 | |||
963 | /* Get the address of the host memory buffer. | ||
964 | */ | ||
965 | bdp = pinfo->tx_cur; | ||
966 | bdbase = pinfo->tx_bd_base; | ||
967 | |||
968 | /* | ||
969 | * Now, do each character. This is not as bad as it looks | ||
970 | * since this is a holding FIFO and not a transmitting FIFO. | ||
971 | * We could add the complexity of filling the entire transmit | ||
972 | * buffer, but we would just wait longer between accesses...... | ||
973 | */ | ||
974 | for (i = 0; i < count; i++, s++) { | ||
975 | /* Wait for transmitter fifo to empty. | ||
976 | * Ready indicates output is ready, and xmt is doing | ||
977 | * that, not that it is ready for us to send. | ||
978 | */ | ||
979 | while ((bdp->cbd_sc & BD_SC_READY) != 0) | ||
980 | ; | ||
981 | |||
982 | /* Send the character out. | ||
983 | * If the buffer address is in the CPM DPRAM, don't | ||
984 | * convert it. | ||
985 | */ | ||
986 | if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR) | ||
987 | cp = (unsigned char *) (bdp->cbd_bufaddr); | ||
988 | else | ||
989 | cp = bus_to_virt(bdp->cbd_bufaddr); | ||
990 | |||
991 | *cp = *s; | ||
992 | |||
993 | bdp->cbd_datlen = 1; | ||
994 | bdp->cbd_sc |= BD_SC_READY; | ||
995 | |||
996 | if (bdp->cbd_sc & BD_SC_WRAP) | ||
997 | bdp = bdbase; | ||
998 | else | ||
999 | bdp++; | ||
1000 | |||
1001 | /* if a LF, also do CR... */ | ||
1002 | if (*s == 10) { | ||
1003 | while ((bdp->cbd_sc & BD_SC_READY) != 0) | ||
1004 | ; | ||
1005 | |||
1006 | if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR) | ||
1007 | cp = (unsigned char *) (bdp->cbd_bufaddr); | ||
1008 | else | ||
1009 | cp = bus_to_virt(bdp->cbd_bufaddr); | ||
1010 | |||
1011 | *cp = 13; | ||
1012 | bdp->cbd_datlen = 1; | ||
1013 | bdp->cbd_sc |= BD_SC_READY; | ||
1014 | |||
1015 | if (bdp->cbd_sc & BD_SC_WRAP) | ||
1016 | bdp = bdbase; | ||
1017 | else | ||
1018 | bdp++; | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | /* | ||
1023 | * Finally, Wait for transmitter & holding register to empty | ||
1024 | * and restore the IER | ||
1025 | */ | ||
1026 | while ((bdp->cbd_sc & BD_SC_READY) != 0) | ||
1027 | ; | ||
1028 | |||
1029 | pinfo->tx_cur = (volatile cbd_t *) bdp; | ||
1030 | } | ||
1031 | |||
1032 | /* | ||
1033 | * Setup console. Be careful is called early ! | ||
1034 | */ | ||
1035 | static int __init cpm_uart_console_setup(struct console *co, char *options) | ||
1036 | { | ||
1037 | struct uart_port *port; | ||
1038 | struct uart_cpm_port *pinfo; | ||
1039 | int baud = 38400; | ||
1040 | int bits = 8; | ||
1041 | int parity = 'n'; | ||
1042 | int flow = 'n'; | ||
1043 | int ret; | ||
1044 | |||
1045 | port = | ||
1046 | (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; | ||
1047 | pinfo = (struct uart_cpm_port *)port; | ||
1048 | |||
1049 | pinfo->flags |= FLAG_CONSOLE; | ||
1050 | |||
1051 | if (options) { | ||
1052 | uart_parse_options(options, &baud, &parity, &bits, &flow); | ||
1053 | } else { | ||
1054 | bd_t *bd = (bd_t *) __res; | ||
1055 | |||
1056 | if (bd->bi_baudrate) | ||
1057 | baud = bd->bi_baudrate; | ||
1058 | else | ||
1059 | baud = 9600; | ||
1060 | } | ||
1061 | |||
1062 | /* | ||
1063 | * Setup any port IO, connect any baud rate generators, | ||
1064 | * etc. This is expected to be handled by board | ||
1065 | * dependant code | ||
1066 | */ | ||
1067 | if (pinfo->set_lineif) | ||
1068 | pinfo->set_lineif(pinfo); | ||
1069 | |||
1070 | if (IS_SMC(pinfo)) { | ||
1071 | pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); | ||
1072 | pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
1073 | } else { | ||
1074 | pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); | ||
1075 | pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
1076 | } | ||
1077 | |||
1078 | ret = cpm_uart_allocbuf(pinfo, 1); | ||
1079 | |||
1080 | if (ret) | ||
1081 | return ret; | ||
1082 | |||
1083 | cpm_uart_initbd(pinfo); | ||
1084 | |||
1085 | if (IS_SMC(pinfo)) | ||
1086 | cpm_uart_init_smc(pinfo); | ||
1087 | else | ||
1088 | cpm_uart_init_scc(pinfo); | ||
1089 | |||
1090 | uart_set_options(port, co, baud, parity, bits, flow); | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | extern struct uart_driver cpm_reg; | ||
1096 | static struct console cpm_scc_uart_console = { | ||
1097 | .name "ttyCPM", | ||
1098 | .write cpm_uart_console_write, | ||
1099 | .device uart_console_device, | ||
1100 | .setup cpm_uart_console_setup, | ||
1101 | .flags CON_PRINTBUFFER, | ||
1102 | .index -1, | ||
1103 | .data = &cpm_reg, | ||
1104 | }; | ||
1105 | |||
1106 | int __init cpm_uart_console_init(void) | ||
1107 | { | ||
1108 | int ret = cpm_uart_init_portdesc(); | ||
1109 | |||
1110 | if (!ret) | ||
1111 | register_console(&cpm_scc_uart_console); | ||
1112 | return ret; | ||
1113 | } | ||
1114 | |||
1115 | console_initcall(cpm_uart_console_init); | ||
1116 | |||
1117 | #define CPM_UART_CONSOLE &cpm_scc_uart_console | ||
1118 | #else | ||
1119 | #define CPM_UART_CONSOLE NULL | ||
1120 | #endif | ||
1121 | |||
1122 | static struct uart_driver cpm_reg = { | ||
1123 | .owner = THIS_MODULE, | ||
1124 | .driver_name = "ttyCPM", | ||
1125 | .dev_name = "ttyCPM", | ||
1126 | .major = SERIAL_CPM_MAJOR, | ||
1127 | .minor = SERIAL_CPM_MINOR, | ||
1128 | .cons = CPM_UART_CONSOLE, | ||
1129 | }; | ||
1130 | |||
1131 | static int __init cpm_uart_init(void) | ||
1132 | { | ||
1133 | int ret, i; | ||
1134 | |||
1135 | printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n"); | ||
1136 | |||
1137 | #ifndef CONFIG_SERIAL_CPM_CONSOLE | ||
1138 | ret = cpm_uart_init_portdesc(); | ||
1139 | if (ret) | ||
1140 | return ret; | ||
1141 | #endif | ||
1142 | |||
1143 | cpm_reg.nr = cpm_uart_nr; | ||
1144 | ret = uart_register_driver(&cpm_reg); | ||
1145 | |||
1146 | if (ret) | ||
1147 | return ret; | ||
1148 | |||
1149 | for (i = 0; i < cpm_uart_nr; i++) { | ||
1150 | int con = cpm_uart_port_map[i]; | ||
1151 | cpm_uart_ports[con].port.line = i; | ||
1152 | cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; | ||
1153 | uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); | ||
1154 | } | ||
1155 | |||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | static void __exit cpm_uart_exit(void) | ||
1160 | { | ||
1161 | int i; | ||
1162 | |||
1163 | for (i = 0; i < cpm_uart_nr; i++) { | ||
1164 | int con = cpm_uart_port_map[i]; | ||
1165 | uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port); | ||
1166 | } | ||
1167 | |||
1168 | uart_unregister_driver(&cpm_reg); | ||
1169 | } | ||
1170 | |||
1171 | module_init(cpm_uart_init); | ||
1172 | module_exit(cpm_uart_exit); | ||
1173 | |||
1174 | MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis"); | ||
1175 | MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $"); | ||
1176 | MODULE_LICENSE("GPL"); | ||
1177 | MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR); | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c new file mode 100644 index 000000000000..de26cf7b003c --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart.c | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports; CPM1 definitions | ||
5 | * | ||
6 | * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2) | ||
7 | * Pantelis Antoniou (panto@intracom.gr) (CPM1) | ||
8 | * | ||
9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | ||
10 | * (C) 2004 Intracom, S.A. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/tty.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/serial.h> | ||
34 | #include <linux/console.h> | ||
35 | #include <linux/sysrq.h> | ||
36 | #include <linux/device.h> | ||
37 | #include <linux/bootmem.h> | ||
38 | #include <linux/dma-mapping.h> | ||
39 | |||
40 | #include <asm/io.h> | ||
41 | #include <asm/irq.h> | ||
42 | |||
43 | #include <linux/serial_core.h> | ||
44 | #include <linux/kernel.h> | ||
45 | |||
46 | #include "cpm_uart.h" | ||
47 | |||
48 | /**************************************************************/ | ||
49 | |||
50 | void cpm_line_cr_cmd(int line, int cmd) | ||
51 | { | ||
52 | ushort val; | ||
53 | volatile cpm8xx_t *cp = cpmp; | ||
54 | |||
55 | switch (line) { | ||
56 | case UART_SMC1: | ||
57 | val = mk_cr_cmd(CPM_CR_CH_SMC1, cmd) | CPM_CR_FLG; | ||
58 | break; | ||
59 | case UART_SMC2: | ||
60 | val = mk_cr_cmd(CPM_CR_CH_SMC2, cmd) | CPM_CR_FLG; | ||
61 | break; | ||
62 | case UART_SCC1: | ||
63 | val = mk_cr_cmd(CPM_CR_CH_SCC1, cmd) | CPM_CR_FLG; | ||
64 | break; | ||
65 | case UART_SCC2: | ||
66 | val = mk_cr_cmd(CPM_CR_CH_SCC2, cmd) | CPM_CR_FLG; | ||
67 | break; | ||
68 | case UART_SCC3: | ||
69 | val = mk_cr_cmd(CPM_CR_CH_SCC3, cmd) | CPM_CR_FLG; | ||
70 | break; | ||
71 | case UART_SCC4: | ||
72 | val = mk_cr_cmd(CPM_CR_CH_SCC4, cmd) | CPM_CR_FLG; | ||
73 | break; | ||
74 | default: | ||
75 | return; | ||
76 | |||
77 | } | ||
78 | cp->cp_cpcr = val; | ||
79 | while (cp->cp_cpcr & CPM_CR_FLG) ; | ||
80 | } | ||
81 | |||
82 | void smc1_lineif(struct uart_cpm_port *pinfo) | ||
83 | { | ||
84 | volatile cpm8xx_t *cp = cpmp; | ||
85 | unsigned int iobits = 0x000000c0; | ||
86 | |||
87 | if (!pinfo->is_portb) { | ||
88 | cp->cp_pbpar |= iobits; | ||
89 | cp->cp_pbdir &= ~iobits; | ||
90 | cp->cp_pbodr &= ~iobits; | ||
91 | } else { | ||
92 | ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits; | ||
93 | ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits; | ||
94 | ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; | ||
95 | } | ||
96 | |||
97 | pinfo->brg = 1; | ||
98 | } | ||
99 | |||
100 | void smc2_lineif(struct uart_cpm_port *pinfo) | ||
101 | { | ||
102 | /* XXX SMC2: insert port configuration here */ | ||
103 | pinfo->brg = 2; | ||
104 | } | ||
105 | |||
106 | void scc1_lineif(struct uart_cpm_port *pinfo) | ||
107 | { | ||
108 | /* XXX SCC1: insert port configuration here */ | ||
109 | pinfo->brg = 1; | ||
110 | } | ||
111 | |||
112 | void scc2_lineif(struct uart_cpm_port *pinfo) | ||
113 | { | ||
114 | /* XXX SCC2: insert port configuration here */ | ||
115 | pinfo->brg = 2; | ||
116 | } | ||
117 | |||
118 | void scc3_lineif(struct uart_cpm_port *pinfo) | ||
119 | { | ||
120 | /* XXX SCC3: insert port configuration here */ | ||
121 | pinfo->brg = 3; | ||
122 | } | ||
123 | |||
124 | void scc4_lineif(struct uart_cpm_port *pinfo) | ||
125 | { | ||
126 | /* XXX SCC4: insert port configuration here */ | ||
127 | pinfo->brg = 4; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Allocate DP-Ram and memory buffers. We need to allocate a transmit and | ||
132 | * receive buffer descriptors from dual port ram, and a character | ||
133 | * buffer area from host mem. If we are allocating for the console we need | ||
134 | * to do it from bootmem | ||
135 | */ | ||
136 | int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) | ||
137 | { | ||
138 | int dpmemsz, memsz; | ||
139 | u8 *dp_mem; | ||
140 | uint dp_offset; | ||
141 | u8 *mem_addr; | ||
142 | dma_addr_t dma_addr = 0; | ||
143 | |||
144 | pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); | ||
145 | |||
146 | dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); | ||
147 | dp_offset = cpm_dpalloc(dpmemsz, 8); | ||
148 | if (IS_DPERR(dp_offset)) { | ||
149 | printk(KERN_ERR | ||
150 | "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); | ||
151 | return -ENOMEM; | ||
152 | } | ||
153 | dp_mem = cpm_dpram_addr(dp_offset); | ||
154 | |||
155 | memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + | ||
156 | L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); | ||
157 | if (is_con) { | ||
158 | mem_addr = (u8 *) m8xx_cpm_hostalloc(memsz); | ||
159 | dma_addr = 0; | ||
160 | } else | ||
161 | mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, | ||
162 | GFP_KERNEL); | ||
163 | |||
164 | if (mem_addr == NULL) { | ||
165 | cpm_dpfree(dp_offset); | ||
166 | printk(KERN_ERR | ||
167 | "cpm_uart_cpm1.c: could not allocate coherent memory\n"); | ||
168 | return -ENOMEM; | ||
169 | } | ||
170 | |||
171 | pinfo->dp_addr = dp_offset; | ||
172 | pinfo->mem_addr = mem_addr; | ||
173 | pinfo->dma_addr = dma_addr; | ||
174 | |||
175 | pinfo->rx_buf = mem_addr; | ||
176 | pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos | ||
177 | * pinfo->rx_fifosize); | ||
178 | |||
179 | pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; | ||
180 | pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | void cpm_uart_freebuf(struct uart_cpm_port *pinfo) | ||
186 | { | ||
187 | dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * | ||
188 | pinfo->rx_fifosize) + | ||
189 | L1_CACHE_ALIGN(pinfo->tx_nrfifos * | ||
190 | pinfo->tx_fifosize), pinfo->mem_addr, | ||
191 | pinfo->dma_addr); | ||
192 | |||
193 | cpm_dpfree(pinfo->dp_addr); | ||
194 | } | ||
195 | |||
196 | /* Setup any dynamic params in the uart desc */ | ||
197 | int cpm_uart_init_portdesc(void) | ||
198 | { | ||
199 | pr_debug("CPM uart[-]:init portdesc\n"); | ||
200 | |||
201 | cpm_uart_nr = 0; | ||
202 | #ifdef CONFIG_SERIAL_CPM_SMC1 | ||
203 | cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0]; | ||
204 | /* | ||
205 | * Is SMC1 being relocated? | ||
206 | */ | ||
207 | # ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH | ||
208 | cpm_uart_ports[UART_SMC1].smcup = | ||
209 | (smc_uart_t *) & cpmp->cp_dparam[0x3C0]; | ||
210 | # else | ||
211 | cpm_uart_ports[UART_SMC1].smcup = | ||
212 | (smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1]; | ||
213 | # endif | ||
214 | cpm_uart_ports[UART_SMC1].port.mapbase = | ||
215 | (unsigned long)&cpmp->cp_smc[0]; | ||
216 | cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); | ||
217 | cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
218 | cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
219 | cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1; | ||
220 | #endif | ||
221 | |||
222 | #ifdef CONFIG_SERIAL_CPM_SMC2 | ||
223 | cpm_uart_ports[UART_SMC2].smcp = &cpmp->cp_smc[1]; | ||
224 | cpm_uart_ports[UART_SMC2].smcup = | ||
225 | (smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC2]; | ||
226 | cpm_uart_ports[UART_SMC2].port.mapbase = | ||
227 | (unsigned long)&cpmp->cp_smc[1]; | ||
228 | cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); | ||
229 | cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
230 | cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
231 | cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2; | ||
232 | #endif | ||
233 | |||
234 | #ifdef CONFIG_SERIAL_CPM_SCC1 | ||
235 | cpm_uart_ports[UART_SCC1].sccp = &cpmp->cp_scc[0]; | ||
236 | cpm_uart_ports[UART_SCC1].sccup = | ||
237 | (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC1]; | ||
238 | cpm_uart_ports[UART_SCC1].port.mapbase = | ||
239 | (unsigned long)&cpmp->cp_scc[0]; | ||
240 | cpm_uart_ports[UART_SCC1].sccp->scc_sccm &= | ||
241 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
242 | cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &= | ||
243 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
244 | cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
245 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1; | ||
246 | #endif | ||
247 | |||
248 | #ifdef CONFIG_SERIAL_CPM_SCC2 | ||
249 | cpm_uart_ports[UART_SCC2].sccp = &cpmp->cp_scc[1]; | ||
250 | cpm_uart_ports[UART_SCC2].sccup = | ||
251 | (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC2]; | ||
252 | cpm_uart_ports[UART_SCC2].port.mapbase = | ||
253 | (unsigned long)&cpmp->cp_scc[1]; | ||
254 | cpm_uart_ports[UART_SCC2].sccp->scc_sccm &= | ||
255 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
256 | cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &= | ||
257 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
258 | cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
259 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2; | ||
260 | #endif | ||
261 | |||
262 | #ifdef CONFIG_SERIAL_CPM_SCC3 | ||
263 | cpm_uart_ports[UART_SCC3].sccp = &cpmp->cp_scc[2]; | ||
264 | cpm_uart_ports[UART_SCC3].sccup = | ||
265 | (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC3]; | ||
266 | cpm_uart_ports[UART_SCC3].port.mapbase = | ||
267 | (unsigned long)&cpmp->cp_scc[2]; | ||
268 | cpm_uart_ports[UART_SCC3].sccp->scc_sccm &= | ||
269 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
270 | cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &= | ||
271 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
272 | cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
273 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3; | ||
274 | #endif | ||
275 | |||
276 | #ifdef CONFIG_SERIAL_CPM_SCC4 | ||
277 | cpm_uart_ports[UART_SCC4].sccp = &cpmp->cp_scc[3]; | ||
278 | cpm_uart_ports[UART_SCC4].sccup = | ||
279 | (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC4]; | ||
280 | cpm_uart_ports[UART_SCC4].port.mapbase = | ||
281 | (unsigned long)&cpmp->cp_scc[3]; | ||
282 | cpm_uart_ports[UART_SCC4].sccp->scc_sccm &= | ||
283 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
284 | cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &= | ||
285 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
286 | cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
287 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4; | ||
288 | #endif | ||
289 | return 0; | ||
290 | } | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h new file mode 100644 index 000000000000..5d867ab581b7 --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart_cpm1.h | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports | ||
5 | * | ||
6 | * definitions for cpm1 | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef CPM_UART_CPM1_H | ||
11 | #define CPM_UART_CPM1_H | ||
12 | |||
13 | #include <asm/commproc.h> | ||
14 | |||
15 | /* defines for IRQs */ | ||
16 | #define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1) | ||
17 | #define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2) | ||
18 | #define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1) | ||
19 | #define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2) | ||
20 | #define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3) | ||
21 | #define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4) | ||
22 | |||
23 | /* the CPM address */ | ||
24 | #define CPM_ADDR IMAP_ADDR | ||
25 | |||
26 | static inline void cpm_set_brg(int brg, int baud) | ||
27 | { | ||
28 | cpm_setbrg(brg, baud); | ||
29 | } | ||
30 | |||
31 | static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) | ||
32 | { | ||
33 | sup->scc_genscc.scc_rfcr = SMC_EB; | ||
34 | sup->scc_genscc.scc_tfcr = SMC_EB; | ||
35 | } | ||
36 | |||
37 | static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) | ||
38 | { | ||
39 | up->smc_rfcr = SMC_EB; | ||
40 | up->smc_tfcr = SMC_EB; | ||
41 | } | ||
42 | |||
43 | #define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0]) | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c new file mode 100644 index 000000000000..b422c3abfba6 --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart_cpm2.c | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports; CPM2 definitions | ||
5 | * | ||
6 | * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2) | ||
7 | * Pantelis Antoniou (panto@intracom.gr) (CPM1) | ||
8 | * | ||
9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | ||
10 | * (C) 2004 Intracom, S.A. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/tty.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/serial.h> | ||
34 | #include <linux/console.h> | ||
35 | #include <linux/sysrq.h> | ||
36 | #include <linux/device.h> | ||
37 | #include <linux/bootmem.h> | ||
38 | #include <linux/dma-mapping.h> | ||
39 | |||
40 | #include <asm/io.h> | ||
41 | #include <asm/irq.h> | ||
42 | |||
43 | #include <linux/serial_core.h> | ||
44 | #include <linux/kernel.h> | ||
45 | |||
46 | #include "cpm_uart.h" | ||
47 | |||
48 | /**************************************************************/ | ||
49 | |||
50 | void cpm_line_cr_cmd(int line, int cmd) | ||
51 | { | ||
52 | volatile cpm_cpm2_t *cp = cpmp; | ||
53 | ulong val; | ||
54 | |||
55 | switch (line) { | ||
56 | case UART_SMC1: | ||
57 | val = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, | ||
58 | cmd) | CPM_CR_FLG; | ||
59 | break; | ||
60 | case UART_SMC2: | ||
61 | val = mk_cr_cmd(CPM_CR_SMC2_PAGE, CPM_CR_SMC2_SBLOCK, 0, | ||
62 | cmd) | CPM_CR_FLG; | ||
63 | break; | ||
64 | case UART_SCC1: | ||
65 | val = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, | ||
66 | cmd) | CPM_CR_FLG; | ||
67 | break; | ||
68 | case UART_SCC2: | ||
69 | val = mk_cr_cmd(CPM_CR_SCC2_PAGE, CPM_CR_SCC2_SBLOCK, 0, | ||
70 | cmd) | CPM_CR_FLG; | ||
71 | break; | ||
72 | case UART_SCC3: | ||
73 | val = mk_cr_cmd(CPM_CR_SCC3_PAGE, CPM_CR_SCC3_SBLOCK, 0, | ||
74 | cmd) | CPM_CR_FLG; | ||
75 | break; | ||
76 | case UART_SCC4: | ||
77 | val = mk_cr_cmd(CPM_CR_SCC4_PAGE, CPM_CR_SCC4_SBLOCK, 0, | ||
78 | cmd) | CPM_CR_FLG; | ||
79 | break; | ||
80 | default: | ||
81 | return; | ||
82 | |||
83 | } | ||
84 | cp->cp_cpcr = val; | ||
85 | while (cp->cp_cpcr & CPM_CR_FLG) ; | ||
86 | } | ||
87 | |||
88 | void smc1_lineif(struct uart_cpm_port *pinfo) | ||
89 | { | ||
90 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
91 | |||
92 | /* SMC1 is only on port D */ | ||
93 | io->iop_ppard |= 0x00c00000; | ||
94 | io->iop_pdird |= 0x00400000; | ||
95 | io->iop_pdird &= ~0x00800000; | ||
96 | io->iop_psord &= ~0x00c00000; | ||
97 | |||
98 | /* Wire BRG1 to SMC1 */ | ||
99 | cpm2_immr->im_cpmux.cmx_smr &= 0x0f; | ||
100 | pinfo->brg = 1; | ||
101 | } | ||
102 | |||
103 | void smc2_lineif(struct uart_cpm_port *pinfo) | ||
104 | { | ||
105 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
106 | |||
107 | /* SMC2 is only on port A */ | ||
108 | io->iop_ppara |= 0x00c00000; | ||
109 | io->iop_pdira |= 0x00400000; | ||
110 | io->iop_pdira &= ~0x00800000; | ||
111 | io->iop_psora &= ~0x00c00000; | ||
112 | |||
113 | /* Wire BRG2 to SMC2 */ | ||
114 | cpm2_immr->im_cpmux.cmx_smr &= 0xf0; | ||
115 | pinfo->brg = 2; | ||
116 | } | ||
117 | |||
118 | void scc1_lineif(struct uart_cpm_port *pinfo) | ||
119 | { | ||
120 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
121 | |||
122 | /* Use Port D for SCC1 instead of other functions. */ | ||
123 | io->iop_ppard |= 0x00000003; | ||
124 | io->iop_psord &= ~0x00000001; /* Rx */ | ||
125 | io->iop_psord |= 0x00000002; /* Tx */ | ||
126 | io->iop_pdird &= ~0x00000001; /* Rx */ | ||
127 | io->iop_pdird |= 0x00000002; /* Tx */ | ||
128 | |||
129 | /* Wire BRG1 to SCC1 */ | ||
130 | cpm2_immr->im_cpmux.cmx_scr &= 0x00ffffff; | ||
131 | cpm2_immr->im_cpmux.cmx_scr |= 0x00000000; | ||
132 | pinfo->brg = 1; | ||
133 | } | ||
134 | |||
135 | void scc2_lineif(struct uart_cpm_port *pinfo) | ||
136 | { | ||
137 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
138 | io->iop_pparb |= 0x008b0000; | ||
139 | io->iop_pdirb |= 0x00880000; | ||
140 | io->iop_psorb |= 0x00880000; | ||
141 | io->iop_pdirb &= ~0x00030000; | ||
142 | io->iop_psorb &= ~0x00030000; | ||
143 | cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff; | ||
144 | cpm2_immr->im_cpmux.cmx_scr |= 0x00090000; | ||
145 | pinfo->brg = 2; | ||
146 | } | ||
147 | |||
148 | void scc3_lineif(struct uart_cpm_port *pinfo) | ||
149 | { | ||
150 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
151 | io->iop_pparb |= 0x008b0000; | ||
152 | io->iop_pdirb |= 0x00880000; | ||
153 | io->iop_psorb |= 0x00880000; | ||
154 | io->iop_pdirb &= ~0x00030000; | ||
155 | io->iop_psorb &= ~0x00030000; | ||
156 | cpm2_immr->im_cpmux.cmx_scr &= 0xffff00ff; | ||
157 | cpm2_immr->im_cpmux.cmx_scr |= 0x00001200; | ||
158 | pinfo->brg = 3; | ||
159 | } | ||
160 | |||
161 | void scc4_lineif(struct uart_cpm_port *pinfo) | ||
162 | { | ||
163 | volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; | ||
164 | |||
165 | io->iop_ppard |= 0x00000600; | ||
166 | io->iop_psord &= ~0x00000600; /* Tx/Rx */ | ||
167 | io->iop_pdird &= ~0x00000200; /* Rx */ | ||
168 | io->iop_pdird |= 0x00000400; /* Tx */ | ||
169 | |||
170 | cpm2_immr->im_cpmux.cmx_scr &= 0xffffff00; | ||
171 | cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b; | ||
172 | pinfo->brg = 4; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Allocate DP-Ram and memory buffers. We need to allocate a transmit and | ||
177 | * receive buffer descriptors from dual port ram, and a character | ||
178 | * buffer area from host mem. If we are allocating for the console we need | ||
179 | * to do it from bootmem | ||
180 | */ | ||
181 | int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) | ||
182 | { | ||
183 | int dpmemsz, memsz; | ||
184 | u8 *dp_mem; | ||
185 | uint dp_offset; | ||
186 | u8 *mem_addr; | ||
187 | dma_addr_t dma_addr = 0; | ||
188 | |||
189 | pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); | ||
190 | |||
191 | dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); | ||
192 | dp_offset = cpm_dpalloc(dpmemsz, 8); | ||
193 | if (IS_DPERR(dp_offset)) { | ||
194 | printk(KERN_ERR | ||
195 | "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | |||
199 | dp_mem = cpm_dpram_addr(dp_offset); | ||
200 | |||
201 | memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + | ||
202 | L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); | ||
203 | if (is_con) | ||
204 | mem_addr = alloc_bootmem(memsz); | ||
205 | else | ||
206 | mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, | ||
207 | GFP_KERNEL); | ||
208 | |||
209 | if (mem_addr == NULL) { | ||
210 | cpm_dpfree(dp_offset); | ||
211 | printk(KERN_ERR | ||
212 | "cpm_uart_cpm.c: could not allocate coherent memory\n"); | ||
213 | return -ENOMEM; | ||
214 | } | ||
215 | |||
216 | pinfo->dp_addr = dp_offset; | ||
217 | pinfo->mem_addr = mem_addr; | ||
218 | pinfo->dma_addr = dma_addr; | ||
219 | |||
220 | pinfo->rx_buf = mem_addr; | ||
221 | pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos | ||
222 | * pinfo->rx_fifosize); | ||
223 | |||
224 | pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; | ||
225 | pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | void cpm_uart_freebuf(struct uart_cpm_port *pinfo) | ||
231 | { | ||
232 | dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * | ||
233 | pinfo->rx_fifosize) + | ||
234 | L1_CACHE_ALIGN(pinfo->tx_nrfifos * | ||
235 | pinfo->tx_fifosize), pinfo->mem_addr, | ||
236 | pinfo->dma_addr); | ||
237 | |||
238 | cpm_dpfree(pinfo->dp_addr); | ||
239 | } | ||
240 | |||
241 | /* Setup any dynamic params in the uart desc */ | ||
242 | int cpm_uart_init_portdesc(void) | ||
243 | { | ||
244 | pr_debug("CPM uart[-]:init portdesc\n"); | ||
245 | |||
246 | cpm_uart_nr = 0; | ||
247 | #ifdef CONFIG_SERIAL_CPM_SMC1 | ||
248 | cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0]; | ||
249 | cpm_uart_ports[UART_SMC1].smcup = | ||
250 | (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1]; | ||
251 | cpm_uart_ports[UART_SMC1].port.mapbase = | ||
252 | (unsigned long)&cpm2_immr->im_smc[0]; | ||
253 | cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); | ||
254 | cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
255 | cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
256 | cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1; | ||
257 | #endif | ||
258 | |||
259 | #ifdef CONFIG_SERIAL_CPM_SMC2 | ||
260 | cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1]; | ||
261 | cpm_uart_ports[UART_SMC2].smcup = | ||
262 | (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2]; | ||
263 | cpm_uart_ports[UART_SMC2].port.mapbase = | ||
264 | (unsigned long)&cpm2_immr->im_smc[1]; | ||
265 | cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); | ||
266 | cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | ||
267 | cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
268 | cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2; | ||
269 | #endif | ||
270 | |||
271 | #ifdef CONFIG_SERIAL_CPM_SCC1 | ||
272 | cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0]; | ||
273 | cpm_uart_ports[UART_SCC1].sccup = | ||
274 | (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1]; | ||
275 | cpm_uart_ports[UART_SCC1].port.mapbase = | ||
276 | (unsigned long)&cpm2_immr->im_scc[0]; | ||
277 | cpm_uart_ports[UART_SCC1].sccp->scc_sccm &= | ||
278 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
279 | cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &= | ||
280 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
281 | cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
282 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1; | ||
283 | #endif | ||
284 | |||
285 | #ifdef CONFIG_SERIAL_CPM_SCC2 | ||
286 | cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1]; | ||
287 | cpm_uart_ports[UART_SCC2].sccup = | ||
288 | (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2]; | ||
289 | cpm_uart_ports[UART_SCC2].port.mapbase = | ||
290 | (unsigned long)&cpm2_immr->im_scc[1]; | ||
291 | cpm_uart_ports[UART_SCC2].sccp->scc_sccm &= | ||
292 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
293 | cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &= | ||
294 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
295 | cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
296 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2; | ||
297 | #endif | ||
298 | |||
299 | #ifdef CONFIG_SERIAL_CPM_SCC3 | ||
300 | cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2]; | ||
301 | cpm_uart_ports[UART_SCC3].sccup = | ||
302 | (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3]; | ||
303 | cpm_uart_ports[UART_SCC3].port.mapbase = | ||
304 | (unsigned long)&cpm2_immr->im_scc[2]; | ||
305 | cpm_uart_ports[UART_SCC3].sccp->scc_sccm &= | ||
306 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
307 | cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &= | ||
308 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
309 | cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
310 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3; | ||
311 | #endif | ||
312 | |||
313 | #ifdef CONFIG_SERIAL_CPM_SCC4 | ||
314 | cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3]; | ||
315 | cpm_uart_ports[UART_SCC4].sccup = | ||
316 | (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4]; | ||
317 | cpm_uart_ports[UART_SCC4].port.mapbase = | ||
318 | (unsigned long)&cpm2_immr->im_scc[3]; | ||
319 | cpm_uart_ports[UART_SCC4].sccp->scc_sccm &= | ||
320 | ~(UART_SCCM_TX | UART_SCCM_RX); | ||
321 | cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &= | ||
322 | ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
323 | cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq); | ||
324 | cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4; | ||
325 | #endif | ||
326 | |||
327 | return 0; | ||
328 | } | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h new file mode 100644 index 000000000000..4793fecf8ece --- /dev/null +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * linux/drivers/serial/cpm_uart_cpm2.h | ||
3 | * | ||
4 | * Driver for CPM (SCC/SMC) serial ports | ||
5 | * | ||
6 | * definitions for cpm2 | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef CPM_UART_CPM2_H | ||
11 | #define CPM_UART_CPM2_H | ||
12 | |||
13 | #include <asm/cpm2.h> | ||
14 | |||
15 | /* defines for IRQs */ | ||
16 | #define SMC1_IRQ SIU_INT_SMC1 | ||
17 | #define SMC2_IRQ SIU_INT_SMC2 | ||
18 | #define SCC1_IRQ SIU_INT_SCC1 | ||
19 | #define SCC2_IRQ SIU_INT_SCC2 | ||
20 | #define SCC3_IRQ SIU_INT_SCC3 | ||
21 | #define SCC4_IRQ SIU_INT_SCC4 | ||
22 | |||
23 | /* the CPM address */ | ||
24 | #define CPM_ADDR CPM_MAP_ADDR | ||
25 | |||
26 | static inline void cpm_set_brg(int brg, int baud) | ||
27 | { | ||
28 | cpm_setbrg(brg, baud); | ||
29 | } | ||
30 | |||
31 | static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) | ||
32 | { | ||
33 | sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; | ||
34 | sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; | ||
35 | } | ||
36 | |||
37 | static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) | ||
38 | { | ||
39 | up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; | ||
40 | up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; | ||
41 | } | ||
42 | |||
43 | #define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0]) | ||
44 | |||
45 | #endif | ||