xref: /OK3568_Linux_fs/kernel/arch/arm/mach-exynos/firmware.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright (C) 2012 Samsung Electronics.
4*4882a593Smuzhiyun // Kyungmin Park <kyungmin.park@samsung.com>
5*4882a593Smuzhiyun // Tomasz Figa <t.figa@samsung.com>
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/io.h>
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/of.h>
11*4882a593Smuzhiyun #include <linux/of_address.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <asm/cacheflush.h>
14*4882a593Smuzhiyun #include <asm/cputype.h>
15*4882a593Smuzhiyun #include <asm/firmware.h>
16*4882a593Smuzhiyun #include <asm/hardware/cache-l2x0.h>
17*4882a593Smuzhiyun #include <asm/suspend.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "common.h"
20*4882a593Smuzhiyun #include "smc.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define EXYNOS_BOOT_ADDR	0x8
23*4882a593Smuzhiyun #define EXYNOS_BOOT_FLAG	0xc
24*4882a593Smuzhiyun 
exynos_save_cp15(void)25*4882a593Smuzhiyun static void exynos_save_cp15(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	/* Save Power control and Diagnostic registers */
28*4882a593Smuzhiyun 	asm ("mrc p15, 0, %0, c15, c0, 0\n"
29*4882a593Smuzhiyun 	     "mrc p15, 0, %1, c15, c0, 1\n"
30*4882a593Smuzhiyun 	     : "=r" (cp15_save_power), "=r" (cp15_save_diag)
31*4882a593Smuzhiyun 	     : : "cc");
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun 
exynos_do_idle(unsigned long mode)34*4882a593Smuzhiyun static int exynos_do_idle(unsigned long mode)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	switch (mode) {
37*4882a593Smuzhiyun 	case FW_DO_IDLE_AFTR:
38*4882a593Smuzhiyun 		if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
39*4882a593Smuzhiyun 			exynos_save_cp15();
40*4882a593Smuzhiyun 		writel_relaxed(__pa_symbol(exynos_cpu_resume_ns),
41*4882a593Smuzhiyun 			       sysram_ns_base_addr + 0x24);
42*4882a593Smuzhiyun 		writel_relaxed(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
43*4882a593Smuzhiyun 		if (soc_is_exynos3250()) {
44*4882a593Smuzhiyun 			flush_cache_all();
45*4882a593Smuzhiyun 			exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE,
46*4882a593Smuzhiyun 				   SMC_POWERSTATE_IDLE, 0);
47*4882a593Smuzhiyun 			exynos_smc(SMC_CMD_SHUTDOWN, OP_TYPE_CLUSTER,
48*4882a593Smuzhiyun 				   SMC_POWERSTATE_IDLE, 0);
49*4882a593Smuzhiyun 		} else
50*4882a593Smuzhiyun 			exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0);
51*4882a593Smuzhiyun 		break;
52*4882a593Smuzhiyun 	case FW_DO_IDLE_SLEEP:
53*4882a593Smuzhiyun 		exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
exynos_cpu_boot(int cpu)58*4882a593Smuzhiyun static int exynos_cpu_boot(int cpu)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	/*
61*4882a593Smuzhiyun 	 * Exynos3250 doesn't need to send smc command for secondary CPU boot
62*4882a593Smuzhiyun 	 * because Exynos3250 removes WFE in secure mode.
63*4882a593Smuzhiyun 	 */
64*4882a593Smuzhiyun 	if (soc_is_exynos3250())
65*4882a593Smuzhiyun 		return 0;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	/*
68*4882a593Smuzhiyun 	 * The second parameter of SMC_CMD_CPU1BOOT command means CPU id.
69*4882a593Smuzhiyun 	 */
70*4882a593Smuzhiyun 	exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0);
71*4882a593Smuzhiyun 	return 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
exynos_set_cpu_boot_addr(int cpu,unsigned long boot_addr)74*4882a593Smuzhiyun static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	void __iomem *boot_reg;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (!sysram_ns_base_addr)
79*4882a593Smuzhiyun 		return -ENODEV;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	boot_reg = sysram_ns_base_addr + 0x1c;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/*
84*4882a593Smuzhiyun 	 * Almost all Exynos-series of SoCs that run in secure mode don't need
85*4882a593Smuzhiyun 	 * additional offset for every CPU, with Exynos4412 being the only
86*4882a593Smuzhiyun 	 * exception.
87*4882a593Smuzhiyun 	 */
88*4882a593Smuzhiyun 	if (soc_is_exynos4412())
89*4882a593Smuzhiyun 		boot_reg += 4 * cpu;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	writel_relaxed(boot_addr, boot_reg);
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
exynos_get_cpu_boot_addr(int cpu,unsigned long * boot_addr)95*4882a593Smuzhiyun static int exynos_get_cpu_boot_addr(int cpu, unsigned long *boot_addr)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	void __iomem *boot_reg;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (!sysram_ns_base_addr)
100*4882a593Smuzhiyun 		return -ENODEV;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	boot_reg = sysram_ns_base_addr + 0x1c;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (soc_is_exynos4412())
105*4882a593Smuzhiyun 		boot_reg += 4 * cpu;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	*boot_addr = readl_relaxed(boot_reg);
108*4882a593Smuzhiyun 	return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
exynos_cpu_suspend(unsigned long arg)111*4882a593Smuzhiyun static int exynos_cpu_suspend(unsigned long arg)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	flush_cache_all();
114*4882a593Smuzhiyun 	outer_flush_all();
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	pr_info("Failed to suspend the system\n");
119*4882a593Smuzhiyun 	writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
120*4882a593Smuzhiyun 	return 1;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
exynos_suspend(void)123*4882a593Smuzhiyun static int exynos_suspend(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
126*4882a593Smuzhiyun 		exynos_save_cp15();
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
129*4882a593Smuzhiyun 	writel(__pa_symbol(exynos_cpu_resume_ns),
130*4882a593Smuzhiyun 		sysram_ns_base_addr + EXYNOS_BOOT_ADDR);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return cpu_suspend(0, exynos_cpu_suspend);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
exynos_resume(void)135*4882a593Smuzhiyun static int exynos_resume(void)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun static const struct firmware_ops exynos_firmware_ops = {
143*4882a593Smuzhiyun 	.do_idle		= IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL,
144*4882a593Smuzhiyun 	.set_cpu_boot_addr	= exynos_set_cpu_boot_addr,
145*4882a593Smuzhiyun 	.get_cpu_boot_addr	= exynos_get_cpu_boot_addr,
146*4882a593Smuzhiyun 	.cpu_boot		= exynos_cpu_boot,
147*4882a593Smuzhiyun 	.suspend		= IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL,
148*4882a593Smuzhiyun 	.resume			= IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
exynos_l2_write_sec(unsigned long val,unsigned reg)151*4882a593Smuzhiyun static void exynos_l2_write_sec(unsigned long val, unsigned reg)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	static int l2cache_enabled;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	switch (reg) {
156*4882a593Smuzhiyun 	case L2X0_CTRL:
157*4882a593Smuzhiyun 		if (val & L2X0_CTRL_EN) {
158*4882a593Smuzhiyun 			/*
159*4882a593Smuzhiyun 			 * Before the cache can be enabled, due to firmware
160*4882a593Smuzhiyun 			 * design, SMC_CMD_L2X0INVALL must be called.
161*4882a593Smuzhiyun 			 */
162*4882a593Smuzhiyun 			if (!l2cache_enabled) {
163*4882a593Smuzhiyun 				exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0);
164*4882a593Smuzhiyun 				l2cache_enabled = 1;
165*4882a593Smuzhiyun 			}
166*4882a593Smuzhiyun 		} else {
167*4882a593Smuzhiyun 			l2cache_enabled = 0;
168*4882a593Smuzhiyun 		}
169*4882a593Smuzhiyun 		exynos_smc(SMC_CMD_L2X0CTRL, val, 0, 0);
170*4882a593Smuzhiyun 		break;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	case L2X0_DEBUG_CTRL:
173*4882a593Smuzhiyun 		exynos_smc(SMC_CMD_L2X0DEBUG, val, 0, 0);
174*4882a593Smuzhiyun 		break;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	default:
177*4882a593Smuzhiyun 		WARN_ONCE(1, "%s: ignoring write to reg 0x%x\n", __func__, reg);
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
exynos_l2_configure(const struct l2x0_regs * regs)181*4882a593Smuzhiyun static void exynos_l2_configure(const struct l2x0_regs *regs)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	exynos_smc(SMC_CMD_L2X0SETUP1, regs->tag_latency, regs->data_latency,
184*4882a593Smuzhiyun 		   regs->prefetch_ctrl);
185*4882a593Smuzhiyun 	exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
exynos_secure_firmware_available(void)188*4882a593Smuzhiyun bool __init exynos_secure_firmware_available(void)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	struct device_node *nd;
191*4882a593Smuzhiyun 	const __be32 *addr;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	nd = of_find_compatible_node(NULL, NULL,
194*4882a593Smuzhiyun 					"samsung,secure-firmware");
195*4882a593Smuzhiyun 	if (!nd)
196*4882a593Smuzhiyun 		return false;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	addr = of_get_address(nd, 0, NULL, NULL);
199*4882a593Smuzhiyun 	of_node_put(nd);
200*4882a593Smuzhiyun 	if (!addr) {
201*4882a593Smuzhiyun 		pr_err("%s: No address specified.\n", __func__);
202*4882a593Smuzhiyun 		return false;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return true;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
exynos_firmware_init(void)208*4882a593Smuzhiyun void __init exynos_firmware_init(void)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	if (!exynos_secure_firmware_available())
211*4882a593Smuzhiyun 		return;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	pr_info("Running under secure firmware.\n");
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	register_firmware_ops(&exynos_firmware_ops);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/*
218*4882a593Smuzhiyun 	 * Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310),
219*4882a593Smuzhiyun 	 * running under secure firmware, require certain registers of L2
220*4882a593Smuzhiyun 	 * cache controller to be written in secure mode. Here .write_sec
221*4882a593Smuzhiyun 	 * callback is provided to perform necessary SMC calls.
222*4882a593Smuzhiyun 	 */
223*4882a593Smuzhiyun 	if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
224*4882a593Smuzhiyun 	    read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
225*4882a593Smuzhiyun 		outer_cache.write_sec = exynos_l2_write_sec;
226*4882a593Smuzhiyun 		outer_cache.configure = exynos_l2_configure;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun #define REG_CPU_STATE_ADDR	(sysram_ns_base_addr + 0x28)
231*4882a593Smuzhiyun #define BOOT_MODE_MASK		0x1f
232*4882a593Smuzhiyun 
exynos_set_boot_flag(unsigned int cpu,unsigned int mode)233*4882a593Smuzhiyun void exynos_set_boot_flag(unsigned int cpu, unsigned int mode)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	unsigned int tmp;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	tmp = readl_relaxed(REG_CPU_STATE_ADDR + cpu * 4);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (mode & BOOT_MODE_MASK)
240*4882a593Smuzhiyun 		tmp &= ~BOOT_MODE_MASK;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	tmp |= mode;
243*4882a593Smuzhiyun 	writel_relaxed(tmp, REG_CPU_STATE_ADDR + cpu * 4);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
exynos_clear_boot_flag(unsigned int cpu,unsigned int mode)246*4882a593Smuzhiyun void exynos_clear_boot_flag(unsigned int cpu, unsigned int mode)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	unsigned int tmp;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	tmp = readl_relaxed(REG_CPU_STATE_ADDR + cpu * 4);
251*4882a593Smuzhiyun 	tmp &= ~mode;
252*4882a593Smuzhiyun 	writel_relaxed(tmp, REG_CPU_STATE_ADDR + cpu * 4);
253*4882a593Smuzhiyun }
254