diff --git a/CLAUDE.md b/CLAUDE.md index f37ea7350711..6c78d023d384 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -108,35 +108,27 @@ The kernel still needs the blob (see "Hand-off to the kernel"). `0x60004004` (128 vs 64 MiB). `dram_init()` reads the same word back. - **Byte order.** The flash controller packs bytes MSB first. U-Boot, the ROM and the vendor kernel all move whole little-endian words through it, so - the chip holds every 32-bit word byte-swapped, and a camera dump reads as - big-endian ("GK7101" in a hex editor). - - `output/u-boot--nor.bin` is **in chip order**: one file for every - way it gets onto a camera. - - A programmer writes it as it is; qemu takes it as `flash-file=` as it - is. - - `sf write` at offset 0 of a buffer starting with the byte-swapped magic - swaps it back first. The vendor U-Boot does this (`check_magic_number()` - in its `gk7101_sflash.c`), and so does `gk_sflash.c`. `run ub` from - either bootloader therefore writes exactly the bytes a programmer - would. A CPU-order image (the SDK's prebuilts) is written unchanged. - - `gk_sflash.c` swaps the boot image's span on read as well (the image - found at offset 0 at probe, or the one last written there). Every - caller (`sf read`, SD recovery's "already on the flash" check) sees - the boot image as the file. Everything past it is the controller's - plain round trip. - - A whole-chip dump in chip order (a programmer's) restores with one - `sf write` at 0: a write at 0 that starts with the swapped magic is - swapped over its whole length. `sf update` splits it into sectors and - only the boot image comes out right. `sf read` of the whole chip is - not a dump either: the boot image in chip order, the rest in CPU - order. - - Exception: the first release (2026-10-18) wrote CPU-order images and - its `gk_sflash.c` has no swap check. `run ub` on a camera running it - would write a chip-order image swapped twice and brick it. Upgrade - those cameras with a programmer. - - Anything else written to flash (kernel, rootfs, environment) is in CPU - order through the drivers; only a raw dump or programmer image of the - whole chip is swapped. + the chip holds every 32-bit word byte-swapped, everywhere: boot image, + env, kernel, rootfs. A programmer's dump reads as big-endian ("GK7101" in + a hex editor, "sqsh" for a squashfs). + - **Every published file is in CPU order**: `u-boot--nor.bin`, as + `gk710x-image.py` writes it, like OpenIPC/firmware's uImage and rootfs. + They load by tftp, mmc or usb and go to flash with `sf write` or SD + recovery as they are. Through the drivers the flash reads and writes in + CPU order; `gk_sflash.c` never swaps a read. + - **Programmer and qemu `flash-file=` images are in chip order**, the + whole image: lay the CPU-order files out at their offsets, then swap + every word, `objcopy -I binary -O binary --reverse-bytes=4 full.bin + programmer.bin` (the openipc branch's README has the full recipe). The + same command turns a programmer's dump back into CPU order. Writing + the files with a programmer as they are puts them on the chip + unswapped: the ROM finds no boot header, U-Boot no kernel. + - A programmer image written through the driver anyway (`sf write`, SD + recovery) is recognised by the swapped magic at 0 and swapped back: the + boot image however the caller splits it, the whole write when one write + covers more. `sf update` of a whole chip-order image therefore only gets + the boot image right. The vendor U-Boot's flash write does the same + (`check_magic_number()` in its `gk7101_sflash.c`). - `gk_sflash.c` keeps the word mapping for unaligned offsets as well: whole words only, writes padded with `0xff`. @@ -272,9 +264,8 @@ bash build.sh gk7102 # one or more SoCs (CROSS_COMPILE defaults to arm-li The emulator is widgetii/qemu-hisilicon, machines `gk7101` and `gk7102` (`docs/goke-gk710x.md` there). `-M gk7102,flash-file=` does the boot -ROM's job from the header, so it boots exactly the flashed bytes. The -release image goes in as it is; firmware parts written behind it (uImage, -rootfs) must be word-swapped, since the chip holds them that way. +ROM's job from the header, so it boots exactly the flashed bytes: a +programmer image (the whole file word-swapped, see "Byte order"). - Guest `reset` re-enters the U-Boot qemu loaded at start-up, not what is in flash now. To check a newly written bootloader, start qemu again on the diff --git a/drivers/mtd/spi/gk_sflash.c b/drivers/mtd/spi/gk_sflash.c index 6a3b36839ba7..58ee6a784003 100644 --- a/drivers/mtd/spi/gk_sflash.c +++ b/drivers/mtd/spi/gk_sflash.c @@ -160,30 +160,28 @@ static int sf_program(u32 addr, const u8 *buf, unsigned int words) #define GK_BOOT_MAGIC 0x474b3731 /* - * The boot ROM reads the boot image as raw chip bytes, while everything - * read or written through the controller is packed MSB first: a 32-bit - * word goes to the chip byte-swapped and comes back swapped again. For the - * kernel, the rootfs and the environment that round trip is invisible. - * For the boot image it is not: a programmer writes it in the chip's - * order, and the vendor U-Boot's flash write recognises such an image by - * its byte-swapped magic and swaps it back (check_magic_number() in its - * gk7101_sflash.c). + * The controller packs bytes MSB first: every 32-bit word goes to the chip + * byte-swapped and comes back swapped again, so through this driver the + * flash reads and writes in CPU order, the order of every published file + * (U-Boot, kernel, rootfs) and of what tftp, mmc or usb load. The chip + * itself, which the boot ROM and a programmer see, holds every word + * swapped; a programmer image is the files laid out and every word + * swapped, and a dump swapped back is in CPU order. * - * This driver does the same, both ways, for every caller: from offset 0 - * to sf_swap_end -- header table plus the U-Boot length the header gives - * -- data is swapped on write and on read, so the boot image reads back - * as the file a programmer writes, byte for byte. The window is the image - * on the flash at probe, and a write at 0 moves it: one that starts with - * the swapped magic opens it as long as that image, however the caller - * splits the rest; any other write at 0 closes it. - * - * A write at 0 that starts with the swapped magic and runs past the boot - * image -- a programmer's whole-chip dump in one sf write, or recovery - * image -- is chip order throughout, and is swapped over its whole - * length. Split into sectors (sf update), only its first sector is seen - * at 0, so only the boot image is swapped back. + * A programmer image may still be written through here (sf write, SD + * recovery). A write at 0 that starts with the swapped boot magic is + * taken for one and swapped back: over sf_swap_end -- header table plus + * the U-Boot length the header gives -- however the caller splits the + * rest, and over its whole length when that one write is longer (a + * whole-chip image). Any other write at 0 closes the window, and so does + * a write elsewhere that does not start where the last one ended: the + * window carries over only the pieces of one image written in a row, so a + * later sf update whose unchanged first sector is skipped does not inherit + * it. The vendor U-Boot's flash write does the same swap + * (check_magic_number() in its gk7101_sflash.c). Reads are never swapped. */ static u32 sf_swap_end; +static loff_t sf_swap_next; /* where the last write ended */ /* The length of a chip-order boot image starting at buf, or 0 */ 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) static void sf_swap_detect(loff_t to, size_t len, const u_char *buf) { - if (to) + if (to) { + if (to != sf_swap_next) + sf_swap_end = 0; return; + } sf_swap_end = sf_boot_len(buf, len); if (sf_swap_end) 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, u32 w = readl(SF_DATA); unsigned int n = min_t(size_t, len, 4 - skip); - if (addr < sf_swap_end) - w = swab32(w); - addr += 4; - if (!skip && n == 4) { put_unaligned_le32(w, buf); } else { @@ -275,6 +272,7 @@ static int gk_sf_write(struct mtd_info *mtd, loff_t to, size_t len, if (to + len > mtd->size) return -EINVAL; sf_swap_detect(to, len, buf); + sf_swap_next = to + len; end = !to && sf_swap_end ? max_t(u32, sf_swap_end, len) : sf_swap_end; *retlen = 0; while (len) { @@ -320,21 +318,6 @@ static int gk_sf_erase(struct mtd_info *mtd, struct erase_info *instr) static struct spi_flash gk_flash; static int gk_announced; -/* The swap window over the boot image already on the flash */ -static void sf_swap_probe(u32 size) -{ - u8 hdr[SZ_2K]; - size_t n; - unsigned int i; - - sf_swap_end = 0; - gk_sf_read(&gk_flash.mtd, 0, sizeof(hdr), &n, hdr); - for (i = 0; i < sizeof(hdr); i += 4) - put_unaligned_le32(swab32(get_unaligned_le32(hdr + i)), - hdr + i); - sf_swap_end = min(sf_boot_len(hdr, sizeof(hdr)), size); -} - struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode) { @@ -376,9 +359,6 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, mtd->_write = gk_sf_write; mtd->_erase = gk_sf_erase; mtd->priv = flash; - /* Once: later writes at 0 keep the window up to date */ - if (!gk_announced) - sf_swap_probe(size); /* Once: the environment and common/openipc.c probe again and again */ if (!gk_announced++) diff --git a/openipc/gk710x-image.py b/openipc/gk710x-image.py index dd0369518f32..f2af31556fe1 100755 --- a/openipc/gk710x-image.py +++ b/openipc/gk710x-image.py @@ -21,11 +21,11 @@ words ("version:", "ddrtest:") and the table ("setup:", "rdcom:", "delay:"), as the header of the vendor image it came from has them. -The flash controller packs bytes MSB first, so the chip holds every 32-bit -word byte-swapped (drivers/mtd/spi/gk_sflash.c). The output is in that -chip order: a programmer writes it as it is, qemu takes it as flash, and -sf write -- the vendor U-Boot's and this one's -- recognises the swapped -magic at offset 0 and swaps it back. +The output is in CPU order, like every other published file: tftp, mmc or +usb load it and sf write puts it at 0. The chip holds every 32-bit word +byte-swapped (drivers/mtd/spi/gk_sflash.c), so a programmer, or qemu's +flash-file, needs every word swapped (the openipc branch's README shows +how). """ import re import struct @@ -78,8 +78,7 @@ def main(): sys.exit('%s: %d bytes, %d over the %d bytes before the environment' % (dst, len(image), len(image) - limit, limit)) with open(dst, 'wb') as f: - f.write(b''.join(image[i:i + 4][::-1] - for i in range(0, len(image), 4))) + f.write(image) if __name__ == '__main__':