[POWERPC] mpc512x: Add MPC512x PSC support to MPC52xx psc driver
authorJohn Rigby <jrigby@freescale.com>
Mon, 28 Jan 2008 17:28:56 +0000 (04:28 +1100)
committerGrant Likely <grant.likely@secretlab.ca>
Wed, 6 Feb 2008 21:05:40 +0000 (14:05 -0700)
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 <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
drivers/serial/Kconfig
drivers/serial/mpc52xx_uart.c
include/asm-powerpc/mpc52xx_psc.h

index d962b74..d9d7673 100644 (file)
@@ -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
index 7ab73fa..821facd 100644 (file)
@@ -16,6 +16,9 @@
  * Some of the code has been inspired/copied from the 2.4 code written
  * by Dale Farnsworth <dfarnsworth@mvista.com>.
  *
+ * Copyright (C) 2008 Freescale Semiconductor Inc.
+ *                    John Rigby <jrigby@gmail.com>
+ * Added support for MPC5121
  * Copyright (C) 2006 Secret Lab Technologies Ltd.
  *                    Grant Likely <grant.likely@secretlab.ca>
  * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
@@ -78,6 +81,7 @@
 #endif
 
 #include <asm/mpc52xx.h>
+#include <asm/mpc512x.h>
 #include <asm/mpc52xx_psc.h>
 
 #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",
index bea42b9..710c5d3 100644 (file)
@@ -190,5 +190,53 @@ struct mpc52xx_psc_fifo {
        u16             tflwfptr;       /* PSC + 0x9e */
 };
 
+#define MPC512x_PSC_FIFO_RESET_SLICE   0x80
+#define MPC512x_PSC_FIFO_ENABLE_SLICE  0x01
+#define MPC512x_PSC_FIFO_ENABLE_DMA    0x04
+
+#define MPC512x_PSC_FIFO_EMPTY         0x1
+#define MPC512x_PSC_FIFO_FULL          0x2
+#define MPC512x_PSC_FIFO_ALARM         0x4
+#define MPC512x_PSC_FIFO_URERR         0x8
+#define MPC512x_PSC_FIFO_ORERR         0x01
+#define MPC512x_PSC_FIFO_MEMERROR      0x02
+
+struct mpc512x_psc_fifo {
+       u32             reserved1[10];
+       u32             txcmd;          /* PSC + 0x80 */
+       u32             txalarm;        /* PSC + 0x84 */
+       u32             txsr;           /* PSC + 0x88 */
+       u32             txisr;          /* PSC + 0x8c */
+       u32             tximr;          /* PSC + 0x90 */
+       u32             txcnt;          /* PSC + 0x94 */
+       u32             txptr;          /* PSC + 0x98 */
+       u32             txsz;           /* PSC + 0x9c */
+       u32             reserved2[7];
+       union {
+               u8      txdata_8;
+               u16     txdata_16;
+               u32     txdata_32;
+       } txdata;                       /* PSC + 0xbc */
+#define txdata_8 txdata.txdata_8
+#define txdata_16 txdata.txdata_16
+#define txdata_32 txdata.txdata_32
+       u32             rxcmd;          /* PSC + 0xc0 */
+       u32             rxalarm;        /* PSC + 0xc4 */
+       u32             rxsr;           /* PSC + 0xc8 */
+       u32             rxisr;          /* PSC + 0xcc */
+       u32             rximr;          /* PSC + 0xd0 */
+       u32             rxcnt;          /* PSC + 0xd4 */
+       u32             rxptr;          /* PSC + 0xd8 */
+       u32             rxsz;           /* PSC + 0xdc */
+       u32             reserved3[7];
+       union {
+               u8      rxdata_8;
+               u16     rxdata_16;
+               u32     rxdata_32;
+       } rxdata;                       /* PSC + 0xfc */
+#define rxdata_8 rxdata.rxdata_8
+#define rxdata_16 rxdata.rxdata_16
+#define rxdata_32 rxdata.rxdata_32
+};
 
 #endif  /* __ASM_MPC52xx_PSC_H__ */