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