aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-09-25 11:42:57 -0400
committerArnd Bergmann <arnd@arndb.de>2014-09-25 11:42:57 -0400
commite36087998a3b01f3c6c93fa9465e40103f427315 (patch)
tree029c1db87eb84dc72e796174455f0c453885fa74
parent3b8f5030ddcf51112542e1e6ef27da237642069d (diff)
parent8097171e19bb69f3e2226827440b71ececa5d74f (diff)
Merge tag 'zynq-cleanup-for-3.18' of git://git.xilinx.com/linux-xlnx into next/soc
Pull "arm: Xilinx Zynq cleanup patches for v3.18" from Michal Simek: - PM support - Fix L2 useless setting Signed-off-by: Arnd Bergmann <arnd@arndb.de> * tag 'zynq-cleanup-for-3.18' of git://git.xilinx.com/linux-xlnx: ARM: zynq: Remove useless L2C AUX setting ARM: zynq: Rename 'zynq_platform_cpu_die' ARM: zynq: Remove hotplug.c ARM: zynq: Synchronise zynq_cpu_die/kill ARM: zynq: cpuidle: Remove pointless code ARM: zynq: Remove invalidate cache for cpu die ARM: zynq: PM: Enable DDR clock stop ARM: zynq: DT: Add DDRC node Documentation: devicetree: Add binding for Synopsys DDR controller ARM: zynq: PM: Enable A9 internal clock gating feature
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/synopsys.txt11
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi5
-rw-r--r--arch/arm/mach-zynq/Makefile3
-rw-r--r--arch/arm/mach-zynq/common.c11
-rw-r--r--arch/arm/mach-zynq/common.h16
-rw-r--r--arch/arm/mach-zynq/hotplug.c47
-rw-r--r--arch/arm/mach-zynq/platsmp.c41
-rw-r--r--arch/arm/mach-zynq/pm.c83
-rw-r--r--arch/arm/mach-zynq/slcr.c43
-rw-r--r--drivers/cpuidle/cpuidle-zynq.c10
10 files changed, 207 insertions, 63 deletions
diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
new file mode 100644
index 000000000000..f9c6454146b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
@@ -0,0 +1,11 @@
1Binding for Synopsys IntelliDDR Multi Protocol Memory Controller
2
3Required properties:
4 - compatible: Should be 'xlnx,zynq-ddrc-a05'
5 - reg: Base address and size of the controllers memory area
6
7Example:
8 memory-controller@f8006000 {
9 compatible = "xlnx,zynq-ddrc-a05";
10 reg = <0xf8006000 0x1000>;
11 };
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 6cc83d4c6c76..587cadcf7001 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -146,6 +146,11 @@
146 cache-level = <2>; 146 cache-level = <2>;
147 }; 147 };
148 148
149 memory-controller@f8006000 {
150 compatible = "xlnx,zynq-ddrc-a05";
151 reg = <0xf8006000 0x1000>;
152 } ;
153
149 uart0: serial@e0000000 { 154 uart0: serial@e0000000 {
150 compatible = "xlnx,xuartps", "cdns,uart-r1p8"; 155 compatible = "xlnx,xuartps", "cdns,uart-r1p8";
151 status = "disabled"; 156 status = "disabled";
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 1b25d92ebf22..c85fb3f7d5cd 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -3,8 +3,7 @@
3# 3#
4 4
5# Common support 5# Common support
6obj-y := common.o slcr.o 6obj-y := common.o slcr.o pm.o
7CFLAGS_REMOVE_hotplug.o =-march=armv6k 7CFLAGS_REMOVE_hotplug.o =-march=armv6k
8CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9 8CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9
9obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
10obj-$(CONFIG_SMP) += headsmp.o platsmp.o 9obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 31a6fa40ba37..613c476872eb 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -98,6 +98,12 @@ static int __init zynq_get_revision(void)
98 return revision; 98 return revision;
99} 99}
100 100
101static void __init zynq_init_late(void)
102{
103 zynq_core_pm_init();
104 zynq_pm_late_init();
105}
106
101/** 107/**
102 * zynq_init_machine - System specific initialization, intended to be 108 * zynq_init_machine - System specific initialization, intended to be
103 * called from board specific initialization. 109 * called from board specific initialization.
@@ -198,12 +204,13 @@ static const char * const zynq_dt_match[] = {
198 204
199DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") 205DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
200 /* 64KB way size, 8-way associativity, parity disabled */ 206 /* 64KB way size, 8-way associativity, parity disabled */
201 .l2c_aux_val = 0x02000000, 207 .l2c_aux_val = 0x00000000,
202 .l2c_aux_mask = 0xf0ffffff, 208 .l2c_aux_mask = 0xffffffff,
203 .smp = smp_ops(zynq_smp_ops), 209 .smp = smp_ops(zynq_smp_ops),
204 .map_io = zynq_map_io, 210 .map_io = zynq_map_io,
205 .init_irq = zynq_irq_init, 211 .init_irq = zynq_irq_init,
206 .init_machine = zynq_init_machine, 212 .init_machine = zynq_init_machine,
213 .init_late = zynq_init_late,
207 .init_time = zynq_timer_init, 214 .init_time = zynq_timer_init,
208 .dt_compat = zynq_dt_match, 215 .dt_compat = zynq_dt_match,
209 .reserve = zynq_memory_init, 216 .reserve = zynq_memory_init,
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index f652f0a884a6..2bc71273c73c 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void);
24extern void zynq_slcr_system_reset(void); 24extern void zynq_slcr_system_reset(void);
25extern void zynq_slcr_cpu_stop(int cpu); 25extern void zynq_slcr_cpu_stop(int cpu);
26extern void zynq_slcr_cpu_start(int cpu); 26extern void zynq_slcr_cpu_start(int cpu);
27extern bool zynq_slcr_cpu_state_read(int cpu);
28extern void zynq_slcr_cpu_state_write(int cpu, bool die);
27extern u32 zynq_slcr_get_device_id(void); 29extern u32 zynq_slcr_get_device_id(void);
28 30
29#ifdef CONFIG_SMP 31#ifdef CONFIG_SMP
@@ -37,7 +39,17 @@ extern struct smp_operations zynq_smp_ops __initdata;
37 39
38extern void __iomem *zynq_scu_base; 40extern void __iomem *zynq_scu_base;
39 41
40/* Hotplug */ 42void zynq_pm_late_init(void);
41extern void zynq_platform_cpu_die(unsigned int cpu); 43
44static inline void zynq_core_pm_init(void)
45{
46 /* A9 clock gating */
47 asm volatile ("mrc p15, 0, r12, c15, c0, 0\n"
48 "orr r12, r12, #1\n"
49 "mcr p15, 0, r12, c15, c0, 0\n"
50 : /* no outputs */
51 : /* no inputs */
52 : "r12");
53}
42 54
43#endif 55#endif
diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c
index 5052c70326e4..b685c89f11e4 100644
--- a/arch/arm/mach-zynq/hotplug.c
+++ b/arch/arm/mach-zynq/hotplug.c
@@ -10,50 +10,5 @@
10 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13#include <linux/kernel.h> 13#include <asm/proc-fns.h>
14#include <linux/errno.h>
15#include <linux/smp.h>
16 14
17#include <asm/cacheflush.h>
18#include <asm/cp15.h>
19#include "common.h"
20
21static inline void zynq_cpu_enter_lowpower(void)
22{
23 unsigned int v;
24
25 flush_cache_all();
26 asm volatile(
27 " mcr p15, 0, %1, c7, c5, 0\n"
28 " dsb\n"
29 /*
30 * Turn off coherency
31 */
32 " mrc p15, 0, %0, c1, c0, 1\n"
33 " bic %0, %0, #0x40\n"
34 " mcr p15, 0, %0, c1, c0, 1\n"
35 " mrc p15, 0, %0, c1, c0, 0\n"
36 " bic %0, %0, %2\n"
37 " mcr p15, 0, %0, c1, c0, 0\n"
38 : "=&r" (v)
39 : "r" (0), "Ir" (CR_C)
40 : "cc");
41}
42
43/*
44 * platform-specific code to shutdown a CPU
45 *
46 * Called with IRQs disabled
47 */
48void zynq_platform_cpu_die(unsigned int cpu)
49{
50 zynq_cpu_enter_lowpower();
51
52 /*
53 * there is no power-control hardware on this platform, so all
54 * we can do is put the core into WFI; this is safe as the calling
55 * code will have already disabled interrupts
56 */
57 for (;;)
58 cpu_do_idle();
59}
diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c
index abc82ef085c1..52d768ff7857 100644
--- a/arch/arm/mach-zynq/platsmp.c
+++ b/arch/arm/mach-zynq/platsmp.c
@@ -112,20 +112,59 @@ static void __init zynq_smp_prepare_cpus(unsigned int max_cpus)
112 scu_enable(zynq_scu_base); 112 scu_enable(zynq_scu_base);
113} 113}
114 114
115/**
116 * zynq_secondary_init - Initialize secondary CPU cores
117 * @cpu: CPU that is initialized
118 *
119 * This function is in the hotplug path. Don't move it into the
120 * init section!!
121 */
122static void zynq_secondary_init(unsigned int cpu)
123{
124 zynq_core_pm_init();
125}
126
115#ifdef CONFIG_HOTPLUG_CPU 127#ifdef CONFIG_HOTPLUG_CPU
116static int zynq_cpu_kill(unsigned cpu) 128static int zynq_cpu_kill(unsigned cpu)
117{ 129{
130 unsigned long timeout = jiffies + msecs_to_jiffies(50);
131
132 while (zynq_slcr_cpu_state_read(cpu))
133 if (time_after(jiffies, timeout))
134 return 0;
135
118 zynq_slcr_cpu_stop(cpu); 136 zynq_slcr_cpu_stop(cpu);
119 return 1; 137 return 1;
120} 138}
139
140/**
141 * zynq_cpu_die - Let a CPU core die
142 * @cpu: Dying CPU
143 *
144 * Platform-specific code to shutdown a CPU.
145 * Called with IRQs disabled on the dying CPU.
146 */
147static void zynq_cpu_die(unsigned int cpu)
148{
149 zynq_slcr_cpu_state_write(cpu, true);
150
151 /*
152 * there is no power-control hardware on this platform, so all
153 * we can do is put the core into WFI; this is safe as the calling
154 * code will have already disabled interrupts
155 */
156 for (;;)
157 cpu_do_idle();
158}
121#endif 159#endif
122 160
123struct smp_operations zynq_smp_ops __initdata = { 161struct smp_operations zynq_smp_ops __initdata = {
124 .smp_init_cpus = zynq_smp_init_cpus, 162 .smp_init_cpus = zynq_smp_init_cpus,
125 .smp_prepare_cpus = zynq_smp_prepare_cpus, 163 .smp_prepare_cpus = zynq_smp_prepare_cpus,
126 .smp_boot_secondary = zynq_boot_secondary, 164 .smp_boot_secondary = zynq_boot_secondary,
165 .smp_secondary_init = zynq_secondary_init,
127#ifdef CONFIG_HOTPLUG_CPU 166#ifdef CONFIG_HOTPLUG_CPU
128 .cpu_die = zynq_platform_cpu_die, 167 .cpu_die = zynq_cpu_die,
129 .cpu_kill = zynq_cpu_kill, 168 .cpu_kill = zynq_cpu_kill,
130#endif 169#endif
131}; 170};
diff --git a/arch/arm/mach-zynq/pm.c b/arch/arm/mach-zynq/pm.c
new file mode 100644
index 000000000000..911fcf865be8
--- /dev/null
+++ b/arch/arm/mach-zynq/pm.c
@@ -0,0 +1,83 @@
1/*
2 * Zynq power management
3 *
4 * Copyright (C) 2012 - 2014 Xilinx
5 *
6 * Sören Brinkmann <soren.brinkmann@xilinx.com>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <linux/io.h>
23#include <linux/of_address.h>
24#include <linux/of_device.h>
25#include "common.h"
26
27/* register offsets */
28#define DDRC_CTRL_REG1_OFFS 0x60
29#define DDRC_DRAM_PARAM_REG3_OFFS 0x20
30
31/* bitfields */
32#define DDRC_CLOCKSTOP_MASK BIT(23)
33#define DDRC_SELFREFRESH_MASK BIT(12)
34
35static void __iomem *ddrc_base;
36
37/**
38 * zynq_pm_ioremap() - Create IO mappings
39 * @comp: DT compatible string
40 * Return: Pointer to the mapped memory or NULL.
41 *
42 * Remap the memory region for a compatible DT node.
43 */
44static void __iomem *zynq_pm_ioremap(const char *comp)
45{
46 struct device_node *np;
47 void __iomem *base = NULL;
48
49 np = of_find_compatible_node(NULL, NULL, comp);
50 if (np) {
51 base = of_iomap(np, 0);
52 of_node_put(np);
53 } else {
54 pr_warn("%s: no compatible node found for '%s'\n", __func__,
55 comp);
56 }
57
58 return base;
59}
60
61/**
62 * zynq_pm_late_init() - Power management init
63 *
64 * Initialization of power management related featurs and infrastructure.
65 */
66void __init zynq_pm_late_init(void)
67{
68 u32 reg;
69
70 ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05");
71 if (!ddrc_base) {
72 pr_warn("%s: Unable to map DDRC IO memory.\n", __func__);
73 } else {
74 /*
75 * Enable DDRC clock stop feature. The HW takes care of
76 * entering/exiting the correct mode depending
77 * on activity state.
78 */
79 reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
80 reg |= DDRC_CLOCKSTOP_MASK;
81 writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
82 }
83}
diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c
index c43a2d16e223..d4cb50cf97c0 100644
--- a/arch/arm/mach-zynq/slcr.c
+++ b/arch/arm/mach-zynq/slcr.c
@@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu)
138 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); 138 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
139 reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); 139 reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
140 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); 140 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
141
142 zynq_slcr_cpu_state_write(cpu, false);
141} 143}
142 144
143/** 145/**
@@ -154,8 +156,47 @@ void zynq_slcr_cpu_stop(int cpu)
154} 156}
155 157
156/** 158/**
157 * zynq_slcr_init - Regular slcr driver init 159 * zynq_slcr_cpu_state - Read/write cpu state
160 * @cpu: cpu number
158 * 161 *
162 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
163 * 0 means cpu is running, 1 cpu is going to die.
164 *
165 * Return: true if cpu is running, false if cpu is going to die
166 */
167bool zynq_slcr_cpu_state_read(int cpu)
168{
169 u32 state;
170
171 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
172 state &= 1 << (31 - cpu);
173
174 return !state;
175}
176
177/**
178 * zynq_slcr_cpu_state - Read/write cpu state
179 * @cpu: cpu number
180 * @die: cpu state - true if cpu is going to die
181 *
182 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
183 * 0 means cpu is running, 1 cpu is going to die.
184 */
185void zynq_slcr_cpu_state_write(int cpu, bool die)
186{
187 u32 state, mask;
188
189 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
190 mask = 1 << (31 - cpu);
191 if (die)
192 state |= mask;
193 else
194 state &= ~mask;
195 writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
196}
197
198/**
199 * zynq_slcr_init - Regular slcr driver init
159 * Return: 0 on success, negative errno otherwise. 200 * Return: 0 on success, negative errno otherwise.
160 * 201 *
161 * Called early during boot from platform code to remap SLCR area. 202 * Called early during boot from platform code to remap SLCR area.
diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c
index aded75928028..c61b8b2a7c77 100644
--- a/drivers/cpuidle/cpuidle-zynq.c
+++ b/drivers/cpuidle/cpuidle-zynq.c
@@ -26,7 +26,6 @@
26 */ 26 */
27 27
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/cpu_pm.h>
30#include <linux/cpuidle.h> 29#include <linux/cpuidle.h>
31#include <linux/platform_device.h> 30#include <linux/platform_device.h>
32#include <asm/proc-fns.h> 31#include <asm/proc-fns.h>
@@ -38,15 +37,9 @@
38static int zynq_enter_idle(struct cpuidle_device *dev, 37static int zynq_enter_idle(struct cpuidle_device *dev,
39 struct cpuidle_driver *drv, int index) 38 struct cpuidle_driver *drv, int index)
40{ 39{
41 /* Devices must be stopped here */
42 cpu_pm_enter();
43
44 /* Add code for DDR self refresh start */ 40 /* Add code for DDR self refresh start */
45 cpu_do_idle(); 41 cpu_do_idle();
46 42
47 /* Add code for DDR self refresh stop */
48 cpu_pm_exit();
49
50 return index; 43 return index;
51} 44}
52 45
@@ -59,8 +52,7 @@ static struct cpuidle_driver zynq_idle_driver = {
59 .enter = zynq_enter_idle, 52 .enter = zynq_enter_idle,
60 .exit_latency = 10, 53 .exit_latency = 10,
61 .target_residency = 10000, 54 .target_residency = 10000,
62 .flags = CPUIDLE_FLAG_TIME_VALID | 55 .flags = CPUIDLE_FLAG_TIME_VALID,
63 CPUIDLE_FLAG_TIMER_STOP,
64 .name = "RAM_SR", 56 .name = "RAM_SR",
65 .desc = "WFI and RAM Self Refresh", 57 .desc = "WFI and RAM Self Refresh",
66 }, 58 },