1/*
2 * Copyright (c) 2013-2014 Linaro Ltd.
3 * Copyright (c) 2013-2014 Hisilicon Limited.
4 *
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.
8 */
9#include <linux/delay.h>
10#include <linux/io.h>
11#include <linux/memblock.h>
12#include <linux/of_address.h>
13
14#include <asm/cputype.h>
15#include <asm/cp15.h>
16#include <asm/mcpm.h>
17
18#include "core.h"
19
20/* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x]
21 * 1 -- unreset; 0 -- reset
22 */
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)
28
29/*
30 * bits definition in SC_CPU_RESET_STATUS[x]
31 * 1 -- reset status; 0 -- unreset status
32 */
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))
41
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))
45
46#define FAB_SF_MODE			0x0c
47#define FAB_SF_INVLD			0x10
48
49/* bits definition in FB_SF_INVLD */
50#define FB_SF_INVLD_START		(1 << 8)
51
52#define HIP04_MAX_CLUSTERS		4
53#define HIP04_MAX_CPUS_PER_CLUSTER	4
54
55#define POLL_MSEC	10
56#define TIMEOUT_MSEC	1000
57
58static void __iomem *sysctrl, *fabric;
59static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER];
60static DEFINE_SPINLOCK(boot_lock);
61static u32 fabric_phys_addr;
62/*
63 * [0]: bootwrapper physical address
64 * [1]: bootwrapper size
65 * [2]: relocation address
66 * [3]: relocation size
67 */
68static u32 hip04_boot_method[4];
69
70static bool hip04_cluster_is_down(unsigned int cluster)
71{
72	int i;
73
74	for (i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++)
75		if (hip04_cpu_table[cluster][i])
76			return false;
77	return true;
78}
79
80static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
81{
82	unsigned long data;
83
84	if (!fabric)
85		BUG();
86	data = readl_relaxed(fabric + FAB_SF_MODE);
87	if (on)
88		data |= 1 << cluster;
89	else
90		data &= ~(1 << cluster);
91	writel_relaxed(data, fabric + FAB_SF_MODE);
92	do {
93		cpu_relax();
94	} while (data != readl_relaxed(fabric + FAB_SF_MODE));
95}
96
97static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
98{
99	unsigned long data;
100	void __iomem *sys_dreq, *sys_status;
101
102	if (!sysctrl)
103		return -ENODEV;
104	if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
105		return -EINVAL;
106
107	spin_lock_irq(&boot_lock);
108
109	if (hip04_cpu_table[cluster][cpu])
110		goto out;
111
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);
117		do {
118			cpu_relax();
119			data = readl_relaxed(sys_status);
120		} while (data & CLUSTER_DEBUG_RESET_STATUS);
121	}
122
123	data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
124	       CORE_DEBUG_RESET_BIT(cpu);
125	writel_relaxed(data, sys_dreq);
126	do {
127		cpu_relax();
128	} while (data == readl_relaxed(sys_status));
129	/*
130	 * We may fail to power up core again without this delay.
131	 * It's not mentioned in document. It's found by test.
132	 */
133	udelay(20);
134out:
135	hip04_cpu_table[cluster][cpu]++;
136	spin_unlock_irq(&boot_lock);
137
138	return 0;
139}
140
141static void hip04_mcpm_power_down(void)
142{
143	unsigned int mpidr, cpu, cluster;
144	bool skip_wfi = false, last_man = false;
145
146	mpidr = read_cpuid_mpidr();
147	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
148	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
149
150	__mcpm_cpu_going_down(cpu, cluster);
151
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. */
157		skip_wfi = true;
158	} else if (hip04_cpu_table[cluster][cpu] > 1) {
159		pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
160		BUG();
161	}
162
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. */
167		asm volatile(
168		"mcr	p15, 1, %0, c15, c0, 3 \n\t"
169		"isb	\n\t"
170		"dsb	"
171		: : "r" (0x400) );
172		v7_exit_coherency_flush(all);
173		hip04_set_snoop_filter(cluster, 0);
174		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
175	} else {
176		spin_unlock(&boot_lock);
177		v7_exit_coherency_flush(louis);
178	}
179
180	__mcpm_cpu_down(cpu, cluster);
181
182	if (!skip_wfi)
183		wfi();
184}
185
186static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
187{
188	unsigned int data, tries, count;
189	int ret = -ETIMEDOUT;
190
191	BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
192	       cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
193
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]) {
198			ret = -EBUSY;
199			goto err;
200		}
201		cpu_relax();
202		data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
203		if (data & CORE_WFI_STATUS(cpu))
204			break;
205		spin_unlock_irq(&boot_lock);
206		/* Wait for clean L2 when the whole cluster is down. */
207		msleep(POLL_MSEC);
208		spin_lock_irq(&boot_lock);
209	}
210	if (tries >= count)
211		goto err;
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++) {
216		cpu_relax();
217		data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
218		if (data & CORE_RESET_STATUS(cpu))
219			break;
220	}
221	if (tries >= count)
222		goto err;
223	spin_unlock_irq(&boot_lock);
224	return 0;
225err:
226	spin_unlock_irq(&boot_lock);
227	return ret;
228}
229
230static void hip04_mcpm_powered_up(void)
231{
232	unsigned int mpidr, cpu, cluster;
233
234	mpidr = read_cpuid_mpidr();
235	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
236	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
237
238	spin_lock(&boot_lock);
239	if (!hip04_cpu_table[cluster][cpu])
240		hip04_cpu_table[cluster][cpu] = 1;
241	spin_unlock(&boot_lock);
242}
243
244static void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level)
245{
246	asm volatile ("			\n"
247"	cmp	r0, #0			\n"
248"	bxeq	lr			\n"
249	/* calculate fabric phys address */
250"	adr	r2, 2f			\n"
251"	ldmia	r2, {r1, r3}		\n"
252"	sub	r0, r2, r1		\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 */
258"	mov	r0, #1			\n"
259"	mov	r3, r0, lsl r1		\n"
260"	ldr	r0, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
261"	tst	r0, r3			\n"
262"	bxne	lr			\n"
263"	orr	r1, r0, r3		\n"
264"	str	r1, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
265"1:	ldr	r0, [r2, #"__stringify(FAB_SF_MODE)"]	\n"
266"	tst	r0, r3			\n"
267"	beq	1b			\n"
268"	bx	lr			\n"
269
270"	.align	2			\n"
271"2:	.word	.			\n"
272"	.word	fabric_phys_addr	\n"
273	);
274}
275
276static 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,
281};
282
283static bool __init hip04_cpu_table_init(void)
284{
285	unsigned int mpidr, cpu, cluster;
286
287	mpidr = read_cpuid_mpidr();
288	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
289	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
290
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__);
294		return false;
295	}
296	hip04_set_snoop_filter(cluster, 1);
297	hip04_cpu_table[cluster][cpu] = 1;
298	return true;
299}
300
301static int __init hip04_mcpm_init(void)
302{
303	struct device_node *np, *np_sctl, *np_fab;
304	struct resource fab_res;
305	void __iomem *relocation;
306	int ret = -ENODEV;
307
308	np = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-bootwrapper");
309	if (!np)
310		goto err;
311	ret = of_property_read_u32_array(np, "boot-method",
312					 &hip04_boot_method[0], 4);
313	if (ret)
314		goto err;
315	np_sctl = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
316	if (!np_sctl)
317		goto err;
318	np_fab = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-fabric");
319	if (!np_fab)
320		goto err;
321
322	ret = memblock_reserve(hip04_boot_method[0], hip04_boot_method[1]);
323	if (ret)
324		goto err;
325
326	relocation = ioremap(hip04_boot_method[2], hip04_boot_method[3]);
327	if (!relocation) {
328		pr_err("failed to map relocation space\n");
329		ret = -ENOMEM;
330		goto err_reloc;
331	}
332	sysctrl = of_iomap(np_sctl, 0);
333	if (!sysctrl) {
334		pr_err("failed to get sysctrl base\n");
335		ret = -ENOMEM;
336		goto err_sysctrl;
337	}
338	ret = of_address_to_resource(np_fab, 0, &fab_res);
339	if (ret) {
340		pr_err("failed to get fabric base phys\n");
341		goto err_fabric;
342	}
343	fabric_phys_addr = fab_res.start;
344	sync_cache_w(&fabric_phys_addr);
345	fabric = of_iomap(np_fab, 0);
346	if (!fabric) {
347		pr_err("failed to get fabric base\n");
348		ret = -ENOMEM;
349		goto err_fabric;
350	}
351
352	if (!hip04_cpu_table_init()) {
353		ret = -EINVAL;
354		goto err_table;
355	}
356	ret = mcpm_platform_register(&hip04_mcpm_ops);
357	if (ret) {
358		goto err_table;
359	}
360
361	/*
362	 * Fill the instruction address that is used after secondary core
363	 * out of reset.
364	 */
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);
369	iounmap(relocation);
370
371	mcpm_sync_init(hip04_mcpm_power_up_setup);
372	mcpm_smp_set_ops();
373	pr_info("HiP04 MCPM initialized\n");
374	return ret;
375err_table:
376	iounmap(fabric);
377err_fabric:
378	iounmap(sysctrl);
379err_sysctrl:
380	iounmap(relocation);
381err_reloc:
382	memblock_free(hip04_boot_method[0], hip04_boot_method[1]);
383err:
384	return ret;
385}
386early_initcall(hip04_mcpm_init);
387