[linux-yocto] [PATCH 08/70] arch/arm/mach-axxia: adding mach-axxia support

Paul Butler butler.paul at gmail.com
Mon Jun 10 18:45:31 PDT 2013


LSI axm55xx: Add multi-cluster support for up to 16 cores

The LSI axm55xx platform can have up to four clusters, each having four
A15 cores (so up to a total of 16 cores). The current setup assumes that
a single GIC will handle the IPI interrupts on a platform, but a single
GIC can only handle up to eight cores. On the axm55xx platform, an
external distributed interrupt IPI block is used in place of the GIC
software generated IPIs. In this commit, we replace the use of the
standard GIC driver with a axm55xx specific one that supports multiple
clusters.

Modified arch/arm/mach-axxia/axxia-gic.c to to handle the slightly different
way in which a preempt_rt kernel manipulates the Axxia GIC API during boot.
Also updated arch/arm/configs/lsisim_defconfig to set the base level of
prempt_rt to CONFIG_PREEMPT_RTB.  The preempt_rt kernel must be set with
a minimal preempt model, to enable CONFIG_GENERIC_LOCKBREAK, which in turn
allows spinlocks to work correctly across multiple clusters.

LSI axm55xx: Add ability to parse specific core numbers in the DTB

Modified arch/arm/mach-axxia/platsmp.c to be able to parse the "cpu"
entries in the DTB and boot the specified core numbers.

Signed-off-by: David Mercado <david.mercado at windriver.com>
Signed-off-by: Paul Butler <paul.butler at windriver.com>
---
 arch/arm/boot/dts/axm-sim.dts                  |   80 +-
 arch/arm/boot/dts/axm55xx.dts                  |  290 ++++++
 arch/arm/boot/dts/axm55xxsim.dts               |  446 +++++++++
 arch/arm/boot/fmboot/fmboot.S                  |    7 +-
 arch/arm/mach-axxia/Kconfig                    |   31 +
 arch/arm/mach-axxia/Makefile                   |   12 +
 arch/arm/mach-axxia/Makefile.boot              |    5 +
 arch/arm/mach-axxia/axxia-gic.c                | 1167 ++++++++++++++++++++++++
 arch/arm/mach-axxia/axxia.c                    |  261 ++++++
 arch/arm/mach-axxia/axxia.h                    |    5 +
 arch/arm/mach-axxia/clock.c                    |   79 ++
 arch/arm/mach-axxia/headsmp.S                  |   43 +
 arch/arm/mach-axxia/hotplug.c                  |  124 +++
 arch/arm/mach-axxia/i2c.c                      |  220 +++++
 arch/arm/mach-axxia/i2c.h                      |   35 +
 arch/arm/mach-axxia/include/mach/axxia-gic.h   |   16 +
 arch/arm/mach-axxia/include/mach/debug-macro.S |   35 +
 arch/arm/mach-axxia/include/mach/entry-macro.S |    5 +
 arch/arm/mach-axxia/include/mach/gpio.h        |    1 +
 arch/arm/mach-axxia/include/mach/hardware.h    |    1 +
 arch/arm/mach-axxia/include/mach/io.h          |   39 +
 arch/arm/mach-axxia/include/mach/irqs.h        |    4 +
 arch/arm/mach-axxia/include/mach/system.h      |   33 +
 arch/arm/mach-axxia/include/mach/timers.h      |   39 +
 arch/arm/mach-axxia/include/mach/timex.h       |   23 +
 arch/arm/mach-axxia/include/mach/uncompress.h  |   65 ++
 arch/arm/mach-axxia/io.c                       |   40 +
 arch/arm/mach-axxia/pci.c                      |  977 ++++++++++++++++++++
 arch/arm/mach-axxia/pci.h                      |    1 +
 arch/arm/mach-axxia/platsmp.c                  |  175 ++++
 arch/arm/mach-axxia/timers.c                   |  225 +++++
 31 files changed, 4477 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/boot/dts/axm55xx.dts
 create mode 100644 arch/arm/boot/dts/axm55xxsim.dts
 create mode 100644 arch/arm/mach-axxia/Kconfig
 create mode 100644 arch/arm/mach-axxia/Makefile
 create mode 100644 arch/arm/mach-axxia/Makefile.boot
 create mode 100644 arch/arm/mach-axxia/axxia-gic.c
 create mode 100644 arch/arm/mach-axxia/axxia.c
 create mode 100644 arch/arm/mach-axxia/axxia.h
 create mode 100644 arch/arm/mach-axxia/clock.c
 create mode 100644 arch/arm/mach-axxia/headsmp.S
 create mode 100644 arch/arm/mach-axxia/hotplug.c
 create mode 100644 arch/arm/mach-axxia/i2c.c
 create mode 100644 arch/arm/mach-axxia/i2c.h
 create mode 100644 arch/arm/mach-axxia/include/mach/axxia-gic.h
 create mode 100644 arch/arm/mach-axxia/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-axxia/include/mach/entry-macro.S
 create mode 100644 arch/arm/mach-axxia/include/mach/gpio.h
 create mode 100644 arch/arm/mach-axxia/include/mach/hardware.h
 create mode 100644 arch/arm/mach-axxia/include/mach/io.h
 create mode 100644 arch/arm/mach-axxia/include/mach/irqs.h
 create mode 100644 arch/arm/mach-axxia/include/mach/system.h
 create mode 100644 arch/arm/mach-axxia/include/mach/timers.h
 create mode 100644 arch/arm/mach-axxia/include/mach/timex.h
 create mode 100644 arch/arm/mach-axxia/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-axxia/io.c
 create mode 100644 arch/arm/mach-axxia/pci.c
 create mode 100644 arch/arm/mach-axxia/pci.h
 create mode 100644 arch/arm/mach-axxia/platsmp.c
 create mode 100644 arch/arm/mach-axxia/timers.c

diff --git a/arch/arm/boot/dts/axm-sim.dts b/arch/arm/boot/dts/axm-sim.dts
index 5977691..bb46808 100644
--- a/arch/arm/boot/dts/axm-sim.dts
+++ b/arch/arm/boot/dts/axm-sim.dts
@@ -1,5 +1,5 @@
 /*
- * arch/arm/boot/dts/axm5500-sim.dts
+ * arch/arm/boot/dts/axm-sim.dts
  *
  * Copyright (C) 2012 LSI
  *
@@ -64,6 +64,78 @@
 			compatible = "arm,cortex-a15";
 			reg = <3>;
 		};
+
+		cpu at 4 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <4>;
+		};
+
+		cpu at 5 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <5>;
+		};
+
+		cpu at 6 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <6>;
+		};
+
+		cpu at 7 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <7>;
+		};
+
+		cpu at 8 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <8>;
+		};
+
+		cpu at 9 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <9>;
+		};
+
+		cpu at 10 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <10>;
+		};
+
+		cpu at 11 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <11>;
+		};
+
+		cpu at 12 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <12>;
+		};
+
+		cpu at 13 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <13>;
+		};
+
+		cpu at 14 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <14>;
+		};
+
+		cpu at 15 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <15>;
+		};
 	};
 
 	memory at 00000000 {
@@ -76,8 +148,10 @@
 		#interrupt-cells = <3>;
 		#address-cells = <0>;
 		interrupt-controller;
-		reg = <0x20 0x01001000 0 0x1000>,
-		      <0x20 0x01002000 0 0x100>;
+		reg = <0x20 0x01001000 0 0x1000>,  /* gic dist base */
+		      <0x20 0x01002000 0 0x100>,   /* gic cpu base */
+		      <0x20 0x10030000 0 0x100>,   /* axm IPI mask reg base */
+		      <0x20 0x10040000 0 0x20000>; /* axm IPI send reg base */
 	};
 
 	timer {
diff --git a/arch/arm/boot/dts/axm55xx.dts b/arch/arm/boot/dts/axm55xx.dts
new file mode 100644
index 0000000..3359cb4
--- /dev/null
+++ b/arch/arm/boot/dts/axm55xx.dts
@@ -0,0 +1,290 @@
+/*
+ * arch/arm/boot/dts/axm5500-sim.dts
+ *
+ * Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/dts-v1/;
+
+/ {
+	model = "AXM5516";
+	compatible = "arm", "lsi,axm5516";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &axxia_serial0;
+		timer   = &axxia_timers;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <0>;
+		};
+	};
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0 0x00000000 0 0x40000000>;
+	};
+
+	gic: interrupt-controller at 2001001000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x20 0x01001000 0 0x1000>,
+		      <0x20 0x01002000 0 0x100>;
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 13 0xf08>,
+			     <1 14 0xf08>;
+	};
+
+
+	gpdma at 2020140000 {
+		compatible = "lsi,dma32";
+		reg = <0x20 0x20140000 0x00 0x1000>;
+		interrupts = <0 60 4>, /* busy */
+			     <0 61 4>; /* error */
+
+		channel0 {
+			interrupts = <0 62 4>;
+		};
+
+		channel1 {
+			interrupts = <0 63 4>;
+		};
+	};
+
+	gpdma at 2020141000 {
+		status = "disabled";
+		compatible = "lsi,dma32";
+		reg = <0x20 0x20141000 0x00 0x1000>;
+		interrupts = <0 64 4>, /* busy */
+			     <0 65 4>; /* error */
+
+		channel0 {
+			interrupts = <0 66 4>;
+		};
+
+		channel1 {
+			interrupts = <0 67 4>;
+		};
+	};
+
+	gpreg at 2010094000  {
+		compatible = "lsi,gpreg";
+		reg = <0x20 0x10094000 0 0x1000>;
+	};
+
+	ethernet at 201100000000 {
+		compatible = "smsc,lan91c111";
+		device_type = "network";
+		reg = <0x20 0x11000000 0 0x10000>;
+		interrupts = <0 1 4>;
+		phy-mode = "mii";
+		reg-io-width = <4>;
+		smsc,irq-active-high;
+		smsc,irq-push-pull;
+	};
+
+        amba {
+		compatible = "arm,amba-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		mmci at 020101E0000 {
+			compatible = "arm,pl180", "arm,primecell";
+			reg = <0x20 0x101E0000 0x00 0x1000>;
+			interrupts = <0 222 4>,
+				     <0 223 4>;
+		};
+
+		axxia_serial0: uart at 2010080000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x20 0x10080000 0x00 0x1000>;
+			interrupts = <0 56 4>;
+		};
+
+		axxia_timers: timer at 2010091000 {
+			compatible = "arm,sp804", "arm,primecell";
+			reg = <0x20 0x10091000 0 0x1000>;
+			interrupts = <0 47 4>,
+				     <0 48 4>,
+				     <0 49 4>,
+				     <0 50 4>,
+				     <0 51 4>,
+				     <0 52 4>,
+				     <0 53 4>,
+				     <0 54 4>;
+		};
+
+		gpio at 2010092000 {
+			compatible = "arm,pl061", "arm,primecell";
+			reg = <0x20 0x10092000 0 0x1000>;
+			interrupts = <0 10 4>,
+				     <0 11 4>,
+				     <0 12 4>,
+				     <0 13 4>,
+				     <0 14 4>,
+				     <0 15 4>,
+				     <0 16 4>,
+				     <0 17 4>;
+		};
+
+		gpio at 2010093000 {
+			compatible = "arm,pl061", "arm,primecell";
+			reg = <0x20 0x10093000 0x00 0x1000>;
+			interrupts = <0 18 4>;
+		};
+
+		ssp at 2010088000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <0x20 0x10088000 0x00 0x1000>;
+			interrupts = <0 42 4>;
+		};
+
+	};
+
+    PCIE0: pciex at 0xf0120000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <0>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = < 0x30 0x38000000 0x0 0x01000000
+                0x20 0x20120000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > *
+/
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x00000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0xa0000000
+                              0x00 0x00000000
+                              0x00 0x10000000>;
+                    interrupt-parent = <&gic>;
+                interrupts = <29 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 29 2
+                        0000 0 0 2 &gic 29 2
+                        0000 0 0 3 &gic 29 2
+                        0000 0 0 4 &gic 29 2
+                >;
+        };
+
+        PCIE1: pciex at 0xf0128000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <1>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = <0x30 0x78000000 0x0 0x01000000
+                       0x20 0x20128000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > */
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x40000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0xb0000000
+                             0x00 0x00000000
+                              0x00 0x10000000>;
+                interrupt-parent = <&gic>;
+                interrupts = <72 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 72 2
+                        0000 0 0 2 &gic 72 2
+                        0000 0 0 3 &gic 72 2
+                        0000 0 0 4 &gic 72 2
+                >;
+        };
+
+        PCIE2: pciex at 0xf0130000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <2>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = <0x30 0xb8000000 0x0 0x01000000
+                       0x20 0x20130000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > */
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x80000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0xc0000000
+                              0x00 0x00000000
+                              0x00 0x10000000>;
+
+                interrupt-parent = <&gic>;
+                interrupts = <73 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 73 2
+                        0000 0 0 2 &gic 73 2
+                        0000 0 0 3 &gic 73 2
+                        0000 0 0 4 &gic 73 2
+                >;
+        };
+};
+
+/*
+  Local Variables:
+  mode: C
+  End:
+*/
diff --git a/arch/arm/boot/dts/axm55xxsim.dts b/arch/arm/boot/dts/axm55xxsim.dts
new file mode 100644
index 0000000..169aa82
--- /dev/null
+++ b/arch/arm/boot/dts/axm55xxsim.dts
@@ -0,0 +1,446 @@
+/*
+ * arch/arm/boot/dts/axm-sim.dts
+ *
+ * Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/dts-v1/;
+
+/ {
+	model = "AXM5516";
+	compatible = "arm", "lsi,axm5516";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &axxia_serial0;
+		serial1 = &axxia_serial1;
+		serial2 = &axxia_serial2;
+		serial3 = &axxia_serial3;
+		timer   = &axxia_timers;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <0>;
+		};
+
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <1>;
+		};
+
+		cpu at 2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <2>;
+		};
+
+		cpu at 3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <3>;
+		};
+
+		cpu at 4 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <4>;
+		};
+
+		cpu at 5 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <5>;
+		};
+
+		cpu at 6 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <6>;
+		};
+
+		cpu at 7 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <7>;
+		};
+
+		cpu at 8 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <8>;
+		};
+
+		cpu at 9 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <9>;
+		};
+
+		cpu at 10 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <10>;
+		};
+
+		cpu at 11 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <11>;
+		};
+
+		cpu at 12 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <12>;
+		};
+
+		cpu at 13 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <13>;
+		};
+
+		cpu at 14 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <14>;
+		};
+
+		cpu at 15 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <15>;
+		};
+	};
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0 0x00000000 0 0x40000000>;
+	};
+
+	gic: interrupt-controller at 2001001000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x20 0x01001000 0 0x1000>,  /* gic dist base */
+		      <0x20 0x01002000 0 0x100>,   /* gic cpu base */
+		      <0x20 0x10030000 0 0x100>,   /* axm IPI mask reg base */
+		      <0x20 0x10040000 0 0x20000>; /* axm IPI send reg base */
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 13 0xf08>,
+			     <1 14 0xf08>;
+	};
+
+
+	gpdma at 2020140000 {
+		compatible = "lsi,dma32";
+		reg = <0x20 0x20140000 0x00 0x1000>;
+		interrupts = <0 60 4>, /* busy */
+			     <0 61 4>; /* error */
+
+		channel0 {
+			interrupts = <0 62 4>;
+		};
+
+		channel1 {
+			interrupts = <0 63 4>;
+		};
+	};
+
+	gpdma at 2020141000 {
+		status = "disabled";
+		compatible = "lsi,dma32";
+		reg = <0x20 0x20141000 0x00 0x1000>;
+		interrupts = <0 64 4>, /* busy */
+			     <0 65 4>; /* error */
+
+		channel0 {
+			interrupts = <0 66 4>;
+		};
+
+		channel1 {
+			interrupts = <0 67 4>;
+		};
+	};
+
+	gpreg at 2010094000  {
+		compatible = "lsi,gpreg";
+		reg = <0x20 0x10094000 0 0x1000>;
+	};
+
+	ethernet at 201100000000 {
+		compatible = "smsc,lan91c111";
+		device_type = "network";
+		reg = <0x20 0x11000000 0 0x10000>;
+		interrupts = <0 1 4>;
+		phy-mode = "mii";
+		reg-io-width = <4>;
+		smsc,irq-active-high;
+		smsc,irq-push-pull;
+	};
+
+        amba {
+		compatible = "arm,amba-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		mmci at 020101E0000 {
+			compatible = "arm,pl180", "arm,primecell";
+			reg = <0x20 0x101E0000 0x00 0x1000>;
+			interrupts = <0 222 4>,
+				     <0 223 4>;
+		};
+
+		axxia_serial0: uart at 2010080000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x20 0x10080000 0x00 0x1000>;
+			interrupts = <0 56 4>;
+		};
+
+		axxia_serial1: uart at 2010081000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x20 0x10081000 0x00 0x1000>;
+			interrupts = <0 57 4>;
+		};
+
+		axxia_serial2: uart at 2010082000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x20 0x10082000 0x00 0x1000>;
+			interrupts = <0 58 4>;
+		};
+
+		axxia_serial3: uart at 2010083000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x20 0x10083000 0x00 0x1000>;
+			interrupts = <0 59 4>;
+		};
+
+		axxia_timers: timer at 2010091000 {
+			compatible = "arm,sp804", "arm,primecell";
+			reg = <0x20 0x10091000 0 0x1000>;
+			interrupts = <0 47 4>,
+				     <0 48 4>,
+				     <0 49 4>,
+				     <0 50 4>,
+				     <0 51 4>,
+				     <0 52 4>,
+				     <0 53 4>,
+				     <0 54 4>;
+		};
+
+		gpio at 2010092000 {
+			compatible = "arm,pl061", "arm,primecell";
+			reg = <0x20 0x10092000 0 0x1000>;
+			interrupts = <0 10 4>,
+				     <0 11 4>,
+				     <0 12 4>,
+				     <0 13 4>,
+				     <0 14 4>,
+				     <0 15 4>,
+				     <0 16 4>,
+				     <0 17 4>;
+		};
+
+		gpio at 2010093000 {
+			compatible = "arm,pl061", "arm,primecell";
+			reg = <0x20 0x10093000 0x00 0x1000>;
+			interrupts = <0 18 4>;
+		};
+
+		ssp at 2010088000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <0x20 0x10088000 0x00 0x1000>;
+			interrupts = <0 42 4>;
+		};
+
+	};
+
+    PCIE0: pciex at 0xf0120000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <0>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = < 0x30 0x38000000 0x0 0x01000000
+                0x20 0x20120000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> >*/
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x00000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0x00000000
+                              0x00 0x00000000
+                              0x00 0x40000000>;
+                    interrupt-parent = <&gic>;
+                interrupts = <29 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 29 2
+                        0000 0 0 2 &gic 29 2
+                        0000 0 0 3 &gic 29 2
+                        0000 0 0 4 &gic 29 2
+                >;
+        };
+
+        PCIE1: pciex at 0xf0128000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <1>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = <0x30 0x78000000 0x0 0x01000000
+                       0x20 0x20128000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > */
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x40000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0x00000000
+                             0x00 0x00000000
+                              0x00 0x40000000>;
+                interrupt-parent = <&gic>;
+                interrupts = <72 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 72 2
+                        0000 0 0 2 &gic 72 2
+                        0000 0 0 3 &gic 72 2
+                        0000 0 0 4 &gic 72 2
+                >;
+        };
+
+        PCIE2: pciex at 0xf0130000 {
+                compatible = "lsi,plb-pciex";
+                device_type = "pci";
+                enabled = <0>;
+                plx = <0>;
+                primary;
+                port = <2>;
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                /* config space access MPAGE7 registers*/
+                reg = <0x30 0xb8000000 0x0 0x01000000
+                       0x20 0x20130000 0x0 0x00008000 >;
+                bus-range = <0 0x0f>;
+                /* Outbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU (PLB) addr> <2-cell size> > */
+                ranges = <0x03000000 0x00000000 0xa0000000
+                          0x30 0x80000000
+                          0x00 0x10000000>;
+                /* Inbound ranges */
+                /* < <3-cell PCI addr> <2-cell CPU addr> <2-cell size> > */
+                dma-ranges = <0x03000000 0x00000000 0x00000000
+                              0x00 0x00000000
+                              0x00 0x40000000>;
+
+                interrupt-parent = <&gic>;
+                interrupts = <73 2>;
+                interrupt-map-mask = <0000 0 0 7>;
+                interrupt-map = <
+                        /* <3-cell dev> <irq#> <prnt> <2-cell prnt IRQ/sense> */
+                        0000 0 0 1 &gic 73 2
+                        0000 0 0 2 &gic 73 2
+                        0000 0 0 3 &gic 73 2
+                        0000 0 0 4 &gic 73 2
+                >;
+        };
+
+        I2C0: i2c at 0x02010084000 {
+                compatible = "lsi,api2c";
+                device_type = "i2c";
+                enabled = <0>;
+                port = <0>;
+                /* bus_name = "auto"; */
+                /* bus = <2>; */
+                reg = <0x20 0x10084000 0x00 0x1000>;
+		interrupts = <0 19 4>;
+        };
+
+        I2C1: i2c at 0x02010085000 {
+                compatible = "lsi,api2c";
+                device_type = "i2c";
+                enabled = <0>;
+                port = <1>;
+                /* bus_name = "auto"; */
+                /* bus = <3>; */
+                reg = <0x20 0x10085000 0x00 0x1000>;
+		interrupts = <0 20 4>;
+        };
+
+        I2C2: i2c at 0x02010086000 {
+                compatible = "lsi,api2c";
+                device_type = "i2c";
+                enabled = <0>;
+                port = <2>;
+                /* bus_name = "auto"; */
+                /* bus = <4>; */
+                reg = <0x20 0x10086000 0x00 0x1000>;
+		interrupts = <0 21 4>;
+        };
+
+        SMB: i2c at 0x02010087000 {
+                compatible = "lsi,api2c";
+                device_type = "i2c";
+                enabled = <0>;
+                port = <3>;
+                bus_name = "smb";
+                /* bus = <5>; */
+                reg = <0x20 0x10087000 0x00 0x1000>;
+		interrupts = <0 22 4>;
+        };
+};
+
+/*
+  Local Variables:
+  mode: C
+  End:
+*/
diff --git a/arch/arm/boot/fmboot/fmboot.S b/arch/arm/boot/fmboot/fmboot.S
index cd52371..576d1df 100644
--- a/arch/arm/boot/fmboot/fmboot.S
+++ b/arch/arm/boot/fmboot/fmboot.S
@@ -28,7 +28,7 @@ _start:
 	@ CPU initialisation
 	@
 	mrc	p15, 0, r0, c0, c0, 5		@ MPIDR (ARMv7 only)
