]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/armv8/zynqmp/mp.c
common: Fix cpu nr type which is always unsigned type
[u-boot] / arch / arm / cpu / armv8 / zynqmp / mp.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2014 - 2015 Xilinx, Inc.
4  * Michal Simek <michal.simek@xilinx.com>
5  */
6
7 #include <common.h>
8 #include <asm/arch/hardware.h>
9 #include <asm/arch/sys_proto.h>
10 #include <asm/io.h>
11
12 #define LOCK            0
13 #define SPLIT           1
14
15 #define HALT            0
16 #define RELEASE         1
17
18 #define ZYNQMP_BOOTADDR_HIGH_MASK               0xFFFFFFFF
19 #define ZYNQMP_R5_HIVEC_ADDR                    0xFFFF0000
20 #define ZYNQMP_R5_LOVEC_ADDR                    0x0
21 #define ZYNQMP_RPU_CFG_CPU_HALT_MASK            0x01
22 #define ZYNQMP_RPU_CFG_HIVEC_MASK               0x04
23 #define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK    0x08
24 #define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK      0x40
25 #define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK       0x10
26
27 #define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK     0x04
28 #define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK      0x01
29 #define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK      0x02
30 #define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK   0x1000000
31
32 #define ZYNQMP_TCM_START_ADDRESS                0xFFE00000
33 #define ZYNQMP_TCM_BOTH_SIZE                    0x40000
34
35 #define ZYNQMP_CORE_APU0        0
36 #define ZYNQMP_CORE_APU3        3
37
38 #define ZYNQMP_MAX_CORES        6
39
40 int is_core_valid(unsigned int core)
41 {
42         if (core < ZYNQMP_MAX_CORES)
43                 return 1;
44
45         return 0;
46 }
47
48 int cpu_reset(u32 nr)
49 {
50         puts("Feature is not implemented.\n");
51         return 0;
52 }
53
54 static void set_r5_halt_mode(u8 halt, u8 mode)
55 {
56         u32 tmp;
57
58         tmp = readl(&rpu_base->rpu0_cfg);
59         if (halt == HALT)
60                 tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
61         else
62                 tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
63         writel(tmp, &rpu_base->rpu0_cfg);
64
65         if (mode == LOCK) {
66                 tmp = readl(&rpu_base->rpu1_cfg);
67                 if (halt == HALT)
68                         tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
69                 else
70                         tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
71                 writel(tmp, &rpu_base->rpu1_cfg);
72         }
73 }
74
75 static void set_r5_tcm_mode(u8 mode)
76 {
77         u32 tmp;
78
79         tmp = readl(&rpu_base->rpu_glbl_ctrl);
80         if (mode == LOCK) {
81                 tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
82                 tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
83                        ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
84         } else {
85                 tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
86                 tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
87                        ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
88         }
89
90         writel(tmp, &rpu_base->rpu_glbl_ctrl);
91 }
92
93 static void set_r5_reset(u8 mode)
94 {
95         u32 tmp;
96
97         tmp = readl(&crlapb_base->rst_lpd_top);
98         tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
99                ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
100
101         if (mode == LOCK)
102                 tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
103
104         writel(tmp, &crlapb_base->rst_lpd_top);
105 }
106
107 static void release_r5_reset(u8 mode)
108 {
109         u32 tmp;
110
111         tmp = readl(&crlapb_base->rst_lpd_top);
112         tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
113                ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
114
115         if (mode == LOCK)
116                 tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
117
118         writel(tmp, &crlapb_base->rst_lpd_top);
119 }
120
121 static void enable_clock_r5(void)
122 {
123         u32 tmp;
124
125         tmp = readl(&crlapb_base->cpu_r5_ctrl);
126         tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
127         writel(tmp, &crlapb_base->cpu_r5_ctrl);
128
129         /* Give some delay for clock
130          * to propagate */
131         udelay(0x500);
132 }
133
134 int cpu_disable(u32 nr)
135 {
136         if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
137                 u32 val = readl(&crfapb_base->rst_fpd_apu);
138                 val |= 1 << nr;
139                 writel(val, &crfapb_base->rst_fpd_apu);
140         } else {
141                 set_r5_reset(LOCK);
142         }
143
144         return 0;
145 }
146
147 int cpu_status(u32 nr)
148 {
149         if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
150                 u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
151                 u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
152                                       nr * 8);
153                 u32 val = readl(&crfapb_base->rst_fpd_apu);
154                 val &= 1 << nr;
155                 printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
156                        nr, val ? "OFF" : "ON" , addr_high, addr_low);
157         } else {
158                 u32 val = readl(&crlapb_base->rst_lpd_top);
159                 val &= 1 << (nr - 4);
160                 printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
161         }
162
163         return 0;
164 }
165
166 static void set_r5_start(u8 high)
167 {
168         u32 tmp;
169
170         tmp = readl(&rpu_base->rpu0_cfg);
171         if (high)
172                 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
173         else
174                 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
175         writel(tmp, &rpu_base->rpu0_cfg);
176
177         tmp = readl(&rpu_base->rpu1_cfg);
178         if (high)
179                 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
180         else
181                 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
182         writel(tmp, &rpu_base->rpu1_cfg);
183 }
184
185 static void write_tcm_boot_trampoline(u32 boot_addr)
186 {
187         if (boot_addr) {
188                 /*
189                  * Boot trampoline is simple ASM code below.
190                  *
191                  *              b over;
192                  *      label:
193                  *      .word   0
194                  *      over:   ldr     r0, =label
195                  *              ldr     r1, [r0]
196                  *              bx      r1
197                  */
198                 debug("Write boot trampoline for %x\n", boot_addr);
199                 writel(0xea000000, ZYNQMP_TCM_START_ADDRESS);
200                 writel(boot_addr, ZYNQMP_TCM_START_ADDRESS + 0x4);
201                 writel(0xe59f0004, ZYNQMP_TCM_START_ADDRESS + 0x8);
202                 writel(0xe5901000, ZYNQMP_TCM_START_ADDRESS + 0xc);
203                 writel(0xe12fff11, ZYNQMP_TCM_START_ADDRESS + 0x10);
204                 writel(0x00000004, ZYNQMP_TCM_START_ADDRESS + 0x14); // address for
205         }
206 }
207
208 void initialize_tcm(bool mode)
209 {
210         if (!mode) {
211                 set_r5_tcm_mode(LOCK);
212                 set_r5_halt_mode(HALT, LOCK);
213                 enable_clock_r5();
214                 release_r5_reset(LOCK);
215         } else {
216                 set_r5_tcm_mode(SPLIT);
217                 set_r5_halt_mode(HALT, SPLIT);
218                 enable_clock_r5();
219                 release_r5_reset(SPLIT);
220         }
221 }
222
223 int cpu_release(u32 nr, int argc, char * const argv[])
224 {
225         if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
226                 u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
227                 /* HIGH */
228                 writel((u32)(boot_addr >> 32),
229                        ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
230                 /* LOW */
231                 writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
232                        ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
233
234                 u32 val = readl(&crfapb_base->rst_fpd_apu);
235                 val &= ~(1 << nr);
236                 writel(val, &crfapb_base->rst_fpd_apu);
237         } else {
238                 if (argc != 2) {
239                         printf("Invalid number of arguments to release.\n");
240                         printf("<addr> <mode>-Start addr lockstep or split\n");
241                         return 1;
242                 }
243
244                 u32 boot_addr = simple_strtoul(argv[0], NULL, 16);
245                 u32 boot_addr_uniq = 0;
246                 if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
247                       boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
248                         printf("Using TCM jump trampoline for address 0x%x\n",
249                                boot_addr);
250                         /* Save boot address for later usage */
251                         boot_addr_uniq = boot_addr;
252                         /*
253                          * R5 needs to start from LOVEC at TCM
254                          * OCM will be probably occupied by ATF
255                          */
256                         boot_addr = ZYNQMP_R5_LOVEC_ADDR;
257                 }
258
259                 /*
260                  * Since we don't know where the user may have loaded the image
261                  * for an R5 we have to flush all the data cache to ensure
262                  * the R5 sees it.
263                  */
264                 flush_dcache_all();
265
266                 if (!strncmp(argv[1], "lockstep", 8)) {
267                         printf("R5 lockstep mode\n");
268                         set_r5_reset(LOCK);
269                         set_r5_tcm_mode(LOCK);
270                         set_r5_halt_mode(HALT, LOCK);
271                         set_r5_start(boot_addr);
272                         enable_clock_r5();
273                         release_r5_reset(LOCK);
274                         dcache_disable();
275                         write_tcm_boot_trampoline(boot_addr_uniq);
276                         dcache_enable();
277                         set_r5_halt_mode(RELEASE, LOCK);
278                 } else if (!strncmp(argv[1], "split", 5)) {
279                         printf("R5 split mode\n");
280                         set_r5_reset(SPLIT);
281                         set_r5_tcm_mode(SPLIT);
282                         set_r5_halt_mode(HALT, SPLIT);
283                         set_r5_start(boot_addr);
284                         enable_clock_r5();
285                         release_r5_reset(SPLIT);
286                         dcache_disable();
287                         write_tcm_boot_trampoline(boot_addr_uniq);
288                         dcache_enable();
289                         set_r5_halt_mode(RELEASE, SPLIT);
290                 } else {
291                         printf("Unsupported mode\n");
292                         return 1;
293                 }
294         }
295
296         return 0;
297 }