aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/sunzilog.c
diff options
context:
space:
mode:
authorMark Fortescue <mark@mtfhpc.demon.co.uk>2007-05-09 16:49:04 -0400
committerDavid S. Miller <davem@davemloft.net>2007-05-09 16:49:04 -0400
commit7cc5c8559c62289d027812bfdd4eb6a28c5769b6 (patch)
treed0d75ddd6cfcceba5bd5bc2a0e2438a946f04169 /drivers/serial/sunzilog.c
parentca3dd88e411648c76e1911a729440e3763ba5049 (diff)
[SERIAL] sunzilog: Interrupt enable before ISR handler installed
This patch changes the interrupt enable sequence for the sunzilog driver so that interrupts are not enabled untill after the interrupt handler has been installed. If this is not done, some SS1 and SS2 sun4c systems panic on un-handled interrupt before the handler gets installed preventing boot. It also adds in support for the ESCC version of the zilog chips. The changes mean that the FIFO will be enabled for ESCC versions of the SCC UART. My interpretation of the SCC manual and the existing interrupt handler code is that it sould be able to make good use of the FIFO without issues. Signed-off-by: Mark Fortescue <mark@mtfhpc.demon.co.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial/sunzilog.c')
-rw-r--r--drivers/serial/sunzilog.c138
1 files changed, 104 insertions, 34 deletions
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index da73205e54cd..0985193dc57d 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -92,6 +92,8 @@ struct uart_sunzilog_port {
92#define SUNZILOG_FLAG_REGS_HELD 0x00000040 92#define SUNZILOG_FLAG_REGS_HELD 0x00000040
93#define SUNZILOG_FLAG_TX_STOPPED 0x00000080 93#define SUNZILOG_FLAG_TX_STOPPED 0x00000080
94#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100 94#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100
95#define SUNZILOG_FLAG_ESCC 0x00000200
96#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400
95 97
96 unsigned int cflag; 98 unsigned int cflag;
97 99
@@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
174/* This function must only be called when the TX is not busy. The UART 176/* This function must only be called when the TX is not busy. The UART
175 * port lock must be held and local interrupts disabled. 177 * port lock must be held and local interrupts disabled.
176 */ 178 */
177static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) 179static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
178{ 180{
179 int i; 181 int i;
182 int escc;
183 unsigned char r15;
180 184
181 /* Let pending transmits finish. */ 185 /* Let pending transmits finish. */
182 for (i = 0; i < 1000; i++) { 186 for (i = 0; i < 1000; i++) {
@@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
229 write_zsreg(channel, R14, regs[R14]); 233 write_zsreg(channel, R14, regs[R14]);
230 234
231 /* External status interrupt control. */ 235 /* External status interrupt control. */
232 write_zsreg(channel, R15, regs[R15]); 236 write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
237
238 /* ESCC Extension Register */
239 r15 = read_zsreg(channel, R15);
240 if (r15 & 0x01) {
241 write_zsreg(channel, R7, regs[R7p]);
242
243 /* External status interrupt and FIFO control. */
244 write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
245 escc = 1;
246 } else {
247 /* Clear FIFO bit case it is an issue */
248 regs[R15] &= ~FIFOEN;
249 escc = 0;
250 }
233 251
234 /* Reset external status interrupts. */ 252 /* Reset external status interrupts. */
235 write_zsreg(channel, R0, RES_EXT_INT); 253 write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */
236 write_zsreg(channel, R0, RES_EXT_INT); 254 write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
237 255
238 /* Rewrite R3/R5, this time without enables masked. */ 256 /* Rewrite R3/R5, this time without enables masked. */
239 write_zsreg(channel, R3, regs[R3]); 257 write_zsreg(channel, R3, regs[R3]);
@@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
241 259
242 /* Rewrite R1, this time without IRQ enabled masked. */ 260 /* Rewrite R1, this time without IRQ enabled masked. */
243 write_zsreg(channel, R1, regs[R1]); 261 write_zsreg(channel, R1, regs[R1]);
262
263 return escc;
244} 264}
245 265
246/* Reprogram the Zilog channel HW registers with the copies found in the 266/* Reprogram the Zilog channel HW registers with the copies found in the
@@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port)
731 up->curregs[R15] = new_reg; 751 up->curregs[R15] = new_reg;
732 752
733 /* NOTE: Not subject to 'transmitter active' rule. */ 753 /* NOTE: Not subject to 'transmitter active' rule. */
734 write_zsreg(channel, R15, up->curregs[R15]); 754 write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
735 } 755 }
736} 756}
737 757
@@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
861 up->curregs[R14] = BRSRC | BRENAB; 881 up->curregs[R14] = BRSRC | BRENAB;
862 882
863 /* Character size, stop bits, and parity. */ 883 /* Character size, stop bits, and parity. */
864 up->curregs[3] &= ~RxN_MASK; 884 up->curregs[R3] &= ~RxN_MASK;
865 up->curregs[5] &= ~TxN_MASK; 885 up->curregs[R5] &= ~TxN_MASK;
866 switch (cflag & CSIZE) { 886 switch (cflag & CSIZE) {
867 case CS5: 887 case CS5:
868 up->curregs[3] |= Rx5; 888 up->curregs[R3] |= Rx5;
869 up->curregs[5] |= Tx5; 889 up->curregs[R5] |= Tx5;
870 up->parity_mask = 0x1f; 890 up->parity_mask = 0x1f;
871 break; 891 break;
872 case CS6: 892 case CS6:
873 up->curregs[3] |= Rx6; 893 up->curregs[R3] |= Rx6;
874 up->curregs[5] |= Tx6; 894 up->curregs[R5] |= Tx6;
875 up->parity_mask = 0x3f; 895 up->parity_mask = 0x3f;
876 break; 896 break;
877 case CS7: 897 case CS7:
878 up->curregs[3] |= Rx7; 898 up->curregs[R3] |= Rx7;
879 up->curregs[5] |= Tx7; 899 up->curregs[R5] |= Tx7;
880 up->parity_mask = 0x7f; 900 up->parity_mask = 0x7f;
881 break; 901 break;
882 case CS8: 902 case CS8:
883 default: 903 default:
884 up->curregs[3] |= Rx8; 904 up->curregs[R3] |= Rx8;
885 up->curregs[5] |= Tx8; 905 up->curregs[R5] |= Tx8;
886 up->parity_mask = 0xff; 906 up->parity_mask = 0xff;
887 break; 907 break;
888 }; 908 };
889 up->curregs[4] &= ~0x0c; 909 up->curregs[R4] &= ~0x0c;
890 if (cflag & CSTOPB) 910 if (cflag & CSTOPB)
891 up->curregs[4] |= SB2; 911 up->curregs[R4] |= SB2;
892 else 912 else
893 up->curregs[4] |= SB1; 913 up->curregs[R4] |= SB1;
894 if (cflag & PARENB) 914 if (cflag & PARENB)
895 up->curregs[4] |= PAR_ENAB; 915 up->curregs[R4] |= PAR_ENAB;
896 else 916 else
897 up->curregs[4] &= ~PAR_ENAB; 917 up->curregs[R4] &= ~PAR_ENAB;
898 if (!(cflag & PARODD)) 918 if (!(cflag & PARODD))
899 up->curregs[4] |= PAR_EVEN; 919 up->curregs[R4] |= PAR_EVEN;
900 else 920 else
901 up->curregs[4] &= ~PAR_EVEN; 921 up->curregs[R4] &= ~PAR_EVEN;
902 922
903 up->port.read_status_mask = Rx_OVR; 923 up->port.read_status_mask = Rx_OVR;
904 if (iflag & INPCK) 924 if (iflag & INPCK)
@@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
952 972
953static const char *sunzilog_type(struct uart_port *port) 973static const char *sunzilog_type(struct uart_port *port)
954{ 974{
955 return "zs"; 975 struct uart_sunzilog_port *up = UART_ZILOG(port);
976
977 return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
956} 978}
957 979
958/* We do not request/release mappings of the registers here, this 980/* We do not request/release mappings of the registers here, this
@@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
1170 1192
1171 spin_lock_irqsave(&up->port.lock, flags); 1193 spin_lock_irqsave(&up->port.lock, flags);
1172 1194
1173 up->curregs[R15] = BRKIE; 1195 up->curregs[R15] |= BRKIE;
1174 sunzilog_convert_to_zs(up, con->cflag, 0, brg); 1196 sunzilog_convert_to_zs(up, con->cflag, 0, brg);
1175 1197
1176 sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); 1198 sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
1229 baud = 4800; 1251 baud = 4800;
1230 } 1252 }
1231 1253
1232 up->curregs[R15] = BRKIE; 1254 up->curregs[R15] |= BRKIE;
1233 brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); 1255 brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
1234 sunzilog_convert_to_zs(up, up->cflag, 0, brg); 1256 sunzilog_convert_to_zs(up, up->cflag, 0, brg);
1235 sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); 1257 sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
1283 1305
1284 if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | 1306 if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
1285 SUNZILOG_FLAG_CONS_MOUSE)) { 1307 SUNZILOG_FLAG_CONS_MOUSE)) {
1308 up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
1309 up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
1310 up->curregs[R3] = RxENAB | Rx8;
1311 up->curregs[R5] = TxENAB | Tx8;
1312 up->curregs[R6] = 0x00; /* SDLC Address */
1313 up->curregs[R7] = 0x7E; /* SDLC Flag */
1314 up->curregs[R9] = NV;
1315 up->curregs[R7p] = 0x00;
1286 sunzilog_init_kbdms(up, up->port.line); 1316 sunzilog_init_kbdms(up, up->port.line);
1287 up->curregs[R9] |= (NV | MIE); 1317 /* Only enable interrupts if an ISR handler available */
1318 if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
1319 up->curregs[R9] |= MIE;
1288 write_zsreg(channel, R9, up->curregs[R9]); 1320 write_zsreg(channel, R9, up->curregs[R9]);
1289 } else { 1321 } else {
1290 /* Normal serial TTY. */ 1322 /* Normal serial TTY. */
@@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
1293 up->curregs[R4] = PAR_EVEN | X16CLK | SB1; 1325 up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
1294 up->curregs[R3] = RxENAB | Rx8; 1326 up->curregs[R3] = RxENAB | Rx8;
1295 up->curregs[R5] = TxENAB | Tx8; 1327 up->curregs[R5] = TxENAB | Tx8;
1296 up->curregs[R9] = NV | MIE; 1328 up->curregs[R6] = 0x00; /* SDLC Address */
1329 up->curregs[R7] = 0x7E; /* SDLC Flag */
1330 up->curregs[R9] = NV;
1297 up->curregs[R10] = NRZ; 1331 up->curregs[R10] = NRZ;
1298 up->curregs[R11] = TCBR | RCBR; 1332 up->curregs[R11] = TCBR | RCBR;
1299 baud = 9600; 1333 baud = 9600;
@@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
1301 up->curregs[R12] = (brg & 0xff); 1335 up->curregs[R12] = (brg & 0xff);
1302 up->curregs[R13] = (brg >> 8) & 0xff; 1336 up->curregs[R13] = (brg >> 8) & 0xff;
1303 up->curregs[R14] = BRSRC | BRENAB; 1337 up->curregs[R14] = BRSRC | BRENAB;
1304 __load_zsregs(channel, up->curregs); 1338 up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
1339 up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
1340 if (__load_zsregs(channel, up->curregs)) {
1341 up->flags |= SUNZILOG_FLAG_ESCC;
1342 }
1343 /* Only enable interrupts if an ISR handler available */
1344 if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
1345 up->curregs[R9] |= MIE;
1305 write_zsreg(channel, R9, up->curregs[R9]); 1346 write_zsreg(channel, R9, up->curregs[R9]);
1306 } 1347 }
1307 1348
@@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
1390 return err; 1431 return err;
1391 } 1432 }
1392 } else { 1433 } else {
1393 printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) " 1434 printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
1394 "is a zs\n", 1435 "is a %s\n",
1395 op->dev.bus_id, up[0].port.mapbase, op->irqs[0]); 1436 op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
1396 printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) " 1437 sunzilog_type (&up[0].port));
1397 "is a zs\n", 1438 printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
1398 op->dev.bus_id, up[1].port.mapbase, op->irqs[0]); 1439 "is a %s\n",
1440 op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
1441 sunzilog_type (&up[1].port));
1399 } 1442 }
1400 1443
1401 dev_set_drvdata(&op->dev, &up[0]); 1444 dev_set_drvdata(&op->dev, &up[0]);
@@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void)
1487 goto out_unregister_uart; 1530 goto out_unregister_uart;
1488 1531
1489 if (zilog_irq != -1) { 1532 if (zilog_irq != -1) {
1533 struct uart_sunzilog_port *up = sunzilog_irq_chain;
1490 err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, 1534 err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
1491 "zs", sunzilog_irq_chain); 1535 "zs", sunzilog_irq_chain);
1492 if (err) 1536 if (err)
1493 goto out_unregister_driver; 1537 goto out_unregister_driver;
1538
1539 /* Enable Interrupts */
1540 while (up) {
1541 struct zilog_channel __iomem *channel;
1542
1543 /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
1544 channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
1545 up->flags |= SUNZILOG_FLAG_ISR_HANDLER;
1546 up->curregs[R9] |= MIE;
1547 write_zsreg(channel, R9, up->curregs[R9]);
1548 up = up->next;
1549 }
1494 } 1550 }
1495 1551
1496out: 1552out:
@@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void)
1515 of_unregister_driver(&zs_driver); 1571 of_unregister_driver(&zs_driver);
1516 1572
1517 if (zilog_irq != -1) { 1573 if (zilog_irq != -1) {
1574 struct uart_sunzilog_port *up = sunzilog_irq_chain;
1575
1576 /* Disable Interrupts */
1577 while (up) {
1578 struct zilog_channel __iomem *channel;
1579
1580 /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
1581 channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
1582 up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER;
1583 up->curregs[R9] &= ~MIE;
1584 write_zsreg(channel, R9, up->curregs[R9]);
1585 up = up->next;
1586 }
1587
1518 free_irq(zilog_irq, sunzilog_irq_chain); 1588 free_irq(zilog_irq, sunzilog_irq_chain);
1519 zilog_irq = -1; 1589 zilog_irq = -1;
1520 } 1590 }