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 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 #if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE)
tegra_pmc_detect_tz_only(void)19 static 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 
tegra_pmc_readl(unsigned long offset)52 uint32_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 
tegra_pmc_writel(u32 value,unsigned long offset)70 void 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 
reset_cpu(void)88 void reset_cpu(void)
89 {
90 	u32 value;
91 
92 	value = tegra_pmc_readl(PMC_CNTRL);
93 	value |= PMC_CNTRL_MAIN_RST;
94 	tegra_pmc_writel(value, PMC_CNTRL);
95 }
96