xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/zynqmp/mp.c (revision fe84c48eeb8e9cb0b8b80a4c0a53bb089adff9af)
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