uboot/arch/arm/mach-tegra/pmc.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
   4 */
   5
   6#include <common.h>
   7
   8#include <linux/arm-smccc.h>
   9
  10#include <asm/io.h>
  11#include <asm/arch-tegra/pmc.h>
  12
  13DECLARE_GLOBAL_DATA_PTR;
  14
  15#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
  16static bool tegra_pmc_detect_tz_only(void)
  17{
  18        static bool initialized = false;
  19        static bool is_tz_only = false;
  20        u32 value, saved;
  21
  22        if (!initialized) {
  23                saved = readl(NV_PA_PMC_BASE + PMC_SCRATCH0);
  24                value = saved ^ 0xffffffff;
  25
  26                if (value == 0xffffffff)
  27                        value = 0xdeadbeef;
  28
  29                /* write pattern and read it back */
  30                writel(value, NV_PA_PMC_BASE + PMC_SCRATCH0);
  31                value = readl(NV_PA_PMC_BASE + PMC_SCRATCH0);
  32
  33                /* if we read all-zeroes, access is restricted to TZ only */
  34                if (value == 0) {
  35                        debug("access to PMC is restricted to TZ\n");
  36                        is_tz_only = true;
  37                } else {
  38                        /* restore original value */
  39                        writel(saved, NV_PA_PMC_BASE + PMC_SCRATCH0);
  40                }
  41
  42                initialized = true;
  43        }
  44
  45        return is_tz_only;
  46}
  47#endif
  48
  49uint32_t tegra_pmc_readl(unsigned long offset)
  50{
  51#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
  52        if (tegra_pmc_detect_tz_only()) {
  53                struct arm_smccc_res res;
  54
  55                arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0,
  56                              0, 0, 0, &res);
  57                if (res.a0)
  58                        printf("%s(): SMC failed: %lu\n", __func__, res.a0);
  59
  60                return res.a1;
  61        }
  62#endif
  63
  64        return readl(NV_PA_PMC_BASE + offset);
  65}
  66
  67void tegra_pmc_writel(u32 value, unsigned long offset)
  68{
  69#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
  70        if (tegra_pmc_detect_tz_only()) {
  71                struct arm_smccc_res res;
  72
  73                arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset,
  74                              value, 0, 0, 0, 0, &res);
  75                if (res.a0)
  76                        printf("%s(): SMC failed: %lu\n", __func__, res.a0);
  77
  78                return;
  79        }
  80#endif
  81
  82        writel(value, NV_PA_PMC_BASE + offset);
  83}
  84
  85void reset_cpu(ulong addr)
  86{
  87        u32 value;
  88
  89        value = tegra_pmc_readl(PMC_CNTRL);
  90        value |= PMC_CNTRL_MAIN_RST;
  91        tegra_pmc_writel(value, PMC_CNTRL);
  92}
  93