1/*
2 * Copyright 2014 Linaro Ltd.
3 * Copyright (C) 2014 ZTE Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/delay.h>
11#include <linux/errno.h>
12#include <linux/init.h>
13#include <linux/io.h>
14#include <linux/jiffies.h>
15#include <linux/of.h>
16#include <linux/of_address.h>
17#include <linux/smp.h>
18
19#include <asm/cacheflush.h>
20#include <asm/cp15.h>
21#include <asm/fncpy.h>
22#include <asm/proc-fns.h>
23#include <asm/smp_scu.h>
24#include <asm/smp_plat.h>
25
26#include "core.h"
27
28#define AON_SYS_CTRL_RESERVED1		0xa8
29
30#define BUS_MATRIX_REMAP_CONFIG		0x00
31
32#define PCU_CPU0_CTRL			0x00
33#define PCU_CPU1_CTRL			0x04
34#define PCU_CPU1_ST			0x0c
35#define PCU_GLOBAL_CTRL			0x14
36#define PCU_EXPEND_CONTROL		0x34
37
38#define ZX_IRAM_BASE			0x00200000
39
40static void __iomem *pcu_base;
41static void __iomem *matrix_base;
42static void __iomem *scu_base;
43
44void __init zx_smp_prepare_cpus(unsigned int max_cpus)
45{
46	struct device_node *np;
47	unsigned long base = 0;
48	void __iomem *aonsysctrl_base;
49	void __iomem *sys_iram;
50
51	base = scu_a9_get_base();
52	scu_base = ioremap(base, SZ_256);
53	if (!scu_base) {
54		pr_err("%s: failed to map scu\n", __func__);
55		return;
56	}
57
58	scu_enable(scu_base);
59
60	np = of_find_compatible_node(NULL, NULL, "zte,sysctrl");
61	if (!np) {
62		pr_err("%s: failed to find sysctrl node\n", __func__);
63		return;
64	}
65
66	aonsysctrl_base = of_iomap(np, 0);
67	if (!aonsysctrl_base) {
68		pr_err("%s: failed to map aonsysctrl\n", __func__);
69		of_node_put(np);
70		return;
71	}
72
73	/*
74	 * Write the address of secondary startup into the
75	 * system-wide flags register. The BootMonitor waits
76	 * until it receives a soft interrupt, and then the
77	 * secondary CPU branches to this address.
78	 */
79	__raw_writel(virt_to_phys(zx_secondary_startup),
80		     aonsysctrl_base + AON_SYS_CTRL_RESERVED1);
81
82	iounmap(aonsysctrl_base);
83	of_node_put(np);
84
85	np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu");
86	pcu_base = of_iomap(np, 0);
87	of_node_put(np);
88	WARN_ON(!pcu_base);
89
90	np = of_find_compatible_node(NULL, NULL, "zte,zx-bus-matrix");
91	matrix_base = of_iomap(np, 0);
92	of_node_put(np);
93	WARN_ON(!matrix_base);
94
95	/* Map the first 4 KB IRAM for suspend usage */
96	sys_iram = __arm_ioremap_exec(ZX_IRAM_BASE, PAGE_SIZE, false);
97	zx_secondary_startup_pa = virt_to_phys(zx_secondary_startup);
98	fncpy(sys_iram, &zx_resume_jump, zx_suspend_iram_sz);
99}
100
101static int zx_boot_secondary(unsigned int cpu, struct task_struct *idle)
102{
103	static bool first_boot = true;
104
105	if (first_boot) {
106		arch_send_wakeup_ipi_mask(cpumask_of(cpu));
107		first_boot = false;
108		return 0;
109	}
110
111	/* Swap the base address mapping between IRAM and IROM */
112	writel_relaxed(0x1, matrix_base + BUS_MATRIX_REMAP_CONFIG);
113
114	/* Power on CPU1 */
115	writel_relaxed(0x0, pcu_base + PCU_CPU1_CTRL);
116
117	/* Wait for power on ack */
118	while (readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x4)
119		cpu_relax();
120
121	/* Swap back the mapping of IRAM and IROM */
122	writel_relaxed(0x0, matrix_base + BUS_MATRIX_REMAP_CONFIG);
123
124	return 0;
125}
126
127#ifdef CONFIG_HOTPLUG_CPU
128static inline void cpu_enter_lowpower(void)
129{
130	unsigned int v;
131
132	asm volatile(
133		"mcr	p15, 0, %1, c7, c5, 0\n"
134	"	mcr	p15, 0, %1, c7, c10, 4\n"
135	/*
136	 * Turn off coherency
137	 */
138	"	mrc	p15, 0, %0, c1, c0, 1\n"
139	"	bic	%0, %0, %3\n"
140	"	mcr	p15, 0, %0, c1, c0, 1\n"
141	"	mrc	p15, 0, %0, c1, c0, 0\n"
142	"	bic	%0, %0, %2\n"
143	"	mcr	p15, 0, %0, c1, c0, 0\n"
144	  : "=&r" (v)
145	  : "r" (0), "Ir" (CR_C), "Ir" (0x40)
146	  : "cc");
147}
148
149static int zx_cpu_kill(unsigned int cpu)
150{
151	unsigned long timeout = jiffies + msecs_to_jiffies(2000);
152
153	writel_relaxed(0x2, pcu_base + PCU_CPU1_CTRL);
154
155	while ((readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x3) != 0x0) {
156		if (time_after(jiffies, timeout)) {
157			pr_err("*** cpu1 poweroff timeout\n");
158			break;
159		}
160	}
161	return 1;
162}
163
164static void zx_cpu_die(unsigned int cpu)
165{
166	scu_power_mode(scu_base, SCU_PM_POWEROFF);
167	cpu_enter_lowpower();
168
169	while (1)
170		cpu_do_idle();
171}
172#endif
173
174static void zx_secondary_init(unsigned int cpu)
175{
176	scu_power_mode(scu_base, SCU_PM_NORMAL);
177}
178
179struct smp_operations zx_smp_ops __initdata = {
180	.smp_prepare_cpus	= zx_smp_prepare_cpus,
181	.smp_secondary_init	= zx_secondary_init,
182	.smp_boot_secondary	= zx_boot_secondary,
183#ifdef CONFIG_HOTPLUG_CPU
184	.cpu_kill		= zx_cpu_kill,
185	.cpu_die		= zx_cpu_die,
186#endif
187};
188
189CPU_METHOD_OF_DECLARE(zx_smp, "zte,zx296702-smp", &zx_smp_ops);
190