Commit ec9cbe09 authored by Finn Thain's avatar Finn Thain Committed by Geert Uytterhoeven

pmac-zilog: add platform driver

Add platform driver support to the pmac-zilog driver, for m68k macs.
Place the powermac-specific code inside #ifdef CONFIG_PPC_PMAC.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
parent 1f7b5fff
...@@ -701,6 +701,11 @@ CONFIG_VT_HW_CONSOLE_BINDING=y ...@@ -701,6 +701,11 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
# #
# Non-8250 serial port support # Non-8250 serial port support
# #
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_PMACZILOG=y
CONFIG_SERIAL_PMACZILOG_TTYS=y
CONFIG_SERIAL_PMACZILOG_CONSOLE=y
CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTYS=y
......
...@@ -822,6 +822,11 @@ CONFIG_A2232=y ...@@ -822,6 +822,11 @@ CONFIG_A2232=y
# #
# Non-8250 serial port support # Non-8250 serial port support
# #
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_PMACZILOG=y
CONFIG_SERIAL_PMACZILOG_TTYS=y
CONFIG_SERIAL_PMACZILOG_CONSOLE=y
CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTYS=y
......
...@@ -1086,12 +1086,12 @@ config SERIAL_68360 ...@@ -1086,12 +1086,12 @@ config SERIAL_68360
default y default y
config SERIAL_PMACZILOG config SERIAL_PMACZILOG
tristate "PowerMac z85c30 ESCC support" tristate "Mac or PowerMac z85c30 ESCC support"
depends on PPC_OF && PPC_PMAC depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
select SERIAL_CORE select SERIAL_CORE
help help
This driver supports the Zilog z85C30 serial ports found on This driver supports the Zilog z85C30 serial ports found on
PowerMac machines. (Power)Mac machines.
Say Y or M if you want to be able to these serial ports. Say Y or M if you want to be able to these serial ports.
config SERIAL_PMACZILOG_TTYS config SERIAL_PMACZILOG_TTYS
...@@ -1116,16 +1116,16 @@ config SERIAL_PMACZILOG_TTYS ...@@ -1116,16 +1116,16 @@ config SERIAL_PMACZILOG_TTYS
unable to use the 8250 module for PCMCIA or other 16C550-style unable to use the 8250 module for PCMCIA or other 16C550-style
UARTs. UARTs.
Say N unless you need the z85c30 ports on your powermac Say N unless you need the z85c30 ports on your (Power)Mac
to appear as /dev/ttySn. to appear as /dev/ttySn.
config SERIAL_PMACZILOG_CONSOLE config SERIAL_PMACZILOG_CONSOLE
bool "Console on PowerMac z85c30 serial port" bool "Console on Mac or PowerMac z85c30 serial port"
depends on SERIAL_PMACZILOG=y depends on SERIAL_PMACZILOG=y
select SERIAL_CORE_CONSOLE select SERIAL_CORE_CONSOLE
help help
If you would like to be able to use the z85c30 serial port If you would like to be able to use the z85c30 serial port
on your PowerMac as the console, you can do so by answering on your (Power)Mac as the console, you can do so by answering
Y to this option. Y to this option.
config SERIAL_LH7A40X config SERIAL_LH7A40X
......
...@@ -63,11 +63,17 @@ ...@@ -63,11 +63,17 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/pmac_feature.h> #include <asm/pmac_feature.h>
#include <asm/dbdma.h> #include <asm/dbdma.h>
#include <asm/macio.h> #include <asm/macio.h>
#else
#include <linux/platform_device.h>
#define of_machine_is_compatible(x) (0)
#endif
#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ #define SUPPORT_SYSRQ
...@@ -83,11 +89,9 @@ ...@@ -83,11 +89,9 @@
static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the PowerMac serial ports."); MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
#ifdef CONFIG_SERIAL_PMACZILOG_TTYS #ifdef CONFIG_SERIAL_PMACZILOG_TTYS
#define PMACZILOG_MAJOR TTY_MAJOR #define PMACZILOG_MAJOR TTY_MAJOR
#define PMACZILOG_MINOR 64 #define PMACZILOG_MINOR 64
...@@ -341,7 +345,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) ...@@ -341,7 +345,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
write_zsreg(uap, R1, uap->curregs[R1]); write_zsreg(uap, R1, uap->curregs[R1]);
zssync(uap); zssync(uap);
dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n"); pmz_error("pmz: rx irq flood !\n");
return tty; return tty;
} }
...@@ -757,6 +761,8 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) ...@@ -757,6 +761,8 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
#ifdef CONFIG_PPC_PMAC
/* /*
* Turn power on or off to the SCC and associated stuff * Turn power on or off to the SCC and associated stuff
* (port drivers, modem, IR port, etc.) * (port drivers, modem, IR port, etc.)
...@@ -792,6 +798,15 @@ static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) ...@@ -792,6 +798,15 @@ static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
return delay; return delay;
} }
#else
static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
{
return 0;
}
#endif /* !CONFIG_PPC_PMAC */
/* /*
* FixZeroBug....Works around a bug in the SCC receving channel. * FixZeroBug....Works around a bug in the SCC receving channel.
* Inspired from Darwin code, 15 Sept. 2000 -DanM * Inspired from Darwin code, 15 Sept. 2000 -DanM
...@@ -954,9 +969,9 @@ static int pmz_startup(struct uart_port *port) ...@@ -954,9 +969,9 @@ static int pmz_startup(struct uart_port *port)
} }
pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) { if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
dev_err(&uap->dev->ofdev.dev, "SCC", uap)) {
"Unable to register zs interrupt handler.\n"); pmz_error("Unable to register zs interrupt handler.\n");
pmz_set_scc_power(uap, 0); pmz_set_scc_power(uap, 0);
mutex_unlock(&pmz_irq_mutex); mutex_unlock(&pmz_irq_mutex);
return -ENXIO; return -ENXIO;
...@@ -1196,7 +1211,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) ...@@ -1196,7 +1211,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0 while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
|| (read_zsreg(uap, R1) & ALL_SNT) == 0) { || (read_zsreg(uap, R1) & ALL_SNT) == 0) {
if (--t <= 0) { if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n"); pmz_error("transmitter didn't drain\n");
return; return;
} }
udelay(10); udelay(10);
...@@ -1212,7 +1227,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) ...@@ -1212,7 +1227,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
read_zsdata(uap); read_zsdata(uap);
mdelay(10); mdelay(10);
if (--t <= 0) { if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n"); pmz_error("receiver didn't drain\n");
return; return;
} }
} }
...@@ -1233,8 +1248,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) ...@@ -1233,8 +1248,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
t = 5000; t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) { if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, pmz_error("irda_setup timed out on get_version byte\n");
"irda_setup timed out on get_version byte\n");
goto out; goto out;
} }
udelay(10); udelay(10);
...@@ -1242,8 +1256,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) ...@@ -1242,8 +1256,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
version = read_zsdata(uap); version = read_zsdata(uap);
if (version < 4) { if (version < 4) {
dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n", pmz_info("IrDA: dongle version %d not supported\n", version);
version);
goto out; goto out;
} }
...@@ -1252,18 +1265,16 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) ...@@ -1252,18 +1265,16 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
t = 5000; t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) { if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, pmz_error("irda_setup timed out on speed mode byte\n");
"irda_setup timed out on speed mode byte\n");
goto out; goto out;
} }
udelay(10); udelay(10);
} }
t = read_zsdata(uap); t = read_zsdata(uap);
if (t != cmdbyte) if (t != cmdbyte)
dev_err(&uap->dev->ofdev.dev, pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
"irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n", pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
*baud, version); *baud, version);
(void)read_zsdata(uap); (void)read_zsdata(uap);
...@@ -1413,7 +1424,7 @@ static void pmz_poll_put_char(struct uart_port *port, unsigned char c) ...@@ -1413,7 +1424,7 @@ static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
write_zsdata(uap, c); write_zsdata(uap, c);
} }
#endif #endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops pmz_pops = { static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty, .tx_empty = pmz_tx_empty,
...@@ -1438,6 +1449,8 @@ static struct uart_ops pmz_pops = { ...@@ -1438,6 +1449,8 @@ static struct uart_ops pmz_pops = {
#endif #endif
}; };
#ifdef CONFIG_PPC_PMAC
/* /*
* Setup one port structure after probing, HW is down at this point, * Setup one port structure after probing, HW is down at this point,
* Unlike sunzilog, we don't need to pre-init the spinlock as we don't * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
...@@ -1834,6 +1847,88 @@ static int __init pmz_probe(void) ...@@ -1834,6 +1847,88 @@ static int __init pmz_probe(void)
return 0; return 0;
} }
#else
extern struct platform_device scc_a_pdev, scc_b_pdev;
static int __init pmz_init_port(struct uart_pmac_port *uap)
{
struct resource *r_ports;
int irq;
r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
irq = platform_get_irq(uap->node, 0);
if (!r_ports || !irq)
return -ENODEV;
uap->port.mapbase = r_ports->start;
uap->port.membase = (unsigned char __iomem *) r_ports->start;
uap->port.iotype = UPIO_MEM;
uap->port.irq = irq;
uap->port.uartclk = ZS_CLOCK;
uap->port.fifosize = 1;
uap->port.ops = &pmz_pops;
uap->port.type = PORT_PMAC_ZILOG;
uap->port.flags = 0;
uap->control_reg = uap->port.membase;
uap->data_reg = uap->control_reg + 4;
uap->port_type = 0;
pmz_convert_to_zs(uap, CS8, 0, 9600);
return 0;
}
static int __init pmz_probe(void)
{
int err;
pmz_ports_count = 0;
pmz_ports[0].mate = &pmz_ports[1];
pmz_ports[0].port.line = 0;
pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A;
pmz_ports[0].node = &scc_a_pdev;
err = pmz_init_port(&pmz_ports[0]);
if (err)
return err;
pmz_ports_count++;
pmz_ports[1].mate = &pmz_ports[0];
pmz_ports[1].port.line = 1;
pmz_ports[1].flags = 0;
pmz_ports[1].node = &scc_b_pdev;
err = pmz_init_port(&pmz_ports[1]);
if (err)
return err;
pmz_ports_count++;
return 0;
}
static void pmz_dispose_port(struct uart_pmac_port *uap)
{
memset(uap, 0, sizeof(struct uart_pmac_port));
}
static int __init pmz_attach(struct platform_device *pdev)
{
int i;
for (i = 0; i < pmz_ports_count; i++)
if (pmz_ports[i].node == pdev)
return 0;
return -ENODEV;
}
static int __exit pmz_detach(struct platform_device *pdev)
{
return 0;
}
#endif /* !CONFIG_PPC_PMAC */
#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
static void pmz_console_write(struct console *con, const char *s, unsigned int count); static void pmz_console_write(struct console *con, const char *s, unsigned int count);
...@@ -1894,6 +1989,8 @@ static int __init pmz_register(void) ...@@ -1894,6 +1989,8 @@ static int __init pmz_register(void)
return rc; return rc;
} }
#ifdef CONFIG_PPC_PMAC
static struct of_device_id pmz_match[] = static struct of_device_id pmz_match[] =
{ {
{ {
...@@ -1915,6 +2012,18 @@ static struct macio_driver pmz_driver = { ...@@ -1915,6 +2012,18 @@ static struct macio_driver pmz_driver = {
.resume = pmz_resume, .resume = pmz_resume,
}; };
#else
static struct platform_driver pmz_driver = {
.remove = __exit_p(pmz_detach),
.driver = {
.name = "scc",
.owner = THIS_MODULE,
},
};
#endif /* !CONFIG_PPC_PMAC */
static int __init init_pmz(void) static int __init init_pmz(void)
{ {
int rc, i; int rc, i;
...@@ -1953,15 +2062,23 @@ static int __init init_pmz(void) ...@@ -1953,15 +2062,23 @@ static int __init init_pmz(void)
/* /*
* Then we register the macio driver itself * Then we register the macio driver itself
*/ */
#ifdef CONFIG_PPC_PMAC
return macio_register_driver(&pmz_driver); return macio_register_driver(&pmz_driver);
#else
return platform_driver_probe(&pmz_driver, pmz_attach);
#endif
} }
static void __exit exit_pmz(void) static void __exit exit_pmz(void)
{ {
int i; int i;
#ifdef CONFIG_PPC_PMAC
/* Get rid of macio-driver (detach from macio) */ /* Get rid of macio-driver (detach from macio) */
macio_unregister_driver(&pmz_driver); macio_unregister_driver(&pmz_driver);
#else
platform_driver_unregister(&pmz_driver);
#endif
for (i = 0; i < pmz_ports_count; i++) { for (i = 0; i < pmz_ports_count; i++) {
struct uart_pmac_port *uport = &pmz_ports[i]; struct uart_pmac_port *uport = &pmz_ports[i];
......
#ifndef __PMAC_ZILOG_H__ #ifndef __PMAC_ZILOG_H__
#define __PMAC_ZILOG_H__ #define __PMAC_ZILOG_H__
#ifdef CONFIG_PPC_PMAC
#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg) #define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
#define pmz_info(fmt, arg...) dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
#else
#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
#define pmz_info(fmt, arg...) dev_info(&uap->node->dev, fmt, ## arg)
#endif
/* /*
* At most 2 ESCCs with 2 ports each * At most 2 ESCCs with 2 ports each
...@@ -17,6 +25,7 @@ struct uart_pmac_port { ...@@ -17,6 +25,7 @@ struct uart_pmac_port {
struct uart_port port; struct uart_port port;
struct uart_pmac_port *mate; struct uart_pmac_port *mate;
#ifdef CONFIG_PPC_PMAC
/* macio_dev for the escc holding this port (maybe be null on /* macio_dev for the escc holding this port (maybe be null on
* early inited port) * early inited port)
*/ */
...@@ -25,6 +34,9 @@ struct uart_pmac_port { ...@@ -25,6 +34,9 @@ struct uart_pmac_port {
* of "escc" node (ie. ch-a or ch-b) * of "escc" node (ie. ch-a or ch-b)
*/ */
struct device_node *node; struct device_node *node;
#else
struct platform_device *node;
#endif
/* Port type as obtained from device tree (IRDA, modem, ...) */ /* Port type as obtained from device tree (IRDA, modem, ...) */
int port_type; int port_type;
...@@ -55,10 +67,12 @@ struct uart_pmac_port { ...@@ -55,10 +67,12 @@ struct uart_pmac_port {
volatile u8 __iomem *control_reg; volatile u8 __iomem *control_reg;
volatile u8 __iomem *data_reg; volatile u8 __iomem *data_reg;
#ifdef CONFIG_PPC_PMAC
unsigned int tx_dma_irq; unsigned int tx_dma_irq;
unsigned int rx_dma_irq; unsigned int rx_dma_irq;
volatile struct dbdma_regs __iomem *tx_dma_regs; volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs; volatile struct dbdma_regs __iomem *rx_dma_regs;
#endif
struct ktermios termios_cache; struct ktermios termios_cache;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment