1 /* 2 * (C) Copyright 2014 - 2015 Xilinx, Inc. 3 * Michal Simek <michal.simek@xilinx.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <asm/arch/hardware.h> 10 #include <asm/arch/sys_proto.h> 11 #include <asm/io.h> 12 13 #define LOCK 0 14 #define SPLIT 1 15 16 #define HALT 0 17 #define RELEASE 1 18 19 #define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF 20 #define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000 21 #define ZYNQMP_R5_LOVEC_ADDR 0x0 22 #define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01 23 #define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04 24 #define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08 25 #define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40 26 #define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10 27 28 #define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04 29 #define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01 30 #define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02 31 #define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000 32 33 #define ZYNQMP_TCM_START_ADDRESS 0xFFE00000 34 #define ZYNQMP_TCM_BOTH_SIZE 0x40000 35 36 #define ZYNQMP_CORE_APU0 0 37 #define ZYNQMP_CORE_APU3 3 38 39 #define ZYNQMP_MAX_CORES 6 40 41 int is_core_valid(unsigned int core) 42 { 43 if (core < ZYNQMP_MAX_CORES) 44 return 1; 45 46 return 0; 47 } 48 49 int cpu_reset(int nr) 50 { 51 puts("Feature is not implemented.\n"); 52 return 0; 53 } 54 55 static void set_r5_halt_mode(u8 halt, u8 mode) 56 { 57 u32 tmp; 58 59 tmp = readl(&rpu_base->rpu0_cfg); 60 if (halt == HALT) 61 tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK; 62 else 63 tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK; 64 writel(tmp, &rpu_base->rpu0_cfg); 65 66 if (mode == LOCK) { 67 tmp = readl(&rpu_base->rpu1_cfg); 68 if (halt == HALT) 69 tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK; 70 else 71 tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK; 72 writel(tmp, &rpu_base->rpu1_cfg); 73 } 74 } 75 76 static void set_r5_tcm_mode(u8 mode) 77 { 78 u32 tmp; 79 80 tmp = readl(&rpu_base->rpu_glbl_ctrl); 81 if (mode == LOCK) { 82 tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK; 83 tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK | 84 ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK; 85 } else { 86 tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK; 87 tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK | 88 ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK); 89 } 90 91 writel(tmp, &rpu_base->rpu_glbl_ctrl); 92 } 93 94 static void set_r5_reset(u8 mode) 95 { 96 u32 tmp; 97 98 tmp = readl(&crlapb_base->rst_lpd_top); 99 tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK | 100 ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK); 101 102 if (mode == LOCK) 103 tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK; 104 105 writel(tmp, &crlapb_base->rst_lpd_top); 106 } 107 108 static void release_r5_reset(u8 mode) 109 { 110 u32 tmp; 111 112 tmp = readl(&crlapb_base->rst_lpd_top); 113 tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK | 114 ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK); 115 116 if (mode == LOCK) 117 tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK; 118 119 writel(tmp, &crlapb_base->rst_lpd_top); 120 } 121 122 static void enable_clock_r5(void) 123 { 124 u32 tmp; 125 126 tmp = readl(&crlapb_base->cpu_r5_ctrl); 127 tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK; 128 writel(tmp, &crlapb_base->cpu_r5_ctrl); 129 130 /* Give some delay for clock 131 * to propogate */ 132 udelay(0x500); 133 } 134 135 int cpu_disable(int nr) 136 { 137 if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { 138 u32 val = readl(&crfapb_base->rst_fpd_apu); 139 val |= 1 << nr; 140 writel(val, &crfapb_base->rst_fpd_apu); 141 } else { 142 set_r5_reset(LOCK); 143 } 144 145 return 0; 146 } 147 148 int cpu_status(int nr) 149 { 150 if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { 151 u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8); 152 u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) + 153 nr * 8); 154 u32 val = readl(&crfapb_base->rst_fpd_apu); 155 val &= 1 << nr; 156 printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n", 157 nr, val ? "OFF" : "ON" , addr_high, addr_low); 158 } else { 159 u32 val = readl(&crlapb_base->rst_lpd_top); 160 val &= 1 << (nr - 4); 161 printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON"); 162 } 163 164 return 0; 165 } 166 167 static void set_r5_start(u8 high) 168 { 169 u32 tmp; 170 171 tmp = readl(&rpu_base->rpu0_cfg); 172 if (high) 173 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK; 174 else 175 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK; 176 writel(tmp, &rpu_base->rpu0_cfg); 177 178 tmp = readl(&rpu_base->rpu1_cfg); 179 if (high) 180 tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK; 181 else 182 tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK; 183 writel(tmp, &rpu_base->rpu1_cfg); 184 } 185 186 int cpu_release(int nr, int argc, char * const argv[]) 187 { 188 if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { 189 u64 boot_addr = simple_strtoull(argv[0], NULL, 16); 190 /* HIGH */ 191 writel((u32)(boot_addr >> 32), 192 ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8); 193 /* LOW */ 194 writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK), 195 ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8); 196 197 u32 val = readl(&crfapb_base->rst_fpd_apu); 198 val &= ~(1 << nr); 199 writel(val, &crfapb_base->rst_fpd_apu); 200 } else { 201 if (argc != 2) { 202 printf("Invalid number of arguments to release.\n"); 203 printf("<addr> <mode>-Start addr lockstep or split\n"); 204 return 1; 205 } 206 207 u32 boot_addr = simple_strtoul(argv[0], NULL, 16); 208 if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR || 209 boot_addr == ZYNQMP_R5_HIVEC_ADDR)) { 210 printf("Invalid starting address 0x%x\n", boot_addr); 211 printf("0 or 0xffff0000 are permitted\n"); 212 return 1; 213 } 214 215 if (!strncmp(argv[1], "lockstep", 8)) { 216 printf("R5 lockstep mode\n"); 217 set_r5_tcm_mode(LOCK); 218 set_r5_halt_mode(HALT, LOCK); 219 set_r5_start(boot_addr); 220 enable_clock_r5(); 221 release_r5_reset(LOCK); 222 set_r5_halt_mode(RELEASE, LOCK); 223 } else if (!strncmp(argv[1], "split", 5)) { 224 printf("R5 split mode\n"); 225 set_r5_tcm_mode(SPLIT); 226 set_r5_halt_mode(HALT, SPLIT); 227 enable_clock_r5(); 228 release_r5_reset(SPLIT); 229 set_r5_halt_mode(RELEASE, SPLIT); 230 } else { 231 printf("Unsupported mode\n"); 232 return 1; 233 } 234 } 235 236 return 0; 237 } 238