0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/cpu_pm.h>
0009 #include <linux/delay.h>
0010 #include <linux/init.h>
0011 #include <linux/io.h>
0012 #include <linux/ioport.h>
0013 #include <linux/of_address.h>
0014 #include <linux/smp.h>
0015 #include <linux/suspend.h>
0016 #include <linux/threads.h>
0017 #include <asm/cacheflush.h>
0018 #include <asm/cp15.h>
0019 #include <asm/proc-fns.h>
0020 #include <asm/smp_plat.h>
0021 #include <asm/suspend.h>
0022 #include "common.h"
0023 #include "rcar-gen2.h"
0024
0025 static struct {
0026 void __iomem *iomem;
0027 int bit;
0028 } apmu_cpus[NR_CPUS];
0029
0030 #define WUPCR_OFFS 0x10
0031 #define PSTR_OFFS 0x40
0032 #define CPUNCR_OFFS(n) (0x100 + (0x10 * (n)))
0033
0034 #define DBGRCR_OFFS 0x180
0035
0036
0037 #define CPUNST(r, n) (((r) >> (n * 4)) & 3)
0038 #define CPUST_RUN 0
0039 #define CPUST_STANDBY 3
0040
0041
0042 #define DBGCPUREN BIT(24)
0043 #define DBGCPUNREN(n) BIT((n) + 20)
0044 #define DBGCPUPREN BIT(19)
0045
0046 static int __maybe_unused apmu_power_on(void __iomem *p, int bit)
0047 {
0048
0049 writel_relaxed(BIT(bit), p + WUPCR_OFFS);
0050
0051
0052 while (readl_relaxed(p + WUPCR_OFFS) != 0)
0053 ;
0054
0055 return 0;
0056 }
0057
0058 static int __maybe_unused apmu_power_off(void __iomem *p, int bit)
0059 {
0060
0061 writel_relaxed(3, p + CPUNCR_OFFS(bit));
0062 return 0;
0063 }
0064
0065 static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit)
0066 {
0067 int k;
0068
0069 for (k = 0; k < 1000; k++) {
0070 if (CPUNST(readl_relaxed(p + PSTR_OFFS), bit) == CPUST_STANDBY)
0071 return 1;
0072
0073 mdelay(1);
0074 }
0075
0076 return 0;
0077 }
0078
0079 static int __maybe_unused apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu))
0080 {
0081 void __iomem *p = apmu_cpus[cpu].iomem;
0082
0083 return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL;
0084 }
0085
0086 #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND)
0087
0088 static inline void cpu_enter_lowpower_a15(void)
0089 {
0090 unsigned int v;
0091
0092 asm volatile(
0093 " mrc p15, 0, %0, c1, c0, 0\n"
0094 " bic %0, %0, %1\n"
0095 " mcr p15, 0, %0, c1, c0, 0\n"
0096 : "=&r" (v)
0097 : "Ir" (CR_C)
0098 : "cc");
0099
0100 flush_cache_louis();
0101
0102 asm volatile(
0103
0104
0105
0106 " mrc p15, 0, %0, c1, c0, 1\n"
0107 " bic %0, %0, %1\n"
0108 " mcr p15, 0, %0, c1, c0, 1\n"
0109 : "=&r" (v)
0110 : "Ir" (0x40)
0111 : "cc");
0112
0113 isb();
0114 dsb();
0115 }
0116
0117 static void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu)
0118 {
0119
0120
0121 apmu_wrap(cpu, apmu_power_off);
0122
0123
0124 cpu_enter_lowpower_a15();
0125 }
0126 #endif
0127
0128 #if defined(CONFIG_HOTPLUG_CPU)
0129 static void shmobile_smp_apmu_cpu_die(unsigned int cpu)
0130 {
0131
0132 shmobile_smp_hook(cpu, 0, 0);
0133
0134
0135 shmobile_smp_apmu_cpu_shutdown(cpu);
0136
0137
0138 shmobile_smp_sleep();
0139 }
0140
0141 static int shmobile_smp_apmu_cpu_kill(unsigned int cpu)
0142 {
0143 return apmu_wrap(cpu, apmu_power_off_poll);
0144 }
0145 #endif
0146
0147 #if defined(CONFIG_SUSPEND)
0148 static int shmobile_smp_apmu_do_suspend(unsigned long cpu)
0149 {
0150 shmobile_smp_hook(cpu, __pa_symbol(cpu_resume), 0);
0151 shmobile_smp_apmu_cpu_shutdown(cpu);
0152 cpu_do_idle();
0153 return 1;
0154 }
0155
0156 static inline void cpu_leave_lowpower(void)
0157 {
0158 unsigned int v;
0159
0160 asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
0161 " orr %0, %0, %1\n"
0162 " mcr p15, 0, %0, c1, c0, 0\n"
0163 " mrc p15, 0, %0, c1, c0, 1\n"
0164 " orr %0, %0, %2\n"
0165 " mcr p15, 0, %0, c1, c0, 1\n"
0166 : "=&r" (v)
0167 : "Ir" (CR_C), "Ir" (0x40)
0168 : "cc");
0169 }
0170
0171 static int shmobile_smp_apmu_enter_suspend(suspend_state_t state)
0172 {
0173 cpu_suspend(smp_processor_id(), shmobile_smp_apmu_do_suspend);
0174 cpu_leave_lowpower();
0175 return 0;
0176 }
0177
0178 void __init shmobile_smp_apmu_suspend_init(void)
0179 {
0180 shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend;
0181 }
0182 #endif
0183
0184 #ifdef CONFIG_SMP
0185 static void apmu_init_cpu(struct resource *res, int cpu, int bit)
0186 {
0187 u32 x;
0188
0189 if ((cpu >= ARRAY_SIZE(apmu_cpus)) || apmu_cpus[cpu].iomem)
0190 return;
0191
0192 apmu_cpus[cpu].iomem = ioremap(res->start, resource_size(res));
0193 apmu_cpus[cpu].bit = bit;
0194
0195 pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);
0196
0197
0198 x = readl(apmu_cpus[cpu].iomem + DBGRCR_OFFS);
0199 x |= DBGCPUREN | DBGCPUNREN(bit) | DBGCPUPREN;
0200 writel(x, apmu_cpus[cpu].iomem + DBGRCR_OFFS);
0201 }
0202
0203 static const struct of_device_id apmu_ids[] = {
0204 { .compatible = "renesas,apmu" },
0205 { }
0206 };
0207
0208 static void apmu_parse_dt(void (*fn)(struct resource *res, int cpu, int bit))
0209 {
0210 struct device_node *np_apmu, *np_cpu;
0211 struct resource res;
0212 int bit, index;
0213 u32 id;
0214
0215 for_each_matching_node(np_apmu, apmu_ids) {
0216
0217 bool is_allowed = false;
0218
0219 for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
0220 np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
0221 if (np_cpu) {
0222 if (!of_property_read_u32(np_cpu, "reg", &id)) {
0223 if (id == cpu_logical_map(0)) {
0224 is_allowed = true;
0225 of_node_put(np_cpu);
0226 break;
0227 }
0228
0229 }
0230 of_node_put(np_cpu);
0231 }
0232 }
0233 if (!is_allowed)
0234 continue;
0235
0236 for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
0237 np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
0238 if (np_cpu) {
0239 if (!of_property_read_u32(np_cpu, "reg", &id)) {
0240 index = get_logical_index(id);
0241 if ((index >= 0) &&
0242 !of_address_to_resource(np_apmu,
0243 0, &res))
0244 fn(&res, index, bit);
0245 }
0246 of_node_put(np_cpu);
0247 }
0248 }
0249 }
0250 }
0251
0252 static void __init shmobile_smp_apmu_setup_boot(void)
0253 {
0254
0255 shmobile_boot_fn = __pa_symbol(shmobile_smp_boot);
0256 shmobile_boot_fn_gen2 = shmobile_boot_fn;
0257 }
0258
0259 static int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
0260 struct task_struct *idle)
0261 {
0262
0263 shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_apmu), 0);
0264
0265 return apmu_wrap(cpu, apmu_power_on);
0266 }
0267
0268 static void __init shmobile_smp_apmu_prepare_cpus_dt(unsigned int max_cpus)
0269 {
0270 shmobile_smp_apmu_setup_boot();
0271 apmu_parse_dt(apmu_init_cpu);
0272 rcar_gen2_pm_init();
0273 }
0274
0275 static struct smp_operations apmu_smp_ops __initdata = {
0276 .smp_prepare_cpus = shmobile_smp_apmu_prepare_cpus_dt,
0277 .smp_boot_secondary = shmobile_smp_apmu_boot_secondary,
0278 #ifdef CONFIG_HOTPLUG_CPU
0279 .cpu_can_disable = shmobile_smp_cpu_can_disable,
0280 .cpu_die = shmobile_smp_apmu_cpu_die,
0281 .cpu_kill = shmobile_smp_apmu_cpu_kill,
0282 #endif
0283 };
0284
0285 CPU_METHOD_OF_DECLARE(shmobile_smp_apmu, "renesas,apmu", &apmu_smp_ops);
0286 #endif