[linux-yocto] [PATCH 13/87] arch/arm/mach-axxia: adding mach-axxia support

Paul Butler butler.paul at gmail.com
Mon May 27 09:55:44 PDT 2013


Signed-off-by: Paul Butler <paul.butler at windriver.com>
---
 arch/arm/mach-axxia/Kconfig                    |  20 +
 arch/arm/mach-axxia/Makefile                   |  10 +
 arch/arm/mach-axxia/Makefile.boot              |   5 +
 arch/arm/mach-axxia/axxia.c                    | 232 +++++++
 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/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                      | 908 +++++++++++++++++++++++++
 arch/arm/mach-axxia/pci.h                      |   1 +
 arch/arm/mach-axxia/platsmp.c                  | 174 +++++
 arch/arm/mach-axxia/timers.c                   | 225 ++++++
 23 files changed, 2111 insertions(+)
 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.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/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/mach-axxia/Kconfig b/arch/arm/mach-axxia/Kconfig
new file mode 100644
index 0000000..b309d99
--- /dev/null
+++ b/arch/arm/mach-axxia/Kconfig
@@ -0,0 +1,20 @@
+menu "Axxia platform type"
+	depends on ARCH_AXXIA
+
+config ARCH_AXXIA_DT
+	bool "Device Tree support for LSI Axxia platforms"
+	select ARM_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..6e157dd
--- /dev/null
+++ b/arch/arm/mach-axxia/Makefile
@@ -0,0 +1,10 @@
+#
+# 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_SMP)			+= platsmp.o headsmp.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.c b/arch/arm/mach-axxia/axxia.c
new file mode 100644
index 0000000..623957e
--- /dev/null
+++ b/arch/arm/mach-axxia/axxia.c
@@ -0,0 +1,232 @@
+/*
+ * 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 "axxia.h"
+#include "pci.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),
+	{}
+};
+
+struct pl022_config_chip spi_eeprom = {
+	.iface = SSP_INTERFACE_MOTOROLA_SPI,
+	.clk_freq = {
+		.cpsdvsr = 0,   /* value from 2 to 254 (even only!) */
+		.scr     = 0,	/* value from 0 to 255 */
+	},
+	.com_mode = POLLING_TRANSFER,
+};
+
+static struct spi_board_info spi_devs[] __initdata = {
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom,
+		.bus_num                = 0,
+		.chip_select            = 0,
+		.max_speed_hz           = 12000000,
+		.mode                   = SPI_MODE_0,
+	},
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom,
+		.bus_num                = 0,
+		.chip_select            = 1,
+		.max_speed_hz           = 12000000,
+		.mode                   = SPI_MODE_0,
+	},
+	{
+		.modalias               = "spidev",
+		.controller_data        = &spi_eeprom,
+		.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)) {
+		printk(KERN_INFO "SSPCSR = %08x\n", readl(ssp_base+0x30));
+		writel((0x1F << 8) | (0<<5) | (0x1F<<0), ssp_base+0x30);
+	}
+
+	axxia_pcie_init();
+}
+
+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	= 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..bc7414b
--- /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
+	and	r0, r0, #15
+	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..c504a72
--- /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 inline void 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/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..5ba4b80
--- /dev/null
+++ b/arch/arm/mach-axxia/pci.c
@@ -0,0 +1,908 @@
+/*
+ * 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 <asm/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
+static DECLARE_BITMAP(msi_irq_in_use, AXXIA55xx_NUM_MSI_IRQS);
+
+
+#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	res;
+};
+
+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);
+
+/* 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);
+			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;
+	u32 msg_fifo_stat;
+	u32 msg_fifo_info;
+	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;
+	u32 mpage_lower, pciah, pcial;
+	u32 msiLower, msiHigher, msiFinal;
+	u64 size, msiAddr;
+	void __iomem *cfg_addr, *cfg_data;
+	int mappedIrq;
+	int err;
+
+	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->res.name = "PCIe MEM";
+	port->res.start = port->cfg_space.start - 0x38000000;
+	/* allocate 256 M -- 2 MPAGEs worth */
+	port->res.end = port->res.start + 0x10000000 - 1;
+	port->res.flags = IORESOURCE_MEM;
+
+	if (request_resource(&iomem_resource, &port->res))
+		panic("Request PCIe Memory resource failed for port %d\n",
+		      portno);
+
+	pci_add_resource_offset(&sys->resources, &port->res, sys->mem_offset);
+	printk(KERN_INFO "port res start = 0x%012llx, end = 0x%012llx\n",
+	       port->res.start, port->res.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, 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;
+	}
+
+	/* Setup as root complex */
+	pci_config = readl(cfg_addr + 0x1000);
+#ifdef PRINT_CONFIG_ACCESSES
+	printk(KERN_INFO "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_ERR
+		       "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(KERN_ERR
+		       "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_ERR
+		       "PCI link state now = 0x%x\n", link_state);
+		if (link_state != 0xb) {
+			printk(KERN_ERR
+			       "PCI link still in bad state - giving up!\n");
+			goto fail;
+		}
+	}
+
+	/* setup ACP for 4GB 1=Prefetchable, 10=Locate anywhere in
+	 * 64 bit address space */
+	writel(0x1000000c, cfg_addr + 0x10);
+	writel(0x0, cfg_addr + 0x14);
+	writel(((0xff << 16) | (0x1 << 8) | 0x0), cfg_addr + PCI_PRIMARY_BUS);
+
+	/* 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;
+	for (i = 0; i < num_pages; i++) {
+		pciah = U64_TO_U32_HIGH(port->pci_addr);
+		pcial = U64_TO_U32_LOW(port->pci_addr);
+		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;
+	}
+
+	if (sys->domain == 0) {
+		/* Setup MSI address for PEI0 only since it support MSI */
+		msiAddr = port->cfg_space.end & 0xfffffffffffffC00;
+		msiLower = U64_TO_U32_LOW(msiAddr);
+		msiLower = msiLower >> 10;
+		msiHigher = U64_TO_U32_HIGH(msiAddr);
+		msiHigher = msiHigher & 0x3F;
+		msiFinal = ((msiHigher << 22) | (msiLower));
+		printk(KERN_ERR
+		       "PEI%d msiHigher = 0x%x, msiLower = 0x%x\n",
+		       sys->domain, msiHigher, msiLower);
+		printk(KERN_ERR
+		       "PEI%d msiAddr = 0x%012llx, msiFinal = 0x%x\n",
+		       sys->domain, msiAddr, msiFinal);
+		writel(msiFinal, cfg_addr + 0x1190);
+	}
+	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;
+}
+
+/* Tegra PCIE requires relaxed ordering */
+static void __devinit axxia_pcie_msi_enable(struct pci_dev *dev)
+{
+	u32 msi_lower, msi_higher = 0;
+	int pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	struct axxia_pciex_port *port;
+	int mappedIrq;
+	int err;
+
+	port = bus_to_port(dev->bus);
+
+	if (pos <= 0) {
+		dev_err(&dev->dev, "skipping MSI enable\n");
+		printk(KERN_ERR "skipping MSI enable\n");
+		return;
+	}
+
+	if (port->index == 0) {
+		/* MSI support only in PEI0 */
+		msi_lower = port->pci_addr | (port->cfg_space.end & 0xfffc00);
+		printk(KERN_ERR
+		       "PEI%d axxia_pcie_msi_enable Found MSI, msi_lower = 0x%x\n",
+		       port->index, msi_lower);
+		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+				       msi_lower);
+		pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+				       msi_higher);
+		/* IRQ# 73-88 for PEI0 MSI INTs */
+		for (mappedIrq = 73; mappedIrq <= 88; mappedIrq++) {
+			printk(KERN_ERR
+			       "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);
+				return;
+			}
+		}
+	}
+	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 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;
+	const u32 pval;
+	int portno;
+	const char *val;
+	const u32 *field;
+	int rlen;
+	int pna = of_n_addr_cells(np);
+	int num = pna + 5;
+
+	/* 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_ERR "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_ERR "utl_regs start = 0x%012llx, end = 0x%012llx\n",
+	       port->utl_regs.start, port->utl_regs.end);
+
+	field = of_get_property(np, "dma-ranges", &rlen);
+	if (field == NULL)
+		printk(KERN_ERR "not able to get dma-ranges\n");
+
+	/* Walk it */
+	while ((rlen -= num * 4) >= 0) {
+		u64 pci_addr = of_read_number(field + 1, 2);
+		printk(KERN_ERR "pci_addr = 0x%012llx\n", pci_addr);
+		port->pci_addr = pci_addr;
+		break;
+	}
+	printk(KERN_ERR "%s PCIE%d config base = 0x%012llx\n", np->full_name,
+	       port->index, port->utl_regs.start);
+}
+
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..7a63b4a
--- /dev/null
+++ b/arch/arm/mach-axxia/platsmp.c
@@ -0,0 +1,174 @@
+/*
+ *  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_fdt.h>
+#include <asm/smp_plat.h>
+#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.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 any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	gic_secondary_init(0);
+
+	/*
+	 * 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;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	_raw_spin_lock(&boot_lock);
+
+	/*
+	 * This is really belt and braces; we hold unintended secondary
+	 * CPUs in the holding pen until we're ready for them.  However,
+	 * since we haven't sent them a soft interrupt, they shouldn't
+	 * be there.
+	 */
+	write_pen_release(cpu_logical_map(cpu));
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+	gic_raise_softirq(cpumask_of(cpu), 1);
+
+	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;
+}
+
+static int __init axxia_dt_cpus_num(unsigned long node, const char *uname,
+		int depth, void *data)
+{
+	static int prev_depth = -1;
+	static int nr_cpus = -1;
+
+	if (prev_depth > depth && nr_cpus > 0)
+		return nr_cpus;
+
+	if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
+		nr_cpus = 0;
+
+	if (nr_cpus >= 0) {
+		const char *device_type = of_get_flat_dt_prop(node,
+				"device_type", NULL);
+
+		if (device_type && strcmp(device_type, "cpu") == 0)
+			nr_cpus++;
+	}
+
+	prev_depth = depth;
+
+	return 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, i;
+
+	ncores = of_scan_flat_dt(axxia_dt_cpus_num, NULL);
+
+	if (ncores < 2)
+		return;
+
+	if (ncores > nr_cpu_ids) {
+		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+				ncores, nr_cpu_ids);
+		ncores = nr_cpu_ids;
+	}
+
+	for (i = 0; i < ncores; ++i)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(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);
+
+	*(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