aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaesar Wang <wxt@rock-chips.com>2015-06-09 05:49:57 -0400
committerHeiko Stuebner <heiko@sntech.de>2015-07-05 18:46:59 -0400
commitfe4407c0dc58215a7abfb7532740d79ddabe7a7a (patch)
treeca61939e0381b774e33b80b1a92c262c9033c415
parent33939403112791866da6b64875385fa1b7d9865a (diff)
ARM: rockchip: fix the CPU soft reset
We need different orderings when turning a core on and turning a core off. In one case we need to assert reset before turning power off. In ther other case we need to turn power on and the deassert reset. In general, the correct flow is: CPU off: reset_control_assert regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), BIT(pd)) wait_for_power_domain_to_turn_off CPU on: regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), 0) wait_for_power_domain_to_turn_on reset_control_deassert This is needed for stressing CPU up/down, as per: cd /sys/devices/system/cpu/ for i in $(seq 10000); do echo "================= $i ============" for j in $(seq 100); do while [[ "$(cat cpu1/online)$(cat cpu2/online)$(cat cpu3/online)" != "000"" ]] echo 0 > cpu1/online echo 0 > cpu2/online echo 0 > cpu3/online done while [[ "$(cat cpu1/online)$(cat cpu2/online)$(cat cpu3/online)" != "111" ]]; do echo 1 > cpu1/online echo 1 > cpu2/online echo 1 > cpu3/online done done done The following is reproducable log: [34466.186812] PM: noirq suspend of devices complete after 0.669 msecs [34466.186824] Disabling non-boot CPUs ... [34466.187509] CPU1: shutdown [34466.188672] CPU2: shutdown [34473.736627] Kernel panic - not syncing:Watchdog detected hard LOCKUP on cpu 0 ....... or others similar log: ....... [ 4072.454453] CPU1: shutdown [ 4072.504436] CPU2: shutdown [ 4072.554426] CPU3: shutdown [ 4072.577827] CPU1: Booted secondary processor [ 4072.582611] CPU2: Booted secondary processor <hang> Tested by cpu up/down scripts, the results told us need delay more time before write the sram. The wait time is affected by many aspects (e.g: cpu frequency, bootrom frequency, sram frequency, bus speed, ...). Although the cpus other than cpu0 will write the sram, the speedy is no the same as cpu0, if the cpu0 early wake up, perhaps the other cpus can't startup. As we know, the cpu0 can wake up when the cpu1/2/3 write the 'sram+4/8' and send the sev. Anyway..... At the moment, 1ms delay will be happy work for cpu up/down scripts test. Signed-off-by: Caesar Wang <wxt@rock-chips.com> Reviewed-by: Doug Anderson <dianders@chromium.org> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Fixes: 3ee851e212d0 ("ARM: rockchip: add basic smp support for rk3288") Cc: stable@vger.kernel.org Signed-off-by: Heiko Stuebner <heiko@sntech.de>
-rw-r--r--arch/arm/mach-rockchip/platsmp.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
index 8fcec1cc101e..d1a5fec68887 100644
--- a/arch/arm/mach-rockchip/platsmp.c
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -72,29 +72,22 @@ static struct reset_control *rockchip_get_core_reset(int cpu)
72static int pmu_set_power_domain(int pd, bool on) 72static int pmu_set_power_domain(int pd, bool on)
73{ 73{
74 u32 val = (on) ? 0 : BIT(pd); 74 u32 val = (on) ? 0 : BIT(pd);
75 struct reset_control *rstc = rockchip_get_core_reset(pd);
75 int ret; 76 int ret;
76 77
78 if (IS_ERR(rstc) && read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
79 pr_err("%s: could not get reset control for core %d\n",
80 __func__, pd);
81 return PTR_ERR(rstc);
82 }
83
77 /* 84 /*
78 * We need to soft reset the cpu when we turn off the cpu power domain, 85 * We need to soft reset the cpu when we turn off the cpu power domain,
79 * or else the active processors might be stalled when the individual 86 * or else the active processors might be stalled when the individual
80 * processor is powered down. 87 * processor is powered down.
81 */ 88 */
82 if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { 89 if (!IS_ERR(rstc) && !on)
83 struct reset_control *rstc = rockchip_get_core_reset(pd); 90 reset_control_assert(rstc);
84
85 if (IS_ERR(rstc)) {
86 pr_err("%s: could not get reset control for core %d\n",
87 __func__, pd);
88 return PTR_ERR(rstc);
89 }
90
91 if (on)
92 reset_control_deassert(rstc);
93 else
94 reset_control_assert(rstc);
95
96 reset_control_put(rstc);
97 }
98 91
99 ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); 92 ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
100 if (ret < 0) { 93 if (ret < 0) {
@@ -112,6 +105,12 @@ static int pmu_set_power_domain(int pd, bool on)
112 } 105 }
113 } 106 }
114 107
108 if (!IS_ERR(rstc)) {
109 if (on)
110 reset_control_deassert(rstc);
111 reset_control_put(rstc);
112 }
113
115 return 0; 114 return 0;
116} 115}
117 116
@@ -146,9 +145,14 @@ static int rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle)
146 * the mailbox: 145 * the mailbox:
147 * sram_base_addr + 4: 0xdeadbeaf 146 * sram_base_addr + 4: 0xdeadbeaf
148 * sram_base_addr + 8: start address for pc 147 * sram_base_addr + 8: start address for pc
148 * The cpu0 need to wait the other cpus other than cpu0 entering
149 * the wfe state.The wait time is affected by many aspects.
150 * (e.g: cpu frequency, bootrom frequency, sram frequency, ...)
149 * */ 151 * */
150 udelay(10); 152 mdelay(1); /* ensure the cpus other than cpu0 to startup */
151 writel(virt_to_phys(secondary_startup), sram_base_addr + 8); 153
154 writel(virt_to_phys(rockchip_secondary_startup),
155 sram_base_addr + 8);
152 writel(0xDEADBEAF, sram_base_addr + 4); 156 writel(0xDEADBEAF, sram_base_addr + 4);
153 dsb_sev(); 157 dsb_sev();
154 } 158 }