blob: ed10832c981445e2e96f0d2d65cf6b59033ddc27 [file] [log] [blame]
Andre Przywara6d0b81b2018-09-28 00:43:32 +01001# 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
45.text
46_start:
47 l.movhi r3, 0 # FIXUP! with core mask
48 l.movhi r0, 0 # clear r0
49 l.movhi r13, 0x170 # r13: CPU_CFG_BASE=0x01700000
50wait_wfi:
51 l.lwz r5, 0x30(r13) # load C_CPU_STATUS
52 l.and r5, r5, r3 # mask requested core
53 l.sfeq r5, r0 # is it not yet in WFI?
54 l.bf wait_wfi # try again
55
56 l.srli r6, r3, 16 # move mask to lower 16 bits
57 l.sfeqi r6, 1 # core 0 is special
58 l.bf 1f # don't touch the bit for core 0
59 l.movhi r13, 0x1f0 # address of R_CPUCFG (delay)
60 l.lwz r5, 0x1500(r13) # core output clamps
61 l.or r5, r5, r6 # set bit to ...
62 l.sw 0x1500(r13), r5 # ... activate for our core
63
641: l.lwz r5, 0x1c30(r13) # CPU power-on reset
65 l.xori r6, r6, -1 # negate core mask
66 l.and r5, r5, r6 # clear bit to ...
67 l.sw 0x1c30(r13), r5 # ... assert for our core
68
69 l.ff1 r6, r3 # get core number from high mask
70 l.addi r6, r6, -17 # convert to 0-3
71 l.slli r6, r6, 2 # r5: core number*4 (0-12)
72 l.add r6, r6, r13 # add to base address
73 l.ori r5, r0, 0xff # 0xff means all switches off
74 l.sw 0x1540(r6), r5 # core power switch registers
75
76reset: l.sw 0x1c00(r13),r0 # pull down our own reset line
77
78 l.j reset # just in case ....
79 l.nop 0x0 # (delay slot)
80
81# same as above, but with the MMIO addresses matching the H6 SoC
82_start_h6:
83 l.movhi r3, 0 # FIXUP! with core mask
84 l.movhi r0, 0 # clear r0
85 l.movhi r13, 0x901 # r13: CPU_CFG_BASE=0x09010000
861:
87 l.lwz r5, 0x80(r13) # load C_CPU_STATUS
88 l.and r5, r5, r3 # mask requested core
89 l.sfeq r5, r0 # is it not yet in WFI?
90 l.bf 1b # try again
91
92 l.srli r6, r3, 16 # move mask to lower 16 bits(ds)
93 l.sfeqi r6, 1 # core 0 is special
94 l.bf 1f # don't touch the bit for core 0
95 l.movhi r13, 0x700 # address of R_CPUCFG (ds)
96 l.lwz r5, 0x0444(r13) # core output clamps
97 l.or r5, r5, r6 # set bit to ...
98 l.sw 0x0444(r13), r5 # ... activate for our core
99
1001: l.lwz r5, 0x0440(r13) # CPU power-on reset
101 l.xori r6, r6, -1 # negate core mask
102 l.and r5, r5, r6 # clear bit to ...
103 l.sw 0x0440(r13), r5 # ... assert for our core
104
105 l.ff1 r6, r3 # get core number from high mask
106 l.addi r6, r6, -17 # convert to 0-3
107 l.slli r6, r6, 2 # r5: core number*4 (0-12)
108 l.add r6, r6, r13 # add to base address
109 l.ori r5, r0, 0xff # 0xff means all switches off
110 l.sw 0x0450(r6), r5 # core power switch registers
111
1121: l.sw 0x0400(r13),r0 # pull down our own reset line
113
114 l.j 1b # just in case ...
115 l.nop 0x0 # (delay slot)