mp.c 6.9 KB

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