From 599f030cc596cd41a0f966afd4cee2e2fc48ee86 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Tue, 29 Jan 2008 04:28:55 +1100 Subject: [POWERPC] mpc512x: Factor out 5200 dependencies from 52xx psc driver PSC devices are different between the mpc5200 and the mpc5121 this patch localizes the differences in preparation for adding mpc5121 support to the psc uart driver. Signed-off-by: John Rigby Signed-off-by: Grant Likely --- drivers/serial/mpc52xx_uart.c | 256 +++++++++++++++++++++++++++++++----------- 1 file changed, 192 insertions(+), 64 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 3c4d29e59b2c..7ab73fa4a80f 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -67,7 +67,6 @@ #include #include #include - #include #include @@ -111,8 +110,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; static void mpc52xx_uart_of_enumerate(void); #endif + #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) -#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) /* Forward declaration of the interruption handling routine */ @@ -137,6 +136,162 @@ static struct of_device_id mpc52xx_uart_of_match[] = { }; #endif +/* ======================================================================== */ +/* PSC fifo operations for isolating differences between 52xx and 512x */ +/* ======================================================================== */ + +struct psc_ops { + void (*fifo_init)(struct uart_port *port); + int (*raw_rx_rdy)(struct uart_port *port); + int (*raw_tx_rdy)(struct uart_port *port); + int (*rx_rdy)(struct uart_port *port); + int (*tx_rdy)(struct uart_port *port); + int (*tx_empty)(struct uart_port *port); + void (*stop_rx)(struct uart_port *port); + void (*start_tx)(struct uart_port *port); + void (*stop_tx)(struct uart_port *port); + void (*rx_clr_irq)(struct uart_port *port); + void (*tx_clr_irq)(struct uart_port *port); + void (*write_char)(struct uart_port *port, unsigned char c); + unsigned char (*read_char)(struct uart_port *port); + void (*cw_disable_ints)(struct uart_port *port); + void (*cw_restore_ints)(struct uart_port *port); + unsigned long (*getuartclk)(void *p); +}; + +#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) +static void mpc52xx_psc_fifo_init(struct uart_port *port) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); + + /* /32 prescaler */ + out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); + + out_8(&fifo->rfcntl, 0x00); + out_be16(&fifo->rfalarm, 0x1ff); + out_8(&fifo->tfcntl, 0x07); + out_be16(&fifo->tfalarm, 0x80); + + port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); +} + +static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_RXRDY; +} + +static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_TXRDY; +} + + +static int mpc52xx_psc_rx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_isr) + & port->read_status_mask + & MPC52xx_PSC_IMR_RXRDY; +} + +static int mpc52xx_psc_tx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_isr) + & port->read_status_mask + & MPC52xx_PSC_IMR_TXRDY; +} + +static int mpc52xx_psc_tx_empty(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_TXEMP; +} + +static void mpc52xx_psc_start_tx(struct uart_port *port) +{ + port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_stop_tx(struct uart_port *port) +{ + port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_stop_rx(struct uart_port *port) +{ + port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) +{ +} + +static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) +{ +} + +static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) +{ + out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); +} + +static unsigned char mpc52xx_psc_read_char(struct uart_port *port) +{ + return in_8(&PSC(port)->mpc52xx_psc_buffer_8); +} + +static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) +{ + out_be16(&PSC(port)->mpc52xx_psc_imr, 0); +} + +static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) +{ + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +/* Search for bus-frequency property in this node or a parent */ +static unsigned long mpc52xx_getuartclk(void *p) +{ +#if defined(CONFIG_PPC_MERGE) + /* + * 5200 UARTs have a / 32 prescaler + * but the generic serial code assumes 16 + * so return ipb freq / 2 + */ + return mpc52xx_find_ipb_freq(p) / 2; +#else + pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n"); + return NULL; +#endif +} + +static struct psc_ops mpc52xx_psc_ops = { + .fifo_init = mpc52xx_psc_fifo_init, + .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, + .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, + .rx_rdy = mpc52xx_psc_rx_rdy, + .tx_rdy = mpc52xx_psc_tx_rdy, + .tx_empty = mpc52xx_psc_tx_empty, + .stop_rx = mpc52xx_psc_stop_rx, + .start_tx = mpc52xx_psc_start_tx, + .stop_tx = mpc52xx_psc_stop_tx, + .rx_clr_irq = mpc52xx_psc_rx_clr_irq, + .tx_clr_irq = mpc52xx_psc_tx_clr_irq, + .write_char = mpc52xx_psc_write_char, + .read_char = mpc52xx_psc_read_char, + .cw_disable_ints = mpc52xx_psc_cw_disable_ints, + .cw_restore_ints = mpc52xx_psc_cw_restore_ints, + .getuartclk = mpc52xx_getuartclk, +}; + +static struct psc_ops *psc_ops = &mpc52xx_psc_ops; /* ======================================================================== */ /* UART operations */ @@ -145,8 +300,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { static unsigned int mpc52xx_uart_tx_empty(struct uart_port *port) { - int status = in_be16(&PSC(port)->mpc52xx_psc_status); - return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; + return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; } static void @@ -166,16 +320,14 @@ static void mpc52xx_uart_stop_tx(struct uart_port *port) { /* port->lock taken by caller */ - port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->stop_tx(port); } static void mpc52xx_uart_start_tx(struct uart_port *port) { /* port->lock taken by caller */ - port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->start_tx(port); } static void @@ -188,8 +340,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch) if (ch) { /* Make sure tx interrupts are on */ /* Truly necessary ??? They should be anyway */ - port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->start_tx(port); } spin_unlock_irqrestore(&port->lock, flags); @@ -199,8 +350,7 @@ static void mpc52xx_uart_stop_rx(struct uart_port *port) { /* port->lock taken by caller */ - port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->stop_rx(port); } static void @@ -227,7 +377,6 @@ static int mpc52xx_uart_startup(struct uart_port *port) { struct mpc52xx_psc __iomem *psc = PSC(port); - struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port); int ret; /* Request IRQ */ @@ -242,15 +391,7 @@ mpc52xx_uart_startup(struct uart_port *port) out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ - out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ - - out_8(&fifo->rfcntl, 0x00); - out_be16(&fifo->rfalarm, 0x1ff); - out_8(&fifo->tfcntl, 0x07); - out_be16(&fifo->tfalarm, 0x80); - - port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->fifo_init(port); out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); @@ -333,8 +474,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, * boot for the console, all stuff is not yet ready to receive at that * time and that just makes the kernel oops */ /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ - while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && - --j) + while (!mpc52xx_uart_tx_empty(port) && --j) udelay(1); if (!j) @@ -462,11 +602,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) unsigned short status; /* While we can read, do so ! */ - while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) & - MPC52xx_PSC_SR_RXRDY) { - + while (psc_ops->raw_rx_rdy(port)) { /* Get the char */ - ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8); + ch = psc_ops->read_char(port); /* Handle sysreq char */ #ifdef SUPPORT_SYSRQ @@ -481,6 +619,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) flag = TTY_NORMAL; port->icount.rx++; + status = in_be16(&PSC(port)->mpc52xx_psc_status); + if (status & (MPC52xx_PSC_SR_PE | MPC52xx_PSC_SR_FE | MPC52xx_PSC_SR_RB)) { @@ -510,7 +650,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) tty_flip_buffer_push(tty); - return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; + return psc_ops->raw_rx_rdy(port); } static inline int @@ -520,7 +660,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) /* Process out of band chars */ if (port->x_char) { - out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char); + psc_ops->write_char(port, port->x_char); port->icount.tx++; port->x_char = 0; return 1; @@ -533,8 +673,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) } /* Send chars */ - while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) { - out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]); + while (psc_ops->raw_tx_rdy(port)) { + psc_ops->write_char(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -560,7 +700,6 @@ mpc52xx_uart_int(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; - unsigned short status; spin_lock(&port->lock); @@ -569,18 +708,12 @@ mpc52xx_uart_int(int irq, void *dev_id) /* If we don't find anything to do, we stop */ keepgoing = 0; - /* Read status */ - status = in_be16(&PSC(port)->mpc52xx_psc_isr); - status &= port->read_status_mask; - - /* Do we need to receive chars ? */ - /* For this RX interrupts must be on and some chars waiting */ - if (status & MPC52xx_PSC_IMR_RXRDY) + psc_ops->rx_clr_irq(port); + if (psc_ops->rx_rdy(port)) keepgoing |= mpc52xx_uart_int_rx_chars(port); - /* Do we need to send chars ? */ - /* For this, TX must be ready and TX interrupt enabled */ - if (status & MPC52xx_PSC_IMR_TXRDY) + psc_ops->tx_clr_irq(port); + if (psc_ops->tx_rdy(port)) keepgoing |= mpc52xx_uart_int_tx_chars(port); /* Limit number of iteration */ @@ -647,36 +780,33 @@ static void mpc52xx_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = &mpc52xx_uart_ports[co->index]; - struct mpc52xx_psc __iomem *psc = PSC(port); unsigned int i, j; /* Disable interrupts */ - out_be16(&psc->mpc52xx_psc_imr, 0); + psc_ops->cw_disable_ints(port); /* Wait the TX buffer to be empty */ j = 5000000; /* Maximum wait */ - while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && - --j) + while (!mpc52xx_uart_tx_empty(port) && --j) udelay(1); /* Write all the chars */ for (i = 0; i < count; i++, s++) { /* Line return handling */ if (*s == '\n') - out_8(&psc->mpc52xx_psc_buffer_8, '\r'); + psc_ops->write_char(port, '\r'); /* Send the char */ - out_8(&psc->mpc52xx_psc_buffer_8, *s); + psc_ops->write_char(port, *s); /* Wait the TX buffer to be empty */ j = 20000; /* Maximum wait */ - while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXEMP) && --j) + while (!mpc52xx_uart_tx_empty(port) && --j) udelay(1); } /* Restore interrupt state */ - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->cw_restore_ints(port); } #if !defined(CONFIG_PPC_MERGE) @@ -721,7 +851,7 @@ mpc52xx_console_setup(struct console *co, char *options) { struct uart_port *port = &mpc52xx_uart_ports[co->index]; struct device_node *np = mpc52xx_uart_nodes[co->index]; - unsigned int ipb_freq; + unsigned int uartclk; struct resource res; int ret; @@ -753,17 +883,16 @@ mpc52xx_console_setup(struct console *co, char *options) return ret; } - /* Search for bus-frequency property in this node or a parent */ - ipb_freq = mpc52xx_find_ipb_freq(np); - if (ipb_freq == 0) { - pr_debug("Could not find IPB bus frequency!\n"); + uartclk = psc_ops->getuartclk(np); + if (uartclk == 0) { + pr_debug("Could not find uart clock frequency!\n"); return -EINVAL; } /* Basic port init. Needed since we use some uart_??? func before * real init for early access */ spin_lock_init(&port->lock); - port->uartclk = ipb_freq / 2; + port->uartclk = uartclk; port->ops = &mpc52xx_uart_ops; port->mapbase = res.start; port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); @@ -949,7 +1078,7 @@ static int __devinit mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) { int idx = -1; - unsigned int ipb_freq; + unsigned int uartclk; struct uart_port *port = NULL; struct resource res; int ret; @@ -965,10 +1094,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) pr_debug("Found %s assigned to ttyPSC%x\n", mpc52xx_uart_nodes[idx]->full_name, idx); - /* Search for bus-frequency property in this node or a parent */ - ipb_freq = mpc52xx_find_ipb_freq(op->node); - if (ipb_freq == 0) { - dev_dbg(&op->dev, "Could not find IPB bus frequency!\n"); + uartclk = psc_ops->getuartclk(op->node); + if (uartclk == 0) { + dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); return -EINVAL; } @@ -976,7 +1104,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) port = &mpc52xx_uart_ports[idx]; spin_lock_init(&port->lock); - port->uartclk = ipb_freq / 2; + port->uartclk = uartclk; port->fifosize = 512; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | -- cgit v1.2.3 From 25ae3a0739c69425a911925b43213895a9802b98 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Tue, 29 Jan 2008 04:28:56 +1100 Subject: [POWERPC] mpc512x: Add MPC512x PSC support to MPC52xx psc driver Add 512x support using the psc_ops framework established with the previous patch. All 512x PSCs share the same interrupt so add IRQF_SHARED to irq flags. Signed-off-by: John Rigby Signed-off-by: Grant Likely --- drivers/serial/Kconfig | 12 +-- drivers/serial/mpc52xx_uart.c | 177 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 177 insertions(+), 12 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index d962b74e3114..d9d7673b712b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1114,17 +1114,17 @@ config SERIAL_SGI_L1_CONSOLE say Y. Otherwise, say N. config SERIAL_MPC52xx - tristate "Freescale MPC52xx family PSC serial support" - depends on PPC_MPC52xx + tristate "Freescale MPC52xx/MPC512x family PSC serial support" + depends on PPC_MPC52xx || PPC_MPC512x select SERIAL_CORE help - This drivers support the MPC52xx PSC serial ports. If you would - like to use them, you must answer Y or M to this option. Not that + This driver supports MPC52xx and MPC512x PSC serial ports. If you would + like to use them, you must answer Y or M to this option. Note that for use as console, it must be included in kernel and not as a module. config SERIAL_MPC52xx_CONSOLE - bool "Console on a Freescale MPC52xx family PSC serial port" + bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port" depends on SERIAL_MPC52xx=y select SERIAL_CORE_CONSOLE help @@ -1132,7 +1132,7 @@ config SERIAL_MPC52xx_CONSOLE of the Freescale MPC52xx family as a console. config SERIAL_MPC52xx_CONSOLE_BAUD - int "Freescale MPC52xx family PSC serial port baud" + int "Freescale MPC52xx/MPC512x family PSC serial port baud" depends on SERIAL_MPC52xx_CONSOLE=y default "9600" help diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 7ab73fa4a80f..821facd10bbc 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -16,6 +16,9 @@ * Some of the code has been inspired/copied from the 2.4 code written * by Dale Farnsworth . * + * Copyright (C) 2008 Freescale Semiconductor Inc. + * John Rigby + * Added support for MPC5121 * Copyright (C) 2006 Secret Lab Technologies Ltd. * Grant Likely * Copyright (C) 2004-2006 Sylvain Munaut @@ -78,6 +81,7 @@ #endif #include +#include #include #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -129,13 +133,29 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); #if defined(CONFIG_PPC_MERGE) static struct of_device_id mpc52xx_uart_of_match[] = { - { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", }, - { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */ - { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */ +#ifdef CONFIG_PPC_MPC52xx + { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, + /* binding used by old lite5200 device trees: */ + { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, + /* binding used by efika: */ + { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, +#endif +#ifdef CONFIG_PPC_MPC512x + { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, + {}, +#endif +}; +#if defined(CONFIG_PPC_MERGE) +static const struct of_device_id mpc52xx_uart_of_match[] = { + {.type = "serial", + .compatible = "mpc5200-psc-uart", +#endif {}, }; #endif +#endif + /* ======================================================================== */ /* PSC fifo operations for isolating differences between 52xx and 512x */ /* ======================================================================== */ @@ -159,6 +179,7 @@ struct psc_ops { unsigned long (*getuartclk)(void *p); }; +#ifdef CONFIG_PPC_MPC52xx #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) static void mpc52xx_psc_fifo_init(struct uart_port *port) { @@ -291,7 +312,145 @@ static struct psc_ops mpc52xx_psc_ops = { .getuartclk = mpc52xx_getuartclk, }; -static struct psc_ops *psc_ops = &mpc52xx_psc_ops; +#endif /* CONFIG_MPC52xx */ + +#ifdef CONFIG_PPC_MPC512x +#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) +static void mpc512x_psc_fifo_init(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_512x(port)->txalarm, 1); + out_be32(&FIFO_512x(port)->tximr, 0); + + out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_512x(port)->rxalarm, 1); + out_be32(&FIFO_512x(port)->rximr, 0); + + out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); + out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); +} + +static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); +} + +static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); +} + +static int mpc512x_psc_rx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->rxsr) + & in_be32(&FIFO_512x(port)->rximr) + & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc512x_psc_tx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->txsr) + & in_be32(&FIFO_512x(port)->tximr) + & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc512x_psc_tx_empty(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->txsr) + & MPC512x_PSC_FIFO_EMPTY; +} + +static void mpc512x_psc_stop_rx(struct uart_port *port) +{ + unsigned long rx_fifo_imr; + + rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); + rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); +} + +static void mpc512x_psc_start_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); + tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); +} + +static void mpc512x_psc_stop_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); + tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); +} + +static void mpc512x_psc_rx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); +} + +static void mpc512x_psc_tx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); +} + +static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) +{ + out_8(&FIFO_512x(port)->txdata_8, c); +} + +static unsigned char mpc512x_psc_read_char(struct uart_port *port) +{ + return in_8(&FIFO_512x(port)->rxdata_8); +} + +static void mpc512x_psc_cw_disable_ints(struct uart_port *port) +{ + port->read_status_mask = + in_be32(&FIFO_512x(port)->tximr) << 16 | + in_be32(&FIFO_512x(port)->rximr); + out_be32(&FIFO_512x(port)->tximr, 0); + out_be32(&FIFO_512x(port)->rximr, 0); +} + +static void mpc512x_psc_cw_restore_ints(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->tximr, + (port->read_status_mask >> 16) & 0x7f); + out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); +} + +static unsigned long mpc512x_getuartclk(void *p) +{ + return mpc512x_find_ips_freq(p); +} + +static struct psc_ops mpc512x_psc_ops = { + .fifo_init = mpc512x_psc_fifo_init, + .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, + .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, + .rx_rdy = mpc512x_psc_rx_rdy, + .tx_rdy = mpc512x_psc_tx_rdy, + .tx_empty = mpc512x_psc_tx_empty, + .stop_rx = mpc512x_psc_stop_rx, + .start_tx = mpc512x_psc_start_tx, + .stop_tx = mpc512x_psc_stop_tx, + .rx_clr_irq = mpc512x_psc_rx_clr_irq, + .tx_clr_irq = mpc512x_psc_tx_clr_irq, + .write_char = mpc512x_psc_write_char, + .read_char = mpc512x_psc_read_char, + .cw_disable_ints = mpc512x_psc_cw_disable_ints, + .cw_restore_ints = mpc512x_psc_cw_restore_ints, + .getuartclk = mpc512x_getuartclk, +}; +#endif + +static struct psc_ops *psc_ops; /* ======================================================================== */ /* UART operations */ @@ -381,7 +540,8 @@ mpc52xx_uart_startup(struct uart_port *port) /* Request IRQ */ ret = request_irq(port->irq, mpc52xx_uart_int, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port); + IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED, + "mpc52xx_psc_uart", port); if (ret) return ret; @@ -1208,15 +1368,19 @@ mpc52xx_uart_of_enumerate(void) static int enum_done; struct device_node *np; const unsigned int *devno; + const struct of_device_id *match; int i; if (enum_done) return; for_each_node_by_type(np, "serial") { - if (!of_match_node(mpc52xx_uart_of_match, np)) + match = of_match_node(mpc52xx_uart_of_match, np); + if (!match) continue; + psc_ops = match->data; + /* Is a particular device number requested? */ devno = of_get_property(np, "port-number", NULL); mpc52xx_uart_of_assign(np, devno ? *devno : -1); @@ -1277,6 +1441,7 @@ mpc52xx_uart_init(void) return ret; } #else + psc_ops = &mpc52xx_psc_ops; ret = platform_driver_register(&mpc52xx_uart_platform_driver); if (ret) { printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", -- cgit v1.2.3