diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2007-11-28 19:21:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-29 12:24:53 -0500 |
commit | 68576cf122bc5195c758ed295e78b5858472378a (patch) | |
tree | 5b6b7cb9608bf757bf3368c808f14bf206eddbe8 /drivers/serial/ip22zilog.c | |
parent | 6d4f5879b6f4da50bde94e1cae73755978ed048f (diff) |
IP22ZILOG: fix lockup and sysrq
- fix lockup when switching from early console to real console
- make sysrq reliable
- fix panic, if sysrq is issued before console is opened
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/ip22zilog.c')
-rw-r--r-- | drivers/serial/ip22zilog.c | 247 |
1 files changed, 106 insertions, 141 deletions
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index f3257f708ef9..9c95bc0398ad 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c | |||
@@ -45,8 +45,6 @@ | |||
45 | 45 | ||
46 | #include "ip22zilog.h" | 46 | #include "ip22zilog.h" |
47 | 47 | ||
48 | void ip22_do_break(void); | ||
49 | |||
50 | /* | 48 | /* |
51 | * On IP22 we need to delay after register accesses but we do not need to | 49 | * On IP22 we need to delay after register accesses but we do not need to |
52 | * flush writes. | 50 | * flush writes. |
@@ -81,12 +79,9 @@ struct uart_ip22zilog_port { | |||
81 | #define IP22ZILOG_FLAG_REGS_HELD 0x00000040 | 79 | #define IP22ZILOG_FLAG_REGS_HELD 0x00000040 |
82 | #define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 | 80 | #define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 |
83 | #define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 | 81 | #define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 |
82 | #define IP22ZILOG_FLAG_RESET_DONE 0x00000200 | ||
84 | 83 | ||
85 | unsigned int cflag; | 84 | unsigned int tty_break; |
86 | |||
87 | /* L1-A keyboard break state. */ | ||
88 | int kbd_id; | ||
89 | int l1_down; | ||
90 | 85 | ||
91 | unsigned char parity_mask; | 86 | unsigned char parity_mask; |
92 | unsigned char prev_status; | 87 | unsigned char prev_status; |
@@ -250,13 +245,26 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, | |||
250 | } | 245 | } |
251 | } | 246 | } |
252 | 247 | ||
253 | static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, | 248 | #define Rx_BRK 0x0100 /* BREAK event software flag. */ |
254 | struct zilog_channel *channel) | 249 | #define Rx_SYS 0x0200 /* SysRq event software flag. */ |
250 | |||
251 | static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up, | ||
252 | struct zilog_channel *channel) | ||
255 | { | 253 | { |
256 | struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */ | 254 | struct tty_struct *tty; |
255 | unsigned char ch, flag; | ||
256 | unsigned int r1; | ||
257 | |||
258 | tty = NULL; | ||
259 | if (up->port.info != NULL && | ||
260 | up->port.info->tty != NULL) | ||
261 | tty = up->port.info->tty; | ||
257 | 262 | ||
258 | while (1) { | 263 | for (;;) { |
259 | unsigned char ch, r1, flag; | 264 | ch = readb(&channel->control); |
265 | ZSDELAY(); | ||
266 | if (!(ch & Rx_CH_AV)) | ||
267 | break; | ||
260 | 268 | ||
261 | r1 = read_zsreg(channel, R1); | 269 | r1 = read_zsreg(channel, R1); |
262 | if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { | 270 | if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { |
@@ -265,43 +273,26 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, | |||
265 | ZS_WSYNC(channel); | 273 | ZS_WSYNC(channel); |
266 | } | 274 | } |
267 | 275 | ||
268 | ch = readb(&channel->control); | ||
269 | ZSDELAY(); | ||
270 | |||
271 | /* This funny hack depends upon BRK_ABRT not interfering | ||
272 | * with the other bits we care about in R1. | ||
273 | */ | ||
274 | if (ch & BRK_ABRT) | ||
275 | r1 |= BRK_ABRT; | ||
276 | |||
277 | ch = readb(&channel->data); | 276 | ch = readb(&channel->data); |
278 | ZSDELAY(); | 277 | ZSDELAY(); |
279 | 278 | ||
280 | ch &= up->parity_mask; | 279 | ch &= up->parity_mask; |
281 | 280 | ||
282 | if (ZS_IS_CONS(up) && (r1 & BRK_ABRT)) { | 281 | /* Handle the null char got when BREAK is removed. */ |
283 | /* Wait for BREAK to deassert to avoid potentially | 282 | if (!ch) |
284 | * confusing the PROM. | 283 | r1 |= up->tty_break; |
285 | */ | ||
286 | while (1) { | ||
287 | ch = readb(&channel->control); | ||
288 | ZSDELAY(); | ||
289 | if (!(ch & BRK_ABRT)) | ||
290 | break; | ||
291 | } | ||
292 | ip22_do_break(); | ||
293 | return; | ||
294 | } | ||
295 | 284 | ||
296 | /* A real serial line, record the character and status. */ | 285 | /* A real serial line, record the character and status. */ |
297 | flag = TTY_NORMAL; | 286 | flag = TTY_NORMAL; |
298 | up->port.icount.rx++; | 287 | up->port.icount.rx++; |
299 | if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) { | 288 | if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) { |
300 | if (r1 & BRK_ABRT) { | 289 | up->tty_break = 0; |
301 | r1 &= ~(PAR_ERR | CRC_ERR); | 290 | |
291 | if (r1 & (Rx_SYS | Rx_BRK)) { | ||
302 | up->port.icount.brk++; | 292 | up->port.icount.brk++; |
303 | if (uart_handle_break(&up->port)) | 293 | if (r1 & Rx_SYS) |
304 | goto next_char; | 294 | continue; |
295 | r1 &= ~(PAR_ERR | CRC_ERR); | ||
305 | } | 296 | } |
306 | else if (r1 & PAR_ERR) | 297 | else if (r1 & PAR_ERR) |
307 | up->port.icount.parity++; | 298 | up->port.icount.parity++; |
@@ -310,30 +301,21 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, | |||
310 | if (r1 & Rx_OVR) | 301 | if (r1 & Rx_OVR) |
311 | up->port.icount.overrun++; | 302 | up->port.icount.overrun++; |
312 | r1 &= up->port.read_status_mask; | 303 | r1 &= up->port.read_status_mask; |
313 | if (r1 & BRK_ABRT) | 304 | if (r1 & Rx_BRK) |
314 | flag = TTY_BREAK; | 305 | flag = TTY_BREAK; |
315 | else if (r1 & PAR_ERR) | 306 | else if (r1 & PAR_ERR) |
316 | flag = TTY_PARITY; | 307 | flag = TTY_PARITY; |
317 | else if (r1 & CRC_ERR) | 308 | else if (r1 & CRC_ERR) |
318 | flag = TTY_FRAME; | 309 | flag = TTY_FRAME; |
319 | } | 310 | } |
320 | if (uart_handle_sysrq_char(&up->port, ch)) | ||
321 | goto next_char; | ||
322 | 311 | ||
323 | if (up->port.ignore_status_mask == 0xff || | 312 | if (uart_handle_sysrq_char(&up->port, ch)) |
324 | (r1 & up->port.ignore_status_mask) == 0) | 313 | continue; |
325 | tty_insert_flip_char(tty, ch, flag); | ||
326 | 314 | ||
327 | if (r1 & Rx_OVR) | 315 | if (tty) |
328 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 316 | uart_insert_char(&up->port, r1, Rx_OVR, ch, flag); |
329 | next_char: | ||
330 | ch = readb(&channel->control); | ||
331 | ZSDELAY(); | ||
332 | if (!(ch & Rx_CH_AV)) | ||
333 | break; | ||
334 | } | 317 | } |
335 | 318 | return tty; | |
336 | tty_flip_buffer_push(tty); | ||
337 | } | 319 | } |
338 | 320 | ||
339 | static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, | 321 | static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, |
@@ -348,6 +330,15 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, | |||
348 | ZSDELAY(); | 330 | ZSDELAY(); |
349 | ZS_WSYNC(channel); | 331 | ZS_WSYNC(channel); |
350 | 332 | ||
333 | if (up->curregs[R15] & BRKIE) { | ||
334 | if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) { | ||
335 | if (uart_handle_break(&up->port)) | ||
336 | up->tty_break = Rx_SYS; | ||
337 | else | ||
338 | up->tty_break = Rx_BRK; | ||
339 | } | ||
340 | } | ||
341 | |||
351 | if (ZS_WANTS_MODEM_STATUS(up)) { | 342 | if (ZS_WANTS_MODEM_STATUS(up)) { |
352 | if (status & SYNC) | 343 | if (status & SYNC) |
353 | up->port.icount.dsr++; | 344 | up->port.icount.dsr++; |
@@ -356,10 +347,10 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, | |||
356 | * But it does not tell us which bit has changed, we have to keep | 347 | * But it does not tell us which bit has changed, we have to keep |
357 | * track of this ourselves. | 348 | * track of this ourselves. |
358 | */ | 349 | */ |
359 | if ((status & DCD) ^ up->prev_status) | 350 | if ((status ^ up->prev_status) ^ DCD) |
360 | uart_handle_dcd_change(&up->port, | 351 | uart_handle_dcd_change(&up->port, |
361 | (status & DCD)); | 352 | (status & DCD)); |
362 | if ((status & CTS) ^ up->prev_status) | 353 | if ((status ^ up->prev_status) ^ CTS) |
363 | uart_handle_cts_change(&up->port, | 354 | uart_handle_cts_change(&up->port, |
364 | (status & CTS)); | 355 | (status & CTS)); |
365 | 356 | ||
@@ -447,19 +438,21 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) | |||
447 | while (up) { | 438 | while (up) { |
448 | struct zilog_channel *channel | 439 | struct zilog_channel *channel |
449 | = ZILOG_CHANNEL_FROM_PORT(&up->port); | 440 | = ZILOG_CHANNEL_FROM_PORT(&up->port); |
441 | struct tty_struct *tty; | ||
450 | unsigned char r3; | 442 | unsigned char r3; |
451 | 443 | ||
452 | spin_lock(&up->port.lock); | 444 | spin_lock(&up->port.lock); |
453 | r3 = read_zsreg(channel, R3); | 445 | r3 = read_zsreg(channel, R3); |
454 | 446 | ||
455 | /* Channel A */ | 447 | /* Channel A */ |
448 | tty = NULL; | ||
456 | if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { | 449 | if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { |
457 | writeb(RES_H_IUS, &channel->control); | 450 | writeb(RES_H_IUS, &channel->control); |
458 | ZSDELAY(); | 451 | ZSDELAY(); |
459 | ZS_WSYNC(channel); | 452 | ZS_WSYNC(channel); |
460 | 453 | ||
461 | if (r3 & CHARxIP) | 454 | if (r3 & CHARxIP) |
462 | ip22zilog_receive_chars(up, channel); | 455 | tty = ip22zilog_receive_chars(up, channel); |
463 | if (r3 & CHAEXT) | 456 | if (r3 & CHAEXT) |
464 | ip22zilog_status_handle(up, channel); | 457 | ip22zilog_status_handle(up, channel); |
465 | if (r3 & CHATxIP) | 458 | if (r3 & CHATxIP) |
@@ -467,18 +460,22 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) | |||
467 | } | 460 | } |
468 | spin_unlock(&up->port.lock); | 461 | spin_unlock(&up->port.lock); |
469 | 462 | ||
463 | if (tty) | ||
464 | tty_flip_buffer_push(tty); | ||
465 | |||
470 | /* Channel B */ | 466 | /* Channel B */ |
471 | up = up->next; | 467 | up = up->next; |
472 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | 468 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); |
473 | 469 | ||
474 | spin_lock(&up->port.lock); | 470 | spin_lock(&up->port.lock); |
471 | tty = NULL; | ||
475 | if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { | 472 | if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { |
476 | writeb(RES_H_IUS, &channel->control); | 473 | writeb(RES_H_IUS, &channel->control); |
477 | ZSDELAY(); | 474 | ZSDELAY(); |
478 | ZS_WSYNC(channel); | 475 | ZS_WSYNC(channel); |
479 | 476 | ||
480 | if (r3 & CHBRxIP) | 477 | if (r3 & CHBRxIP) |
481 | ip22zilog_receive_chars(up, channel); | 478 | tty = ip22zilog_receive_chars(up, channel); |
482 | if (r3 & CHBEXT) | 479 | if (r3 & CHBEXT) |
483 | ip22zilog_status_handle(up, channel); | 480 | ip22zilog_status_handle(up, channel); |
484 | if (r3 & CHBTxIP) | 481 | if (r3 & CHBTxIP) |
@@ -486,6 +483,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) | |||
486 | } | 483 | } |
487 | spin_unlock(&up->port.lock); | 484 | spin_unlock(&up->port.lock); |
488 | 485 | ||
486 | if (tty) | ||
487 | tty_flip_buffer_push(tty); | ||
488 | |||
489 | up = up->next; | 489 | up = up->next; |
490 | } | 490 | } |
491 | 491 | ||
@@ -681,11 +681,46 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) | |||
681 | spin_unlock_irqrestore(&port->lock, flags); | 681 | spin_unlock_irqrestore(&port->lock, flags); |
682 | } | 682 | } |
683 | 683 | ||
684 | static void __ip22zilog_reset(struct uart_ip22zilog_port *up) | ||
685 | { | ||
686 | struct zilog_channel *channel; | ||
687 | int i; | ||
688 | |||
689 | if (up->flags & IP22ZILOG_FLAG_RESET_DONE) | ||
690 | return; | ||
691 | |||
692 | /* Let pending transmits finish. */ | ||
693 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | ||
694 | for (i = 0; i < 1000; i++) { | ||
695 | unsigned char stat = read_zsreg(channel, R1); | ||
696 | if (stat & ALL_SNT) | ||
697 | break; | ||
698 | udelay(100); | ||
699 | } | ||
700 | |||
701 | if (!ZS_IS_CHANNEL_A(up)) { | ||
702 | up++; | ||
703 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | ||
704 | } | ||
705 | write_zsreg(channel, R9, FHWRES); | ||
706 | ZSDELAY_LONG(); | ||
707 | (void) read_zsreg(channel, R0); | ||
708 | |||
709 | up->flags |= IP22ZILOG_FLAG_RESET_DONE; | ||
710 | up->next->flags |= IP22ZILOG_FLAG_RESET_DONE; | ||
711 | } | ||
712 | |||
684 | static void __ip22zilog_startup(struct uart_ip22zilog_port *up) | 713 | static void __ip22zilog_startup(struct uart_ip22zilog_port *up) |
685 | { | 714 | { |
686 | struct zilog_channel *channel; | 715 | struct zilog_channel *channel; |
687 | 716 | ||
688 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | 717 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); |
718 | |||
719 | __ip22zilog_reset(up); | ||
720 | |||
721 | __load_zsregs(channel, up->curregs); | ||
722 | /* set master interrupt enable */ | ||
723 | write_zsreg(channel, R9, up->curregs[R9]); | ||
689 | up->prev_status = readb(&channel->control); | 724 | up->prev_status = readb(&channel->control); |
690 | 725 | ||
691 | /* Enable receiver and transmitter. */ | 726 | /* Enable receiver and transmitter. */ |
@@ -859,8 +894,6 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, | |||
859 | else | 894 | else |
860 | up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS; | 895 | up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS; |
861 | 896 | ||
862 | up->cflag = termios->c_cflag; | ||
863 | |||
864 | ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); | 897 | ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); |
865 | uart_update_timeout(port, termios->c_cflag, baud); | 898 | uart_update_timeout(port, termios->c_cflag, baud); |
866 | 899 | ||
@@ -992,74 +1025,29 @@ ip22zilog_console_write(struct console *con, const char *s, unsigned int count) | |||
992 | spin_unlock_irqrestore(&up->port.lock, flags); | 1025 | spin_unlock_irqrestore(&up->port.lock, flags); |
993 | } | 1026 | } |
994 | 1027 | ||
995 | void | ||
996 | ip22serial_console_termios(struct console *con, char *options) | ||
997 | { | ||
998 | int baud = 9600, bits = 8, cflag; | ||
999 | int parity = 'n'; | ||
1000 | int flow = 'n'; | ||
1001 | |||
1002 | if (options) | ||
1003 | uart_parse_options(options, &baud, &parity, &bits, &flow); | ||
1004 | |||
1005 | cflag = CREAD | HUPCL | CLOCAL; | ||
1006 | |||
1007 | switch (baud) { | ||
1008 | case 150: cflag |= B150; break; | ||
1009 | case 300: cflag |= B300; break; | ||
1010 | case 600: cflag |= B600; break; | ||
1011 | case 1200: cflag |= B1200; break; | ||
1012 | case 2400: cflag |= B2400; break; | ||
1013 | case 4800: cflag |= B4800; break; | ||
1014 | case 9600: cflag |= B9600; break; | ||
1015 | case 19200: cflag |= B19200; break; | ||
1016 | case 38400: cflag |= B38400; break; | ||
1017 | default: baud = 9600; cflag |= B9600; break; | ||
1018 | } | ||
1019 | |||
1020 | con->cflag = cflag | CS8; /* 8N1 */ | ||
1021 | |||
1022 | uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud); | ||
1023 | } | ||
1024 | |||
1025 | static int __init ip22zilog_console_setup(struct console *con, char *options) | 1028 | static int __init ip22zilog_console_setup(struct console *con, char *options) |
1026 | { | 1029 | { |
1027 | struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; | 1030 | struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; |
1028 | unsigned long flags; | 1031 | unsigned long flags; |
1029 | int baud, brg; | 1032 | int baud = 9600, bits = 8; |
1030 | 1033 | int parity = 'n'; | |
1031 | printk("Console: ttyS%d (IP22-Zilog)\n", con->index); | 1034 | int flow = 'n'; |
1032 | 1035 | ||
1033 | /* Get firmware console settings. */ | 1036 | up->flags |= IP22ZILOG_FLAG_IS_CONS; |
1034 | ip22serial_console_termios(con, options); | ||
1035 | 1037 | ||
1036 | /* Firmware console speed is limited to 150-->38400 baud so | 1038 | printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index); |
1037 | * this hackish cflag thing is OK. | ||
1038 | */ | ||
1039 | switch (con->cflag & CBAUD) { | ||
1040 | case B150: baud = 150; break; | ||
1041 | case B300: baud = 300; break; | ||
1042 | case B600: baud = 600; break; | ||
1043 | case B1200: baud = 1200; break; | ||
1044 | case B2400: baud = 2400; break; | ||
1045 | case B4800: baud = 4800; break; | ||
1046 | default: case B9600: baud = 9600; break; | ||
1047 | case B19200: baud = 19200; break; | ||
1048 | case B38400: baud = 38400; break; | ||
1049 | }; | ||
1050 | |||
1051 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); | ||
1052 | 1039 | ||
1053 | spin_lock_irqsave(&up->port.lock, flags); | 1040 | spin_lock_irqsave(&up->port.lock, flags); |
1054 | 1041 | ||
1055 | up->curregs[R15] = BRKIE; | 1042 | up->curregs[R15] |= BRKIE; |
1056 | ip22zilog_convert_to_zs(up, con->cflag, 0, brg); | ||
1057 | 1043 | ||
1058 | __ip22zilog_startup(up); | 1044 | __ip22zilog_startup(up); |
1059 | 1045 | ||
1060 | spin_unlock_irqrestore(&up->port.lock, flags); | 1046 | spin_unlock_irqrestore(&up->port.lock, flags); |
1061 | 1047 | ||
1062 | return 0; | 1048 | if (options) |
1049 | uart_parse_options(options, &baud, &parity, &bits, &flow); | ||
1050 | return uart_set_options(&up->port, con, baud, parity, bits, flow); | ||
1063 | } | 1051 | } |
1064 | 1052 | ||
1065 | static struct uart_driver ip22zilog_reg; | 1053 | static struct uart_driver ip22zilog_reg; |
@@ -1140,25 +1128,10 @@ static void __init ip22zilog_prepare(void) | |||
1140 | up[(chip * 2) + 1].port.line = (chip * 2) + 1; | 1128 | up[(chip * 2) + 1].port.line = (chip * 2) + 1; |
1141 | up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; | 1129 | up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; |
1142 | } | 1130 | } |
1143 | } | ||
1144 | |||
1145 | static void __init ip22zilog_init_hw(void) | ||
1146 | { | ||
1147 | int i; | ||
1148 | |||
1149 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
1150 | struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; | ||
1151 | struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | ||
1152 | unsigned long flags; | ||
1153 | int baud, brg; | ||
1154 | 1131 | ||
1155 | spin_lock_irqsave(&up->port.lock, flags); | 1132 | for (channel = 0; channel < NUM_CHANNELS; channel++) { |
1156 | 1133 | struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel]; | |
1157 | if (ZS_IS_CHANNEL_A(up)) { | 1134 | int brg; |
1158 | write_zsreg(channel, R9, FHWRES); | ||
1159 | ZSDELAY_LONG(); | ||
1160 | (void) read_zsreg(channel, R0); | ||
1161 | } | ||
1162 | 1135 | ||
1163 | /* Normal serial TTY. */ | 1136 | /* Normal serial TTY. */ |
1164 | up->parity_mask = 0xff; | 1137 | up->parity_mask = 0xff; |
@@ -1169,16 +1142,10 @@ static void __init ip22zilog_init_hw(void) | |||
1169 | up->curregs[R9] = NV | MIE; | 1142 | up->curregs[R9] = NV | MIE; |
1170 | up->curregs[R10] = NRZ; | 1143 | up->curregs[R10] = NRZ; |
1171 | up->curregs[R11] = TCBR | RCBR; | 1144 | up->curregs[R11] = TCBR | RCBR; |
1172 | baud = 9600; | 1145 | brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); |
1173 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); | ||
1174 | up->curregs[R12] = (brg & 0xff); | 1146 | up->curregs[R12] = (brg & 0xff); |
1175 | up->curregs[R13] = (brg >> 8) & 0xff; | 1147 | up->curregs[R13] = (brg >> 8) & 0xff; |
1176 | up->curregs[R14] = BRENAB; | 1148 | up->curregs[R14] = BRENAB; |
1177 | __load_zsregs(channel, up->curregs); | ||
1178 | /* set master interrupt enable */ | ||
1179 | write_zsreg(channel, R9, up->curregs[R9]); | ||
1180 | |||
1181 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
1182 | } | 1149 | } |
1183 | } | 1150 | } |
1184 | 1151 | ||
@@ -1195,8 +1162,6 @@ static int __init ip22zilog_ports_init(void) | |||
1195 | panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); | 1162 | panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); |
1196 | } | 1163 | } |
1197 | 1164 | ||
1198 | ip22zilog_init_hw(); | ||
1199 | |||
1200 | ret = uart_register_driver(&ip22zilog_reg); | 1165 | ret = uart_register_driver(&ip22zilog_reg); |
1201 | if (ret == 0) { | 1166 | if (ret == 0) { |
1202 | int i; | 1167 | int i; |