1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * R-Car Generation 2 Power management support |
4 | * |
5 | * Copyright (C) 2013 - 2015 Renesas Electronics Corporation |
6 | * Copyright (C) 2011 Renesas Solutions Corp. |
7 | * Copyright (C) 2011 Magnus Damm |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/ioport.h> |
12 | #include <linux/of.h> |
13 | #include <linux/of_address.h> |
14 | #include <linux/smp.h> |
15 | #include <asm/io.h> |
16 | #include <asm/cputype.h> |
17 | #include "common.h" |
18 | #include "rcar-gen2.h" |
19 | |
20 | /* RST */ |
21 | #define RST 0xe6160000 |
22 | |
23 | #define CA15BAR 0x0020 /* CA15 Boot Address Register */ |
24 | #define CA7BAR 0x0030 /* CA7 Boot Address Register */ |
25 | #define CA15RESCNT 0x0040 /* CA15 Reset Control Register */ |
26 | #define CA7RESCNT 0x0044 /* CA7 Reset Control Register */ |
27 | |
28 | /* SYS Boot Address Register */ |
29 | #define SBAR_BAREN BIT(4) /* SBAR is valid */ |
30 | |
31 | /* Reset Control Registers */ |
32 | #define CA15RESCNT_CODE 0xa5a50000 |
33 | #define CA15RESCNT_CPUS 0xf /* CPU0-3 */ |
34 | #define CA7RESCNT_CODE 0x5a5a0000 |
35 | #define CA7RESCNT_CPUS 0xf /* CPU0-3 */ |
36 | |
37 | /* On-chip RAM */ |
38 | #define ICRAM1 0xe63c0000 /* Inter Connect RAM1 (4 KiB) */ |
39 | |
40 | static inline u32 phys_to_sbar(phys_addr_t addr) |
41 | { |
42 | return (addr >> 8) & 0xfffffc00; |
43 | } |
44 | |
45 | void __init rcar_gen2_pm_init(void) |
46 | { |
47 | void __iomem *p; |
48 | u32 bar; |
49 | struct device_node *np; |
50 | bool has_a7 = false; |
51 | bool has_a15 = false; |
52 | struct resource res; |
53 | int error; |
54 | |
55 | if (!request_mem_region(0, SZ_256K, "Boot Area" )) { |
56 | pr_err("Failed to request boot area\n" ); |
57 | return; |
58 | } |
59 | |
60 | for_each_of_cpu_node(np) { |
61 | if (of_device_is_compatible(device: np, "arm,cortex-a15" )) |
62 | has_a15 = true; |
63 | else if (of_device_is_compatible(device: np, "arm,cortex-a7" )) |
64 | has_a7 = true; |
65 | } |
66 | |
67 | np = of_find_compatible_node(NULL, NULL, compat: "renesas,smp-sram" ); |
68 | if (!np) { |
69 | /* No smp-sram in DT, fall back to hardcoded address */ |
70 | res = (struct resource)DEFINE_RES_MEM(ICRAM1, |
71 | shmobile_boot_size); |
72 | goto map; |
73 | } |
74 | |
75 | error = of_address_to_resource(dev: np, index: 0, r: &res); |
76 | of_node_put(node: np); |
77 | if (error) { |
78 | pr_err("Failed to get smp-sram address: %d\n" , error); |
79 | return; |
80 | } |
81 | |
82 | map: |
83 | /* RAM for jump stub, because BAR requires 256KB aligned address */ |
84 | if (res.start & (256 * 1024 - 1) || |
85 | resource_size(res: &res) < shmobile_boot_size) { |
86 | pr_err("Invalid smp-sram region\n" ); |
87 | return; |
88 | } |
89 | |
90 | p = ioremap(offset: res.start, size: resource_size(res: &res)); |
91 | if (!p) |
92 | return; |
93 | /* |
94 | * install the reset vector, use the largest version if we have enough |
95 | * memory available |
96 | */ |
97 | if (resource_size(res: &res) >= shmobile_boot_size_gen2) { |
98 | shmobile_boot_cpu_gen2 = read_cpuid_mpidr(); |
99 | memcpy_toio(p, shmobile_boot_vector_gen2, |
100 | shmobile_boot_size_gen2); |
101 | } else { |
102 | memcpy_toio(p, shmobile_boot_vector, shmobile_boot_size); |
103 | } |
104 | iounmap(addr: p); |
105 | |
106 | /* setup reset vectors */ |
107 | p = ioremap(RST, size: 0x63); |
108 | bar = phys_to_sbar(addr: res.start); |
109 | if (has_a15) { |
110 | writel_relaxed(bar, p + CA15BAR); |
111 | writel_relaxed(bar | SBAR_BAREN, p + CA15BAR); |
112 | |
113 | /* de-assert reset for CA15 CPUs */ |
114 | writel_relaxed((readl_relaxed(p + CA15RESCNT) & |
115 | ~CA15RESCNT_CPUS) | CA15RESCNT_CODE, |
116 | p + CA15RESCNT); |
117 | } |
118 | if (has_a7) { |
119 | writel_relaxed(bar, p + CA7BAR); |
120 | writel_relaxed(bar | SBAR_BAREN, p + CA7BAR); |
121 | |
122 | /* de-assert reset for CA7 CPUs */ |
123 | writel_relaxed((readl_relaxed(p + CA7RESCNT) & |
124 | ~CA7RESCNT_CPUS) | CA7RESCNT_CODE, |
125 | p + CA7RESCNT); |
126 | } |
127 | iounmap(addr: p); |
128 | |
129 | shmobile_smp_apmu_suspend_init(); |
130 | } |
131 | |