move mini_fo from target/linux/package/ to package/.
[openwrt.git] / target / linux / sibyte-2.6 / patches / 000-DUART.patch
1 --- linux-2.6.16.7/drivers/char/Kconfig 2006-04-21 14:38:30.000000000 -0700
2 +++ linux-2.6.16.7/drivers/char/Kconfig 2006-04-21 14:39:29.000000000 -0700
3 @@ -340,6 +340,14 @@
4 To compile this driver as a module, choose M here: the
5 module will be called istallion.
6
7 +config SIBYTE_SB1250_DUART
8 + bool "Support for BCM1xxx onchip DUART"
9 + depends on MIPS && SIBYTE_SB1xxx_SOC=y
10 +
11 +config SIBYTE_SB1250_DUART_CONSOLE
12 + bool "Console on BCM1xxx DUART"
13 + depends on SIBYTE_SB1250_DUART
14 +
15 config AU1000_UART
16 bool "Enable Au1000 UART Support"
17 depends on SERIAL_NONSTANDARD && MIPS
18 diff -Nurb linux-2.6.16.7/drivers/char/Makefile linux-2.6.16.7/drivers/char/Makefile
19 --- linux-2.6.16.7/drivers/char/Makefile 2006-04-17 14:53:25.000000000 -0700
20 +++ linux-2.6.16.7/drivers/char/Makefile 2006-04-28 12:14:24.000000000 -0700
21 @@ -31,6 +31,7 @@
22 obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
23 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
24 obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
25 +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
26 obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o
27 obj-$(CONFIG_RISCOM8) += riscom8.o
28 obj-$(CONFIG_ISI) += isicom.o
29 diff -Nurb linux-2.6.16.7/drivers/char/sb1250_duart.c linux-2.6.16.7/drivers/char/sb1250_duart.c
30 --- linux-2.6.16.7/drivers/char/sb1250_duart.c 1969-12-31 16:00:00.000000000 -0800
31 +++ linux-2.6.16.7/drivers/char/sb1250_duart.c 2006-04-28 12:13:49.000000000 -0700
32 @@ -0,0 +1,911 @@
33 +/*
34 + * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
35 + *
36 + * This program is free software; you can redistribute it and/or
37 + * modify it under the terms of the GNU General Public License
38 + * as published by the Free Software Foundation; either version 2
39 + * of the License, or (at your option) any later version.
40 + *
41 + * This program is distributed in the hope that it will be useful,
42 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 + * GNU General Public License for more details.
45 + *
46 + * You should have received a copy of the GNU General Public License
47 + * along with this program; if not, write to the Free Software
48 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
49 + */
50 +
51 +/*
52 + * Driver support for the on-chip sb1250 dual-channel serial port,
53 + * running in asynchronous mode. Also, support for doing a serial console
54 + * on one of those ports
55 + */
56 +#include <linux/config.h>
57 +#include <linux/types.h>
58 +#include <linux/kernel.h>
59 +#include <linux/serial.h>
60 +#include <linux/interrupt.h>
61 +#include <linux/module.h>
62 +#include <linux/console.h>
63 +#include <linux/kdev_t.h>
64 +#include <linux/major.h>
65 +#include <linux/termios.h>
66 +#include <linux/spinlock.h>
67 +#include <linux/irq.h>
68 +#include <linux/errno.h>
69 +#include <linux/tty.h>
70 +#include <linux/sched.h>
71 +#include <linux/tty_flip.h>
72 +#include <linux/timer.h>
73 +#include <linux/init.h>
74 +#include <linux/mm.h>
75 +#include <asm/delay.h>
76 +#include <asm/io.h>
77 +#include <asm/uaccess.h>
78 +#include <asm/sibyte/swarm.h>
79 +#include <asm/sibyte/sb1250.h>
80 +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
81 +#include <asm/sibyte/bcm1480_regs.h>
82 +#include <asm/sibyte/bcm1480_int.h>
83 +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
84 +#include <asm/sibyte/sb1250_regs.h>
85 +#include <asm/sibyte/sb1250_int.h>
86 +#else
87 +#error invalid SiByte UART configuation
88 +#endif
89 +#include <asm/sibyte/sb1250_uart.h>
90 +#include <asm/war.h>
91 +
92 +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
93 +#define UNIT_CHANREG(n,reg) A_BCM1480_DUART_CHANREG((n),(reg))
94 +#define UNIT_IMRREG(n) A_BCM1480_DUART_IMRREG(n)
95 +#define UNIT_INT(n) (K_BCM1480_INT_UART_0 + (n))
96 +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
97 +#define UNIT_CHANREG(n,reg) A_DUART_CHANREG((n),(reg))
98 +#define UNIT_IMRREG(n) A_DUART_IMRREG(n)
99 +#define UNIT_INT(n) (K_INT_UART_0 + (n))
100 +#else
101 +#error invalid SiByte UART configuation
102 +#endif
103 +
104 +/* Toggle spewing of debugging output */
105 +#undef DEBUG
106 +
107 +#define DEFAULT_CFLAGS (CS8 | B115200)
108 +
109 +#define TX_INTEN 1
110 +#define DUART_INITIALIZED 2
111 +
112 +#define DUART_MAX_LINE 4
113 +char sb1250_duart_present[DUART_MAX_LINE];
114 +EXPORT_SYMBOL(sb1250_duart_present);
115 +
116 +/*
117 + * Still not sure what the termios structures set up here are for,
118 + * but we have to supply pointers to them to register the tty driver
119 + */
120 +static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
121 +
122 +/*
123 + * This lock protects both the open flags for all the uart states as
124 + * well as the reference count for the module
125 + */
126 +static DEFINE_SPINLOCK(open_lock);
127 +
128 +typedef struct {
129 + unsigned char outp_buf[SERIAL_XMIT_SIZE];
130 + unsigned int outp_head;
131 + unsigned int outp_tail;
132 + unsigned int outp_count;
133 + spinlock_t outp_lock;
134 + unsigned int open;
135 + unsigned int line;
136 + unsigned int last_cflags;
137 + unsigned long flags;
138 + struct tty_struct *tty;
139 + /* CSR addresses */
140 + volatile u32 *status;
141 + volatile u32 *imr;
142 + volatile u32 *tx_hold;
143 + volatile u32 *rx_hold;
144 + volatile u32 *mode_1;
145 + volatile u32 *mode_2;
146 + volatile u32 *clk_sel;
147 + volatile u32 *cmd;
148 +} uart_state_t;
149 +
150 +static uart_state_t uart_states[DUART_MAX_LINE];
151 +
152 +/*
153 + * Inline functions local to this module
154 + */
155 +
156 +/*
157 + * In bug 1956, we get glitches that can mess up uart registers. This
158 + * "write-mode-1 after any register access" is the accepted
159 + * workaround.
160 + */
161 +#if SIBYTE_1956_WAR
162 +static unsigned int last_mode1[DUART_MAX_LINE];
163 +#endif
164 +
165 +static inline u32 READ_SERCSR(volatile u32 *addr, int line)
166 +{
167 + u32 val = csr_in32(addr);
168 +#if SIBYTE_1956_WAR
169 + csr_out32(last_mode1[line], uart_states[line].mode_1);
170 +#endif
171 + return val;
172 +}
173 +
174 +static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line)
175 +{
176 + csr_out32(val, addr);
177 +#if SIBYTE_1956_WAR
178 + csr_out32(last_mode1[line], uart_states[line].mode_1);
179 +#endif
180 +}
181 +
182 +static void init_duart_port(uart_state_t *port, int line)
183 +{
184 + if (!(port->flags & DUART_INITIALIZED)) {
185 + port->line = line;
186 + port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS));
187 + port->imr = IOADDR(UNIT_IMRREG(line));
188 + port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD));
189 + port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD));
190 + port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1));
191 + port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
192 + port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
193 + port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
194 + port->flags |= DUART_INITIALIZED;
195 + }
196 +}
197 +
198 +/*
199 + * Mask out the passed interrupt lines at the duart level. This should be
200 + * called while holding the associated outp_lock.
201 + */
202 +static inline void duart_mask_ints(unsigned int line, unsigned int mask)
203 +{
204 + uart_state_t *port = uart_states + line;
205 + u64 tmp = READ_SERCSR(port->imr, line);
206 + WRITE_SERCSR(tmp & ~mask, port->imr, line);
207 +}
208 +
209 +
210 +/* Unmask the passed interrupt lines at the duart level */
211 +static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
212 +{
213 + uart_state_t *port = uart_states + line;
214 + u64 tmp = READ_SERCSR(port->imr, line);
215 + WRITE_SERCSR(tmp | mask, port->imr, line);
216 +}
217 +
218 +static inline void transmit_char_pio(uart_state_t *us)
219 +{
220 + struct tty_struct *tty = us->tty;
221 + int blocked = 0;
222 +
223 + if (spin_trylock(&us->outp_lock)) {
224 + for (;;) {
225 + if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
226 + break;
227 + if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
228 + break;
229 + } else {
230 + WRITE_SERCSR(us->outp_buf[us->outp_head],
231 + us->tx_hold, us->line);
232 + us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
233 + if (--us->outp_count <= 0)
234 + break;
235 + }
236 + udelay(10);
237 + }
238 + spin_unlock(&us->outp_lock);
239 + } else {
240 + blocked = 1;
241 + }
242 +
243 + if (!us->outp_count || tty->stopped ||
244 + tty->hw_stopped || blocked) {
245 + us->flags &= ~TX_INTEN;
246 + duart_mask_ints(us->line, M_DUART_IMR_TX);
247 + }
248 +
249 + if (us->open &&
250 + (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
251 + /*
252 + * We told the discipline at one point that we had no
253 + * space, so it went to sleep. Wake it up when we hit
254 + * half empty
255 + */
256 + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
257 + tty->ldisc.write_wakeup)
258 + tty->ldisc.write_wakeup(tty);
259 + wake_up_interruptible(&tty->write_wait);
260 + }
261 +}
262 +
263 +/*
264 + * Generic interrupt handler for both channels. dev_id is a pointer
265 + * to the proper uart_states structure, so from that we can derive
266 + * which port interrupted
267 + */
268 +
269 +static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs)
270 +{
271 + uart_state_t *us = (uart_state_t *)dev_id;
272 + struct tty_struct *tty = us->tty;
273 + unsigned int status = READ_SERCSR(us->status, us->line);
274 +
275 + pr_debug("DUART INT\n");
276 +
277 + if (status & M_DUART_RX_RDY) {
278 + int counter = 2048;
279 + unsigned int ch;
280 +
281 + if (status & M_DUART_OVRUN_ERR)
282 + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
283 + if (status & M_DUART_PARITY_ERR) {
284 + printk("Parity error!\n");
285 + } else if (status & M_DUART_FRM_ERR) {
286 + printk("Frame error!\n");
287 + }
288 +
289 + while (counter > 0) {
290 + if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
291 + break;
292 + ch = READ_SERCSR(us->rx_hold, us->line);
293 + tty_insert_flip_char(tty, ch, 0);
294 + udelay(1);
295 + counter--;
296 + }
297 + tty_flip_buffer_push(tty);
298 + }
299 +
300 + if (status & M_DUART_TX_RDY) {
301 + transmit_char_pio(us);
302 + }
303 +
304 + return IRQ_HANDLED;
305 +}
306 +
307 +/*
308 + * Actual driver functions
309 + */
310 +
311 +/* Return the number of characters we can accomodate in a write at this instant */
312 +static int duart_write_room(struct tty_struct *tty)
313 +{
314 + uart_state_t *us = (uart_state_t *) tty->driver_data;
315 + int retval;
316 +
317 + retval = SERIAL_XMIT_SIZE - us->outp_count;
318 +
319 + pr_debug("duart_write_room called, returning %i\n", retval);
320 +
321 + return retval;
322 +}
323 +
324 +/* memcpy the data from src to destination, but take extra care if the
325 + data is coming from user space */
326 +static inline int copy_buf(char *dest, const char *src, int size, int from_user)
327 +{
328 + if (from_user) {
329 + (void) copy_from_user(dest, src, size);
330 + } else {
331 + memcpy(dest, src, size);
332 + }
333 + return size;
334 +}
335 +
336 +/*
337 + * Buffer up to count characters from buf to be written. If we don't have
338 + * other characters buffered, enable the tx interrupt to start sending
339 + */
340 +static int duart_write(struct tty_struct *tty, const unsigned char *buf,
341 + int count)
342 +{
343 + uart_state_t *us;
344 + int c, t, total = 0;
345 + unsigned long flags;
346 +
347 + if (!tty) return 0;
348 +
349 + us = tty->driver_data;
350 + if (!us) return 0;
351 +
352 + pr_debug("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
353 +
354 + spin_lock_irqsave(&us->outp_lock, flags);
355 +
356 + for (;;) {
357 + c = count;
358 +
359 + t = SERIAL_XMIT_SIZE - us->outp_tail;
360 + if (t < c) c = t;
361 +
362 + t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
363 + if (t < c) c = t;
364 +
365 + if (c <= 0) break;
366 +
367 + memcpy(us->outp_buf + us->outp_tail, buf, c);
368 +
369 + us->outp_count += c;
370 + us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
371 + buf += c;
372 + count -= c;
373 + total += c;
374 + }
375 +
376 + spin_unlock_irqrestore(&us->outp_lock, flags);
377 +
378 + if (us->outp_count && !tty->stopped &&
379 + !tty->hw_stopped && !(us->flags & TX_INTEN)) {
380 + us->flags |= TX_INTEN;
381 + duart_unmask_ints(us->line, M_DUART_IMR_TX);
382 + }
383 +
384 + return total;
385 +}
386 +
387 +
388 +/* Buffer one character to be written. If there's not room for it, just drop
389 + it on the floor. This is used for echo, among other things */
390 +static void duart_put_char(struct tty_struct *tty, u_char ch)
391 +{
392 + uart_state_t *us = (uart_state_t *) tty->driver_data;
393 + unsigned long flags;
394 +
395 + pr_debug("duart_put_char called. Char is %x (%c)\n", (int)ch, ch);
396 +
397 + spin_lock_irqsave(&us->outp_lock, flags);
398 +
399 + if (us->outp_count == SERIAL_XMIT_SIZE) {
400 + spin_unlock_irqrestore(&us->outp_lock, flags);
401 + return;
402 + }
403 +
404 + us->outp_buf[us->outp_tail] = ch;
405 + us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
406 + us->outp_count++;
407 +
408 + spin_unlock_irqrestore(&us->outp_lock, flags);
409 +}
410 +
411 +static void duart_flush_chars(struct tty_struct * tty)
412 +{
413 + uart_state_t *port;
414 +
415 + if (!tty) return;
416 +
417 + port = tty->driver_data;
418 +
419 + if (!port) return;
420 +
421 + if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
422 + return;
423 + }
424 +
425 + port->flags |= TX_INTEN;
426 + duart_unmask_ints(port->line, M_DUART_IMR_TX);
427 +}
428 +
429 +/* Return the number of characters in the output buffer that have yet to be
430 + written */
431 +static int duart_chars_in_buffer(struct tty_struct *tty)
432 +{
433 + uart_state_t *us = (uart_state_t *) tty->driver_data;
434 + int retval;
435 +
436 + retval = us->outp_count;
437 +
438 + pr_debug("duart_chars_in_buffer returning %i\n", retval);
439 +
440 + return retval;
441 +}
442 +
443 +/* Kill everything we haven't yet shoved into the FIFO. Turn off the
444 + transmit interrupt since we've nothing more to transmit */
445 +static void duart_flush_buffer(struct tty_struct *tty)
446 +{
447 + uart_state_t *us = (uart_state_t *) tty->driver_data;
448 + unsigned long flags;
449 +
450 + pr_debug("duart_flush_buffer called\n");
451 + spin_lock_irqsave(&us->outp_lock, flags);
452 + us->outp_head = us->outp_tail = us->outp_count = 0;
453 + spin_unlock_irqrestore(&us->outp_lock, flags);
454 +
455 + wake_up_interruptible(&us->tty->write_wait);
456 + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
457 + tty->ldisc.write_wakeup)
458 + tty->ldisc.write_wakeup(tty);
459 +}
460 +
461 +
462 +/* See sb1250 user manual for details on these registers */
463 +static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
464 +{
465 + unsigned int mode_reg1 = 0, mode_reg2 = 0;
466 + unsigned int clk_divisor;
467 + uart_state_t *port = uart_states + line;
468 +
469 + switch (cflag & CSIZE) {
470 + case CS7:
471 + mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
472 +
473 + default:
474 + /* We don't handle CS5 or CS6...is there a way we're supposed to flag this?
475 + right now we just force them to CS8 */
476 + mode_reg1 |= 0x0;
477 + break;
478 + }
479 + if (cflag & CSTOPB) {
480 + mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
481 + }
482 + if (!(cflag & PARENB)) {
483 + mode_reg1 |= V_DUART_PARITY_MODE_NONE;
484 + }
485 + if (cflag & PARODD) {
486 + mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
487 + }
488 +
489 + /* Formula for this is (5000000/baud)-1, but we saturate
490 + at 12 bits, which means we can't actually do anything less
491 + that 1200 baud */
492 + switch (cflag & CBAUD) {
493 + case B200:
494 + case B300:
495 + case B1200: clk_divisor = 4095; break;
496 + case B1800: clk_divisor = 2776; break;
497 + case B2400: clk_divisor = 2082; break;
498 + case B4800: clk_divisor = 1040; break;
499 + default:
500 + case B9600: clk_divisor = 519; break;
501 + case B19200: clk_divisor = 259; break;
502 + case B38400: clk_divisor = 129; break;
503 + case B57600: clk_divisor = 85; break;
504 + case B115200: clk_divisor = 42; break;
505 + }
506 + WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
507 + WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
508 + WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
509 + port->last_cflags = cflag;
510 +}
511 +
512 +
513 +/* Handle notification of a termios change. */
514 +static void duart_set_termios(struct tty_struct *tty, struct termios *old)
515 +{
516 + uart_state_t *us = (uart_state_t *) tty->driver_data;
517 +
518 + pr_debug("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
519 + if (old && tty->termios->c_cflag == old->c_cflag)
520 + return;
521 + duart_set_cflag(us->line, tty->termios->c_cflag);
522 +}
523 +
524 +static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
525 +
526 + struct serial_struct tmp;
527 +
528 + memset(&tmp, 0, sizeof(tmp));
529 +
530 + tmp.type=PORT_SB1250;
531 + tmp.line=us->line;
532 + tmp.port=UNIT_CHANREG(tmp.line,0);
533 + tmp.irq=UNIT_INT(tmp.line);
534 + tmp.xmit_fifo_size=16; /* fixed by hw */
535 + tmp.baud_base=5000000;
536 + tmp.io_type=SERIAL_IO_MEM;
537 +
538 + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
539 + return -EFAULT;
540 +
541 + return 0;
542 +}
543 +
544 +static int duart_ioctl(struct tty_struct *tty, struct file * file,
545 + unsigned int cmd, unsigned long arg)
546 +{
547 + uart_state_t *us = (uart_state_t *) tty->driver_data;
548 +
549 +/* if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
550 + return -ENODEV;*/
551 + switch (cmd) {
552 + case TIOCMGET:
553 + printk("Ignoring TIOCMGET\n");
554 + break;
555 + case TIOCMBIS:
556 + printk("Ignoring TIOCMBIS\n");
557 + break;
558 + case TIOCMBIC:
559 + printk("Ignoring TIOCMBIC\n");
560 + break;
561 + case TIOCMSET:
562 + printk("Ignoring TIOCMSET\n");
563 + break;
564 + case TIOCGSERIAL:
565 + return get_serial_info(us,(struct serial_struct *) arg);
566 + case TIOCSSERIAL:
567 + printk("Ignoring TIOCSSERIAL\n");
568 + break;
569 + case TIOCSERCONFIG:
570 + printk("Ignoring TIOCSERCONFIG\n");
571 + break;
572 + case TIOCSERGETLSR: /* Get line status register */
573 + printk("Ignoring TIOCSERGETLSR\n");
574 + break;
575 + case TIOCSERGSTRUCT:
576 + printk("Ignoring TIOCSERGSTRUCT\n");
577 + break;
578 + case TIOCMIWAIT:
579 + printk("Ignoring TIOCMIWAIT\n");
580 + break;
581 + case TIOCGICOUNT:
582 + printk("Ignoring TIOCGICOUNT\n");
583 + break;
584 + case TIOCSERGWILD:
585 + printk("Ignoring TIOCSERGWILD\n");
586 + break;
587 + case TIOCSERSWILD:
588 + printk("Ignoring TIOCSERSWILD\n");
589 + break;
590 + default:
591 + break;
592 + }
593 +// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
594 + return -ENOIOCTLCMD;
595 +}
596 +
597 +/* XXXKW locking? */
598 +static void duart_start(struct tty_struct *tty)
599 +{
600 + uart_state_t *us = (uart_state_t *) tty->driver_data;
601 +
602 + pr_debug("duart_start called\n");
603 +
604 + if (us->outp_count && !(us->flags & TX_INTEN)) {
605 + us->flags |= TX_INTEN;
606 + duart_unmask_ints(us->line, M_DUART_IMR_TX);
607 + }
608 +}
609 +
610 +/* XXXKW locking? */
611 +static void duart_stop(struct tty_struct *tty)
612 +{
613 + uart_state_t *us = (uart_state_t *) tty->driver_data;
614 +
615 + pr_debug("duart_stop called\n");
616 +
617 + if (us->outp_count && (us->flags & TX_INTEN)) {
618 + us->flags &= ~TX_INTEN;
619 + duart_mask_ints(us->line, M_DUART_IMR_TX);
620 + }
621 +}
622 +
623 +/* Not sure on the semantics of this; are we supposed to wait until the stuff
624 + already in the hardware FIFO drains, or are we supposed to wait until
625 + we've drained the output buffer, too? I'm assuming the former, 'cause thats
626 + what the other drivers seem to assume
627 +*/
628 +
629 +static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
630 +{
631 + uart_state_t *us = (uart_state_t *) tty->driver_data;
632 + unsigned long orig_jiffies;
633 +
634 + orig_jiffies = jiffies;
635 + pr_debug("duart_wait_until_sent(%d)+\n", timeout);
636 + while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
637 + set_current_state(TASK_INTERRUPTIBLE);
638 + schedule_timeout(1);
639 + if (signal_pending(current))
640 + break;
641 + if (timeout && time_after(jiffies, orig_jiffies + timeout))
642 + break;
643 + }
644 + pr_debug("duart_wait_until_sent()-\n");
645 +}
646 +
647 +/*
648 + * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
649 + */
650 +static void duart_hangup(struct tty_struct *tty)
651 +{
652 + uart_state_t *us = (uart_state_t *) tty->driver_data;
653 +
654 + duart_flush_buffer(tty);
655 + us->open = 0;
656 + us->tty = 0;
657 +}
658 +
659 +/*
660 + * Open a tty line. Note that this can be called multiple times, so ->open can
661 + * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was
662 + * zero
663 + */
664 +static int duart_open(struct tty_struct *tty, struct file *filp)
665 +{
666 + uart_state_t *us;
667 + unsigned int line = tty->index;
668 + unsigned long flags;
669 +
670 + if ((line >= tty->driver->num) || !sb1250_duart_present[line])
671 + return -ENODEV;
672 +
673 + pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
674 + current->pid, current->comm, tty, tty->read_wait,
675 + tty->write_wait);
676 +
677 + us = uart_states + line;
678 + tty->driver_data = us;
679 +
680 + spin_lock_irqsave(&open_lock, flags);
681 + if (!us->open) {
682 + us->tty = tty;
683 + us->tty->termios->c_cflag = us->last_cflags;
684 + }
685 + us->open++;
686 + us->flags &= ~TX_INTEN;
687 + duart_unmask_ints(line, M_DUART_IMR_RX);
688 + spin_unlock_irqrestore(&open_lock, flags);
689 +
690 + return 0;
691 +}
692 +
693 +
694 +/*
695 + * Close a reference count out. If reference count hits zero, null the
696 + * tty, kill the interrupts. The tty_io driver is responsible for making
697 + * sure we've cleared out our internal buffers before calling close()
698 + */
699 +static void duart_close(struct tty_struct *tty, struct file *filp)
700 +{
701 + uart_state_t *us = (uart_state_t *) tty->driver_data;
702 + unsigned long flags;
703 +
704 + pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm);
705 +
706 + if (!us || !us->open)
707 + return;
708 +
709 + spin_lock_irqsave(&open_lock, flags);
710 + if (tty_hung_up_p(filp)) {
711 + spin_unlock_irqrestore(&open_lock, flags);
712 + return;
713 + }
714 +
715 + if (--us->open < 0) {
716 + us->open = 0;
717 + printk(KERN_ERR "duart: bad open count: %d\n", us->open);
718 + }
719 + if (us->open) {
720 + spin_unlock_irqrestore(&open_lock, flags);
721 + return;
722 + }
723 +
724 + spin_unlock_irqrestore(&open_lock, flags);
725 +
726 + tty->closing = 1;
727 +
728 + /* Stop accepting input */
729 + duart_mask_ints(us->line, M_DUART_IMR_RX);
730 + /* Wait for FIFO to drain */
731 + while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
732 + ;
733 +
734 + if (tty->driver->flush_buffer)
735 + tty->driver->flush_buffer(tty);
736 + if (tty->ldisc.flush_buffer)
737 + tty->ldisc.flush_buffer(tty);
738 + tty->closing = 0;
739 +}
740 +
741 +
742 +static struct tty_operations duart_ops = {
743 + .open = duart_open,
744 + .close = duart_close,
745 + .write = duart_write,
746 + .put_char = duart_put_char,
747 + .flush_chars = duart_flush_chars,
748 + .write_room = duart_write_room,
749 + .chars_in_buffer = duart_chars_in_buffer,
750 + .flush_buffer = duart_flush_buffer,
751 + .ioctl = duart_ioctl,
752 +// .throttle = duart_throttle,
753 +// .unthrottle = duart_unthrottle,
754 + .set_termios = duart_set_termios,
755 + .stop = duart_stop,
756 + .start = duart_start,
757 + .hangup = duart_hangup,
758 + .wait_until_sent = duart_wait_until_sent,
759 +};
760 +
761 +/* Initialize the sb1250_duart_present array based on SOC type. */
762 +static void __init sb1250_duart_init_present_lines(void)
763 +{
764 + int i, max_lines;
765 +
766 + /* Set the number of available units based on the SOC type. */
767 + switch (soc_type) {
768 + case K_SYS_SOC_TYPE_BCM1x55:
769 + case K_SYS_SOC_TYPE_BCM1x80:
770 + max_lines = 4;
771 + break;
772 + default:
773 + /* Assume at least two serial ports at the normal address. */
774 + max_lines = 2;
775 + break;
776 + }
777 + if (max_lines > DUART_MAX_LINE)
778 + max_lines = DUART_MAX_LINE;
779 +
780 + for (i = 0; i < max_lines; i++)
781 + sb1250_duart_present[i] = 1;
782 +}
783 +
784 +/* Set up the driver and register it, register the UART interrupts. This
785 + is called from tty_init, or as a part of the module init */
786 +static int __init sb1250_duart_init(void)
787 +{
788 + int i;
789 +
790 + sb1250_duart_init_present_lines();
791 +
792 + sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE);
793 + if (!sb1250_duart_driver)
794 + return -ENOMEM;
795 +
796 + sb1250_duart_driver->owner = THIS_MODULE;
797 + sb1250_duart_driver->name = "duart";
798 + sb1250_duart_driver->devfs_name = "duart/";
799 + sb1250_duart_driver->major = TTY_MAJOR;
800 + sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
801 + sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL;
802 + sb1250_duart_driver->subtype = SERIAL_TYPE_NORMAL;
803 + sb1250_duart_driver->init_termios = tty_std_termios;
804 + sb1250_duart_driver->flags = TTY_DRIVER_REAL_RAW;
805 + tty_set_operations(sb1250_duart_driver, &duart_ops);
806 +
807 + for (i=0; i<DUART_MAX_LINE; i++) {
808 + uart_state_t *port = uart_states + i;
809 +
810 + if (!sb1250_duart_present[i])
811 + continue;
812 +
813 + init_duart_port(port, i);
814 + spin_lock_init(&port->outp_lock);
815 + duart_mask_ints(i, M_DUART_IMR_ALL);
816 + if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
817 + panic("Couldn't get uart0 interrupt line");
818 + }
819 + __raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
820 + IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
821 + duart_set_cflag(i, DEFAULT_CFLAGS);
822 + }
823 +
824 + /* Interrupts are now active, our ISR can be called. */
825 +
826 + if (tty_register_driver(sb1250_duart_driver)) {
827 + printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
828 + put_tty_driver(sb1250_duart_driver);
829 + return 1;
830 + }
831 + return 0;
832 +}
833 +
834 +/* Unload the driver. Unregister stuff, get ready to go away */
835 +static void __exit sb1250_duart_fini(void)
836 +{
837 + unsigned long flags;
838 + int i;
839 +
840 + local_irq_save(flags);
841 + tty_unregister_driver(sb1250_duart_driver);
842 + put_tty_driver(sb1250_duart_driver);
843 +
844 + for (i=0; i<DUART_MAX_LINE; i++) {
845 + if (!sb1250_duart_present[i])
846 + continue;
847 + free_irq(UNIT_INT(i), &uart_states[i]);
848 + disable_irq(UNIT_INT(i));
849 + }
850 + local_irq_restore(flags);
851 +}
852 +
853 +module_init(sb1250_duart_init);
854 +module_exit(sb1250_duart_fini);
855 +MODULE_DESCRIPTION("SB1250 Duart serial driver");
856 +MODULE_AUTHOR("Broadcom Corp.");
857 +
858 +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
859 +
860 +/*
861 + * Serial console stuff. Very basic, polling driver for doing serial
862 + * console output. The console_sem is held by the caller, so we
863 + * shouldn't be interrupted for more console activity.
864 + * XXXKW What about getting interrupted by uart driver activity?
865 + */
866 +
867 +void serial_outc(unsigned char c, int line)
868 +{
869 + uart_state_t *port = uart_states + line;
870 + while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
871 + WRITE_SERCSR(c, port->tx_hold, line);
872 + while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
873 +}
874 +
875 +static void ser_console_write(struct console *cons, const char *s,
876 + unsigned int count)
877 +{
878 + int line = cons->index;
879 + uart_state_t *port = uart_states + line;
880 + u32 imr;
881 +
882 + imr = READ_SERCSR(port->imr, line);
883 + WRITE_SERCSR(0, port->imr, line);
884 + while (count--) {
885 + if (*s == '\n')
886 + serial_outc('\r', line);
887 + serial_outc(*s++, line);
888 + }
889 + WRITE_SERCSR(imr, port->imr, line);
890 +}
891 +
892 +static struct tty_driver *ser_console_device(struct console *c, int *index)
893 +{
894 + *index = c->index;
895 + return sb1250_duart_driver;
896 +}
897 +
898 +static int ser_console_setup(struct console *cons, char *str)
899 +{
900 + int i;
901 +
902 + sb1250_duart_init_present_lines();
903 +
904 + for (i=0; i<DUART_MAX_LINE; i++) {
905 + uart_state_t *port = uart_states + i;
906 +
907 + if (!sb1250_duart_present[i])
908 + continue;
909 +
910 + init_duart_port(port, i);
911 +#if SIBYTE_1956_WAR
912 + last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
913 +#endif
914 + WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
915 + port->mode_1, i);
916 + WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
917 + port->mode_2, i);
918 + WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
919 + port->clk_sel, i);
920 + WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
921 + port->cmd, i);
922 + }
923 + return 0;
924 +}
925 +
926 +static struct console sb1250_ser_cons = {
927 + .name = "duart",
928 + .write = ser_console_write,
929 + .device = ser_console_device,
930 + .setup = ser_console_setup,
931 + .flags = CON_PRINTBUFFER,
932 + .index = -1,
933 +};
934 +
935 +static int __init sb1250_serial_console_init(void)
936 +{
937 + register_console(&sb1250_ser_cons);
938 + return 0;
939 +}
940 +
941 +console_initcall(sb1250_serial_console_init);
942 +
943 +#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
944 diff -Nurb linux-2.6.16.7/include/linux/serial.h linux-2.6.16.7/include/linux/serial.h
945 --- linux-2.6.16.7/include/linux/serial.h 2006-04-17 14:53:25.000000000 -0700
946 +++ linux-2.6.16.7/include/linux/serial.h 2006-04-28 12:25:19.000000000 -0700
947 @@ -76,7 +76,8 @@
948 #define PORT_16654 11
949 #define PORT_16850 12
950 #define PORT_RSA 13 /* RSA-DV II/S card */
951 -#define PORT_MAX 13
952 +#define PORT_SB1250 14
953 +#define PORT_MAX 14
954
955 #define SERIAL_IO_PORT 0
956 #define SERIAL_IO_HUB6 1
This page took 0.086698 seconds and 5 git commands to generate.