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