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 Courbotstatic 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 Courbotstatic 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 Schrijvervoid __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