diff options
author | David S. Miller <davem@davemloft.net> | 2006-06-29 18:13:17 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-29 19:37:42 -0400 |
commit | 3676463178401293d625a102a00da0473fa33a1b (patch) | |
tree | 5c46e9e73e068c1303b297078f9b5a1f20857bd8 /drivers | |
parent | 8f96cd1a69d4c43e3473406a1fdf15cd9f1de5e5 (diff) |
[SERIAL] sunzilog: Convert to of_driver.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/sunzilog.c | 785 |
1 files changed, 258 insertions, 527 deletions
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 9f42677287ad..cbdf9d605b3f 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* | 1 | /* sunzilog.c: Zilog serial driver for Sparc systems. |
2 | * sunzilog.c | ||
3 | * | 2 | * |
4 | * Driver for Zilog serial chips found on Sun workstations and | 3 | * Driver for Zilog serial chips found on Sun workstations and |
5 | * servers. This driver could actually be made more generic. | 4 | * servers. This driver could actually be made more generic. |
@@ -10,7 +9,7 @@ | |||
10 | * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their | 9 | * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their |
11 | * work there. | 10 | * work there. |
12 | * | 11 | * |
13 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) | 12 | * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) |
14 | */ | 13 | */ |
15 | 14 | ||
16 | #include <linux/config.h> | 15 | #include <linux/config.h> |
@@ -38,10 +37,8 @@ | |||
38 | 37 | ||
39 | #include <asm/io.h> | 38 | #include <asm/io.h> |
40 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
41 | #ifdef CONFIG_SPARC64 | 40 | #include <asm/prom.h> |
42 | #include <asm/fhc.h> | 41 | #include <asm/of_device.h> |
43 | #endif | ||
44 | #include <asm/sbus.h> | ||
45 | 42 | ||
46 | #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 43 | #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
47 | #define SUPPORT_SYSRQ | 44 | #define SUPPORT_SYSRQ |
@@ -65,7 +62,7 @@ | |||
65 | #define ZSDELAY() | 62 | #define ZSDELAY() |
66 | #define ZSDELAY_LONG() | 63 | #define ZSDELAY_LONG() |
67 | #define ZS_WSYNC(__channel) \ | 64 | #define ZS_WSYNC(__channel) \ |
68 | sbus_readb(&((__channel)->control)) | 65 | readb(&((__channel)->control)) |
69 | #endif | 66 | #endif |
70 | 67 | ||
71 | static int num_sunzilog; | 68 | static int num_sunzilog; |
@@ -107,7 +104,7 @@ struct uart_sunzilog_port { | |||
107 | unsigned char prev_status; | 104 | unsigned char prev_status; |
108 | 105 | ||
109 | #ifdef CONFIG_SERIO | 106 | #ifdef CONFIG_SERIO |
110 | struct serio *serio; | 107 | struct serio serio; |
111 | int serio_open; | 108 | int serio_open; |
112 | #endif | 109 | #endif |
113 | }; | 110 | }; |
@@ -138,9 +135,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, | |||
138 | { | 135 | { |
139 | unsigned char retval; | 136 | unsigned char retval; |
140 | 137 | ||
141 | sbus_writeb(reg, &channel->control); | 138 | writeb(reg, &channel->control); |
142 | ZSDELAY(); | 139 | ZSDELAY(); |
143 | retval = sbus_readb(&channel->control); | 140 | retval = readb(&channel->control); |
144 | ZSDELAY(); | 141 | ZSDELAY(); |
145 | 142 | ||
146 | return retval; | 143 | return retval; |
@@ -149,9 +146,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, | |||
149 | static void write_zsreg(struct zilog_channel __iomem *channel, | 146 | static void write_zsreg(struct zilog_channel __iomem *channel, |
150 | unsigned char reg, unsigned char value) | 147 | unsigned char reg, unsigned char value) |
151 | { | 148 | { |
152 | sbus_writeb(reg, &channel->control); | 149 | writeb(reg, &channel->control); |
153 | ZSDELAY(); | 150 | ZSDELAY(); |
154 | sbus_writeb(value, &channel->control); | 151 | writeb(value, &channel->control); |
155 | ZSDELAY(); | 152 | ZSDELAY(); |
156 | } | 153 | } |
157 | 154 | ||
@@ -162,17 +159,17 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) | |||
162 | for (i = 0; i < 32; i++) { | 159 | for (i = 0; i < 32; i++) { |
163 | unsigned char regval; | 160 | unsigned char regval; |
164 | 161 | ||
165 | regval = sbus_readb(&channel->control); | 162 | regval = readb(&channel->control); |
166 | ZSDELAY(); | 163 | ZSDELAY(); |
167 | if (regval & Rx_CH_AV) | 164 | if (regval & Rx_CH_AV) |
168 | break; | 165 | break; |
169 | 166 | ||
170 | regval = read_zsreg(channel, R1); | 167 | regval = read_zsreg(channel, R1); |
171 | sbus_readb(&channel->data); | 168 | readb(&channel->data); |
172 | ZSDELAY(); | 169 | ZSDELAY(); |
173 | 170 | ||
174 | if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { | 171 | if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { |
175 | sbus_writeb(ERR_RES, &channel->control); | 172 | writeb(ERR_RES, &channel->control); |
176 | ZSDELAY(); | 173 | ZSDELAY(); |
177 | ZS_WSYNC(channel); | 174 | ZS_WSYNC(channel); |
178 | } | 175 | } |
@@ -194,7 +191,7 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * | |||
194 | udelay(100); | 191 | udelay(100); |
195 | } | 192 | } |
196 | 193 | ||
197 | sbus_writeb(ERR_RES, &channel->control); | 194 | writeb(ERR_RES, &channel->control); |
198 | ZSDELAY(); | 195 | ZSDELAY(); |
199 | ZS_WSYNC(channel); | 196 | ZS_WSYNC(channel); |
200 | 197 | ||
@@ -291,7 +288,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, | |||
291 | /* Stop-A is handled by drivers/char/keyboard.c now. */ | 288 | /* Stop-A is handled by drivers/char/keyboard.c now. */ |
292 | #ifdef CONFIG_SERIO | 289 | #ifdef CONFIG_SERIO |
293 | if (up->serio_open) | 290 | if (up->serio_open) |
294 | serio_interrupt(up->serio, ch, 0, regs); | 291 | serio_interrupt(&up->serio, ch, 0, regs); |
295 | #endif | 292 | #endif |
296 | } else if (ZS_IS_MOUSE(up)) { | 293 | } else if (ZS_IS_MOUSE(up)) { |
297 | int ret = suncore_mouse_baud_detection(ch, is_break); | 294 | int ret = suncore_mouse_baud_detection(ch, is_break); |
@@ -306,7 +303,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, | |||
306 | case 0: | 303 | case 0: |
307 | #ifdef CONFIG_SERIO | 304 | #ifdef CONFIG_SERIO |
308 | if (up->serio_open) | 305 | if (up->serio_open) |
309 | serio_interrupt(up->serio, ch, 0, regs); | 306 | serio_interrupt(&up->serio, ch, 0, regs); |
310 | #endif | 307 | #endif |
311 | break; | 308 | break; |
312 | }; | 309 | }; |
@@ -330,12 +327,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, | |||
330 | 327 | ||
331 | r1 = read_zsreg(channel, R1); | 328 | r1 = read_zsreg(channel, R1); |
332 | if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { | 329 | if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { |
333 | sbus_writeb(ERR_RES, &channel->control); | 330 | writeb(ERR_RES, &channel->control); |
334 | ZSDELAY(); | 331 | ZSDELAY(); |
335 | ZS_WSYNC(channel); | 332 | ZS_WSYNC(channel); |
336 | } | 333 | } |
337 | 334 | ||
338 | ch = sbus_readb(&channel->control); | 335 | ch = readb(&channel->control); |
339 | ZSDELAY(); | 336 | ZSDELAY(); |
340 | 337 | ||
341 | /* This funny hack depends upon BRK_ABRT not interfering | 338 | /* This funny hack depends upon BRK_ABRT not interfering |
@@ -347,7 +344,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, | |||
347 | if (!(ch & Rx_CH_AV)) | 344 | if (!(ch & Rx_CH_AV)) |
348 | break; | 345 | break; |
349 | 346 | ||
350 | ch = sbus_readb(&channel->data); | 347 | ch = readb(&channel->data); |
351 | ZSDELAY(); | 348 | ZSDELAY(); |
352 | 349 | ||
353 | ch &= up->parity_mask; | 350 | ch &= up->parity_mask; |
@@ -406,10 +403,10 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, | |||
406 | { | 403 | { |
407 | unsigned char status; | 404 | unsigned char status; |
408 | 405 | ||
409 | status = sbus_readb(&channel->control); | 406 | status = readb(&channel->control); |
410 | ZSDELAY(); | 407 | ZSDELAY(); |
411 | 408 | ||
412 | sbus_writeb(RES_EXT_INT, &channel->control); | 409 | writeb(RES_EXT_INT, &channel->control); |
413 | ZSDELAY(); | 410 | ZSDELAY(); |
414 | ZS_WSYNC(channel); | 411 | ZS_WSYNC(channel); |
415 | 412 | ||
@@ -421,7 +418,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, | |||
421 | * confusing the PROM. | 418 | * confusing the PROM. |
422 | */ | 419 | */ |
423 | while (1) { | 420 | while (1) { |
424 | status = sbus_readb(&channel->control); | 421 | status = readb(&channel->control); |
425 | ZSDELAY(); | 422 | ZSDELAY(); |
426 | if (!(status & BRK_ABRT)) | 423 | if (!(status & BRK_ABRT)) |
427 | break; | 424 | break; |
@@ -458,7 +455,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, | |||
458 | struct circ_buf *xmit; | 455 | struct circ_buf *xmit; |
459 | 456 | ||
460 | if (ZS_IS_CONS(up)) { | 457 | if (ZS_IS_CONS(up)) { |
461 | unsigned char status = sbus_readb(&channel->control); | 458 | unsigned char status = readb(&channel->control); |
462 | ZSDELAY(); | 459 | ZSDELAY(); |
463 | 460 | ||
464 | /* TX still busy? Just wait for the next TX done interrupt. | 461 | /* TX still busy? Just wait for the next TX done interrupt. |
@@ -487,7 +484,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, | |||
487 | 484 | ||
488 | if (up->port.x_char) { | 485 | if (up->port.x_char) { |
489 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; | 486 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; |
490 | sbus_writeb(up->port.x_char, &channel->data); | 487 | writeb(up->port.x_char, &channel->data); |
491 | ZSDELAY(); | 488 | ZSDELAY(); |
492 | ZS_WSYNC(channel); | 489 | ZS_WSYNC(channel); |
493 | 490 | ||
@@ -506,7 +503,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, | |||
506 | goto ack_tx_int; | 503 | goto ack_tx_int; |
507 | 504 | ||
508 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; | 505 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; |
509 | sbus_writeb(xmit->buf[xmit->tail], &channel->data); | 506 | writeb(xmit->buf[xmit->tail], &channel->data); |
510 | ZSDELAY(); | 507 | ZSDELAY(); |
511 | ZS_WSYNC(channel); | 508 | ZS_WSYNC(channel); |
512 | 509 | ||
@@ -519,7 +516,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, | |||
519 | return; | 516 | return; |
520 | 517 | ||
521 | ack_tx_int: | 518 | ack_tx_int: |
522 | sbus_writeb(RES_Tx_P, &channel->control); | 519 | writeb(RES_Tx_P, &channel->control); |
523 | ZSDELAY(); | 520 | ZSDELAY(); |
524 | ZS_WSYNC(channel); | 521 | ZS_WSYNC(channel); |
525 | } | 522 | } |
@@ -540,7 +537,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg | |||
540 | /* Channel A */ | 537 | /* Channel A */ |
541 | tty = NULL; | 538 | tty = NULL; |
542 | if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { | 539 | if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { |
543 | sbus_writeb(RES_H_IUS, &channel->control); | 540 | writeb(RES_H_IUS, &channel->control); |
544 | ZSDELAY(); | 541 | ZSDELAY(); |
545 | ZS_WSYNC(channel); | 542 | ZS_WSYNC(channel); |
546 | 543 | ||
@@ -563,7 +560,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg | |||
563 | spin_lock(&up->port.lock); | 560 | spin_lock(&up->port.lock); |
564 | tty = NULL; | 561 | tty = NULL; |
565 | if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { | 562 | if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { |
566 | sbus_writeb(RES_H_IUS, &channel->control); | 563 | writeb(RES_H_IUS, &channel->control); |
567 | ZSDELAY(); | 564 | ZSDELAY(); |
568 | ZS_WSYNC(channel); | 565 | ZS_WSYNC(channel); |
569 | 566 | ||
@@ -594,7 +591,7 @@ static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *p | |||
594 | unsigned char status; | 591 | unsigned char status; |
595 | 592 | ||
596 | channel = ZILOG_CHANNEL_FROM_PORT(port); | 593 | channel = ZILOG_CHANNEL_FROM_PORT(port); |
597 | status = sbus_readb(&channel->control); | 594 | status = readb(&channel->control); |
598 | ZSDELAY(); | 595 | ZSDELAY(); |
599 | 596 | ||
600 | return status; | 597 | return status; |
@@ -682,7 +679,7 @@ static void sunzilog_start_tx(struct uart_port *port) | |||
682 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; | 679 | up->flags |= SUNZILOG_FLAG_TX_ACTIVE; |
683 | up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; | 680 | up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; |
684 | 681 | ||
685 | status = sbus_readb(&channel->control); | 682 | status = readb(&channel->control); |
686 | ZSDELAY(); | 683 | ZSDELAY(); |
687 | 684 | ||
688 | /* TX busy? Just wait for the TX done interrupt. */ | 685 | /* TX busy? Just wait for the TX done interrupt. */ |
@@ -693,7 +690,7 @@ static void sunzilog_start_tx(struct uart_port *port) | |||
693 | * IRQ sending engine. | 690 | * IRQ sending engine. |
694 | */ | 691 | */ |
695 | if (port->x_char) { | 692 | if (port->x_char) { |
696 | sbus_writeb(port->x_char, &channel->data); | 693 | writeb(port->x_char, &channel->data); |
697 | ZSDELAY(); | 694 | ZSDELAY(); |
698 | ZS_WSYNC(channel); | 695 | ZS_WSYNC(channel); |
699 | 696 | ||
@@ -702,7 +699,7 @@ static void sunzilog_start_tx(struct uart_port *port) | |||
702 | } else { | 699 | } else { |
703 | struct circ_buf *xmit = &port->info->xmit; | 700 | struct circ_buf *xmit = &port->info->xmit; |
704 | 701 | ||
705 | sbus_writeb(xmit->buf[xmit->tail], &channel->data); | 702 | writeb(xmit->buf[xmit->tail], &channel->data); |
706 | ZSDELAY(); | 703 | ZSDELAY(); |
707 | ZS_WSYNC(channel); | 704 | ZS_WSYNC(channel); |
708 | 705 | ||
@@ -779,7 +776,7 @@ static void __sunzilog_startup(struct uart_sunzilog_port *up) | |||
779 | struct zilog_channel __iomem *channel; | 776 | struct zilog_channel __iomem *channel; |
780 | 777 | ||
781 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | 778 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); |
782 | up->prev_status = sbus_readb(&channel->control); | 779 | up->prev_status = readb(&channel->control); |
783 | 780 | ||
784 | /* Enable receiver and transmitter. */ | 781 | /* Enable receiver and transmitter. */ |
785 | up->curregs[R3] |= RxENAB; | 782 | up->curregs[R3] |= RxENAB; |
@@ -963,7 +960,7 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios, | |||
963 | 960 | ||
964 | static const char *sunzilog_type(struct uart_port *port) | 961 | static const char *sunzilog_type(struct uart_port *port) |
965 | { | 962 | { |
966 | return "SunZilog"; | 963 | return "zs"; |
967 | } | 964 | } |
968 | 965 | ||
969 | /* We do not request/release mappings of the registers here, this | 966 | /* We do not request/release mappings of the registers here, this |
@@ -1012,7 +1009,6 @@ static struct uart_sunzilog_port *sunzilog_port_table; | |||
1012 | static struct zilog_layout __iomem **sunzilog_chip_regs; | 1009 | static struct zilog_layout __iomem **sunzilog_chip_regs; |
1013 | 1010 | ||
1014 | static struct uart_sunzilog_port *sunzilog_irq_chain; | 1011 | static struct uart_sunzilog_port *sunzilog_irq_chain; |
1015 | static int zilog_irq = -1; | ||
1016 | 1012 | ||
1017 | static struct uart_driver sunzilog_reg = { | 1013 | static struct uart_driver sunzilog_reg = { |
1018 | .owner = THIS_MODULE, | 1014 | .owner = THIS_MODULE, |
@@ -1021,232 +1017,47 @@ static struct uart_driver sunzilog_reg = { | |||
1021 | .major = TTY_MAJOR, | 1017 | .major = TTY_MAJOR, |
1022 | }; | 1018 | }; |
1023 | 1019 | ||
1024 | static void * __init alloc_one_table(unsigned long size) | 1020 | static int __init sunzilog_alloc_tables(void) |
1025 | { | 1021 | { |
1026 | void *ret; | 1022 | struct uart_sunzilog_port *up; |
1027 | 1023 | unsigned long size; | |
1028 | ret = kmalloc(size, GFP_KERNEL); | 1024 | int i; |
1029 | if (ret != NULL) | ||
1030 | memset(ret, 0, size); | ||
1031 | 1025 | ||
1032 | return ret; | 1026 | size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); |
1033 | } | 1027 | sunzilog_port_table = kzalloc(size, GFP_KERNEL); |
1028 | if (!sunzilog_port_table) | ||
1029 | return -ENOMEM; | ||
1034 | 1030 | ||
1035 | static void __init sunzilog_alloc_tables(void) | 1031 | for (i = 0; i < NUM_CHANNELS; i++) { |
1036 | { | 1032 | up = &sunzilog_port_table[i]; |
1037 | sunzilog_port_table = | ||
1038 | alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port)); | ||
1039 | sunzilog_chip_regs = | ||
1040 | alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *)); | ||
1041 | |||
1042 | if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) { | ||
1043 | prom_printf("SunZilog: Cannot allocate tables.\n"); | ||
1044 | prom_halt(); | ||
1045 | } | ||
1046 | } | ||
1047 | 1033 | ||
1048 | #ifdef CONFIG_SPARC64 | 1034 | spin_lock_init(&up->port.lock); |
1049 | 1035 | ||
1050 | /* We used to attempt to use the address property of the Zilog device node | 1036 | if (i == 0) |
1051 | * but that totally is not necessary on sparc64. | 1037 | sunzilog_irq_chain = up; |
1052 | */ | ||
1053 | static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) | ||
1054 | { | ||
1055 | void __iomem *mapped_addr; | ||
1056 | unsigned int sun4u_ino; | ||
1057 | struct sbus_bus *sbus = NULL; | ||
1058 | struct sbus_dev *sdev = NULL; | ||
1059 | int err; | ||
1060 | 1038 | ||
1061 | if (central_bus == NULL) { | 1039 | if (i < NUM_CHANNELS - 1) |
1062 | for_each_sbus(sbus) { | 1040 | up->next = up + 1; |
1063 | for_each_sbusdev(sdev, sbus) { | 1041 | else |
1064 | if (sdev->prom_node == zsnode) | 1042 | up->next = NULL; |
1065 | goto found; | ||
1066 | } | ||
1067 | } | ||
1068 | } | ||
1069 | found: | ||
1070 | if (sdev == NULL && central_bus == NULL) { | ||
1071 | prom_printf("SunZilog: sdev&¢ral == NULL for " | ||
1072 | "Zilog %d in get_zs_sun4u.\n", chip); | ||
1073 | prom_halt(); | ||
1074 | } | ||
1075 | if (central_bus == NULL) { | ||
1076 | mapped_addr = | ||
1077 | sbus_ioremap(&sdev->resource[0], 0, | ||
1078 | PAGE_SIZE, | ||
1079 | "Zilog Registers"); | ||
1080 | } else { | ||
1081 | struct linux_prom_registers zsregs[1]; | ||
1082 | |||
1083 | err = prom_getproperty(zsnode, "reg", | ||
1084 | (char *) &zsregs[0], | ||
1085 | sizeof(zsregs)); | ||
1086 | if (err == -1) { | ||
1087 | prom_printf("SunZilog: Cannot map " | ||
1088 | "Zilog %d regs on " | ||
1089 | "central bus.\n", chip); | ||
1090 | prom_halt(); | ||
1091 | } | ||
1092 | apply_fhc_ranges(central_bus->child, | ||
1093 | &zsregs[0], 1); | ||
1094 | apply_central_ranges(central_bus, &zsregs[0], 1); | ||
1095 | mapped_addr = (void __iomem *) | ||
1096 | ((((u64)zsregs[0].which_io)<<32UL) | | ||
1097 | ((u64)zsregs[0].phys_addr)); | ||
1098 | } | 1043 | } |
1099 | 1044 | ||
1100 | if (zilog_irq == -1) { | 1045 | size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); |
1101 | if (central_bus) { | 1046 | sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); |
1102 | unsigned long iclr, imap; | 1047 | if (!sunzilog_chip_regs) { |
1103 | 1048 | kfree(sunzilog_port_table); | |
1104 | iclr = central_bus->child->fhc_regs.uregs | 1049 | sunzilog_irq_chain = NULL; |
1105 | + FHC_UREGS_ICLR; | 1050 | return -ENOMEM; |
1106 | imap = central_bus->child->fhc_regs.uregs | ||
1107 | + FHC_UREGS_IMAP; | ||
1108 | zilog_irq = build_irq(0, iclr, imap); | ||
1109 | } else { | ||
1110 | err = prom_getproperty(zsnode, "interrupts", | ||
1111 | (char *) &sun4u_ino, | ||
1112 | sizeof(sun4u_ino)); | ||
1113 | zilog_irq = sbus_build_irq(sbus_root, sun4u_ino); | ||
1114 | } | ||
1115 | } | 1051 | } |
1116 | 1052 | ||
1117 | return (struct zilog_layout __iomem *) mapped_addr; | 1053 | return 0; |
1118 | } | 1054 | } |
1119 | #else /* CONFIG_SPARC64 */ | ||
1120 | 1055 | ||
1121 | /* | 1056 | static void sunzilog_free_tables(void) |
1122 | * XXX The sun4d case is utterly screwed: it tries to re-walk the tree | ||
1123 | * (for the 3rd time) in order to find bootbus and cpu. Streamline it. | ||
1124 | */ | ||
1125 | static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node) | ||
1126 | { | 1057 | { |
1127 | struct linux_prom_irqs irq_info[2]; | 1058 | kfree(sunzilog_port_table); |
1128 | void __iomem *mapped_addr = NULL; | 1059 | sunzilog_irq_chain = NULL; |
1129 | int zsnode, cpunode, bbnode; | 1060 | kfree(sunzilog_chip_regs); |
1130 | struct linux_prom_registers zsreg[4]; | ||
1131 | struct resource res; | ||
1132 | |||
1133 | if (sparc_cpu_model == sun4d) { | ||
1134 | int walk; | ||
1135 | |||
1136 | zsnode = 0; | ||
1137 | bbnode = 0; | ||
1138 | cpunode = 0; | ||
1139 | for (walk = prom_getchild(prom_root_node); | ||
1140 | (walk = prom_searchsiblings(walk, "cpu-unit")) != 0; | ||
1141 | walk = prom_getsibling(walk)) { | ||
1142 | bbnode = prom_getchild(walk); | ||
1143 | if (bbnode && | ||
1144 | (bbnode = prom_searchsiblings(bbnode, "bootbus"))) { | ||
1145 | if ((zsnode = prom_getchild(bbnode)) == node) { | ||
1146 | cpunode = walk; | ||
1147 | break; | ||
1148 | } | ||
1149 | } | ||
1150 | } | ||
1151 | if (!walk) { | ||
1152 | prom_printf("SunZilog: Cannot find the %d'th bootbus on sun4d.\n", | ||
1153 | (chip / 2)); | ||
1154 | prom_halt(); | ||
1155 | } | ||
1156 | |||
1157 | if (prom_getproperty(zsnode, "reg", | ||
1158 | (char *) zsreg, sizeof(zsreg)) == -1) { | ||
1159 | prom_printf("SunZilog: Cannot map Zilog %d\n", chip); | ||
1160 | prom_halt(); | ||
1161 | } | ||
1162 | /* XXX Looks like an off by one? */ | ||
1163 | prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); | ||
1164 | res.start = zsreg[0].phys_addr; | ||
1165 | res.end = res.start + (8 - 1); | ||
1166 | res.flags = zsreg[0].which_io | IORESOURCE_IO; | ||
1167 | mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); | ||
1168 | |||
1169 | } else { | ||
1170 | zsnode = node; | ||
1171 | |||
1172 | #if 0 /* XXX When was this used? */ | ||
1173 | if (prom_getintdefault(zsnode, "slave", -1) != chipid) { | ||
1174 | zsnode = prom_getsibling(zsnode); | ||
1175 | continue; | ||
1176 | } | ||
1177 | #endif | ||
1178 | |||
1179 | /* | ||
1180 | * "address" is only present on ports that OBP opened | ||
1181 | * (from Mitch Bradley's "Hitchhiker's Guide to OBP"). | ||
1182 | * We do not use it. | ||
1183 | */ | ||
1184 | |||
1185 | if (prom_getproperty(zsnode, "reg", | ||
1186 | (char *) zsreg, sizeof(zsreg)) == -1) { | ||
1187 | prom_printf("SunZilog: Cannot map Zilog %d\n", chip); | ||
1188 | prom_halt(); | ||
1189 | } | ||
1190 | if (sparc_cpu_model == sun4m) /* Crude. Pass parent. XXX */ | ||
1191 | prom_apply_obio_ranges(zsreg, 1); | ||
1192 | res.start = zsreg[0].phys_addr; | ||
1193 | res.end = res.start + (8 - 1); | ||
1194 | res.flags = zsreg[0].which_io | IORESOURCE_IO; | ||
1195 | mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); | ||
1196 | } | ||
1197 | |||
1198 | if (prom_getproperty(zsnode, "intr", | ||
1199 | (char *) irq_info, sizeof(irq_info)) | ||
1200 | % sizeof(struct linux_prom_irqs)) { | ||
1201 | prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n", | ||
1202 | chip); | ||
1203 | prom_halt(); | ||
1204 | } | ||
1205 | if (zilog_irq == -1) { | ||
1206 | zilog_irq = irq_info[0].pri; | ||
1207 | } else if (zilog_irq != irq_info[0].pri) { | ||
1208 | /* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */ | ||
1209 | prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n", | ||
1210 | chip); | ||
1211 | prom_halt(); | ||
1212 | } | ||
1213 | |||
1214 | return (struct zilog_layout __iomem *) mapped_addr; | ||
1215 | } | ||
1216 | #endif /* !(CONFIG_SPARC64) */ | ||
1217 | |||
1218 | /* Get the address of the registers for SunZilog instance CHIP. */ | ||
1219 | static struct zilog_layout __iomem * __init get_zs(int chip, int node) | ||
1220 | { | ||
1221 | if (chip < 0 || chip >= NUM_SUNZILOG) { | ||
1222 | prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip); | ||
1223 | prom_halt(); | ||
1224 | } | ||
1225 | |||
1226 | #ifdef CONFIG_SPARC64 | ||
1227 | return get_zs_sun4u(chip, node); | ||
1228 | #else | ||
1229 | |||
1230 | if (sparc_cpu_model == sun4) { | ||
1231 | struct resource res; | ||
1232 | |||
1233 | /* Not probe-able, hard code it. */ | ||
1234 | switch (chip) { | ||
1235 | case 0: | ||
1236 | res.start = 0xf1000000; | ||
1237 | break; | ||
1238 | case 1: | ||
1239 | res.start = 0xf0000000; | ||
1240 | break; | ||
1241 | }; | ||
1242 | zilog_irq = 12; | ||
1243 | res.end = (res.start + (8 - 1)); | ||
1244 | res.flags = IORESOURCE_IO; | ||
1245 | return sbus_ioremap(&res, 0, 8, "SunZilog"); | ||
1246 | } | ||
1247 | |||
1248 | return get_zs_sun4cmd(chip, node); | ||
1249 | #endif | ||
1250 | } | 1061 | } |
1251 | 1062 | ||
1252 | #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ | 1063 | #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ |
@@ -1260,7 +1071,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) | |||
1260 | * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM | 1071 | * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM |
1261 | */ | 1072 | */ |
1262 | do { | 1073 | do { |
1263 | unsigned char val = sbus_readb(&channel->control); | 1074 | unsigned char val = readb(&channel->control); |
1264 | if (val & Tx_BUF_EMP) { | 1075 | if (val & Tx_BUF_EMP) { |
1265 | ZSDELAY(); | 1076 | ZSDELAY(); |
1266 | break; | 1077 | break; |
@@ -1268,7 +1079,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) | |||
1268 | udelay(5); | 1079 | udelay(5); |
1269 | } while (--loops); | 1080 | } while (--loops); |
1270 | 1081 | ||
1271 | sbus_writeb(ch, &channel->data); | 1082 | writeb(ch, &channel->data); |
1272 | ZSDELAY(); | 1083 | ZSDELAY(); |
1273 | ZS_WSYNC(channel); | 1084 | ZS_WSYNC(channel); |
1274 | } | 1085 | } |
@@ -1385,28 +1196,6 @@ static struct console sunzilog_console = { | |||
1385 | .data = &sunzilog_reg, | 1196 | .data = &sunzilog_reg, |
1386 | }; | 1197 | }; |
1387 | 1198 | ||
1388 | static int __init sunzilog_console_init(void) | ||
1389 | { | ||
1390 | int i; | ||
1391 | |||
1392 | if (con_is_present()) | ||
1393 | return 0; | ||
1394 | |||
1395 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
1396 | int this_minor = sunzilog_reg.minor + i; | ||
1397 | |||
1398 | if ((this_minor - 64) == (serial_console - 1)) | ||
1399 | break; | ||
1400 | } | ||
1401 | if (i == NUM_CHANNELS) | ||
1402 | return 0; | ||
1403 | |||
1404 | sunzilog_console.index = i; | ||
1405 | sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; | ||
1406 | register_console(&sunzilog_console); | ||
1407 | return 0; | ||
1408 | } | ||
1409 | |||
1410 | static inline struct console *SUNZILOG_CONSOLE(void) | 1199 | static inline struct console *SUNZILOG_CONSOLE(void) |
1411 | { | 1200 | { |
1412 | int i; | 1201 | int i; |
@@ -1431,101 +1220,8 @@ static inline struct console *SUNZILOG_CONSOLE(void) | |||
1431 | 1220 | ||
1432 | #else | 1221 | #else |
1433 | #define SUNZILOG_CONSOLE() (NULL) | 1222 | #define SUNZILOG_CONSOLE() (NULL) |
1434 | #define sunzilog_console_init() do { } while (0) | ||
1435 | #endif | 1223 | #endif |
1436 | 1224 | ||
1437 | /* | ||
1438 | * We scan the PROM tree recursively. This is the most reliable way | ||
1439 | * to find Zilog nodes on various platforms. However, we face an extreme | ||
1440 | * shortage of kernel stack, so we must be very careful. To that end, | ||
1441 | * we scan only to a certain depth, and we use a common property buffer | ||
1442 | * in the scan structure. | ||
1443 | */ | ||
1444 | #define ZS_PROPSIZE 128 | ||
1445 | #define ZS_SCAN_DEPTH 5 | ||
1446 | |||
1447 | struct zs_probe_scan { | ||
1448 | int depth; | ||
1449 | void (*scanner)(struct zs_probe_scan *t, int node); | ||
1450 | |||
1451 | int devices; | ||
1452 | char prop[ZS_PROPSIZE]; | ||
1453 | }; | ||
1454 | |||
1455 | static int __inline__ sunzilog_node_ok(int node, const char *name, int len) | ||
1456 | { | ||
1457 | if (strncmp(name, "zs", len) == 0) | ||
1458 | return 1; | ||
1459 | /* Don't fold this procedure just yet. Compare to su_node_ok(). */ | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | static void __init sunzilog_scan(struct zs_probe_scan *t, int node) | ||
1464 | { | ||
1465 | int len; | ||
1466 | |||
1467 | for (; node != 0; node = prom_getsibling(node)) { | ||
1468 | len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE); | ||
1469 | if (len <= 1) | ||
1470 | continue; /* Broken PROM node */ | ||
1471 | if (sunzilog_node_ok(node, t->prop, len)) { | ||
1472 | (*t->scanner)(t, node); | ||
1473 | } else { | ||
1474 | if (t->depth < ZS_SCAN_DEPTH) { | ||
1475 | t->depth++; | ||
1476 | sunzilog_scan(t, prom_getchild(node)); | ||
1477 | --t->depth; | ||
1478 | } | ||
1479 | } | ||
1480 | } | ||
1481 | } | ||
1482 | |||
1483 | static void __init sunzilog_prepare(void) | ||
1484 | { | ||
1485 | struct uart_sunzilog_port *up; | ||
1486 | struct zilog_layout __iomem *rp; | ||
1487 | int channel, chip; | ||
1488 | |||
1489 | /* | ||
1490 | * Temporary fix. | ||
1491 | */ | ||
1492 | for (channel = 0; channel < NUM_CHANNELS; channel++) | ||
1493 | spin_lock_init(&sunzilog_port_table[channel].port.lock); | ||
1494 | |||
1495 | sunzilog_irq_chain = up = &sunzilog_port_table[0]; | ||
1496 | for (channel = 0; channel < NUM_CHANNELS - 1; channel++) | ||
1497 | up[channel].next = &up[channel + 1]; | ||
1498 | up[channel].next = NULL; | ||
1499 | |||
1500 | for (chip = 0; chip < NUM_SUNZILOG; chip++) { | ||
1501 | rp = sunzilog_chip_regs[chip]; | ||
1502 | up[(chip * 2) + 0].port.membase = (void __iomem *)&rp->channelA; | ||
1503 | up[(chip * 2) + 1].port.membase = (void __iomem *)&rp->channelB; | ||
1504 | |||
1505 | /* Channel A */ | ||
1506 | up[(chip * 2) + 0].port.iotype = UPIO_MEM; | ||
1507 | up[(chip * 2) + 0].port.irq = zilog_irq; | ||
1508 | up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; | ||
1509 | up[(chip * 2) + 0].port.fifosize = 1; | ||
1510 | up[(chip * 2) + 0].port.ops = &sunzilog_pops; | ||
1511 | up[(chip * 2) + 0].port.type = PORT_SUNZILOG; | ||
1512 | up[(chip * 2) + 0].port.flags = 0; | ||
1513 | up[(chip * 2) + 0].port.line = (chip * 2) + 0; | ||
1514 | up[(chip * 2) + 0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; | ||
1515 | |||
1516 | /* Channel B */ | ||
1517 | up[(chip * 2) + 1].port.iotype = UPIO_MEM; | ||
1518 | up[(chip * 2) + 1].port.irq = zilog_irq; | ||
1519 | up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; | ||
1520 | up[(chip * 2) + 1].port.fifosize = 1; | ||
1521 | up[(chip * 2) + 1].port.ops = &sunzilog_pops; | ||
1522 | up[(chip * 2) + 1].port.type = PORT_SUNZILOG; | ||
1523 | up[(chip * 2) + 1].port.flags = 0; | ||
1524 | up[(chip * 2) + 1].port.line = (chip * 2) + 1; | ||
1525 | up[(chip * 2) + 1].flags |= 0; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) | 1225 | static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) |
1530 | { | 1226 | { |
1531 | int baud, brg; | 1227 | int baud, brg; |
@@ -1539,8 +1235,6 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe | |||
1539 | up->cflag = B4800 | CS8 | CLOCAL | CREAD; | 1235 | up->cflag = B4800 | CS8 | CLOCAL | CREAD; |
1540 | baud = 4800; | 1236 | baud = 4800; |
1541 | } | 1237 | } |
1542 | printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n", | ||
1543 | channel, up->port.membase, zilog_irq); | ||
1544 | 1238 | ||
1545 | up->curregs[R15] = BRKIE; | 1239 | up->curregs[R15] = BRKIE; |
1546 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); | 1240 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); |
@@ -1552,216 +1246,253 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe | |||
1552 | #ifdef CONFIG_SERIO | 1246 | #ifdef CONFIG_SERIO |
1553 | static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) | 1247 | static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) |
1554 | { | 1248 | { |
1555 | struct serio *serio; | 1249 | struct serio *serio = &up->serio; |
1556 | |||
1557 | up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
1558 | if (serio) { | ||
1559 | memset(serio, 0, sizeof(*serio)); | ||
1560 | 1250 | ||
1561 | serio->port_data = up; | 1251 | serio->port_data = up; |
1562 | 1252 | ||
1563 | serio->id.type = SERIO_RS232; | 1253 | serio->id.type = SERIO_RS232; |
1564 | if (channel == KEYBOARD_LINE) { | 1254 | if (channel == KEYBOARD_LINE) { |
1565 | serio->id.proto = SERIO_SUNKBD; | 1255 | serio->id.proto = SERIO_SUNKBD; |
1566 | strlcpy(serio->name, "zskbd", sizeof(serio->name)); | 1256 | strlcpy(serio->name, "zskbd", sizeof(serio->name)); |
1567 | } else { | ||
1568 | serio->id.proto = SERIO_SUN; | ||
1569 | serio->id.extra = 1; | ||
1570 | strlcpy(serio->name, "zsms", sizeof(serio->name)); | ||
1571 | } | ||
1572 | strlcpy(serio->phys, | ||
1573 | (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), | ||
1574 | sizeof(serio->phys)); | ||
1575 | |||
1576 | serio->write = sunzilog_serio_write; | ||
1577 | serio->open = sunzilog_serio_open; | ||
1578 | serio->close = sunzilog_serio_close; | ||
1579 | |||
1580 | serio_register_port(serio); | ||
1581 | } else { | 1257 | } else { |
1582 | printk(KERN_WARNING "zs%d: not enough memory for serio port\n", | 1258 | serio->id.proto = SERIO_SUN; |
1583 | channel); | 1259 | serio->id.extra = 1; |
1260 | strlcpy(serio->name, "zsms", sizeof(serio->name)); | ||
1584 | } | 1261 | } |
1262 | strlcpy(serio->phys, | ||
1263 | (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), | ||
1264 | sizeof(serio->phys)); | ||
1265 | |||
1266 | serio->write = sunzilog_serio_write; | ||
1267 | serio->open = sunzilog_serio_open; | ||
1268 | serio->close = sunzilog_serio_close; | ||
1269 | serio->dev.parent = up->port.dev; | ||
1270 | |||
1271 | serio_register_port(serio); | ||
1585 | } | 1272 | } |
1586 | #endif | 1273 | #endif |
1587 | 1274 | ||
1588 | static void __init sunzilog_init_hw(void) | 1275 | static void __init sunzilog_init_hw(struct uart_sunzilog_port *up) |
1589 | { | 1276 | { |
1590 | int i; | 1277 | struct zilog_channel __iomem *channel; |
1591 | 1278 | unsigned long flags; | |
1592 | for (i = 0; i < NUM_CHANNELS; i++) { | 1279 | int baud, brg; |
1593 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | ||
1594 | struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | ||
1595 | unsigned long flags; | ||
1596 | int baud, brg; | ||
1597 | 1280 | ||
1598 | spin_lock_irqsave(&up->port.lock, flags); | 1281 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); |
1599 | 1282 | ||
1600 | if (ZS_IS_CHANNEL_A(up)) { | 1283 | spin_lock_irqsave(&up->port.lock, flags); |
1601 | write_zsreg(channel, R9, FHWRES); | 1284 | if (ZS_IS_CHANNEL_A(up)) { |
1602 | ZSDELAY_LONG(); | 1285 | write_zsreg(channel, R9, FHWRES); |
1603 | (void) read_zsreg(channel, R0); | 1286 | ZSDELAY_LONG(); |
1604 | } | 1287 | (void) read_zsreg(channel, R0); |
1288 | } | ||
1605 | 1289 | ||
1606 | if (i == KEYBOARD_LINE || i == MOUSE_LINE) { | 1290 | if (up->port.line == KEYBOARD_LINE || |
1607 | sunzilog_init_kbdms(up, i); | 1291 | up->port.line == MOUSE_LINE) { |
1608 | up->curregs[R9] |= (NV | MIE); | 1292 | sunzilog_init_kbdms(up, up->port.line); |
1609 | write_zsreg(channel, R9, up->curregs[R9]); | 1293 | up->curregs[R9] |= (NV | MIE); |
1610 | } else { | 1294 | write_zsreg(channel, R9, up->curregs[R9]); |
1611 | /* Normal serial TTY. */ | 1295 | } else { |
1612 | up->parity_mask = 0xff; | 1296 | /* Normal serial TTY. */ |
1613 | up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; | 1297 | up->parity_mask = 0xff; |
1614 | up->curregs[R4] = PAR_EVEN | X16CLK | SB1; | 1298 | up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; |
1615 | up->curregs[R3] = RxENAB | Rx8; | 1299 | up->curregs[R4] = PAR_EVEN | X16CLK | SB1; |
1616 | up->curregs[R5] = TxENAB | Tx8; | 1300 | up->curregs[R3] = RxENAB | Rx8; |
1617 | up->curregs[R9] = NV | MIE; | 1301 | up->curregs[R5] = TxENAB | Tx8; |
1618 | up->curregs[R10] = NRZ; | 1302 | up->curregs[R9] = NV | MIE; |
1619 | up->curregs[R11] = TCBR | RCBR; | 1303 | up->curregs[R10] = NRZ; |
1620 | baud = 9600; | 1304 | up->curregs[R11] = TCBR | RCBR; |
1621 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); | 1305 | baud = 9600; |
1622 | up->curregs[R12] = (brg & 0xff); | 1306 | brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); |
1623 | up->curregs[R13] = (brg >> 8) & 0xff; | 1307 | up->curregs[R12] = (brg & 0xff); |
1624 | up->curregs[R14] = BRSRC | BRENAB; | 1308 | up->curregs[R13] = (brg >> 8) & 0xff; |
1625 | __load_zsregs(channel, up->curregs); | 1309 | up->curregs[R14] = BRSRC | BRENAB; |
1626 | write_zsreg(channel, R9, up->curregs[R9]); | 1310 | __load_zsregs(channel, up->curregs); |
1627 | } | 1311 | write_zsreg(channel, R9, up->curregs[R9]); |
1312 | } | ||
1628 | 1313 | ||
1629 | spin_unlock_irqrestore(&up->port.lock, flags); | 1314 | spin_unlock_irqrestore(&up->port.lock, flags); |
1630 | 1315 | ||
1631 | #ifdef CONFIG_SERIO | 1316 | #ifdef CONFIG_SERIO |
1632 | if (i == KEYBOARD_LINE || i == MOUSE_LINE) | 1317 | if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE) |
1633 | sunzilog_register_serio(up, i); | 1318 | sunzilog_register_serio(up, up->port.line); |
1634 | #endif | 1319 | #endif |
1635 | } | ||
1636 | } | ||
1637 | |||
1638 | static struct zilog_layout __iomem * __init get_zs(int chip, int node); | ||
1639 | |||
1640 | static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node) | ||
1641 | { | ||
1642 | sunzilog_chip_regs[t->devices] = get_zs(t->devices, node); | ||
1643 | t->devices++; | ||
1644 | } | 1320 | } |
1645 | 1321 | ||
1646 | static int __init sunzilog_ports_init(void) | 1322 | static int __devinit zs_get_instance(struct device_node *dp) |
1647 | { | 1323 | { |
1648 | struct zs_probe_scan scan; | ||
1649 | int ret; | 1324 | int ret; |
1650 | int uart_count; | ||
1651 | int i; | ||
1652 | 1325 | ||
1653 | printk(KERN_DEBUG "SunZilog: %d chips.\n", NUM_SUNZILOG); | 1326 | ret = of_getintprop_default(dp, "slave", -1); |
1327 | if (ret != -1) | ||
1328 | return ret; | ||
1654 | 1329 | ||
1655 | scan.scanner = sunzilog_scan_probe; | 1330 | if (of_find_property(dp, "keyboard", NULL)) |
1656 | scan.depth = 0; | 1331 | ret = 1; |
1657 | scan.devices = 0; | 1332 | else |
1658 | sunzilog_scan(&scan, prom_getchild(prom_root_node)); | 1333 | ret = 0; |
1659 | 1334 | ||
1660 | sunzilog_prepare(); | 1335 | return ret; |
1336 | } | ||
1661 | 1337 | ||
1662 | if (request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, | 1338 | static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) |
1663 | "SunZilog", sunzilog_irq_chain)) { | 1339 | { |
1664 | prom_printf("SunZilog: Unable to register zs interrupt handler.\n"); | 1340 | static int zilog_irq = -1; |
1665 | prom_halt(); | 1341 | struct of_device *op = to_of_device(&dev->dev); |
1666 | } | 1342 | struct uart_sunzilog_port *up; |
1343 | struct zilog_layout __iomem *rp; | ||
1344 | int inst = zs_get_instance(dev->node); | ||
1345 | int err; | ||
1667 | 1346 | ||
1668 | sunzilog_init_hw(); | 1347 | sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, |
1348 | sizeof(struct zilog_layout), | ||
1349 | "zs"); | ||
1350 | if (!sunzilog_chip_regs[inst]) | ||
1351 | return -ENOMEM; | ||
1669 | 1352 | ||
1670 | /* We can only init this once we have probed the Zilogs | 1353 | rp = sunzilog_chip_regs[inst]; |
1671 | * in the system. Do not count channels assigned to keyboards | ||
1672 | * or mice when we are deciding how many ports to register. | ||
1673 | */ | ||
1674 | uart_count = 0; | ||
1675 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
1676 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | ||
1677 | 1354 | ||
1678 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) | 1355 | if (zilog_irq == -1) { |
1679 | continue; | 1356 | zilog_irq = op->irqs[0]; |
1357 | err = request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, | ||
1358 | "zs", sunzilog_irq_chain); | ||
1359 | if (err) { | ||
1360 | of_iounmap(rp, sizeof(struct zilog_layout)); | ||
1680 | 1361 | ||
1681 | uart_count++; | 1362 | return err; |
1363 | } | ||
1682 | } | 1364 | } |
1683 | |||
1684 | sunzilog_reg.nr = uart_count; | ||
1685 | sunzilog_reg.minor = sunserial_current_minor; | ||
1686 | |||
1687 | ret = uart_register_driver(&sunzilog_reg); | ||
1688 | if (ret == 0) { | ||
1689 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; | ||
1690 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); | ||
1691 | 1365 | ||
1692 | sunserial_current_minor += uart_count; | 1366 | up = &sunzilog_port_table[inst * 2]; |
1693 | 1367 | ||
1694 | for (i = 0; i < NUM_CHANNELS; i++) { | 1368 | /* Channel A */ |
1695 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | 1369 | up[0].port.mapbase = op->resource[0].start + 0x00; |
1696 | 1370 | up[0].port.membase = (void __iomem *) &rp->channelA; | |
1697 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) | 1371 | up[0].port.iotype = UPIO_MEM; |
1698 | continue; | 1372 | up[0].port.irq = op->irqs[0]; |
1699 | 1373 | up[0].port.uartclk = ZS_CLOCK; | |
1700 | if (uart_add_one_port(&sunzilog_reg, &up->port)) { | 1374 | up[0].port.fifosize = 1; |
1701 | printk(KERN_ERR | 1375 | up[0].port.ops = &sunzilog_pops; |
1702 | "SunZilog: failed to add port zs%d\n", i); | 1376 | up[0].port.type = PORT_SUNZILOG; |
1703 | } | 1377 | up[0].port.flags = 0; |
1378 | up[0].port.line = (inst * 2) + 0; | ||
1379 | up[0].port.dev = &op->dev; | ||
1380 | up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; | ||
1381 | if (inst == 1) | ||
1382 | up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; | ||
1383 | sunzilog_init_hw(&up[0]); | ||
1384 | |||
1385 | /* Channel B */ | ||
1386 | up[1].port.mapbase = op->resource[0].start + 0x04; | ||
1387 | up[1].port.membase = (void __iomem *) &rp->channelB; | ||
1388 | up[1].port.iotype = UPIO_MEM; | ||
1389 | up[1].port.irq = op->irqs[0]; | ||
1390 | up[1].port.uartclk = ZS_CLOCK; | ||
1391 | up[1].port.fifosize = 1; | ||
1392 | up[1].port.ops = &sunzilog_pops; | ||
1393 | up[1].port.type = PORT_SUNZILOG; | ||
1394 | up[1].port.flags = 0; | ||
1395 | up[1].port.line = (inst * 2) + 1; | ||
1396 | up[1].port.dev = &op->dev; | ||
1397 | up[1].flags |= 0; | ||
1398 | if (inst == 1) | ||
1399 | up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; | ||
1400 | sunzilog_init_hw(&up[1]); | ||
1401 | |||
1402 | if (inst != 1) { | ||
1403 | err = uart_add_one_port(&sunzilog_reg, &up[0].port); | ||
1404 | if (err) { | ||
1405 | of_iounmap(rp, sizeof(struct zilog_layout)); | ||
1406 | return err; | ||
1407 | } | ||
1408 | err = uart_add_one_port(&sunzilog_reg, &up[1].port); | ||
1409 | if (err) { | ||
1410 | uart_remove_one_port(&sunzilog_reg, &up[0].port); | ||
1411 | of_iounmap(rp, sizeof(struct zilog_layout)); | ||
1412 | return err; | ||
1704 | } | 1413 | } |
1705 | } | 1414 | } |
1706 | 1415 | ||
1707 | return ret; | 1416 | return 0; |
1708 | } | ||
1709 | |||
1710 | static void __init sunzilog_scan_count(struct zs_probe_scan *t, int node) | ||
1711 | { | ||
1712 | t->devices++; | ||
1713 | } | 1417 | } |
1714 | 1418 | ||
1715 | static int __init sunzilog_ports_count(void) | 1419 | static int __devexit zs_remove(struct of_device *dev) |
1716 | { | 1420 | { |
1717 | struct zs_probe_scan scan; | 1421 | struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); |
1422 | struct zilog_channel __iomem *channel; | ||
1718 | 1423 | ||
1719 | /* Sun4 Zilog setup is hard coded, no probing to do. */ | 1424 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { |
1720 | if (sparc_cpu_model == sun4) | 1425 | #ifdef CONFIG_SERIO |
1721 | return 2; | 1426 | serio_unregister_port(&up->serio); |
1427 | #endif | ||
1428 | } else | ||
1429 | uart_remove_one_port(&sunzilog_reg, &up->port); | ||
1722 | 1430 | ||
1723 | scan.scanner = sunzilog_scan_count; | 1431 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); |
1724 | scan.depth = 0; | ||
1725 | scan.devices = 0; | ||
1726 | 1432 | ||
1727 | sunzilog_scan(&scan, prom_getchild(prom_root_node)); | 1433 | of_iounmap(channel, sizeof(struct zilog_channel)); |
1728 | 1434 | ||
1729 | return scan.devices; | 1435 | return 0; |
1730 | } | 1436 | } |
1731 | 1437 | ||
1438 | static struct of_device_id zs_match[] = { | ||
1439 | { | ||
1440 | .name = "zs", | ||
1441 | }, | ||
1442 | {}, | ||
1443 | }; | ||
1444 | MODULE_DEVICE_TABLE(of, zs_match); | ||
1445 | |||
1446 | static struct of_platform_driver zs_driver = { | ||
1447 | .name = "zs", | ||
1448 | .match_table = zs_match, | ||
1449 | .probe = zs_probe, | ||
1450 | .remove = __devexit_p(zs_remove), | ||
1451 | }; | ||
1452 | |||
1732 | static int __init sunzilog_init(void) | 1453 | static int __init sunzilog_init(void) |
1733 | { | 1454 | { |
1455 | struct device_node *dp; | ||
1456 | int err; | ||
1734 | 1457 | ||
1735 | NUM_SUNZILOG = sunzilog_ports_count(); | 1458 | NUM_SUNZILOG = 0; |
1736 | if (NUM_SUNZILOG == 0) | 1459 | for_each_node_by_name(dp, "zs") |
1737 | return -ENODEV; | 1460 | NUM_SUNZILOG++; |
1738 | 1461 | ||
1739 | sunzilog_alloc_tables(); | 1462 | if (NUM_SUNZILOG) { |
1463 | int uart_count; | ||
1740 | 1464 | ||
1741 | sunzilog_ports_init(); | 1465 | err = sunzilog_alloc_tables(); |
1466 | if (err) | ||
1467 | return err; | ||
1742 | 1468 | ||
1743 | return 0; | 1469 | /* Subtract 1 for keyboard, 1 for mouse. */ |
1470 | uart_count = (NUM_SUNZILOG * 2) - 2; | ||
1471 | |||
1472 | sunzilog_reg.nr = uart_count; | ||
1473 | sunzilog_reg.minor = sunserial_current_minor; | ||
1474 | err = uart_register_driver(&sunzilog_reg); | ||
1475 | if (err) { | ||
1476 | sunzilog_free_tables(); | ||
1477 | return err; | ||
1478 | } | ||
1479 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; | ||
1480 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); | ||
1481 | |||
1482 | sunserial_current_minor += uart_count; | ||
1483 | } | ||
1484 | |||
1485 | return of_register_driver(&zs_driver, &of_bus_type); | ||
1744 | } | 1486 | } |
1745 | 1487 | ||
1746 | static void __exit sunzilog_exit(void) | 1488 | static void __exit sunzilog_exit(void) |
1747 | { | 1489 | { |
1748 | int i; | 1490 | of_unregister_driver(&zs_driver); |
1749 | 1491 | ||
1750 | for (i = 0; i < NUM_CHANNELS; i++) { | 1492 | if (NUM_SUNZILOG) { |
1751 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | 1493 | uart_unregister_driver(&sunzilog_reg); |
1752 | 1494 | sunzilog_free_tables(); | |
1753 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { | ||
1754 | #ifdef CONFIG_SERIO | ||
1755 | if (up->serio) { | ||
1756 | serio_unregister_port(up->serio); | ||
1757 | up->serio = NULL; | ||
1758 | } | ||
1759 | #endif | ||
1760 | } else | ||
1761 | uart_remove_one_port(&sunzilog_reg, &up->port); | ||
1762 | } | 1495 | } |
1763 | |||
1764 | uart_unregister_driver(&sunzilog_reg); | ||
1765 | } | 1496 | } |
1766 | 1497 | ||
1767 | module_init(sunzilog_init); | 1498 | module_init(sunzilog_init); |