First version
[3rdparty/ote_partner/tlk.git] / platform / tegra / monitor / psci.c
1 /*
2  * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 #include <stdlib.h>
25 #include <err.h>
26 #include <debug.h>
27 #include <platform.h>
28 #include <platform/memmap.h>
29 #include <reg.h>
30 #include <string.h>
31 #include <psci.h>
32 #include <target/debugconfig.h>
33 #include <platform/platform_p.h>
34 #include <lib/monitor/monitor_vector.h>
35
36 /* referenced APBDEV_PMC_SECURE registers */
37 #define MC_SECURITY_CFG1_0              0x74
38
39 #define PMC_SECURE_DISABLE2             0x2c4
40 #define PMC_SECURE_DISABLE2_WRITE22_ON  (1 << 28)
41 #define PMC_SECURE_SCRATCH22            0x338
42
43 #define EVP_CPU_RESET_VECTOR            0x100
44
45 #define SB_CSR                          0x0
46 #define SB_CSR_NS_RST_VEC_WR_DIS        (1 << 1)
47
48 static volatile uint32_t cpus_started;
49 static const uint32_t cpus_expected = ((1 << MONCPUS) - 1);
50
51 /* sets of MMIO ranges setup */
52 #define MMIO_RANGE_0_ADDR       0x50000000
53 #define MMIO_RANGE_1_ADDR       0x60000000
54 #define MMIO_RANGE_2_ADDR       0x70000000
55 #define MMIO_RANGE_SIZE         0x200000
56
57 static void psci_program_reset_vectors()
58 {
59         uint64_t phys_cpu_reset;
60         uint32_t reg;
61
62         phys_cpu_reset = mon_virt_to_phys(&__mon_cpu_reset_vector);
63
64         /* set exception vector (read to flush) */
65         writel(phys_cpu_reset, TEGRA_EXCEPTION_VECTORS_BASE + EVP_CPU_RESET_VECTOR);
66         (void)readl(TEGRA_EXCEPTION_VECTORS_BASE + EVP_CPU_RESET_VECTOR);
67
68         /* ensure SECURE_SCRATCH22 is write locked */
69         reg  = readl(TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);
70         reg |= PMC_SECURE_DISABLE2_WRITE22_ON;
71         writel(reg, TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);      /* lock */
72
73         /* set secure boot control (read to flush) */
74         reg  = readl(TEGRA_SB_BASE + SB_CSR);
75         reg |= SB_CSR_NS_RST_VEC_WR_DIS;
76         writel(reg, TEGRA_SB_BASE + SB_CSR);
77         (void)readl(TEGRA_SB_BASE + SB_CSR);
78 }
79
80 /*
81  * One-time init called during cold boot from primary CPU
82  */
83 void platform_psci_init(uint32_t cpu)
84 {
85         uint64_t phys_cpu_reset;
86         uint32_t reg;
87
88         /* identity map MMIO ranges for register access */
89         (void) mon_mmu_map_mmio(MMIO_RANGE_0_ADDR, MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE);
90         (void) mon_mmu_map_mmio(MMIO_RANGE_1_ADDR, MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE);
91         (void) mon_mmu_map_mmio(MMIO_RANGE_2_ADDR, MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE);
92
93         platform_init_debug_port(DEFAULT_DEBUG_PORT);
94
95         reg  = readl(TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);
96         reg &= ~PMC_SECURE_DISABLE2_WRITE22_ON;
97         writel(reg, TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);      /* unlock */
98
99         phys_cpu_reset = mon_virt_to_phys(&__mon_cpu_reset_vector);
100         writel(phys_cpu_reset, TEGRA_PMC_BASE + PMC_SECURE_SCRATCH22);
101
102         reg  = readl(TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);
103         reg |= PMC_SECURE_DISABLE2_WRITE22_ON;
104         writel(reg, TEGRA_PMC_BASE + PMC_SECURE_DISABLE2);      /* lock */
105
106         mon_atomic_or(&cpus_started, 1 << cpu);
107
108         platform_init_memory(__mon_phys_base, __mon_phys_size);
109         platform_config_interrupts();
110 }
111
112 /*
113  * One time init call during end of cold boot from primary CPU
114  */
115 void platform_psci_coldboot_epilog()
116 {
117         /* mark entire TLK carveout as secure in the MC */
118         platform_secure_dram_aperture();
119
120         /* make sure all CPUs have reset before reprogramming vector */
121         while (cpus_started != cpus_expected)
122                 ;
123
124         psci_program_reset_vectors();
125 }
126
127 /*
128  * Routine is called when a CPU goes through reset, either a secondary
129  * CPU during cold boot, or all CPUs during system suspend.
130  */
131 void platform_psci_cpu_has_reset(uint32_t cpu)
132 {
133         uint32_t reg;
134
135         mon_atomic_or(&cpus_started, 1 << cpu);
136
137         /*
138          * Opportunity to do an per-CPU setup after reset. For now, only
139          * restores global state, so just run on the primary (CPU0).
140          */
141         if (cpu != 0)
142                 return;
143
144         /*
145          * Avoid relying on having seen an LP0 enter SMC.
146          *
147          * If MC_SECURITY_CFG1 has gone back zero (its POR value) then LP0
148          * has occurred (as it's not part of BL's warmboot restore) and system
149          * registers need to be reloaded.
150          */
151         reg = readl(TEGRA_MC_BASE + MC_SECURITY_CFG1_0);
152         if (reg == (__mon_phys_size >> 20))
153                 return;
154
155         psci_program_reset_vectors();
156         platform_restore_memory();
157         platform_config_interrupts();
158 }
159
160 int platform_psci_handler(struct psci_frame *frame, uint32_t cpu)
161 {
162         /* currently, only handling CPU_SUSPEND */
163         if (frame->r[0] != PSCI_FUNC_ID_CPU_SUSPEND)
164                 return PSCI_RETURN_NOT_SUPPORTED;
165
166         /* save NS entry point */
167         ((uint64_t *)&__mon_cpu_return_addr)[cpu] = frame->r[2];
168
169         return PSCI_RETURN_SUCCESS;
170 }