From: David Miller To: sammy@sammy.net Cc: linux-m68k@vger.kernel.org Subject: Re: [PATCH] Sun3/3x Serial driver support From: Sam Creasey Date: Tue, 3 Apr 2007 10:43:42 -0400 > Adds serial support for sun3/3x machines. This patch has basically > been around for years, but my own laziness has kept me from committing > upstream. > > Signed-off-by: Sam Creasey Same thing here, please build a proper openprom device tree in the sun3 port and then you'll need to make few, if any, changes to the sparc drivers. I've made these drivers as portable as possible, frankly, and if you cook up proper in-kernel device objects, you'll need to do no porting at all. --------------------------------------------------------------------------- From sammy@sammy.net Tue Apr 3 16:47:31 2007 Date: Tue, 3 Apr 2007 10:43:42 -0400 From: Sam Creasey To: linux-m68k@vger.kernel.org, David S. Miller Subject: [PATCH] Sun3/3x Serial driver support Adds serial support for sun3/3x machines. This patch has basically been around for years, but my own laziness has kept me from committing upstream. Signed-off-by: Sam Creasey --- drivers/serial/Kconfig | 4 drivers/serial/suncore.c | 4 drivers/serial/sunzilog.c | 200 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 195 insertions(+), 13 deletions(-) --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -543,14 +543,14 @@ config SERIAL_UARTLITE_CONSOLE config SERIAL_SUNCORE bool - depends on SPARC + depends on SPARC || SUN3 || SUN3X select SERIAL_CORE select SERIAL_CORE_CONSOLE default y config SERIAL_SUNZILOG tristate "Sun Zilog8530 serial support" - depends on SPARC + depends on SPARC || SUN3 || SUN3X help This driver supports the Zilog8530 serial ports found on many Sparc systems. Say Y or M if you want to be able to these serial ports. --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -29,6 +29,7 @@ EXPORT_SYMBOL(sunserial_current_minor); void sunserial_console_termios(struct console *con) { +#if !defined(CONFIG_SUN3) && !defined (CONFIG_SUN3X) char mode[16], buf[16], *s; char *mode_prop = "ttyX-mode"; char *cd_prop = "ttyX-ignore-cd"; @@ -162,6 +163,9 @@ no_options: } con->cflag = cflag; +#else /* CONFIG_SUN3(X) */ + con->cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; +#endif } EXPORT_SYMBOL(sunserial_console_termios); --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -35,13 +35,30 @@ #include #include -#include -#include #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif +#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) +#include +#include +#define readb sbus_readb +#define writeb sbus_writeb + +#else +#include +#include +#endif + +#ifdef CONFIG_SUN3 +#include +#endif + +#ifdef CONFIG_SUN3X +#include +#endif + #include #include "suncore.h" @@ -415,7 +432,15 @@ static void sunzilog_status_handle(struc if (!(status & BRK_ABRT)) break; } - sun_do_break(); +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + sun_do_break(); +#else +#ifdef CONFIG_SUN3 + prom_reboot(""); +#else + sun3x_reboot(); +#endif +#endif return; } } @@ -523,6 +548,13 @@ static irqreturn_t sunzilog_interrupt(in struct tty_struct *tty; unsigned char r3; +#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) + if(!channel) { + up = up->next; + continue; + } +#endif + spin_lock(&up->port.lock); r3 = read_zsreg(channel, R3); @@ -1193,6 +1225,7 @@ static struct console sunzilog_console_o static inline struct console *SUNZILOG_CONSOLE(void) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) int i; if (con_is_present()) @@ -1209,6 +1242,10 @@ static inline struct console *SUNZILOG_C sunzilog_console_ops.index = i; sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; +#else + sunzilog_console_ops.index = 0; + sunzilog_port_table[0].flags |= SUNZILOG_FLAG_IS_CONS; +#endif return &sunzilog_console_ops; } @@ -1266,6 +1303,8 @@ static void __init sunzilog_register_ser } #endif +static int zilog_irq = -1; + static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) { struct zilog_channel __iomem *channel; @@ -1276,9 +1315,16 @@ static void __devinit sunzilog_init_hw(s spin_lock_irqsave(&up->port.lock, flags); if (ZS_IS_CHANNEL_A(up)) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); +#endif (void) read_zsreg(channel, R0); +#ifdef CONFIG_SUN3 + /* should sun3x run here? */ + /* program the int vector */ + write_zsreg(channel, R2, 0x18+zilog_irq); +#endif } if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | @@ -1293,7 +1339,11 @@ static void __devinit sunzilog_init_hw(s up->curregs[R4] = PAR_EVEN | X16CLK | SB1; up->curregs[R3] = RxENAB | Rx8; up->curregs[R5] = TxENAB | Tx8; +#ifdef CONFIG_SUN3 + up->curregs[R9] = MIE; +#else up->curregs[R9] = NV | MIE; +#endif up->curregs[R10] = NRZ; up->curregs[R11] = TCBR | RCBR; baud = 9600; @@ -1314,9 +1364,75 @@ static void __devinit sunzilog_init_hw(s #endif } -static int zilog_irq = -1; +#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) +static struct zilog_layout * __init get_zs(int chip) +{ + unsigned int vaddr = 0; + if (chip < 0 || chip >= NUM_SUNZILOG) { + prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip); + prom_halt(); + } + +#ifndef CONFIG_SUN3X + /* sun3 OBIO version */ + /* Grrr, these have to be hardcoded aieee */ + switch(chip) { + case 0: + for(vaddr = 0xfe00000; vaddr < (0xfe00000 + + SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) { + unsigned long iopte; + + iopte = sun3_get_pte(vaddr); + if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ + continue; + + if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == + 0x20000) { + break; + } + } + break; + case 1: + for(vaddr = 0xfe00000; vaddr < (0xfe00000 + + SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) { + + unsigned long iopte; + + iopte = sun3_get_pte(vaddr); + if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ + continue; + + if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == + 0) { + break; + } + } + break; + }; +#else + /* sun3x is a wee bit cleaner. :) */ + switch(chip) { + case 0: + vaddr = SUN3X_ZS2; + break; + + case 1: + vaddr = SUN3X_ZS1; + break; + } +#endif + + if(!vaddr) + panic("get_zs whee no serial chip mappable"); + + return (struct zilog_layout *)(unsigned long) vaddr; +} + +static int __devinit zs_probe(void) +#else static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match) +#endif { static int inst; struct uart_sunzilog_port *up; @@ -1325,51 +1441,70 @@ static int __devinit zs_probe(struct of_ int err; keyboard_mouse = 0; +#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) + sunzilog_chip_regs[inst] = get_zs(inst); + if(inst) + keyboard_mouse = 1; +#else if (of_find_property(op->node, "keyboard", NULL)) keyboard_mouse = 1; sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, sizeof(struct zilog_layout), "zs"); +#endif /* CONFIG_SUN3 || CONFIG_SUN3X */ + if (!sunzilog_chip_regs[inst]) return -ENOMEM; rp = sunzilog_chip_regs[inst]; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) if (zilog_irq == -1) zilog_irq = op->irqs[0]; +#endif up = &sunzilog_port_table[inst * 2]; /* Channel A */ - up[0].port.mapbase = op->resource[0].start + 0x00; up[0].port.membase = (void __iomem *) &rp->channelA; - up[0].port.iotype = UPIO_MEM; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + up[0].port.mapbase = op->resource[0].start + 0x00; up[0].port.irq = op->irqs[0]; + up[0].port.dev = &op->dev; +#else + up[0].port.mapbase = (unsigned long)up[0].port.membase; + up[0].port.irq = zilog_irq; +#endif + up[0].port.iotype = UPIO_MEM; up[0].port.uartclk = ZS_CLOCK; up[0].port.fifosize = 1; up[0].port.ops = &sunzilog_pops; up[0].port.type = PORT_SUNZILOG; up[0].port.flags = 0; up[0].port.line = (inst * 2) + 0; - up[0].port.dev = &op->dev; up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; if (keyboard_mouse) up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; sunzilog_init_hw(&up[0]); /* Channel B */ - up[1].port.mapbase = op->resource[0].start + 0x04; up[1].port.membase = (void __iomem *) &rp->channelB; - up[1].port.iotype = UPIO_MEM; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + up[1].port.mapbase = op->resource[0].start + 0x04; up[1].port.irq = op->irqs[0]; + up[1].port.dev = &op->dev; +#else + up[1].port.mapbase = (unsigned long)up[1].port.membase; + up[1].port.irq = zilog_irq; +#endif + up[1].port.iotype = UPIO_MEM; up[1].port.uartclk = ZS_CLOCK; up[1].port.fifosize = 1; up[1].port.ops = &sunzilog_pops; up[1].port.type = PORT_SUNZILOG; up[1].port.flags = 0; up[1].port.line = (inst * 2) + 1; - up[1].port.dev = &op->dev; up[1].flags |= 0; if (keyboard_mouse) up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; @@ -1378,33 +1513,50 @@ static int __devinit zs_probe(struct of_ if (!keyboard_mouse) { err = uart_add_one_port(&sunzilog_reg, &up[0].port); if (err) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) of_iounmap(&op->resource[0], rp, sizeof(struct zilog_layout)); +#endif return err; } err = uart_add_one_port(&sunzilog_reg, &up[1].port); if (err) { uart_remove_one_port(&sunzilog_reg, &up[0].port); +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) of_iounmap(&op->resource[0], rp, sizeof(struct zilog_layout)); +#endif return err; } } else { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) " "is a zs\n", op->dev.bus_id, up[0].port.mapbase, op->irqs[0]); printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) " "is a zs\n", op->dev.bus_id, up[1].port.mapbase, op->irqs[0]); +#else + printk(KERN_INFO "zs%d: Keyboard at MMIO %lx (irq = %d) " + "is a zs\n", + inst, up[0].port.mapbase, zilog_irq); + printk(KERN_INFO "zs%d: Mouse at MMIO %lx (irq = %d) " + "is a zs\n", + inst, up[1].port.mapbase, zilog_irq); +#endif } + +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) dev_set_drvdata(&op->dev, &up[0]); +#endif inst++; return 0; } +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) static void __devexit zs_remove_one(struct uart_sunzilog_port *up) { if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { @@ -1445,13 +1597,17 @@ static struct of_platform_driver zs_driv .probe = zs_probe, .remove = __devexit_p(zs_remove), }; +#endif /* !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) */ static int __init sunzilog_init(void) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) struct device_node *dp; +#endif int err, uart_count; int num_keybms; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) NUM_SUNZILOG = 0; num_keybms = 0; for_each_node_by_name(dp, "zs") { @@ -1459,6 +1615,10 @@ static int __init sunzilog_init(void) if (of_find_property(dp, "keyboard", NULL)) num_keybms++; } +#else + NUM_SUNZILOG = 2; + num_keybms = 1; +#endif uart_count = 0; if (NUM_SUNZILOG) { @@ -1481,6 +1641,7 @@ static int __init sunzilog_init(void) sunserial_current_minor += uart_count; } +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) err = of_register_driver(&zs_driver, &of_bus_type); if (err) @@ -1492,12 +1653,28 @@ static int __init sunzilog_init(void) if (err) goto out_unregister_driver; } +#else + + zilog_irq = 6; + err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_DISABLED, + "zs", sunzilog_irq_chain); + if (err) + goto out_unregister_uart; + + /* probe for two zs instances on sun3/3x */ + zs_probe(); + zs_probe(); + + +#endif out: return err; +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) out_unregister_driver: of_unregister_driver(&zs_driver); +#endif out_unregister_uart: if (NUM_SUNZILOG) { @@ -1512,8 +1689,9 @@ out_free_tables: static void __exit sunzilog_exit(void) { +#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) of_unregister_driver(&zs_driver); - +#endif if (zilog_irq != -1) { free_irq(zilog_irq, sunzilog_irq_chain); zilog_irq = -1;