1/* 2 * Copyright 2014 Linaro Ltd. 3 * Copyright (C) 2014 ZTE Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10#include <linux/delay.h> 11#include <linux/errno.h> 12#include <linux/init.h> 13#include <linux/io.h> 14#include <linux/jiffies.h> 15#include <linux/of.h> 16#include <linux/of_address.h> 17#include <linux/smp.h> 18 19#include <asm/cacheflush.h> 20#include <asm/cp15.h> 21#include <asm/fncpy.h> 22#include <asm/proc-fns.h> 23#include <asm/smp_scu.h> 24#include <asm/smp_plat.h> 25 26#include "core.h" 27 28#define AON_SYS_CTRL_RESERVED1 0xa8 29 30#define BUS_MATRIX_REMAP_CONFIG 0x00 31 32#define PCU_CPU0_CTRL 0x00 33#define PCU_CPU1_CTRL 0x04 34#define PCU_CPU1_ST 0x0c 35#define PCU_GLOBAL_CTRL 0x14 36#define PCU_EXPEND_CONTROL 0x34 37 38#define ZX_IRAM_BASE 0x00200000 39 40static void __iomem *pcu_base; 41static void __iomem *matrix_base; 42static void __iomem *scu_base; 43 44void __init zx_smp_prepare_cpus(unsigned int max_cpus) 45{ 46 struct device_node *np; 47 unsigned long base = 0; 48 void __iomem *aonsysctrl_base; 49 void __iomem *sys_iram; 50 51 base = scu_a9_get_base(); 52 scu_base = ioremap(base, SZ_256); 53 if (!scu_base) { 54 pr_err("%s: failed to map scu\n", __func__); 55 return; 56 } 57 58 scu_enable(scu_base); 59 60 np = of_find_compatible_node(NULL, NULL, "zte,sysctrl"); 61 if (!np) { 62 pr_err("%s: failed to find sysctrl node\n", __func__); 63 return; 64 } 65 66 aonsysctrl_base = of_iomap(np, 0); 67 if (!aonsysctrl_base) { 68 pr_err("%s: failed to map aonsysctrl\n", __func__); 69 of_node_put(np); 70 return; 71 } 72 73 /* 74 * Write the address of secondary startup into the 75 * system-wide flags register. The BootMonitor waits 76 * until it receives a soft interrupt, and then the 77 * secondary CPU branches to this address. 78 */ 79 __raw_writel(virt_to_phys(zx_secondary_startup), 80 aonsysctrl_base + AON_SYS_CTRL_RESERVED1); 81 82 iounmap(aonsysctrl_base); 83 of_node_put(np); 84 85 np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); 86 pcu_base = of_iomap(np, 0); 87 of_node_put(np); 88 WARN_ON(!pcu_base); 89 90 np = of_find_compatible_node(NULL, NULL, "zte,zx-bus-matrix"); 91 matrix_base = of_iomap(np, 0); 92 of_node_put(np); 93 WARN_ON(!matrix_base); 94 95 /* Map the first 4 KB IRAM for suspend usage */ 96 sys_iram = __arm_ioremap_exec(ZX_IRAM_BASE, PAGE_SIZE, false); 97 zx_secondary_startup_pa = virt_to_phys(zx_secondary_startup); 98 fncpy(sys_iram, &zx_resume_jump, zx_suspend_iram_sz); 99} 100 101static int zx_boot_secondary(unsigned int cpu, struct task_struct *idle) 102{ 103 static bool first_boot = true; 104 105 if (first_boot) { 106 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 107 first_boot = false; 108 return 0; 109 } 110 111 /* Swap the base address mapping between IRAM and IROM */ 112 writel_relaxed(0x1, matrix_base + BUS_MATRIX_REMAP_CONFIG); 113 114 /* Power on CPU1 */ 115 writel_relaxed(0x0, pcu_base + PCU_CPU1_CTRL); 116 117 /* Wait for power on ack */ 118 while (readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x4) 119 cpu_relax(); 120 121 /* Swap back the mapping of IRAM and IROM */ 122 writel_relaxed(0x0, matrix_base + BUS_MATRIX_REMAP_CONFIG); 123 124 return 0; 125} 126 127#ifdef CONFIG_HOTPLUG_CPU 128static inline void cpu_enter_lowpower(void) 129{ 130 unsigned int v; 131 132 asm volatile( 133 "mcr p15, 0, %1, c7, c5, 0\n" 134 " mcr p15, 0, %1, c7, c10, 4\n" 135 /* 136 * Turn off coherency 137 */ 138 " mrc p15, 0, %0, c1, c0, 1\n" 139 " bic %0, %0, %3\n" 140 " mcr p15, 0, %0, c1, c0, 1\n" 141 " mrc p15, 0, %0, c1, c0, 0\n" 142 " bic %0, %0, %2\n" 143 " mcr p15, 0, %0, c1, c0, 0\n" 144 : "=&r" (v) 145 : "r" (0), "Ir" (CR_C), "Ir" (0x40) 146 : "cc"); 147} 148 149static int zx_cpu_kill(unsigned int cpu) 150{ 151 unsigned long timeout = jiffies + msecs_to_jiffies(2000); 152 153 writel_relaxed(0x2, pcu_base + PCU_CPU1_CTRL); 154 155 while ((readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x3) != 0x0) { 156 if (time_after(jiffies, timeout)) { 157 pr_err("*** cpu1 poweroff timeout\n"); 158 break; 159 } 160 } 161 return 1; 162} 163 164static void zx_cpu_die(unsigned int cpu) 165{ 166 scu_power_mode(scu_base, SCU_PM_POWEROFF); 167 cpu_enter_lowpower(); 168 169 while (1) 170 cpu_do_idle(); 171} 172#endif 173 174static void zx_secondary_init(unsigned int cpu) 175{ 176 scu_power_mode(scu_base, SCU_PM_NORMAL); 177} 178 179struct smp_operations zx_smp_ops __initdata = { 180 .smp_prepare_cpus = zx_smp_prepare_cpus, 181 .smp_secondary_init = zx_secondary_init, 182 .smp_boot_secondary = zx_boot_secondary, 183#ifdef CONFIG_HOTPLUG_CPU 184 .cpu_kill = zx_cpu_kill, 185 .cpu_die = zx_cpu_die, 186#endif 187}; 188 189CPU_METHOD_OF_DECLARE(zx_smp, "zte,zx296702-smp", &zx_smp_ops); 190