2 * Copyright (c) 2013-2014 Linaro Ltd.
3 * Copyright (c) 2013-2014 Hisilicon Limited.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 #include <linux/delay.h>
11 #include <linux/memblock.h>
12 #include <linux/of_address.h>
14 #include <asm/cputype.h>
20 /* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x]
21 * 1 -- unreset; 0 -- reset
23 #define CORE_RESET_BIT(x) (1 << x)
24 #define NEON_RESET_BIT(x) (1 << (x + 4))
25 #define CORE_DEBUG_RESET_BIT(x) (1 << (x + 9))
26 #define CLUSTER_L2_RESET_BIT (1 << 8)
27 #define CLUSTER_DEBUG_RESET_BIT (1 << 13)
30 * bits definition in SC_CPU_RESET_STATUS[x]
31 * 1 -- reset status; 0 -- unreset status
33 #define CORE_RESET_STATUS(x) (1 << x)
34 #define NEON_RESET_STATUS(x) (1 << (x + 4))
35 #define CORE_DEBUG_RESET_STATUS(x) (1 << (x + 9))
36 #define CLUSTER_L2_RESET_STATUS (1 << 8)
37 #define CLUSTER_DEBUG_RESET_STATUS (1 << 13)
38 #define CORE_WFI_STATUS(x) (1 << (x + 16))
39 #define CORE_WFE_STATUS(x) (1 << (x + 20))
40 #define CORE_DEBUG_ACK(x) (1 << (x + 24))
42 #define SC_CPU_RESET_REQ(x) (0x520 + (x << 3)) /* reset */
43 #define SC_CPU_RESET_DREQ(x) (0x524 + (x << 3)) /* unreset */
44 #define SC_CPU_RESET_STATUS(x) (0x1520 + (x << 3))
46 #define FAB_SF_MODE 0x0c
47 #define FAB_SF_INVLD 0x10
49 /* bits definition in FB_SF_INVLD */
50 #define FB_SF_INVLD_START (1 << 8)
52 #define HIP04_MAX_CLUSTERS 4
53 #define HIP04_MAX_CPUS_PER_CLUSTER 4
56 #define TIMEOUT_MSEC 1000
58 static void __iomem
*sysctrl
, *fabric
;
59 static int hip04_cpu_table
[HIP04_MAX_CLUSTERS
][HIP04_MAX_CPUS_PER_CLUSTER
];
60 static DEFINE_SPINLOCK(boot_lock
);
61 static u32 fabric_phys_addr
;
63 * [0]: bootwrapper physical address
64 * [1]: bootwrapper size
65 * [2]: relocation address
66 * [3]: relocation size
68 static u32 hip04_boot_method
[4];
70 static bool hip04_cluster_is_down(unsigned int cluster
)
74 for (i
= 0; i
< HIP04_MAX_CPUS_PER_CLUSTER
; i
++)
75 if (hip04_cpu_table
[cluster
][i
])
80 static void hip04_set_snoop_filter(unsigned int cluster
, unsigned int on
)
86 data
= readl_relaxed(fabric
+ FAB_SF_MODE
);
90 data
&= ~(1 << cluster
);
91 writel_relaxed(data
, fabric
+ FAB_SF_MODE
);
94 } while (data
!= readl_relaxed(fabric
+ FAB_SF_MODE
));
97 static int hip04_mcpm_power_up(unsigned int cpu
, unsigned int cluster
)
100 void __iomem
*sys_dreq
, *sys_status
;
104 if (cluster
>= HIP04_MAX_CLUSTERS
|| cpu
>= HIP04_MAX_CPUS_PER_CLUSTER
)
107 spin_lock_irq(&boot_lock
);
109 if (hip04_cpu_table
[cluster
][cpu
])
112 sys_dreq
= sysctrl
+ SC_CPU_RESET_DREQ(cluster
);
113 sys_status
= sysctrl
+ SC_CPU_RESET_STATUS(cluster
);
114 if (hip04_cluster_is_down(cluster
)) {
115 data
= CLUSTER_DEBUG_RESET_BIT
;
116 writel_relaxed(data
, sys_dreq
);
119 data
= readl_relaxed(sys_status
);
120 } while (data
& CLUSTER_DEBUG_RESET_STATUS
);
123 data
= CORE_RESET_BIT(cpu
) | NEON_RESET_BIT(cpu
) | \
124 CORE_DEBUG_RESET_BIT(cpu
);
125 writel_relaxed(data
, sys_dreq
);
128 } while (data
== readl_relaxed(sys_status
));
130 * We may fail to power up core again without this delay.
131 * It's not mentioned in document. It's found by test.
135 hip04_cpu_table
[cluster
][cpu
]++;
136 spin_unlock_irq(&boot_lock
);
141 static void hip04_mcpm_power_down(void)
143 unsigned int mpidr
, cpu
, cluster
;
144 bool skip_wfi
= false, last_man
= false;
146 mpidr
= read_cpuid_mpidr();
147 cpu
= MPIDR_AFFINITY_LEVEL(mpidr
, 0);
148 cluster
= MPIDR_AFFINITY_LEVEL(mpidr
, 1);
150 __mcpm_cpu_going_down(cpu
, cluster
);
152 spin_lock(&boot_lock
);
153 BUG_ON(__mcpm_cluster_state(cluster
) != CLUSTER_UP
);
154 hip04_cpu_table
[cluster
][cpu
]--;
155 if (hip04_cpu_table
[cluster
][cpu
] == 1) {
156 /* A power_up request went ahead of us. */
158 } else if (hip04_cpu_table
[cluster
][cpu
] > 1) {
159 pr_err("Cluster %d CPU%d boots multiple times\n", cluster
, cpu
);
163 last_man
= hip04_cluster_is_down(cluster
);
164 if (last_man
&& __mcpm_outbound_enter_critical(cpu
, cluster
)) {
165 spin_unlock(&boot_lock
);
166 /* Since it's Cortex A15, disable L2 prefetching. */
168 "mcr p15, 1, %0, c15, c0, 3 \n\t"
172 v7_exit_coherency_flush(all
);
173 hip04_set_snoop_filter(cluster
, 0);
174 __mcpm_outbound_leave_critical(cluster
, CLUSTER_DOWN
);
176 spin_unlock(&boot_lock
);
177 v7_exit_coherency_flush(louis
);
180 __mcpm_cpu_down(cpu
, cluster
);
186 static int hip04_mcpm_wait_for_powerdown(unsigned int cpu
, unsigned int cluster
)
188 unsigned int data
, tries
, count
;
189 int ret
= -ETIMEDOUT
;
191 BUG_ON(cluster
>= HIP04_MAX_CLUSTERS
||
192 cpu
>= HIP04_MAX_CPUS_PER_CLUSTER
);
194 count
= TIMEOUT_MSEC
/ POLL_MSEC
;
195 spin_lock_irq(&boot_lock
);
196 for (tries
= 0; tries
< count
; tries
++) {
197 if (hip04_cpu_table
[cluster
][cpu
]) {
202 data
= readl_relaxed(sysctrl
+ SC_CPU_RESET_STATUS(cluster
));
203 if (data
& CORE_WFI_STATUS(cpu
))
205 spin_unlock_irq(&boot_lock
);
206 /* Wait for clean L2 when the whole cluster is down. */
208 spin_lock_irq(&boot_lock
);
212 data
= CORE_RESET_BIT(cpu
) | NEON_RESET_BIT(cpu
) | \
213 CORE_DEBUG_RESET_BIT(cpu
);
214 writel_relaxed(data
, sysctrl
+ SC_CPU_RESET_REQ(cluster
));
215 for (tries
= 0; tries
< count
; tries
++) {
217 data
= readl_relaxed(sysctrl
+ SC_CPU_RESET_STATUS(cluster
));
218 if (data
& CORE_RESET_STATUS(cpu
))
223 spin_unlock_irq(&boot_lock
);
226 spin_unlock_irq(&boot_lock
);
230 static void hip04_mcpm_powered_up(void)
232 unsigned int mpidr
, cpu
, cluster
;
234 mpidr
= read_cpuid_mpidr();
235 cpu
= MPIDR_AFFINITY_LEVEL(mpidr
, 0);
236 cluster
= MPIDR_AFFINITY_LEVEL(mpidr
, 1);
238 spin_lock(&boot_lock
);
239 if (!hip04_cpu_table
[cluster
][cpu
])
240 hip04_cpu_table
[cluster
][cpu
] = 1;
241 spin_unlock(&boot_lock
);
244 static void __naked
hip04_mcpm_power_up_setup(unsigned int affinity_level
)
249 /* calculate fabric phys address */
251 " ldmia r2, {r1, r3} \n"
253 " ldr r2, [r0, r3] \n"
254 /* get cluster id from MPIDR */
255 " mrc p15, 0, r0, c0, c0, 5 \n"
256 " ubfx r1, r0, #8, #8 \n"
257 /* 1 << cluster id */
259 " mov r3, r0, lsl r1 \n"
260 " ldr r0, [r2, #"__stringify(FAB_SF_MODE
)"] \n"
264 " str r1, [r2, #"__stringify(FAB_SF_MODE
)"] \n"
265 "1: ldr r0, [r2, #"__stringify(FAB_SF_MODE
)"] \n"
272 " .word fabric_phys_addr \n"
276 static const struct mcpm_platform_ops hip04_mcpm_ops
= {
277 .power_up
= hip04_mcpm_power_up
,
278 .power_down
= hip04_mcpm_power_down
,
279 .wait_for_powerdown
= hip04_mcpm_wait_for_powerdown
,
280 .powered_up
= hip04_mcpm_powered_up
,
283 static bool __init
hip04_cpu_table_init(void)
285 unsigned int mpidr
, cpu
, cluster
;
287 mpidr
= read_cpuid_mpidr();
288 cpu
= MPIDR_AFFINITY_LEVEL(mpidr
, 0);
289 cluster
= MPIDR_AFFINITY_LEVEL(mpidr
, 1);
291 if (cluster
>= HIP04_MAX_CLUSTERS
||
292 cpu
>= HIP04_MAX_CPUS_PER_CLUSTER
) {
293 pr_err("%s: boot CPU is out of bound!\n", __func__
);
296 hip04_set_snoop_filter(cluster
, 1);
297 hip04_cpu_table
[cluster
][cpu
] = 1;
301 static int __init
hip04_mcpm_init(void)
303 struct device_node
*np
, *np_sctl
, *np_fab
;
304 struct resource fab_res
;
305 void __iomem
*relocation
;
308 np
= of_find_compatible_node(NULL
, NULL
, "hisilicon,hip04-bootwrapper");
311 ret
= of_property_read_u32_array(np
, "boot-method",
312 &hip04_boot_method
[0], 4);
315 np_sctl
= of_find_compatible_node(NULL
, NULL
, "hisilicon,sysctrl");
318 np_fab
= of_find_compatible_node(NULL
, NULL
, "hisilicon,hip04-fabric");
322 ret
= memblock_reserve(hip04_boot_method
[0], hip04_boot_method
[1]);
326 relocation
= ioremap(hip04_boot_method
[2], hip04_boot_method
[3]);
328 pr_err("failed to map relocation space\n");
332 sysctrl
= of_iomap(np_sctl
, 0);
334 pr_err("failed to get sysctrl base\n");
338 ret
= of_address_to_resource(np_fab
, 0, &fab_res
);
340 pr_err("failed to get fabric base phys\n");
343 fabric_phys_addr
= fab_res
.start
;
344 sync_cache_w(&fabric_phys_addr
);
345 fabric
= of_iomap(np_fab
, 0);
347 pr_err("failed to get fabric base\n");
352 if (!hip04_cpu_table_init()) {
356 ret
= mcpm_platform_register(&hip04_mcpm_ops
);
362 * Fill the instruction address that is used after secondary core
365 writel_relaxed(hip04_boot_method
[0], relocation
);
366 writel_relaxed(0xa5a5a5a5, relocation
+ 4); /* magic number */
367 writel_relaxed(virt_to_phys(mcpm_entry_point
), relocation
+ 8);
368 writel_relaxed(0, relocation
+ 12);
371 mcpm_sync_init(hip04_mcpm_power_up_setup
);
373 pr_info("HiP04 MCPM initialized\n");
382 memblock_free(hip04_boot_method
[0], hip04_boot_method
[1]);
386 early_initcall(hip04_mcpm_init
);