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