linux/arch/arm/mach-tegra/reset.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * arch/arm/mach-tegra/reset.c
   4 *
   5 * Copyright (C) 2011,2012 NVIDIA Corporation.
   6 */
   7
   8#include <linux/bitops.h>
   9#include <linux/cpumask.h>
  10#include <linux/init.h>
  11#include <linux/io.h>
  12
  13#include <linux/firmware/trusted_foundations.h>
  14
  15#include <soc/tegra/fuse.h>
  16
  17#include <asm/cacheflush.h>
  18#include <asm/firmware.h>
  19#include <asm/hardware/cache-l2x0.h>
  20
  21#include "iomap.h"
  22#include "irammap.h"
  23#include "reset.h"
  24#include "sleep.h"
  25
  26#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
  27                                TEGRA_IRAM_RESET_HANDLER_OFFSET)
  28
  29static bool is_enabled;
  30
  31static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
  32{
  33        void __iomem *evp_cpu_reset =
  34                IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100);
  35        void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE);
  36        u32 reg;
  37
  38        /*
  39         * NOTE: This must be the one and only write to the EVP CPU reset
  40         *       vector in the entire system.
  41         */
  42        writel(reset_address, evp_cpu_reset);
  43        wmb();
  44        reg = readl(evp_cpu_reset);
  45
  46        /*
  47         * Prevent further modifications to the physical reset vector.
  48         *  NOTE: Has no effect on chips prior to Tegra30.
  49         */
  50        reg = readl(sb_ctrl);
  51        reg |= 2;
  52        writel(reg, sb_ctrl);
  53        wmb();
  54}
  55
  56static void __init tegra_cpu_reset_handler_enable(void)
  57{
  58        void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE);
  59        const u32 reset_address = TEGRA_IRAM_RESET_BASE +
  60                                                tegra_cpu_reset_handler_offset;
  61        int err;
  62
  63        BUG_ON(is_enabled);
  64        BUG_ON(tegra_cpu_reset_handler_size > TEGRA_IRAM_RESET_HANDLER_SIZE);
  65
  66        memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start,
  67                        tegra_cpu_reset_handler_size);
  68
  69        err = call_firmware_op(set_cpu_boot_addr, 0, reset_address);
  70        switch (err) {
  71        case -ENOSYS:
  72                tegra_cpu_reset_handler_set(reset_address);
  73                /* fall through */
  74        case 0:
  75                is_enabled = true;
  76                break;
  77        default:
  78                pr_crit("Cannot set CPU reset handler: %d\n", err);
  79                BUG();
  80        }
  81}
  82
  83void __init tegra_cpu_reset_handler_init(void)
  84{
  85        __tegra_cpu_reset_handler_data[TEGRA_RESET_TF_PRESENT] =
  86                trusted_foundations_registered();
  87
  88#ifdef CONFIG_SMP
  89        __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
  90                *((u32 *)cpu_possible_mask);
  91        __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
  92                __pa_symbol((void *)secondary_startup);
  93#endif
  94
  95#ifdef CONFIG_PM_SLEEP
  96        __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP1] =
  97                TEGRA_IRAM_LPx_RESUME_AREA;
  98        __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] =
  99                __pa_symbol((void *)tegra_resume);
 100#endif
 101
 102        tegra_cpu_reset_handler_enable();
 103}
 104