123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * (C) Copyright 2014 - 2015 Xilinx, Inc.
- * Michal Simek <michal.simek@xilinx.com>
- */
- #include <common.h>
- #include <cpu_func.h>
- #include <asm/arch/hardware.h>
- #include <asm/arch/sys_proto.h>
- #include <asm/io.h>
- #define LOCK 0
- #define SPLIT 1
- #define HALT 0
- #define RELEASE 1
- #define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF
- #define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000
- #define ZYNQMP_R5_LOVEC_ADDR 0x0
- #define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01
- #define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04
- #define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08
- #define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40
- #define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10
- #define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04
- #define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01
- #define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02
- #define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000
- #define ZYNQMP_TCM_START_ADDRESS 0xFFE00000
- #define ZYNQMP_TCM_BOTH_SIZE 0x40000
- #define ZYNQMP_CORE_APU0 0
- #define ZYNQMP_CORE_APU3 3
- #define ZYNQMP_MAX_CORES 6
- int is_core_valid(unsigned int core)
- {
- if (core < ZYNQMP_MAX_CORES)
- return 1;
- return 0;
- }
- int cpu_reset(u32 nr)
- {
- puts("Feature is not implemented.\n");
- return 0;
- }
- static void set_r5_halt_mode(u8 halt, u8 mode)
- {
- u32 tmp;
- tmp = readl(&rpu_base->rpu0_cfg);
- if (halt == HALT)
- tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
- else
- tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
- writel(tmp, &rpu_base->rpu0_cfg);
- if (mode == LOCK) {
- tmp = readl(&rpu_base->rpu1_cfg);
- if (halt == HALT)
- tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
- else
- tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
- writel(tmp, &rpu_base->rpu1_cfg);
- }
- }
- static void set_r5_tcm_mode(u8 mode)
- {
- u32 tmp;
- tmp = readl(&rpu_base->rpu_glbl_ctrl);
- if (mode == LOCK) {
- tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
- tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
- ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
- } else {
- tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
- tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
- ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
- }
- writel(tmp, &rpu_base->rpu_glbl_ctrl);
- }
- static void set_r5_reset(u8 mode)
- {
- u32 tmp;
- tmp = readl(&crlapb_base->rst_lpd_top);
- tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
- ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
- if (mode == LOCK)
- tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
- writel(tmp, &crlapb_base->rst_lpd_top);
- }
- static void release_r5_reset(u8 mode)
- {
- u32 tmp;
- tmp = readl(&crlapb_base->rst_lpd_top);
- tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
- ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
- if (mode == LOCK)
- tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
- writel(tmp, &crlapb_base->rst_lpd_top);
- }
- static void enable_clock_r5(void)
- {
- u32 tmp;
- tmp = readl(&crlapb_base->cpu_r5_ctrl);
- tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
- writel(tmp, &crlapb_base->cpu_r5_ctrl);
- /* Give some delay for clock
- * to propagate */
- udelay(0x500);
- }
- int cpu_disable(u32 nr)
- {
- if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
- u32 val = readl(&crfapb_base->rst_fpd_apu);
- val |= 1 << nr;
- writel(val, &crfapb_base->rst_fpd_apu);
- } else {
- set_r5_reset(LOCK);
- }
- return 0;
- }
- int cpu_status(u32 nr)
- {
- if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
- u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
- u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
- nr * 8);
- u32 val = readl(&crfapb_base->rst_fpd_apu);
- val &= 1 << nr;
- printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
- nr, val ? "OFF" : "ON" , addr_high, addr_low);
- } else {
- u32 val = readl(&crlapb_base->rst_lpd_top);
- val &= 1 << (nr - 4);
- printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
- }
- return 0;
- }
- static void set_r5_start(u8 high)
- {
- u32 tmp;
- tmp = readl(&rpu_base->rpu0_cfg);
- if (high)
- tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
- else
- tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
- writel(tmp, &rpu_base->rpu0_cfg);
- tmp = readl(&rpu_base->rpu1_cfg);
- if (high)
- tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
- else
- tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
- writel(tmp, &rpu_base->rpu1_cfg);
- }
- static void write_tcm_boot_trampoline(u32 boot_addr)
- {
- if (boot_addr) {
- /*
- * Boot trampoline is simple ASM code below.
- *
- * b over;
- * label:
- * .word 0
- * over: ldr r0, =label
- * ldr r1, [r0]
- * bx r1
- */
- debug("Write boot trampoline for %x\n", boot_addr);
- writel(0xea000000, ZYNQMP_TCM_START_ADDRESS);
- writel(boot_addr, ZYNQMP_TCM_START_ADDRESS + 0x4);
- writel(0xe59f0004, ZYNQMP_TCM_START_ADDRESS + 0x8);
- writel(0xe5901000, ZYNQMP_TCM_START_ADDRESS + 0xc);
- writel(0xe12fff11, ZYNQMP_TCM_START_ADDRESS + 0x10);
- writel(0x00000004, ZYNQMP_TCM_START_ADDRESS + 0x14); // address for
- }
- }
- void initialize_tcm(bool mode)
- {
- if (!mode) {
- set_r5_tcm_mode(LOCK);
- set_r5_halt_mode(HALT, LOCK);
- enable_clock_r5();
- release_r5_reset(LOCK);
- } else {
- set_r5_tcm_mode(SPLIT);
- set_r5_halt_mode(HALT, SPLIT);
- enable_clock_r5();
- release_r5_reset(SPLIT);
- }
- }
- int cpu_release(u32 nr, int argc, char *const argv[])
- {
- if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
- u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
- /* HIGH */
- writel((u32)(boot_addr >> 32),
- ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
- /* LOW */
- writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
- ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
- u32 val = readl(&crfapb_base->rst_fpd_apu);
- val &= ~(1 << nr);
- writel(val, &crfapb_base->rst_fpd_apu);
- } else {
- if (argc != 2) {
- printf("Invalid number of arguments to release.\n");
- printf("<addr> <mode>-Start addr lockstep or split\n");
- return 1;
- }
- u32 boot_addr = simple_strtoul(argv[0], NULL, 16);
- u32 boot_addr_uniq = 0;
- if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
- boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
- printf("Using TCM jump trampoline for address 0x%x\n",
- boot_addr);
- /* Save boot address for later usage */
- boot_addr_uniq = boot_addr;
- /*
- * R5 needs to start from LOVEC at TCM
- * OCM will be probably occupied by ATF
- */
- boot_addr = ZYNQMP_R5_LOVEC_ADDR;
- }
- /*
- * Since we don't know where the user may have loaded the image
- * for an R5 we have to flush all the data cache to ensure
- * the R5 sees it.
- */
- flush_dcache_all();
- if (!strncmp(argv[1], "lockstep", 8)) {
- printf("R5 lockstep mode\n");
- set_r5_reset(LOCK);
- set_r5_tcm_mode(LOCK);
- set_r5_halt_mode(HALT, LOCK);
- set_r5_start(boot_addr);
- enable_clock_r5();
- release_r5_reset(LOCK);
- dcache_disable();
- write_tcm_boot_trampoline(boot_addr_uniq);
- dcache_enable();
- set_r5_halt_mode(RELEASE, LOCK);
- } else if (!strncmp(argv[1], "split", 5)) {
- printf("R5 split mode\n");
- set_r5_reset(SPLIT);
- set_r5_tcm_mode(SPLIT);
- set_r5_halt_mode(HALT, SPLIT);
- set_r5_start(boot_addr);
- enable_clock_r5();
- release_r5_reset(SPLIT);
- dcache_disable();
- write_tcm_boot_trampoline(boot_addr_uniq);
- dcache_enable();
- set_r5_halt_mode(RELEASE, SPLIT);
- } else {
- printf("Unsupported mode\n");
- return 1;
- }
- }
- return 0;
- }
|