15cb24200SMichal Simek /*
25cb24200SMichal Simek * (C) Copyright 2014 - 2015 Xilinx, Inc.
35cb24200SMichal Simek * Michal Simek <michal.simek@xilinx.com>
45cb24200SMichal Simek *
55cb24200SMichal Simek * SPDX-License-Identifier: GPL-2.0+
65cb24200SMichal Simek */
75cb24200SMichal Simek
85cb24200SMichal Simek #include <common.h>
95cb24200SMichal Simek #include <asm/arch/hardware.h>
105cb24200SMichal Simek #include <asm/arch/sys_proto.h>
115cb24200SMichal Simek #include <asm/io.h>
125cb24200SMichal Simek
135cb24200SMichal Simek #define LOCK 0
145cb24200SMichal Simek #define SPLIT 1
155cb24200SMichal Simek
165cb24200SMichal Simek #define HALT 0
175cb24200SMichal Simek #define RELEASE 1
185cb24200SMichal Simek
195cb24200SMichal Simek #define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF
205cb24200SMichal Simek #define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000
215cb24200SMichal Simek #define ZYNQMP_R5_LOVEC_ADDR 0x0
225cb24200SMichal Simek #define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01
235cb24200SMichal Simek #define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04
245cb24200SMichal Simek #define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08
255cb24200SMichal Simek #define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40
265cb24200SMichal Simek #define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10
275cb24200SMichal Simek
285cb24200SMichal Simek #define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04
295cb24200SMichal Simek #define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01
305cb24200SMichal Simek #define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02
315cb24200SMichal Simek #define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000
325cb24200SMichal Simek
335cb24200SMichal Simek #define ZYNQMP_TCM_START_ADDRESS 0xFFE00000
345cb24200SMichal Simek #define ZYNQMP_TCM_BOTH_SIZE 0x40000
355cb24200SMichal Simek
365cb24200SMichal Simek #define ZYNQMP_CORE_APU0 0
375cb24200SMichal Simek #define ZYNQMP_CORE_APU3 3
385cb24200SMichal Simek
395cb24200SMichal Simek #define ZYNQMP_MAX_CORES 6
405cb24200SMichal Simek
is_core_valid(unsigned int core)415cb24200SMichal Simek int is_core_valid(unsigned int core)
425cb24200SMichal Simek {
435cb24200SMichal Simek if (core < ZYNQMP_MAX_CORES)
445cb24200SMichal Simek return 1;
455cb24200SMichal Simek
465cb24200SMichal Simek return 0;
475cb24200SMichal Simek }
485cb24200SMichal Simek
cpu_reset(int nr)495cb24200SMichal Simek int cpu_reset(int nr)
505cb24200SMichal Simek {
515cb24200SMichal Simek puts("Feature is not implemented.\n");
525cb24200SMichal Simek return 0;
535cb24200SMichal Simek }
545cb24200SMichal Simek
set_r5_halt_mode(u8 halt,u8 mode)555cb24200SMichal Simek static void set_r5_halt_mode(u8 halt, u8 mode)
565cb24200SMichal Simek {
575cb24200SMichal Simek u32 tmp;
585cb24200SMichal Simek
595cb24200SMichal Simek tmp = readl(&rpu_base->rpu0_cfg);
605cb24200SMichal Simek if (halt == HALT)
615cb24200SMichal Simek tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
625cb24200SMichal Simek else
635cb24200SMichal Simek tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
645cb24200SMichal Simek writel(tmp, &rpu_base->rpu0_cfg);
655cb24200SMichal Simek
665cb24200SMichal Simek if (mode == LOCK) {
675cb24200SMichal Simek tmp = readl(&rpu_base->rpu1_cfg);
685cb24200SMichal Simek if (halt == HALT)
695cb24200SMichal Simek tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
705cb24200SMichal Simek else
715cb24200SMichal Simek tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
725cb24200SMichal Simek writel(tmp, &rpu_base->rpu1_cfg);
735cb24200SMichal Simek }
745cb24200SMichal Simek }
755cb24200SMichal Simek
set_r5_tcm_mode(u8 mode)765cb24200SMichal Simek static void set_r5_tcm_mode(u8 mode)
775cb24200SMichal Simek {
785cb24200SMichal Simek u32 tmp;
795cb24200SMichal Simek
805cb24200SMichal Simek tmp = readl(&rpu_base->rpu_glbl_ctrl);
815cb24200SMichal Simek if (mode == LOCK) {
825cb24200SMichal Simek tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
835cb24200SMichal Simek tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
845cb24200SMichal Simek ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
855cb24200SMichal Simek } else {
865cb24200SMichal Simek tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
875cb24200SMichal Simek tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
885cb24200SMichal Simek ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
895cb24200SMichal Simek }
905cb24200SMichal Simek
915cb24200SMichal Simek writel(tmp, &rpu_base->rpu_glbl_ctrl);
925cb24200SMichal Simek }
935cb24200SMichal Simek
set_r5_reset(u8 mode)945cb24200SMichal Simek static void set_r5_reset(u8 mode)
955cb24200SMichal Simek {
965cb24200SMichal Simek u32 tmp;
975cb24200SMichal Simek
985cb24200SMichal Simek tmp = readl(&crlapb_base->rst_lpd_top);
995cb24200SMichal Simek tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
1005cb24200SMichal Simek ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
1015cb24200SMichal Simek
1025cb24200SMichal Simek if (mode == LOCK)
1035cb24200SMichal Simek tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
1045cb24200SMichal Simek
1055cb24200SMichal Simek writel(tmp, &crlapb_base->rst_lpd_top);
1065cb24200SMichal Simek }
1075cb24200SMichal Simek
release_r5_reset(u8 mode)1085cb24200SMichal Simek static void release_r5_reset(u8 mode)
1095cb24200SMichal Simek {
1105cb24200SMichal Simek u32 tmp;
1115cb24200SMichal Simek
1125cb24200SMichal Simek tmp = readl(&crlapb_base->rst_lpd_top);
1135cb24200SMichal Simek tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
1145cb24200SMichal Simek ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
1155cb24200SMichal Simek
1165cb24200SMichal Simek if (mode == LOCK)
1175cb24200SMichal Simek tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
1185cb24200SMichal Simek
1195cb24200SMichal Simek writel(tmp, &crlapb_base->rst_lpd_top);
1205cb24200SMichal Simek }
1215cb24200SMichal Simek
enable_clock_r5(void)1225cb24200SMichal Simek static void enable_clock_r5(void)
1235cb24200SMichal Simek {
1245cb24200SMichal Simek u32 tmp;
1255cb24200SMichal Simek
1265cb24200SMichal Simek tmp = readl(&crlapb_base->cpu_r5_ctrl);
1275cb24200SMichal Simek tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
1285cb24200SMichal Simek writel(tmp, &crlapb_base->cpu_r5_ctrl);
1295cb24200SMichal Simek
1305cb24200SMichal Simek /* Give some delay for clock
13162a3b7ddSRobert P. J. Day * to propagate */
1325cb24200SMichal Simek udelay(0x500);
1335cb24200SMichal Simek }
1345cb24200SMichal Simek
cpu_disable(int nr)1355cb24200SMichal Simek int cpu_disable(int nr)
1365cb24200SMichal Simek {
1375cb24200SMichal Simek if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
1385cb24200SMichal Simek u32 val = readl(&crfapb_base->rst_fpd_apu);
1395cb24200SMichal Simek val |= 1 << nr;
1405cb24200SMichal Simek writel(val, &crfapb_base->rst_fpd_apu);
1415cb24200SMichal Simek } else {
1425cb24200SMichal Simek set_r5_reset(LOCK);
1435cb24200SMichal Simek }
1445cb24200SMichal Simek
1455cb24200SMichal Simek return 0;
1465cb24200SMichal Simek }
1475cb24200SMichal Simek
cpu_status(int nr)1485cb24200SMichal Simek int cpu_status(int nr)
1495cb24200SMichal Simek {
1505cb24200SMichal Simek if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
1515cb24200SMichal Simek u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
1525cb24200SMichal Simek u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
1535cb24200SMichal Simek nr * 8);
1545cb24200SMichal Simek u32 val = readl(&crfapb_base->rst_fpd_apu);
1555cb24200SMichal Simek val &= 1 << nr;
1565cb24200SMichal Simek printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
1575cb24200SMichal Simek nr, val ? "OFF" : "ON" , addr_high, addr_low);
1585cb24200SMichal Simek } else {
1595cb24200SMichal Simek u32 val = readl(&crlapb_base->rst_lpd_top);
1605cb24200SMichal Simek val &= 1 << (nr - 4);
1615cb24200SMichal Simek printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
1625cb24200SMichal Simek }
1635cb24200SMichal Simek
1645cb24200SMichal Simek return 0;
1655cb24200SMichal Simek }
1665cb24200SMichal Simek
set_r5_start(u8 high)1675cb24200SMichal Simek static void set_r5_start(u8 high)
1685cb24200SMichal Simek {
1695cb24200SMichal Simek u32 tmp;
1705cb24200SMichal Simek
1715cb24200SMichal Simek tmp = readl(&rpu_base->rpu0_cfg);
1725cb24200SMichal Simek if (high)
1735cb24200SMichal Simek tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
1745cb24200SMichal Simek else
1755cb24200SMichal Simek tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
1765cb24200SMichal Simek writel(tmp, &rpu_base->rpu0_cfg);
1775cb24200SMichal Simek
1785cb24200SMichal Simek tmp = readl(&rpu_base->rpu1_cfg);
1795cb24200SMichal Simek if (high)
1805cb24200SMichal Simek tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
1815cb24200SMichal Simek else
1825cb24200SMichal Simek tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
1835cb24200SMichal Simek writel(tmp, &rpu_base->rpu1_cfg);
1845cb24200SMichal Simek }
1855cb24200SMichal Simek
write_tcm_boot_trampoline(u32 boot_addr)186a7bcd4c3SMichal Simek static void write_tcm_boot_trampoline(u32 boot_addr)
187a7bcd4c3SMichal Simek {
188a7bcd4c3SMichal Simek if (boot_addr) {
189a7bcd4c3SMichal Simek /*
190a7bcd4c3SMichal Simek * Boot trampoline is simple ASM code below.
191a7bcd4c3SMichal Simek *
192a7bcd4c3SMichal Simek * b over;
193a7bcd4c3SMichal Simek * label:
194a7bcd4c3SMichal Simek * .word 0
195a7bcd4c3SMichal Simek * over: ldr r0, =label
196a7bcd4c3SMichal Simek * ldr r1, [r0]
197a7bcd4c3SMichal Simek * bx r1
198a7bcd4c3SMichal Simek */
199a7bcd4c3SMichal Simek debug("Write boot trampoline for %x\n", boot_addr);
200a7bcd4c3SMichal Simek writel(0xea000000, ZYNQMP_TCM_START_ADDRESS);
201a7bcd4c3SMichal Simek writel(boot_addr, ZYNQMP_TCM_START_ADDRESS + 0x4);
202a7bcd4c3SMichal Simek writel(0xe59f0004, ZYNQMP_TCM_START_ADDRESS + 0x8);
203a7bcd4c3SMichal Simek writel(0xe5901000, ZYNQMP_TCM_START_ADDRESS + 0xc);
204a7bcd4c3SMichal Simek writel(0xe12fff11, ZYNQMP_TCM_START_ADDRESS + 0x10);
205a7bcd4c3SMichal Simek writel(0x00000004, ZYNQMP_TCM_START_ADDRESS + 0x14); // address for
206a7bcd4c3SMichal Simek }
207a7bcd4c3SMichal Simek }
208a7bcd4c3SMichal Simek
initialize_tcm(bool mode)209*a076789eSSiva Durga Prasad Paladugu void initialize_tcm(bool mode)
210*a076789eSSiva Durga Prasad Paladugu {
211*a076789eSSiva Durga Prasad Paladugu if (!mode) {
212*a076789eSSiva Durga Prasad Paladugu set_r5_tcm_mode(LOCK);
213*a076789eSSiva Durga Prasad Paladugu set_r5_halt_mode(HALT, LOCK);
214*a076789eSSiva Durga Prasad Paladugu enable_clock_r5();
215*a076789eSSiva Durga Prasad Paladugu release_r5_reset(LOCK);
216*a076789eSSiva Durga Prasad Paladugu } else {
217*a076789eSSiva Durga Prasad Paladugu set_r5_tcm_mode(SPLIT);
218*a076789eSSiva Durga Prasad Paladugu set_r5_halt_mode(HALT, SPLIT);
219*a076789eSSiva Durga Prasad Paladugu enable_clock_r5();
220*a076789eSSiva Durga Prasad Paladugu release_r5_reset(SPLIT);
221*a076789eSSiva Durga Prasad Paladugu }
222*a076789eSSiva Durga Prasad Paladugu }
223*a076789eSSiva Durga Prasad Paladugu
cpu_release(int nr,int argc,char * const argv[])2245cb24200SMichal Simek int cpu_release(int nr, int argc, char * const argv[])
2255cb24200SMichal Simek {
2265cb24200SMichal Simek if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
2275cb24200SMichal Simek u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
2285cb24200SMichal Simek /* HIGH */
2295cb24200SMichal Simek writel((u32)(boot_addr >> 32),
2305cb24200SMichal Simek ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
2315cb24200SMichal Simek /* LOW */
2325cb24200SMichal Simek writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
2335cb24200SMichal Simek ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
2345cb24200SMichal Simek
2355cb24200SMichal Simek u32 val = readl(&crfapb_base->rst_fpd_apu);
2365cb24200SMichal Simek val &= ~(1 << nr);
2375cb24200SMichal Simek writel(val, &crfapb_base->rst_fpd_apu);
2385cb24200SMichal Simek } else {
2395cb24200SMichal Simek if (argc != 2) {
2405cb24200SMichal Simek printf("Invalid number of arguments to release.\n");
2415cb24200SMichal Simek printf("<addr> <mode>-Start addr lockstep or split\n");
2425cb24200SMichal Simek return 1;
2435cb24200SMichal Simek }
2445cb24200SMichal Simek
2455cb24200SMichal Simek u32 boot_addr = simple_strtoul(argv[0], NULL, 16);
246a7bcd4c3SMichal Simek u32 boot_addr_uniq = 0;
2475cb24200SMichal Simek if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
2485cb24200SMichal Simek boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
249a7bcd4c3SMichal Simek printf("Using TCM jump trampoline for address 0x%x\n",
250a7bcd4c3SMichal Simek boot_addr);
251a7bcd4c3SMichal Simek /* Save boot address for later usage */
252a7bcd4c3SMichal Simek boot_addr_uniq = boot_addr;
253a7bcd4c3SMichal Simek /*
254a7bcd4c3SMichal Simek * R5 needs to start from LOVEC at TCM
255a7bcd4c3SMichal Simek * OCM will be probably occupied by ATF
256a7bcd4c3SMichal Simek */
257a7bcd4c3SMichal Simek boot_addr = ZYNQMP_R5_LOVEC_ADDR;
2585cb24200SMichal Simek }
2595cb24200SMichal Simek
2605cb24200SMichal Simek if (!strncmp(argv[1], "lockstep", 8)) {
2615cb24200SMichal Simek printf("R5 lockstep mode\n");
2625cb24200SMichal Simek set_r5_tcm_mode(LOCK);
2635cb24200SMichal Simek set_r5_halt_mode(HALT, LOCK);
264fb101168SMichal Simek set_r5_start(boot_addr);
2655cb24200SMichal Simek enable_clock_r5();
2665cb24200SMichal Simek release_r5_reset(LOCK);
267a7bcd4c3SMichal Simek write_tcm_boot_trampoline(boot_addr_uniq);
2685cb24200SMichal Simek set_r5_halt_mode(RELEASE, LOCK);
2695cb24200SMichal Simek } else if (!strncmp(argv[1], "split", 5)) {
2705cb24200SMichal Simek printf("R5 split mode\n");
2715cb24200SMichal Simek set_r5_tcm_mode(SPLIT);
2725cb24200SMichal Simek set_r5_halt_mode(HALT, SPLIT);
2735cb24200SMichal Simek enable_clock_r5();
2745cb24200SMichal Simek release_r5_reset(SPLIT);
275a7bcd4c3SMichal Simek write_tcm_boot_trampoline(boot_addr_uniq);
2765cb24200SMichal Simek set_r5_halt_mode(RELEASE, SPLIT);
2775cb24200SMichal Simek } else {
2785cb24200SMichal Simek printf("Unsupported mode\n");
2795cb24200SMichal Simek return 1;
2805cb24200SMichal Simek }
2815cb24200SMichal Simek }
2825cb24200SMichal Simek
2835cb24200SMichal Simek return 0;
2845cb24200SMichal Simek }
285