xref: /openbmc/linux/arch/arm/mach-tegra/reset.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b36ab975SPeter De Schrijver /*
3b36ab975SPeter De Schrijver  * arch/arm/mach-tegra/reset.c
4b36ab975SPeter De Schrijver  *
5b36ab975SPeter De Schrijver  * Copyright (C) 2011,2012 NVIDIA Corporation.
6b36ab975SPeter De Schrijver  */
7b36ab975SPeter De Schrijver 
8a0524accSThierry Reding #include <linux/bitops.h>
9a0524accSThierry Reding #include <linux/cpumask.h>
10b36ab975SPeter De Schrijver #include <linux/init.h>
11b36ab975SPeter De Schrijver #include <linux/io.h>
12b36ab975SPeter De Schrijver 
134cb5d9ecSThierry Reding #include <linux/firmware/trusted_foundations.h>
144cb5d9ecSThierry Reding 
15304664eaSThierry Reding #include <soc/tegra/fuse.h>
16304664eaSThierry Reding 
17b36ab975SPeter De Schrijver #include <asm/cacheflush.h>
18265c89c9SAlexandre Courbot #include <asm/firmware.h>
19a0524accSThierry Reding #include <asm/hardware/cache-l2x0.h>
20b36ab975SPeter De Schrijver 
212be39c07SStephen Warren #include "iomap.h"
22bb1de887SStephen Warren #include "irammap.h"
23b36ab975SPeter De Schrijver #include "reset.h"
24d3f29365SJoseph Lo #include "sleep.h"
25b36ab975SPeter De Schrijver 
26b36ab975SPeter De Schrijver #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
27b36ab975SPeter De Schrijver 				TEGRA_IRAM_RESET_HANDLER_OFFSET)
28b36ab975SPeter De Schrijver 
29b36ab975SPeter De Schrijver static bool is_enabled;
30b36ab975SPeter De Schrijver 
tegra_cpu_reset_handler_set(const u32 reset_address)31ad14eceeSAlexandre Courbot static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
32b36ab975SPeter De Schrijver {
33b36ab975SPeter De Schrijver 	void __iomem *evp_cpu_reset =
34b36ab975SPeter De Schrijver 		IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100);
35b36ab975SPeter De Schrijver 	void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE);
36b36ab975SPeter De Schrijver 	u32 reg;
37b36ab975SPeter De Schrijver 
38b36ab975SPeter De Schrijver 	/*
39b36ab975SPeter De Schrijver 	 * NOTE: This must be the one and only write to the EVP CPU reset
40b36ab975SPeter De Schrijver 	 *       vector in the entire system.
41b36ab975SPeter De Schrijver 	 */
42ad14eceeSAlexandre Courbot 	writel(reset_address, evp_cpu_reset);
43b36ab975SPeter De Schrijver 	wmb();
44b36ab975SPeter De Schrijver 	reg = readl(evp_cpu_reset);
45b36ab975SPeter De Schrijver 
46b36ab975SPeter De Schrijver 	/*
47b36ab975SPeter De Schrijver 	 * Prevent further modifications to the physical reset vector.
48b36ab975SPeter De Schrijver 	 *  NOTE: Has no effect on chips prior to Tegra30.
49b36ab975SPeter De Schrijver 	 */
50b36ab975SPeter De Schrijver 	reg = readl(sb_ctrl);
51b36ab975SPeter De Schrijver 	reg |= 2;
52b36ab975SPeter De Schrijver 	writel(reg, sb_ctrl);
53b36ab975SPeter De Schrijver 	wmb();
54b36ab975SPeter De Schrijver }
55ad14eceeSAlexandre Courbot 
tegra_cpu_reset_handler_enable(void)56ad14eceeSAlexandre Courbot static void __init tegra_cpu_reset_handler_enable(void)
57ad14eceeSAlexandre Courbot {
58ad14eceeSAlexandre Courbot 	void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE);
59ad14eceeSAlexandre Courbot 	const u32 reset_address = TEGRA_IRAM_RESET_BASE +
60ad14eceeSAlexandre Courbot 						tegra_cpu_reset_handler_offset;
61265c89c9SAlexandre Courbot 	int err;
62ad14eceeSAlexandre Courbot 
63ad14eceeSAlexandre Courbot 	BUG_ON(is_enabled);
64ad14eceeSAlexandre Courbot 	BUG_ON(tegra_cpu_reset_handler_size > TEGRA_IRAM_RESET_HANDLER_SIZE);
65ad14eceeSAlexandre Courbot 
66ad14eceeSAlexandre Courbot 	memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start,
67ad14eceeSAlexandre Courbot 			tegra_cpu_reset_handler_size);
68ad14eceeSAlexandre Courbot 
69265c89c9SAlexandre Courbot 	err = call_firmware_op(set_cpu_boot_addr, 0, reset_address);
70265c89c9SAlexandre Courbot 	switch (err) {
71265c89c9SAlexandre Courbot 	case -ENOSYS:
72ad14eceeSAlexandre Courbot 		tegra_cpu_reset_handler_set(reset_address);
73*df561f66SGustavo A. R. Silva 		fallthrough;
74265c89c9SAlexandre Courbot 	case 0:
75b36ab975SPeter De Schrijver 		is_enabled = true;
76265c89c9SAlexandre Courbot 		break;
77265c89c9SAlexandre Courbot 	default:
78265c89c9SAlexandre Courbot 		pr_crit("Cannot set CPU reset handler: %d\n", err);
79265c89c9SAlexandre Courbot 		BUG();
80265c89c9SAlexandre Courbot 	}
81b36ab975SPeter De Schrijver }
82b36ab975SPeter De Schrijver 
tegra_cpu_reset_handler_init(void)83b36ab975SPeter De Schrijver void __init tegra_cpu_reset_handler_init(void)
84b36ab975SPeter De Schrijver {
852af6597aSDmitry Osipenko 	__tegra_cpu_reset_handler_data[TEGRA_RESET_TF_PRESENT] =
862af6597aSDmitry Osipenko 		trusted_foundations_registered();
87b36ab975SPeter De Schrijver 
88b36ab975SPeter De Schrijver #ifdef CONFIG_SMP
89b36ab975SPeter De Schrijver 	__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
909e32366fSJoseph Lo 		*((u32 *)cpu_possible_mask);
91b36ab975SPeter De Schrijver 	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
9264fc2a94SFlorian Fainelli 		__pa_symbol((void *)secondary_startup);
93b36ab975SPeter De Schrijver #endif
94b36ab975SPeter De Schrijver 
95d3f29365SJoseph Lo #ifdef CONFIG_PM_SLEEP
965b795d05SJoseph Lo 	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP1] =
97fddb770dSStephen Warren 		TEGRA_IRAM_LPx_RESUME_AREA;
98d3f29365SJoseph Lo 	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] =
9964fc2a94SFlorian Fainelli 		__pa_symbol((void *)tegra_resume);
100d3f29365SJoseph Lo #endif
101d3f29365SJoseph Lo 
102b36ab975SPeter De Schrijver 	tegra_cpu_reset_handler_enable();
103b36ab975SPeter De Schrijver }
104