From faa4907c0b291bc40092646f7f72d889f37a648b Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov <7954832+dimerr@users.noreply.github.com> Date: Thu, 22 Oct 2026 08:53:09 +0000 Subject: [PATCH] gk710x: images in CPU order; how to make a programmer image openipc-gk710x now publishes u-boot--nor.bin in CPU order, like OpenIPC's uImage and rootfs, so all three load by tftp, mmc or usb and go on with sf write. README: why a programmer needs the whole flash image word-swapped and how to make one with dd + objcopy --reverse-bytes=4 (or perl), and a dump back; U-Boot has started on GK7102C cameras; SD recovery. build-gk710x.yml's smoke step already swaps a CPU-order image into chip order for qemu's flash file; its comments say so now. The README recipe, run as it is: the 8 MiB programmer image equals the three files laid out and word-swapped, U-Boot alone and the dump round trip likewise, and perl gives the same bytes as objcopy. --- .github/workflows/build-gk710x.yml | 10 +++---- README.md | 46 ++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-gk710x.yml b/.github/workflows/build-gk710x.yml index d5bcfd1f1a07..9c6ed187384e 100644 --- a/.github/workflows/build-gk710x.yml +++ b/.github/workflows/build-gk710x.yml @@ -169,10 +169,10 @@ jobs: # SoC is a hard gate on release. # # The flash controller packs bytes MSB first, so the chip holds every - # 32-bit word byte-swapped. openipc-gk710x builds its images in that chip - # order (the header reads "GK71"), as a programmer writes them, and they - # go into the flash file as they are; an image of an earlier build, in - # CPU order ("17KG"), is swapped into chip order first. The second boot + # 32-bit word byte-swapped. openipc-gk710x publishes its images in CPU + # order (the header reads "17KG"), and they are swapped into chip order, + # as a programmer image, for the flash file; an image of an earlier + # build, already in chip order ("GK71"), goes in as it is. The second boot # must then load the environment the first saved, which proves the # driver's writes land where its reads find them. qemu_smoke: @@ -220,7 +220,7 @@ jobs: import sys u = open(sys.argv[1], 'rb').read() if u[:4] == b'17KG': - print('CPU-order image: swapping it into chip order') + print('CPU-order image: swapped into chip order for the flash') u = b''.join(u[i:i + 4][::-1] for i in range(0, len(u), 4)) elif u[:4] != b'GK71': sys.exit('%s: no GK710x boot header' % sys.argv[1]) diff --git a/README.md b/README.md index 22eee7d87126..12f250db8340 100644 --- a/README.md +++ b/README.md @@ -104,12 +104,38 @@ boards). The boot ROM runs the DDR set-up listed in the image's header and copies U-Boot into DDR, so `u-boot--nor.bin` is the header and `u-boot.bin`, -written at flash offset 0. One file serves every way of installing it: it -is in the flash chip's own byte order, so a programmer writes it as it is, -and `sf write` -- the vendor bootloader's and this one's -- recognises that -order at offset 0 and swaps it back as it programs. A camera already -running the first release of this port (2026-10-18), whose `sf write` lacks -that check, has to be upgraded with a programmer. +written at flash offset 0. Like OpenIPC's `uImage` and `rootfs` for these +SoCs it is in the normal (CPU) byte order: load it by tftp, from an SD +card or a USB stick, and write it with `sf write` (or `run ub`). + +**Programmer images.** The flash controller swaps the bytes of every +32-bit word on the way to the chip and back, so the chip itself holds +every word reversed: U-Boot, environment, kernel and rootfs alike. A +programmer writes the chip directly, so it needs the whole flash image in +that order. Do not write the files with a programmer as they are, and do +not just concatenate them: lay them out at their offsets, then reverse +every 32-bit word of the whole image. + +```sh +# U-Boot alone +objcopy -I binary -O binary --reverse-bytes=4 \ + u-boot-gk7102-nor.bin u-boot-gk7102-programmer.bin + +# a full 8 MiB flash: U-Boot at 0, kernel at 0x50000, rootfs at 0x250000 +tr '\0' '\377' < /dev/zero | head -c 8M > full.bin +dd if=u-boot-gk7102-nor.bin of=full.bin conv=notrunc +dd if=uImage.gk7102 of=full.bin conv=notrunc bs=64k seek=5 +dd if=rootfs.squashfs.gk7102 of=full.bin conv=notrunc bs=64k seek=37 +objcopy -I binary -O binary --reverse-bytes=4 full.bin full-programmer.bin + +# a programmer's dump back into the normal order (what sf read shows) +objcopy -I binary -O binary --reverse-bytes=4 dump.bin dump-normal.bin +``` + +Without binutils, `perl -0777 -pe 's/(.)(.)(.)(.)/$4$3$2$1/gs' in > out` +does the same. qemu-hisilicon's `flash-file=` takes the programmer image. +A programmer image written through U-Boot anyway (`sf write` at 0, SD +recovery) is recognised and swapped back. The vendor kernel needs what the vendor U-Boot leaves it besides ATAGs: its HAL blob, memory layout words and the board's GPIO map, from which it @@ -118,8 +144,10 @@ vendor reference boards' default layout (rb-sc1035 v2.1, sc1045, imx225, ov9750, jxh42 v2.0, gc1024; GK7101 rb-ov2710 v2.2); `setenv gpiomap v1` selects the other one (rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222). -These images have so far run only on qemu-hisilicon's `gk7101` and -`gk7102` machines, not on a camera. SD card recovery is not enabled. +U-Boot has started on GK7102C cameras; the rest has run only on +qemu-hisilicon's machines. Without Ethernet (GK7102C cameras), recovery is +from an SD card: `*.img` files, each a uImage wrapper whose load address is +the flash offset its payload goes to. ```sh git clone --branch openipc-gk710x https://github.com/OpenIPC/u-boot.git @@ -230,7 +258,7 @@ same shape. It runs on pull requests to this branch that change it, on pushes and pull requests to `openipc-gk710x` (through that branch's `ci.yml`), and manually. Every SoC has a qemu-hisilicon machine model, so every image is smoke-tested: booted from an 8 MiB flash image holding it as -a programmer would write it, then a second time, which must load the +a programmer would write it (word-swapped), then a second time, which must load the environment the first boot saved. Its `release` input fills this repository's