blob: 9b46a25a1cbe970f1b6e01e2ab2f688549c59003 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Michal Simek58f865f2015-04-15 13:36:40 +02002/*
3 * (C) Copyright 2014 - 2015 Xilinx, Inc.
Michal Simeka8c94362023-07-10 14:35:49 +02004 * Michal Simek <michal.simek@amd.com>
Michal Simek58f865f2015-04-15 13:36:40 +02005 */
6
Tom Rinidec7ea02024-05-20 13:35:03 -06007#include <config.h>
Simon Glass970b61e2019-11-14 12:57:09 -07008#include <cpu_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060010#include <vsprintf.h>
Michal Simeka7acb532023-06-23 14:51:57 +020011#include <zynqmp_firmware.h>
Michal Simek58f865f2015-04-15 13:36:40 +020012#include <asm/arch/hardware.h>
13#include <asm/arch/sys_proto.h>
14#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060016#include <linux/string.h>
Michal Simek58f865f2015-04-15 13:36:40 +020017
18#define LOCK 0
19#define SPLIT 1
20
21#define HALT 0
22#define RELEASE 1
23
24#define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF
25#define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000
26#define ZYNQMP_R5_LOVEC_ADDR 0x0
27#define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01
28#define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04
29#define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08
30#define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40
31#define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10
32
33#define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04
34#define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01
35#define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02
36#define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000
37
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +020038#define ZYNQMP_R5_0_TCM_START_ADDR 0xFFE00000
39#define ZYNQMP_R5_1_TCM_START_ADDR 0xFFE90000
Michal Simek58f865f2015-04-15 13:36:40 +020040#define ZYNQMP_TCM_BOTH_SIZE 0x40000
41
42#define ZYNQMP_CORE_APU0 0
43#define ZYNQMP_CORE_APU3 3
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -060044#define ZYNQMP_CORE_RPU0 4
45#define ZYNQMP_CORE_RPU1 5
Michal Simek58f865f2015-04-15 13:36:40 +020046
47#define ZYNQMP_MAX_CORES 6
48
Lukas Funkec6f90582022-10-28 14:15:47 +020049#define ZYNQMP_RPU0_USE_MASK BIT(1)
50#define ZYNQMP_RPU1_USE_MASK BIT(2)
51
Michal Simek58f865f2015-04-15 13:36:40 +020052int is_core_valid(unsigned int core)
53{
54 if (core < ZYNQMP_MAX_CORES)
55 return 1;
56
57 return 0;
58}
59
Michal Simek1669e182018-06-13 08:56:31 +020060int cpu_reset(u32 nr)
Michal Simek58f865f2015-04-15 13:36:40 +020061{
62 puts("Feature is not implemented.\n");
63 return 0;
64}
65
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -060066static void set_r5_halt_mode(u32 nr, u8 halt, u8 mode)
Michal Simek58f865f2015-04-15 13:36:40 +020067{
68 u32 tmp;
69
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -060070 if (mode == LOCK || nr == ZYNQMP_CORE_RPU0) {
71 tmp = readl(&rpu_base->rpu0_cfg);
72 if (halt == HALT)
73 tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
74 else
75 tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
76 writel(tmp, &rpu_base->rpu0_cfg);
77 }
Michal Simek58f865f2015-04-15 13:36:40 +020078
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -060079 if (mode == LOCK || nr == ZYNQMP_CORE_RPU1) {
Michal Simek58f865f2015-04-15 13:36:40 +020080 tmp = readl(&rpu_base->rpu1_cfg);
81 if (halt == HALT)
82 tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
83 else
84 tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
85 writel(tmp, &rpu_base->rpu1_cfg);
86 }
87}
88
89static void set_r5_tcm_mode(u8 mode)
90{
91 u32 tmp;
92
93 tmp = readl(&rpu_base->rpu_glbl_ctrl);
94 if (mode == LOCK) {
95 tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
96 tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
97 ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
98 } else {
99 tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
100 tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
101 ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
102 }
103
104 writel(tmp, &rpu_base->rpu_glbl_ctrl);
105}
106
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600107static void set_r5_reset(u32 nr, u8 mode)
Michal Simek58f865f2015-04-15 13:36:40 +0200108{
109 u32 tmp;
110
111 tmp = readl(&crlapb_base->rst_lpd_top);
Neal Fragerd929bbf2022-05-04 09:12:26 +0200112 if (mode == LOCK) {
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600113 tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
Neal Fragerd929bbf2022-05-04 09:12:26 +0200114 ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK |
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600115 ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK);
Neal Fragerd929bbf2022-05-04 09:12:26 +0200116 } else {
117 if (nr == ZYNQMP_CORE_RPU0) {
118 tmp |= ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK;
119 if (tmp & ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK)
120 tmp |= ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK;
121 } else {
122 tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
123 if (tmp & ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK)
124 tmp |= ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK;
125 }
126 }
Michal Simek58f865f2015-04-15 13:36:40 +0200127
128 writel(tmp, &crlapb_base->rst_lpd_top);
129}
130
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600131static void release_r5_reset(u32 nr, u8 mode)
Michal Simek58f865f2015-04-15 13:36:40 +0200132{
133 u32 tmp;
134
135 tmp = readl(&crlapb_base->rst_lpd_top);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600136 if (mode == LOCK || nr == ZYNQMP_CORE_RPU0)
137 tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
138 ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
Michal Simek58f865f2015-04-15 13:36:40 +0200139
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600140 if (mode == LOCK || nr == ZYNQMP_CORE_RPU1)
141 tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
142 ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK);
Michal Simek58f865f2015-04-15 13:36:40 +0200143
144 writel(tmp, &crlapb_base->rst_lpd_top);
145}
146
147static void enable_clock_r5(void)
148{
149 u32 tmp;
150
151 tmp = readl(&crlapb_base->cpu_r5_ctrl);
152 tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
153 writel(tmp, &crlapb_base->cpu_r5_ctrl);
154
155 /* Give some delay for clock
Robert P. J. Day8d56db92016-07-15 13:44:45 -0400156 * to propagate */
Michal Simek58f865f2015-04-15 13:36:40 +0200157 udelay(0x500);
158}
159
Neal Fragerd929bbf2022-05-04 09:12:26 +0200160static int check_r5_mode(void)
161{
162 u32 tmp;
163
164 tmp = readl(&rpu_base->rpu_glbl_ctrl);
165 if (tmp & ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK)
166 return SPLIT;
167
168 return LOCK;
169}
170
Michal Simek1669e182018-06-13 08:56:31 +0200171int cpu_disable(u32 nr)
Michal Simek58f865f2015-04-15 13:36:40 +0200172{
Venkatesh Yadav Abbarapuae8bc3d2022-10-04 11:04:54 +0530173 if (nr <= ZYNQMP_CORE_APU3) {
Michal Simek58f865f2015-04-15 13:36:40 +0200174 u32 val = readl(&crfapb_base->rst_fpd_apu);
175 val |= 1 << nr;
176 writel(val, &crfapb_base->rst_fpd_apu);
177 } else {
Neal Fragerd929bbf2022-05-04 09:12:26 +0200178 set_r5_reset(nr, check_r5_mode());
Michal Simek58f865f2015-04-15 13:36:40 +0200179 }
180
181 return 0;
182}
183
Michal Simek1669e182018-06-13 08:56:31 +0200184int cpu_status(u32 nr)
Michal Simek58f865f2015-04-15 13:36:40 +0200185{
Venkatesh Yadav Abbarapuae8bc3d2022-10-04 11:04:54 +0530186 if (nr <= ZYNQMP_CORE_APU3) {
Michal Simek58f865f2015-04-15 13:36:40 +0200187 u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
188 u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
189 nr * 8);
190 u32 val = readl(&crfapb_base->rst_fpd_apu);
191 val &= 1 << nr;
192 printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
193 nr, val ? "OFF" : "ON" , addr_high, addr_low);
194 } else {
195 u32 val = readl(&crlapb_base->rst_lpd_top);
196 val &= 1 << (nr - 4);
197 printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
198 }
199
200 return 0;
201}
202
203static void set_r5_start(u8 high)
204{
205 u32 tmp;
206
207 tmp = readl(&rpu_base->rpu0_cfg);
208 if (high)
209 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
210 else
211 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
212 writel(tmp, &rpu_base->rpu0_cfg);
213
214 tmp = readl(&rpu_base->rpu1_cfg);
215 if (high)
216 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
217 else
218 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
219 writel(tmp, &rpu_base->rpu1_cfg);
220}
221
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +0200222static void write_tcm_boot_trampoline(u32 nr, u32 boot_addr)
Michal Simekf5005ce2015-05-22 13:28:23 +0200223{
224 if (boot_addr) {
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +0200225 u64 tcm_start_addr = ZYNQMP_R5_0_TCM_START_ADDR;
226
227 if (nr == ZYNQMP_CORE_RPU1)
228 tcm_start_addr = ZYNQMP_R5_1_TCM_START_ADDR;
229
Michal Simekf5005ce2015-05-22 13:28:23 +0200230 /*
231 * Boot trampoline is simple ASM code below.
232 *
233 * b over;
234 * label:
235 * .word 0
236 * over: ldr r0, =label
237 * ldr r1, [r0]
238 * bx r1
239 */
240 debug("Write boot trampoline for %x\n", boot_addr);
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +0200241 writel(0xea000000, tcm_start_addr);
242 writel(boot_addr, tcm_start_addr + 0x4);
243 writel(0xe59f0004, tcm_start_addr + 0x8);
244 writel(0xe5901000, tcm_start_addr + 0xc);
245 writel(0xe12fff11, tcm_start_addr + 0x10);
246 writel(0x00000004, tcm_start_addr + 0x14);
Michal Simekf5005ce2015-05-22 13:28:23 +0200247 }
248}
249
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530250void initialize_tcm(bool mode)
251{
252 if (!mode) {
253 set_r5_tcm_mode(LOCK);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600254 set_r5_halt_mode(ZYNQMP_CORE_RPU0, HALT, LOCK);
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530255 enable_clock_r5();
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600256 release_r5_reset(ZYNQMP_CORE_RPU0, LOCK);
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530257 } else {
258 set_r5_tcm_mode(SPLIT);
Neal Frager7aba2552023-03-23 08:25:06 +0000259 set_r5_halt_mode(ZYNQMP_CORE_RPU0, HALT, SPLIT);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600260 set_r5_halt_mode(ZYNQMP_CORE_RPU1, HALT, SPLIT);
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530261 enable_clock_r5();
Neal Frager7aba2552023-03-23 08:25:06 +0000262 release_r5_reset(ZYNQMP_CORE_RPU0, SPLIT);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600263 release_r5_reset(ZYNQMP_CORE_RPU1, SPLIT);
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530264 }
Lukas Funkec6f90582022-10-28 14:15:47 +0200265}
266
267static void mark_r5_used(u32 nr, u8 mode)
268{
269 u32 mask = 0;
270
271 if (mode == LOCK) {
272 mask = ZYNQMP_RPU0_USE_MASK | ZYNQMP_RPU1_USE_MASK;
273 } else {
274 switch (nr) {
275 case ZYNQMP_CORE_RPU0:
276 mask = ZYNQMP_RPU0_USE_MASK;
277 break;
278 case ZYNQMP_CORE_RPU1:
279 mask = ZYNQMP_RPU1_USE_MASK;
280 break;
281 default:
282 return;
283 }
284 }
285 zynqmp_mmio_write((ulong)&pmu_base->gen_storage4, mask, mask);
Siva Durga Prasad Paladugu5e2a9072017-07-13 19:01:09 +0530286}
287
Simon Glassed38aef2020-05-10 11:40:03 -0600288int cpu_release(u32 nr, int argc, char *const argv[])
Michal Simek58f865f2015-04-15 13:36:40 +0200289{
Venkatesh Yadav Abbarapuae8bc3d2022-10-04 11:04:54 +0530290 if (nr <= ZYNQMP_CORE_APU3) {
Michal Simek58f865f2015-04-15 13:36:40 +0200291 u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
292 /* HIGH */
293 writel((u32)(boot_addr >> 32),
294 ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
295 /* LOW */
296 writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
297 ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
298
299 u32 val = readl(&crfapb_base->rst_fpd_apu);
300 val &= ~(1 << nr);
301 writel(val, &crfapb_base->rst_fpd_apu);
302 } else {
303 if (argc != 2) {
304 printf("Invalid number of arguments to release.\n");
305 printf("<addr> <mode>-Start addr lockstep or split\n");
306 return 1;
307 }
308
Simon Glass3ff49ec2021-07-24 09:03:29 -0600309 u32 boot_addr = hextoul(argv[0], NULL);
Michal Simekf5005ce2015-05-22 13:28:23 +0200310 u32 boot_addr_uniq = 0;
Michal Simek58f865f2015-04-15 13:36:40 +0200311 if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
312 boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
Michal Simekf5005ce2015-05-22 13:28:23 +0200313 printf("Using TCM jump trampoline for address 0x%x\n",
314 boot_addr);
315 /* Save boot address for later usage */
316 boot_addr_uniq = boot_addr;
317 /*
318 * R5 needs to start from LOVEC at TCM
319 * OCM will be probably occupied by ATF
320 */
321 boot_addr = ZYNQMP_R5_LOVEC_ADDR;
Michal Simek58f865f2015-04-15 13:36:40 +0200322 }
323
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530324 /*
325 * Since we don't know where the user may have loaded the image
326 * for an R5 we have to flush all the data cache to ensure
327 * the R5 sees it.
328 */
329 flush_dcache_all();
330
Michal Simek58f865f2015-04-15 13:36:40 +0200331 if (!strncmp(argv[1], "lockstep", 8)) {
Venkatesh Yadav Abbarapu5824c172023-06-08 08:51:52 +0530332 if (nr != ZYNQMP_CORE_RPU0) {
333 printf("Lockstep mode should run on ZYNQMP_CORE_RPU0\n");
334 return 1;
335 }
Michal Simek58f865f2015-04-15 13:36:40 +0200336 printf("R5 lockstep mode\n");
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600337 set_r5_reset(nr, LOCK);
Michal Simek58f865f2015-04-15 13:36:40 +0200338 set_r5_tcm_mode(LOCK);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600339 set_r5_halt_mode(nr, HALT, LOCK);
Michal Simek08adc902015-05-22 13:26:33 +0200340 set_r5_start(boot_addr);
Michal Simek58f865f2015-04-15 13:36:40 +0200341 enable_clock_r5();
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600342 release_r5_reset(nr, LOCK);
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530343 dcache_disable();
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +0200344 write_tcm_boot_trampoline(nr, boot_addr_uniq);
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530345 dcache_enable();
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600346 set_r5_halt_mode(nr, RELEASE, LOCK);
Lukas Funkec6f90582022-10-28 14:15:47 +0200347 mark_r5_used(nr, LOCK);
Michal Simek58f865f2015-04-15 13:36:40 +0200348 } else if (!strncmp(argv[1], "split", 5)) {
349 printf("R5 split mode\n");
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600350 set_r5_reset(nr, SPLIT);
Michal Simek58f865f2015-04-15 13:36:40 +0200351 set_r5_tcm_mode(SPLIT);
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600352 set_r5_halt_mode(nr, HALT, SPLIT);
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530353 set_r5_start(boot_addr);
Michal Simek58f865f2015-04-15 13:36:40 +0200354 enable_clock_r5();
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600355 release_r5_reset(nr, SPLIT);
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530356 dcache_disable();
Ashok Reddy Somab43d3cf2023-04-05 15:06:45 +0200357 write_tcm_boot_trampoline(nr, boot_addr_uniq);
Siva Durga Prasad Paladugue0a1f1e2017-08-01 16:24:52 +0530358 dcache_enable();
Ashok Reddy Soma86d212e2021-04-15 05:12:15 -0600359 set_r5_halt_mode(nr, RELEASE, SPLIT);
Lukas Funkec6f90582022-10-28 14:15:47 +0200360 mark_r5_used(nr, SPLIT);
Michal Simek58f865f2015-04-15 13:36:40 +0200361 } else {
362 printf("Unsupported mode\n");
363 return 1;
364 }
365 }
366
367 return 0;
368}