1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Low-level power-management support for Alpine platform. |
4 | * |
5 | * Copyright (C) 2015 Annapurna Labs Ltd. |
6 | */ |
7 | |
8 | #include <linux/io.h> |
9 | #include <linux/of.h> |
10 | #include <linux/of_address.h> |
11 | #include <linux/regmap.h> |
12 | #include <linux/mfd/syscon.h> |
13 | |
14 | #include "alpine_cpu_pm.h" |
15 | #include "alpine_cpu_resume.h" |
16 | |
17 | /* NB registers */ |
18 | #define AL_SYSFAB_POWER_CONTROL(cpu) (0x2000 + (cpu)*0x100 + 0x20) |
19 | |
20 | static struct regmap *al_sysfabric; |
21 | static struct al_cpu_resume_regs __iomem *al_cpu_resume_regs; |
22 | static int wakeup_supported; |
23 | |
24 | int alpine_cpu_wakeup(unsigned int phys_cpu, uint32_t phys_resume_addr) |
25 | { |
26 | if (!wakeup_supported) |
27 | return -ENOSYS; |
28 | |
29 | /* |
30 | * Set CPU resume address - |
31 | * secure firmware running on boot will jump to this address |
32 | * after setting proper CPU mode, and initialiing e.g. secure |
33 | * regs (the same mode all CPUs are booted to - usually HYP) |
34 | */ |
35 | writel(val: phys_resume_addr, |
36 | addr: &al_cpu_resume_regs->per_cpu[phys_cpu].resume_addr); |
37 | |
38 | /* Power-up the CPU */ |
39 | regmap_write(map: al_sysfabric, AL_SYSFAB_POWER_CONTROL(phys_cpu), val: 0); |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | void __init alpine_cpu_pm_init(void) |
45 | { |
46 | struct device_node *np; |
47 | uint32_t watermark; |
48 | |
49 | al_sysfabric = syscon_regmap_lookup_by_compatible(s: "al,alpine-sysfabric-service" ); |
50 | |
51 | np = of_find_compatible_node(NULL, NULL, compat: "al,alpine-cpu-resume" ); |
52 | al_cpu_resume_regs = of_iomap(node: np, index: 0); |
53 | |
54 | wakeup_supported = !IS_ERR(ptr: al_sysfabric) && al_cpu_resume_regs; |
55 | |
56 | if (wakeup_supported) { |
57 | watermark = readl(addr: &al_cpu_resume_regs->watermark); |
58 | wakeup_supported = (watermark & AL_CPU_RESUME_MAGIC_NUM_MASK) |
59 | == AL_CPU_RESUME_MAGIC_NUM; |
60 | } |
61 | } |
62 | |