]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-2.6.25' of git://git.secretlab.ca/git/linux-2.6-mpc52xx into for...
authorPaul Mackerras <paulus@samba.org>
Thu, 7 Feb 2008 00:21:09 +0000 (11:21 +1100)
committerPaul Mackerras <paulus@samba.org>
Thu, 7 Feb 2008 00:21:09 +0000 (11:21 +1100)
12 files changed:
arch/powerpc/Kconfig
arch/powerpc/boot/dts/mpc5121ads.dts [new file with mode: 0644]
arch/powerpc/platforms/512x/Kconfig [new file with mode: 0644]
arch/powerpc/platforms/512x/Makefile [new file with mode: 0644]
arch/powerpc/platforms/512x/mpc5121_ads.c [new file with mode: 0644]
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/Makefile
drivers/serial/Kconfig
drivers/serial/mpc52xx_uart.c
include/asm-powerpc/mpc512x.h [new file with mode: 0644]
include/asm-powerpc/mpc52xx_psc.h

index cf030b00441507166720db089caf700cd3691181..1348bbc9251031052cca137a805f6ee9c56c28c4 100644 (file)
@@ -512,7 +512,7 @@ config PCI
        bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
                || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
                || PPC_PS3 || 44x
-       default y if !40x && !CPM2 && !8xx && !PPC_83xx \
+       default y if !40x && !CPM2 && !8xx && !PPC_MPC512x && !PPC_83xx \
                && !PPC_85xx && !PPC_86xx
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
        default PCI_QSPAN if !4xx && !CPM2 && 8xx
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
new file mode 100644 (file)
index 0000000..94ad7b2
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * MPC5121E MDS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "mpc5121ads";
+       compatible = "fsl,mpc5121ads";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5121@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <0x20>;     // 32 bytes
+                       i-cache-line-size = <0x20>;     // 32 bytes
+                       d-cache-size = <0x8000>;        // L1, 32K
+                       i-cache-size = <0x8000>;        // L1, 32K
+                       timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
+                       bus-frequency = <198000000>;    // 198 MHz csb bus
+                       clock-frequency = <396000000>;  // 396 MHz ppc core
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x10000000>;  // 256MB at 0
+       };
+
+       localbus@80000020 {
+               compatible = "fsl,mpc5121ads-localbus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0x80000020 0x40>;
+
+               ranges = <0x0 0x0 0xfc000000 0x04000000
+                         0x2 0x0 0x82000000 0x00008000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0x0 0x4000000>;
+                       bank-width = <4>;
+                       device-width = <1>;
+               };
+
+               board-control@2,0 {
+                       compatible = "fsl,mpc5121ads-cpld";
+                       reg = <0x2 0x0 0x8000>;
+               };
+       };
+
+       soc@80000000 {
+               compatible = "fsl,mpc5121-immr";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               ranges = <0x0 0x80000000 0x400000>;
+               reg = <0x80000000 0x400000>;
+               bus-frequency = <66000000>;     // 66 MHz ips bus
+
+
+               // IPIC
+               // interrupts cell = <intr #, sense>
+               // sense values match linux IORESOURCE_IRQ_* defines:
+               // sense == 8: Level, low assertion
+               // sense == 2: Edge, high-to-low change
+               //
+               ipic: interrupt-controller@c00 {
+                       compatible = "fsl,mpc5121-ipic", "fsl,ipic";
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0xc00 0x100>;
+               };
+
+               // 512x PSCs are not 52xx PSCs compatible
+               // PSC3 serial port A aka ttyPSC0
+               serial@11300 {
+                       device_type = "serial";
+                       compatible = "fsl,mpc5121-psc-uart";
+                       // Logical port assignment needed until driver
+                       // learns to use aliases
+                       port-number = <0>;
+                       cell-index = <3>;
+                       reg = <0x11300 0x100>;
+                       interrupts = <0x28 0x8>; // actually the fifo irq
+                       interrupt-parent = < &ipic >;
+               };
+
+               // PSC4 serial port B aka ttyPSC1
+               serial@11400 {
+                       device_type = "serial";
+                       compatible = "fsl,mpc5121-psc-uart";
+                       // Logical port assignment needed until driver
+                       // learns to use aliases
+                       port-number = <1>;
+                       cell-index = <4>;
+                       reg = <0x11400 0x100>;
+                       interrupts = <0x28 0x8>; // actually the fifo irq
+                       interrupt-parent = < &ipic >;
+               };
+
+               pscsfifo@11f00 {
+                       compatible = "fsl,mpc5121-psc-fifo";
+                       reg = <0x11f00 0x100>;
+                       interrupts = <0x28 0x8>;
+                       interrupt-parent = < &ipic >;
+               };
+       };
+};
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
new file mode 100644 (file)
index 0000000..c6fa49e
--- /dev/null
@@ -0,0 +1,20 @@
+config PPC_MPC512x
+       bool
+       select FSL_SOC
+       select IPIC
+       default n
+
+config PPC_MPC5121
+       bool
+       select PPC_MPC512x
+       default n
+
+config MPC5121_ADS
+       bool "Freescale MPC5121E ADS"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select DEFAULT_UIMAGE
+       select WANT_DEVICE_TREE
+       select PPC_MPC5121
+       help
+         This option enables support for the MPC5121E ADS board.
+       default n
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
new file mode 100644 (file)
index 0000000..232c89f
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for the Freescale PowerPC 512x linux kernel.
+#
+obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
new file mode 100644 (file)
index 0000000..50bd3a3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
+ *
+ * Description:
+ * MPC5121 ADS board setup
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+/**
+ *     mpc512x_find_ips_freq - Find the IPS bus frequency for a device
+ *     @node:  device node
+ *
+ *     Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
+ */
+unsigned long
+mpc512x_find_ips_freq(struct device_node *node)
+{
+       struct device_node *np;
+       const unsigned int *p_ips_freq = NULL;
+
+       of_node_get(node);
+       while (node) {
+               p_ips_freq = of_get_property(node, "bus-frequency", NULL);
+               if (p_ips_freq)
+                       break;
+
+               np = of_get_parent(node);
+               of_node_put(node);
+               node = np;
+       }
+       if (node)
+               of_node_put(node);
+
+       return p_ips_freq ? *p_ips_freq : 0;
+}
+EXPORT_SYMBOL(mpc512x_find_ips_freq);
+
+static struct of_device_id __initdata of_bus_ids[] = {
+       { .name = "soc", },
+       { .name = "localbus", },
+       {},
+};
+
+static void __init mpc5121_ads_declare_of_platform_devices(void)
+{
+       /* Find every child of the SOC node and add it to of_platform */
+       if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
+               printk(KERN_ERR __FILE__ ": "
+                       "Error while probing of_platform bus\n");
+}
+
+static void __init mpc5121_ads_init_IRQ(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
+       if (!np)
+               return;
+
+       ipic_init(np, 0);
+       of_node_put(np);
+
+       /*
+        * Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       ipic_set_default_priority();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc5121_ads_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
+}
+
+define_machine(mpc5121_ads) {
+       .name                   = "MPC5121 ADS",
+       .probe                  = mpc5121_ads_probe,
+       .init                   = mpc5121_ads_declare_of_platform_devices,
+       .init_IRQ               = mpc5121_ads_init_IRQ,
+       .get_irq                = ipic_get_irq,
+       .calibrate_decr         = generic_calibrate_decr,
+};
index 045b8c80eeaf1bc9aec1681c4c68071bef5724a2..fcedbec07f94fe7478f50f19833afe3b9c87a20e 100644 (file)
@@ -42,6 +42,7 @@ config CLASSIC32
 source "arch/powerpc/platforms/pseries/Kconfig"
 source "arch/powerpc/platforms/iseries/Kconfig"
 source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/512x/Kconfig"
 source "arch/powerpc/platforms/52xx/Kconfig"
 source "arch/powerpc/platforms/powermac/Kconfig"
 source "arch/powerpc/platforms/prep/Kconfig"
index eea2e7049fed5ef74bd1dc0761d278994dcc0d87..69941ba709753fe0972f125aa2121c857161aa3d 100644 (file)
@@ -14,7 +14,7 @@ choice
          There are five families of 32 bit PowerPC chips supported.
          The most common ones are the desktop and server CPUs (601, 603,
          604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
-         embedded 52xx/82xx/83xx/86xx counterparts.
+         embedded 512x/52xx/82xx/83xx/86xx counterparts.
          The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
          (85xx) each form a family of their own that is not compatible
          with the others.
@@ -22,7 +22,7 @@ choice
          If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
 
 config 6xx
-       bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
+       bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
        select PPC_FPU
 
 config PPC_85xx
@@ -225,7 +225,7 @@ config NR_CPUS
 
 config NOT_COHERENT_CACHE
        bool
-       depends on 4xx || 8xx || E200
+       depends on 4xx || 8xx || E200 || PPC_MPC512x
        default y
 
 config CHECK_CACHE_COHERENCY
index 6d9079da5f5a917c9357faa19f22300dab43f178..a984894466d91c23dcafe92e97932e31c9d43bf3 100644 (file)
@@ -11,6 +11,7 @@ endif
 obj-$(CONFIG_PPC_CHRP)         += chrp/
 obj-$(CONFIG_40x)              += 40x/
 obj-$(CONFIG_44x)              += 44x/
+obj-$(CONFIG_PPC_MPC512x)      += 512x/
 obj-$(CONFIG_PPC_MPC52xx)      += 52xx/
 obj-$(CONFIG_PPC_8xx)          += 8xx/
 obj-$(CONFIG_PPC_82xx)         += 82xx/
index 4fa7927997ad53319af9ae03fee86932dac18b6d..ddfb1eab736371a6676ccdd637d197865b32ea2f 100644 (file)
@@ -1138,17 +1138,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
@@ -1156,7 +1156,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 3c4d29e59b2c58581d1b380e95fabff4f5e9a6df..821facd10bbc1036cbb9183bd7ece3a230dd65ab 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>
@@ -67,7 +70,6 @@
 #include <linux/serial.h>
 #include <linux/sysrq.h>
 #include <linux/console.h>
-
 #include <linux/delay.h>
 #include <linux/io.h>
 
@@ -79,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)
@@ -111,8 +114,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 */
@@ -130,13 +133,324 @@ 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      */
+/* ======================================================================== */
+
+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);
+};
+
+#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)
+{
+       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,
+};
+
+#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                                                          */
@@ -145,8 +459,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 +479,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 +499,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 +509,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,12 +536,12 @@ 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 */
        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;
 
@@ -242,15 +551,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 +634,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 +762,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 +779,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 +810,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 +820,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 +833,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 +860,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 +868,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 +940,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 +1011,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 +1043,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 +1238,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 +1254,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 +1264,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 |
@@ -1080,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);
@@ -1149,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",
diff --git a/include/asm-powerpc/mpc512x.h b/include/asm-powerpc/mpc512x.h
new file mode 100644 (file)
index 0000000..c48a165
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
+ *
+ * Description:
+ * MPC5121 Prototypes and definitions
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_POWERPC_MPC512x_H__
+#define __ASM_POWERPC_MPC512x_H__
+
+extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
+
+#endif /* __ASM_POWERPC_MPC512x_H__ */
+
index bea42b95390f3aec6e1bf6732faba42f9785ddd4..710c5d36efaa08496f1a473633acfdf132b3eba1 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__ */