aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/boot/dts/imx6q-sabrelite.dts48
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi41
-rw-r--r--arch/arm/include/asm/mach/arch.h1
-rw-r--r--arch/arm/include/asm/system.h1
-rw-r--r--arch/arm/kernel/machine_kexec.c4
-rw-r--r--arch/arm/kernel/process.c81
-rw-r--r--arch/arm/kernel/setup.c3
-rw-r--r--arch/arm/kernel/smp.c54
-rw-r--r--arch/arm/lib/Makefile3
-rw-r--r--arch/arm/lib/call_with_stack.S44
-rw-r--r--arch/arm/mach-clps711x/include/mach/system.h2
-rw-r--r--arch/arm/mach-ebsa110/include/mach/system.h2
-rw-r--r--arch/arm/mach-footbridge/include/mach/system.h2
-rw-r--r--arch/arm/mach-imx/Kconfig2
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/clock-imx6q.c121
-rw-r--r--arch/arm/mach-imx/gpc.c21
-rw-r--r--arch/arm/mach-imx/head-v7.S1
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c89
-rw-r--r--arch/arm/mach-imx/pm-imx6q.c128
-rw-r--r--arch/arm/mach-imx/src.c23
-rw-r--r--arch/arm/mach-imx/suspend-imx6q.S308
-rw-r--r--arch/arm/mach-iop32x/include/mach/system.h2
-rw-r--r--arch/arm/mach-iop33x/include/mach/system.h2
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/system.h2
-rw-r--r--arch/arm/mach-ks8695/include/mach/system.h2
-rw-r--r--arch/arm/mach-mmp/include/mach/system.h4
-rw-r--r--arch/arm/mach-mxs/system.c2
-rw-r--r--arch/arm/mach-pnx4008/include/mach/system.h2
-rw-r--r--arch/arm/mach-pxa/reset.c2
-rw-r--r--arch/arm/mach-rpc/include/mach/system.h2
-rw-r--r--arch/arm/mach-s3c2410/include/mach/system-reset.h4
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/system.h2
-rw-r--r--arch/arm/mach-sa1100/include/mach/system.h2
-rw-r--r--arch/arm/mach-shmobile/include/mach/system.h2
-rw-r--r--arch/arm/mach-w90x900/include/mach/system.h2
-rw-r--r--arch/arm/mm/idmap.c2
-rw-r--r--arch/arm/mm/nommu.c2
-rw-r--r--arch/arm/plat-mxc/audmux-v2.c63
-rw-r--r--arch/arm/plat-mxc/cpufreq.c89
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/dma.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/esdhc.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/mx6q.h6
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc.h1
-rw-r--r--arch/arm/plat-mxc/system.c2
-rw-r--r--arch/arm/plat-spear/include/plat/system.h2
47 files changed, 1078 insertions, 110 deletions
diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index 4ee2af9275c..9e8557f5f13 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -23,12 +23,24 @@
soc {
aips-bus@02000000 { /* AIPS1 */
+ spba-bus@02000000 {
+ ssi@0202c000 { /* SSI2 */
+ status = "okay";
+ fsl,ssi-uses-dma;
+ fsl,ssi-synchronous-mode;
+ };
+ };
+
ldb@020e0000 {
disp-pwr-gpios = <&gpio1 0 0>; /* gpio2 0 */
mode = "sin0";
ext_ref = "true";
lvds0 = <1 0>;
};
+
+ wdog@020bc000 { /* WDOG1 */
+ status = "okay";
+ };
};
aips-bus@02100000 { /* AIPS2 */
@@ -50,10 +62,26 @@
status = "okay";
};
+ audmux@021d8000 {
+ status = "okay";
+ };
+
uart2: uart@021e8000 {
status = "okay";
};
+ i2c@021a0000 { /* I2C1 */
+ status = "okay";
+ clock-frequency = <100000>;
+
+ codec: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ VDDA-supply = <&reg_2P5V>;
+ VDDIO-supply = <&reg_3P3V>;
+ };
+ };
+
i2c@021a4000 { /* I2C2 */
status = "okay";
clock-frequency = <100000>;
@@ -140,4 +168,24 @@
compatible = "fsl,vout_ipuv3";
};
};
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_2P5V: regulator-2P5V {
+ compatible = "regulator-fixed";
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ reg_3P3V: regulator-3P3V {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index d450515f48d..e25883bc522 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -29,6 +29,13 @@
compatible = "arm,cortex-a9";
reg = <0>;
next-level-cache = <&L2>;
+ cpu-freqs = <996000000 792000000 396000000 198000000>;
+ cpu-volts = < /* min max */
+ 1225000 1450000 /* 996M */
+ 1100000 1450000 /* 792M */
+ 950000 1450000 /* 396M */
+ 850000 1450000>; /* 198M */
+ trans-latency = <61036>; /* two CLK32 periods */
};
cpu@1 {
@@ -178,18 +185,27 @@
};
ssi@02028000 { /* SSI1 */
+ compatible = "fsl,imx6q-ssi", "fsl,imx1-ssi";
reg = <0x02028000 0x4000>;
interrupts = <0 46 0x04>;
+ fsl,dma-events = <38 37>;
+ status = "disabled";
};
ssi@0202c000 { /* SSI2 */
+ compatible = "fsl,imx6q-ssi", "fsl,imx1-ssi";
reg = <0x0202c000 0x4000>;
interrupts = <0 47 0x04>;
+ fsl,dma-events = <42 41>;
+ status = "disabled";
};
ssi@02030000 { /* SSI3 */
+ compatible = "fsl,imx6q-ssi", "fsl,imx1-ssi";
reg = <0x02030000 0x4000>;
interrupts = <0 48 0x04>;
+ fsl,dma-events = <46 45>;
+ status = "disabled";
};
asrc@02034000 {
@@ -364,6 +380,7 @@
};
snvs@020cc000 {
+ compatible = "fsl,snvs";
reg = <0x020cc000 0x4000>;
interrupts = <0 19 0x04 0 20 0x04>;
};
@@ -391,6 +408,7 @@
};
iomuxc@020e0000 {
+ compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
};
@@ -413,6 +431,7 @@
compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma";
reg = <0x020ec000 0x4000>;
interrupts = <0 2 0x04>;
+ fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q-to1.bin";
};
};
@@ -518,11 +537,15 @@
};
ocotp@021bc000 {
- reg = <0x021bc000 0x4000>;
+ compatible = "fsl,imx6q-ocotp";
+ reg = <0x021bc000 0x8000>;
+ interrupts = <0 21 0x04>;
};
- ocotp@021c0000 {
- reg = <0x021c0000 0x4000>;
+ viim@021bc000 {
+ compatible = "fsl,imx6q-viim";
+ reg = <0x021bc000 0x4000>,
+ <0x021c0000 0x4000>;
interrupts = <0 21 0x04>;
};
@@ -537,7 +560,9 @@
};
audmux@021d8000 {
+ compatible = "fsl,audmux-v2";
reg = <0x021d8000 0x4000>;
+ status = "disabled";
};
mipi@021dc000 { /* MIPI-CSI */
@@ -602,6 +627,16 @@
revision = <4>;
};
+ galcore@virtual {
+ compatible = "viv,galcore";
+ reg = <0x00130000 0x4000>, /* gc2000 */
+ <0x00134000 0x4000>, /* gc320 */
+ <0x02204000 0x4000>; /* gc355 */
+ interrupts = <0 9 0x04 /* gc2000 */
+ 0 10 0x04 /* gc320 */
+ 0 11 0x04>; /* gc355 */
+ };
+
ahci@0x02200000 { /* AHCI SATA */
compatible = "fsl,imx6q-ahci";
reg = <0x02200000 0x4000>;
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 2b0efc3104a..61ae6bb42c5 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -46,6 +46,7 @@ struct machine_desc {
#ifdef CONFIG_MULTI_IRQ_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
+ void (*restart)(char, const char *);
};
/*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 984014b9264..fe7de7571ba 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -101,6 +101,7 @@ extern int __pure cpu_architecture(void);
extern void cpu_init(void);
void arm_machine_restart(char mode, const char *cmd);
+void soft_restart(unsigned long);
extern void (*arm_pm_restart)(char str, const char *cmd);
#define UDBG_UNDEFINED (1 << 0)
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index e59bbd496c3..29620b632ed 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -16,7 +16,7 @@
extern const unsigned char relocate_new_kernel[];
extern const unsigned int relocate_new_kernel_size;
-extern void setup_mm_for_reboot(char mode);
+extern void setup_mm_for_reboot(void);
extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
@@ -113,7 +113,7 @@ void machine_kexec(struct kimage *image)
kexec_reinit();
local_irq_disable();
local_fiq_disable();
- setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
+ setup_mm_for_reboot();
flush_cache_all();
outer_flush_all();
outer_disable();
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 3d0c6fb74ae..423bb201945 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -57,7 +57,7 @@ static const char *isa_modes[] = {
"ARM" , "Thumb" , "Jazelle", "ThumbEE"
};
-extern void setup_mm_for_reboot(char mode);
+extern void setup_mm_for_reboot(void);
static volatile int hlt_counter;
@@ -92,18 +92,24 @@ static int __init hlt_setup(char *__unused)
__setup("nohlt", nohlt_setup);
__setup("hlt", hlt_setup);
-void arm_machine_restart(char mode, const char *cmd)
+extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+typedef void (*phys_reset_t)(unsigned long);
+
+/*
+ * A temporary stack to use for CPU reset. This is static so that we
+ * don't clobber it with the identity mapping. When running with this
+ * stack, any references to the current task *will not work* so you
+ * should really do as little as possible before jumping to your reset
+ * code.
+ */
+static u64 soft_restart_stack[16];
+
+static void __soft_restart(void *addr)
{
- /* Disable interrupts first */
- local_irq_disable();
- local_fiq_disable();
+ phys_reset_t phys_reset;
- /*
- * Tell the mm system that we are going to reboot -
- * we may need it to insert some 1:1 mappings so that
- * soft boot works.
- */
- setup_mm_for_reboot(mode);
+ /* Take out a flat memory mapping. */
+ setup_mm_for_reboot();
/* Clean and invalidate caches */
flush_cache_all();
@@ -114,18 +120,41 @@ void arm_machine_restart(char mode, const char *cmd)
/* Push out any further dirty data, and ensure cache is empty */
flush_cache_all();
- /*
- * Now call the architecture specific reboot code.
- */
- arch_reset(mode, cmd);
+ /* Switch to the identity mapping. */
+ phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+ phys_reset((unsigned long)addr);
- /*
- * Whoops - the architecture was unable to reboot.
- * Tell the user!
- */
- mdelay(1000);
- printk("Reboot failed -- System halted\n");
- while (1);
+ /* Should never get here. */
+ BUG();
+}
+
+void soft_restart(unsigned long addr)
+{
+ u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
+
+ /* Disable interrupts first */
+ local_irq_disable();
+ local_fiq_disable();
+
+ /* Disable the L2 if we're the last man standing. */
+ if (num_online_cpus() == 1)
+ outer_disable();
+
+ /* Change to the new stack and continue with the reset. */
+ call_with_stack(__soft_restart, (void *)addr, (void *)stack);
+
+ /* Should never get here. */
+ BUG();
+}
+
+void arm_machine_restart(char mode, const char *cmd)
+{
+ /* Disable interrupts first */
+ local_irq_disable();
+ local_fiq_disable();
+
+ /* Call the architecture specific reboot code. */
+ arch_reset(mode, cmd);
}
/*
@@ -253,7 +282,15 @@ void machine_power_off(void)
void machine_restart(char *cmd)
{
machine_shutdown();
+
arm_pm_restart(reboot_mode, cmd);
+
+ /* Give a grace period for failure to restart of 1s */
+ mdelay(1000);
+
+ /* Whoops - the platform was unable to reboot. Tell the user! */
+ printk("Reboot failed -- System halted\n");
+ while (1);
}
void __show_regs(struct pt_regs *regs)
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 8fc2c8fcbdc..d662dca774d 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -928,6 +928,9 @@ void __init setup_arch(char **cmdline_p)
paging_init(mdesc);
request_standard_resources(mdesc);
+ if (mdesc->restart)
+ arm_pm_restart = mdesc->restart;
+
unflatten_device_tree();
#ifdef CONFIG_SMP
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ef5640b9e21..ac9cadc3850 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@
#include <linux/percpu.h>
#include <linux/clockchips.h>
#include <linux/completion.h>
+#include <linux/cpufreq.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
@@ -631,3 +632,56 @@ int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
}
+
+#ifdef CONFIG_CPU_FREQ
+
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+static unsigned long global_l_p_j_ref;
+static unsigned long global_l_p_j_ref_freq;
+
+static int cpufreq_callback(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freq = data;
+ int cpu = freq->cpu;
+
+ if (freq->flags & CPUFREQ_CONST_LOOPS)
+ return NOTIFY_OK;
+
+ if (!per_cpu(l_p_j_ref, cpu)) {
+ per_cpu(l_p_j_ref, cpu) =
+ per_cpu(cpu_data, cpu).loops_per_jiffy;
+ per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+ if (!global_l_p_j_ref) {
+ global_l_p_j_ref = loops_per_jiffy;
+ global_l_p_j_ref_freq = freq->old;
+ }
+ }
+
+ if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+ global_l_p_j_ref_freq,
+ freq->new);
+ per_cpu(cpu_data, cpu).loops_per_jiffy =
+ cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+ per_cpu(l_p_j_ref_freq, cpu),
+ freq->new);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_notifier = {
+ .notifier_call = cpufreq_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+ return cpufreq_register_notifier(&cpufreq_notifier,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+#endif
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index cf73a7f742d..0ade0acc1ed 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -13,7 +13,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
testchangebit.o testclearbit.o testsetbit.o \
ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
ucmpdi2.o lib1funcs.o div64.o \
- io-readsb.o io-writesb.o io-readsl.o io-writesl.o
+ io-readsb.o io-writesb.o io-readsl.o io-writesl.o \
+ call_with_stack.o
mmu-y := clear_user.o copy_page.o getuser.o putuser.o
diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S
new file mode 100644
index 00000000000..916c80f13ae
--- /dev/null
+++ b/arch/arm/lib/call_with_stack.S
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/lib/call_with_stack.S
+ *
+ * Copyright (C) 2011 ARM Ltd.
+ * Written by Will Deacon <will.deacon@arm.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.
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * void call_with_stack(void (*fn)(void *), void *arg, void *sp)
+ *
+ * Change the stack to that pointed at by sp, then invoke fn(arg) with
+ * the new stack.
+ */
+ENTRY(call_with_stack)
+ str sp, [r2, #-4]!
+ str lr, [r2, #-4]!
+
+ mov sp, r2
+ mov r2, r0
+ mov r0, r1
+
+ adr lr, BSYM(1f)
+ mov pc, r2
+
+1: ldr lr, [sp]
+ ldr sp, [sp, #4]
+ mov pc, lr
+ENDPROC(call_with_stack)
diff --git a/arch/arm/mach-clps711x/include/mach/system.h b/arch/arm/mach-clps711x/include/mach/system.h
index f916cd7a477..6c119937d39 100644
--- a/arch/arm/mach-clps711x/include/mach/system.h
+++ b/arch/arm/mach-clps711x/include/mach/system.h
@@ -34,7 +34,7 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
- cpu_reset(0);
+ soft_restart(0);
}
#endif
diff --git a/arch/arm/mach-ebsa110/include/mach/system.h b/arch/arm/mach-ebsa110/include/mach/system.h
index 9a26245bf1f..0d5df72a03f 100644
--- a/arch/arm/mach-ebsa110/include/mach/system.h
+++ b/arch/arm/mach-ebsa110/include/mach/system.h
@@ -34,6 +34,6 @@ static inline void arch_idle(void)
asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
}
-#define arch_reset(mode, cmd) cpu_reset(0x80000000)
+#define arch_reset(mode, cmd) soft_restart(0x80000000)
#endif
diff --git a/arch/arm/mach-footbridge/include/mach/system.h b/arch/arm/mach-footbridge/include/mach/system.h
index 0b293156620..249f895910f 100644
--- a/arch/arm/mach-footbridge/include/mach/system.h
+++ b/arch/arm/mach-footbridge/include/mach/system.h
@@ -24,7 +24,7 @@ static inline void arch_reset(char mode, const char *cmd)
/*
* Jump into the ROM
*/
- cpu_reset(0x41000000);
+ soft_restart(0x41000000);
} else {
if (machine_is_netwinder()) {
/* open up the SuperIO chip
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 47dc42520cd..ccb9c440b4a 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -595,6 +595,7 @@ comment "i.MX6 family:"
config SOC_IMX6Q
bool "i.MX6 Quad support"
+ select ARCH_HAS_CPUFREQ
select ARM_GIC
select CACHE_L2X0
select CPU_V7
@@ -606,6 +607,7 @@ config SOC_IMX6Q
select ARM_CPU_SUSPEND if PM
select USE_OF
select ARCH_MXC_IOMUX_V3
+ select ARCH_MXC_AUDMUX_V2
help
This enables support for Freescale i.MX6 Quad processor.
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index f5920c24f7d..2901584d47f 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -73,5 +73,5 @@ obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
ifeq ($(CONFIG_PM),y)
-obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o
+obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o suspend-imx6q.o
endif
diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c
index a54f8c9ad14..737a0048d19 100644
--- a/arch/arm/mach-imx/clock-imx6q.c
+++ b/arch/arm/mach-imx/clock-imx6q.c
@@ -132,6 +132,8 @@
#define CG14 28
#define CG15 30
+#define BM_CCR_RBC_EN (0x1 << 27)
+
#define BM_CCSR_PLL1_SW_SEL (0x1 << 2)
#define BM_CCSR_STEP_SEL (0x1 << 8)
@@ -346,6 +348,12 @@
#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26)
#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27)
+#define BP_CCOSR_CKO1_EN 7
+#define BP_CCOSR_CKO1_PODF 4
+#define BM_CCOSR_CKO1_PODF (0x7 << 4)
+#define BP_CCOSR_CKO1_SEL 0
+#define BM_CCOSR_CKO1_SEL (0xf << 0)
+
#define FREQ_480M 480000000
#define FREQ_528M 528000000
#define FREQ_594M 594000000
@@ -416,6 +424,7 @@ static struct clk ipu1_di1_clk;
static struct clk ipu2_di0_clk;
static struct clk ipu2_di1_clk;
static struct clk enfc_clk;
+static struct clk cko1_clk;
static struct clk dummy_clk = {};
static unsigned long external_high_reference;
@@ -961,6 +970,24 @@ static void _clk_disable(struct clk *clk)
writel_relaxed(reg, clk->enable_reg);
}
+static int _clk_enable_1b(struct clk *clk)
+{
+ u32 reg;
+ reg = readl_relaxed(clk->enable_reg);
+ reg |= 0x1 << clk->enable_shift;
+ writel_relaxed(reg, clk->enable_reg);
+
+ return 0;
+}
+
+static void _clk_disable_1b(struct clk *clk)
+{
+ u32 reg;
+ reg = readl_relaxed(clk->enable_reg);
+ reg &= ~(0x1 << clk->enable_shift);
+ writel_relaxed(reg, clk->enable_reg);
+}
+
struct divider {
struct clk *clk;
void __iomem *reg;
@@ -1006,6 +1033,7 @@ DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE);
DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE);
DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP);
DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP);
+DEF_CLK_DIV1(cko1_div, &cko1_clk, CCOSR, CKO1);
#define DEF_CLK_DIV2(d, c, r, b) \
static struct divider d = { \
@@ -1061,6 +1089,7 @@ static struct divider *dividers[] = {
&enfc_div,
&spdif_div,
&asrc_serial_div,
+ &cko1_div,
};
static unsigned long ldb_di_clk_get_rate(struct clk *clk)
@@ -1648,6 +1677,32 @@ DEF_IPU_DI_MUX(CSCDR2, 2, 1);
DEF_IPU_MUX(1);
DEF_IPU_MUX(2);
+static struct multiplexer cko1_mux = {
+ .clk = &cko1_clk,
+ .reg = CCOSR,
+ .bp = BP_CCOSR_CKO1_SEL,
+ .bm = BM_CCOSR_CKO1_SEL,
+ .parents = {
+ &pll3_usb_otg,
+ &pll2_bus,
+ &pll1_sys,
+ &pll5_video,
+ &dummy_clk,
+ &axi_clk,
+ &enfc_clk,
+ &ipu1_di0_clk,
+ &ipu1_di1_clk,
+ &ipu2_di0_clk,
+ &ipu2_di1_clk,
+ &ahb_clk,
+ &ipg_clk,
+ &ipg_perclk,
+ &ckil_clk,
+ &pll4_audio,
+ NULL
+ },
+};
+
static struct multiplexer *multiplexers[] = {
&axi_mux,
&periph_mux,
@@ -1690,6 +1745,7 @@ static struct multiplexer *multiplexers[] = {
&ipu2_di1_mux,
&ipu1_mux,
&ipu2_mux,
+ &cko1_mux,
};
static int _clk_set_parent(struct clk *clk, struct clk *parent)
@@ -1713,7 +1769,7 @@ static int _clk_set_parent(struct clk *clk, struct clk *parent)
break;
i++;
}
- if (!m->parents[i])
+ if (!m->parents[i] || m->parents[i] == &dummy_clk)
return -EINVAL;
val = readl_relaxed(m->reg);
@@ -1770,6 +1826,21 @@ DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg);
.secondary = s, \
}
+#define DEF_CLK_1B(name, er, es, p, s) \
+ static struct clk name = { \
+ __INIT_CLK_DEBUG(name) \
+ .enable_reg = er, \
+ .enable_shift = es, \
+ .enable = _clk_enable_1b, \
+ .disable = _clk_disable_1b, \
+ .get_rate = _clk_get_rate, \
+ .set_rate = _clk_set_rate, \
+ .round_rate = _clk_round_rate, \
+ .set_parent = _clk_set_parent, \
+ .parent = p, \
+ .secondary = s, \
+ }
+
DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL);
DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL);
DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL);
@@ -1836,7 +1907,8 @@ DEF_CLK(usdhc3_clk, CCGR6, CG3, &pll2_pfd_400m, NULL);
DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL);
DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL);
DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL);
-DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL);
+DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, &ocram_clk);
+DEF_CLK_1B(cko1_clk, CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL);
static int pcie_clk_enable(struct clk *clk)
{
@@ -2019,6 +2091,10 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("imx6q-ahci", "ahci_phy", ahci_phy_clk),
_REGISTER_CLOCK("imx6q-ahci", "ahci_dma", ahci_dma_clk),
_REGISTER_CLOCK(NULL, "cpu", arm_clk),
+ _REGISTER_CLOCK(NULL, "gpu3d_clk", gpu3d_core_clk),
+ _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_core_clk),
+ _REGISTER_CLOCK(NULL, "gpu3d_shader_clk", gpu3d_shader_clk),
+ _REGISTER_CLOCK(NULL, "ocotp_clk", iim_clk),
_REGISTER_CLOCK(NULL, "ipu1_clk", ipu1_clk),
_REGISTER_CLOCK(NULL, "ipu2_clk", ipu2_clk),
_REGISTER_CLOCK(NULL, "ipu1_di0_clk", ipu1_di0_clk),
@@ -2030,39 +2106,50 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "ldb_di1_clk", ldb_di1_clk),
_REGISTER_CLOCK(NULL, "vpu_clk", vpu_clk),
_REGISTER_CLOCK(NULL, "gpt_clk", gpt_clk),
+ _REGISTER_CLOCK("202c000.ssi", NULL, ssi2_clk),
+ _REGISTER_CLOCK(NULL, "clko_clk", cko1_clk),
};
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
- u32 val = readl_relaxed(CLPCR);
+ u32 clpcr = readl_relaxed(CLPCR);
+ u32 ccr = readl_relaxed(CCR);
- val &= ~BM_CLPCR_LPM;
+ clpcr &= ~(BM_CLPCR_LPM | BM_CLPCR_VSTBY | BM_CLPCR_SBYOS
+ | BM_CLPCR_STBY_COUNT | BM_CLPCR_WB_PER_AT_LPM);
+ ccr &= ~(BM_CCR_RBC_EN);
switch (mode) {
case WAIT_CLOCKED:
break;
case WAIT_UNCLOCKED:
- val |= 0x1 << BP_CLPCR_LPM;
+ clpcr |= 0x1 << BP_CLPCR_LPM;
break;
case STOP_POWER_ON:
- val |= 0x2 << BP_CLPCR_LPM;
+ clpcr |= 0x2 << BP_CLPCR_LPM;
break;
case WAIT_UNCLOCKED_POWER_OFF:
- val |= 0x1 << BP_CLPCR_LPM;
- val &= ~BM_CLPCR_VSTBY;
- val &= ~BM_CLPCR_SBYOS;
- val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
+ clpcr |= 0x1 << BP_CLPCR_LPM;
break;
case STOP_POWER_OFF:
- val |= 0x2 << BP_CLPCR_LPM;
- val |= 0x3 << BP_CLPCR_STBY_COUNT;
- val |= BM_CLPCR_VSTBY;
- val |= BM_CLPCR_SBYOS;
- val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
+ clpcr |= 0x2 << BP_CLPCR_LPM;
+ clpcr |= 0x3 << BP_CLPCR_STBY_COUNT;
+ clpcr |= BM_CLPCR_VSTBY;
+ clpcr |= BM_CLPCR_SBYOS;
break;
+ case ARM_POWER_OFF:
+ clpcr |= 0x2 << BP_CLPCR_LPM;
+ clpcr |= 0x3 << BP_CLPCR_STBY_COUNT;
+ clpcr |= BM_CLPCR_VSTBY;
+ clpcr |= BM_CLPCR_SBYOS;
+ clpcr |= BM_CLPCR_WB_PER_AT_LPM;
+ /* assert anatop_reg_bypass signal */
+ ccr |= BM_CCR_RBC_EN;
+ break;
default:
return -EINVAL;
}
- writel_relaxed(val, CLPCR);
+ writel_relaxed(clpcr, CLPCR);
+ writel_relaxed(ccr, CCR);
return 0;
}
@@ -2144,6 +2231,8 @@ int __init mx6q_clocks_init(void)
clk_set_rate(&usdhc3_clk, 49500000);
clk_set_rate(&usdhc4_clk, 49500000);
+ clk_set_parent(&cko1_clk, &ahb_clk);
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
base = of_iomap(np, 0);
WARN_ON(!base);
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index e1537f9e45b..8fc255b6daa 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -17,15 +17,36 @@
#include <linux/of_irq.h>
#include <asm/hardware/gic.h>
+#define GPC_CNTR 0x000
#define GPC_IMR1 0x008
+#define GPC_ISR1 0x018
+#define GPC_ISR2 0x01c
+#define GPC_ISR3 0x020
+#define GPC_ISR4 0x024
#define GPC_PGC_CPU_PDN 0x2a0
#define IMR_NUM 4
+#define ISR_NUM 4
static void __iomem *gpc_base;
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];
+bool imx_gpc_wake_irq_pending(void)
+{
+ void __iomem *reg_isr1 = gpc_base + GPC_ISR1;
+ int i;
+ u32 val;
+
+ for (i = 0; i < ISR_NUM; i++) {
+ val = readl_relaxed(reg_isr1 + i * 4);
+ if (val & gpc_wake_irqs[i])
+ return true;
+ }
+
+ return false;
+}
+
void imx_gpc_pre_suspend(void)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S
index ea12b0c4a05..7e49deb128a 100644
--- a/arch/arm/mach-imx/head-v7.S
+++ b/arch/arm/mach-imx/head-v7.S
@@ -16,7 +16,6 @@
#include <asm/hardware/cache-l2x0.h>
.section ".text.head", "ax"
- __CPUINIT
/*
* The secondary kernel init calls v7_flush_dcache_all before it enables
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index b33b9f2807e..4978c7aa95b 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -10,16 +10,21 @@
* http://www.gnu.org/copyleft/gpl.html
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/micrel_phy.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/fsl_devices.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
@@ -34,6 +39,12 @@
#include "devices-imx6q.h"
static iomux_v3_cfg_t imx6q_sabrelite_pads[] = {
+ /* AUDMUX */
+ MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD,
+ MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC,
+ MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD,
+ MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS,
+
/* DISPLAY */
MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK,
MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15,
@@ -65,6 +76,11 @@ static iomux_v3_cfg_t imx6q_sabrelite_pads[] = {
MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23,
/* PWM1 */
MX6Q_PAD_SD1_CMD__PWM4_PWMO,
+ /* sgtl5000 clock */
+ MX6Q_PAD_GPIO_0__CCM_CLKO,
+ /* I2C1, SGTL5000 */
+ MX6Q_PAD_EIM_D21__I2C1_SCL, /* GPIO3[21] */
+ MX6Q_PAD_EIM_D28__I2C1_SDA, /* GPIO3[28] */
/* I2C2 */
MX6Q_PAD_KEY_COL3__I2C2_SCL,
MX6Q_PAD_KEY_ROW3__I2C2_SDA,
@@ -91,6 +107,36 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev)
return 0;
}
+void imx6q_restart(char mode, const char *cmd)
+{
+ struct device_node *np;
+ void __iomem *wdog_base;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt");
+ wdog_base = of_iomap(np, 0);
+ if (!wdog_base)
+ goto soft;
+
+ imx_src_prepare_restart();
+
+ /* enable wdog */
+ writew_relaxed(1 << 2, wdog_base);
+ /* write twice to ensure the request will not get ignored */
+ writew_relaxed(1 << 2, wdog_base);
+
+ /* wait for reset to assert ... */
+ mdelay(500);
+
+ pr_err("Watchdog reset failed to assert reset\n");
+
+ /* delay to allow the serial port to show the message */
+ mdelay(50);
+
+soft:
+ /* we'll take a jump through zero as a poor second */
+ soft_restart(0);
+}
+
static int mx6q_ipuv3_init(int id)
{
imx_reset_ipu(id);
@@ -126,6 +172,45 @@ static const struct of_dev_auxdata imx6q_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("fsl,imx6q-ahci", MX6Q_SATA_BASE_ADDR, "imx6q-ahci", &imx_sata_pdata),
};
+static struct mxc_audio_platform_data mx6_sabrelite_audio_data;
+
+static int mx6_sabrelite_sgtl5000_init(void)
+{
+ struct clk *clko;
+ int rate;
+
+ clko = clk_get(NULL, "clko_clk");
+ if (IS_ERR(clko)) {
+ pr_err("can't get CLKO clock.\n");
+ return PTR_ERR(clko);
+ }
+ rate = clk_round_rate(clko, 16000000);
+ if (rate < 8000000 || rate > 27000000) {
+ pr_err("Error:SGTL5000 mclk freq %d out of range!\n", rate);
+ clk_put(clko);
+ return -1;
+ }
+ mx6_sabrelite_audio_data.sysclk = rate;
+ clk_set_rate(clko, rate);
+ clk_enable(clko);
+ return 0;
+}
+
+static struct mxc_audio_platform_data mx6_sabrelite_audio_data = {
+ .ssi_num = 1,
+ .src_port = 2,
+ .ext_port = 4,
+ .init = mx6_sabrelite_sgtl5000_init,
+ .hp_gpio = -1,
+};
+
+static struct platform_device mx6_sabrelite_audio_device = {
+ .name = "imx-sgtl5000",
+ .dev = {
+ .platform_data = &mx6_sabrelite_audio_data,
+ },
+};
+
static void __init imx6q_init_machine(void)
{
if (of_machine_is_compatible("fsl,imx6q-sabrelite")) {
@@ -140,6 +225,9 @@ static void __init imx6q_init_machine(void)
iram_init(MX6Q_IRAM_BASE_ADDR, MX6Q_IRAM_SIZE);
+ if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
+ platform_device_register(&mx6_sabrelite_audio_device);
+
imx6q_pm_init();
}
@@ -218,4 +306,5 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)")
.timer = &imx6q_timer,
.init_machine = imx6q_init_machine,
.dt_compat = imx6q_dt_compat,
+ .restart = imx6q_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index f20f191d7cc..85b758ec4af 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -13,31 +13,73 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/suspend.h>
+#include <asm/mach/map.h>
#include <asm/cacheflush.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/hardware/cache-l2x0.h>
+#include <mach/iram.h>
#include <mach/common.h>
#include <mach/hardware.h>
+struct imx_iram_pm {
+ void *iram_cpaddr;
+ unsigned long suspend_iram_paddr;
+ unsigned long suspend_iram_size;
+ void *suspend_iram_vaddr;
+ void *reg_ptr[4];
+} imx6q_iram_pm;
+
extern unsigned long phys_l2x0_saved_regs;
+extern void imx6q_suspend(void);
+static void (*suspend_in_iram)(unsigned long iram_paddr,
+ unsigned long iram_vaddr,
+ unsigned long iram_size);
static int imx6q_suspend_finish(unsigned long val)
{
- cpu_do_idle();
+ if ((val == PM_SUSPEND_MEM) && suspend_in_iram) {
+ suspend_in_iram((unsigned long)imx6q_iram_pm.suspend_iram_paddr,
+ (unsigned long)imx6q_iram_pm.suspend_iram_vaddr,
+ (unsigned long)imx6q_iram_pm.suspend_iram_size);
+ } else
+ cpu_do_idle();
+
return 0;
}
+static void imx6q_prepare_suspend_iram(void)
+{
+ unsigned long *iram_stack = imx6q_iram_pm.suspend_iram_vaddr
+ + imx6q_iram_pm.suspend_iram_size;
+
+ *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[3];
+ *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[2];
+ *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[1];
+ *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[0];
+}
+
static int imx6q_pm_enter(suspend_state_t state)
{
switch (state) {
+ case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
- imx6q_set_lpm(STOP_POWER_OFF);
+ if (imx_gpc_wake_irq_pending())
+ return 0;
+
+ if (state == PM_SUSPEND_STANDBY)
+ imx6q_set_lpm(STOP_POWER_OFF);
+ else
+ imx6q_set_lpm(ARM_POWER_OFF);
+
imx_gpc_pre_suspend();
imx_set_cpu_jump(0, v7_cpu_resume);
+ if (state == PM_SUSPEND_MEM)
+ imx6q_prepare_suspend_iram();
/* Zzz ... */
- cpu_suspend(0, imx6q_suspend_finish);
+ cpu_suspend(state, imx6q_suspend_finish);
imx_smp_prepare();
imx_gpc_post_resume();
break;
@@ -48,11 +90,55 @@ static int imx6q_pm_enter(suspend_state_t state)
return 0;
}
+static int imx6q_pm_valid(suspend_state_t state)
+{
+ return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
+}
+
static const struct platform_suspend_ops imx6q_pm_ops = {
.enter = imx6q_pm_enter,
- .valid = suspend_valid_only_mem,
+ .valid = imx6q_pm_valid,
};
+static int __init imx6q_pm_iram_of_init(void)
+{
+ struct device_node *np;
+
+ /*
+ * these register may already ioremaped, need figure out
+ * one way to save vmalloc space.
+ */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src");
+ imx6q_iram_pm.reg_ptr[0] = of_iomap(np, 0);
+ if (!imx6q_iram_pm.reg_ptr[0])
+ goto err0;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc");
+ imx6q_iram_pm.reg_ptr[1] = of_iomap(np, 0);
+ if (!imx6q_iram_pm.reg_ptr[1])
+ goto err1;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc");
+ imx6q_iram_pm.reg_ptr[2] = of_iomap(np, 0);
+ if (!imx6q_iram_pm.reg_ptr[2])
+ goto err2;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+ imx6q_iram_pm.reg_ptr[3] = of_iomap(np, 0);
+ if (!imx6q_iram_pm.reg_ptr[3])
+ goto err3;
+
+ return 0;
+err3:
+ iounmap(imx6q_iram_pm.reg_ptr[2]);
+err2:
+ iounmap(imx6q_iram_pm.reg_ptr[1]);
+err1:
+ iounmap(imx6q_iram_pm.reg_ptr[0]);
+err0:
+ return -EINVAL;
+}
+
void __init imx6q_pm_init(void)
{
/*
@@ -67,4 +153,38 @@ void __init imx6q_pm_init(void)
phys_l2x0_saved_regs = __pa(&l2x0_saved_regs);
suspend_set_ops(&imx6q_pm_ops);
+
+ /* Move suspend routine into iRAM */
+ imx6q_iram_pm.suspend_iram_size = SZ_4K;
+ imx6q_iram_pm.iram_cpaddr = iram_alloc(imx6q_iram_pm.suspend_iram_size,
+ &imx6q_iram_pm.suspend_iram_paddr);
+ if (imx6q_iram_pm.iram_cpaddr) {
+ if (imx6q_pm_iram_of_init() < 0) {
+ iram_free(imx6q_iram_pm.suspend_iram_paddr,
+ imx6q_iram_pm.suspend_iram_size);
+ return;
+ }
+ /*
+ * Need to remap the area here since we want the memory region
+ * to be noncached & executable.
+ */
+ imx6q_iram_pm.suspend_iram_vaddr =
+ __arm_ioremap(imx6q_iram_pm.suspend_iram_paddr,
+ imx6q_iram_pm.suspend_iram_size,
+ MT_MEMORY_NONCACHED);
+ pr_info("cpaddr = %p suspend_iram_base=%p\n",
+ imx6q_iram_pm.iram_cpaddr,
+ imx6q_iram_pm.suspend_iram_vaddr);
+
+ /*
+ * Need to run the suspend code from IRAM as the DDR needs
+ * to be put into low power mode manually.
+ */
+ memcpy(imx6q_iram_pm.iram_cpaddr, imx6q_suspend,
+ imx6q_iram_pm.suspend_iram_size);
+
+ suspend_in_iram = (void *)imx6q_iram_pm.suspend_iram_vaddr;
+
+ } else
+ suspend_in_iram = NULL;
}
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index 9c6b01c488f..1f3d0de521e 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -20,6 +20,7 @@
#define SRC_SCR 0x000
#define SRC_SIMR 0x018
#define SRC_GPR1 0x020
+#define BP_SRC_SCR_WARM_RESET_ENABLE 0
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22
#define BP_SRC_SCR_VPU_RST 2
@@ -91,11 +92,33 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
src_base + SRC_GPR1 + cpu * 8);
}
+void imx_src_prepare_restart(void)
+{
+ u32 val;
+
+ /* clear enable bits of secondary cores */
+ val = readl_relaxed(src_base + SRC_SCR);
+ val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);
+ writel_relaxed(val, src_base + SRC_SCR);
+
+ /* clear persistent entry register of primary core */
+ writel_relaxed(0, src_base + SRC_GPR1);
+}
+
void __init imx_src_init(void)
{
struct device_node *np;
+ u32 val;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src");
src_base = of_iomap(np, 0);
WARN_ON(!src_base);
+
+ /*
+ * force warm reset sources to generate cold reset
+ * for a more reliable restart
+ */
+ val = readl_relaxed(src_base + SRC_SCR);
+ val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
+ writel_relaxed(val, src_base + SRC_SCR);
}
diff --git a/arch/arm/mach-imx/suspend-imx6q.S b/arch/arm/mach-imx/suspend-imx6q.S
new file mode 100644
index 00000000000..f803e2b7b11
--- /dev/null
+++ b/arch/arm/mach-imx/suspend-imx6q.S
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/linkage.h>
+#include <mach/hardware.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define SRC_GPR1_OFFSET 0x020
+#define SRC_GPR2_OFFSET 0x024
+#define MMDC_MAPSR_OFFSET 0x404
+#define MMDC_MAPSR_PSS (1 << 4)
+#define MMDC_MAPSR_PSD (1 << 0)
+#define ANATOP_REG_2P5 0x130
+
+.macro ddr_io_save
+ ldr r4, [r9, #0x5ac] /* DRAM_DQM0 */
+ ldr r5, [r9, #0x5b4] /* DRAM_DQM1 */
+ ldr r6, [r9, #0x528] /* DRAM_DQM2 */
+ ldr r7, [r9, #0x520] /* DRAM_DQM3 */
+ stmfd sp!, {r4-r7}
+
+ ldr r4, [r9, #0x514] /* DRAM_DQM4 */
+ ldr r5, [r9, #0x510] /* DRAM_DQM5 */
+ ldr r6, [r9, #0x5bc] /* DRAM_DQM6 */
+ ldr r7, [r9, #0x5c4] /* DRAM_DQM7 */
+ stmfd sp!, {r4-r7}
+
+ ldr r4, [r9, #0x56c] /* DRAM_CAS */
+ ldr r5, [r9, #0x578] /* DRAM_RAS */
+ ldr r6, [r9, #0x588] /* DRAM_SDCLK_0 */
+ ldr r7, [r9, #0x594] /* DRAM_SDCLK_1 */
+ stmfd sp!, {r4-r7}
+
+ ldr r5, [r9, #0x750] /* DDRMODE_CTL */
+ ldr r6, [r9, #0x774] /* DDRMODE */
+ stmfd sp!, {r5-r6}
+
+ ldr r4, [r9, #0x5a8] /* DRAM_SDQS0 */
+ ldr r5, [r9, #0x5b0] /* DRAM_SDQS1 */
+ ldr r6, [r9, #0x524] /* DRAM_SDQS2 */
+ ldr r7, [r9, #0x51c] /* DRAM_SDQS3 */
+ stmfd sp!, {r4-r7}
+
+ ldr r4, [r9, #0x518] /* DRAM_SDQS4 */
+ ldr r5, [r9, #0x50c] /* DRAM_SDQS5 */
+ ldr r6, [r9, #0x5b8] /* DRAM_SDQS6 */
+ ldr r7, [r9, #0x5c0] /* DRAM_SDQS7 */
+ stmfd sp!, {r4-r7}
+
+ ldr r4, [r9, #0x784] /* GPR_B0DS */
+ ldr r5, [r9, #0x788] /* GPR_B1DS */
+ ldr r6, [r9, #0x794] /* GPR_B2DS */
+ ldr r7, [r9, #0x79c] /* GPR_B3DS */
+ stmfd sp!, {r4-r7}
+
+ ldr r4, [r9, #0x7a0] /* GPR_B4DS */
+ ldr r5, [r9, #0x7a4] /* GPR_B5DS */
+ ldr r6, [r9, #0x7a8] /* GPR_B6DS */
+ ldr r7, [r9, #0x748] /* GPR_B7DS */
+ stmfd sp!, {r4-r7}
+
+ ldr r5, [r9, #0x74c] /* GPR_ADDS*/
+ ldr r6, [r9, #0x59c] /* DRAM_SODT0*/
+ ldr r7, [r9, #0x5a0] /* DRAM_SODT1*/
+ stmfd sp!, {r5-r7}
+.endm
+
+.macro ddr_io_restore
+ ldmfd sp!, {r5-r7}
+ str r5, [r9, #0x74c] /* GPR_ADDS*/
+ str r6, [r9, #0x59c] /* DRAM_SODT0*/
+ str r7, [r9, #0x5a0] /* DRAM_SODT1*/
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x7a0] /* GPR_B4DS */
+ str r5, [r9, #0x7a4] /* GPR_B5DS */
+ str r6, [r9, #0x7a8] /* GPR_B6DS */
+ str r7, [r9, #0x748] /* GPR_B7DS */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x784] /* GPR_B0DS */
+ str r5, [r9, #0x788] /* GPR_B1DS */
+ str r6, [r9, #0x794] /* GPR_B2DS */
+ str r7, [r9, #0x79c] /* GPR_B3DS */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x518] /* DRAM_SDQS4 */
+ str r5, [r9, #0x50c] /* DRAM_SDQS5 */
+ str r6, [r9, #0x5b8] /* DRAM_SDQS6 */
+ str r7, [r9, #0x5c0] /* DRAM_SDQS7 */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x5a8] /* DRAM_SDQS0 */
+ str r5, [r9, #0x5b0] /* DRAM_SDQS1 */
+ str r6, [r9, #0x524] /* DRAM_SDQS2 */
+ str r7, [r9, #0x51c] /* DRAM_SDQS3 */
+
+ ldmfd sp!, {r5-r6}
+ str r5, [r9, #0x750] /* DDRMODE_CTL */
+ str r6, [r9, #0x774] /* DDRMODE */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x56c] /* DRAM_CAS */
+ str r5, [r9, #0x578] /* DRAM_RAS */
+ str r6, [r9, #0x588] /* DRAM_SDCLK_0 */
+ str r7, [r9, #0x594] /* DRAM_SDCLK_1 */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x514] /* DRAM_DQM4 */
+ str r5, [r9, #0x510] /* DRAM_DQM5 */
+ str r6, [r9, #0x5bc] /* DRAM_DQM6 */
+ str r7, [r9, #0x5c4] /* DRAM_DQM7 */
+
+ ldmfd sp!, {r4-r7}
+ str r4, [r9, #0x5ac] /* DRAM_DQM0 */
+ str r5, [r9, #0x5b4] /* DRAM_DQM1 */
+ str r6, [r9, #0x528] /* DRAM_DQM2 */
+ str r7, [r9, #0x520] /* DRAM_DQM3 */
+.endm
+
+.macro ddr_io_set_lpm
+ mov r4, #0
+ str r4, [r9, #0x5ac] /* DRAM_DQM0 */
+ str r4, [r9, #0x5b4] /* DRAM_DQM1 */
+ str r4, [r9, #0x528] /* DRAM_DQM2 */
+ str r4, [r9, #0x520] /* DRAM_DQM3 */
+
+ str r4, [r9, #0x514] /* DRAM_DQM4 */
+ str r4, [r9, #0x510] /* DRAM_DQM5 */
+ str r4, [r9, #0x5bc] /* DRAM_DQM6 */
+ str r4, [r9, #0x5c4] /* DRAM_DQM7 */
+
+ str r4, [r9, #0x56c] /* DRAM_CAS */
+ str r4, [r9, #0x578] /* DRAM_RAS */
+ str r4, [r9, #0x588] /* DRAM_SDCLK_0 */
+ str r4, [r9, #0x594] /* DRAM_SDCLK_1 */
+
+ str r4, [r9, #0x750] /* DDRMODE_CTL */
+ str r4, [r9, #0x774] /* DDRMODE */
+
+ str r4, [r9, #0x5a8] /* DRAM_SDQS0 */
+ str r4, [r9, #0x5b0] /* DRAM_SDQS1 */
+ str r4, [r9, #0x524] /* DRAM_SDQS2 */
+ str r4, [r9, #0x51c] /* DRAM_SDQS3 */
+
+ str r4, [r9, #0x518] /* DRAM_SDQS4 */
+ str r4, [r9, #0x50c] /* DRAM_SDQS5 */
+ str r4, [r9, #0x5b8] /* DRAM_SDQS6 */
+ str r4, [r9, #0x5c0] /* DRAM_SDQS7 */
+
+ str r4, [r9, #0x784] /* GPR_B0DS */
+ str r4, [r9, #0x788] /* GPR_B1DS */
+ str r4, [r9, #0x794] /* GPR_B2DS */
+ str r4, [r9, #0x79c] /* GPR_B3DS */
+
+ str r4, [r9, #0x7a0] /* GPR_B4DS */
+ str r4, [r9, #0x7a4] /* GPR_B5DS */
+ str r4, [r9, #0x7a8] /* GPR_B6DS */
+ str r4, [r9, #0x748] /* GPR_B7DS */
+
+ str r4, [r9, #0x74c] /* GPR_ADDS*/
+ str r4, [r9, #0x59c] /* DRAM_SODT0*/
+ str r4, [r9, #0x5a0] /* DRAM_SODT1*/
+.endm
+
+/*
+ * imx6q_suspend:
+ *
+ * Suspend the processor (eg, wait for interrupt).
+ * Set the DDR into Self Refresh
+ * IRQs are already disabled.
+ *
+ * Registers usage in the imx6q_suspend:
+ *
+ * r0: suspend_iram_paddr
+ * r1: suspend_iram_vaddr
+ * r2: suspend_iram_size
+ *
+ * r8: src_base pointer
+ * r9: iomux_base pointer
+ * r10: mmdc_base pointer
+ * r11: anatop_base pointer
+ * sp: iram stack
+ *
+ * Corrupted registers: r0-r3
+ */
+
+ENTRY(imx6q_suspend)
+ mov r3, sp @ save sp
+ add sp, r1, r2 @ set sp to top iram stack
+ sub sp, sp, #16 @ 4 regs ptr
+ stmfd sp!, {r4 - r12, lr} @ save registers
+
+ add r4, r1, r2
+ ldr r8, [r4, #-16] @ r8 = src_base pointer
+ ldr r9, [r4, #-12] @ r9 = iomux_base pointer
+ ldr r10, [r4, #-8] @ r10 = mmdc_base pointer
+ ldr r11, [r4, #-4] @ r11 = anatop_base pointer
+
+ /* should not access sp in ddr until resume with cache MMU on */
+ stmfd sp!, {r3} @ save old sp
+
+ ldr r4, [r8, #SRC_GPR1_OFFSET] @ r8 = src_base pointer
+ stmfd sp!, {r4} @ save old resume func
+
+ /* Enable weak 2P5 linear regulator */
+ ldr r4, [r11, #ANATOP_REG_2P5] @ r11 = anatop_base pointer
+ orr r4, r4, #0x40000
+ str r4, [r11, #ANATOP_REG_2P5]
+ mov r6, #1
+wait: ldr r4, [r11, #ANATOP_REG_2P5]
+ and r4, r4, r6, lsl #17 @ output ok?
+ cmp r4, #0
+ beq wait
+
+ /* save ddr iomux regs */
+ ddr_io_save
+
+ /* set ddr to low power mode */
+ ldr r4, [r10, #MMDC_MAPSR_OFFSET] @ r10 = mmdc_base pointer
+ bic r4, #MMDC_MAPSR_PSD
+ str r4, [r10, #MMDC_MAPSR_OFFSET]
+refresh:
+ ldr r4, [r10, #MMDC_MAPSR_OFFSET]
+ and r4, r4, #MMDC_MAPSR_PSS
+ cmp r4, #0
+ beq refresh
+
+ ddr_io_set_lpm
+
+ /* save resume pointer into SRC_GPR1, sp pointer into SRC_GPR2 */
+ ldr r4, =imx6q_suspend
+ ldr r5, =imx6q_resume
+ sub r5, r5, r4 @ r5 = resmue offset
+ add r5, r0, r5 @ r0 = suspend_iram_paddr, r5 = resmue phy addr
+ str r5, [r8, #SRC_GPR1_OFFSET] @ r8 = src_base pointer
+ sub r5, sp, r1 @ r1 = suspend_iram_vaddr, r5 = sp offset
+ add r5, r0, r5 @ r0 = suspend_iram_paddr, r5 = sp phy addr
+ str r5, [r8, #SRC_GPR2_OFFSET] @ r8 = src_base pointer
+
+ /* execute a wfi instruction to let SOC go into stop mode */
+ dsb
+ wfi
+
+ nop
+ nop
+ nop
+ nop
+
+ /*
+ * if go here, means there is a wakeup irq pending, we should resume
+ * system immediately.
+ */
+ ddr_io_restore
+
+ /* Disable weak 2P5 linear regulator */
+ ldr r4, [r11, #ANATOP_REG_2P5] @ r11 = anatop_base pointer
+ bic r4, #0x40000
+ str r4, [r11, #ANATOP_REG_2P5]
+
+ ldmfd sp!, {r4} @ drop old resmue func ptr
+ ldmfd sp!, {r3}
+ ldmfd sp!, {r4 - r12, lr}
+ mov sp, r3
+ mov pc, lr
+
+/*
+ * when SOC exit stop mode, arm core restart from here, currently
+ * are running with MMU off.
+ */
+imx6q_resume:
+ ldr r0, =MX6Q_SRC_BASE_ADDR
+ mov r1, #0x0
+ str r1, [r0, #SRC_GPR1_OFFSET] @ clear SRC_GPR1
+ ldr sp, [r0, #SRC_GPR2_OFFSET]
+ str r1, [r0, #SRC_GPR2_OFFSET] @ clear SRC_GPR2
+
+ ldr r9, =MX6Q_IOMUXC_BASE_ADDR
+ ddr_io_restore
+
+ ldr r0, =MX6Q_MMDC0_BASE_ADDR
+ ldr r1, [r0, #MMDC_MAPSR_OFFSET]
+ orr r1, #MMDC_MAPSR_PSD
+ str r1, [r0, #MMDC_MAPSR_OFFSET]
+
+ /* Disable weak 2P5 linear regulator */
+ ldr r0, =MX6Q_ANATOP_BASE_ADDR
+ ldr r1, [r0, #ANATOP_REG_2P5]
+ bic r1, #0x40000
+ str r1, [r0, #ANATOP_REG_2P5]
+
+ ldmfd sp!, {r2} @ resmue func ptr
+ ldmfd sp!, {r3}
+ ldmfd sp!, {r4 - r12, lr}
+ mov sp, r3
+
+ /* return back */
+ mov pc, r2
+ENDPROC(imx6q_suspend)
diff --git a/arch/arm/mach-iop32x/include/mach/system.h b/arch/arm/mach-iop32x/include/mach/system.h
index a4b808fe0d8..4865a9bff85 100644
--- a/arch/arm/mach-iop32x/include/mach/system.h
+++ b/arch/arm/mach-iop32x/include/mach/system.h
@@ -30,5 +30,5 @@ static inline void arch_reset(char mode, const char *cmd)
*IOP3XX_PCSR = 0x30;
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
}
diff --git a/arch/arm/mach-iop33x/include/mach/system.h b/arch/arm/mach-iop33x/include/mach/system.h
index f192a34be07..86d1b20dd69 100644
--- a/arch/arm/mach-iop33x/include/mach/system.h
+++ b/arch/arm/mach-iop33x/include/mach/system.h
@@ -19,5 +19,5 @@ static inline void arch_reset(char mode, const char *cmd)
*IOP3XX_PCSR = 0x30;
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
}
diff --git a/arch/arm/mach-ixp4xx/include/mach/system.h b/arch/arm/mach-ixp4xx/include/mach/system.h
index 54c0af7fa2d..24337d9d275 100644
--- a/arch/arm/mach-ixp4xx/include/mach/system.h
+++ b/arch/arm/mach-ixp4xx/include/mach/system.h
@@ -26,7 +26,7 @@ static inline void arch_reset(char mode, const char *cmd)
{
if ( 1 && mode == 's') {
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
} else {
/* Use on-chip reset capability */
diff --git a/arch/arm/mach-ks8695/include/mach/system.h b/arch/arm/mach-ks8695/include/mach/system.h
index fb1dda9be2d..ceb19c90aa5 100644
--- a/arch/arm/mach-ks8695/include/mach/system.h
+++ b/arch/arm/mach-ks8695/include/mach/system.h
@@ -32,7 +32,7 @@ static void arch_reset(char mode, const char *cmd)
unsigned int reg;
if (mode == 's')
- cpu_reset(0);
+ soft_restart(0);
/* disable timer0 */
reg = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h
index 1a8a25edb1b..cb0637933a8 100644
--- a/arch/arm/mach-mmp/include/mach/system.h
+++ b/arch/arm/mach-mmp/include/mach/system.h
@@ -19,8 +19,8 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
if (cpu_is_pxa168())
- cpu_reset(0xffff0000);
+ soft_restart(0xffff0000);
else
- cpu_reset(0);
+ soft_restart(0);
}
#endif /* __ASM_MACH_SYSTEM_H */
diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c
index 20ec3bddf7c..cab88364e7c 100644
--- a/arch/arm/mach-mxs/system.c
+++ b/arch/arm/mach-mxs/system.c
@@ -53,7 +53,7 @@ void arch_reset(char mode, const char *cmd)
mdelay(50);
/* We'll take a jump through zero as a poor second */
- cpu_reset(0);
+ soft_restart(0);
}
static int __init mxs_arch_reset_init(void)
diff --git a/arch/arm/mach-pnx4008/include/mach/system.h b/arch/arm/mach-pnx4008/include/mach/system.h
index 5dda2bb55f8..5d6384a6128 100644
--- a/arch/arm/mach-pnx4008/include/mach/system.h
+++ b/arch/arm/mach-pnx4008/include/mach/system.h
@@ -32,7 +32,7 @@ static void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
- cpu_reset(0);
+ soft_restart(0);
}
#endif
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
index 01e9d643394..b8bcda15da8 100644
--- a/arch/arm/mach-pxa/reset.c
+++ b/arch/arm/mach-pxa/reset.c
@@ -88,7 +88,7 @@ void arch_reset(char mode, const char *cmd)
switch (mode) {
case 's':
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
break;
case 'g':
do_gpio_reset();
diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h
index 45c7b935dc4..a354f4d092c 100644
--- a/arch/arm/mach-rpc/include/mach/system.h
+++ b/arch/arm/mach-rpc/include/mach/system.h
@@ -23,5 +23,5 @@ static inline void arch_reset(char mode, const char *cmd)
/*
* Jump into the ROM
*/
- cpu_reset(0);
+ soft_restart(0);
}
diff --git a/arch/arm/mach-s3c2410/include/mach/system-reset.h b/arch/arm/mach-s3c2410/include/mach/system-reset.h
index 6faadcee772..913893d4465 100644
--- a/arch/arm/mach-s3c2410/include/mach/system-reset.h
+++ b/arch/arm/mach-s3c2410/include/mach/system-reset.h
@@ -19,7 +19,7 @@ static void
arch_reset(char mode, const char *cmd)
{
if (mode == 's') {
- cpu_reset(0);
+ soft_restart(0);
}
if (s3c24xx_reset_hook)
@@ -28,5 +28,5 @@ arch_reset(char mode, const char *cmd)
arch_wdt_reset();
/* we'll take a jump through zero as a poor second */
- cpu_reset(0);
+ soft_restart(0);
}
diff --git a/arch/arm/mach-s3c64xx/include/mach/system.h b/arch/arm/mach-s3c64xx/include/mach/system.h
index 2e58cb7a714..d8ca5786ba2 100644
--- a/arch/arm/mach-s3c64xx/include/mach/system.h
+++ b/arch/arm/mach-s3c64xx/include/mach/system.h
@@ -24,7 +24,7 @@ static void arch_reset(char mode, const char *cmd)
arch_wdt_reset();
/* if all else fails, or mode was for soft, jump to 0 */
- cpu_reset(0);
+ soft_restart(0);
}
#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-sa1100/include/mach/system.h b/arch/arm/mach-sa1100/include/mach/system.h
index ba9da9f7f18..345d35b7450 100644
--- a/arch/arm/mach-sa1100/include/mach/system.h
+++ b/arch/arm/mach-sa1100/include/mach/system.h
@@ -14,7 +14,7 @@ static inline void arch_reset(char mode, const char *cmd)
{
if (mode == 's') {
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
} else {
/* Use on-chip reset capability */
RSRR = RSRR_SWR;
diff --git a/arch/arm/mach-shmobile/include/mach/system.h b/arch/arm/mach-shmobile/include/mach/system.h
index 76a687eeaa2..956ac18ddbf 100644
--- a/arch/arm/mach-shmobile/include/mach/system.h
+++ b/arch/arm/mach-shmobile/include/mach/system.h
@@ -8,7 +8,7 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
- cpu_reset(0);
+ soft_restart(0);
}
#endif
diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h
index ce228bdc66d..68875a1c16b 100644
--- a/arch/arm/mach-w90x900/include/mach/system.h
+++ b/arch/arm/mach-w90x900/include/mach/system.h
@@ -33,7 +33,7 @@ static void arch_reset(char mode, const char *cmd)
{
if (mode == 's') {
/* Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
} else {
__raw_writel(WTE | WTRE | WTCLK, WTCR);
}
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 2be9139a4ef..296ad2eaddb 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -78,7 +78,7 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
* the user-mode pages. This will then ensure that we have predictable
* results when turning the mmu off
*/
-void setup_mm_for_reboot(char mode)
+void setup_mm_for_reboot(void)
{
/*
* We need to access to user-mode page tables here. For kernel threads
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 941a98c9e8a..88417514b2c 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -43,7 +43,7 @@ void __init paging_init(struct machine_desc *mdesc)
/*
* We don't need to do anything here for nommu machines.
*/
-void setup_mm_for_reboot(char mode)
+void setup_mm_for_reboot(void)
{
}
diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c
index 8cced35009b..73eb555ecb8 100644
--- a/arch/arm/plat-mxc/audmux-v2.c
+++ b/arch/arm/plat-mxc/audmux-v2.c
@@ -20,7 +20,9 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <mach/audmux.h>
#include <mach/hardware.h>
@@ -184,9 +186,66 @@ int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
}
EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port);
+#ifdef CONFIG_OF
+
+static int audmux_v2_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ if (!request_mem_region(res->start, resource_size(res), "audmux_v2")) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ return -EBUSY;
+ }
+
+ audmux_base = ioremap(res->start, resource_size(res));
+ if (!audmux_base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENODEV;
+ goto failed_ioremap;
+ }
+
+ audmux_clk = clk_get(NULL, "audmux");
+ if (IS_ERR(audmux_clk)) {
+ dev_warn(&pdev->dev, "%s: cannot get clock: %d\n",
+ __func__, ret);
+ audmux_clk = NULL;
+ }
+
+ audmux_debugfs_init();
+ return 0;
+
+failed_ioremap:
+ release_mem_region(res->start, resource_size(res));
+
+ return ret;
+}
+
+static const struct of_device_id audmux_v2_dt_ids[] = {
+ { .compatible = "fsl,audmux-v2", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver audmux_v2_driver = {
+ .probe = audmux_v2_probe,
+ .driver = {
+ .name = "audmux_v2",
+ .of_match_table = audmux_v2_dt_ids,
+ },
+};
+
+#endif
+
static int mxc_audmux_v2_init(void)
{
+#ifdef CONFIG_OF
+ return platform_driver_register(&audmux_v2_driver);
+#else
int ret;
+
if (cpu_is_mx51()) {
audmux_base = MX51_IO_ADDRESS(MX51_AUDMUX_BASE_ADDR);
} else if (cpu_is_mx31()) {
@@ -194,10 +253,9 @@ static int mxc_audmux_v2_init(void)
} else if (cpu_is_mx35()) {
audmux_clk = clk_get(NULL, "audmux");
if (IS_ERR(audmux_clk)) {
- ret = PTR_ERR(audmux_clk);
printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
ret);
- return ret;
+ audmux_clk = NULL;
}
audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR);
} else if (cpu_is_mx25()) {
@@ -212,6 +270,7 @@ static int mxc_audmux_v2_init(void)
}
audmux_debugfs_init();
+#endif
return 0;
}
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 7e8bc5cdfe8..6b4cc711824 100644
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <asm/cpu.h>
#include <mach/hardware.h>
#include <mach/clock.h>
@@ -34,6 +35,7 @@ static int cpu_freq_khz_min;
static int cpu_freq_khz_max;
static struct clk *cpu_clk;
+static DEFINE_MUTEX(cpu_lock);
static struct cpufreq_frequency_table *imx_freq_table;
static int cpu_op_nr;
@@ -59,17 +61,11 @@ int set_cpu_freq(int freq)
static int mxc_verify_speed(struct cpufreq_policy *policy)
{
- if (policy->cpu != 0)
- return -EINVAL;
-
return cpufreq_frequency_table_verify(policy, imx_freq_table);
}
static unsigned int mxc_get_speed(unsigned int cpu)
{
- if (cpu)
- return 0;
-
return clk_get_rate(cpu_clk) / 1000;
}
@@ -77,23 +73,39 @@ static int mxc_set_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
struct cpufreq_freqs freqs;
- int freq_Hz;
+ int freq_Hz, cpu;
int ret = 0;
unsigned int index;
+ mutex_lock(&cpu_lock);
+
cpufreq_frequency_table_target(policy, imx_freq_table,
target_freq, relation, &index);
freq_Hz = imx_freq_table[index].frequency * 1000;
freqs.old = clk_get_rate(cpu_clk) / 1000;
- freqs.new = freq_Hz / 1000;
- freqs.cpu = 0;
+ freqs.new = clk_round_rate(cpu_clk, freq_Hz);
+ freqs.new = (freqs.new ? freqs.new : freq_Hz) / 1000;
freqs.flags = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (freqs.old == freqs.new) {
+ mutex_unlock(&cpu_lock);
+ return 0;
+ }
+
+ for_each_possible_cpu(cpu) {
+ freqs.cpu = cpu;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
ret = set_cpu_freq(freq_Hz);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ for_each_possible_cpu(cpu) {
+ freqs.cpu = cpu;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+
+ mutex_unlock(&cpu_lock);
return ret;
}
@@ -105,7 +117,7 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy)
printk(KERN_INFO "i.MXC CPU frequency driver\n");
- if (policy->cpu != 0)
+ if (policy->cpu >= num_possible_cpus())
return -EINVAL;
if (!get_cpu_op)
@@ -117,37 +129,45 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy)
return PTR_ERR(cpu_clk);
}
- cpu_op_tbl = get_cpu_op(&cpu_op_nr);
+ mutex_lock(&cpu_lock);
+ if (!imx_freq_table) {
+ cpu_op_tbl = get_cpu_op(&cpu_op_nr);
- cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000;
- cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000;
+ cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000;
+ cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000;
- imx_freq_table = kmalloc(
- sizeof(struct cpufreq_frequency_table) * (cpu_op_nr + 1),
- GFP_KERNEL);
- if (!imx_freq_table) {
- ret = -ENOMEM;
- goto err1;
- }
+ imx_freq_table = kmalloc(sizeof(struct cpufreq_frequency_table)
+ * (cpu_op_nr + 1), GFP_KERNEL);
+ if (!imx_freq_table) {
+ ret = -ENOMEM;
+ mutex_unlock(&cpu_lock);
+ goto err1;
+ }
- for (i = 0; i < cpu_op_nr; i++) {
- imx_freq_table[i].index = i;
- imx_freq_table[i].frequency = cpu_op_tbl[i].cpu_rate / 1000;
+ for (i = 0; i < cpu_op_nr; i++) {
+ imx_freq_table[i].index = i;
+ imx_freq_table[i].frequency =
+ cpu_op_tbl[i].cpu_rate / 1000;
- if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min)
- cpu_freq_khz_min = cpu_op_tbl[i].cpu_rate / 1000;
+ if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min)
+ cpu_freq_khz_min =
+ cpu_op_tbl[i].cpu_rate / 1000;
- if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max)
- cpu_freq_khz_max = cpu_op_tbl[i].cpu_rate / 1000;
- }
+ if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max)
+ cpu_freq_khz_max =
+ cpu_op_tbl[i].cpu_rate / 1000;
+ }
- imx_freq_table[i].index = i;
- imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
+ imx_freq_table[i].index = i;
+ imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
+ }
+ mutex_unlock(&cpu_lock);
policy->cur = clk_get_rate(cpu_clk) / 1000;
policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
-
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ cpumask_setall(policy->cpus);
/* Manual states, that PLL stabilizes in two CLK32 periods */
policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
@@ -174,7 +194,10 @@ static int mxc_cpufreq_exit(struct cpufreq_policy *policy)
set_cpu_freq(cpu_freq_khz_max * 1000);
clk_put(cpu_clk);
+ mutex_lock(&cpu_lock);
kfree(imx_freq_table);
+ imx_freq_table = NULL;
+ mutex_unlock(&cpu_lock);
return 0;
}
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index d6a191de71f..e7575929a1c 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -82,6 +82,7 @@ enum mxc_cpu_pwr_mode {
WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */
STOP_POWER_ON, /* just STOP */
STOP_POWER_OFF, /* STOP + SRPG */
+ ARM_POWER_OFF, /* STOP + SRPG + ARM power off */
};
extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
@@ -126,7 +127,9 @@ extern void imx_reset_vpu(void);
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
extern void imx_src_init(void);
+extern void imx_src_prepare_restart(void);
extern void imx_gpc_init(void);
+extern bool imx_gpc_wake_irq_pending(void);
extern void imx_gpc_pre_suspend(void);
extern void imx_gpc_post_resume(void);
extern void imx51_babbage_common_init(void);
diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h
index dd41a6475be..2003f44fca5 100644
--- a/arch/arm/plat-mxc/include/mach/dma.h
+++ b/arch/arm/plat-mxc/include/mach/dma.h
@@ -67,8 +67,7 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan)
static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
{
- return !strcmp(dev_name(chan->device->dev), "imx31-sdma") ||
- !strcmp(dev_name(chan->device->dev), "imx35-sdma") ||
+ return strstr(dev_name(chan->device->dev), "sdma") ||
!strcmp(dev_name(chan->device->dev), "imx-dma");
}
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
index aaf97481f41..4ab603e25b8 100644
--- a/arch/arm/plat-mxc/include/mach/esdhc.h
+++ b/arch/arm/plat-mxc/include/mach/esdhc.h
@@ -32,6 +32,7 @@ enum cd_types {
* @cd_gpio: gpio for card_detect interrupt
* @wp_type: type of write_protect method (see wp_types enum above)
* @cd_type: type of card_detect method (see cd_types enum above)
+ * @vdd_180: 1.8V VDD supported
*/
struct esdhc_platform_data {
@@ -39,5 +40,6 @@ struct esdhc_platform_data {
unsigned int cd_gpio;
enum wp_types wp_type;
enum cd_types cd_type;
+ int vdd_180;
};
#endif /* __ASM_ARCH_IMX_ESDHC_H */
diff --git a/arch/arm/plat-mxc/include/mach/mx6q.h b/arch/arm/plat-mxc/include/mach/mx6q.h
index 67e3abd8930..a289ffe2ddd 100644
--- a/arch/arm/plat-mxc/include/mach/mx6q.h
+++ b/arch/arm/plat-mxc/include/mach/mx6q.h
@@ -29,6 +29,12 @@
#define MX6Q_CCM_SIZE 0x4000
#define MX6Q_ANATOP_BASE_ADDR 0x020c8000
#define MX6Q_ANATOP_SIZE 0x1000
+#define MX6Q_SRC_BASE_ADDR 0x020d8000
+#define MX6Q_SRC_SIZE 0x4000
+#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000
+#define MX6Q_IOMUXC_SIZE 0x4000
+#define MX6Q_MMDC0_BASE_ADDR 0x021b0000
+#define MX6Q_MMDC0_SIZE 0x4000
#define MX6Q_UART2_BASE_ADDR 0x021e8000
#define MX6Q_UART4_BASE_ADDR 0x021f0000
#define MX6Q_UART_SIZE 0x4000
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index a74b87db893..5a4aa1a1b8c 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -203,6 +203,7 @@ struct cpu_op {
u32 pll_reg;
u32 pll_rate;
u32 cpu_rate;
+ int cpu_voltage;
u32 pdr0_reg;
u32 pdf;
u32 mfi;
diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c
index d65fb31a55c..7e5c76ea446 100644
--- a/arch/arm/plat-mxc/system.c
+++ b/arch/arm/plat-mxc/system.c
@@ -71,7 +71,7 @@ void arch_reset(char mode, const char *cmd)
mdelay(50);
/* we'll take a jump through zero as a poor second */
- cpu_reset(0);
+ soft_restart(0);
}
void mxc_arch_reset_init(void __iomem *base)
diff --git a/arch/arm/plat-spear/include/plat/system.h b/arch/arm/plat-spear/include/plat/system.h
index a235fa0ca77..1171f228d71 100644
--- a/arch/arm/plat-spear/include/plat/system.h
+++ b/arch/arm/plat-spear/include/plat/system.h
@@ -31,7 +31,7 @@ static inline void arch_reset(char mode, const char *cmd)
{
if (mode == 's') {
/* software reset, Jump into ROM at address 0 */
- cpu_reset(0);
+ soft_restart(0);
} else {
/* hardware reset, Use on-chip reset capability */
sysctl_soft_reset((void __iomem *)VA_SPEAR_SYS_CTRL_BASE);