arisc_off.S 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # turn_off_core.S
  2. #
  3. # Copyright (c) 2018, Andre Przywara <osp@andrep.de>
  4. # SPDX-License-Identifier: BSD-3-Clause
  5. #
  6. # OpenRISC assembly to turn off an ARM core on an Allwinner SoC from
  7. # the arisc management controller.
  8. # Generate a binary representation with:
  9. # $ or1k-elf-as -c -o turn_off_core.o turn_off_core.S
  10. # $ or1k-elf-objcopy -O binary --reverse-bytes=4 turn_off_core.o \
  11. # turn_off_core.bin
  12. # The encoded instructions go into an array defined in
  13. # plat/allwinner/sun50i_*/include/core_off_arisc.h, to be handed off to
  14. # the arisc processor.
  15. #
  16. # This routine is meant to be called directly from arisc reset (put the
  17. # start address in the reset vector), to be actually triggered by that
  18. # very ARM core to be turned off.
  19. # It expects the core number presented as a mask in the upper half of
  20. # r3, so to be patched in the lower 16 bits of the first instruction,
  21. # overwriting the 0 in this code here.
  22. # The code will do the following:
  23. # - Read the C_CPU_STATUS register, which contains the status of the WFI
  24. # lines of each of the four A53 cores.
  25. # - Loop until the core in question reaches WFI.
  26. # - Using that mask, activate the core output clamps by setting the
  27. # respective core bit in CPUX_PWROFF_GATING_REG (0x1f01500).
  28. # Note that the clamp for core 0 covers more than just the core, activating
  29. # it hangs the whole system. So we skip this step for core 0.
  30. # - Using the negated mask, assert the core's reset line by clearing the
  31. # respective bit in C_RST_CTRL (0x1f01c30).
  32. # - Finally turn off the core's power switch by writing 0xff to the
  33. # respective CPUx_PWR_SWITCH_REG (0x1f01540 ff.)
  34. # - Assert the arisc's own reset to end execution.
  35. # This also signals other arisc users that the chip is free again.
  36. # So in C this would look like:
  37. # while (!(readl(0x1700030) & (1U << core_nr)))
  38. # ;
  39. # if (core_nr != 0)
  40. # writel(readl(0x1f01500) | (1U << core_nr), 0x1f01500);
  41. # writel(readl(0x1f01c30) & ~(1U << core_nr), 0x1f01c30);
  42. # writel(0xff, 0x1f01540 + (core_nr * 4));
  43. # (using A64/H5 addresses)
  44. .text
  45. _start:
  46. l.movhi r3, 0 # FIXUP! with core mask
  47. l.movhi r0, 0 # clear r0
  48. l.movhi r13, 0x170 # r13: CPU_CFG_BASE=0x01700000
  49. wait_wfi:
  50. l.lwz r5, 0x30(r13) # load C_CPU_STATUS
  51. l.and r5, r5, r3 # mask requested core
  52. l.sfeq r5, r0 # is it not yet in WFI?
  53. l.bf wait_wfi # try again
  54. l.srli r6, r3, 16 # move mask to lower 16 bits
  55. l.sfeqi r6, 1 # core 0 is special
  56. l.bf 1f # don't touch the bit for core 0
  57. l.movhi r13, 0x1f0 # address of R_CPUCFG (delay)
  58. l.lwz r5, 0x1500(r13) # core output clamps
  59. l.or r5, r5, r6 # set bit to ...
  60. l.sw 0x1500(r13), r5 # ... activate for our core
  61. 1: l.lwz r5, 0x1c30(r13) # CPU power-on reset
  62. l.xori r6, r6, -1 # negate core mask
  63. l.and r5, r5, r6 # clear bit to ...
  64. l.sw 0x1c30(r13), r5 # ... assert for our core
  65. l.ff1 r6, r3 # get core number from high mask
  66. l.addi r6, r6, -17 # convert to 0-3
  67. l.slli r6, r6, 2 # r5: core number*4 (0-12)
  68. l.add r6, r6, r13 # add to base address
  69. l.ori r5, r0, 0xff # 0xff means all switches off
  70. l.sw 0x1540(r6), r5 # core power switch registers
  71. reset: l.sw 0x1c00(r13),r0 # pull down our own reset line
  72. l.j reset # just in case ....
  73. l.nop 0x0 # (delay slot)
  74. # same as above, but with the MMIO addresses matching the H6 SoC
  75. _start_h6:
  76. l.movhi r3, 0 # FIXUP! with core mask
  77. l.movhi r0, 0 # clear r0
  78. l.movhi r13, 0x901 # r13: CPU_CFG_BASE=0x09010000
  79. 1:
  80. l.lwz r5, 0x80(r13) # load C_CPU_STATUS
  81. l.and r5, r5, r3 # mask requested core
  82. l.sfeq r5, r0 # is it not yet in WFI?
  83. l.bf 1b # try again
  84. l.srli r6, r3, 16 # move mask to lower 16 bits(ds)
  85. l.sfeqi r6, 1 # core 0 is special
  86. l.bf 1f # don't touch the bit for core 0
  87. l.movhi r13, 0x700 # address of R_CPUCFG (ds)
  88. l.lwz r5, 0x0444(r13) # core output clamps
  89. l.or r5, r5, r6 # set bit to ...
  90. l.sw 0x0444(r13), r5 # ... activate for our core
  91. 1: l.lwz r5, 0x0440(r13) # CPU power-on reset
  92. l.xori r6, r6, -1 # negate core mask
  93. l.and r5, r5, r6 # clear bit to ...
  94. l.sw 0x0440(r13), r5 # ... assert for our core
  95. l.ff1 r6, r3 # get core number from high mask
  96. l.addi r6, r6, -17 # convert to 0-3
  97. l.slli r6, r6, 2 # r5: core number*4 (0-12)
  98. l.add r6, r6, r13 # add to base address
  99. l.ori r5, r0, 0xff # 0xff means all switches off
  100. l.sw 0x0450(r6), r5 # core power switch registers
  101. 1: l.sw 0x0400(r13),r0 # pull down our own reset line
  102. l.j 1b # just in case ...
  103. l.nop 0x0 # (delay slot)