-	and	r0, r0, #15			@ CPU number
+	bic 	r0, #0xff000000			@ CPU number
 	cmp	r0, #0				@ primary CPU?
 	beq	2f
 
@@ -39,13 +39,12 @@ _start:
 	adr	r2, 1f
 	ldmia	r2, {r3 - r7}			@ move the code to a location
 	stmia	r1, {r3 - r7}			@ less likely to be overridden
-	add	r0, r1, #0x20			@ Entry point for secondary
-						@ CPUs @ SPIN_TABLE_BASE+0x20
+	add	r0, r1, #0x20			@ Entry point for secondary CPUs
+						@ SPIN_TABLE_BASE+0x20
 	mov	r2, #0
 	str	r2, [r0, #0]			@ ensure initially zero
 	mov	pc, r1				@ branch to the relocated code
 1:
-	wfe
 	ldr	r1, [r0]
 	cmp	r1, #0
 	beq	1b
diff --git a/arch/arm/mach-axxia/Kconfig b/arch/arm/mach-axxia/Kconfig
new file mode 100644
index 0000000..4a4922f
--- /dev/null
+++ b/arch/arm/mach-axxia/Kconfig
@@ -0,0 +1,31 @@
+menu "Axxia platform type"
+	depends on ARCH_AXXIA
+
+config ARCH_AXXIA_GIC
+        bool "Multi-cluster ARM GIC support for the LSI Axxia platforms"
+        select IRQ_DOMAIN
+        select MULTI_IRQ_HANDLER
+	help
+	  The LSI Axxia platforms can have up to four clusters, each having
+	  four cores (so a total of 16 cores). This requires the use of a
+	  distributed interrupt system in lieu of of a single ARM GIC.
+
+	  This option enables support for this multi-cluster setup.
+
+config ARCH_AXXIA_DT
+	bool "Device Tree support for LSI Axxia platforms"
+	select ARCH_AXXIA_GIC
+	select ARM_PATCH_PHYS_VIRT
+	select AUTO_ZRELADDR
+	select CPU_V7
+	select HAVE_SMP
+	select MIGHT_HAVE_CACHE_L2X0
+	select USE_OF
+	help
+	  The LSI Axxia platforms require a Flattened Device Tree to be passed
+	  to the kernel.
+
+	  If your bootloader supports Flattened Device Tree based booting,
+	  say Y here.
+
+endmenu
diff --git a/arch/arm/mach-axxia/Makefile b/arch/arm/mach-axxia/Makefile
new file mode 100644
index 0000000..2d43ee7
--- /dev/null
+++ b/arch/arm/mach-axxia/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux kernel.
+#
+obj-y					:= axxia.o
+obj-y					+= clock.o
+obj-y                                   += io.o
+obj-y					+= timers.o
+obj-y					+= pci.o
+obj-$(CONFIG_I2C)			+= i2c.o
+obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
+obj-$(CONFIG_ARCH_AXXIA_GIC)		+= axxia-gic.o
+obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
diff --git a/arch/arm/mach-axxia/Makefile.boot b/arch/arm/mach-axxia/Makefile.boot
new file mode 100644
index 0000000..c6dd891
--- /dev/null
+++ b/arch/arm/mach-axxia/Makefile.boot
@@ -0,0 +1,5 @@
+# Those numbers are used only by the non-DT V2P-CA9 platform
+# The DT-enabled ones require CONFIG_AUTO_ZRELADDR=y
+   zreladdr-y	+= 0x60008000
+params_phys-y	:= 0x60000100
+initrd_phys-y	:= 0x60800000
diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c
new file mode 100644
index 0000000..20d04ea
--- /dev/null
+++ b/arch/arm/mach-axxia/axxia-gic.c
@@ -0,0 +1,1167 @@
+/*
+ *  linux/arch/arm/mach-axxia/axxia-gic.c
+ *
+ *  Cloned from linux/arch/arm/common/gic.c
+ *
+ *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Interrupt architecture for the Axxia:
+ *
+ * o The Axxia chip can have up to four clusters, and each cluster has
+ *   an ARM GIC interrupt controller.
+ *
+ * o In each GIC, there is one Interrupt Distributor, which receives
+ *   interrupts from system devices and sends them to the Interrupt
+ *   Controllers.
+ *
+ * o There is one CPU Interface per CPU, which sends interrupts sent
+ *   by the Distributor, and interrupts generated locally, to the
+ *   associated CPU. The base address of the CPU interface is usually
+ *   aliased so that the same address points to different chips depending
+ *   on the CPU it is accessed from.
+ *
+ * o The Axxia chip uses a distributed interrupt interface that's used
+ *   for IPI messaging between clusters. Therefore, this design does not
+ *   use the GIC software generated interrupts (0 - 16).
+ *
+ * Note that IRQs 0-31 are special - they are local to each CPU.
+ * As such, the enable set/clear, pending set/clear and active bit
+ * registers are banked per-cpu for these sources.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+#include <asm/exception.h>
+#include <asm/smp_plat.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/gic.h>
+
+#include <mach/axxia-gic.h>
+
+static u32 irq_cpuid[1020];
+static void __iomem *ipi_mask_reg_base;
+static void __iomem *ipi_send_reg_base;
+
+/* AXM IPI numbers */
+enum axxia_ext_ipi_num {
+	IPI0_CPU0 = 227,	/* Axm IPI 195 */
+	IPI0_CPU1,
+	IPI0_CPU2,
+	IPI0_CPU3,
+	IPI1_CPU0,		/* Axm IPI 199 */
+	IPI1_CPU1,
+	IPI1_CPU2,
+	IPI1_CPU3,
+	IPI2_CPU0,		/* Axm IPI 203 */
+	IPI2_CPU1,
+	IPI2_CPU2,
+	IPI2_CPU3,
+	IPI3_CPU0,		/* Axm IPI 207 */
+	IPI3_CPU1,
+	IPI3_CPU2,
+	IPI3_CPU3,
+	MAX_AXM_IPI_NUM
+};
+static u32 mplx_ipi_num_45;
+static u32 mplx_ipi_num_61;
+
+union gic_base {
+	void __iomem *common_base;
+	void __percpu __iomem **percpu_base;
+};
+
+struct gic_chip_data {
+	union gic_base dist_base;
+	union gic_base cpu_base;
+#ifdef CONFIG_CPU_PM
+	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+	u32 __percpu *saved_ppi_enable;
+	u32 __percpu *saved_ppi_conf;
+#endif
+	struct irq_domain *domain;
+	unsigned int gic_irqs;
+};
+
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static struct gic_chip_data gic_data __read_mostly;
+
+#define gic_data_dist_base(d)	((d)->dist_base.common_base)
+#define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
+#define gic_set_base_accessor(d, f)
+
+static inline void __iomem *gic_dist_base(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return gic_data_dist_base(gic_data);
+}
+
+static inline void __iomem *gic_cpu_base(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return gic_data_cpu_base(gic_data);
+}
+
+static inline unsigned int gic_irq(struct irq_data *d)
+{
+	return d->hwirq;
+}
+
+/*
+ * Routines to acknowledge, disable and enable interrupts.
+ */
+struct gic_mask_irq_wrapper_struct {
+	struct irq_data *d;
+};
+
+static void _gic_mask_irq(void *arg)
+{
+	struct irq_data *d = (struct irq_data *)arg;
+	u32 mask = 1 << (gic_irq(d) % 32);
+
+	raw_spin_lock(&irq_controller_lock);
+	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR
+				+ (gic_irq(d) / 32) * 4);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_mask_irq(struct irq_data *d)
+{
+	u32 pcpu = cpu_logical_map(smp_processor_id());
+	u32 irqid = gic_irq(d);
+
+	if (irqid >= 1020)
+		return;
+
+	/* Deal with PPI interrupts directly. */
+	if (irqid > 16 && irqid < 32) {
+		_gic_mask_irq(d);
+		return;
+	}
+
+	/*
+	 * If the cpu that this interrupt is assigned to falls within
+	 * the same cluster as the cpu we're currently running on, do
+	 * the IRQ masking directly. Otherwise, use the IPI mechanism
+	 * to remotely do the masking.
+	 */
+	if ((cpu_logical_map(irq_cpuid[irqid]) / 4) == (pcpu / 4)) {
+		_gic_mask_irq(d);
+	} else {
+		/*
+		 * We are running here with local interrupts
+		 * disabled. Temporarily re-enable them to
+		 * avoid possible deadlock when calling
+		 * smp_call_function_single().
+		 */
+		local_irq_enable();
+		smp_call_function_single(irq_cpuid[irqid],
+					 _gic_mask_irq,
+					 d, 1);
+		local_irq_disable();
+	}
+}
+
+static void _gic_unmask_irq(void *arg)
+{
+	struct irq_data *d = (struct irq_data *)arg;
+	u32 mask = 1 << (gic_irq(d) % 32);
+
+	raw_spin_lock(&irq_controller_lock);
+	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET
+				+ (gic_irq(d) / 32) * 4);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_unmask_irq(struct irq_data *d)
+{
+	u32 pcpu = cpu_logical_map(smp_processor_id());
+	u32 irqid = gic_irq(d);
+
+	if (irqid >= 1020)
+		return;
+
+	/* Deal with PPI interrupts directly. */
+	if (irqid > 15 && irqid < 32) {
+		_gic_unmask_irq(d);
+		return;
+	}
+
+	/*
+	 * If the cpu that this interrupt is assigned to falls within
+	 * the same cluster as the cpu we're currently running on, do
+	 * the IRQ masking directly. Otherwise, use the IPI mechanism
+	 * to remotely do the masking.
+	 */
+	if ((cpu_logical_map(irq_cpuid[irqid]) / 4) == (pcpu / 4)) {
+		_gic_unmask_irq(d);
+	} else {
+		/*
+		 * We are running here with local interrupts
+		 * disabled. Temporarily re-enable them to
+		 * avoid possible deadlock when calling
+		 * smp_call_function_single().
+		 */
+		local_irq_enable();
+		smp_call_function_single(irq_cpuid[irqid],
+					 _gic_unmask_irq,
+					 d, 1);
+		local_irq_disable();
+	}
+}
+
+static void gic_eoi_irq(struct irq_data *d)
+{
+	/*
+	 * This always runs on the same cpu that is handling
+	 * an IRQ, so no need to worry about running this on
+	 * remote clusters.
+	 */
+	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+}
+
+static int _gic_set_type(struct irq_data *d, unsigned int type)
+{
+	void __iomem *base = gic_dist_base(d);
+	unsigned int gicirq = gic_irq(d);
+	u32 enablemask = 1 << (gicirq % 32);
+	u32 enableoff = (gicirq / 32) * 4;
+	u32 confmask = 0x2 << ((gicirq % 16) * 2);
+	u32 confoff = (gicirq / 16) * 4;
+	bool enabled = false;
+	u32 val;
+
+	/* Interrupt configuration for SGIs can't be changed. */
+	if (gicirq < 16)
+		return -EINVAL;
+
+	/* Interrupt configuration for the AXM IPIs can't be changed. */
+	if ((gicirq >= IPI0_CPU0) && (gicirq < MAX_AXM_IPI_NUM))
+		return -EINVAL;
+
+	/* We only support two interrupt trigger types. */
+	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+		return -EINVAL;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+	if (type == IRQ_TYPE_LEVEL_HIGH)
+		val &= ~confmask;
+	else if (type == IRQ_TYPE_EDGE_RISING)
+		val |= confmask;
+
+	/*
+	 * As recommended by the spec, disable the interrupt before changing
+	 * the configuration.
+	 */
+	if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff)
+			  & enablemask) {
+		writel_relaxed(enablemask,
+			       base + GIC_DIST_ENABLE_CLEAR + enableoff);
+		enabled = true;
+	}
+
+	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+
+	if (enabled)
+		writel_relaxed(enablemask,
+			       base + GIC_DIST_ENABLE_SET + enableoff);
+
+	raw_spin_unlock(&irq_controller_lock);
+
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+struct gic_set_type_wrapper_struct {
+	struct irq_data *d;
+	unsigned int type;
+	int status;
+};
+
+static void gic_set_type_wrapper(void *data)
+{
+	struct gic_set_type_wrapper_struct *pArgs =
+		(struct gic_set_type_wrapper_struct *)data;
+
+	pArgs->status = _gic_set_type(pArgs->d, pArgs->type);
+}
+#endif
+
+static int gic_set_type(struct irq_data *d, unsigned int type)
+{
+#ifdef CONFIG_SMP
+	int i, nr_cluster_ids = ((nr_cpu_ids-1) / 4) + 1;
+	u32 pcpu = cpu_logical_map(smp_processor_id());
+	struct gic_set_type_wrapper_struct data;
+
+	/*
+	 * Duplicate IRQ type settings across all clusters. Run
+	 * directly for this cluster, use IPI for all others.
+	 */
+	data.d = d;
+	data.type = type;
+	for (i = 0; i < nr_cluster_ids; i++) {
+		if (i == (pcpu/4))
+			continue;
+
+		/*
+		 * We are running here with local interrupts
+		 * disabled. Temporarily re-enable them to
+		 * avoid possible deadlock when calling
+		 * smp_call_function_single().
+		 */
+		local_irq_enable();
+		smp_call_function_single((i/4),
+			 gic_set_type_wrapper, &data, 1);
+		local_irq_disable();
+		if (data.status != 0)
+			printk(KERN_ERR "gic_set_type() error (%d)!\n",
+			       data.status);
+	}
+#endif
+	return _gic_set_type(d, type);
+}
+
+static int gic_retrigger(struct irq_data *d)
+{
+	return -ENXIO;
+}
+
+#ifdef CONFIG_SMP
+
+/* Mechanism for forwarding IRQ affinity requests to other clusters. */
+struct gic_set_affinity_wrapper_struct {
+	struct irq_data *d;
+	const struct cpumask *mask_val;
+	bool disable;
+};
+
+static void _gic_set_affinity(void *data)
+{
+	struct gic_set_affinity_wrapper_struct *pArgs =
+		(struct gic_set_affinity_wrapper_struct *)data;
+	void __iomem *reg  = gic_dist_base(pArgs->d) +
+			     GIC_DIST_TARGET + (gic_irq(pArgs->d) & ~3);
+	unsigned int shift = (gic_irq(pArgs->d) % 4) * 8;
+	unsigned int cpu = cpumask_any_and(pArgs->mask_val, cpu_online_mask);
+	u32 val, affinity_mask, affinity_bit;
+	u32 enable_mask, enable_offset;
+
+	/*
+	 * Normalize the cpu number as seen by Linux (0-15) to a
+	 * number as seen by a cluster (0-3).
+	 */
+	affinity_bit = 1 << ((cpu_logical_map(cpu) % 4) + shift);
+	affinity_mask = 0xff << shift;
+
+	enable_mask = 1 << (gic_irq(pArgs->d) % 32);
+	enable_offset = 4 * (gic_irq(pArgs->d) / 32);
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl_relaxed(reg) & ~affinity_mask;
+	if (pArgs->disable == true) {
+		writel_relaxed(val, reg);
+		writel_relaxed(enable_mask, gic_data_dist_base(&gic_data)
+				+ GIC_DIST_ENABLE_CLEAR + enable_offset);
+	} else {
+		writel_relaxed(val | affinity_bit, reg);
+		writel_relaxed(enable_mask, gic_data_dist_base(&gic_data)
+				+ GIC_DIST_ENABLE_SET + enable_offset);
+	}
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static int gic_set_affinity(struct irq_data *d,
+			    const struct cpumask *mask_val,
+			    bool force)
+{
+	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+	u32 pcpu = cpu_logical_map(smp_processor_id());
+	unsigned int irqid = gic_irq(d);
+	struct gic_set_affinity_wrapper_struct data;
+
+	if (cpu >= nr_cpu_ids)
+		return -EINVAL;
+
+	if (irqid >= 1020)
+		return -EINVAL;
+
+	data.d = d;
+	data.mask_val = mask_val;
+	data.disable = false;
+
+	/*
+	 * If the new physical cpu assignment falls within the same
+	 * cluster as the cpu we're currently running on, set the IRQ
+	 * affinity directly. Otherwise, use the IPI mechanism.
+	 */
+	if ((cpu_logical_map(cpu) / 4) == (pcpu / 4)) {
+		_gic_set_affinity(&data);
+	} else {
+		/* Temporarily re-enable local interrupts. */
+		local_irq_enable();
+		smp_call_function_single(cpu, _gic_set_affinity, &data, 1);
+		local_irq_disable();
+	}
+
+	/*
+	 * If the new physical cpu assignment is on a cluster that's
+	 * different than the prior cluster, remove the IRQ affinity
+	 * on the old cluster.
+	 */
+	if ((cpu_logical_map(cpu) / 4) !=
+		(cpu_logical_map(irq_cpuid[irqid]) / 4)) {
+		/*
+		 * If old cpu assignment falls within the same cluster as
+		 * the cpu we're currently running on, set the IRQ affinity
+		 * directly. Otherwise, use IPI mechanism.
+		 */
+		data.disable = true;
+		if ((cpu_logical_map(irq_cpuid[irqid]) / 4) == (pcpu / 4)) {
+			_gic_set_affinity(&data);
+		} else {
+			/* Temporarily re-enable local interrupts. */
+			local_irq_enable();
+			smp_call_function_single(irq_cpuid[irqid],
+						 _gic_set_affinity, &data, 1);
+			local_irq_disable();
+		}
+	}
+
+	/* Update Axxia IRQ affinity table with the new logical CPU number. */
+	irq_cpuid[irqid] = cpu;
+
+	return IRQ_SET_MASK_OK;
+}
+#endif /* SMP */
+
+#ifdef CONFIG_PM
+static int gic_set_wake(struct irq_data *d, unsigned int on)
+{
+	int ret = -ENXIO;
+
+	return ret;
+}
+
+#else
+#define gic_set_wake	NULL
+#endif
+
+asmlinkage void __exception_irq_entry axxia_gic_handle_irq(struct pt_regs *regs)
+{
+	u32 irqstat, irqnr;
+	u32 ipinum = 0;
+	u32 mask, offset;
+	struct gic_chip_data *gic = &gic_data;
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+
+	do {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqnr = irqstat & ~0x1c00;
+
+		if (likely(irqnr > 15 && irqnr < 1021)) {
+			irqnr = irq_find_mapping(gic->domain, irqnr);
+
+			/*
+			 * Check if this is an external Axxia IPI interrupt.
+			 * Translate to a standard ARM internal IPI number.
+			 * The Axxia only has 4 IPI interrupts, so we
+			 * multiplex IPI_CALL_FUNC and IPI_CALL_FUNC_SINGLE
+			 * as one IPI. We also multiplex IPI_CPU_STOP and
+			 * IPI_WAKEUP as one IPI.
+			 *
+			 * IPI0_CPUx = IPI_TIMER (2)
+			 * IPI1_CPUx = IPI_RESCHEDULE (3)
+			 * IPI2_CPUx = IPI_CALL_FUNC (4) /
+			 *             IPI_CALL_FUNC_SINGLE (5)
+			 * IPI3_CPUx = IPI_CPU_STOP (6) /
+			 *             IPI_WAKEUP (1)
+			 *
+			 * Note that if the ipi_msg_type enum changes in
+			 * arch/arm/kernel/smp.c then this will have to be
+			 * updated as well.
+			 */
+			switch (irqnr) {
+			case IPI0_CPU0:
+			case IPI0_CPU1:
+			case IPI0_CPU2:
+			case IPI0_CPU3:
+				ipinum = 2;
+				break;
+
+			case IPI1_CPU0:
+			case IPI1_CPU1:
+			case IPI1_CPU2:
+			case IPI1_CPU3:
+				ipinum = 3;
+				break;
+
+			case IPI2_CPU0:
+			case IPI2_CPU1:
+			case IPI2_CPU2:
+			case IPI2_CPU3:
+				ipinum = mplx_ipi_num_45; /* 4 or 5 */
+				break;
+
+			case IPI3_CPU0:
+			case IPI3_CPU1:
+			case IPI3_CPU2:
+			case IPI3_CPU3:
+				ipinum = mplx_ipi_num_61; /* 6 or 1 */
+				break;
+
+			default:
+				/* Not an Axxia IPI */
+				ipinum = 0;
+				break;
+			}
+
+			if (ipinum) {
+				/*
+				 * Write the original irq number to the
+				 * EOI register to acknowledge the IRQ.
+				 * No need to write CPUID field, since this
+				 * is really a SPI interrupt, not a SGI.
+				 */
+				writel_relaxed(irqnr, cpu_base + GIC_CPU_EOI);
+
+				/*
+				 * Unlike the GIC softirqs, the Axxia IPI
+				 * interrupts do not remain enabled after
+				 * firing. Re-enable the interrupt here.
+				 */
+				mask = 1 << (irqnr % 32);
+				offset = 4 * (irqnr / 32);
+				writel_relaxed(mask,
+					gic_data_dist_base(&gic_data)
+					+ GIC_DIST_ENABLE_SET + offset);
+
+#ifdef CONFIG_SMP
+				/* Do the normal IPI handling. */
+				handle_IPI(ipinum, regs);
+#endif
+
+			} else {
+				handle_IRQ(irqnr, regs);
+			}
+			continue;
+		}
+		if (irqnr < 16) {
+			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+#ifdef CONFIG_SMP
+			handle_IPI(irqnr, regs);
+#endif
+			continue;
+		}
+		break;
+	} while (1);
+}
+
+static struct irq_chip gic_chip = {
+	.name			= "GIC",
+	.irq_mask		= gic_mask_irq,
+	.irq_unmask		= gic_unmask_irq,
+	.irq_eoi		= gic_eoi_irq,
+	.irq_set_type		= gic_set_type,
+	.irq_retrigger		= gic_retrigger,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= gic_set_affinity,
+#endif
+	.irq_set_wake		= gic_set_wake,
+};
+
+static void __init gic_axxia_init(struct gic_chip_data *gic)
+{
+	int i;
+	u32 cpumask;
+
+	/*
+	 * Initialize the Axxia IRQ affinity table. All non-IPI
+	 * interrupts are initially assigned to logical cpu 0.
+	 */
+	for (i = 0; i < 1020; i++)
+		irq_cpuid[i] = 0;
+
+	/* Unmask all Axxia IPI interrupts */
+	cpumask = 0;
+	for (i = 0; i < nr_cpu_ids; i++)
+		cpumask |= 1 << i;
+	for (i = 0; i < nr_cpu_ids; i++)
+		writel_relaxed(cpumask, ipi_mask_reg_base + 0x40 + i * 4);
+}
+
+static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
+{
+	unsigned int i;
+	u32 cpumask;
+	unsigned int gic_irqs = gic->gic_irqs;
+	void __iomem *base = gic_data_dist_base(gic);
+	u32 cpu = cpu_logical_map(smp_processor_id());
+	u8 cpumask_8;
+	u32 confmask;
+	u32 confoff;
+	u32 enablemask;
+	u32 enableoff;
+	u32 val;
+
+	cpumask = 1 << cpu;
+	cpumask |= cpumask << 8;
+	cpumask |= cpumask << 16;
+
+	writel_relaxed(0, base + GIC_DIST_CTRL);
+
+	/*
+	 * Set all global interrupts to be level triggered, active low.
+	 */
+	for (i = 32; i < gic_irqs; i += 16)
+		writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
+
+	/*
+	 * Set all global interrupts to this CPU only.
+	 * (Only do this for the first core on cluster 0).
+	 */
+	if (cpu == 0)
+		for (i = 32; i < gic_irqs; i += 4)
+			writel_relaxed(cpumask,
+				       base + GIC_DIST_TARGET + i * 4 / 4);
+
+	/*
+	 * Set priority on all global interrupts.
+	 */
+	for (i = 32; i < gic_irqs; i += 4)
+		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+
+	/*
+	 * Disable all interrupts.  Leave the PPI and SGIs alone
+	 * as these enables are banked registers.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff,
+			       base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+
+	/*
+	 * Set Axxia IPI interrupts for all CPUs in this cluster.
+	 */
+	for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
+		cpumask_8 = 1 << ((i - IPI0_CPU0) % 4);
+		writeb_relaxed(cpumask_8,
+			base + GIC_DIST_TARGET + (4 * (i / 4)) + i % 4);
+	}
+
+	/*
+	 * Set Axxia IPI interrupts to be edge triggered.
+	 */
+	for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
+		confmask = 0x2 << ((i % 16) * 2);
+		confoff = (i / 16) * 4;
+		val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+		val |= confmask;
+		writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+	}
+
+	/*
+	 * Do the initial enable of the Axxia IPI interrupts here.
+	 * NOTE: Writing a 0 to this register has no effect, so
+	 * no need to read and OR in bits, just writing is OK.
+	 */
+	for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
+		enablemask = 1 << (i % 32);
+		enableoff = (i / 32) * 4;
+		writel_relaxed(enablemask,
+			       base + GIC_DIST_ENABLE_SET + enableoff);
+	}
+
+	writel_relaxed(1, base + GIC_DIST_CTRL);
+}
+
+static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	void __iomem *base = gic_data_cpu_base(gic);
+	int i;
+
+	/*
+	 * Deal with the banked PPI and SGI interrupts - disable all
+	 * PPI interrupts, and also all SGI interrupts (we don't use
+	 * SGIs in the Axxia).
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_ENABLE_CLEAR);
+
+	/*
+	 * Set priority on PPI and SGI interrupts
+	 */
+	for (i = 0; i < 32; i += 4)
+		writel_relaxed(0xa0a0a0a0,
+			       dist_base + GIC_DIST_PRI + i * 4 / 4);
+
+	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
+	writel_relaxed(1, base + GIC_CPU_CTRL);
+}
+
+#ifdef CONFIG_CPU_PM
+/*
+ * Saves the GIC distributor registers during suspend or idle.  Must be called
+ * with interrupts disabled but before powering down the GIC.  After calling
+ * this function, no interrupts will be delivered by the GIC, and another
+ * platform-specific wakeup source must be enabled.
+ */
+static void gic_dist_save(void)
+{
+	unsigned int gic_irqs;
+	void __iomem *dist_base;
+	int i;
+
+	gic_irqs = gic_data.gic_irqs;
+	dist_base = gic_data_dist_base(&gic_data);
+
+	if (!dist_base)
+		return;
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+		gic_data.saved_spi_conf[i] =
+			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+		gic_data.saved_spi_target[i] =
+			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+		gic_data.saved_spi_enable[i] =
+			readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+/*
+ * Restores the GIC distributor registers during resume or when coming out of
+ * idle.  Must be called before enabling interrupts.  If a level interrupt
+ * that occured while the GIC was suspended is still present, it will be
+ * handled normally, but any edge interrupts that occured will not be seen by
+ * the GIC and need to be handled by the platform-specific wakeup source.
+ */
+static void gic_dist_restore(void)
+{
+	unsigned int gic_irqs;
+	unsigned int i;
+	void __iomem *dist_base;
+
+	gic_irqs = gic_data.gic_irqs;
+	dist_base = gic_data_dist_base(&gic_data);
+
+	if (!dist_base)
+		return;
+
+	writel_relaxed(0, dist_base + GIC_DIST_CTRL);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+		writel_relaxed(gic_data.saved_spi_conf[i],
+			dist_base + GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+		writel_relaxed(0xa0a0a0a0,
+			dist_base + GIC_DIST_PRI + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+		writel_relaxed(gic_data.saved_spi_target[i],
+			dist_base + GIC_DIST_TARGET + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+		writel_relaxed(gic_data.saved_spi_enable[i],
+			dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+}
+
+static void gic_cpu_save(void)
+{
+	int i;
+	u32 *ptr;
+	void __iomem *dist_base;
+	void __iomem *cpu_base;
+
+	dist_base = gic_data_dist_base(&gic_data);
+	cpu_base = gic_data_cpu_base(&gic_data);
+
+	if (!dist_base || !cpu_base)
+		return;
+
+	ptr = __this_cpu_ptr(gic_data.saved_ppi_enable);
+	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+	ptr = __this_cpu_ptr(gic_data.saved_ppi_conf);
+	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+		ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+}
+
+static void gic_cpu_restore(void)
+{
+	int i;
+	u32 *ptr;
+	void __iomem *dist_base;
+	void __iomem *cpu_base;
+
+	dist_base = gic_data_dist_base(&gic_data);
+	cpu_base = gic_data_cpu_base(&gic_data);
+
+	if (!dist_base || !cpu_base)
+		return;
+
+	ptr = __this_cpu_ptr(gic_data.saved_ppi_enable);
+	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+		writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+	ptr = __this_cpu_ptr(gic_data.saved_ppi_conf);
+	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+		writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
+
+	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
+		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
+
+	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
+	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+}
+
+static int _gic_notifier(struct notifier_block *self,
+			 unsigned long cmd, void *v)
+{
+	int i;
+
+	switch (cmd) {
+	case CPU_PM_ENTER:
+		gic_cpu_save();
+		break;
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		gic_cpu_restore();
+		break;
+	case CPU_CLUSTER_PM_ENTER:
+		gic_dist_save();
+		break;
+	case CPU_CLUSTER_PM_ENTER_FAILED:
+	case CPU_CLUSTER_PM_EXIT:
+		gic_dist_restore();
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+/* Mechanism for forwarding PM events to other clusters. */
+struct gic_notifier_wrapper_struct {
+	struct notifier_block *self;
+	unsigned long cmd;
+	void *v;
+};
+
+static void gic_notifier_wrapper(void *data)
+{
+	struct gic_notifier_wrapper_struct *pArgs =
+		(struct gic_notifier_wrapper_struct *)data;
+
+	_gic_notifier(pArgs->self, pArgs->cmd, pArgs->v);
+}
+
+static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
+{
+	int i;
+	struct gic_notifier_wrapper_struct data;
+	int nr_cluster_ids = ((nr_cpu_ids-1) / 4) + 1;
+	u32 pcpu = cpu_logical_map(smp_processor_id());
+
+	/* Use IPI mechanism to execute this at other clusters. */
+	data.self = self;
+	data.cmd = cmd;
+	data.v = v;
+	for (i = 0; i < nr_cluster_ids; i++) {
+		/* Skip the cluster we're already executing on - do last. */
+		if ((pcpu/4) == i)
+			continue;
+
+		/* Have the first cpu in each cluster execute this. */
+		local_irq_enable(); /* Temporarily re-enable interrupts. */
+		smp_call_function_single((i * 4),
+					 gic_notifier_wrapper,
+					 &data, 0);
+		local_irq_disable();
+	}
+
+	/* Execute on this cluster. */
+	_gic_notifier(self, cmd, v);
+
+	return NOTIFY_OK;
+	}
+
+static struct notifier_block gic_notifier_block = {
+	.notifier_call = gic_notifier,
+};
+
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+	gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+		sizeof(u32));
+	BUG_ON(!gic->saved_ppi_enable);
+
+	gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
+		sizeof(u32));
+	BUG_ON(!gic->saved_ppi_conf);
+
+	if (gic == &gic_data)
+		cpu_pm_register_notifier(&gic_notifier_block);
+}
+#else
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+}
+#endif /* CONFIG_CPU_PM */
+
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+				irq_hw_number_t hw)
+{
+	if (hw < 32) {
+		irq_set_percpu_devid(irq);
+		irq_set_chip_and_handler(irq, &gic_chip,
+					 handle_percpu_devid_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+	} else {
+		irq_set_chip_and_handler(irq, &gic_chip,
+					 handle_fasteoi_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+	}
+	irq_set_chip_data(irq, d->host_data);
+	return 0;
+}
+
+static int gic_irq_domain_xlate(struct irq_domain *d,
+				struct device_node *controller,
+				const u32 *intspec,
+				unsigned int intsize,
+				unsigned long *out_hwirq,
+				unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 3)
+		return -EINVAL;
+
+	/* Get the interrupt number and add 16 to skip over SGIs */
+	*out_hwirq = intspec[1] + 16;
+
+	/* For SPIs, we need to add 16 more to get the GIC irq ID number */
+	if (!intspec[0])
+		*out_hwirq += 16;
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+	return 0;
+}
+
+const struct irq_domain_ops gic_irq_domain_ops = {
+	.map = gic_irq_domain_map,
+	.xlate = gic_irq_domain_xlate,
+};
+
+void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+			   void __iomem *dist_base, void __iomem *cpu_base,
+			   u32 percpu_offset, struct device_node *node)
+{
+	irq_hw_number_t hwirq_base;
+	struct gic_chip_data *gic;
+	int gic_irqs, irq_base;
+
+	gic = &gic_data;
+
+	/* Normal, sane GIC... */
+	gic->dist_base.common_base = dist_base;
+	gic->cpu_base.common_base = cpu_base;
+	gic_set_base_accessor(gic, gic_get_common_base);
+
+	/*
+	 * For primary GICs, skip over SGIs.
+	 * For secondary GICs, skip over PPIs, too.
+	 */
+	if ((irq_start & 31) > 0) {
+		hwirq_base = 16;
+		if (irq_start != -1)
+			irq_start = (irq_start & ~31) + 16;
+	} else {
+		hwirq_base = 32;
+	}
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources.
+	 */
+	gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
+	gic_irqs = (gic_irqs + 1) * 32;
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic->gic_irqs = gic_irqs;
+
+	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
+	if (IS_ERR_VALUE(irq_base)) {
+		WARN(1,
+		 "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+		     irq_start);
+		irq_base = irq_start;
+	}
+	gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
+				    hwirq_base, &gic_irq_domain_ops, gic);
+	if (WARN_ON(!gic->domain))
+		return;
+
+	gic_axxia_init(gic);
+	gic_dist_init(gic);
+	gic_cpu_init(gic);
+	gic_pm_init(gic);
+}
+
+void __cpuinit axxia_gic_secondary_init(void)
+{
+	gic_cpu_init(&gic_data);
+}
+
+
+void __cpuinit axxia_gic_secondary_cluster_init(void)
+{
+	struct gic_chip_data *gic = &gic_data;
+
+	/*
+	 * Initialize the GIC distributor and cpu interfaces
+	 * for secondary clusters in the Axxia SoC.
+	 */
+
+	gic_dist_init(gic);
+	gic_cpu_init(gic);
+}
+
+#ifdef CONFIG_SMP
+void axxia_gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+{
+	int cpu;
+	unsigned long map = 0;
+	unsigned int regoffset;
+	u32 phys_cpu = cpu_logical_map(smp_processor_id());
+
+	/* Sanity check the physical cpu number */
+	if (phys_cpu >= nr_cpu_ids) {
+		printk(KERN_ERR "Invalid cpu num (%d) >= max (%d)\n",
+			phys_cpu, nr_cpu_ids);
+		return;
+	}
+
+	/* Convert our logical CPU mask into a physical one. */
+	for_each_cpu(cpu, mask)
+		map |= 1 << cpu_logical_map(cpu);
+
+	/*
+	 * Convert the standard ARM IPI number (as defined in
+	 * arch/arm/kernel/smp.c) to an Axxia IPI interrupt.
+	 * The Axxia sends IPI interrupts to other cores via
+	 * the use of "IPI send" registers. Each register is
+	 * specific to a sending CPU and IPI number. For example:
+	 * regoffset 0x0 = CPU0 uses to send IPI0 to other CPUs
+	 * regoffset 0x4 = CPU0 uses to send IPI1 to other CPUs
+	 * ...
+	 * regoffset 0x1000 = CPU1 uses to send IPI0 to other CPUs
+	 * regoffset 0x1004 = CPU1 uses to send IPI1 to other CPUs
+	 * ...
+	 */
+
+	if (phys_cpu < 8)
+		regoffset = phys_cpu * 0x1000;
+	else
+		regoffset = (phys_cpu - 8) * 0x1000 + 0x10000;
+
+	switch (irq) {
+	case 2: /* IPI_TIMER */
+		regoffset += 0x0; /* Axxia IPI0 */
+		break;
+
+	case 3: /* IPI_RESCHEDULE */
+		regoffset += 0x4; /* Axxia IPI1 */
+		break;
+
+	case 4: /* IPI_CALL_FUNC */
+	case 5: /* IPI_CALL_FUNC_SINGLE */
+		regoffset += 0x8; /* Axxia IPI2 */
+		mplx_ipi_num_45 = irq;
+		break;
+
+	case 6: /* IPI_CPU_STOP */
+	case 1: /* IPI_WAKEUP */
+		regoffset += 0xC; /* Axxia IPI3 */
+		mplx_ipi_num_61 = irq;
+		break;
+
+	default:
+		/* Unknown ARM IPI */
+		printk(KERN_ERR "Unknown ARM IPI num (%d)!\n", irq);
+		return;
+	}
+
+	/*
+	 * Ensure that stores to Normal memory are visible to the
+	 * other CPUs before issuing the IPI.
+	 */
+	dsb();
+
+	/* Axxia chip uses external SPI interrupts for IPI functionality. */
+	writel_relaxed(map, ipi_send_reg_base + regoffset);
+}
+#endif /* SMP */
+
+#ifdef CONFIG_OF
+
+int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+	void __iomem *cpu_base;
+	void __iomem *dist_base;
+	u32 percpu_offset;
+
+	if (WARN_ON(!node))
+		return -ENODEV;
+
+	dist_base = of_iomap(node, 0);
+	WARN(!dist_base, "unable to map gic dist registers\n");
+
+	cpu_base = of_iomap(node, 1);
+	WARN(!cpu_base, "unable to map gic cpu registers\n");
+
+	ipi_mask_reg_base = of_iomap(node, 2);
+	WARN(!ipi_mask_reg_base, "unable to map Axxia IPI mask registers\n");
+
+	ipi_send_reg_base = of_iomap(node, 3);
+	WARN(!ipi_send_reg_base, "unable to map Axxia IPI send registers\n");
+
+	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
+		percpu_offset = 0;
+
+	gic_init_bases(0, -1, dist_base, cpu_base, percpu_offset, node);
+
+	return 0;
+}
+#endif
diff --git a/arch/arm/mach-axxia/axxia.c b/arch/arm/mach-axxia/axxia.c
new file mode 100644
index 0000000..5d4f586
--- /dev/null
+++ b/arch/arm/mach-axxia/axxia.c
@@ -0,0 +1,261 @@
+/*
+ * arch/arm/mach-axxia/axxia.c
+ *
+ * Support for the LSI Axxia boards based on ARM cores.
+ *
+ * Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl061.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/smsc911x.h>
+#include <linux/spi/spi.h>
+#include <linux/clkdev.h>
+#ifdef CONFIG_ARM_ARCH_TIMER
+#include <asm/arch_timer.h>
+#endif
+#include <asm/mach-types.h>
+#include <asm/sizes.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
+#include <mach/timers.h>
+#include <mach/axxia-gic.h>
+#include "axxia.h"
+#include "pci.h"
+#include "i2c.h"
+
+static const char *axxia_dt_match[] __initconst = {
+	"lsi,axm5516",		/* AXM5516 */
+	NULL
+};
+
+
+static void __iomem *ssp_base;
+
+void __init axxia_dt_map_io(void)
+{
+}
+
+void __init axxia_dt_init_early(void)
+{
+}
+
+static struct of_device_id axxia_irq_match[] __initdata = {
+	{
+		.compatible = "arm,cortex-a15-gic",
+		.data = gic_of_init,
+	},
+	{ }
+};
+
+static void __init axxia_dt_init_irq(void)
+{
+	of_irq_init(axxia_irq_match);
+}
+
+void __init axxia_dt_timer_init(void)
+{
+	const char *path;
+	struct device_node *node;
+	void __iomem *base;
+
+	axxia_init_clocks();
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+	{
+		int err = arch_timer_of_register();
+		if (err == 0)
+			err = arch_timer_sched_clock_init();
+		WARN_ON(err);
+	}
+#endif
+
+	if (of_property_read_string(of_aliases, "timer", &path)) {
+		WARN_ON(1);
+		return;
+	}
+
+	node = of_find_node_by_path(path);
+	if (WARN_ON(node == NULL))
+		return;
+
+	base = of_iomap(node, 0);
+	if (WARN_ON(base == NULL))
+		return;
+
+	__sp804_clocksource_and_sched_clock_init(base, "axxia-timer0", 0);
+	sp804_clockevents_init(base + 0x20,
+			       irq_of_parse_and_map(node, 1),
+			       "axxia-timer1");
+}
+
+
+static struct sys_timer axxia_dt_timer = {
+	.init = axxia_dt_timer_init,
+};
+
+static struct mmci_platform_data mmc_plat_data = {
+	.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+	.status	  = NULL,
+	.gpio_wp  = -ENOSYS,
+	.gpio_cd  = -ENOSYS
+};
+
+struct pl061_platform_data gpio0_plat_data = {
+	.gpio_base  = 0,
+	.irq_base   = 0,
+	.directions = 0,	/* startup directions, 1: out, 0: in */
+	.values     = 0		/* startup values */
+};
+
+struct pl061_platform_data gpio1_plat_data = {
+	.gpio_base  = 8,
+	.irq_base   = 0,
+	.directions = 0,	/* startup directions, 1: out, 0: in */
+	.values     = 0		/* startup values */
+};
+
+static struct pl022_ssp_controller ssp_plat_data = {
+	.bus_id         = 0,
+	.num_chipselect = 5,
+	.enable_dma     = 0
+};
+
+static struct of_dev_auxdata axxia_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,primecell", 0x20101E0000ULL,
+		       "mmci",  &mmc_plat_data),
+	OF_DEV_AUXDATA("arm,primecell", 0x2010088000ULL,
+		       "ssp",   &ssp_plat_data),
+	OF_DEV_AUXDATA("arm,primecell", 0x2010092000ULL,
+		       "gpio0", &gpio0_plat_data),
+	OF_DEV_AUXDATA("arm,primecell", 0x2010093000ULL,
+		       "gpio1", &gpio1_plat_data),
+	{}
+};
+
+static inline void
+spidev_chip_select(u32 control, unsigned n)
+{
+	if (control == SSP_CHIP_SELECT)
+		writel(~(1<<n) & 0x1F, ssp_base+0x30);
+	else
+		writel(0x1F, ssp_base+0x30);
+}
+
+static void spi_cs_eeprom0(u32 control) { spidev_chip_select(control, 0); }
+static void spi_cs_eeprom1(u32 control) { spidev_chip_select(control, 1); }
+static void spi_cs_eeprom2(u32 control) { spidev_chip_select(control, 2); }
+
+struct pl022_config_chip spi_eeprom0 = {
+	.iface      = SSP_INTERFACE_MOTOROLA_SPI,
+	.com_mode   = POLLING_TRANSFER,
+	.cs_control = spi_cs_eeprom0
+};
+
+struct pl022_config_chip spi_eeprom1 = {
+	.iface      = SSP_INTERFACE_MOTOROLA_SPI,
+	.com_mode   = POLLING_TRANSFER,
+	.cs_control = spi_cs_eeprom1
+};
+
+struct pl022_config_chip spi_eeprom2 = {
+	.iface      = SSP_INTERFACE_MOTOROLA_SPI,
+	.com_mode   = POLLING_TRANSFER,
+	.cs_control = spi_cs_eeprom2
+};
+
+static struct spi_board_info spi_devs[] __initdata = {
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom0,
+		.bus_num                = 0,
+		.chip_select            = 0,
+		.max_speed_hz           = 12000000,
+		.mode                   = SPI_MODE_0,
+	},
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom1,
+		.bus_num                = 0,
+		.chip_select            = 1,
+		.max_speed_hz           = 12000000,
+		.mode                   = SPI_MODE_0,
+	},
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom2,
+		.bus_num                = 0,
+		.chip_select            = 2,
+		.max_speed_hz           = 12000000,
+		.mode                   = SPI_MODE_0,
+	},
+};
+
+void __init axxia_dt_init(void)
+{
+	l2x0_of_init(0x00400000, 0xfe0fffff);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     axxia_auxdata_lookup, NULL);
+	pm_power_off = NULL; /* TBD */
+
+	spi_register_board_info(spi_devs, ARRAY_SIZE(spi_devs));
+
+	/*
+	 * Setup PL022 to handle chip-select signal automatically
+	 */
+	ssp_base = of_iomap(of_find_compatible_node(NULL, NULL, "arm,pl022"),
+			    0);
+	if (!WARN_ON(ssp_base == NULL)) {
+		/* Use legacy mode, bits 0..4 control nCS[0..4] pins */
+		writel(0x1F, ssp_base+0x30);
+	}
+
+	axxia_pcie_init();
+
+#ifdef CONFIG_I2C
+	axxia_register_i2c_busses();
+#endif
+}
+
+static void axxia_restart(char str, const char *cmd)
+{
+	/* TBD */
+}
+
+DT_MACHINE_START(AXXIA_DT, "LSI Axxia")
+	.dt_compat	= axxia_dt_match,
+	.map_io		= axxia_dt_map_io,
+	.init_early	= axxia_dt_init_early,
+	.init_irq	= axxia_dt_init_irq,
+	.timer		= &axxia_dt_timer,
+	.init_machine	= axxia_dt_init,
+	.handle_irq	= axxia_gic_handle_irq,
+	.restart	= axxia_restart,
+MACHINE_END
diff --git a/arch/arm/mach-axxia/axxia.h b/arch/arm/mach-axxia/axxia.h
new file mode 100644
index 0000000..1c8e800
--- /dev/null
+++ b/arch/arm/mach-axxia/axxia.h
@@ -0,0 +1,5 @@
+#ifndef _AXXIA_H
+
+void axxia_init_clocks(void);
+
+#endif
diff --git a/arch/arm/mach-axxia/clock.c b/arch/arm/mach-axxia/clock.c
new file mode 100644
index 0000000..619ba5d
--- /dev/null
+++ b/arch/arm/mach-axxia/clock.c
@@ -0,0 +1,79 @@
+/*
+ *  linux/arch/arm/mach-axxia/clock.c
+ *
+ *  Copyright (C) 2012 LSI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+
+#define AXXIA_CPU_CLOCK 1400000000
+#define AXXIA_SYS_CLOCK  450000000
+#define AXXIA_DDR_CLOCK 1866000000
+
+#define clk_register_clkdev(_clk, _conid, _devfmt, ...) \
+	do { \
+		struct clk_lookup *cl; \
+		cl = clkdev_alloc(_clk, _conid, _devfmt, ## __VA_ARGS__); \
+		clkdev_add(cl); \
+	} while (0)
+
+
+void __init
+axxia_init_clocks(void)
+{
+	struct clk *clk;
+	int i;
+
+	/* APB clock dummy */
+	clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL,
+				      CLK_IS_ROOT, AXXIA_SYS_CLOCK/2);
+	clk_register_clkdev(clk, "apb_pclk", NULL);
+
+	/* CPU core clock (1400MHz) from CPU_PLL */
+	clk = clk_register_fixed_rate(NULL, "clk_cpu", NULL,
+				      CLK_IS_ROOT, AXXIA_CPU_CLOCK);
+
+	/* APB and System AXI clock from CPU_PLL */
+	clk = clk_register_fixed_rate(NULL, "clk_pclk", NULL,
+				      CLK_IS_ROOT, AXXIA_CPU_CLOCK/9);
+
+	/* DDR3 (interface 1) clock from SMEM1_PLL */
+	clk = clk_register_fixed_rate(NULL, "clk_smem1_2x", NULL,
+				      CLK_IS_ROOT, AXXIA_DDR_CLOCK);
+
+	/* AXIS slow peripheral clock from SMEM1_PLL. */
+	clk = clk_register_fixed_rate(NULL, "clk_per", NULL,
+				      CLK_IS_ROOT, 24000000);
+	/* PL011 UART0 */
+	clk_register_clkdev(clk, NULL, "2010080000.uart");
+	/* PL011 UART1 */
+	clk_register_clkdev(clk, NULL, "2010081000.uart");
+	/* PL011 UART2 */
+	clk_register_clkdev(clk, NULL, "2010082000.uart");
+	/* PL011 UART3 */
+	clk_register_clkdev(clk, NULL, "2010083000.uart");
+	/* PL022 SSP */
+	clk_register_clkdev(clk, NULL, "ssp");
+
+	/* Timers 1MHz clock */
+	clk = clk_register_fixed_rate(NULL, "clk_1mhz", NULL,
+				      CLK_IS_ROOT, 1000000);
+	/* SP804 timers */
+	clk_register_clkdev(clk, NULL, "sp804");
+	for (i = 0; i < 8; i++)
+		clk_register_clkdev(clk, NULL, "axxia-timer%d", i);
+
+	/* Dummy MMC clk */
+	clk = clk_register_fixed_rate(NULL, "clk_mmci", NULL,
+				      CLK_IS_ROOT, 25000000);
+	/* PL180 MMCI */
+	clk_register_clkdev(clk, NULL, "mmci");
+}
diff --git a/arch/arm/mach-axxia/headsmp.S b/arch/arm/mach-axxia/headsmp.S
new file mode 100644
index 0000000..6a36f38
--- /dev/null
+++ b/arch/arm/mach-axxia/headsmp.S
@@ -0,0 +1,43 @@
+/*
+ *  linux/arch/arm/mach-axxia/headsmp.S
+ *
+ *  Cloned from linux/arch/arm/mach-realview/headsmp.S
+ *
+ *  Copyright (c) 2003 ARM Limited
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+	__CPUINIT
+
+/*
+ * Axxia specific entry point for secondary CPUs.  This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(axxia_secondary_startup)
+	mrc	p15, 0, r0, c0, c0, 5
+	bic	r0, #0xff000000
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * We've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+ENDPROC(axxia_secondary_startup)
+
+	.align 2
+1:	.long	.
+	.long	pen_release
diff --git a/arch/arm/mach-axxia/hotplug.c b/arch/arm/mach-axxia/hotplug.c
new file mode 100644
index 0000000..9ecd64d
--- /dev/null
+++ b/arch/arm/mach-axxia/hotplug.c
@@ -0,0 +1,124 @@
+/*
+ *  linux/arch/arm/mach-realview/hotplug.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/cp15.h>
+
+extern volatile int pen_release;
+
+static inline void cpu_enter_lowpower(void)
+{
+	unsigned int v;
+
+	flush_cache_all();
+	asm volatile(
+		"mcr	p15, 0, %1, c7, c5, 0\n"
+	"	mcr	p15, 0, %1, c7, c10, 4\n"
+	/*
+	 * Turn off coherency
+	 */
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	bic	%0, %0, %3\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	"	mrc	p15, 0, %0, c1, c0, 0\n"
+	"	bic	%0, %0, %2\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	  : "=&r" (v)
+	  : "r" (0), "Ir" (CR_C), "Ir" (0x40)
+	  : "cc");
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(
+		"mrc	p15, 0, %0, c1, c0, 0\n"
+	"	orr	%0, %0, %1\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	orr	%0, %0, %2\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	  : "=&r" (v)
+	  : "Ir" (CR_C), "Ir" (0x40)
+	  : "cc");
+}
+
+static void __ref platform_do_lowpower(unsigned int cpu, int *spurious)
+{
+	/*
+	 * there is no power-control hardware on this platform, so all
+	 * we can do is put the core into WFI; this is safe as the calling
+	 * code will have already disabled interrupts
+	 */
+	for (;;) {
+		wfi();
+
+		if (pen_release == cpu_logical_map(cpu)) {
+			/*
+			 * OK, proper wakeup, we're done
+			 */
+			break;
+		}
+
+		/*
+		 * Getting here, means that we have come out of WFI without
+		 * having been woken up - this shouldn't happen
+		 *
+		 * Just note it happening - when we're woken, we can report
+		 * its occurrence.
+		 */
+		(*spurious)++;
+	}
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return 1;
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+	int spurious = 0;
+
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	cpu_enter_lowpower();
+	platform_do_lowpower(cpu, &spurious);
+
+	/*
+	 * bring this CPU back into the world of cache
+	 * coherency, and then restore interrupts
+	 */
+	cpu_leave_lowpower();
+
+	if (spurious)
+		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+	return cpu == 0 ? -EPERM : 0;
+}
diff --git a/arch/arm/mach-axxia/i2c.c b/arch/arm/mach-axxia/i2c.c
new file mode 100644
index 0000000..5f9eff3
--- /dev/null
+++ b/arch/arm/mach-axxia/i2c.c
@@ -0,0 +1,220 @@
+/*
+ * linux/arch/arm/mach-axxia/i2c.c
+ *
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2013 LSI Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/i2c.h>
+#include <linux/i2c-axxia.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+
+#include <mach/irqs.h>
+
+#include "i2c.h"
+
+/*****************************************************************************
+* Local Definitions & State
+*****************************************************************************/
+
+static const char name[] = "axxia_ai2c";
+
+
+static struct axxia_i2c_bus_platform_data       *axxia_i2cx_ports;
+static unsigned int                              axxia_i2cx_port_count;
+static struct platform_device                   *axxia_i2cx_devices;
+static struct platform_device                  **axxia_i2cx_device_ptrs;
+
+
+static inline
+int
+axxia_add_i2c_bus(
+	struct device_node          *np,
+	struct platform_device      *pdev,
+	int                          ndx,
+	int                          bus_id)
+{
+	struct axxia_i2c_bus_platform_data  *pdata;
+	const u32                            pval;
+	const char                          *val;
+	int                                  portno;
+
+	/* Get the port number from the device-tree */
+	if (!of_property_read_u32(np, "port", (u32 *)&pval)) {
+		portno = pval;
+	} else {
+		printk(KERN_ERR "I2C: Can't find port number for %s\n",
+			np->full_name);
+		return -ENXIO;
+	}
+	if (portno > axxia_i2cx_port_count) {
+		printk(KERN_ERR "I2C: port number out of range for %s\n",
+			np->full_name);
+		return -ENXIO;
+	}
+
+	pdata = &axxia_i2cx_ports[ndx];
+	pdata->node  = of_node_get(np);
+
+	pdata->index = portno;
+
+	/* Verify device type */
+	val = of_get_property(np, "device_type", NULL);
+	if (strcmp(val, "i2c")) {
+		printk(KERN_ERR "I2C%d: missing or incorrect device_type for %s\n",
+			portno, np->full_name);
+		return -ENXIO;
+	}
+
+	/* Get or insert bus name */
+	val = of_get_property(np, "bus_name", NULL);
+	if (val)
+		strncpy(pdata->name, val, MAX_AXXIA_I2C_HWMOD_NAME_LEN);
+	else
+		sprintf(pdata->name, "i2c%d", portno);
+
+	pdata->rev = AXXIA_I2C_IP_VERSION_2;        /* AXM55xx */
+
+	pdata->flags = AXXIA_I2C_FLAGS_NONE;
+
+	/* Get the bus number from the device-tree */
+	if (!of_property_read_u32(np, "bus", (u32 *)&pval))
+		pdata->bus_nr = pval;
+	else
+		pdata->bus_nr = ~0;
+
+	/* Fetch config space registers address */
+	if (of_address_to_resource(np, 0, &pdata->dev_space)) {
+		printk(KERN_ERR "%s: Can't get I2C device space !",
+			np->full_name);
+		return -ENXIO;
+	}
+	pdata->dev_space.flags = IORESOURCE_MEM;
+
+	/* Hookup an interrupt handler -- TBD, maybe later */
+	pdata->int_space.start = irq_of_parse_and_map(np, 0);
+	pdata->int_space.flags = IORESOURCE_IRQ;
+
+	if (pdata->bus_nr == ~0) {
+		printk(KERN_INFO
+			"I2C Port %d found; bus#=<auto> '%s'\n",
+			portno, pdata->name);
+	} else {
+		printk(KERN_INFO
+			"I2C Port %d found; bus#=i%d '%s'\n",
+			portno, pdata->bus_nr, pdata->name);
+	}
+	printk(KERN_INFO
+	    "  dev_space start = 0x%012llx, end = 0x%012llx\n",
+	    pdata->dev_space.start, pdata->dev_space.end);
+	printk(KERN_INFO
+	    "  mappedIrq#=%x\n", (unsigned int)pdata->int_space.start);
+
+	/* Fill in the device */
+	pdev->id = ndx;
+	pdev->name = name;
+	pdev->num_resources = 2;
+	pdev->resource = &pdata->dev_space;
+	pdev->dev.platform_data = pdata;
+
+	/* printk(KERN_INFO
+	    "pdev: id=%d name='%s' n_r=%d res=%p d.p_d=%p\n",
+	    pdev->id, pdev->name, pdev->num_resources,
+	    pdev->resource, pdev->dev.platform_data); */
+
+	return 0;
+}
+
+
+/**
+ * axxia_register_i2c_busses - register I2C busses with device descriptors
+ *
+ * Returns 0 on success or an error code.
+ */
+int __init
+axxia_register_i2c_busses(
+	void)
+{
+	int                 i;
+	int                 err;
+	struct device_node *np;
+
+	/* How many of these devices will be needed? */
+	axxia_i2cx_port_count = 0;
+	for_each_compatible_node(np, NULL, "lsi,api2c")
+		axxia_i2cx_port_count++;
+
+	if (axxia_i2cx_port_count == 0)
+		return -ENXIO;
+
+	/* Allocate memory */
+	axxia_i2cx_ports = kzalloc(axxia_i2cx_port_count*
+				   sizeof(struct axxia_i2c_bus_platform_data),
+				   GFP_KERNEL);
+	if (!axxia_i2cx_ports) {
+		printk(KERN_WARNING "I2C: failed to allocate ports array\n");
+		return -ENOMEM;
+	}
+	memset(axxia_i2cx_ports, 0,
+	       axxia_i2cx_port_count*
+	       sizeof(struct axxia_i2c_bus_platform_data));
+
+	axxia_i2cx_devices = kzalloc(axxia_i2cx_port_count*
+				     sizeof(struct platform_device),
+				     GFP_KERNEL);
+	if (!axxia_i2cx_devices) {
+		printk(KERN_WARNING "I2C: failed to allocate devices array\n");
+		return -ENOMEM;
+	}
+	memset(axxia_i2cx_devices, 0,
+	       axxia_i2cx_port_count*sizeof(struct platform_device));
+
+	axxia_i2cx_device_ptrs = kzalloc(axxia_i2cx_port_count*
+					 sizeof(struct platform_device *),
+					 GFP_KERNEL);
+	if (!axxia_i2cx_device_ptrs) {
+		printk(KERN_WARNING
+			"I2C: failed to allocate device ptrs array\n");
+		return -ENOMEM;
+	}
+	memset(axxia_i2cx_device_ptrs, 0,
+	       axxia_i2cx_port_count*sizeof(struct platform_device *));
+
+	/* Now parse and fill in the device entries */
+	i = 0;
+	for_each_compatible_node(np, NULL, "lsi,api2c")
+	{
+	    axxia_i2cx_device_ptrs[i] = &axxia_i2cx_devices[i];
+
+	    err = axxia_add_i2c_bus(np, axxia_i2cx_device_ptrs[i],
+				    i, i+ARCH_AXXIA_MAX_I2C_BUS_NR);
+	    if (err == 0)
+		i++;
+	}
+
+	return platform_add_devices(axxia_i2cx_device_ptrs, i);
+}
diff --git a/arch/arm/mach-axxia/i2c.h b/arch/arm/mach-axxia/i2c.h
new file mode 100644
index 0000000..8e31379
--- /dev/null
+++ b/arch/arm/mach-axxia/i2c.h
@@ -0,0 +1,35 @@
+/*
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2013 LSI Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __ASM__ARCH_AXXIA_I2C_H
+#define __ASM__ARCH_AXXIA_I2C_H
+
+
+/*
+ * Default bus id to expect for an AXXIA platform.
+ */
+#define ARCH_AXXIA_MAX_I2C_BUSSES       1
+#define ARCH_AXXIA_MAX_I2C_BUS_NR       2
+
+
+extern int axxia_register_i2c_busses(void);
+
+
+#endif /* __ASM__ARCH_AXXIA_I2C_H */
diff --git a/arch/arm/mach-axxia/include/mach/axxia-gic.h b/arch/arm/mach-axxia/include/mach/axxia-gic.h
new file mode 100644
index 0000000..5463260
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/axxia-gic.h
@@ -0,0 +1,16 @@
+/*
+ *  arch/arm/mach-axxia/axxia-gic.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __AXXIA_GIC_H
+#define __AXXIA_GIC_H
+
+void axxia_gic_handle_irq(struct pt_regs *regs);
+void axxia_gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
+void axxia_gic_secondary_cluster_init(void);
+void axxia_gic_secondary_init(void);
+
+#endif
diff --git a/arch/arm/mach-axxia/include/mach/debug-macro.S b/arch/arm/mach-axxia/include/mach/debug-macro.S
new file mode 100644
index 0000000..f25a024
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/debug-macro.S
@@ -0,0 +1,35 @@
+/* arch/arm/mach-realview/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 1994-1999 Russell King
+ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifdef CONFIG_DEBUG_VEXPRESS_CA9X4_UART
+#define DEBUG_LL_PHYS_BASE		0x10000000
+#define DEBUG_LL_UART_OFFSET		0x00009000
+#endif
+
+#ifdef CONFIG_DEBUG_VEXPRESS_RS1_UART
+#define DEBUG_LL_PHYS_BASE		0x1c000000
+#define DEBUG_LL_UART_OFFSET		0x00090000
+#endif
+
+#define DEBUG_LL_VIRT_BASE		0xf8000000
+
+#ifndef DEBUG_LL_UART_OFFSET
+#error "Unknown vexpress UART offset"
+#endif
+
+		.macro	addruart,rp,rv,tmp
+		mov	\rp, #DEBUG_LL_UART_OFFSET
+		orr	\rv, \rp, #DEBUG_LL_VIRT_BASE
+		orr	\rp, \rp, #DEBUG_LL_PHYS_BASE
+		.endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-axxia/include/mach/entry-macro.S b/arch/arm/mach-axxia/include/mach/entry-macro.S
new file mode 100644
index 0000000..a14f9e6
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/entry-macro.S
@@ -0,0 +1,5 @@
+	.macro	disable_fiq
+	.endm
+
+	.macro	arch_ret_to_user, tmp1, tmp2
+	.endm
diff --git a/arch/arm/mach-axxia/include/mach/gpio.h b/arch/arm/mach-axxia/include/mach/gpio.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/gpio.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/arch/arm/mach-axxia/include/mach/hardware.h b/arch/arm/mach-axxia/include/mach/hardware.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/hardware.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/arch/arm/mach-axxia/include/mach/io.h b/arch/arm/mach-axxia/include/mach/io.h
new file mode 100644
index 0000000..40924cd
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/io.h
@@ -0,0 +1,39 @@
+/*
+ *  arch/arm/mach-vexpress/include/mach/io.h
+ *
+ *  Copyright (C) 2003 ARM Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <linux/types.h>
+
+#define __io(a)		__typesafe_io(a)
+#define __mem_pci(a)	(a)
+
+/*
+  Make the first argument to ioremap() be phys_addr_t (64 bits in this
+  case) instead of unsigned long.  When __arch_ioremap is defiend,
+  __arch_iounmap must be defined also.  Just use the default for
+  iounmap().
+*/
+
+void __iomem *__axxia_arch_ioremap(phys_addr_t, size_t, unsigned int);
+#define __arch_ioremap __axxia_arch_ioremap
+#define __arch_iounmap __iounmap
+
+#endif
diff --git a/arch/arm/mach-axxia/include/mach/irqs.h b/arch/arm/mach-axxia/include/mach/irqs.h
new file mode 100644
index 0000000..4b10ee7
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/irqs.h
@@ -0,0 +1,4 @@
+#define IRQ_LOCALTIMER		29
+#define IRQ_LOCALWDOG		30
+
+#define NR_IRQS	256
diff --git a/arch/arm/mach-axxia/include/mach/system.h b/arch/arm/mach-axxia/include/mach/system.h
new file mode 100644
index 0000000..f653a8e
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/system.h
@@ -0,0 +1,33 @@
+/*
+ *  arch/arm/mach-vexpress/include/mach/system.h
+ *
+ *  Copyright (C) 2003 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static inline void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle();
+}
+
+#endif
diff --git a/arch/arm/mach-axxia/include/mach/timers.h b/arch/arm/mach-axxia/include/mach/timers.h
new file mode 100644
index 0000000..8aa49c9
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/timers.h
@@ -0,0 +1,39 @@
+/*
+ *  arch/arm/mach-axxia/include/mach/timers.h
+ *
+ *  Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+  This is based on arch/arm/include/asm/hardware/timer-sp.h
+
+  See arch/arm/mach-axxia/timers.c for details.
+ */
+
+#include <asm/hardware/timer-sp.h>
+
+#define AXXIA_TIMER_1_BASE 0x00
+#define AXXIA_TIMER_2_BASE 0x20
+#define AXXIA_TIMER_3_BASE 0x40
+#define AXXIA_TIMER_4_BASE 0x60
+#define AXXIA_TIMER_5_BASE 0x80
+#define AXXIA_TIMER_6_BASE 0xa0
+#define AXXIA_TIMER_7_BASE 0xc0
+#define AXXIA_TIMER_8_BASE 0xe0
+
+void axxia_timer_clocksource_init(void __iomem *, const char *);
+void axxia_timer_clockevents_init(void __iomem *, unsigned int, const char *);
diff --git a/arch/arm/mach-axxia/include/mach/timex.h b/arch/arm/mach-axxia/include/mach/timex.h
new file mode 100644
index 0000000..00029ba
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/timex.h
@@ -0,0 +1,23 @@
+/*
+ *  arch/arm/mach-vexpress/include/mach/timex.h
+ *
+ *  RealView architecture timex specifications
+ *
+ *  Copyright (C) 2003 ARM Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff --git a/arch/arm/mach-axxia/include/mach/uncompress.h b/arch/arm/mach-axxia/include/mach/uncompress.h
new file mode 100644
index 0000000..a386048
--- /dev/null
+++ b/arch/arm/mach-axxia/include/mach/uncompress.h
@@ -0,0 +1,65 @@
+/*
+ *  arch/arm/mach-vexpress/include/mach/uncompress.h
+ *
+ *  Copyright (C) 2003 ARM Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#define AMBA_UART_DR(base)	(*(volatile unsigned char *)((base) + 0x00))
+#define AMBA_UART_LCRH(base)	(*(volatile unsigned char *)((base) + 0x2c))
+#define AMBA_UART_CR(base)	(*(volatile unsigned char *)((base) + 0x30))
+#define AMBA_UART_FR(base)	(*(volatile unsigned char *)((base) + 0x18))
+
+
+#if defined(CONFIG_DEBUG_VEXPRESS_CA9X4_UART)
+#define get_uart_base()	(0x10000000 + 0x00009000)
+#elif defined(CONFIG_DEBUG_VEXPRESS_RS1_UART)
+#define get_uart_base()	(0x1c000000 + 0x00090000)
+#else
+#define get_uart_base() (0UL)
+#endif
+
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+	unsigned long base = get_uart_base();
+
+	if (!base)
+		return;
+
+	while (AMBA_UART_FR(base) & (1 << 5))
+		barrier();
+
+	AMBA_UART_DR(base) = c;
+}
+
+static inline void flush(void)
+{
+	unsigned long base = get_uart_base();
+
+	if (!base)
+		return;
+
+	while (AMBA_UART_FR(base) & (1 << 3))
+		barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-axxia/io.c b/arch/arm/mach-axxia/io.c
new file mode 100644
index 0000000..2fff1b7
--- /dev/null
+++ b/arch/arm/mach-axxia/io.c
@@ -0,0 +1,40 @@
+/*
+ * arch/arm/mach-axxia/io.c
+ *
+ * Support for the LSI Axxia boards based on ARM cores.
+ *
+ * Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+void __iomem *
+__axxia_arch_ioremap(phys_addr_t physical_address, size_t size,
+		     unsigned int flags)
+{
+	unsigned long pfn;
+	unsigned long offset;
+
+	pfn = (unsigned long)((physical_address >> PAGE_SHIFT) & 0xffffffffULL);
+	offset = (unsigned long)(physical_address & (PAGE_SIZE - 1));
+
+	return __arm_ioremap_pfn(pfn, 0, size, flags);
+}
+EXPORT_SYMBOL(__axxia_arch_ioremap);
diff --git a/arch/arm/mach-axxia/pci.c b/arch/arm/mach-axxia/pci.c
new file mode 100644
index 0000000..c1d930d
--- /dev/null
+++ b/arch/arm/mach-axxia/pci.c
@@ -0,0 +1,977 @@
+/*
+ * PCI / PCI-X / PCI-Express support for ARM A15 Cortex parts
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+
+#include <linux/io.h>
+
+#include <asm/sizes.h>
+#include <asm/mach/pci.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm-generic/errno-base.h>
+
+#include <linux/msi.h>
+
+#define AXXIA55xx_NUM_MSI_IRQS 256
+
+#undef PRINT_CONFIG_ACCESSES
+/*#define PRINT_CONFIG_ACCESSES*/
+
+static u32 last_mpage;
+static u32 last_port;
+
+#define U64_TO_U32_LOW(val)	((u32)((val) & 0x00000000ffffffffULL))
+#define U64_TO_U32_HIGH(val)	((u32)((val) >> 32))
+
+#define ACPX1_PCIE_MPAGE_UPPER(n) (0x1010 + (n * 8))
+#define ACPX1_PCIE_MPAGE_LOWER(n) (0x1014 + (n * 8))
+
+struct axxia_pciex_port {
+	unsigned int	index;
+	u8 root_bus_nr;
+	bool link_up;
+	void __iomem	*cfg_addr;
+	void __iomem	*cfg_data;
+	u64 pci_addr;
+	int endpoint;
+	struct device_node	*node;
+	struct resource	utl_regs;
+	struct resource	cfg_space;
+	struct resource	outbound, inbound;
+	dma_addr_t msi_phys;
+};
+
+static struct axxia_pciex_port *axxia_pciex_ports;
+static unsigned int axxia_pciex_port_count = 3;
+
+static void axxia_probe_pciex_bridge(struct device_node *np);
+
+static void __init
+fixup_axxia_pci_bridge(struct pci_dev *dev)
+{
+	/* if we aren't a PCIe don't bother */
+	if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
+		return ;
+
+	/*
+	 * Set the class appropriately for a bridge device
+	 */
+	printk(KERN_INFO
+	       "PCI: Setting PCI Class to PCI_CLASS_BRIDGE_HOST for %04x:%04x\n",
+	       dev->vendor, dev->device);
+	dev->class = PCI_CLASS_BRIDGE_HOST << 8;
+	/*
+	 * Make the bridge transparent
+	 */
+	dev->transparent = 1;
+
+	return ;
+}
+
+DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5101, fixup_axxia_pci_bridge);
+DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5108, fixup_axxia_pci_bridge);
+DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5120, fixup_axxia_pci_bridge);
+
+/* Convert to Bus# to PCIe port# */
+static struct axxia_pciex_port *bus_to_port(struct pci_bus *bus)
+{
+	return axxia_pciex_ports + pci_domain_nr(bus);
+}
+
+/* Validate the Bus#/Device#/Function# */
+static int axxia_pciex_validate_bdf(struct pci_bus *bus, unsigned int devfn)
+{
+	struct axxia_pciex_port *port;
+
+	port = bus_to_port(bus);
+
+	/* Endpoint can not generate upstream(remote) config cycles */
+	if (port->endpoint)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (((!((PCI_FUNC(devfn) == 0) && (PCI_SLOT(devfn) == 0)))
+		&& (bus->number == port->root_bus_nr))
+		|| (!(PCI_SLOT(devfn) == 0)
+		&& (bus->number == port->root_bus_nr+1))) {
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	return 0;
+}
+
+/* Get the configuration access base address */
+static void __iomem *axxia_pciex_get_config_base(struct axxia_pciex_port *port,
+			struct pci_bus *bus, unsigned int devfn)
+{
+	unsigned mpage;
+	u32 addr;
+	int dev, fn;
+	int cfg_type;
+	int relbus;
+
+	if (bus->number == port->root_bus_nr) {
+		return port->cfg_addr;
+	} else {
+		relbus = bus->number - (port->root_bus_nr + 1);
+		dev = ((PCI_SLOT(devfn) & 0xf8) >> 3);
+		fn  = PCI_FUNC(devfn) & 0x7;
+
+		if (dev > 31)
+			return NULL;
+
+		/* Primary bus */
+		if (relbus && (bus->number != port->root_bus_nr))
+			cfg_type = 1;
+		else
+			cfg_type = 0;
+
+		/* build the mpage register */
+		mpage = (bus->number << 11) | (dev << 6) | (cfg_type << 5);
+		mpage |= 0x10;   /* enable MPAGE for configuration access */
+		mpage |= (fn << 19);
+
+		if ((mpage != last_mpage) || (port->index != last_port)) {
+			addr = ((u32)port->cfg_addr)
+					+ ACPX1_PCIE_MPAGE_UPPER(7);
+			writel(0x0, (u32 *) addr);
+			addr = ((u32)port->cfg_addr)
+					+ ACPX1_PCIE_MPAGE_LOWER(7);
+			writel(mpage, (u32 *) addr);
+			/* printk("pcie_get_base: %02x:%02x:%02x setting
+				mpage = 0x%08x in addr = 0x%08x\n", bus->number,
+				dev, fn, mpage, addr);*/
+			last_mpage = mpage;
+			last_port = port->index;
+		}
+		return port->cfg_data;
+	}
+}
+
+/* Read the config space */
+static int
+arm_pciex_axxia_read_config(struct pci_bus *bus, unsigned int devfn,
+		int offset, int len, u32 *val)
+{
+	struct axxia_pciex_port *port = bus_to_port(bus);
+	void __iomem *addr;
+	u32 bus_addr;
+	u32 val32;
+	int bo = offset & 0x3;
+	int rc = PCIBIOS_SUCCESSFUL;
+	u32 bus_addr1;
+
+	if (axxia_pciex_validate_bdf(bus, devfn) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	addr = axxia_pciex_get_config_base(port, bus, devfn);
+
+	if (!addr) {
+		*val = 0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	/*
+	 * addressing is different for local config access vs.
+	 * access through the mapped config space.
+	 */
+	if (bus->number == 0) {
+		int wo = offset & 0xfffffffc;
+		bus_addr = (u32) addr + wo;
+		bus_addr1 = bus_addr;
+	} else {
+		/*
+		 * mapped config space only supports 32-bit access
+		 *
+		 *  AXI address [3:0] is not used at all.
+		 *  AXI address[9:4] becomes register number.
+		 *  AXI address[13:10] becomes Ext. register number
+		 *  AXI address[17:14] becomes 1st DWBE for configuration
+		 *  read only.
+		 *  AXI address[29:27] is used to select one of 8 Mpage
+		 *  registers.
+		 */
+		bus_addr = (u32) addr + (offset << 2);
+		bus_addr1 = bus_addr;
+
+		switch (len) {
+		case 1:
+			bus_addr |=  ((1 << bo)) << 14;
+			break;
+		case 2:
+			bus_addr |=  ((3 << bo)) << 14;
+			break;
+		default:
+			bus_addr |=  (0xf) << 14;
+			break;
+		}
+	}
+	/*
+	 * do the read
+	 */
+	val32 = readl((u32 *)bus_addr);
+
+	switch (len) {
+	case 1:
+		*val = (val32 >> (bo * 8)) & 0xff;
+		break;
+	case 2:
+		*val = (val32 >> (bo * 8)) & 0xffff;
+		break;
+	default:
+		*val = val32;
+		break;
+	}
+
+#ifdef PRINT_CONFIG_ACCESSES
+	printk(KERN_INFO
+		"acp_read_config for PEI%d: %3d  fn=0x%04x o=0x%04x l=%d a=0x%08x v=0x%08x, dev=%d\n",
+			port->index, bus->number, devfn, offset, len,
+			bus_addr, *val, PCI_SLOT(devfn));
+#endif
+	return rc;
+}
+
+/* Write the config space */
+static int arm_pciex_axxia_write_config(struct pci_bus *bus, unsigned int devfn,
+			int offset, int len, u32 val)
+{
+	struct axxia_pciex_port *port = bus_to_port(bus);
+	void __iomem *addr;
+	u32 bus_addr;
+	u32 val32;
+
+	if (axxia_pciex_validate_bdf(bus, devfn) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	addr = axxia_pciex_get_config_base(port, bus, devfn);
+
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * addressing is different for local config access vs.
+	 * access through the mapped config space. We need to
+	 * translate the offset for mapped config access
+	 */
+	if (bus->number == 0) {
+		/* the local ACP RC only supports 32-bit dword config access,
+		 * so if this is a byte or 16-bit word access we need to
+		 * perform a read-modify write
+		 */
+		if (len == 4) {
+			bus_addr = (u32) addr + offset;
+		} else {
+			int bs = ((offset & 0x3) * 8);
+
+			bus_addr = (u32) addr + (offset & 0xfffffffc);
+			val32 = readl((u32 *)bus_addr);
+
+			if (len == 2) {
+				val32 = (val32 & ~(0xffff << bs))
+					| ((val & 0xffff) << bs);
+			} else {
+				val32 = (val32 & ~(0xff << bs))
+					| ((val & 0xff) << bs);
+			}
+
+			val = val32;
+			len = 4;
+		}
+	} else {
+		bus_addr = (u32) addr + (offset << 2) + (offset & 0x3);
+	}
+
+#ifdef PRINT_CONFIG_ACCESSES
+	printk(KERN_INFO
+		"acp_write_config: bus=%3d devfn=0x%04x offset=0x%04x len=%d addr=0x%08x val=0x%08x\n",
+		bus->number, devfn, offset, len, bus_addr, val);
+#endif
+
+	switch (len) {
+	case 1:
+		writeb(val, (u8 *)(bus_addr));
+		break;
+	case 2:
+		writew(val, (u16 *)(bus_addr));
+		break;
+	default:
+		writel(val, (u32 *)(bus_addr));
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops axxia_pciex_pci_ops = {
+	.read  = arm_pciex_axxia_read_config,
+	.write = arm_pciex_axxia_write_config,
+};
+
+/* ACP PCIe ISR to handle Legacy Interrupts */
+static irqreturn_t
+acp_pcie_isr(int irq, void *arg)
+{
+	u32 intr_status;
+	u32 msg_fifo_stat;
+	u32 msg_fifo_info;
+	u8  externalPciIntr = 0;
+	struct axxia_pciex_port *port = (struct axxia_pciex_port *)arg;
+	void __iomem *mbase = (void __iomem *)port->cfg_addr;
+
+	/* read the PEI interrupt status register */
+	intr_status = readl(mbase+0x10c0);
+
+	/* check if this is a PCIe message from an external device */
+	if (intr_status & 0x00000010) {
+		externalPciIntr = 1;
+
+		msg_fifo_stat = readl(mbase+0x10b4);
+
+		/* loop until the message fifo is empty */
+		while ((msg_fifo_stat & 0x01) == 0)  {
+			u8 bus, dev, fn;
+			u8 msg_type;
+			msg_fifo_info = readl(mbase+0x10b0);
+
+			bus = (msg_fifo_info >> 16) & 0xff;
+			dev = (msg_fifo_info >> 11) & 0x1f;
+			fn  = (msg_fifo_info >>  8) & 0x07;
+			msg_type = msg_fifo_info & 0xff;
+
+			/* print out the BDF and message type.
+			 * We ignore the common message types.
+			 */
+			switch (msg_type) {
+			case 0x20:  /*    assert_INTa */
+				printk(KERN_INFO "PEI%d --> INTa asserted\n",
+					port->index);
+				break;
+			case 0x21:  /*    assert_INTb */
+				printk(KERN_INFO "PEI%d --> INTb asserted\n",
+					port->index);
+				break;
+			case 0x22:  /*    assert_INTc */
+				printk(KERN_INFO "PEI%d --> INTc asserted\n",
+					port->index);
+				break;
+			case 0x23:  /*    assert_INTd */
+				printk(KERN_INFO "PEI%d --> INTd asserted\n",
+					port->index);
+				break;
+			case 0x24:  /* de-assert_INTa */
+				printk(KERN_INFO "PEI%d --> INTa de-asserted\n",
+					port->index);
+				break;
+			case 0x25:  /* de-assert_INTb */
+				printk(KERN_INFO "PEI%d --> INTb de-asserted\n",
+					port->index);
+				break;
+			case 0x26:  /* de-assert_INTc */
+				printk(KERN_INFO "PEI%d --> INTc de-asserted\n",
+					port->index);
+				break;
+			case 0x27:  /* de-assert_INTd */
+				printk(KERN_INFO "PEI%d --> INTd de-asserted\n",
+					port->index);
+				break;
+			default:
+				printk(KERN_INFO "BDF %02x:%02x.%x sent msgtype 0x%02x\n",
+						bus, dev, fn, msg_type);
+				break;
+			}
+
+			/* re-read fifo status */
+			msg_fifo_stat = readl(mbase+0x10b4);
+		}
+	} else {
+		/* Ignore the common interrupts, still need to figure out what
+		 * they all mean.*/
+		if (intr_status & 0xf3ffffab) {
+			u32 t2a_err_stat;
+			u32 t2a_other_err_stat;
+			u32 int_enb;
+			u32 linkStatus;
+			u32 offset;
+
+			printk(KERN_ERR
+				"ACP_PCIE_ISR: got PEI%d error interrupt 0x%08x\n",
+				intr_status, port->index);
+
+			linkStatus = readl(mbase+0x117c);
+			printk(KERN_ERR "link_status (0x117c) = 0x%08x\n",
+				linkStatus);
+
+			if (intr_status & 0x00020000) {
+				t2a_err_stat = readl(mbase+0x1170);
+				printk(KERN_ERR "t2a_fn_indp_err_stat = 0x%08x\n",
+					t2a_err_stat);
+
+				int_enb = readl(mbase+0x10c4);
+				int_enb &= 0xfffdffff;
+				writel(int_enb, mbase + 0x10c4);
+			}
+
+			if (intr_status & 0x00040000) {
+				t2a_other_err_stat = readl(mbase+0x1174);
+				printk(KERN_ERR "t2a_fn_indp_other_err_stat = 0x%08x\n",
+					t2a_other_err_stat);
+				int_enb = readl(mbase+0x10c4);
+				int_enb &= 0xfffbffff;
+				writel(int_enb, mbase + 0x10c4);
+			}
+
+			if (intr_status & 0x00000800) {
+				printk(KERN_INFO "pci_config = 0x%08x\n",
+					readl(mbase + 0x1000));
+				printk(KERN_INFO "pci_status = 0x%08x\n",
+					readl(mbase + 0x1004));
+				int_enb = readl(mbase + 0x10c4);
+				int_enb &= 0xfffff7ff;
+				writel(int_enb, mbase + 0x10c4);
+			}
+			/*
+			 * dump all the potentially interesting PEI registers
+			 */
+			for (offset = 0x114c; offset <= 0x1180; offset += 4) {
+				printk(KERN_INFO "  0x%04x : 0x%08x\n", offset,
+					readl(mbase + offset));
+			}
+		}
+	}
+
+	/*
+	 *  We clear all the interrupts in the PEI status, even though
+	 *  interrupts from external devices have not yet been handled.
+	 *  That should be okay, since the PCI IRQ in the MPIC won't be
+	 *  re-enabled until all external handlers have been called.
+	 */
+	writel(intr_status, mbase + 0x10c0);
+	return externalPciIntr ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* ACP PCIe ISR to handle MSI Interrupts */
+static irqreturn_t
+acp_pcie_MSI_isr(int irq, void *arg) {
+	u32 intr_status;
+	u8  msiIntr = 0, bit = 0;
+	struct axxia_pciex_port *port = (struct axxia_pciex_port *)arg;
+	void __iomem *mbase = (void __iomem *)port->cfg_addr;
+	u32 statusReg, statusVal;
+
+	/* read the PEI MSI Level2 interrupt status register */
+	intr_status = readl(mbase+0x1230);
+
+	/* check if this is a PCIe MSI interrupt */
+	if (intr_status & 0x0000ffff) {
+		msiIntr = 1;
+		for (bit = 0; bit < 16; bit++) {
+			if (intr_status & (0x1 << bit)) {
+				printk(KERN_INFO "PEI%d --> MSI%d-%d interrupt asserted\n",
+					port->index, bit*16, ((bit+1)*16)-1);
+				/* MSI Level 1 interrupt status */
+				statusReg = (0x123c + (0xc * bit));
+				statusVal = readl(mbase+statusReg);
+				printk(KERN_INFO "MSI status Reg 0x%x val = 0x%x\n",
+					statusReg, statusVal);
+				/* clear statusReg */
+				writel(statusVal, mbase+statusReg);
+			}
+		}
+	}
+	/*
+	 *  We clear all the interrupts in the PEI status, even though
+	 *  interrupts from MSI devices have not yet been handled.
+	 */
+	writel(intr_status, mbase + 0x1230);
+	return msiIntr ? IRQ_NONE : IRQ_HANDLED;
+}
+
+
+/* PCIe setup function */
+int axxia_pcie_setup(int portno, struct pci_sys_data *sys)
+{
+	struct axxia_pciex_port *port;
+	u32 pci_config, pci_status, link_state;
+	int i, num_pages, err;
+	u32 mpage_lower, pciah, pcial;
+	u64 size, bar0_size;
+	void __iomem *cfg_addr = NULL;
+	void __iomem *cfg_data = NULL;
+	void __iomem *tpage_base;
+	int mappedIrq;
+	u32 inbound_size;
+
+	port = &axxia_pciex_ports[sys->domain];
+	printk(KERN_INFO "cfg_space start = 0x%012llx, end = 0x%012llx\n",
+		port->cfg_space.start, port->cfg_space.end);
+	printk(KERN_INFO "utl_regs start = 0x%012llx, end = 0x%012llx\n",
+		port->utl_regs.start, port->utl_regs.end);
+	port->root_bus_nr = sys->busnr;
+
+	/* 1M external config */
+	cfg_data = ioremap(port->cfg_space.start, 0x100000);
+	if (cfg_data == NULL) {
+		printk(KERN_ERR "%s: Can't map external config space !",
+			port->node->full_name);
+		goto fail;
+	}
+	port->cfg_data = cfg_data;
+
+	/* IORESOURCE_MEM */
+	port->outbound.name = "PCIe MEM";
+	port->outbound.start = port->cfg_space.start - 0x38000000;
+	/* allocate 256 M -- 2 MPAGEs worth */
+	port->outbound.end = port->outbound.start + 0x10000000 - 1;
+	port->outbound.flags = IORESOURCE_MEM;
+
+	if (request_resource(&iomem_resource, &port->outbound))
+		panic("Request PCIe Memory resource failed for port %d\n",
+		      portno);
+
+	pci_add_resource_offset(&sys->resources, &port->outbound,
+			sys->mem_offset);
+	printk(KERN_INFO "port res start = 0x%012llx, end = 0x%012llx\n",
+		port->outbound.start, port->outbound.end);
+	printk(KERN_INFO "port system mem_offset start = 0x%012llx\n",
+		sys->mem_offset);
+
+	/* 4K  internal config */
+	cfg_addr = ioremap(port->utl_regs.start, 0x10000);
+	if (cfg_addr == NULL) {
+		printk(KERN_ERR "%s: Can't map external config space !",
+			port->node->full_name);
+		goto fail;
+	}
+	port->cfg_addr = cfg_addr;
+	printk(KERN_INFO "cfg_addr for port %d = 0x%8x\n", port->index,
+		(unsigned int)port->cfg_addr);
+	pci_config = readl(cfg_addr);
+#ifdef PRINT_CONFIG_ACCESSES
+	printk(KERN_INFO "pci_vendor = 0x%08x\n", pci_config);
+#endif
+
+	/* hookup an interrupt handler */
+	printk(KERN_INFO "PCIE%d mapping interrupt\n", port->index);
+	mappedIrq = irq_of_parse_and_map(port->node, 0);
+
+	if (sys->domain == 0) {
+		/* IRQ# 68 for PEI0 */
+		mappedIrq = 100;
+	} else if (sys->domain == 2) {
+		/* IRQ# 70 for PEI2 */
+		mappedIrq = 102;
+	}
+	printk(KERN_INFO "Requesting irq#%d for PEI%d Legacy INTs\n",
+			mappedIrq, port->index);
+	err = request_irq(mappedIrq, acp_pcie_isr,
+			  IRQF_SHARED, "acp_pcie", port);
+	if (err) {
+		printk(KERN_ERR "request_irq failed!!!! for IRQ# %d err = %d\n",
+			mappedIrq, err);
+		goto fail;
+	}
+
+	/* MSI INTS for PEI0 */
+	if (sys->domain == 0) {
+		/* IRQ# 73-88 for PEI0 MSI INTs */
+		for (mappedIrq = 73; mappedIrq <= 88; mappedIrq++) {
+			printk(KERN_INFO
+				"Requesting irq#%d for PEI0 MSI INTs\n",
+				mappedIrq+32);
+			err = request_irq(mappedIrq+32, acp_pcie_MSI_isr,
+				IRQF_SHARED, "acp_pcie_MSI", port);
+			if (err) {
+				printk(KERN_ERR
+					"request_irq failed!!!! for IRQ# %d err = %d\n",
+					mappedIrq+32, err);
+				goto fail;
+			}
+		}
+	}
+
+	/* Setup as root complex */
+	pci_config = readl(cfg_addr + 0x1000);
+#ifdef PRINT_CONFIG_ACCESSES
+	printk("pci_config = 0x%08x\n", pci_config);
+#endif
+
+	pci_status = readl(cfg_addr + 0x1004);
+	link_state = (pci_status & 0x3f00) >> 8;
+	printk(KERN_INFO
+		"PCIE%d status = 0x%08x : PCI link state = 0x%x\n",
+		port->index, pci_status, link_state);
+
+	/* make sure the ACP device is configured as PCI Root Complex */
+	if ((pci_status & 0x18) != 0x18) {
+		printk(KERN_INFO
+			"ACP device is not PCI Root Complex! status = 0x%08x\n",
+			pci_status);
+		goto fail;
+	}
+
+	/* make sure the link is up */
+	if (link_state != 0xb) {
+		/* reset */
+		printk("PCI link in bad state - resetting\n");
+		pci_config |= 1;
+		writel(pci_config, cfg_addr + 0x1000);
+		msleep(1000);
+		pci_status = readl(cfg_addr + 0x1004);
+		link_state = (pci_status & 0x3f00) >> 8;
+		printk(KERN_INFO "PCI link state now = 0x%x\n", link_state);
+		if (link_state != 0xb) {
+			printk(KERN_INFO "PCI link still in bad state - giving up!\n");
+			goto fail;
+		}
+	}
+
+	/* ACP X1 setup MPAGE registers */
+	/*
+	 * MPAGE7 is dedicated to config access, so we only
+	 *  have 7 128MB pages available for memory i/o.
+	 *  Calculate how many pages we need
+	 */
+	size = 7 * 1024*128*1024;
+	num_pages = ((size - 1) >> 27) + 1;
+	pciah = U64_TO_U32_HIGH(port->pci_addr);
+	pcial = U64_TO_U32_LOW(port->pci_addr);
+	for (i = 0; i < num_pages; i++) {
+		mpage_lower = (pcial & 0xf8000000);
+		mpage_lower |= 0x0;
+		writel(pciah, cfg_addr + ACPX1_PCIE_MPAGE_UPPER(i));
+		writel(mpage_lower, cfg_addr + ACPX1_PCIE_MPAGE_LOWER(i));
+		pcial += 0x08000000;
+	}
+
+	inbound_size = (u32) (port->inbound.end - port->inbound.start + 1);
+
+	/* configures the RC Memory Space Configuration Register */
+	writel(inbound_size, cfg_addr + 0x11f4);
+
+	/* write all 1s to BAR0 register */
+	writel(0xffffffff, cfg_addr + 0x10);
+
+	/* read back BAR0 */
+	bar0_size = readl(cfg_addr + 0x10);
+	if ((bar0_size & inbound_size) != inbound_size)
+		printk(KERN_INFO "Writing/Reading BAR0 reg failed\n");
+
+	/* set the BASE0 address to start of PCIe base */
+	writel(port->inbound.start, cfg_addr + 0x10);
+
+	/* setup TPAGE registers for inbound mapping */
+	/* We set the MSB of each TPAGE to select 128-bit AXI access.
+	 * For the address field we simply program an incrementing value
+	 * to map consecutive pages
+	 */
+	tpage_base = cfg_addr + 0x1050;
+	for (i = 0; i < 8; i++) {
+		writel((0x80000000 + i), tpage_base);
+		tpage_base += 4;
+	}
+
+
+	return 1;
+fail:
+	if (cfg_data)
+		iounmap(cfg_data);
+	if (cfg_addr)
+		iounmap(cfg_addr);
+	return 0;
+}
+
+/* Just a dummy arch_setup_msi_irq() function */
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	return 0;
+}
+
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+}
+
+
+
+/* Scan PCIe bus */
+static struct pci_bus __init *
+axxia_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pci_bus *bus;
+	struct axxia_pciex_port *port;
+
+	/* get the pointer to port struct from domain# */
+	port = &axxia_pciex_ports[sys->domain];
+
+	if (nr < axxia_pciex_port_count) {
+		bus = pci_scan_root_bus(NULL, sys->busnr,
+			&axxia_pciex_pci_ops, sys, &sys->resources);
+	} else {
+		bus = NULL;
+		BUG();
+	}
+
+	return bus;
+}
+
+/* MSI setup */
+static void __devinit axxia_pcie_msi_enable(struct pci_dev *dev)
+{
+	u32 pci_higher = 0, msi_lower = 0;
+	u16 flag_val;
+	int pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	struct axxia_pciex_port *port;
+	void *msi_virt;
+	int device, fn, bus_num;
+	static u32 pci_lower, msi_count;
+
+	port = bus_to_port(dev->bus);
+
+	if (pos <= 0) {
+		dev_err(&dev->dev, "skipping MSI enable\n");
+		printk(KERN_INFO "skipping MSI enable\n");
+		return;
+	}
+
+	/* MSI applicable only to PEI0 */
+	if (port->index == 0) {
+		/* MSI is generated when EP writes to address mapped */
+		if (msi_lower == 0) {
+			/* MSI support only in PEI0 */
+			/* allocate 1K to manage 256 MSIs
+			 * one for each endpoint */
+
+			if ((!dma_set_coherent_mask(&dev->dev,
+				DMA_BIT_MASK(64))) ||
+				(!dma_set_coherent_mask(&dev->dev,
+				DMA_BIT_MASK(32)))) {
+				msi_virt = dma_alloc_coherent(&dev->dev,
+					1024, &(port->msi_phys), GFP_KERNEL);
+			} else {
+				printk(KERN_INFO
+					"No suitable DMA available. MSI cannot be supported\n");
+				return;
+			}
+			msi_lower = (u32)port->msi_phys;
+			/* Please note we have 1:1 mapping for inbound */
+			pci_lower = port->inbound.start + msi_lower;
+			printk("PEI%d dma_alloc_coherent msiAddr = 0x%x\n",
+				port->index, msi_lower);
+			writel(msi_lower>>10, port->cfg_addr + 0x1190);
+		}
+		device = ((PCI_SLOT(dev->devfn) & 0xf8) >> 3);
+		fn  = PCI_FUNC(dev->devfn) & 0x7;
+		bus_num = dev->bus->number;
+
+		printk(KERN_INFO
+			"PEI%d axxia_pcie_msi_enable Found MSI%d, msi_lower = 0x%x for bus_num = %d, dev = %d, fn = %d\n",
+			port->index, msi_count, msi_lower,
+			bus_num, device, fn);
+		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+			pci_lower);
+		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+			pci_higher);
+
+		/* Enable MSI */
+		dev->msi_enabled = 1;
+
+		pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &flag_val);
+		flag_val = flag_val | 0x1;
+		pci_write_config_word(dev, pos + PCI_MSI_FLAGS,
+			(flag_val | 0x1));
+
+		/* for next EP MSI */
+		pci_lower = pci_lower + 0x4;
+		msi_count++;
+	}
+	return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, axxia_pcie_msi_enable);
+
+/* Port definition struct
+ * Please note: PEI core#1 is not used in AXM5500 */
+static struct hw_pci __refdata axxia_pcie_hw[] = {
+	[0] = {
+		.nr_controllers = 1,
+		.domain = 0,
+		.swizzle = pci_std_swizzle,
+		.setup = axxia_pcie_setup,
+		.scan = axxia_pcie_scan_bus
+	},
+	[1] = {
+		.nr_controllers = 0,
+		.domain = 1
+	},
+	[2] = {
+		.nr_controllers = 1,
+		.domain = 2,
+		.swizzle = pci_std_swizzle,
+		.setup = axxia_pcie_setup,
+		.scan = axxia_pcie_scan_bus
+	}
+};
+
+/* Initialize PCIe */
+void __init axxia_pcie_init(void)
+{
+	struct device_node *np;
+	/* allocate memory */
+	axxia_pciex_ports = kzalloc(axxia_pciex_port_count
+		* sizeof(struct axxia_pciex_port), GFP_KERNEL);
+
+	if (!axxia_pciex_ports) {
+		printk(KERN_WARNING "PCIE: failed to allocate ports array\n");
+		return;
+	}
+	for_each_compatible_node(np, NULL, "lsi,plb-pciex")
+		axxia_probe_pciex_bridge(np);
+
+	pci_common_init(&axxia_pcie_hw[0]);
+	pci_common_init(&axxia_pcie_hw[1]);
+	pci_common_init(&axxia_pcie_hw[2]);
+
+	return;
+}
+
+static void axxia_probe_pciex_bridge(struct device_node *np)
+{
+	struct axxia_pciex_port *port;
+	u32 pval;
+	int portno;
+	const char *val;
+	const u32 *field;
+	int rlen;
+	int pna = of_n_addr_cells(np);
+	int num = pna + 5;
+	u64 size;
+	u64 pci_addr;
+
+	/* Get the port number from the device-tree */
+	if (!of_property_read_u32(np, "port", &pval)) {
+		portno = pval;
+		if (portno == 1) {
+			/* only PCIe0 and PCIe2 are supported in AXM5500 */
+			return;
+		}
+		printk(KERN_INFO "PCIE Port %d found\n", portno);
+	} else {
+		printk(KERN_ERR "PCIE: Can't find port number for %s\n",
+		       np->full_name);
+		return;
+	}
+
+	if (portno > axxia_pciex_port_count) {
+		printk(KERN_ERR "PCIE: port number out of range for %s\n",
+		       np->full_name);
+		return;
+	}
+
+	port = &axxia_pciex_ports[portno];
+	port->index = portno;
+
+	port->node = of_node_get(np);
+
+	/* Check if device_type property is set to "pci" or "pci-endpoint".
+	 * Resulting from this setup this PCIe port will be configured
+	 * as root-complex or as endpoint.
+	 */
+	val = of_get_property(port->node, "device_type", NULL);
+	if (!strcmp(val, "pci-endpoint")) {
+		port->endpoint = 1;
+	} else if (!strcmp(val, "pci")) {
+		port->endpoint = 0;
+	} else {
+		printk(KERN_ERR "PCIE%d: missing or incorrect device_type for %s\n",
+		       portno, np->full_name);
+		return;
+	}
+	printk(KERN_ERR "PCIE%d: endpoint = %d\n", portno, port->endpoint);
+
+	/* Fetch config space registers address */
+	if (of_address_to_resource(np, 0, &port->cfg_space)) {
+		printk(KERN_ERR "%s: Can't get PCI-E config space !",
+		       np->full_name);
+		return;
+	}
+	printk(KERN_INFO
+		"cfg_space start = 0x%012llx, end = 0x%012llx\n",
+		port->cfg_space.start, port->cfg_space.end);
+
+	/* Fetch host bridge internal registers address */
+	if (of_address_to_resource(np, 1, &port->utl_regs)) {
+		printk(KERN_ERR "%s: Can't get UTL register base !",
+		       np->full_name);
+		return;
+	}
+	printk(KERN_INFO
+		"utl_regs start = 0x%012llx, end = 0x%012llx\n",
+		port->utl_regs.start, port->utl_regs.end);
+
+	field = of_get_property(np, "ranges", &rlen);
+	if (field == NULL)
+		printk("not able to get ranges\n");
+
+	pci_addr = of_read_number(field + 1, 2);
+	printk(KERN_INFO "pci_addr = 0x%012llx\n", pci_addr);
+	port->pci_addr = pci_addr;
+
+	printk(KERN_INFO "%s PCIE%d config base = 0x%012llx\n",
+		np->full_name, port->index, port->utl_regs.start);
+
+	/* Default 256 MB */
+	port->inbound.start = 0;
+	size = 0x10000000;
+	port->inbound.end = size - 1;
+	port->inbound.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+	/* Get dma-ranges property */
+	field = of_get_property(np, "dma-ranges", &rlen);
+	if (field == NULL) {
+		printk(KERN_INFO "not able to get dma-ranges\n");
+		/* use default */
+		return;
+	}
+
+	/* Walk it */
+	while ((rlen -= num * 4) >= 0) {
+		u64 pci_addr = of_read_number(field + 1, 2);
+		u64 cpu_addr = of_read_number(field + 3, 1);
+		size = of_read_number(field + pna + 3, 2);
+		field += num;
+
+		/* We currently only support memory at 0, and pci_addr
+		 * within 32 bits space and 1:1 mapping
+		 */
+		if (cpu_addr != 0 || pci_addr > 0xffffffff) {
+			printk(KERN_WARNING
+			       "%s: Ignored unsupported dma range 0x%016llx...0x%016llx -> 0x%016llx\n",
+				np->full_name, pci_addr,
+				pci_addr + size - 1, cpu_addr);
+			continue;
+		}
+		/* Use that */
+		port->inbound.start = pci_addr;
+		/* Beware of 32 bits resources */
+		if (sizeof(resource_size_t) == sizeof(u32) &&
+			(pci_addr + size) > 0x100000000ull) {
+			port->inbound.end = 0xffffffff;
+		} else
+			port->inbound.end = port->inbound.start + size - 1;
+		break;
+	}
+	printk(KERN_INFO "inbound start = 0x%016llx, end = 0x%016llx\n",\
+		port->inbound.start, port->inbound.end);
+}
diff --git a/arch/arm/mach-axxia/pci.h b/arch/arm/mach-axxia/pci.h
new file mode 100644
index 0000000..d4211a4
--- /dev/null
+++ b/arch/arm/mach-axxia/pci.h
@@ -0,0 +1 @@
+void axxia_pcie_init(void);
diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
new file mode 100644
index 0000000..3b202b9
--- /dev/null
+++ b/arch/arm/mach-axxia/platsmp.c
@@ -0,0 +1,175 @@
+/*
+ *  linux/arch/arm/mach-axxia/platsmp.c
+ *
+ *  Copyright (C) 2012 LSI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <asm/smp_plat.h>
+#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+
+#include <mach/axxia-gic.h>
+
+/*
+ * Control for which core is the next to come out of the secondary
+ * boot "holding pen".
+ */
+volatile int __cpuinitdata pen_release = -1;
+
+extern void axxia_secondary_startup(void);
+
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static DEFINE_RAW_SPINLOCK(boot_lock);
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+	/*
+	 * If this isn't the first physical core in a secondary cluster
+	 * then run the standard GIC secondary init routine. Otherwise,
+	 * run the Axxia secondary cluster init routine.
+	 */
+	if (cpu_logical_map(cpu) % 4)
+		axxia_gic_secondary_init();
+	else
+		axxia_gic_secondary_cluster_init();
+
+	/*
+	 * Let the primary processor know we're out of the
+	 * pen, then head off into the C entry point.
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	_raw_spin_lock(&boot_lock);
+	_raw_spin_unlock(&boot_lock);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+	int phys_cpu, cluster;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one.
+	 */
+	_raw_spin_lock(&boot_lock);
+
+	/*
+	 * In the Axxia, the bootloader does not put the secondary cores
+	 * into a wait-for-event (wfe) or wait-for-interrupt (wfi) state
+	 * because of the multi-cluster design (i.e., there's no way for
+	 * the primary core in cluster 0 to send an event or interrupt
+	 * to secondary cores in the other clusters).
+	 *
+	 * Instead, the secondary cores are immediately put into a loop
+	 * that polls the "pen_release" global and MPIDR register. The two
+	 * are compared and if they match, a secondary core then executes
+	 * the Axxia secondary startup code.
+	 *
+	 * Here we convert the "cpu" variable to be compatible with the
+	 * ARM MPIDR register format (CLUSTERID and CPUID):
+	 *
+	 * Bits:   |11 10 9 8|7 6 5 4 3 2|1 0
+	 *         | CLUSTER | Reserved  |CPU
+	 */
+	phys_cpu = cpu_logical_map(cpu);
+	cluster = (phys_cpu / 4) << 8;
+	phys_cpu = cluster + (phys_cpu % 4);
+
+	/* Release the specified core */
+	write_pen_release(phys_cpu);
+
+	/* Wait for so long, then give up if nothing happens ... */
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * Now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish.
+	 */
+	_raw_spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init smp_init_cpus(void)
+{
+	int ncores = 0;
+	struct device_node *np;
+	u32 cpu_num;
+
+	for_each_node_by_name(np, "cpu") {
+		if (++ncores > nr_cpu_ids) {
+			pr_warn("SMP: More cores (%u) in DTB than max (%u)\n",
+				ncores, nr_cpu_ids);
+			break;
+		}
+		if (!of_property_read_u32(np, "reg", &cpu_num)) {
+			if (cpu_num >= 0 && cpu_num < 16)
+				set_cpu_possible(cpu_num, true);
+			else
+				pr_warn("SMP: Invalid cpu number (%u)\n",
+					 cpu_num);
+		}
+	}
+
+	set_smp_cross_call(axxia_gic_raise_softirq);
+}
+
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i;
+
+	/*
+	 * Initialise the present map, which describes the set of CPUs
+	 * actually populated at the present time.
+	 */
+	for (i = 0; i < max_cpus; i++)
+		set_cpu_present(i, true);
+
+	/*
+	 * This is the entry point of the routine that the secondary
+	 * cores will execute once they are released from their
+	 * "holding pen".
+	 */
+	*(u32 *)phys_to_virt(0x10000020) =
+		virt_to_phys(axxia_secondary_startup);
+}
diff --git a/arch/arm/mach-axxia/timers.c b/arch/arm/mach-axxia/timers.c
new file mode 100644
index 0000000..17b0c73
--- /dev/null
+++ b/arch/arm/mach-axxia/timers.c
@@ -0,0 +1,225 @@
+/*
+ *  arch/arm/mach-axxia/timers.c
+ *
+ *  Copyright (C) 2012 LSI
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+  This is based on arch/arm/common/timer-sp.c.
+
+  The timers used are SP804s, but, there are 8 timers instead of 2,
+  AND the ID registers are missing.
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/sched_clock.h>
+#include <asm/hardware/arm_timer.h>
+
+struct axxia_timer {
+	struct clock_event_device  dev;
+	struct irqaction           irqaction;
+	void __iomem               *base;
+	unsigned long              reload;
+};
+
+#define timer_to_clock_event(_x) container_of(_x, struct axxia_timer, dev)
+
+static void __iomem *sched_clock_base;
+
+static u32 sp804_read(void)
+{
+	return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+}
+
+/**
+ * axxia_timer_set_mode
+ */
+static void
+axxia_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+	struct axxia_timer *timer = timer_to_clock_event(evt);
+	unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+
+	printk(KERN_INFO
+	       "axxia_timer_set_mode: CPU#%d set mode %d on timer %s\n",
+	       smp_processor_id(), mode, timer->dev.name);
+
+	writel(ctrl, timer->base + TIMER_CTRL);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel(timer->reload, timer->base + TIMER_LOAD);
+		ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* period set, and timer enabled in 'next_event' hook */
+		ctrl |= TIMER_CTRL_ONESHOT;
+		break;
+
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		break;
+	}
+
+	writel(ctrl, timer->base + TIMER_CTRL);
+}
+
+/**
+ * axxia_timer_set_next_event
+ *
+ */
+static int
+axxia_timer_set_next_event(unsigned long next, struct clock_event_device *evt)
+{
+	struct axxia_timer *timer = timer_to_clock_event(evt);
+	unsigned long ctrl;
+
+	ctrl = readl(timer->base + TIMER_CTRL);
+	writel(next, timer->base + TIMER_LOAD);
+	writel(ctrl | TIMER_CTRL_ENABLE, timer->base + TIMER_CTRL);
+
+	return 0;
+}
+
+
+/**
+ * axxia_timer_handler - IRQ handler for the timer.
+ *
+ */
+static irqreturn_t
+axxia_timer_handler(int irq, void *dev_id)
+{
+	struct axxia_timer *timer = (struct axxia_timer *)dev_id;
+
+	/* clear the interrupt */
+	writel(1, timer->base + TIMER_INTCLR);
+
+	timer->dev.event_handler(&timer->dev);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * axxia_timer_get_clock_rate
+ *
+ */
+static long __init
+axxia_timer_get_clock_rate(const char *name)
+{
+	struct clk *clk;
+	long rate;
+	int err;
+
+	clk = clk_get_sys("sp804", name);
+	if (IS_ERR(clk)) {
+		pr_err("sp804: %s clock not found: %d\n", name,
+			(int)PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
+
+	err = clk_prepare(clk);
+	if (err) {
+		pr_err("sp804: %s clock failed to prepare: %d\n", name, err);
+		clk_put(clk);
+		return err;
+	}
+
+	err = clk_enable(clk);
+	if (err) {
+		pr_err("sp804: %s clock failed to enable: %d\n", name, err);
+		clk_unprepare(clk);
+		clk_put(clk);
+		return err;
+	}
+
+	rate = clk_get_rate(clk);
+	if (rate < 0) {
+		pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
+		clk_disable(clk);
+		clk_unprepare(clk);
+		clk_put(clk);
+	}
+
+	return rate;
+}
+
+void __init
+axxia_timer_clocksource_init(void __iomem *base, const char *name)
+{
+	long rate;
+
+	rate = axxia_timer_get_clock_rate(name);
+	if (WARN_ON(rate < 0))
+		return;
+
+	/* Setup timer 0 as free-running clocksource */
+	writel(0, base + TIMER_CTRL);
+	writel(0xffffffff, base + TIMER_LOAD);
+	writel(0xffffffff, base + TIMER_VALUE);
+	writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+		base + TIMER_CTRL);
+
+	clocksource_mmio_init(base + TIMER_VALUE, name,
+		rate, 200, 32, clocksource_mmio_readl_down);
+
+	sched_clock_base = base;
+	setup_sched_clock(sp804_read, 32, rate);
+}
+
+void __init
+axxia_timer_clockevents_init(void __iomem *base,
+			     unsigned int irq, const char *name)
+{
+	struct axxia_timer *evt;
+	long               rate;
+
+	rate = axxia_timer_get_clock_rate(name);
+	if (WARN_ON(rate < 0))
+		return;
+
+	evt = kzalloc(sizeof *evt, GFP_KERNEL);
+	if (evt == NULL)
+		return;
+
+	evt->dev.features       = CLOCK_EVT_FEAT_PERIODIC |
+				  CLOCK_EVT_FEAT_ONESHOT,
+	evt->dev.set_mode	= axxia_timer_set_mode,
+	evt->dev.set_next_event	= axxia_timer_set_next_event,
+	evt->dev.rating		= 400,
+	evt->dev.name           = name;
+	evt->dev.irq            = irq;
+	evt->dev.cpumask	= cpu_all_mask,
+	evt->base               = base;
+	evt->reload             = DIV_ROUND_CLOSEST(rate, HZ);
+
+	evt->irqaction.name     = name;
+	evt->irqaction.flags    = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+	evt->irqaction.handler	= axxia_timer_handler;
+	evt->irqaction.dev_id	= evt;
+
+	setup_irq(irq, &evt->irqaction);
+	clockevents_config_and_register(&evt->dev, rate, 0xf, 0xffffffff);
+}
-- 
1.8.3




More information about the linux-yocto mailing list