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