Skip to content

Commit 76c9f5c

Browse files
authored
Merge pull request #50 from OpenIPC/gk710x/cpu-order
gk710x: publish U-Boot in CPU order, like every other file
2 parents ee357e8 + 11c6a8d commit 76c9f5c

3 files changed

Lines changed: 53 additions & 83 deletions

File tree

‎CLAUDE.md‎

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -108,35 +108,27 @@ The kernel still needs the blob (see "Hand-off to the kernel").
108108
`0x60004004` (128 vs 64 MiB). `dram_init()` reads the same word back.
109109
- **Byte order.** The flash controller packs bytes MSB first. U-Boot, the
110110
ROM and the vendor kernel all move whole little-endian words through it, so
111-
the chip holds every 32-bit word byte-swapped, and a camera dump reads as
112-
big-endian ("GK7101" in a hex editor).
113-
- `output/u-boot-<soc>-nor.bin` is **in chip order**: one file for every
114-
way it gets onto a camera.
115-
- A programmer writes it as it is; qemu takes it as `flash-file=` as it
116-
is.
117-
- `sf write` at offset 0 of a buffer starting with the byte-swapped magic
118-
swaps it back first. The vendor U-Boot does this (`check_magic_number()`
119-
in its `gk7101_sflash.c`), and so does `gk_sflash.c`. `run ub` from
120-
either bootloader therefore writes exactly the bytes a programmer
121-
would. A CPU-order image (the SDK's prebuilts) is written unchanged.
122-
- `gk_sflash.c` swaps the boot image's span on read as well (the image
123-
found at offset 0 at probe, or the one last written there). Every
124-
caller (`sf read`, SD recovery's "already on the flash" check) sees
125-
the boot image as the file. Everything past it is the controller's
126-
plain round trip.
127-
- A whole-chip dump in chip order (a programmer's) restores with one
128-
`sf write` at 0: a write at 0 that starts with the swapped magic is
129-
swapped over its whole length. `sf update` splits it into sectors and
130-
only the boot image comes out right. `sf read` of the whole chip is
131-
not a dump either: the boot image in chip order, the rest in CPU
132-
order.
133-
- Exception: the first release (2026-10-18) wrote CPU-order images and
134-
its `gk_sflash.c` has no swap check. `run ub` on a camera running it
135-
would write a chip-order image swapped twice and brick it. Upgrade
136-
those cameras with a programmer.
137-
- Anything else written to flash (kernel, rootfs, environment) is in CPU
138-
order through the drivers; only a raw dump or programmer image of the
139-
whole chip is swapped.
111+
the chip holds every 32-bit word byte-swapped, everywhere: boot image,
112+
env, kernel, rootfs. A programmer's dump reads as big-endian ("GK7101" in
113+
a hex editor, "sqsh" for a squashfs).
114+
- **Every published file is in CPU order**: `u-boot-<soc>-nor.bin`, as
115+
`gk710x-image.py` writes it, like OpenIPC/firmware's uImage and rootfs.
116+
They load by tftp, mmc or usb and go to flash with `sf write` or SD
117+
recovery as they are. Through the drivers the flash reads and writes in
118+
CPU order; `gk_sflash.c` never swaps a read.
119+
- **Programmer and qemu `flash-file=` images are in chip order**, the
120+
whole image: lay the CPU-order files out at their offsets, then swap
121+
every word, `objcopy -I binary -O binary --reverse-bytes=4 full.bin
122+
programmer.bin` (the openipc branch's README has the full recipe). The
123+
same command turns a programmer's dump back into CPU order. Writing
124+
the files with a programmer as they are puts them on the chip
125+
unswapped: the ROM finds no boot header, U-Boot no kernel.
126+
- A programmer image written through the driver anyway (`sf write`, SD
127+
recovery) is recognised by the swapped magic at 0 and swapped back: the
128+
boot image however the caller splits it, the whole write when one write
129+
covers more. `sf update` of a whole chip-order image therefore only gets
130+
the boot image right. The vendor U-Boot's flash write does the same
131+
(`check_magic_number()` in its `gk7101_sflash.c`).
140132
- `gk_sflash.c` keeps the word mapping for unaligned offsets as well:
141133
whole words only, writes padded with `0xff`.
142134

@@ -272,9 +264,8 @@ bash build.sh gk7102 # one or more SoCs (CROSS_COMPILE defaults to arm-li
272264

273265
The emulator is widgetii/qemu-hisilicon, machines `gk7101` and `gk7102`
274266
(`docs/goke-gk710x.md` there). `-M gk7102,flash-file=<image>` does the boot
275-
ROM's job from the header, so it boots exactly the flashed bytes. The
276-
release image goes in as it is; firmware parts written behind it (uImage,
277-
rootfs) must be word-swapped, since the chip holds them that way.
267+
ROM's job from the header, so it boots exactly the flashed bytes: a
268+
programmer image (the whole file word-swapped, see "Byte order").
278269

279270
- Guest `reset` re-enters the U-Boot qemu loaded at start-up, not what is in
280271
flash now. To check a newly written bootloader, start qemu again on the

‎drivers/mtd/spi/gk_sflash.c‎

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -160,30 +160,28 @@ static int sf_program(u32 addr, const u8 *buf, unsigned int words)
160160
#define GK_BOOT_MAGIC 0x474b3731
161161

162162
/*
163-
* The boot ROM reads the boot image as raw chip bytes, while everything
164-
* read or written through the controller is packed MSB first: a 32-bit
165-
* word goes to the chip byte-swapped and comes back swapped again. For the
166-
* kernel, the rootfs and the environment that round trip is invisible.
167-
* For the boot image it is not: a programmer writes it in the chip's
168-
* order, and the vendor U-Boot's flash write recognises such an image by
169-
* its byte-swapped magic and swaps it back (check_magic_number() in its
170-
* gk7101_sflash.c).
163+
* The controller packs bytes MSB first: every 32-bit word goes to the chip
164+
* byte-swapped and comes back swapped again, so through this driver the
165+
* flash reads and writes in CPU order, the order of every published file
166+
* (U-Boot, kernel, rootfs) and of what tftp, mmc or usb load. The chip
167+
* itself, which the boot ROM and a programmer see, holds every word
168+
* swapped; a programmer image is the files laid out and every word
169+
* swapped, and a dump swapped back is in CPU order.
171170
*
172-
* This driver does the same, both ways, for every caller: from offset 0
173-
* to sf_swap_end -- header table plus the U-Boot length the header gives
174-
* -- data is swapped on write and on read, so the boot image reads back
175-
* as the file a programmer writes, byte for byte. The window is the image
176-
* on the flash at probe, and a write at 0 moves it: one that starts with
177-
* the swapped magic opens it as long as that image, however the caller
178-
* splits the rest; any other write at 0 closes it.
179-
*
180-
* A write at 0 that starts with the swapped magic and runs past the boot
181-
* image -- a programmer's whole-chip dump in one sf write, or recovery
182-
* image -- is chip order throughout, and is swapped over its whole
183-
* length. Split into sectors (sf update), only its first sector is seen
184-
* at 0, so only the boot image is swapped back.
171+
* A programmer image may still be written through here (sf write, SD
172+
* recovery). A write at 0 that starts with the swapped boot magic is
173+
* taken for one and swapped back: over sf_swap_end -- header table plus
174+
* the U-Boot length the header gives -- however the caller splits the
175+
* rest, and over its whole length when that one write is longer (a
176+
* whole-chip image). Any other write at 0 closes the window, and so does
177+
* a write elsewhere that does not start where the last one ended: the
178+
* window carries over only the pieces of one image written in a row, so a
179+
* later sf update whose unchanged first sector is skipped does not inherit
180+
* it. The vendor U-Boot's flash write does the same swap
181+
* (check_magic_number() in its gk7101_sflash.c). Reads are never swapped.
185182
*/
186183
static u32 sf_swap_end;
184+
static loff_t sf_swap_next; /* where the last write ended */
187185

188186
/* The length of a chip-order boot image starting at buf, or 0 */
189187
static u32 sf_boot_len(const u_char *buf, size_t len)
@@ -213,8 +211,11 @@ static u32 sf_boot_len(const u_char *buf, size_t len)
213211

214212
static void sf_swap_detect(loff_t to, size_t len, const u_char *buf)
215213
{
216-
if (to)
214+
if (to) {
215+
if (to != sf_swap_next)
216+
sf_swap_end = 0;
217217
return;
218+
}
218219
sf_swap_end = sf_boot_len(buf, len);
219220
if (sf_swap_end)
220221
printf("SF: boot image in the chip's byte order, swapping it back\n");
@@ -239,10 +240,6 @@ static int gk_sf_read(struct mtd_info *mtd, loff_t from, size_t len,
239240
u32 w = readl(SF_DATA);
240241
unsigned int n = min_t(size_t, len, 4 - skip);
241242

242-
if (addr < sf_swap_end)
243-
w = swab32(w);
244-
addr += 4;
245-
246243
if (!skip && n == 4) {
247244
put_unaligned_le32(w, buf);
248245
} else {
@@ -275,6 +272,7 @@ static int gk_sf_write(struct mtd_info *mtd, loff_t to, size_t len,
275272
if (to + len > mtd->size)
276273
return -EINVAL;
277274
sf_swap_detect(to, len, buf);
275+
sf_swap_next = to + len;
278276
end = !to && sf_swap_end ? max_t(u32, sf_swap_end, len) : sf_swap_end;
279277
*retlen = 0;
280278
while (len) {
@@ -320,21 +318,6 @@ static int gk_sf_erase(struct mtd_info *mtd, struct erase_info *instr)
320318
static struct spi_flash gk_flash;
321319
static int gk_announced;
322320

323-
/* The swap window over the boot image already on the flash */
324-
static void sf_swap_probe(u32 size)
325-
{
326-
u8 hdr[SZ_2K];
327-
size_t n;
328-
unsigned int i;
329-
330-
sf_swap_end = 0;
331-
gk_sf_read(&gk_flash.mtd, 0, sizeof(hdr), &n, hdr);
332-
for (i = 0; i < sizeof(hdr); i += 4)
333-
put_unaligned_le32(swab32(get_unaligned_le32(hdr + i)),
334-
hdr + i);
335-
sf_swap_end = min(sf_boot_len(hdr, sizeof(hdr)), size);
336-
}
337-
338321
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
339322
unsigned int max_hz, unsigned int spi_mode)
340323
{
@@ -376,9 +359,6 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
376359
mtd->_write = gk_sf_write;
377360
mtd->_erase = gk_sf_erase;
378361
mtd->priv = flash;
379-
/* Once: later writes at 0 keep the window up to date */
380-
if (!gk_announced)
381-
sf_swap_probe(size);
382362

383363
/* Once: the environment and common/openipc.c probe again and again */
384364
if (!gk_announced++)

‎openipc/gk710x-image.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
words ("version:", "ddrtest:") and the table ("setup:", "rdcom:",
2222
"delay:"), as the header of the vendor image it came from has them.
2323
24-
The flash controller packs bytes MSB first, so the chip holds every 32-bit
25-
word byte-swapped (drivers/mtd/spi/gk_sflash.c). The output is in that
26-
chip order: a programmer writes it as it is, qemu takes it as flash, and
27-
sf write -- the vendor U-Boot's and this one's -- recognises the swapped
28-
magic at offset 0 and swaps it back.
24+
The output is in CPU order, like every other published file: tftp, mmc or
25+
usb load it and sf write puts it at 0. The chip holds every 32-bit word
26+
byte-swapped (drivers/mtd/spi/gk_sflash.c), so a programmer, or qemu's
27+
flash-file, needs every word swapped (the openipc branch's README shows
28+
how).
2929
"""
3030
import re
3131
import struct
@@ -78,8 +78,7 @@ def main():
7878
sys.exit('%s: %d bytes, %d over the %d bytes before the environment'
7979
% (dst, len(image), len(image) - limit, limit))
8080
with open(dst, 'wb') as f:
81-
f.write(b''.join(image[i:i + 4][::-1]
82-
for i in range(0, len(image), 4)))
81+
f.write(image)
8382

8483

8584
if __name__ == '__main__':

0 commit comments

Comments
 (0)