xref: /linux/Documentation/arch/arm/zte/zx297520v3.rst (revision efe86f088f48f18c27b648e5724048947f3b7fb4)
1.. SPDX-License-Identifier: GPL-2.0-only
2
3====================================
4Booting Linux on ZTE zx297520v3 SoCs
5====================================
6
7Author:	Stefan Dösinger
8
9Date  : 27 Jan 2026
10
111. Hardware description
12---------------------------
13Zx297520v3 SoCs use a 64-bit capable Cortex-A53 CPU and GICv3, although they
14run in arm32 mode only. The CPU has support EL3, but no hypervisor (EL2) and
15it seems to lack VFP and NEON.
16
17The SoC is used in a number of cheap LTE to WiFi routers, both battery powered
18MiFis and stationary CPEs. In addition to the CPU these devices usually have
1964 MB Ram (although some is shared with the LTE chip), 128 MB NAND flash, an
20SDIO connected RTL8192-type Wifi chip limited to 2.4 ghz operation, USB 2,
21and buttons. Devices with as low as 32 MB or as high as 128 MB ram exist, as
22do devices with 8 or 16 MB of NOR flash.
23
24Some devices, especially the stationary ones, have 100 mbit Ethernet and an
25Ethernet switch.
26
27Usually the devices have LEDs for status indication, although some have SPI or
28I2C connected displays.
29
30Some have an SD card slot. If it exists, it is a better choice for the root
31file system because it easily outperforms the built-in NAND.
32
33The LTE interface runs on a separate DSP called ZSP880. It is probably derived
34from LSI ZSPs and has an undocumented instruction set. The ZSP communicates
35with the main CPU via SRAM and DRAM and a mailbox hardware that can generate
36IRQs on either ends.
37
38There is also a Cortex M0 CPU, which is responsible for early HW initialization
39and starting the Cortex A53 CPU. It does not have any essential purpose once
40U-Boot is started. An SRAM-based handover protocol exists to run custom code on
41this CPU.
42
432. Booting via USB
44---------------------------
45
46The Boot ROM has support for booting custom code via USB. This mode can be
47entered by connecting a Boot PIN to GND or by modifying the third byte on NAND
48(set it to anything other than 0x5A aka 'Z'). A free software tool to start
49custom U-Boot and kernels can be found here:
50
51https://github.com/zx297520v3-mainline/zx297520v3-loader
52
53If USB download mode is entered but no boot commands are sent through USB, the
54device will proceed to boot normally after a few seconds. It is therefore
55possible to enable USB boot permanently and still leave the default boot files
56in place.
57
58https://github.com/zx297520v3-mainline/u-boot-mainline
59
60Contains an U-Boot version that can be used with the USB loader and sets up the
61CPU and interrupt controller to comply with Linux's booting requirements.
62
633. Building for built-in U-Boot
64-------------------------------
65The devices come with an ancient U-Boot that loads legacy uImages from NAND and
66boots them without a chance for the user to interrupt. The images are stored in
67files ap_cpuap.bin and ap_recovery.bin on a jffs2 partition named imagefs,
68usually mtd4. A file named "fotaflag" switches between the two modes.
69
70In addition to the uImage header, those files have a 384-byte signature header,
71which is used for authenticating the images on some devices. Most devices have
72this authentication disabled and it is enough to pad the uImage files with 384
73zero bytes.
74
75Builtin U-Boot also poorly sets up the CPU. Read the next section for details
76on this. It has no support for loading DTBs, so CONFIG_ARM_APPENDED_DTB is
77needed.
78
79So to build an image that boots from NAND the following steps are necessary:
80
811) Patch the assembly code from section 3 into arch/arm/kernel/head.S.
822) make zx29_defconfig
833) make [-j x]
844) cat arch/arm/boot/zImage arch/arm/boot/dts/zte/[device].dtb > kernel+dtb
855) mkimage -A arm -O linux -T kernel -C none -a 0x20008000 -d kernel+dtb uimg
866) dd if=/dev/zero bs=1 count=384 of=ap_recovery.bin
877) cat uimg >> ap_recovery.bin
888) Place this file onto imagefs on the device. Delete ap_cpuap.bin if the
89   free space is not enough.
909) Create the file fotaflag: echo -n FOTA-RECOVERY > fotaflag
91
92For development, booting ap_recovery.bin is recommended because the normal boot
93mode arms the watchdog before starting the kernel.
94
954. CPU and GIC Setup
96---------------------------
97
98Generally CPU and GICv3 need to be set up according to the requirements spelled
99out in Documentation/arch/arm64/booting.rst. For zx297520v3 this means:
100
1011. GICD_CTLR.DS=1 to disable GIC security
1022. Enable access to ICC_SRE
1033. Disable trapping IRQs into monitor mode
1044. Configure EL2 and below to run in insecure mode.
1055. Configure timer PPIs to active-low.
106
107The kernel sources provided by ZTE do not boot either (interrupts do not work
108at all). They are incomplete in other aspects too, so it is assumed that there
109is some workaround similar to the one described in this document somewhere in
110the binary blobs.
111
112The assembly code below is given as an example of how to achieve this:
113
114::
115
116 #include <linux/irqchip/arm-gic-v3.h>
117 #include <asm/assembler.h>
118 #include <asm/cp15.h>
119
120 @ Detect sane bootloaders and skip the hack
121 ldr	r3, =0xf2000000
122 ldr	r3, [r3]
123 ldr	r4, =(GICD_CTLR_ARE_NS | GICD_CTLR_DS)
124 cmp	r3, r4
125 beq	skip_zx_hack
126 @ This allows EL1 to handle ints hat are normally handled by EL2/3.
127 ldr	r3, =0xf2000000
128 str     r4, [r3]
129
130 cps     #MON_MODE
131
132 @ Work in non-secure physical address space: SCR_EL3.NS = 1. At least the UART
133 @ seems to respond only to non-secure addresses. I have taken insipiration from
134 @ Raspberry pi's armstub7.S here.
135 mov	r3, #0x131			@ non-secure, Make F, A bits in CPSR writeable
136 @ Allow hypervisor call.
137 mcr     p15, 0, r3, c1, c1, 0
138
139 @ AP_PPI_MODE_REG: Configure timer PPIs (10, 11, 13, 14) to active-low.
140 ldr	r3, =0xF22020a8
141 ldr	r4, =0x50
142 str	r4, [r3]
143 ldr	r3, =0xF22020ac
144 ldr	r4, =0x14
145 str	r4, [r3]
146
147 @ Enable EL2 access to ICC_SRE (bit 3, ICC_SRE_EL3.Enable). Enable system reg
148 @ access to GICv3 registers (bit 0, ICC_SRE_EL3.SRE) for EL1 and EL3.
149 mrc	p15, 6, r3, c12, c12, 5         @ ICC_SRE_EL3
150 orr	r3, #0x9                        @ FIXME: No defines for SRE_EL3 values?
151 mcr	p15, 6, r3, c12, c12, 5
152 mrc	p15, 0, r3, c12, c12, 5         @ ICC_SRE_EL1
153 orr	r3, #(ICC_SRE_EL1_SRE)
154 mcr	p15, 0, r3, c12, c12, 5
155
156 @ Like ICC_SRE_EL3, enable EL1 access to ICC_SRE and system register access
157 @ for EL2.
158 mrc	p15, 4, r3, c12, c9, 5          @ ICC_SRE_EL2 aka ICC_HSRE
159 orr	r3, r3, #(ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE)
160 mcr	p15, 4, r3, c12, c9, 5
161 isb
162
163 @ Back to SVC mode
164 cps	#SVC_MODE
165 skip_zx_hack:
166
167