summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-spear
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:02:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:02:30 +0000
commit76cb841cb886eef6b3bee341a2266c76578724ad (patch)
treef5892e5ba6cc11949952a6ce4ecbe6d516d6ce58 /arch/arm/mach-spear
parentInitial commit. (diff)
downloadlinux-76cb841cb886eef6b3bee341a2266c76578724ad.tar.xz
linux-76cb841cb886eef6b3bee341a2266c76578724ad.zip
Adding upstream version 4.19.249.upstream/4.19.249
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'arch/arm/mach-spear')
-rw-r--r--arch/arm/mach-spear/Kconfig95
-rw-r--r--arch/arm/mach-spear/Makefile27
-rw-r--r--arch/arm/mach-spear/generic.h56
-rw-r--r--arch/arm/mach-spear/headsmp.S47
-rw-r--r--arch/arm/mach-spear/hotplug.c101
-rw-r--r--arch/arm/mach-spear/include/mach/irqs.h35
-rw-r--r--arch/arm/mach-spear/include/mach/misc_regs.h22
-rw-r--r--arch/arm/mach-spear/include/mach/spear.h91
-rw-r--r--arch/arm/mach-spear/include/mach/uncompress.h42
-rw-r--r--arch/arm/mach-spear/pl080.c78
-rw-r--r--arch/arm/mach-spear/pl080.h21
-rw-r--r--arch/arm/mach-spear/platsmp.c131
-rw-r--r--arch/arm/mach-spear/restart.c35
-rw-r--r--arch/arm/mach-spear/spear1310.c65
-rw-r--r--arch/arm/mach-spear/spear1340.c38
-rw-r--r--arch/arm/mach-spear/spear13xx.c128
-rw-r--r--arch/arm/mach-spear/spear300.c217
-rw-r--r--arch/arm/mach-spear/spear310.c259
-rw-r--r--arch/arm/mach-spear/spear320.c274
-rw-r--r--arch/arm/mach-spear/spear3xx.c110
-rw-r--r--arch/arm/mach-spear/spear6xx.c422
-rw-r--r--arch/arm/mach-spear/time.c256
22 files changed, 2550 insertions, 0 deletions
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig
new file mode 100644
index 000000000..1b6cae5e7
--- /dev/null
+++ b/arch/arm/mach-spear/Kconfig
@@ -0,0 +1,95 @@
+#
+# SPEAr Platform configuration file
+#
+
+menuconfig PLAT_SPEAR
+ bool "ST SPEAr Family"
+ depends on ARCH_MULTI_V7 || ARCH_MULTI_V5
+ select ARM_AMBA
+ select CLKSRC_MMIO
+ select GPIOLIB
+
+if PLAT_SPEAR
+
+config ARCH_SPEAR13XX
+ bool "ST SPEAr13xx"
+ depends on ARCH_MULTI_V7
+ select ARM_GIC
+ select GPIO_SPEAR_SPICS
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select PINCTRL
+ select MFD_SYSCON
+ help
+ Supports for ARM's SPEAR13XX family
+
+if ARCH_SPEAR13XX
+
+config MACH_SPEAR1310
+ bool "SPEAr1310 Machine support with Device Tree"
+ select PINCTRL_SPEAR1310
+ select PHY_ST_SPEAR1310_MIPHY
+ help
+ Supports ST SPEAr1310 machine configured via the device-tree
+
+config MACH_SPEAR1340
+ bool "SPEAr1340 Machine support with Device Tree"
+ select PINCTRL_SPEAR1340
+ select PHY_ST_SPEAR1340_MIPHY
+ help
+ Supports ST SPEAr1340 machine configured via the device-tree
+
+endif #ARCH_SPEAR13XX
+
+config ARCH_SPEAR3XX
+ bool "ST SPEAr3xx"
+ depends on ARCH_MULTI_V5
+ depends on !ARCH_SPEAR13XX
+ select ARM_VIC
+ select PINCTRL
+ help
+ Supports for ARM's SPEAR3XX family
+
+if ARCH_SPEAR3XX
+
+config MACH_SPEAR300
+ bool "SPEAr300 Machine support with Device Tree"
+ select PINCTRL_SPEAR300
+ help
+ Supports ST SPEAr300 machine configured via the device-tree
+
+config MACH_SPEAR310
+ bool "SPEAr310 Machine support with Device Tree"
+ select PINCTRL_SPEAR310
+ help
+ Supports ST SPEAr310 machine configured via the device-tree
+
+config MACH_SPEAR320
+ bool "SPEAr320 Machine support with Device Tree"
+ select PINCTRL_SPEAR320
+ help
+ Supports ST SPEAr320 machine configured via the device-tree
+
+endif
+
+config ARCH_SPEAR6XX
+ bool "ST SPEAr6XX"
+ depends on ARCH_MULTI_V5
+ depends on !ARCH_SPEAR13XX
+ select ARM_VIC
+ help
+ Supports for ARM's SPEAR6XX family
+
+config MACH_SPEAR600
+ def_bool y
+ depends on ARCH_SPEAR6XX
+ help
+ Supports ST SPEAr600 boards configured via the device-tree
+
+config ARCH_SPEAR_AUTO
+ bool
+ depends on !ARCH_SPEAR13XX && !ARCH_SPEAR6XX
+ select ARCH_SPEAR3XX
+
+endif
+
diff --git a/arch/arm/mach-spear/Makefile b/arch/arm/mach-spear/Makefile
new file mode 100644
index 000000000..176b14f83
--- /dev/null
+++ b/arch/arm/mach-spear/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# SPEAr Platform specific Makefile
+#
+
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
+
+# Common support
+obj-y := restart.o time.o
+
+smp-$(CONFIG_SMP) += headsmp.o platsmp.o
+smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+
+obj-$(CONFIG_ARCH_SPEAR13XX) += spear13xx.o $(smp-y)
+obj-$(CONFIG_MACH_SPEAR1310) += spear1310.o
+obj-$(CONFIG_MACH_SPEAR1340) += spear1340.o
+
+obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o
+obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o
+obj-$(CONFIG_MACH_SPEAR300) += spear300.o
+obj-$(CONFIG_MACH_SPEAR310) += spear310.o
+obj-$(CONFIG_MACH_SPEAR320) += spear320.o
+
+obj-$(CONFIG_ARCH_SPEAR6XX) += spear6xx.o
+obj-$(CONFIG_ARCH_SPEAR6XX) += pl080.o
+
+CFLAGS_hotplug.o += -march=armv7-a
diff --git a/arch/arm/mach-spear/generic.h b/arch/arm/mach-spear/generic.h
new file mode 100644
index 000000000..909b97c0b
--- /dev/null
+++ b/arch/arm/mach-spear/generic.h
@@ -0,0 +1,56 @@
+/*
+ * spear machine family generic header file
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_GENERIC_H
+#define __MACH_GENERIC_H
+
+#include <linux/dmaengine.h>
+#include <linux/amba/pl08x.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/mach/time.h>
+
+extern void spear13xx_timer_init(void);
+extern void spear3xx_timer_init(void);
+extern struct pl022_ssp_controller pl022_plat_data;
+extern struct pl08x_platform_data pl080_plat_data;
+
+void __init spear_setup_of_timer(void);
+void __init spear3xx_clk_init(void __iomem *misc_base,
+ void __iomem *soc_config_base);
+void __init spear3xx_map_io(void);
+void __init spear3xx_dt_init_irq(void);
+void __init spear6xx_clk_init(void __iomem *misc_base);
+void __init spear13xx_map_io(void);
+void __init spear13xx_l2x0_init(void);
+
+void spear_restart(enum reboot_mode, const char *);
+
+void spear13xx_secondary_startup(void);
+void spear13xx_cpu_die(unsigned int cpu);
+
+extern const struct smp_operations spear13xx_smp_ops;
+
+#ifdef CONFIG_MACH_SPEAR1310
+void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base);
+#else
+static inline void spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base) {}
+#endif
+
+#ifdef CONFIG_MACH_SPEAR1340
+void __init spear1340_clk_init(void __iomem *misc_base);
+#else
+static inline void spear1340_clk_init(void __iomem *misc_base) {}
+#endif
+
+#endif /* __MACH_GENERIC_H */
diff --git a/arch/arm/mach-spear/headsmp.S b/arch/arm/mach-spear/headsmp.S
new file mode 100644
index 000000000..c52192dc3
--- /dev/null
+++ b/arch/arm/mach-spear/headsmp.S
@@ -0,0 +1,47 @@
+/*
+ * arch/arm/mach-spear13XX/headsmp.S
+ *
+ * Picked from realview
+ * Copyright (c) 2012 ST Microelectronics Limited
+ * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
+ *
+ * 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>
+
+ __INIT
+
+/*
+ * spear13xx 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(spear13xx_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
+
+ /* re-enable coherency */
+ mrc p15, 0, r0, c1, c0, 1
+ orr r0, r0, #(1 << 6) | (1 << 0)
+ mcr p15, 0, r0, c1, c0, 1
+ /*
+ * we've been released from the holding pen: secondary_stack
+ * should now contain the SVC stack for this core
+ */
+ b secondary_startup
+
+ .align
+1: .long .
+ .long pen_release
+ENDPROC(spear13xx_secondary_startup)
diff --git a/arch/arm/mach-spear/hotplug.c b/arch/arm/mach-spear/hotplug.c
new file mode 100644
index 000000000..12edd1cf8
--- /dev/null
+++ b/arch/arm/mach-spear/hotplug.c
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/arm/mach-spear13xx/hotplug.c
+ *
+ * Copyright (C) 2012 ST Microelectronics Ltd.
+ * Deepak Sikri <deepak.sikri@st.com>
+ *
+ * based upon linux/arch/arm/mach-realview/hotplug.c
+ *
+ * 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/cp15.h>
+#include <asm/smp_plat.h>
+
+static inline void cpu_enter_lowpower(void)
+{
+ unsigned int v;
+
+ asm volatile(
+ " mcr p15, 0, %1, c7, c5, 0\n"
+ " dsb\n"
+ /*
+ * Turn off coherency
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, #0x20\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)
+ : "cc", "memory");
+}
+
+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, #0x20\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (CR_C)
+ : "cc");
+}
+
+static inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious)
+{
+ for (;;) {
+ wfi();
+
+ if (pen_release == 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)++;
+ }
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void spear13xx_cpu_die(unsigned int cpu)
+{
+ int spurious = 0;
+
+ /*
+ * we're ready for shutdown now, so do it
+ */
+ cpu_enter_lowpower();
+ spear13xx_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);
+}
diff --git a/arch/arm/mach-spear/include/mach/irqs.h b/arch/arm/mach-spear/include/mach/irqs.h
new file mode 100644
index 000000000..7058720c5
--- /dev/null
+++ b/arch/arm/mach-spear/include/mach/irqs.h
@@ -0,0 +1,35 @@
+/*
+ * IRQ helper macros for spear machine family
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_IRQS_H
+#define __MACH_IRQS_H
+
+#ifdef CONFIG_ARCH_SPEAR3XX
+#define NR_IRQS 256
+#endif
+
+#ifdef CONFIG_ARCH_SPEAR6XX
+/* IRQ definitions */
+/* VIC 1 */
+#define IRQ_VIC_END 64
+
+/* GPIO pins virtual irqs */
+#define VIRTUAL_IRQS 24
+#define NR_IRQS (IRQ_VIC_END + VIRTUAL_IRQS)
+#endif
+
+#ifdef CONFIG_ARCH_SPEAR13XX
+#define IRQ_GIC_END 160
+#define NR_IRQS IRQ_GIC_END
+#endif
+
+#endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear/include/mach/misc_regs.h b/arch/arm/mach-spear/include/mach/misc_regs.h
new file mode 100644
index 000000000..cfaf7c665
--- /dev/null
+++ b/arch/arm/mach-spear/include/mach/misc_regs.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-spear3xx/include/mach/misc_regs.h
+ *
+ * Miscellaneous registers definitions for SPEAr3xx machine family
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_MISC_REGS_H
+#define __MACH_MISC_REGS_H
+
+#include <mach/spear.h>
+
+#define MISC_BASE (VA_SPEAR_ICM3_MISC_REG_BASE)
+#define DMA_CHN_CFG (MISC_BASE + 0x0A0)
+
+#endif /* __MACH_MISC_REGS_H */
diff --git a/arch/arm/mach-spear/include/mach/spear.h b/arch/arm/mach-spear/include/mach/spear.h
new file mode 100644
index 000000000..5ed841ccf
--- /dev/null
+++ b/arch/arm/mach-spear/include/mach/spear.h
@@ -0,0 +1,91 @@
+/*
+ * SPEAr3xx/6xx Machine family specific definition
+ *
+ * Copyright (C) 2009,2012 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPEAR_H
+#define __MACH_SPEAR_H
+
+#include <asm/memory.h>
+
+#if defined(CONFIG_ARCH_SPEAR3XX) || defined (CONFIG_ARCH_SPEAR6XX)
+
+/* ICM1 - Low speed connection */
+#define SPEAR_ICM1_2_BASE UL(0xD0000000)
+#define VA_SPEAR_ICM1_2_BASE IOMEM(0xFD000000)
+#define SPEAR_ICM1_UART_BASE UL(0xD0000000)
+#define VA_SPEAR_ICM1_UART_BASE (VA_SPEAR_ICM1_2_BASE - SPEAR_ICM1_2_BASE + SPEAR_ICM1_UART_BASE)
+#define SPEAR3XX_ICM1_SSP_BASE UL(0xD0100000)
+
+/* ML-1, 2 - Multi Layer CPU Subsystem */
+#define SPEAR_ICM3_ML1_2_BASE UL(0xF0000000)
+#define VA_SPEAR6XX_ML_CPU_BASE IOMEM(0xF0000000)
+
+/* ICM3 - Basic Subsystem */
+#define SPEAR_ICM3_SMI_CTRL_BASE UL(0xFC000000)
+#define VA_SPEAR_ICM3_SMI_CTRL_BASE IOMEM(0xFC000000)
+#define SPEAR_ICM3_DMA_BASE UL(0xFC400000)
+#define SPEAR_ICM3_SYS_CTRL_BASE UL(0xFCA00000)
+#define VA_SPEAR_ICM3_SYS_CTRL_BASE (VA_SPEAR_ICM3_SMI_CTRL_BASE - SPEAR_ICM3_SMI_CTRL_BASE + SPEAR_ICM3_SYS_CTRL_BASE)
+#define SPEAR_ICM3_MISC_REG_BASE UL(0xFCA80000)
+#define VA_SPEAR_ICM3_MISC_REG_BASE (VA_SPEAR_ICM3_SMI_CTRL_BASE - SPEAR_ICM3_SMI_CTRL_BASE + SPEAR_ICM3_MISC_REG_BASE)
+
+/* Debug uart for linux, will be used for debug and uncompress messages */
+#define SPEAR_DBG_UART_BASE SPEAR_ICM1_UART_BASE
+
+/* Sysctl base for spear platform */
+#define SPEAR_SYS_CTRL_BASE SPEAR_ICM3_SYS_CTRL_BASE
+#define VA_SPEAR_SYS_CTRL_BASE VA_SPEAR_ICM3_SYS_CTRL_BASE
+#endif /* SPEAR3xx || SPEAR6XX */
+
+/* SPEAr320 Macros */
+#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000)
+#define VA_SPEAR320_SOC_CONFIG_BASE IOMEM(0xFE000000)
+
+#ifdef CONFIG_ARCH_SPEAR13XX
+
+#define PERIP_GRP2_BASE UL(0xB3000000)
+#define VA_PERIP_GRP2_BASE IOMEM(0xF9000000)
+#define MCIF_SDHCI_BASE UL(0xB3000000)
+#define SYSRAM0_BASE UL(0xB3800000)
+#define VA_SYSRAM0_BASE IOMEM(0xF9800000)
+#define SYS_LOCATION (VA_SYSRAM0_BASE + 0x600)
+
+#define PERIP_GRP1_BASE UL(0xE0000000)
+#define VA_PERIP_GRP1_BASE IOMEM(0xFD000000)
+#define UART_BASE UL(0xE0000000)
+#define VA_UART_BASE IOMEM(0xFD000000)
+#define SSP_BASE UL(0xE0100000)
+#define MISC_BASE UL(0xE0700000)
+#define VA_MISC_BASE IOMEM(0xFD700000)
+
+#define A9SM_AND_MPMC_BASE UL(0xEC000000)
+#define VA_A9SM_AND_MPMC_BASE IOMEM(0xFC000000)
+
+#define SPEAR1310_RAS_BASE UL(0xD8400000)
+#define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000))
+
+/* A9SM peripheral offsets */
+#define A9SM_PERIP_BASE UL(0xEC800000)
+#define VA_A9SM_PERIP_BASE IOMEM(0xFC800000)
+#define VA_SCU_BASE (VA_A9SM_PERIP_BASE + 0x00)
+
+#define L2CC_BASE UL(0xED000000)
+#define VA_L2CC_BASE IOMEM(UL(0xFB000000))
+
+/* others */
+#define MCIF_CF_BASE UL(0xB2800000)
+
+/* Debug uart for linux, will be used for debug and uncompress messages */
+#define SPEAR_DBG_UART_BASE UART_BASE
+
+#endif /* SPEAR13XX */
+
+#endif /* __MACH_SPEAR_H */
diff --git a/arch/arm/mach-spear/include/mach/uncompress.h b/arch/arm/mach-spear/include/mach/uncompress.h
new file mode 100644
index 000000000..8439b9c12
--- /dev/null
+++ b/arch/arm/mach-spear/include/mach/uncompress.h
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/plat-spear/include/plat/uncompress.h
+ *
+ * Serial port stubs for kernel decompress status messages
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/amba/serial.h>
+#include <mach/spear.h>
+
+#ifndef __PLAT_UNCOMPRESS_H
+#define __PLAT_UNCOMPRESS_H
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+ void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE;
+
+ while (readl_relaxed(base + UART01x_FR) & UART01x_FR_TXFF)
+ barrier();
+
+ writel_relaxed(c, base + UART01x_DR);
+}
+
+static inline void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#endif /* __PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/mach-spear/pl080.c b/arch/arm/mach-spear/pl080.c
new file mode 100644
index 000000000..b4529f3e0
--- /dev/null
+++ b/arch/arm/mach-spear/pl080.c
@@ -0,0 +1,78 @@
+/*
+ * arch/arm/plat-spear/pl080.c
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/amba/pl08x.h>
+#include <linux/amba/bus.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/spinlock_types.h>
+#include <mach/spear.h>
+#include <mach/misc_regs.h>
+
+static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
+
+struct {
+ unsigned char busy;
+ unsigned char val;
+} signals[16] = {{0, 0}, };
+
+int pl080_get_signal(const struct pl08x_channel_data *cd)
+{
+ unsigned int signal = cd->min_signal, val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* Return if signal is already acquired by somebody else */
+ if (signals[signal].busy &&
+ (signals[signal].val != cd->muxval)) {
+ spin_unlock_irqrestore(&lock, flags);
+ return -EBUSY;
+ }
+
+ /* If acquiring for the first time, configure it */
+ if (!signals[signal].busy) {
+ val = readl(DMA_CHN_CFG);
+
+ /*
+ * Each request line has two bits in DMA_CHN_CFG register. To
+ * goto the bits of current request line, do left shift of
+ * value by 2 * signal number.
+ */
+ val &= ~(0x3 << (signal * 2));
+ val |= cd->muxval << (signal * 2);
+ writel(val, DMA_CHN_CFG);
+ }
+
+ signals[signal].busy++;
+ signals[signal].val = cd->muxval;
+ spin_unlock_irqrestore(&lock, flags);
+
+ return signal;
+}
+
+void pl080_put_signal(const struct pl08x_channel_data *cd, int signal)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* if signal is not used */
+ if (!signals[signal].busy)
+ BUG();
+
+ signals[signal].busy--;
+
+ spin_unlock_irqrestore(&lock, flags);
+}
diff --git a/arch/arm/mach-spear/pl080.h b/arch/arm/mach-spear/pl080.h
new file mode 100644
index 000000000..608dec672
--- /dev/null
+++ b/arch/arm/mach-spear/pl080.h
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/plat-spear/include/plat/pl080.h
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PLAT_PL080_H
+#define __PLAT_PL080_H
+
+struct pl08x_channel_data;
+int pl080_get_signal(const struct pl08x_channel_data *cd);
+void pl080_put_signal(const struct pl08x_channel_data *cd, int signal);
+
+#endif /* __PLAT_PL080_H */
diff --git a/arch/arm/mach-spear/platsmp.c b/arch/arm/mach-spear/platsmp.c
new file mode 100644
index 000000000..39038a038
--- /dev/null
+++ b/arch/arm/mach-spear/platsmp.c
@@ -0,0 +1,131 @@
+/*
+ * arch/arm/mach-spear13xx/platsmp.c
+ *
+ * based upon linux/arch/arm/mach-realview/platsmp.c
+ *
+ * Copyright (C) 2012 ST Microelectronics Ltd.
+ * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
+ *
+ * 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/delay.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_scu.h>
+#include <mach/spear.h>
+#include "generic.h"
+
+/*
+ * 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 write_pen_release(int val)
+{
+ pen_release = val;
+ smp_wmb();
+ sync_cache_w(&pen_release);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __iomem *scu_base = IOMEM(VA_SCU_BASE);
+
+static void spear13xx_secondary_init(unsigned int cpu)
+{
+ /*
+ * 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.
+ */
+ spin_lock(&boot_lock);
+ spin_unlock(&boot_lock);
+}
+
+static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ unsigned long timeout;
+
+ /*
+ * set synchronisation state between this boot processor
+ * and the secondary one
+ */
+ spin_lock(&boot_lock);
+
+ /*
+ * The secondary processor is waiting to be released from
+ * the holding pen - release it, then wait for it to flag
+ * that it has been released by resetting pen_release.
+ *
+ * Note that "pen_release" is the hardware CPU ID, whereas
+ * "cpu" is Linux's internal ID.
+ */
+ write_pen_release(cpu);
+
+ 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
+ */
+ 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.
+ */
+static void __init spear13xx_smp_init_cpus(void)
+{
+ unsigned int i, ncores = scu_get_core_count(scu_base);
+
+ 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);
+}
+
+static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
+{
+
+ scu_enable(scu_base);
+
+ /*
+ * Write the address of secondary startup into the system-wide location
+ * (presently it is in SRAM). The BootMonitor waits until it receives a
+ * soft interrupt, and then the secondary CPU branches to this address.
+ */
+ __raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION);
+}
+
+const struct smp_operations spear13xx_smp_ops __initconst = {
+ .smp_init_cpus = spear13xx_smp_init_cpus,
+ .smp_prepare_cpus = spear13xx_smp_prepare_cpus,
+ .smp_secondary_init = spear13xx_secondary_init,
+ .smp_boot_secondary = spear13xx_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = spear13xx_cpu_die,
+#endif
+};
diff --git a/arch/arm/mach-spear/restart.c b/arch/arm/mach-spear/restart.c
new file mode 100644
index 000000000..b4342155a
--- /dev/null
+++ b/arch/arm/mach-spear/restart.c
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-spear/restart.c
+ *
+ * SPEAr platform specific restart functions
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/io.h>
+#include <linux/amba/sp810.h>
+#include <linux/reboot.h>
+#include <asm/system_misc.h>
+#include <mach/spear.h>
+#include "generic.h"
+
+#define SPEAR13XX_SYS_SW_RES (VA_MISC_BASE + 0x204)
+void spear_restart(enum reboot_mode mode, const char *cmd)
+{
+ if (mode == REBOOT_SOFT) {
+ /* software reset, Jump into ROM at address 0 */
+ soft_restart(0);
+ } else {
+ /* hardware reset, Use on-chip reset capability */
+#ifdef CONFIG_ARCH_SPEAR13XX
+ writel_relaxed(0x01, SPEAR13XX_SYS_SW_RES);
+#endif
+#if defined(CONFIG_ARCH_SPEAR3XX) || defined(CONFIG_ARCH_SPEAR6XX)
+ sysctl_soft_reset((void __iomem *)VA_SPEAR_SYS_CTRL_BASE);
+#endif
+ }
+}
diff --git a/arch/arm/mach-spear/spear1310.c b/arch/arm/mach-spear/spear1310.c
new file mode 100644
index 000000000..a7d4f1368
--- /dev/null
+++ b/arch/arm/mach-spear/spear1310.c
@@ -0,0 +1,65 @@
+/*
+ * arch/arm/mach-spear13xx/spear1310.c
+ *
+ * SPEAr1310 machine source file
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr1310: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/pata_arasan_cf_data.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include "generic.h"
+#include <mach/spear.h>
+
+/* Base addresses */
+#define SPEAR1310_RAS_GRP1_BASE UL(0xD8000000)
+#define VA_SPEAR1310_RAS_GRP1_BASE UL(0xFA000000)
+
+static void __init spear1310_dt_init(void)
+{
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
+}
+
+static const char * const spear1310_dt_board_compat[] = {
+ "st,spear1310",
+ "st,spear1310-evb",
+ NULL,
+};
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xD8000000 0xFA000000
+ */
+static struct map_desc spear1310_io_desc[] __initdata = {
+ {
+ .virtual = VA_SPEAR1310_RAS_GRP1_BASE,
+ .pfn = __phys_to_pfn(SPEAR1310_RAS_GRP1_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ },
+};
+
+static void __init spear1310_map_io(void)
+{
+ iotable_init(spear1310_io_desc, ARRAY_SIZE(spear1310_io_desc));
+ spear13xx_map_io();
+}
+
+DT_MACHINE_START(SPEAR1310_DT, "ST SPEAr1310 SoC with Flattened Device Tree")
+ .smp = smp_ops(spear13xx_smp_ops),
+ .map_io = spear1310_map_io,
+ .init_time = spear13xx_timer_init,
+ .init_machine = spear1310_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear1310_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
new file mode 100644
index 000000000..a212af90c
--- /dev/null
+++ b/arch/arm/mach-spear/spear1340.c
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/mach-spear13xx/spear1340.c
+ *
+ * SPEAr1340 machine source file
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr1340: " fmt
+
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include "generic.h"
+
+static void __init spear1340_dt_init(void)
+{
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
+}
+
+static const char * const spear1340_dt_board_compat[] = {
+ "st,spear1340",
+ "st,spear1340-evb",
+ NULL,
+};
+
+DT_MACHINE_START(SPEAR1340_DT, "ST SPEAr1340 SoC with Flattened Device Tree")
+ .smp = smp_ops(spear13xx_smp_ops),
+ .map_io = spear13xx_map_io,
+ .init_time = spear13xx_timer_init,
+ .init_machine = spear1340_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear1340_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c
new file mode 100644
index 000000000..31c43cabf
--- /dev/null
+++ b/arch/arm/mach-spear/spear13xx.c
@@ -0,0 +1,128 @@
+/*
+ * arch/arm/mach-spear13xx/spear13xx.c
+ *
+ * SPEAr13XX machines common source file
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr13xx: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/mach/map.h>
+#include <mach/spear.h>
+#include "generic.h"
+
+void __init spear13xx_l2x0_init(void)
+{
+ /*
+ * 512KB (64KB/way), 8-way associativity, parity supported
+ *
+ * FIXME: 9th bit, of Auxillary Controller register must be set
+ * for some spear13xx devices for stable L2 operation.
+ *
+ * Enable Early BRESP, L2 prefetch for Instruction and Data,
+ * write alloc and 'Full line of zero' options
+ *
+ */
+ if (!IS_ENABLED(CONFIG_CACHE_L2X0))
+ return;
+
+ writel_relaxed(0x06, VA_L2CC_BASE + L310_PREFETCH_CTRL);
+
+ /*
+ * Program following latencies in order to make
+ * SPEAr1340 work at 600 MHz
+ */
+ writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL);
+ writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL);
+ l2x0_init(VA_L2CC_BASE, 0x30a00001, 0xfe0fffff);
+}
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xB3000000 0xF9000000
+ * 0xE0000000 0xFD000000
+ * 0xEC000000 0xFC000000
+ * 0xED000000 0xFB000000
+ */
+static struct map_desc spear13xx_io_desc[] __initdata = {
+ {
+ .virtual = (unsigned long)VA_PERIP_GRP2_BASE,
+ .pfn = __phys_to_pfn(PERIP_GRP2_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_PERIP_GRP1_BASE,
+ .pfn = __phys_to_pfn(PERIP_GRP1_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_A9SM_AND_MPMC_BASE,
+ .pfn = __phys_to_pfn(A9SM_AND_MPMC_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_L2CC_BASE,
+ .pfn = __phys_to_pfn(L2CC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ },
+};
+
+/* This will create static memory mapping for selected devices */
+void __init spear13xx_map_io(void)
+{
+ iotable_init(spear13xx_io_desc, ARRAY_SIZE(spear13xx_io_desc));
+}
+
+static void __init spear13xx_clk_init(void)
+{
+ if (of_machine_is_compatible("st,spear1310"))
+ spear1310_clk_init(VA_MISC_BASE, VA_SPEAR1310_RAS_BASE);
+ else if (of_machine_is_compatible("st,spear1340"))
+ spear1340_clk_init(VA_MISC_BASE);
+ else
+ pr_err("%s: Unknown machine\n", __func__);
+}
+
+void __init spear13xx_timer_init(void)
+{
+ char pclk_name[] = "osc_24m_clk";
+ struct clk *gpt_clk, *pclk;
+
+ spear13xx_clk_init();
+
+ /* get the system timer clock */
+ gpt_clk = clk_get_sys("gpt0", NULL);
+ if (IS_ERR(gpt_clk)) {
+ pr_err("%s:couldn't get clk for gpt\n", __func__);
+ BUG();
+ }
+
+ /* get the suitable parent clock for timer*/
+ pclk = clk_get(NULL, pclk_name);
+ if (IS_ERR(pclk)) {
+ pr_err("%s:couldn't get %s as parent for gpt\n", __func__,
+ pclk_name);
+ BUG();
+ }
+
+ clk_set_parent(gpt_clk, pclk);
+ clk_put(gpt_clk);
+ clk_put(pclk);
+
+ spear_setup_of_timer();
+ timer_probe();
+}
diff --git a/arch/arm/mach-spear/spear300.c b/arch/arm/mach-spear/spear300.c
new file mode 100644
index 000000000..325b89579
--- /dev/null
+++ b/arch/arm/mach-spear/spear300.c
@@ -0,0 +1,217 @@
+/*
+ * arch/arm/mach-spear3xx/spear300.c
+ *
+ * SPEAr300 machine source file
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr300: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include "generic.h"
+#include <mach/spear.h>
+
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear300_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ },
+};
+
+/* Add SPEAr300 auxdata to pass platform data */
+static struct of_dev_auxdata spear300_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ {}
+};
+
+static void __init spear300_dt_init(void)
+{
+ pl080_plat_data.slave_channels = spear300_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear300_dma_info);
+
+ of_platform_default_populate(NULL, spear300_auxdata_lookup, NULL);
+}
+
+static const char * const spear300_dt_board_compat[] = {
+ "st,spear300",
+ "st,spear300-evb",
+ NULL,
+};
+
+static void __init spear300_map_io(void)
+{
+ spear3xx_map_io();
+}
+
+DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree")
+ .map_io = spear300_map_io,
+ .init_time = spear3xx_timer_init,
+ .init_machine = spear300_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear300_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/spear310.c b/arch/arm/mach-spear/spear310.c
new file mode 100644
index 000000000..59e173dc8
--- /dev/null
+++ b/arch/arm/mach-spear/spear310.c
@@ -0,0 +1,259 @@
+/*
+ * arch/arm/mach-spear3xx/spear310.c
+ *
+ * SPEAr310 machine source file
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr310: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include "generic.h"
+#include <mach/spear.h>
+
+#define SPEAR310_UART1_BASE UL(0xB2000000)
+#define SPEAR310_UART2_BASE UL(0xB2080000)
+#define SPEAR310_UART3_BASE UL(0xB2100000)
+#define SPEAR310_UART4_BASE UL(0xB2180000)
+#define SPEAR310_UART5_BASE UL(0xB2200000)
+
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear310_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart2_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart2_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart3_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart3_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart4_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart4_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart5_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart5_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ },
+};
+
+/* uart devices plat data */
+static struct amba_pl011_data spear310_uart_data[] = {
+ {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart1_tx",
+ .dma_rx_param = "uart1_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart2_tx",
+ .dma_rx_param = "uart2_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart3_tx",
+ .dma_rx_param = "uart3_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart4_tx",
+ .dma_rx_param = "uart4_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart5_tx",
+ .dma_rx_param = "uart5_rx",
+ },
+};
+
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear310_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART1_BASE, NULL,
+ &spear310_uart_data[0]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART2_BASE, NULL,
+ &spear310_uart_data[1]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART3_BASE, NULL,
+ &spear310_uart_data[2]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART4_BASE, NULL,
+ &spear310_uart_data[3]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART5_BASE, NULL,
+ &spear310_uart_data[4]),
+ {}
+};
+
+static void __init spear310_dt_init(void)
+{
+ pl080_plat_data.slave_channels = spear310_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear310_dma_info);
+
+ of_platform_default_populate(NULL, spear310_auxdata_lookup, NULL);
+}
+
+static const char * const spear310_dt_board_compat[] = {
+ "st,spear310",
+ "st,spear310-evb",
+ NULL,
+};
+
+static void __init spear310_map_io(void)
+{
+ spear3xx_map_io();
+}
+
+DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree")
+ .map_io = spear310_map_io,
+ .init_time = spear3xx_timer_init,
+ .init_machine = spear310_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear310_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/spear320.c b/arch/arm/mach-spear/spear320.c
new file mode 100644
index 000000000..0958f68a2
--- /dev/null
+++ b/arch/arm/mach-spear/spear320.c
@@ -0,0 +1,274 @@
+/*
+ * arch/arm/mach-spear3xx/spear320.c
+ *
+ * SPEAr320 machine source file
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr320: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include "generic.h"
+#include <mach/spear.h>
+
+#define SPEAR320_UART1_BASE UL(0xA3000000)
+#define SPEAR320_UART2_BASE UL(0xA4000000)
+#define SPEAR320_SSP0_BASE UL(0xA5000000)
+#define SPEAR320_SSP1_BASE UL(0xA6000000)
+
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear320_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c0_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c0_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart2_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart2_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c1_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c1_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c2_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c2_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2s_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2s_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "rs485_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "rs485_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB2,
+ },
+};
+
+static struct pl022_ssp_controller spear320_ssp_data[] = {
+ {
+ .bus_id = 1,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp1_tx",
+ .dma_rx_param = "ssp1_rx",
+ .num_chipselect = 2,
+ }, {
+ .bus_id = 2,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp2_tx",
+ .dma_rx_param = "ssp2_rx",
+ .num_chipselect = 2,
+ }
+};
+
+static struct amba_pl011_data spear320_uart_data[] = {
+ {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart1_tx",
+ .dma_rx_param = "uart1_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart2_tx",
+ .dma_rx_param = "uart2_rx",
+ },
+};
+
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear320_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP0_BASE, NULL,
+ &spear320_ssp_data[0]),
+ OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP1_BASE, NULL,
+ &spear320_ssp_data[1]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART1_BASE, NULL,
+ &spear320_uart_data[0]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART2_BASE, NULL,
+ &spear320_uart_data[1]),
+ {}
+};
+
+static void __init spear320_dt_init(void)
+{
+ pl080_plat_data.slave_channels = spear320_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear320_dma_info);
+
+ of_platform_default_populate(NULL, spear320_auxdata_lookup, NULL);
+}
+
+static const char * const spear320_dt_board_compat[] = {
+ "st,spear320",
+ "st,spear320-evb",
+ "st,spear320-hmi",
+ NULL,
+};
+
+struct map_desc spear320_io_desc[] __initdata = {
+ {
+ .virtual = (unsigned long)VA_SPEAR320_SOC_CONFIG_BASE,
+ .pfn = __phys_to_pfn(SPEAR320_SOC_CONFIG_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ },
+};
+
+static void __init spear320_map_io(void)
+{
+ iotable_init(spear320_io_desc, ARRAY_SIZE(spear320_io_desc));
+ spear3xx_map_io();
+}
+
+DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree")
+ .map_io = spear320_map_io,
+ .init_time = spear3xx_timer_init,
+ .init_machine = spear320_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear320_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/spear3xx.c b/arch/arm/mach-spear/spear3xx.c
new file mode 100644
index 000000000..8537fcffe
--- /dev/null
+++ b/arch/arm/mach-spear/spear3xx.c
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/mach-spear3xx/spear3xx.c
+ *
+ * SPEAr3XX machines common source file
+ *
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <vireshk@kernel.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "SPEAr3xx: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl080.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <asm/mach/map.h>
+#include "pl080.h"
+#include "generic.h"
+#include <mach/spear.h>
+#include <mach/misc_regs.h>
+
+/* ssp device registration */
+struct pl022_ssp_controller pl022_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp0_tx",
+ .dma_rx_param = "ssp0_rx",
+ /*
+ * This is number of spi devices that can be connected to spi. There are
+ * two type of chipselects on which slave devices can work. One is chip
+ * select provided by spi masters other is controlled through external
+ * gpio's. We can't use chipselect provided from spi master (because as
+ * soon as FIFO becomes empty, CS is disabled and transfer ends). So
+ * this number now depends on number of gpios available for spi. each
+ * slave on each master requires a separate gpio pin.
+ */
+ .num_chipselect = 2,
+};
+
+/* dmac device registration */
+struct pl08x_platform_data pl080_plat_data = {
+ .memcpy_burst_size = PL08X_BURST_SZ_16,
+ .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS,
+ .memcpy_prot_buff = true,
+ .memcpy_prot_cache = true,
+ .lli_buses = PL08X_AHB1,
+ .mem_buses = PL08X_AHB1,
+ .get_xfer_signal = pl080_get_signal,
+ .put_xfer_signal = pl080_put_signal,
+};
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xD0000000 0xFD000000
+ * 0xFC000000 0xFC000000
+ */
+struct map_desc spear3xx_io_desc[] __initdata = {
+ {
+ .virtual = (unsigned long)VA_SPEAR_ICM1_2_BASE,
+ .pfn = __phys_to_pfn(SPEAR_ICM1_2_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_SPEAR_ICM3_SMI_CTRL_BASE,
+ .pfn = __phys_to_pfn(SPEAR_ICM3_SMI_CTRL_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ },
+};
+
+/* This will create static memory mapping for selected devices */
+void __init spear3xx_map_io(void)
+{
+ iotable_init(spear3xx_io_desc, ARRAY_SIZE(spear3xx_io_desc));
+}
+
+void __init spear3xx_timer_init(void)
+{
+ char pclk_name[] = "pll3_clk";
+ struct clk *gpt_clk, *pclk;
+
+ spear3xx_clk_init(MISC_BASE, VA_SPEAR320_SOC_CONFIG_BASE);
+
+ /* get the system timer clock */
+ gpt_clk = clk_get_sys("gpt0", NULL);
+ if (IS_ERR(gpt_clk)) {
+ pr_err("%s:couldn't get clk for gpt\n", __func__);
+ BUG();
+ }
+
+ /* get the suitable parent clock for timer*/
+ pclk = clk_get(NULL, pclk_name);
+ if (IS_ERR(pclk)) {
+ pr_err("%s:couldn't get %s as parent for gpt\n",
+ __func__, pclk_name);
+ BUG();
+ }
+
+ clk_set_parent(gpt_clk, pclk);
+ clk_put(gpt_clk);
+ clk_put(pclk);
+
+ spear_setup_of_timer();
+}
diff --git a/arch/arm/mach-spear/spear6xx.c b/arch/arm/mach-spear/spear6xx.c
new file mode 100644
index 000000000..c5fc11013
--- /dev/null
+++ b/arch/arm/mach-spear/spear6xx.c
@@ -0,0 +1,422 @@
+/*
+ * arch/arm/mach-spear6xx/spear6xx.c
+ *
+ * SPEAr6XX machines common source file
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/amba/pl08x.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/amba/pl080.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include "pl080.h"
+#include "generic.h"
+#include <mach/spear.h>
+#include <mach/misc_regs.h>
+
+/* dmac device registration */
+static struct pl08x_channel_data spear600_dma_info[] = {
+ {
+ .bus_id = "ssp1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp2_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ext0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 2,
+ .periph_buses = PL08X_AHB2,
+ },
+};
+
+static struct pl08x_platform_data spear6xx_pl080_plat_data = {
+ .memcpy_burst_size = PL08X_BURST_SZ_16,
+ .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS,
+ .memcpy_prot_buff = true,
+ .memcpy_prot_cache = true,
+ .lli_buses = PL08X_AHB1,
+ .mem_buses = PL08X_AHB1,
+ .get_xfer_signal = pl080_get_signal,
+ .put_xfer_signal = pl080_put_signal,
+ .slave_channels = spear600_dma_info,
+ .num_slave_channels = ARRAY_SIZE(spear600_dma_info),
+};
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xF0000000 0xF0000000
+ * 0xF1000000 0xF1000000
+ * 0xD0000000 0xFD000000
+ * 0xFC000000 0xFC000000
+ */
+struct map_desc spear6xx_io_desc[] __initdata = {
+ {
+ .virtual = (unsigned long)VA_SPEAR6XX_ML_CPU_BASE,
+ .pfn = __phys_to_pfn(SPEAR_ICM3_ML1_2_BASE),
+ .length = 2 * SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_SPEAR_ICM1_2_BASE,
+ .pfn = __phys_to_pfn(SPEAR_ICM1_2_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = (unsigned long)VA_SPEAR_ICM3_SMI_CTRL_BASE,
+ .pfn = __phys_to_pfn(SPEAR_ICM3_SMI_CTRL_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ },
+};
+
+/* This will create static memory mapping for selected devices */
+void __init spear6xx_map_io(void)
+{
+ iotable_init(spear6xx_io_desc, ARRAY_SIZE(spear6xx_io_desc));
+}
+
+void __init spear6xx_timer_init(void)
+{
+ char pclk_name[] = "pll3_clk";
+ struct clk *gpt_clk, *pclk;
+
+ spear6xx_clk_init(MISC_BASE);
+
+ /* get the system timer clock */
+ gpt_clk = clk_get_sys("gpt0", NULL);
+ if (IS_ERR(gpt_clk)) {
+ pr_err("%s:couldn't get clk for gpt\n", __func__);
+ BUG();
+ }
+
+ /* get the suitable parent clock for timer*/
+ pclk = clk_get(NULL, pclk_name);
+ if (IS_ERR(pclk)) {
+ pr_err("%s:couldn't get %s as parent for gpt\n",
+ __func__, pclk_name);
+ BUG();
+ }
+
+ clk_set_parent(gpt_clk, pclk);
+ clk_put(gpt_clk);
+ clk_put(pclk);
+
+ spear_setup_of_timer();
+}
+
+/* Add auxdata to pass platform data */
+struct of_dev_auxdata spear6xx_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl080", SPEAR_ICM3_DMA_BASE, NULL,
+ &spear6xx_pl080_plat_data),
+ {}
+};
+
+static void __init spear600_dt_init(void)
+{
+ of_platform_default_populate(NULL, spear6xx_auxdata_lookup, NULL);
+}
+
+static const char *spear600_dt_board_compat[] = {
+ "st,spear600",
+ NULL
+};
+
+DT_MACHINE_START(SPEAR600_DT, "ST SPEAr600 (Flattened Device Tree)")
+ .map_io = spear6xx_map_io,
+ .init_time = spear6xx_timer_init,
+ .init_machine = spear600_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear600_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear/time.c b/arch/arm/mach-spear/time.c
new file mode 100644
index 000000000..289e036c9
--- /dev/null
+++ b/arch/arm/mach-spear/time.c
@@ -0,0 +1,256 @@
+/*
+ * arch/arm/plat-spear/time.c
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Shiraz Hashim<shiraz.linux.kernel@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <asm/mach/time.h>
+#include "generic.h"
+
+/*
+ * We would use TIMER0 and TIMER1 as clockevent and clocksource.
+ * Timer0 and Timer1 both belong to same gpt block in cpu subbsystem. Further
+ * they share same functional clock. Any change in one's functional clock will
+ * also affect other timer.
+ */
+
+#define CLKEVT 0 /* gpt0, channel0 as clockevent */
+#define CLKSRC 1 /* gpt0, channel1 as clocksource */
+
+/* Register offsets, x is channel number */
+#define CR(x) ((x) * 0x80 + 0x80)
+#define IR(x) ((x) * 0x80 + 0x84)
+#define LOAD(x) ((x) * 0x80 + 0x88)
+#define COUNT(x) ((x) * 0x80 + 0x8C)
+
+/* Reg bit definitions */
+#define CTRL_INT_ENABLE 0x0100
+#define CTRL_ENABLE 0x0020
+#define CTRL_ONE_SHOT 0x0010
+
+#define CTRL_PRESCALER1 0x0
+#define CTRL_PRESCALER2 0x1
+#define CTRL_PRESCALER4 0x2
+#define CTRL_PRESCALER8 0x3
+#define CTRL_PRESCALER16 0x4
+#define CTRL_PRESCALER32 0x5
+#define CTRL_PRESCALER64 0x6
+#define CTRL_PRESCALER128 0x7
+#define CTRL_PRESCALER256 0x8
+
+#define INT_STATUS 0x1
+
+/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define SPEAR_MIN_RANGE 4
+
+static __iomem void *gpt_base;
+static struct clk *gpt_clk;
+
+static int clockevent_next_event(unsigned long evt,
+ struct clock_event_device *clk_event_dev);
+
+static void __init spear_clocksource_init(void)
+{
+ u32 tick_rate;
+ u16 val;
+
+ /* program the prescaler (/256)*/
+ writew(CTRL_PRESCALER256, gpt_base + CR(CLKSRC));
+
+ /* find out actual clock driving Timer */
+ tick_rate = clk_get_rate(gpt_clk);
+ tick_rate >>= CTRL_PRESCALER256;
+
+ writew(0xFFFF, gpt_base + LOAD(CLKSRC));
+
+ val = readw(gpt_base + CR(CLKSRC));
+ val &= ~CTRL_ONE_SHOT; /* autoreload mode */
+ val |= CTRL_ENABLE ;
+ writew(val, gpt_base + CR(CLKSRC));
+
+ /* register the clocksource */
+ clocksource_mmio_init(gpt_base + COUNT(CLKSRC), "tmr1", tick_rate,
+ 200, 16, clocksource_mmio_readw_up);
+}
+
+static inline void timer_shutdown(struct clock_event_device *evt)
+{
+ u16 val = readw(gpt_base + CR(CLKEVT));
+
+ /* stop the timer */
+ val &= ~CTRL_ENABLE;
+ writew(val, gpt_base + CR(CLKEVT));
+}
+
+static int spear_shutdown(struct clock_event_device *evt)
+{
+ timer_shutdown(evt);
+
+ return 0;
+}
+
+static int spear_set_oneshot(struct clock_event_device *evt)
+{
+ u16 val;
+
+ /* stop the timer */
+ timer_shutdown(evt);
+
+ val = readw(gpt_base + CR(CLKEVT));
+ val |= CTRL_ONE_SHOT;
+ writew(val, gpt_base + CR(CLKEVT));
+
+ return 0;
+}
+
+static int spear_set_periodic(struct clock_event_device *evt)
+{
+ u32 period;
+ u16 val;
+
+ /* stop the timer */
+ timer_shutdown(evt);
+
+ period = clk_get_rate(gpt_clk) / HZ;
+ period >>= CTRL_PRESCALER16;
+ writew(period, gpt_base + LOAD(CLKEVT));
+
+ val = readw(gpt_base + CR(CLKEVT));
+ val &= ~CTRL_ONE_SHOT;
+ val |= CTRL_ENABLE | CTRL_INT_ENABLE;
+ writew(val, gpt_base + CR(CLKEVT));
+
+ return 0;
+}
+
+static struct clock_event_device clkevt = {
+ .name = "tmr0",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = spear_shutdown,
+ .set_state_periodic = spear_set_periodic,
+ .set_state_oneshot = spear_set_oneshot,
+ .tick_resume = spear_shutdown,
+ .set_next_event = clockevent_next_event,
+ .shift = 0, /* to be computed */
+};
+
+static int clockevent_next_event(unsigned long cycles,
+ struct clock_event_device *clk_event_dev)
+{
+ u16 val = readw(gpt_base + CR(CLKEVT));
+
+ if (val & CTRL_ENABLE)
+ writew(val & ~CTRL_ENABLE, gpt_base + CR(CLKEVT));
+
+ writew(cycles, gpt_base + LOAD(CLKEVT));
+
+ val |= CTRL_ENABLE | CTRL_INT_ENABLE;
+ writew(val, gpt_base + CR(CLKEVT));
+
+ return 0;
+}
+
+static irqreturn_t spear_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clkevt;
+
+ writew(INT_STATUS, gpt_base + IR(CLKEVT));
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction spear_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_TIMER,
+ .handler = spear_timer_interrupt
+};
+
+static void __init spear_clockevent_init(int irq)
+{
+ u32 tick_rate;
+
+ /* program the prescaler */
+ writew(CTRL_PRESCALER16, gpt_base + CR(CLKEVT));
+
+ tick_rate = clk_get_rate(gpt_clk);
+ tick_rate >>= CTRL_PRESCALER16;
+
+ clkevt.cpumask = cpumask_of(0);
+
+ clockevents_config_and_register(&clkevt, tick_rate, 3, 0xfff0);
+
+ setup_irq(irq, &spear_timer_irq);
+}
+
+static const struct of_device_id timer_of_match[] __initconst = {
+ { .compatible = "st,spear-timer", },
+ { },
+};
+
+void __init spear_setup_of_timer(void)
+{
+ struct device_node *np;
+ int irq, ret;
+
+ np = of_find_matching_node(NULL, timer_of_match);
+ if (!np) {
+ pr_err("%s: No timer passed via DT\n", __func__);
+ return;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ pr_err("%s: No irq passed for timer via DT\n", __func__);
+ return;
+ }
+
+ gpt_base = of_iomap(np, 0);
+ if (!gpt_base) {
+ pr_err("%s: of iomap failed\n", __func__);
+ return;
+ }
+
+ gpt_clk = clk_get_sys("gpt0", NULL);
+ if (IS_ERR(gpt_clk)) {
+ pr_err("%s:couldn't get clk for gpt\n", __func__);
+ goto err_iomap;
+ }
+
+ ret = clk_prepare_enable(gpt_clk);
+ if (ret < 0) {
+ pr_err("%s:couldn't prepare-enable gpt clock\n", __func__);
+ goto err_prepare_enable_clk;
+ }
+
+ spear_clockevent_init(irq);
+ spear_clocksource_init();
+
+ return;
+
+err_prepare_enable_clk:
+ clk_put(gpt_clk);
+err_iomap:
+ iounmap(gpt_base);
+}