From 0e79a1825d392d25c4d7ee5523ce1492ef5d3489 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:45 +0000 Subject: [PATCH 01/10] net: let NETDEVICES go without DM_ETH NETDEVICES selected DM_ETH, so with CONFIG_DM off a board with a network driver failed to link on uclass and dev_get_priv references. Select it only when DM is on, as openipc-hisilicon and openipc-xm do, so the legacy designware_initialize() path still builds. --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6bbbadc5eef3..04ece297c8ac 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -94,7 +94,7 @@ config DSA_SANDBOX menuconfig NETDEVICES bool "Network device support" depends on NET - select DM_ETH + select DM_ETH if DM help You must select Y to enable any network device support Generally if you have any networking support this is a given From fcd0da6196020c5c163207535224bf5e0180a3c5 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:45 +0000 Subject: [PATCH 02/10] net: designware: use a board's MDIO bus when it registered one The non-DM designware_initialize() always registered an MDIO bus on the MAC's own MDIO lines, named after the device, and connected the PHY there. A PHY that is not on those lines could not be reached. Register the MAC's bus only if no bus of that name exists yet, so a board can supply its own first. Boards that do not are unchanged. The Goke GK710x needs it: its internal PHY's MII registers are memory mapped, not on MDIO. --- drivers/net/designware.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0e63f70934c0..ee23839033ab 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -694,7 +694,12 @@ int designware_initialize(ulong base_addr, u32 interface) priv->interface = interface; - dw_mdio_init(dev->name, priv->mac_regs_p); + /* + * A board whose PHY is not on the MAC's MDIO lines registers its own + * bus under the device's name first. + */ + if (!miiphy_get_dev_by_name(dev->name)) + dw_mdio_init(dev->name, priv->mac_regs_p); priv->bus = miiphy_get_dev_by_name(dev->name); return dw_phy_init(priv, dev); From 9df17433bda50a1c2c037de886da69f20b3df28e Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:46 +0000 Subject: [PATCH 03/10] openipc: add the OpenIPC boot layer The firmware scan, recovery and boot-limit failsafe of the openipc-hisilicon branch, for the Goke GK7101/GK7102: common/openipc.c and include/openipc.h as on openipc-xm (7208b961221, itself from openipc-hisilicon 655d32f5109), unchanged. CONFIG_OPENIPC builds it; PRODUCT_SOC and PRODUCT_SOCMODEL name the target in the environment. --- common/Kconfig | 21 ++ common/Makefile | 2 + common/openipc.c | 715 ++++++++++++++++++++++++++++++++++++++++++++++ include/openipc.h | 7 + 4 files changed, 745 insertions(+) create mode 100644 common/openipc.c create mode 100644 include/openipc.h diff --git a/common/Kconfig b/common/Kconfig index ebee856e5676..b6f754d9fdf8 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1006,3 +1006,24 @@ config FDT_SIMPLEFB These functions can be used by board to indicate to the OS the presence of the simple frame buffer with associated reserved memory + +config OPENIPC + bool "OpenIPC boot layer" + help + The OpenIPC firmware scan, SD/USB recovery and boot-limit failsafe + (common/openipc.c), driven from the board's misc_init_r(), with the + default environment in include/configs/openipc-common.h. + +config PRODUCT_SOC + string "Product SoC name" + default SYS_CONFIG_NAME + help + Target SoC name exposed as 'soc=' (and 'board=') in the default + environment. Set per target by the build system. + +config PRODUCT_SOCMODEL + string "Product SoC model" + default "" + help + Optional board/binning model exposed as 'socmodel=' in the default + environment. diff --git a/common/Makefile b/common/Makefile index 2ed8672c3ac1..d725fc328029 100644 --- a/common/Makefile +++ b/common/Makefile @@ -112,3 +112,5 @@ obj-$(CONFIG_$(SPL_TPL_)STACKPROTECTOR) += stackprot.o obj-$(CONFIG_SCP03) += scp03.o obj-$(CONFIG_QFW) += qfw.o + +obj-$(CONFIG_OPENIPC) += openipc.o diff --git a/common/openipc.c b/common/openipc.c new file mode 100644 index 000000000000..00c363de3dbf --- /dev/null +++ b/common/openipc.c @@ -0,0 +1,715 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_USB +#include +#endif +#ifdef CONFIG_MMC +#include +#endif +#ifdef CONFIG_ENV_IS_IN_NAND +#include +#endif +#ifdef CONFIG_ENV_IS_IN_NAND +#include +#include +#include +#include +#include +#include +#endif + +#define SCAN_FROM CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE +#define SCAN_STEP 0x10000 +#define SCAN_LIMIT 0x400000 + +#define UBI_MAGIC_ASCII "UBI#" +#define FDT_MAGIC 0xd00dfeed + +#define SQSH_SIZE_OFF 0x58 +#define SQSH_MAGIC_BE 0x73717368 +#define SQSH_MAGIC_LE 0x68737173 + +static int check_squashfs(void *buf) { + uint32_t magic = get_unaligned_be32(buf); + if (magic == SQSH_MAGIC_BE || magic == SQSH_MAGIC_LE) + return 1; + return 0; +} + +#ifdef CONFIG_ENV_IS_IN_NAND +#define UBIFS_SB_MAGIC 0x06101831 + +static int check_ubifs(void *buf) { + return get_unaligned_le32(buf) == UBIFS_SB_MAGIC; +} + +/* Check for the UBI marker without attaching: attaching an empty MTD + * would create a fresh UBI on flash. */ +static int ubi_marker_present(void) { + struct mtd_info *mtd; + u8 buf[4]; + size_t retlen; + int ret; + + /* Register the mtdparts partitions before looking one up by name */ + mtd_probe_devices(); + mtd = get_mtd_device_nm("ubi"); + if (IS_ERR(mtd)) + return 0; + + ret = mtd_read(mtd, 0, sizeof(buf), &retlen, buf); + put_mtd_device(mtd); + + return !ret && retlen == sizeof(buf) && + get_unaligned_be32(buf) == UBI_EC_HDR_MAGIC; +} +#endif + +static int check_kernel(void *buf) { + struct image_header *hdr = (struct image_header *)buf; + if (image_check_magic(hdr)) { + return 1; + } + + if (fdt_magic(buf) == FDT_MAGIC) { + if (fdt_check_header(buf) == 0) { + return 1; + } + } + + return 0; +} + +#ifndef CONFIG_ENV_IS_IN_NAND + +static uint64_t get_squashfs_size(void *buf) { + uint32_t magic = get_unaligned_be32(buf); + uint64_t size; + + if (magic == SQSH_MAGIC_BE) { + size = get_unaligned_be64((u8 *)buf + SQSH_SIZE_OFF); + } else { + size = get_unaligned_le64((u8 *)buf + SQSH_SIZE_OFF); + } + + return size; +} + +static int check_rootfs(void *buf, uint64_t *rootfs_size) { + if (check_squashfs(buf)) { + *rootfs_size = get_squashfs_size(buf); + return 1; + } + if (memcmp(buf, UBI_MAGIC_ASCII, 4) == 0) { + *rootfs_size = 0; + return 1; + } + return 0; +} + +static int scan_spi_device(struct spi_flash *flash, ulong *kernel_off, ulong *rootfs_off, uint64_t *kernel_size, + uint64_t *rootfs_size) { + u8 *buf; + ulong offset; + ulong erase_size; + int ret; + + buf = malloc_cache_aligned(SCAN_STEP); + if (!buf) + return -1; + +#ifdef CONFIG_SPI_FLASH + erase_size = flash->sector_size; +#else + erase_size = 0x10000; +#endif + + printf("Scanning 0x%x-0x%x ...\n", SCAN_FROM, SCAN_LIMIT); + + for (offset = SCAN_FROM; offset < SCAN_LIMIT && offset < flash->size; offset += SCAN_STEP) { + ret = spi_flash_read(flash, offset, SCAN_STEP, buf); + if (ret != 0) + continue; + + /* Skip completely empty regions */ + if (buf[0] == 0x00 || buf[0] == 0xFF) { + int i, uniform = 1; + for (i = 1; i < 32; i++) { + if (buf[i] != buf[0]) { + uniform = 0; + break; + } + } + if (uniform) + continue; + } + + if (!*kernel_off && check_kernel(buf)) { + *kernel_off = offset; + printf("Found Kernel at 0x%08lx\n", offset); + } + + if (!*rootfs_off && check_rootfs(buf, rootfs_size)) { + *rootfs_off = offset; + printf("Found RootFS at 0x%08lx (%lldk)\n", offset, *rootfs_size / 1024); + } + + if (*kernel_off && *rootfs_off) + break; + } + + if (*kernel_off && *rootfs_off) { + *kernel_size = *rootfs_off - *kernel_off; + } + + /* Align rootfs size to erase block boundary */ + if (*rootfs_size > 0) { + ulong aligned_size = (*rootfs_size + erase_size - 1) & ~(erase_size - 1); + *rootfs_size = aligned_size; + } + + free(buf); + return 0; +} + +#endif /* !CONFIG_ENV_IS_IN_NAND */ + +#if (defined(CONFIG_MMC) || defined(CONFIG_USB_STORAGE)) && defined(CONFIG_FS_FAT) +#define RECOVERY_KERNEL 0 +#define RECOVERY_ROOTFS 1 + +static int recovery_mount(const char *ifname) { + if (!fs_set_blk_dev(ifname, "0:1", FS_TYPE_FAT)) + return 0; + if (!fs_set_blk_dev(ifname, "0", FS_TYPE_FAT)) + return 0; + return -1; +} + +#ifdef CONFIG_ENV_IS_IN_NAND +static int recovery_ensure_volume(const char *name, const char *size) { + struct ubi_volume_desc *desc; + char cmd[64]; + + desc = ubi_open_volume_nm(0, name, UBI_READONLY); + if (!IS_ERR(desc)) { + ubi_close_volume(desc); + return 0; + } + + printf("Recovery: creating volume %s\n", name); + snprintf(cmd, sizeof(cmd), "ubi create %s %s d", name, size); + + return run_command(cmd, 0); +} + +/* Recreate a system volume so it always has the expected size; the old + * one is removed first because UBI volumes cannot be resized. With + * `liberate' set, a create that runs out of space removes rootfs_data + * and retries: growing the rootfs is the only way to need its PEBs. */ +static int recovery_recreate_volume(const char *name, const char *size, + bool liberate) { + struct ubi_volume_desc *desc; + char cmd[64]; + int ret; + + desc = ubi_open_volume_nm(0, name, UBI_READONLY); + if (!IS_ERR(desc)) { + ubi_close_volume(desc); + printf("Recovery: recreating volume %s\n", name); + snprintf(cmd, sizeof(cmd), "ubi remove %s", name); + run_command(cmd, 0); + } else { + printf("Recovery: creating volume %s\n", name); + } + + snprintf(cmd, sizeof(cmd), "ubi create %s %s d", name, size); + ret = run_command(cmd, 0); + + if (ret && liberate) { + printf("Recovery: no room for %s, dropping rootfs_data\n", name); + run_command("ubi remove rootfs_data", 0); + ret = run_command(cmd, 0); + } + + return ret; +} + +static int recovery_write(const char *name, int type) { + struct image_header hdr; + loff_t actread; + ulong size; + int ret; + + if (!fs_exists(name)) + return 0; + + if (type == RECOVERY_ROOTFS) { + /* Raw ubifs image, written into the rootfs volume */ + loff_t fsize; + + ret = fs_size(name, &fsize); + if (ret || fsize == 0) { + printf("Recovery: failed to stat %s\n", name); + return -1; + } + size = fsize; + } else { + /* Kernel: uImage or FIT, written to the kernel volume */ + ret = fs_read(name, (ulong)&hdr, 0, sizeof(hdr), &actread); + if (ret || actread != sizeof(hdr)) { + printf("Recovery: failed to read %s\n", name); + return -1; + } + + if (image_check_magic(&hdr)) { + size = sizeof(hdr) + image_get_data_size(&hdr); + } else if (fdt_magic(&hdr) == FDT_MAGIC && fdt_check_header(&hdr) == 0) { + size = fdt_totalsize(&hdr); + } else { + printf("Recovery: no valid uImage/FIT header in %s\n", name); + return -1; + } + } + + ret = fs_read(name, CONFIG_SYS_LOAD_ADDR, 0, size, &actread); + if (ret || actread != size) { + printf("Recovery: failed to read %s\n", name); + return -1; + } + + /* Attach only now that there is something to write */ + if (ubi_part("ubi", NULL)) { + printf("Recovery: cannot attach UBI\n"); + return -1; + } + + if (type == RECOVERY_ROOTFS) { + char size_str[24]; + + /* The volume is sized to the image; if it does not fit, the data + * volume is dropped (UBI volumes cannot be resized) */ + snprintf(size_str, sizeof(size_str), "0x%lx", size); + ret = recovery_recreate_volume("rootfs", size_str, true); + if (ret) { + printf("Recovery: cannot recreate rootfs volume (%d)\n", ret); + return -1; + } + + ret = ubi_volume_write("rootfs", (void *)CONFIG_SYS_LOAD_ADDR, size); + if (ret) { + printf("Recovery: failed to write rootfs volume (%d)\n", ret); + return -1; + } + + /* The data volume takes the remaining space; keep it if present */ + recovery_ensure_volume("rootfs_data", "0"); + + printf("Recovery: wrote %s (%lu bytes) to rootfs volume\n", name, size); + } else { + ret = recovery_recreate_volume("kernel", "0x300000", false); + if (ret) { + printf("Recovery: cannot recreate kernel volume (%d)\n", ret); + return -1; + } + + ret = ubi_volume_write("kernel", (void *)CONFIG_SYS_LOAD_ADDR, size); + if (ret) { + printf("Recovery: failed to write kernel volume (%d)\n", ret); + return -1; + } + + printf("Recovery: wrote %s (%lu bytes) to kernel volume\n", name, size); + } + + return 1; +} +#else +static struct spi_flash *recovery_flash; + +static int recovery_write(const char *name, int type) { + struct image_header hdr; + loff_t actread; + ulong addr, size, erase_len; + int ret; + + if (!fs_exists(name)) + return 0; + + ret = fs_read(name, (ulong)&hdr, 0, sizeof(hdr), &actread); + if (ret || actread != sizeof(hdr)) { + printf("Recovery: failed to read %s\n", name); + return -1; + } + + if (image_check_magic(&hdr)) { + addr = image_get_load(&hdr); + size = sizeof(hdr) + image_get_data_size(&hdr); + } else if (type == RECOVERY_KERNEL && fdt_magic(&hdr) == FDT_MAGIC && + fdt_check_header(&hdr) == 0) { + const char *str = env_get("kernaddr"); + + addr = str ? hextoul(str, NULL) : OPENIPC_KERNADDR; + size = fdt_totalsize(&hdr); + } else { + printf("Recovery: no valid uImage/FIT header in %s\n", name); + return -1; + } + + ret = fs_read(name, CONFIG_SYS_LOAD_ADDR, 0, size, &actread); + if (ret || actread != size) { + printf("Recovery: failed to read %s\n", name); + return -1; + } + + erase_len = (size + recovery_flash->sector_size - 1) & + ~(recovery_flash->sector_size - 1); + spi_flash_erase(recovery_flash, addr, erase_len); + spi_flash_write(recovery_flash, addr, size, (void *)CONFIG_SYS_LOAD_ADDR); + + printf("Recovery: wrote %s (%lu bytes) to flash at 0x%lx\n", name, size, + addr); + + return 1; +} +#endif + +/* If a script.txt is present on the medium, execute it (uImage script or + * plain text) instead of searching for kernel/rootfs images. */ +static int recovery_run_script(const char *name) { + loff_t size, actread; + int ret; + char cmd[32]; + + if (!fs_exists(name)) + return 0; + + ret = fs_size(name, &size); + if (ret || size == 0) { + printf("Recovery: failed to stat %s\n", name); + return 1; + } + + ret = fs_read(name, CONFIG_SYS_LOAD_ADDR, 0, size, &actread); + if (ret || actread != size) { + printf("Recovery: failed to read %s\n", name); + return 1; + } + + if (image_check_magic((void *)CONFIG_SYS_LOAD_ADDR)) { + /* uImage-wrapped script (mkimage -A arm -T script -d ...) */ + sprintf(cmd, "source 0x%lx", (ulong)CONFIG_SYS_LOAD_ADDR); + ret = run_command(cmd, 0); + } else { + /* Plain text script */ + ret = run_command_list((char *)CONFIG_SYS_LOAD_ADDR, size, 0); + } + + printf("Recovery: executed %s (%lld bytes)\n", name, size); + + return 1; +} + +static int recovery_try(void) { + char name[64]; + int ret, found = 0; + + /* script.txt takes precedence over the kernel/rootfs search */ + if (recovery_run_script("script.txt")) + return 1; + +#ifndef CONFIG_ENV_IS_IN_NAND + /* Kernel: uImage preferred, FIT fallback */ + sprintf(name, "uImage.%s.img", CONFIG_PRODUCT_SOC); + ret = recovery_write(name, RECOVERY_KERNEL); + if (ret > 0) { + found = 1; + } else if (ret == 0) { + sprintf(name, "fitImage.%s.img", CONFIG_PRODUCT_SOC); + ret = recovery_write(name, RECOVERY_KERNEL); + if (ret > 0) + found = 1; + } +#endif + + /* Rootfs. On NAND it carries the kernel (/boot), its volume is sized + * to the image and rootfs_data takes the rest. */ +#ifdef CONFIG_ENV_IS_IN_NAND + sprintf(name, "rootfs.ubifs.%s.img", CONFIG_PRODUCT_SOC); +#else + sprintf(name, "rootfs.squashfs.%s.img", CONFIG_PRODUCT_SOC); +#endif + ret = recovery_write(name, RECOVERY_ROOTFS); + if (ret > 0) + found = 1; + + return found; +} + +int firmware_recovery(void) { + int found = 0; + +#ifndef CONFIG_ENV_IS_IN_NAND + recovery_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, + CONFIG_SF_DEFAULT_SPEED, + CONFIG_SF_DEFAULT_MODE); + if (!recovery_flash) + return -1; +#endif + +#ifdef CONFIG_MMC + { + struct mmc *mmc = find_mmc_device(0); + + if (mmc && !mmc_init(mmc) && !recovery_mount("mmc")) + found |= recovery_try(); + } +#endif + +#ifdef CONFIG_USB_STORAGE + if (!usb_init() && usb_stor_scan(1) == 0 && !recovery_mount("usb")) + found |= recovery_try(); +#endif + + fs_close(); +#ifndef CONFIG_ENV_IS_IN_NAND + spi_flash_free(recovery_flash); +#endif + + return found ? 0 : -1; +} +#else +int firmware_recovery(void) { + return -1; +} +#endif + +int firmware_scan(void) { +#ifdef CONFIG_ENV_IS_IN_NAND + u8 buf[64]; + int ret; + + printf("Checking UBI firmware...\n"); + + /* Only attach when the UBI actually exists, so we never create one */ + if (!ubi_marker_present()) { + printf("Firmware is absent/corrupt (no UBI)\n"); + env_set("bootfail", "1"); + return 0; + } + + if (ubi_part("ubi", NULL)) { + printf("Firmware is absent/corrupt (cannot attach UBI)\n"); + env_set("bootfail", "1"); + return 0; + } + + /* The kernel is a file in the UBIFS rootfs (/boot/fitImage or + * /boot/uImage): there is no kernel volume to check. */ + ret = ubi_volume_read("rootfs", (char *)buf, sizeof(buf)); + if (ret || !check_ubifs(buf)) { + printf("Firmware is absent/corrupt (rootfs volume)\n"); + env_set("bootfail", "1"); + return 0; + } + + /* A rootfs without a kernel in it boots nothing: hand it to recovery + * like a missing one. loadkernel mounts the volume again itself. */ + if (cmd_ubifs_mount("ubi0:rootfs")) { + printf("Firmware is absent/corrupt (cannot mount rootfs)\n"); + env_set("bootfail", "1"); + return 0; + } + ret = ubifs_exists("/boot/fitImage") || ubifs_exists("/boot/uImage"); + cmd_ubifs_umount(); + if (!ret) { + printf("Firmware is absent/corrupt (no /boot/fitImage or /boot/uImage)\n"); + env_set("bootfail", "1"); + return 0; + } + + env_set("bootfail", NULL); + + return 0; +#else + struct spi_flash *flash; + ulong kernel_off = 0; + ulong rootfs_off = 0; + uint64_t kernel_size = 0; + uint64_t rootfs_size = 0; + + printf("Automatic flash layout detection...\n"); + + flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); + if (!flash) { + printf("Failed to probe SPI flash at %u:%u\n", CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS); + return -1; + } + + scan_spi_device(flash, &kernel_off, &rootfs_off, &kernel_size, &rootfs_size); + +#ifndef CONFIG_TARGET_HI3516CV610_FAMILY + if (kernel_size <= 0x200000) + kernel_size = 0x200000; + if (rootfs_size < 0x500000) + rootfs_size = 0x500000; + else if (rootfs_size > 0x500000 && flash->size > 0x800000) + rootfs_size = 0xa00000; +#endif + + spi_flash_free(flash); + + if (kernel_off) { + char str[32]; + sprintf(str, "0x%08lx", kernel_off); + env_set("kernaddr", str); + + sprintf(str, "0x%llx", kernel_size); + env_set("kernsize", str); + } + + if (rootfs_off) { + char str[32]; + sprintf(str, "0x%08lx", rootfs_off); + env_set("rootaddr", str); + + sprintf(str, "0x%llx", rootfs_size); + env_set("rootsize", str); + + char mtds[128], mtdparts[160]; + const char *mtdids = env_get("mtdids"); + /* + * An environment saved by an earlier OpenIPC U-Boot has no mtdids: its + * bootargs carried "mtdparts=${mtdparts}" with the controller name + * spelled out. Without one the kernel gets "mtdparts=:...", matches no + * flash, and cannot mount /dev/mtdblock3. Name the controller this + * build drives, as its own default environment does. + */ +#ifdef SFC + if (!mtdids || !*mtdids) + mtdids = SFC; +#endif + sprintf(mtds, "%dk(u-boot),%dk(env),%lldk(kernel),%lldk(rootfs),%lldk@0x%lx(firmware),-(rootfs_data)", + CONFIG_ENV_OFFSET / 1024, CONFIG_ENV_SIZE / 1024, kernel_size / 1024, rootfs_size / 1024, + (kernel_size + rootfs_size) / 1024, kernel_off); + env_set("mtds", mtds); + sprintf(mtdparts, "%s:%s", mtdids ? mtdids : "", mtds); + env_set("mtdparts", mtdparts); + } + + if (kernel_off && rootfs_off) { + env_set("bootfail", NULL); + } else { + printf("Firmware is absent/corrupt (kernel=0x%lx, rootfs=0x%lx)\n", kernel_off, rootfs_off); + env_set("bootfail", "1"); + } + + return 0; +#endif +} + +#ifndef OPENIPC_RAM_MAX_SIZE +#ifdef PHYS_SDRAM_1_SIZE +#define OPENIPC_RAM_MAX_SIZE PHYS_SDRAM_1_SIZE +#endif +#endif + +#if defined(OPENIPC_RAM_MAX_SIZE) && defined(CONFIG_SYS_SDRAM_BASE) +ulong openipc_ram_size(void) +{ + return get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, OPENIPC_RAM_MAX_SIZE); +} +#endif + +/* Check whether the device environment area is still blank (donor-style + * CRC check): only then it is safe to write the default environment. */ +static int env_crc_is_blank(void) { + u32 crc; + +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH) + struct spi_flash *flash; + u8 *buf; + + flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, + CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); + if (!flash) + return 0; + + /* Cache-aligned: the DMA path invalidates cache lines around the + * buffer and a plain malloc buffer can share lines with heap metadata */ + buf = malloc_cache_aligned(CONFIG_ENV_SIZE); + if (!buf) { + spi_flash_free(flash); + return 0; + } + + if (spi_flash_read(flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf)) { + free(buf); + spi_flash_free(flash); + return 0; + } + + memcpy(&crc, buf, sizeof(crc)); + free(buf); + spi_flash_free(flash); +#elif defined(CONFIG_ENV_IS_IN_NAND) + struct mtd_info *mtd = get_nand_dev_by_index(0); + size_t len = sizeof(crc); + + if (!mtd) + return 0; + + if (nand_read_skip_bad(mtd, CONFIG_ENV_OFFSET, &len, NULL, mtd->size, + (u_char *)&crc)) + return 0; + + if (len != sizeof(crc)) + return 0; +#else + return 0; +#endif + + return crc == 0xffffffff; +} + +/* An environment saved by an earlier build of this tree carries the retired + * boot-limit command, which reflashes instead of entering failsafe (see + * OPENIPC_ALTBOOTCMD). Replace exactly that one, once; a command anyone + * edited is left alone. */ +static void altbootcmd_migrate(void) { + const char *s = env_get("altbootcmd"); + + if (!s || strcmp(s, OPENIPC_ALTBOOTCMD_RETIRED)) + return; + printf("altbootcmd: retired reflash command replaced with failsafe\n"); + env_set("altbootcmd", OPENIPC_ALTBOOTCMD); + env_save(); +} + +int openipc_helper(void) { + char msize[16]; + sprintf(msize, "%ldM", gd->ram_size / 1024 / 1024); + env_set("totalmem", msize); + firmware_recovery(); + firmware_scan(); + altbootcmd_migrate(); + + /* Persist the default environment on first start (or after a bad env); + * only if the device env area is still blank so we never overwrite + * foreign data (e.g. a RAM-booted U-Boot on another device). */ + if ((gd->flags & GD_FLG_ENV_DEFAULT) && env_crc_is_blank()) + env_save(); + + return 0; +} diff --git a/include/openipc.h b/include/openipc.h new file mode 100644 index 000000000000..b8ccfe058431 --- /dev/null +++ b/include/openipc.h @@ -0,0 +1,7 @@ +#ifndef _OPENIPC_H +#define _OPENIPC_H + +unsigned long openipc_ram_size(void); +int openipc_helper(void); + +#endif \ No newline at end of file From 4344c527f7d9c7a56dc9e29c57797b900f377d39 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:46 +0000 Subject: [PATCH 04/10] arm: gk710x: add the Goke GK7101 and GK7102 Goke's own ARM1176 camera SoCs, not the HiSilicon-derived GK7205/GK7605: GK7102 is the GK7101 die with 64 MiB of DDR2 in the package, GK7101 has 128 MiB outside. Written from the vendor SDK GK710X_LinuxSDK_v2.0.0 (U-Boot 2012.10, Linux 3.4.43); none of its drivers come along. - The boot ROM runs the DDR set-up listed in the flash header and copies U-Boot to its link address, 0xC0800000, so there is no SPL and lowlevel_init is empty. dram_init() tells 64 from 128 MiB by the DDR controller word the header programmed. - The vendor code reaches every register through a HAL blob that remaps blocks, registers and bits. Here the silicon is programmed directly, with the stores the HAL itself makes, recovered by executing it (qemu-hisilicon's gk710x-halmap.py): CPU PLL and UART divider, timer 1 (Ambarella, 69 MHz, through lib/time.c), watchdog reset, pin functions and pad control. - Console: mainline NS16550 at 0x70005000, 32-bit registers, 24 MHz. - Ethernet: mainline DesignWare at 0x6000E000 with the SoC's 10/100 PHY, whose MII registers are memory mapped and are registered as its MDIO bus. The vendor's PHY clock (audio PLL out on a pin), analog trim and MAC/PHY mux are done first. - The vendor kernel, OpenIPC's included, needs more than ATAGs, and board_prep_linux() leaves it what the vendor U-Boot did: the HAL blob at 0xC0012000 (hal_data.h, version 20160913; the kernel calls it first and refuses one older than 20160324), the U2K words at 0xC0000000 (total DDR, mem=, bitstream buffer, PHY type) from which it places its BSB, DSP and USR memory, and the board's GPIO map in the top 64 KiB, from which it configures every pin. U-Boot stays below that 64 KiB. - The SDK's board GPIO headers come down to two layouts, v2 (rb-sc1035 v2.1, sc1045, imx225, ov9750, jxh42 v2.0, gc1024, GK7101 rb-ov2710 v2.2) and v1 (rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222). Both are built in, generated from the headers; gpiomap=v1 selects the second. U-Boot applies the selected map at misc_init_r() as the vendor U-Boot did. - include/configs/openipc-common.h: the openipc-xm environment, NOR only, with the GK parameters: mem= 36M/50M and bsbsize 2M/4M (GK7102/GK7101, the vendor defaults), baseaddr 0xC1000000, console ttySGK0 and the vendor kernel's MTD name gk_flash. SD is left out: the vendor U-Boot had none and the controller's base clock is not known. Under qemu-hisilicon's gk7102 and gk7101 machines (with the flash driver that follows): 64/128 MiB, console, timer, reset, ping and TFTP; the OpenIPC gk7102 kernel takes the HAL, the U2K layout and the GPIO map and boots to login. --- arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-gk710x/Kconfig | 31 + arch/arm/mach-gk710x/Makefile | 3 + arch/arm/mach-gk710x/gpio.c | 55 ++ arch/arm/mach-gk710x/hal_data.h | 680 +++++++++++++++++++++ arch/arm/mach-gk710x/include/mach/gk710x.h | 98 +++ arch/arm/mach-gk710x/kernel.c | 51 ++ arch/arm/mach-gk710x/lowlevel_init.S | 11 + arch/arm/mach-gk710x/soc.c | 72 +++ board/goke/gk710x/Makefile | 3 + board/goke/gk710x/gk710x.c | 122 ++++ board/goke/gk710x/gpio_map.c | 292 +++++++++ include/configs/gk710x.h | 41 ++ include/configs/openipc-common.h | 131 ++++ 15 files changed, 1603 insertions(+) create mode 100644 arch/arm/mach-gk710x/Kconfig create mode 100644 arch/arm/mach-gk710x/Makefile create mode 100644 arch/arm/mach-gk710x/gpio.c create mode 100644 arch/arm/mach-gk710x/hal_data.h create mode 100644 arch/arm/mach-gk710x/include/mach/gk710x.h create mode 100644 arch/arm/mach-gk710x/kernel.c create mode 100644 arch/arm/mach-gk710x/lowlevel_init.S create mode 100644 arch/arm/mach-gk710x/soc.c create mode 100644 board/goke/gk710x/Makefile create mode 100644 board/goke/gk710x/gk710x.c create mode 100644 board/goke/gk710x/gpio_map.c create mode 100644 include/configs/gk710x.h create mode 100644 include/configs/openipc-common.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 82cd456f51f1..44cbc03dbd78 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1224,6 +1224,16 @@ config ARCH_U8500 imply SYS_THUMB_BUILD imply SYSRESET_SYSCON +config ARCH_GK710X + bool "Goke GK7101/GK7102 IP camera SoCs" + select CPU_ARM1176 + select CREATE_ARCH_SYMLINK + select SUPPORT_PASSING_ATAGS + help + Goke's own ARM1176 camera SoCs (not the HiSilicon-derived + GK7205/GK7605). The boot ROM runs the DDR set-up listed in the + flash header, copies U-Boot into DDR and starts it there. + config ARCH_VERSAL bool "Support Xilinx Versal Platform" select ARM64 @@ -2284,6 +2294,8 @@ source "arch/arm/mach-zynqmp/Kconfig" source "arch/arm/mach-versal/Kconfig" +source "arch/arm/mach-gk710x/Kconfig" + source "arch/arm/mach-zynqmp-r5/Kconfig" source "arch/arm/cpu/armv7/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 1f4a1d57883b..4c180efd263e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -59,6 +59,7 @@ machine-$(CONFIG_ARCH_BCMBCA) += bcmbca machine-$(CONFIG_ARCH_BCMSTB) += bcmstb machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_EXYNOS) += exynos +machine-$(CONFIG_ARCH_GK710X) += gk710x machine-$(CONFIG_ARCH_GXP) += hpe machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_IPQ40XX) += ipq40xx diff --git a/arch/arm/mach-gk710x/Kconfig b/arch/arm/mach-gk710x/Kconfig new file mode 100644 index 000000000000..db610d020543 --- /dev/null +++ b/arch/arm/mach-gk710x/Kconfig @@ -0,0 +1,31 @@ +if ARCH_GK710X + +choice + prompt "Goke SoC" + default TARGET_GK7102 + +config TARGET_GK7101 + bool "GK7101" + help + GK7101: ARM1176 with 128 MiB of external DDR2. + +config TARGET_GK7102 + bool "GK7102" + help + GK7102: the GK7101 die with 64 MiB of DDR2 in the package. + +endchoice + +config SYS_SOC + default "gk710x" + +config SYS_VENDOR + default "goke" + +config SYS_BOARD + default "gk710x" + +config SYS_CONFIG_NAME + default "gk710x" + +endif diff --git a/arch/arm/mach-gk710x/Makefile b/arch/arm/mach-gk710x/Makefile new file mode 100644 index 000000000000..46654b9be11c --- /dev/null +++ b/arch/arm/mach-gk710x/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += lowlevel_init.o soc.o gpio.o kernel.o diff --git a/arch/arm/mach-gk710x/gpio.c b/arch/arm/mach-gk710x/gpio.c new file mode 100644 index 000000000000..1d4cf6861815 --- /dev/null +++ b/arch/arm/mach-gk710x/gpio.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Goke GK710x pin functions, from the vendor U-Boot's drivers/gpio/ + * goke_gpio.c (gk7101_gpio_func_config()) with the HAL undone. + * + * A pin type is the vendor's GPIO_TYPE_* word: output function [7:0], input + * function + 2 [15:8], output-enable source [21:16], output and enable + * inversion [23:22], pad control [29:24] and direction [31:30]. The kernel + * decodes the same words from the map U-Boot leaves it (board/goke/gk710x). + */ + +#include +#include +#include + +#define TYPE_OUT_SEL(t) ((t) & 0xff) +#define TYPE_IN_SEL(t) (((t) >> 8) & 0xff) +#define TYPE_OEN_SEL(t) (((t) >> 16) & 0x3f) +#define TYPE_OUT_INV(t) (((t) >> 22) & 1) +#define TYPE_OEN_INV(t) (((t) >> 23) & 1) +#define TYPE_IOCTRL(t) (((t) >> 24) & 0x3f) +#define TYPE_FUNC(t) ((t) >> 30) + +#define FUNC_OUT 2 + +void gk_gpio_config(unsigned int pin, unsigned int type) +{ + unsigned int shift = 8 * (pin % 4); + u32 v; + + if (!type) + return; + + /* Input functions >= 2 are routed from a pin; 0 and 1 are constants */ + if (TYPE_FUNC(type) != FUNC_OUT && TYPE_IN_SEL(type) >= 2) + writel(pin, GK_GPIO_INPUT_CFG(TYPE_IN_SEL(type) - 2)); + + writel(TYPE_OUT_SEL(type) | TYPE_OEN_SEL(type) << 8 | + TYPE_OUT_INV(type) << 14 | TYPE_OEN_INV(type) << 15, + GK_GPIO_OUTPUT_CFG(pin)); + + if (TYPE_IOCTRL(type)) { + v = readl(GK_RCT_IOCTRL_GPIO(pin)); + v &= ~(0x3f << shift); + v |= TYPE_IOCTRL(type) << shift; + writel(v, GK_RCT_IOCTRL_GPIO(pin)); + } +} + +/* After a map is applied, as the vendor gk7101_gpio_initialize() ends */ +void gk_gpio_init(void) +{ + writel(1, GK_GPIO_IN_EN); + writel(0x11, GK_RCT_IOCTRL_MISC2); +} diff --git a/arch/arm/mach-gk710x/hal_data.h b/arch/arm/mach-gk710x/hal_data.h new file mode 100644 index 000000000000..ebe1ff8592c8 --- /dev/null +++ b/arch/arm/mach-gk710x/hal_data.h @@ -0,0 +1,680 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The Goke GK7101/GK7102 HAL: a binary blob, as the vendor ships it in its + * U-Boot (SDK GK710X_LinuxSDK_v2.0.0, board/goke/gk7101/gk7101_hal_data.h, + * version 20160913), linked to run at GK_HAL_ADDR. + * + * U-Boot itself does not use it; its drivers program the silicon directly. + * The vendor kernel, OpenIPC's included, calls hal_init() at its start and + * makes every register access through the table that returns, so the blob + * is copied into place before the kernel starts (mach-gk710x/kernel.c). + * The OpenIPC kernel refuses a HAL older than 20160324. + */ + +static const u32 gk_hal_data[] = { + 0xe92d45f8, 0xe1a04000, 0xe1a05001, 0xe1a06002, 0xe1a0a003, 0xe59d7020, + 0xe3570000, 0x0a00000e, 0xe59f8148, 0xe58802f0, 0xe5881320, 0xe59832f8, + 0xe3530000, 0x0a000002, 0xe2880e2f, 0xe3a01001, 0xe12fff37, 0xe5983328, + 0xe3530000, 0x0a000002, 0xe59f011c, 0xe3a01001, 0xe12fff37, 0xe59f0114, + 0xe59f3114, 0xe5830000, 0xe3540000, 0x03a04206, 0xe59f3108, 0xe5834000, + 0xe3550000, 0x03a05207, 0xe59f30fc, 0xe5835000, 0xe244320f, 0xe2734000, + 0xe0a44003, 0xe59f30d4, 0xe5834330, 0xe59f30e4, 0xe5836000, 0xe59f30e0, + 0xe583a000, 0xe59f30dc, 0xe5803000, 0xe59f30d8, 0xe5803004, 0xe59f30d4, + 0xe5803008, 0xe59f30d0, 0xe580300c, 0xe59f30cc, 0xe5803010, 0xe59f30c8, + 0xe5803014, 0xe59f30c4, 0xe5803018, 0xe59f30c0, 0xe580301c, 0xe59f30bc, + 0xe5803020, 0xe59f30b8, 0xe5803024, 0xe59f30b4, 0xe5803028, 0xe59f30b0, + 0xe580302c, 0xe59f30ac, 0xe5803030, 0xe59f30a8, 0xe5803034, 0xe59f30a4, + 0xe5803038, 0xe59f30a0, 0xe580303c, 0xe59f309c, 0xe5803040, 0xe59f3098, + 0xe5803044, 0xe59f3094, 0xe5803048, 0xe59f3090, 0xe580304c, 0xe59f308c, + 0xe5803050, 0xe59f3088, 0xe5803054, 0xe59f3084, 0xe5803058, 0xe59f3080, + 0xe580305c, 0xe8bd85f8, 0xc0014ac0, 0xc0014de0, 0xc0015e58, 0xc0015eb8, + 0xc0015e4c, 0xc0015e48, 0xc0015e54, 0xc0015e50, 0xc00121f0, 0xc0012a3c, + 0xc0012cb8, 0xc0012c44, 0xc00128cc, 0xc0012bc8, 0xc0012b4c, 0xc0012a94, + 0xc0012298, 0xc00122b0, 0xc00122c8, 0xc00122e8, 0xc0012308, 0xc0012328, + 0xc0012348, 0xc0012368, 0xc0012388, 0xc00123a4, 0xc00123c0, 0xc00123d8, + 0xc00123f0, 0xc0012408, 0xc0012420, 0xc0012438, 0xe59f0000, 0xe12fff1e, + 0x20160913, 0xe92d4008, 0xe1a03001, 0xe3500000, 0x0a000006, 0xe590c008, + 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, 0xe12fff3c, 0xe1a03000, + 0xe1a00003, 0xe8bd8008, 0xe92d4008, 0xe1a03001, 0xe3500000, 0x0a000006, + 0xe590c008, 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, 0xe12fff3c, + 0xe6ff3070, 0xe1a00003, 0xe8bd8008, 0xe92d4008, 0xe1a03001, 0xe3500000, + 0x0a000006, 0xe590c008, 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, + 0xe12fff3c, 0xe6ef3070, 0xe1a00003, 0xe8bd8008, 0xe59f300c, 0xe5933000, + 0xe2833a16, 0xe5930000, 0xe12fff1e, 0xc0015e4c, 0xe59f300c, 0xe5933000, + 0xe2833a16, 0xe5830000, 0xe12fff1e, 0xc0015e4c, 0xe59f3014, 0xe5933000, + 0xe2833a06, 0xe1a00980, 0xe08339a0, 0xe7d30001, 0xe12fff1e, 0xc0015e4c, + 0xe59f3014, 0xe5933000, 0xe2833a06, 0xe1a00980, 0xe08339a0, 0xe19300b1, + 0xe12fff1e, 0xc0015e4c, 0xe59f3014, 0xe5933000, 0xe2833a06, 0xe1a00980, + 0xe08339a0, 0xe7930001, 0xe12fff1e, 0xc0015e4c, 0xe59f3014, 0xe5933000, + 0xe2833a06, 0xe1a00980, 0xe08339a0, 0xe7c32001, 0xe12fff1e, 0xc0015e4c, + 0xe59f3014, 0xe5933000, 0xe2833a06, 0xe1a00980, 0xe08339a0, 0xe18320b1, + 0xe12fff1e, 0xc0015e4c, 0xe59f3014, 0xe5933000, 0xe2833a06, 0xe1a00980, + 0xe08339a0, 0xe7832001, 0xe12fff1e, 0xc0015e4c, 0xe59f3010, 0xe5933000, + 0xe2833a05, 0xe1a00a00, 0xe7930a20, 0xe12fff1e, 0xc0015e4c, 0xe59f3010, + 0xe5933000, 0xe2833a05, 0xe1a00a00, 0xe7831a20, 0xe12fff1e, 0xc0015e4c, + 0xe1a00800, 0xe59f3008, 0xe5933000, 0xe7d30820, 0xe12fff1e, 0xc0015e48, + 0xe6ff0070, 0xe59f3008, 0xe5933000, 0xe19000b3, 0xe12fff1e, 0xc0015e48, + 0xe1a00800, 0xe59f3008, 0xe5933000, 0xe7930820, 0xe12fff1e, 0xc0015e48, + 0xe1a00800, 0xe59f3008, 0xe5933000, 0xe7c31820, 0xe12fff1e, 0xc0015e48, + 0xe6ff0070, 0xe59f3008, 0xe5933000, 0xe18010b3, 0xe12fff1e, 0xc0015e48, + 0xe1a00800, 0xe59f3008, 0xe5933000, 0xe7831820, 0xe12fff1e, 0xc0015e48, + 0xe20034ff, 0xe59f2420, 0xe5922000, 0xe1530002, 0x1a000066, 0xe2003aff, + 0xe3530a0a, 0x0a000041, 0xca00001f, 0xe3530901, 0x0a000038, 0xca00000d, + 0xe3530a01, 0x03a0001b, 0x012fff1e, 0xca000003, 0xe3530000, 0x03a0000c, + 0x012fff1e, 0xea0000ee, 0xe3530a02, 0x03a0000b, 0x012fff1e, 0xe3530a03, + 0x1a0000e9, 0xea000029, 0xe3530a07, 0x03a00016, 0x012fff1e, 0xca000004, + 0xe3530a05, 0x0a00002b, 0xe3530a06, 0x1a0000e0, 0xea000022, 0xe3530902, + 0x03a0001c, 0x012fff1e, 0xe3530a09, 0x1a0000da, 0xea00001e, 0xe3530a1e, + 0x0a000020, 0xca00000a, 0xe3530903, 0x0a00001b, 0xca000002, 0xe3530a0b, + 0x1a0000d1, 0xea000017, 0xe3530a0d, 0x0a000015, 0xe3530801, 0x1a0000cc, + 0xea000016, 0xe3530805, 0x0a000020, 0xca000004, 0xe3530a1f, 0x0a00000f, + 0xe3530802, 0x1a0000c4, 0xea000014, 0xe3530806, 0x0a00001e, 0xe3530807, + 0x1a0000bf, 0xea000021, 0xe3a00002, 0xe12fff1e, 0xe3a0000a, 0xe12fff1e, + 0xe3a00003, 0xe12fff1e, 0xe3a00008, 0xe12fff1e, 0xe3a0000d, 0xe12fff1e, + 0xe20008ff, 0xe59f32ec, 0xe3500811, 0x11a00003, 0x03a00021, 0xe12fff1e, + 0xe20008ff, 0xe59f32d4, 0xe3500812, 0x11a00003, 0x03a00022, 0xe12fff1e, + 0xe20008ff, 0xe59f32bc, 0xe3500815, 0x11a00003, 0x03a00020, 0xe12fff1e, + 0xe20008ff, 0xe59f32a4, 0xe3500816, 0x11a00003, 0x03a00023, 0xe12fff1e, + 0xe20008ff, 0xe59f328c, 0xe3500817, 0x11a00003, 0x03a00006, 0xe12fff1e, + 0xe59f227c, 0xe5922000, 0xe1530002, 0x1a000092, 0xe2003aff, 0xe3530a0b, + 0x0a00008f, 0xca000022, 0xe3530a05, 0x03a0000f, 0x012fff1e, 0xca00000f, + 0xe3530a02, 0x03a0001f, 0x012fff1e, 0xca000005, 0xe3530000, 0x01a00003, + 0x012fff1e, 0xe3530a01, 0x1a00006f, 0xea000034, 0xe3530a03, 0x03a00001, + 0x012fff1e, 0xe3530901, 0x1a000069, 0xea00007a, 0xe3530902, 0x03a0001d, + 0x012fff1e, 0xca000004, 0xe3530a06, 0x0a00002a, 0xe3530a07, 0x1a000060, + 0xea000027, 0xe3530a09, 0x03a0001e, 0x012fff1e, 0xe3530a0a, 0x1a00005a, + 0xea000023, 0xe3530a22, 0x0a000049, 0xca00000d, 0xe3530a16, 0x03a00014, + 0x012fff1e, 0xca000004, 0xe3530a0e, 0x0a00001c, 0xe3530a0f, 0x1a00004e, + 0xea000019, 0xe3530802, 0x0a000019, 0xe3530a21, 0x1a000049, 0xea000028, + 0xe3530703, 0x0a000044, 0xca000004, 0xe3530702, 0x0a000059, 0xe3530a8a, + 0x1a000041, 0xea000056, 0xe3530ac2, 0x0a00003c, 0xe3530ac3, 0x0a00003a, + 0xe3530ac1, 0x1a00003a, 0xea000037, 0xe3a0000e, 0xe12fff1e, 0xe3a00011, + 0xe12fff1e, 0xe3a00004, 0xe12fff1e, 0xe3a00009, 0xe12fff1e, 0xe59f3134, + 0xe0003003, 0xe2431b82, 0xe2411c02, 0xe59f2128, 0xe1510002, 0x93a00015, + 0x912fff1e, 0xe2431b83, 0xe1510002, 0x93a00017, 0x912fff1e, 0xe2822cfe, + 0xe59f0108, 0xe1530000, 0xd1a00002, 0xc3a00013, 0xe12fff1e, 0xe59f30ec, + 0xe0003003, 0xe2432a21, 0xe35200ff, 0x9a00002e, 0xe2422c01, 0xe3520c09, + 0x3a00002b, 0xe2432b87, 0xe35200ff, 0x93a00018, 0x912fff1e, 0xe59f20b4, + 0xe59f00c4, 0xe1530000, 0xd1a00002, 0xc3a00018, 0xe12fff1e, 0xe59f30a4, + 0xe0003003, 0xe2432a22, 0xe3520c06, 0x33a00010, 0x312fff1e, 0xe59f2084, + 0xe59f0098, 0xe1530000, 0xd1a00002, 0xc3a00019, 0xe12fff1e, 0xe3a0001a, + 0xe12fff1e, 0xe200080f, 0xe3500702, 0x0a000012, 0xe3500809, 0x0a000010, + 0xe350080a, 0x0a00000e, 0xe350080b, 0x0a00000c, 0xe350080d, 0x0a00000a, + 0xe350080e, 0x0a00000a, 0xe59f3030, 0xe350080f, 0x11a00003, 0x03a00005, + 0xe12fff1e, 0xe59f001c, 0xe12fff1e, 0xe3a00012, 0xe12fff1e, 0xe3a00005, + 0xe12fff1e, 0xe3a00005, 0xe12fff1e, 0xc0015e50, 0x0000ffff, 0xc0015e54, + 0x000fff00, 0x000001ff, 0x00020dff, 0x00021cff, 0x000225ff, 0xe92d4008, + 0xebfffeea, 0xe2503000, 0xb3a00000, 0xb8bd8008, 0xe3530023, 0xd3a00014, + 0xd59f2008, 0xd0202390, 0xc3a00000, 0xe8bd8008, 0xc0014ac0, 0xe92d4073, + 0xe1a06000, 0xe59f3134, 0xe1500003, 0x0a000046, 0x8a000007, 0xe59f3128, + 0xe1500003, 0x0a00001a, 0xe59f3120, 0xe1500003, 0x159f311c, 0x1a000005, + 0xea00000e, 0xe59f3114, 0xe1500003, 0x0a000012, 0x8a000003, 0xe59f3108, + 0xe1560003, 0x1a00001b, 0xea000008, 0xe59f30fc, 0xe1500003, 0x0a000003, + 0xe2833004, 0xe1500003, 0x1a000014, 0xea00002e, 0xe59f10e4, 0xea00002f, + 0xe59f30e0, 0xe5933000, 0xe2833a16, 0xe5931000, 0xea00002a, 0xe59f30d0, + 0xe5933000, 0xe2833a05, 0xe5933014, 0xe2031018, 0xe3c3203f, 0xe3822008, + 0xe2030006, 0xe18220a0, 0xe2033001, 0xe1823103, 0xe1831081, 0xea00001d, + 0xe3a05000, 0xe58d5004, 0xe1a00006, 0xebffffbe, 0xe2504000, 0x1a000005, + 0xe20634ff, 0xe3530206, 0x13530207, 0x15961000, 0x1a000012, 0xea000010, + 0xe5943004, 0xe1a00006, 0xe28d1004, 0xe12fff33, 0xe2501000, 0x0a00000b, + 0xe5911000, 0xe5943010, 0xe3530000, 0x0a000007, 0xe59d0004, 0xe1a02005, + 0xe12fff33, 0xe1a01000, 0xea000002, 0xe59f1034, 0xea000000, 0xe1a01004, + 0xe1a00001, 0xe8bd807c, 0xa016018c, 0xa0005014, 0xa0160188, 0x90016000, + 0xf3005014, 0xf2016000, 0xf3160188, 0x31303130, 0xc0015e4c, 0xc0015e48, + 0x00474b37, 0xe92d4010, 0xe1a04000, 0xebfffe81, 0xe3500000, 0xba00000b, + 0xe3500023, 0xca000009, 0xe3a02014, 0xe59f302c, 0xe0203092, 0xe5903004, + 0xe3530000, 0x0a000005, 0xe1a00004, 0xe3a01000, 0xe12fff33, 0xe8bd8010, + 0xe3a00000, 0xe8bd8010, 0xe1a00003, 0xe8bd8010, 0xc0014ac0, 0xe92d4073, + 0xe1a05000, 0xe1a04001, 0xe1a00001, 0xebffff7c, 0xe1a06000, 0xe3a03000, + 0xe58d3004, 0xe59f3084, 0xe1540003, 0x0a000004, 0xe59f307c, 0xe1540003, + 0x02433243, 0x1a000003, 0xea000000, 0xe59f306c, 0xe5835000, 0xea000016, + 0xe3500000, 0x1a000004, 0xe20434ff, 0xe3530206, 0x13530207, 0x0a000010, + 0xea00000e, 0xe5903004, 0xe1a00004, 0xe28d1004, 0xe12fff33, 0xe2504000, + 0x0a000009, 0xe5963010, 0xe3530000, 0x0a000005, 0xe59d0004, 0xe1a01005, + 0xe3a02001, 0xe12fff33, 0xe5840000, 0xea000000, 0xe5845000, 0xe8bd807c, + 0x90016000, 0xa0005004, 0x60016000, 0xe92d4073, 0xe1a05000, 0xe1a04001, + 0xe3a03000, 0xe58d3004, 0xe1a00001, 0xebffff4c, 0xe2506000, 0x1a000004, + 0xe20434ff, 0xe3530206, 0x13530207, 0x0a000010, 0xea00000e, 0xe5963004, + 0xe1a00004, 0xe28d1004, 0xe12fff33, 0xe2504000, 0x0a000009, 0xe596300c, + 0xe3530000, 0x0a000005, 0xe59d0004, 0xe1a01005, 0xe3a02001, 0xe12fff33, + 0xe1c400b0, 0xea000000, 0xe1c450b0, 0xe8bd807c, 0xe92d4073, 0xe1a05000, + 0xe1a04001, 0xe3a03000, 0xe58d3004, 0xe1a00001, 0xebffff2d, 0xe2506000, + 0x1a000004, 0xe20434ff, 0xe3530206, 0x13530207, 0x0a000010, 0xea00000e, + 0xe5963004, 0xe1a00004, 0xe28d1004, 0xe12fff33, 0xe2504000, 0x0a000009, + 0xe5963008, 0xe3530000, 0x0a000005, 0xe59d0004, 0xe1a01005, 0xe3a02001, + 0xe12fff33, 0xe5c40000, 0xea000000, 0xe5c45000, 0xe8bd807c, 0xe92d4073, + 0xe1a06000, 0xe3a05000, 0xe58d5004, 0xebffff10, 0xe2504000, 0x1a000005, + 0xe20634ff, 0xe3530206, 0x13530207, 0x11d610b0, 0x01a01004, 0xea00000d, + 0xe5943004, 0xe1a00006, 0xe28d1004, 0xe12fff33, 0xe2501000, 0x0a000007, + 0xe1d110b0, 0xe594300c, 0xe3530000, 0x0a000003, 0xe59d0004, 0xe1a02005, + 0xe12fff33, 0xe1a01000, 0xe1a00001, 0xe8bd807c, 0xe92d4073, 0xe1a06000, + 0xe3a05000, 0xe58d5004, 0xebfffef3, 0xe2504000, 0x1a000005, 0xe20634ff, + 0xe3530206, 0x13530207, 0x15d61000, 0x01a01004, 0xea00000d, 0xe5943004, + 0xe1a00006, 0xe28d1004, 0xe12fff33, 0xe2501000, 0x0a000007, 0xe5d11000, + 0xe5943008, 0xe3530000, 0x0a000003, 0xe59d0004, 0xe1a02005, 0xe12fff33, + 0xe1a01000, 0xe1a00001, 0xe8bd807c, 0xe3510000, 0x1a000007, 0xe6ff3070, + 0xe1a020a3, 0xe2000001, 0xe2022003, 0xe1820100, 0xe2033030, 0xe1830000, + 0xe12fff1e, 0xe2001001, 0xe6ff0070, 0xe1a03080, 0xe2033004, 0xe1a02e80, + 0xe1833081, 0xe1833fa2, 0xe2000030, 0xe1800003, 0xe12fff1e, 0xe3510000, + 0xe2003001, 0x1a00001a, 0xe1a010a0, 0xe2011002, 0xe1a0c080, 0xe1813003, + 0xe20cc004, 0xe1a010a0, 0xe18cc003, 0xe2011c01, 0xe1a030a0, 0xe181100c, + 0xe2033c02, 0xe1a02100, 0xe1833001, 0xe2022b01, 0xe1822003, 0xe2003b42, + 0xe1a010a0, 0xe1832002, 0xe2011802, 0xe1a03080, 0xe1811002, 0xe2033701, + 0xe1833001, 0xe59f2074, 0xe0002002, 0xe1820003, 0xe12fff1e, 0xe1a01080, + 0xe2011004, 0xe1a020a0, 0xe1813003, 0xe2022002, 0xe1a01080, 0xe1823003, + 0xe2011c02, 0xe1a02080, 0xe1811003, 0xe2022b01, 0xe1a03120, 0xe1822001, + 0xe2033c01, 0xe1833002, 0xe2002b42, 0xe1a01080, 0xe1823003, 0xe2011701, + 0xe1a020a0, 0xe1811003, 0xe2022802, 0xe1822001, 0xe59f3008, 0xe0003003, + 0xe1830002, 0xe12fff1e, 0x1ff80000, 0xe3510000, 0xe2003001, 0xe6ef0070, + 0xe2001002, 0x1a000007, 0xe1a02080, 0xe1813003, 0xe2022008, 0xe1a000a0, + 0xe1823003, 0xe2000004, 0xe1800003, 0xe12fff1e, 0xe1a020a0, 0xe1813003, + 0xe2022004, 0xe1a00080, 0xe1823003, 0xe2000008, 0xe1800003, 0xe12fff1e, + 0xe3510000, 0xe200103f, 0xe1a033a0, 0xe2033001, 0xe1811383, 0x1a00000b, + 0xe59f2058, 0xe0002002, 0xe1a0c0a0, 0xe1822001, 0xe20c1501, 0xe1a03080, + 0xe1812002, 0xe2033502, 0xe1832002, 0xe200040f, 0xe1800002, 0xe12fff1e, + 0xe59f3028, 0xe0003003, 0xe1a0c080, 0xe1833001, 0xe20c1502, 0xe1a020a0, + 0xe1813003, 0xe2022501, 0xe1823003, 0xe200040f, 0xe1800003, 0xe12fff1e, + 0x00273f00, 0xe3510000, 0xe1a030a0, 0x1a00000b, 0xe2033001, 0xe1a020a0, + 0xe2022002, 0xe1a010a0, 0xe1823003, 0xe2011004, 0xe2002001, 0xe1813003, + 0xe1833182, 0xe2000090, 0xe1800003, 0xe12fff1e, 0xe2002001, 0xe2031001, + 0xe1a01101, 0xe1a03080, 0xe1811082, 0xe2033008, 0xe1a02e00, 0xe1833001, + 0xe1833fa2, 0xe2000090, 0xe1800003, 0xe12fff1e, 0xe92d4010, 0xe2004001, + 0xe6ff3070, 0xe3510000, 0x1a00000f, 0xe1a010a3, 0xe2011002, 0xe1a020a3, + 0xe1811004, 0xe2022004, 0xe1a0c0a3, 0xe1822001, 0xe20cc008, 0xe1a00183, + 0xe18cc002, 0xe2000010, 0xe180000c, 0xe59f1048, 0xe0031001, 0xe1810000, + 0xe8bd8010, 0xe1a01083, 0xe2011004, 0xe1a02083, 0xe1811004, 0xe2022008, + 0xe1a0c083, 0xe1822001, 0xe20cc010, 0xe1a001a3, 0xe18cc002, 0xe2000002, + 0xe180000c, 0xe59f2008, 0xe0032002, 0xe1820000, 0xe8bd8010, 0x0000c1e0, + 0xe200c001, 0xe6ff3070, 0xe3510000, 0x1a000011, 0xe1a010a3, 0xe2011002, + 0xe1a02083, 0xe181100c, 0xe2022004, 0xe1822001, 0xe2030008, 0xe1a0c0a3, + 0xe1802002, 0xe20cc010, 0xe1a00083, 0xe18cc002, 0xe2000020, 0xe180000c, + 0xe59f1050, 0xe0031001, 0xe1810000, 0xe12fff1e, 0xe1a01083, 0xe2011004, + 0xe1a020a3, 0xe181100c, 0xe2022002, 0xe1822001, 0xe2030008, 0xe1a0c083, + 0xe1802002, 0xe20cc020, 0xe1a000a3, 0xe18cc002, 0xe2000010, 0xe180000c, + 0xe59f2008, 0xe0032002, 0xe1820000, 0xe12fff1e, 0x0000c1c0, 0xe200c001, + 0xe6ff3070, 0xe3510000, 0x1a000014, 0xe1a000a3, 0xe2000002, 0xe1a010a3, + 0xe180000c, 0xe2011004, 0xe1a02103, 0xe1811000, 0xe2022008, 0xe1822001, + 0xe2030010, 0xe1a0c0a3, 0xe1802002, 0xe20cc020, 0xe1a00083, 0xe18cc002, + 0xe2000040, 0xe180000c, 0xe59f105c, 0xe0031001, 0xe1810000, 0xe12fff1e, + 0xe1a00083, 0xe2000004, 0xe1a01083, 0xe180000c, 0xe2011008, 0xe1a02123, + 0xe1811000, 0xe2022002, 0xe1822001, 0xe2030010, 0xe1a0c083, 0xe1802002, + 0xe20cc040, 0xe1a000a3, 0xe18cc002, 0xe2000020, 0xe180000c, 0xe59f2008, + 0xe0032002, 0xe1820000, 0xe12fff1e, 0x00008380, 0xe3510000, 0x1a00000a, + 0xe6ff2070, 0xe1a010a2, 0xe200000b, 0xe2011010, 0xe1a03082, 0xe1810000, + 0xe2033020, 0xe1830000, 0xe2022dff, 0xe1820000, 0xe12fff1e, 0xe6ff3070, + 0xe1a01083, 0xe200000b, 0xe2011020, 0xe1a020a3, 0xe1810000, 0xe2022010, + 0xe1820000, 0xe2033dff, 0xe1830000, 0xe12fff1e, 0xe3510000, 0x1a000007, + 0xe6ef3070, 0xe1a020a3, 0xe2022001, 0xe2000001, 0xe1820080, 0xe2033004, + 0xe1830000, 0xe12fff1e, 0xe2001001, 0xe6ef3070, 0xe1a020a3, 0xe2022001, + 0xe1822081, 0xe2030004, 0xe1800002, 0xe12fff1e, 0xe3510000, 0xe2003001, + 0xe6ef0070, 0x1a00000f, 0xe1a010a0, 0xe2011002, 0xe1a02080, 0xe1813003, + 0xe2022004, 0xe1823003, 0xe2001008, 0xe1a023a0, 0xe1813003, 0xe1833202, + 0xe2002060, 0xe1a00180, 0xe1823003, 0xe2000080, 0xe1800003, 0xe12fff1e, + 0xe1a01080, 0xe2011004, 0xe1a020a0, 0xe1813003, 0xe2022002, 0xe1822003, + 0xe2001008, 0xe1a03180, 0xe1812002, 0xe2033080, 0xe1833002, 0xe2002060, + 0xe1a003a0, 0xe1823003, 0xe1830200, 0xe12fff1e, 0xe3510000, 0x1a000007, + 0xe6ef3070, 0xe1a020a3, 0xe2022001, 0xe2000001, 0xe1820080, 0xe2033004, + 0xe1830000, 0xe12fff1e, 0xe2001001, 0xe6ef3070, 0xe1a020a3, 0xe2022001, + 0xe1822081, 0xe2030004, 0xe1800002, 0xe12fff1e, 0xe92d4010, 0xe1a00a00, + 0xe1a0ca20, 0xe3a02000, 0xe1a03002, 0xe59f4060, 0xe7920004, 0xe15c0000, + 0xe59f0054, 0x1a00000b, 0xe3510000, 0x13a0200c, 0x10220392, 0x15812000, + 0xe3a0200c, 0xe0230392, 0xe59f2038, 0xe5920000, 0xe5933004, 0xe0800003, + 0xe2800a02, 0xe8bd8010, 0xe2833001, 0xe282200c, 0xe353001f, 0x1affffeb, + 0xe59f3010, 0xe5930000, 0xe2800a02, 0xe080000c, 0xe8bd8010, 0xc0014df4, + 0xc0015e4c, 0xe92d4010, 0xe1a00a00, 0xe1a0ca20, 0xe3a02000, 0xe1a03002, + 0xe59f4060, 0xe7920004, 0xe15c0000, 0xe59f0054, 0x1a00000b, 0xe3510000, + 0x13a0200c, 0x10220392, 0x15812000, 0xe3a0200c, 0xe0230392, 0xe59f2038, + 0xe5920000, 0xe5933004, 0xe0800003, 0xe2800a05, 0xe8bd8010, 0xe2833001, + 0xe282200c, 0xe3530015, 0x1affffeb, 0xe59f3010, 0xe5930000, 0xe2800a05, + 0xe080000c, 0xe8bd8010, 0xc0014f68, 0xc0015e4c, 0xe1a00001, 0xe12fff1e, + 0xe1a00001, 0xe12fff1e, 0xe92d4008, 0xe1a03001, 0xe3500000, 0x0a000006, + 0xe590c008, 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, 0xe12fff3c, + 0xe1a03000, 0xe1a00003, 0xe8bd8008, 0xe24dd008, 0xe59f3044, 0xe5933000, + 0xe3510000, 0x1a000007, 0xe2833a03, 0xe5932010, 0xe5933014, 0xe58d1000, + 0xe5cd2000, 0xe5cd3001, 0xe59d0000, 0xea000004, 0xe1a02420, 0xe6ef2072, + 0xe2833a03, 0xe5832014, 0xe6ef0070, 0xe28dd008, 0xe12fff1e, 0xc0015e48, + 0xe24dd008, 0xe59f302c, 0xe5933000, 0xe2510000, 0x0a000006, 0xe2833a03, + 0xe5932014, 0xe3a03000, 0xe58d3000, 0xe5cd3000, 0xe5cd2001, 0xe59d0000, + 0xe28dd008, 0xe12fff1e, 0xc0015e48, 0xe24dd010, 0xe3510000, 0x1a00000d, + 0xe58d1008, 0xe1a02180, 0xe2022010, 0xe1a030a0, 0xe20110ed, 0xe2033002, + 0xe1811002, 0xe1a00e00, 0xe1811003, 0xe3c11001, 0xe1810fa0, 0xe5cd0008, + 0xe59d0008, 0xea000007, 0xe6ef0070, 0xe1a021a0, 0xe1a03080, 0xe2022002, + 0xe2033004, 0xe2000001, 0xe1833002, 0xe1830180, 0xe28dd010, 0xe12fff1e, + 0xe3510000, 0xe1a03120, 0x1a000009, 0xe2001001, 0xe2033001, 0xe1a03083, + 0xe1a02e00, 0xe1833101, 0xe1a00100, 0xe1833fa2, 0xe2000008, 0xe1800003, + 0xe12fff1e, 0xe2033001, 0xe1a01080, 0xe2011004, 0xe2002001, 0xe1813003, + 0xe1a00120, 0xe1833182, 0xe2000002, 0xe1800003, 0xe12fff1e, 0xe6ef2070, + 0xe1a03122, 0xe3530007, 0xca00000f, 0xe3510000, 0x13a0c00c, 0x159f2050, + 0x1022239c, 0x15812000, 0xe3100901, 0xe59f1040, 0xe3a0000c, 0xe59f203c, + 0xe0231390, 0xe5920000, 0xe5933004, 0xe0800003, 0x12800a07, 0x02800a03, + 0xe12fff1e, 0xe3100901, 0xe59f3018, 0xe5930000, 0x12800a07, 0x10800002, + 0x02800a03, 0x00800002, 0xe12fff1e, 0xc0015064, 0xc0015e48, 0xe1a00001, + 0xe12fff1e, 0xe1a00001, 0xe12fff1e, 0xe92d4008, 0xe1a03001, 0xe3500000, + 0x0a000006, 0xe590c008, 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, + 0xe12fff3c, 0xe1a03000, 0xe1a00003, 0xe8bd8008, 0xe59f3010, 0xe5933000, + 0xe2833a09, 0xe1a00a00, 0xe0830a20, 0xe12fff1e, 0xc0015e48, 0xe3510000, + 0xe200301f, 0x1a00000f, 0xe1a02180, 0xe2022c02, 0xe1a01120, 0xe1823003, + 0xe2011080, 0xe1a021a0, 0xe1811003, 0xe2022020, 0xe1a03080, 0xe1822001, + 0xe2033040, 0xe1a00080, 0xe1833002, 0xe2000c01, 0xe1800003, 0xe12fff1e, + 0xe1a021a0, 0xe2022040, 0xe1a01100, 0xe1823003, 0xe2011c02, 0xe1a02180, + 0xe1811003, 0xe2022c01, 0xe1a030a0, 0xe1822001, 0xe2033020, 0xe1a000a0, + 0xe1833002, 0xe2000080, 0xe1800003, 0xe12fff1e, 0xe3510000, 0xe2003003, + 0x1a000012, 0xe1a01120, 0xe2011020, 0xe1a02120, 0xe1813003, 0xe2022004, + 0xe1a01280, 0xe1823003, 0xe2011080, 0xe1a021a0, 0xe1811003, 0xe2022008, + 0xe1a03080, 0xe1822001, 0xe2033010, 0xe1a00080, 0xe1833002, 0xe2000040, + 0xe1800003, 0xe12fff1e, 0xe1a01100, 0xe2011080, 0xe1a02100, 0xe1813003, + 0xe2022010, 0xe1a012a0, 0xe1823003, 0xe2011004, 0xe1a02180, 0xe1811003, + 0xe2022040, 0xe1a030a0, 0xe1822001, 0xe2033008, 0xe1a000a0, 0xe1833002, + 0xe2000020, 0xe1800003, 0xe12fff1e, 0xe3510000, 0xe1a030a0, 0x1a000008, + 0xe1a01120, 0xe2033001, 0xe2011004, 0xe1a02e00, 0xe1813083, 0xe2000001, + 0xe1833fa2, 0xe1830200, 0xe12fff1e, 0xe1a01100, 0xe2033001, 0xe2011010, + 0xe2002001, 0xe1813083, 0xe1a00d80, 0xe1833182, 0xe1830fa0, 0xe12fff1e, + 0xe3510000, 0x1a000009, 0xe1a01120, 0xe1a03100, 0xe2011004, 0xe2033008, + 0xe1a02e00, 0xe1833001, 0xe2000001, 0xe1833fa2, 0xe1830200, 0xe12fff1e, + 0xe1a01100, 0xe1a03120, 0xe2011010, 0xe2033002, 0xe2002001, 0xe1833001, + 0xe1a00d80, 0xe1833182, 0xe1830fa0, 0xe12fff1e, 0xe3510000, 0xe1a031a0, + 0x1a000009, 0xe2033001, 0xe2001001, 0xe1a01181, 0xe1a02f00, 0xe1813103, + 0xe1a000a0, 0xe1833fa2, 0xe2000002, 0xe1800003, 0xe12fff1e, 0xe1a01080, + 0xe2033001, 0xe2011008, 0xe2002001, 0xe1833001, 0xe1a00080, 0xe1833082, + 0xe2000004, 0xe1800003, 0xe12fff1e, 0xe3510000, 0xe1a031a0, 0x1a000008, + 0xe1a01100, 0xe2033001, 0xe2011008, 0xe2002001, 0xe1813103, 0xe1a00e80, + 0xe1833082, 0xe1830fa0, 0xe12fff1e, 0xe2033001, 0xe1a01080, 0xe2011008, + 0xe1a02f00, 0xe1813083, 0xe2000001, 0xe1833fa2, 0xe1830100, 0xe12fff1e, + 0xe3510000, 0xe1a03220, 0x1a00000b, 0xe1a02180, 0xe2033001, 0xe2022010, + 0xe2001001, 0xe1823183, 0xe1a02e80, 0xe1833081, 0xe1a000a0, 0xe1833fa2, + 0xe2000004, 0xe1800003, 0xe12fff1e, 0xe2033001, 0xe1a02080, 0xe2022010, + 0xe1a01f00, 0xe1823083, 0xe2002001, 0xe1833fa1, 0xe1a00080, 0xe1833102, + 0xe2000008, 0xe1800003, 0xe12fff1e, 0xe1a030a0, 0xe2000001, 0xe2033001, + 0xe1830080, 0xe12fff1e, 0xe3510000, 0xe1a030a0, 0x1a000008, 0xe1a02220, + 0xe2022001, 0xe2033001, 0xe1823083, 0xe200200c, 0xe2000001, 0xe1823003, + 0xe1830200, 0xe12fff1e, 0xe2002001, 0xe2033001, 0xe1a03083, 0xe1833202, + 0xe200200c, 0xe1a00d80, 0xe1823003, 0xe1830fa0, 0xe12fff1e, 0xe3510000, + 0xe1a03220, 0x1a00000b, 0xe1a02180, 0xe2033001, 0xe2022010, 0xe2001001, + 0xe1823183, 0xe1a02e80, 0xe1833081, 0xe1a000a0, 0xe1833fa2, 0xe2000004, + 0xe1800003, 0xe12fff1e, 0xe2033001, 0xe1a02080, 0xe2022010, 0xe1a01f00, + 0xe1823083, 0xe2002001, 0xe1833fa1, 0xe1a00080, 0xe1833102, 0xe2000008, + 0xe1800003, 0xe12fff1e, 0xe6ef0070, 0xe1a03120, 0xe3530016, 0xe59f2040, + 0xca00000b, 0xe3510000, 0xe59f0038, 0x13a0c00c, 0x102c039c, 0x1581c000, + 0xe3a0100c, 0xe0230391, 0xe5920000, 0xe5933004, 0xe0800003, 0xe2800a0a, + 0xe12fff1e, 0xe5923000, 0xe2833a0a, 0xe0830000, 0xe12fff1e, 0xc0015e4c, + 0xc00150c4, 0xe92d4008, 0xe1a03001, 0xe3500000, 0x0a000006, 0xe590c008, + 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, 0xe12fff3c, 0xe1a03000, + 0xe1a00003, 0xe8bd8008, 0xe59f3014, 0xe5933000, 0xe2833702, 0xe3c004ff, + 0xe3c0073e, 0xe0830000, 0xe12fff1e, 0xc0015e4c, 0xe3510000, 0x1a000005, + 0xe1a02420, 0xe200003f, 0xe59f3028, 0xe0023003, 0xe1830a00, 0xe12fff1e, + 0xe1a01400, 0xe59f3018, 0xe0013003, 0xe2012407, 0xe1a00300, 0xe1823003, + 0xe1830d20, 0xe12fff1e, 0x00077fff, 0x007fff00, 0xe3510000, 0x1a000005, + 0xe1a02420, 0xe200003f, 0xe59f3028, 0xe0023003, 0xe1830a00, 0xe12fff1e, + 0xe1a01400, 0xe59f3018, 0xe0013003, 0xe2012407, 0xe1a00300, 0xe1823003, + 0xe1830d20, 0xe12fff1e, 0x00077fff, 0x007fff00, 0xe3510000, 0x1a000005, + 0xe1a02420, 0xe200003f, 0xe59f3028, 0xe0023003, 0xe1830a00, 0xe12fff1e, + 0xe1a01400, 0xe59f3018, 0xe0013003, 0xe2012407, 0xe1a00300, 0xe1823003, + 0xe1830d20, 0xe12fff1e, 0x00077fff, 0x007fff00, 0xe3510000, 0x1a000005, + 0xe1a02420, 0xe200003f, 0xe59f3028, 0xe0023003, 0xe1830a00, 0xe12fff1e, + 0xe1a01400, 0xe59f3018, 0xe0013003, 0xe2012407, 0xe1a00300, 0xe1823003, + 0xe1830d20, 0xe12fff1e, 0x00077fff, 0x007fff00, 0xe3510000, 0xe1a030a0, + 0x1a000009, 0xe2033001, 0xe1a010a0, 0xe2011002, 0xe1a020a0, 0xe1813003, + 0xe2022004, 0xe2000001, 0xe1823003, 0xe1830180, 0xe12fff1e, 0xe2001001, + 0xe2032001, 0xe1a02102, 0xe1a03080, 0xe1822081, 0xe2033008, 0xe1a00e00, + 0xe1833002, 0xe1830fa0, 0xe12fff1e, 0xe3510000, 0x1a000005, 0xe1a02420, + 0xe200003f, 0xe59f3028, 0xe0023003, 0xe1830a00, 0xe12fff1e, 0xe1a01400, + 0xe59f3018, 0xe0013003, 0xe2012407, 0xe1a00300, 0xe1823003, 0xe1830d20, + 0xe12fff1e, 0x00077fff, 0x007fff00, 0xe3510000, 0xe1a030a0, 0x1a000014, + 0xe2033001, 0xe1a020a0, 0xe2022002, 0xe1a010a0, 0xe1823003, 0xe2011004, + 0xe1a020a0, 0xe1813003, 0xe2022008, 0xe1a010a0, 0xe1822003, 0xe2011010, + 0xe1a030a0, 0xe1811002, 0xe2033020, 0xe2002001, 0xe1833001, 0xe1833302, + 0xe2000601, 0xe1800003, 0xe12fff1e, 0xe2002001, 0xe203c001, 0xe1a0c10c, + 0xe1a03080, 0xe18cc082, 0xe2033008, 0xe1a02080, 0xe183300c, 0xe2022010, + 0xe1a01080, 0xe1822003, 0xe2011020, 0xe1a03080, 0xe1811002, 0xe2033040, + 0xe1a02c80, 0xe1833001, 0xe1833fa2, 0xe2000601, 0xe1800003, 0xe12fff1e, + 0xe3510000, 0xe1a03220, 0x02033001, 0x0200000f, 0x01830200, 0x12000001, + 0x1203300f, 0x11830200, 0xe12fff1e, 0xe3510000, 0xe200303f, 0x1a000008, + 0xe1a01420, 0xe201103f, 0xe1a02420, 0xe1813803, 0xe2022c3f, 0xe1823003, + 0xe200043f, 0xe1800003, 0xe12fff1e, 0xe1a01820, 0xe201103f, 0xe1a02400, + 0xe1813403, 0xe202283f, 0xe1823003, 0xe200043f, 0xe1800003, 0xe12fff1e, + 0xe92d4010, 0xe6ff0070, 0xe3a02000, 0xe1a03002, 0xe59f4060, 0xe792c004, + 0xe150000c, 0xe59fc054, 0x1a00000b, 0xe3510000, 0x13a0200c, 0x1022c392, + 0x15812000, 0xe3a0200c, 0xe023c392, 0xe59f2038, 0xe5920000, 0xe5933004, + 0xe0800003, 0xe2800817, 0xe8bd8010, 0xe2833001, 0xe282200c, 0xe353003e, + 0x1affffeb, 0xe59f3010, 0xe5933000, 0xe2833817, 0xe0830000, 0xe8bd8010, + 0xc00151d8, 0xc0015e48, 0xe92d4008, 0xe1a03001, 0xe3500000, 0x0a000006, + 0xe590c008, 0xe35c0000, 0x0a000003, 0xe1a00001, 0xe1a01002, 0xe12fff3c, + 0xe1a03000, 0xe1a00003, 0xe8bd8008, 0xe59f300c, 0xe5933000, 0xe2833a05, + 0xe6e30070, 0xe12fff1e, 0xc0015e4c, 0xe92d4010, 0xe6ef0070, 0xe3a02000, + 0xe1a03002, 0xe59f4060, 0xe792c004, 0xe150000c, 0xe59fc054, 0x1a00000b, + 0xe3510000, 0x13a0200c, 0x1022c392, 0x15812000, 0xe3a0200c, 0xe023c392, + 0xe59f2038, 0xe5920000, 0xe5933004, 0xe0800003, 0xe2800b83, 0xe8bd8010, + 0xe2833001, 0xe282200c, 0xe353001f, 0x1affffeb, 0xe59f3010, 0xe5933000, + 0xe2833b83, 0xe0830000, 0xe8bd8010, 0xc00154c0, 0xc0015e4c, 0xe59f300c, + 0xe5933000, 0xe2833b87, 0xe6e30070, 0xe12fff1e, 0xc0015e4c, 0xe3510000, + 0xe1a03820, 0xe1a00800, 0x01830000, 0x11a00820, 0x11800803, 0x11a00860, + 0xe12fff1e, 0xe3510000, 0x01a03a80, 0x02000001, 0x01a00500, 0x01800b23, + 0x11a03b00, 0x11a00520, 0x12000001, 0x11800aa3, 0xe12fff1e, 0xe92d4010, + 0xe6ff0070, 0xe3a02000, 0xe1a03002, 0xe59f4054, 0xe792c004, 0xe150000c, + 0xe59fc048, 0x1a00000b, 0xe3510000, 0x13a0200c, 0x1022c392, 0x15812000, + 0xe3a0200c, 0xe023c392, 0xe59f202c, 0xe5920000, 0xe5933004, 0xe0800003, + 0xe2800801, 0xe8bd8010, 0xe2833001, 0xe282200c, 0xe3530010, 0x1affffeb, + 0xe3a00000, 0xe8bd8010, 0xc0015634, 0xc0015e48, 0xe92d4010, 0xe6ff0070, + 0xe3a02000, 0xe1a03002, 0xe59f4058, 0xe792c004, 0xe150000c, 0xe59fc04c, + 0x1a00000a, 0xe3510000, 0x13a0200c, 0x1022c392, 0x15812000, 0xe3a0200c, + 0xe023c392, 0xe5930004, 0xe59f302c, 0xe5933000, 0xe0800003, 0xe8bd8010, + 0xe2833001, 0xe282200c, 0xe353001c, 0x1affffec, 0xe59f300c, 0xe5933000, + 0xe0800003, 0xe8bd8010, 0xc00156f4, 0xc0015e4c, 0xe3510000, 0xe2003001, + 0x1a000006, 0xe1a020a0, 0xe2022002, 0xe1a00080, 0xe1823003, 0xe2000004, + 0xe1800003, 0xe12fff1e, 0xe1a02080, 0xe2022004, 0xe1a000a0, 0xe1823003, + 0xe2000002, 0xe1800003, 0xe12fff1e, 0xe92d4010, 0xe3a02000, 0xe59f3064, + 0xe4832004, 0xe6ef0070, 0xe1a0c002, 0xe7924003, 0xe1500004, 0x1a00000d, + 0xe3510000, 0x13a0200c, 0x159f3044, 0x10233c92, 0x15813000, 0xe3a0200c, + 0xe59f3030, 0xe02c3c92, 0xe59f3030, 0xe5930000, 0xe59c3008, 0xe0800003, + 0xe2800903, 0xe8bd8010, 0xe28cc001, 0xe282200c, 0xe35c0007, 0x1affffea, + 0xe3a00000, 0xe8bd8010, 0xc0015844, 0xc0015848, 0xc0015e48, 0xe92d4010, + 0xe1a00a00, 0xe1a0ca20, 0xe3a02000, 0xe1a03002, 0xe59f4060, 0xe7920004, + 0xe15c0000, 0xe59f0054, 0x1a00000b, 0xe3510000, 0x13a0200c, 0x10220392, + 0x15812000, 0xe3a0200c, 0xe0230392, 0xe59f2038, 0xe5920000, 0xe5933004, + 0xe0800003, 0xe2800a02, 0xe8bd8010, 0xe2833001, 0xe282200c, 0xe3530019, + 0x1affffeb, 0xe59f3010, 0xe5930000, 0xe2800a02, 0xe080000c, 0xe8bd8010, + 0xc001589c, 0xc0015e48, 0xe92d4010, 0xe1a00a00, 0xe1a0ca20, 0xe3a02000, + 0xe1a03002, 0xe59f4060, 0xe7920004, 0xe15c0000, 0xe59f0054, 0x1a00000b, + 0xe3510000, 0x13a0200c, 0x10220392, 0x15812000, 0xe3a0200c, 0xe0230392, + 0xe59f2038, 0xe5920000, 0xe5933004, 0xe0800003, 0xe2800a0f, 0xe8bd8010, + 0xe2833001, 0xe282200c, 0xe3530019, 0x1affffeb, 0xe59f3010, 0xe5930000, + 0xe2800a0f, 0xe080000c, 0xe8bd8010, 0xc001589c, 0xc0015e48, 0xe92d4010, + 0xe1a00a00, 0xe1a0ca20, 0xe3a02000, 0xe1a03002, 0xe59f0064, 0xe7924000, + 0xe15c0004, 0x1a00000d, 0xe3510000, 0x13a0000c, 0x159f204c, 0x10222390, + 0x15812000, 0xe3a0100c, 0xe59f2040, 0xe0232391, 0xe59f203c, 0xe5920000, + 0xe5933130, 0xe0800003, 0xe2800a01, 0xe8bd8010, 0xe2833001, 0xe282200c, + 0xe3530004, 0x1affffea, 0xe59f3014, 0xe5930000, 0xe2800a01, 0xe080000c, + 0xe8bd8010, 0xc00159c8, 0xc001589c, 0xc0015e48, 0xe3510000, 0x1a000015, + 0xe1a01a80, 0xe1a032a0, 0xe2033002, 0xe1833fa1, 0xe2002004, 0xe1a012a0, + 0xe1823003, 0xe2011010, 0xe1811003, 0xe2003020, 0xe1a02280, 0xe1831001, + 0xe2022040, 0xe1822001, 0xe2001c01, 0xe1a03280, 0xe1812002, 0xe2033c02, + 0xe2000001, 0xe1833002, 0xe1830500, 0xe12fff1e, 0xe2001001, 0xe1a03280, + 0xe2033040, 0xe1833501, 0xe2002004, 0xe1a01280, 0xe1823003, 0xe2011c02, + 0xe1811003, 0xe2003020, 0xe1a022a0, 0xe1831001, 0xe2022002, 0xe1822001, + 0xe2001c01, 0xe1a032a0, 0xe1812002, 0xe2033010, 0xe1a00a80, 0xe1833002, + 0xe1830fa0, 0xe12fff1e, 0xe6ef0070, 0xe1a03120, 0xe353000e, 0xe59f2040, + 0xca00000b, 0xe3510000, 0xe59f0038, 0x13a0c00c, 0x102c039c, 0x1581c000, + 0xe3a0100c, 0xe0230391, 0xe5920000, 0xe5933004, 0xe0800003, 0xe2800a0b, + 0xe12fff1e, 0xe5923000, 0xe2833a0b, 0xe0830000, 0xe12fff1e, 0xc0015e48, + 0xc00159f8, 0xe3510000, 0x1a000002, 0xe1a00160, 0xe6bf0f30, 0xe12fff1e, + 0xe6bf0f30, 0xe1a00f60, 0xe12fff1e, 0xe3510000, 0x1a000002, 0xe1a00160, + 0xe6bf0f30, 0xe12fff1e, 0xe6bf0f30, 0xe1a00f60, 0xe12fff1e, 0xe1a03a00, + 0xe1a02a23, 0xe1a03b23, 0xe353000e, 0xca00000e, 0xe3510000, 0xe59f204c, + 0x13a0000c, 0x10202390, 0x15810000, 0xe3a0100c, 0xe0232391, 0xe5930004, + 0xe3800206, 0xe3800a03, 0xe59f302c, 0xe5933000, 0xe283320a, 0xe1800003, + 0xe12fff1e, 0xe59f3018, 0xe5930000, 0xe280020a, 0xe3800206, 0xe3800a03, + 0xe1800002, 0xe12fff1e, 0xc0015aac, 0xc0015e4c, 0xe1a03a00, 0xe1a02a23, + 0xe1a03b23, 0xe353000e, 0xca00000f, 0xe3510000, 0x13a0000c, 0x159f204c, + 0x10222390, 0x15812000, 0xe3a0100c, 0xe59f2040, 0xe0232391, 0xe59300b8, + 0xe3800206, 0xe3800801, 0xe59f3030, 0xe5933000, 0xe283320a, 0xe1800003, + 0xe12fff1e, 0xe59f301c, 0xe5930000, 0xe280020a, 0xe3800206, 0xe3800801, + 0xe1800002, 0xe12fff1e, 0xc0015b60, 0xc0015aac, 0xc0015e4c, 0xe92d4008, + 0xe1a03001, 0xe3500000, 0x0a000006, 0xe590c008, 0xe35c0000, 0x0a000003, + 0xe1a00001, 0xe1a01002, 0xe12fff3c, 0xe1a03000, 0xe1a00003, 0xe8bd8008, + 0xe3510000, 0x1a00000f, 0xe1a01120, 0xe2003001, 0xe2011003, 0xe1a02100, + 0xe1811103, 0xe2022008, 0xe1a03120, 0xe1822001, 0xe2033010, 0xe1833002, + 0xe2002020, 0xe1a00100, 0xe1823003, 0xe2000040, 0xe1800003, 0xe12fff1e, + 0xe1a01100, 0xe1a03e80, 0xe201100c, 0xe1a02120, 0xe1811fa3, 0xe2022002, + 0xe1a03100, 0xe1822001, 0xe2033040, 0xe1833002, 0xe2002020, 0xe1a00120, + 0xe1823003, 0xe2000010, 0xe1800003, 0xe12fff1e, 0xe3510000, 0x1a000014, + 0xe1a02c80, 0xe1a030a0, 0xe2033002, 0xe1a0c080, 0xe1833fa2, 0xe20cc004, + 0xe1a02120, 0xe18cc003, 0xe2022008, 0xe1a01080, 0xe182200c, 0xe2011010, + 0xe1a03080, 0xe1811002, 0xe2033020, 0xe2002001, 0xe1833001, 0xe1833302, + 0xe2000080, 0xe1800003, 0xe12fff1e, 0xe2002001, 0xe1a03080, 0xe2033004, + 0xe1a0c0a0, 0xe1833302, 0xe20cc002, 0xe1a02100, 0xe18cc003, 0xe2022020, + 0xe1a010a0, 0xe182200c, 0xe2011008, 0xe1a030a0, 0xe1811002, 0xe2033010, + 0xe1a02c80, 0xe1833001, 0xe1833fa2, 0xe2000080, 0xe1800003, 0xe12fff1e, + 0xe3510000, 0xe1a030a0, 0x1a000011, 0xe2033001, 0xe1a010a0, 0xe2011002, + 0xe2002001, 0xe1813003, 0xe1a01080, 0xe1833102, 0xe2011010, 0xe1a02080, + 0xe1811003, 0xe2022020, 0xe1a03120, 0xe1822001, 0xe2033008, 0xe1833002, + 0xe20000c0, 0xe1800003, 0xe12fff1e, 0xe2001001, 0xe2033001, 0xe1a03103, + 0xe1a02e80, 0xe1833081, 0xe1a010a0, 0xe1833fa2, 0xe2011008, 0xe1a020a0, + 0xe1811003, 0xe2022010, 0xe1a03100, 0xe1822001, 0xe2033020, 0xe1833002, + 0xe20000c0, 0xe1800003, 0xe12fff1e, 0xe3510000, 0xe2003003, 0x1a000011, + 0xe1a020a0, 0xe2022004, 0xe1a01080, 0xe1823003, 0xe2011008, 0xe1a021a0, + 0xe1813003, 0xe2022010, 0xe1822003, 0xe2001020, 0xe1a03100, 0xe1812002, + 0xe2033040, 0xe1a00080, 0xe1833002, 0xe2000080, 0xe1800003, 0xe12fff1e, + 0xe1a02080, 0xe2022008, 0xe1a010a0, 0xe1823003, 0xe2011004, 0xe1a02180, + 0xe1813003, 0xe2022080, 0xe1822003, 0xe2001020, 0xe1a03120, 0xe1812002, + 0xe2033010, 0xe1a000a0, 0xe1833002, 0xe2000040, 0xe1800003, 0xe12fff1e, + 0xe6ef3070, 0xe1a03123, 0xe3530006, 0xca00000e, 0xe3510000, 0xe59f2048, + 0x13a0c00c, 0x102c239c, 0x1581c000, 0xe3a0100c, 0xe0232391, 0xe5932004, + 0xe59f3030, 0xe5933000, 0xe0822003, 0xe59f3028, 0xe0003003, 0xe0820003, + 0xe12fff1e, 0xe3c004ff, 0xe3c0060f, 0xe59f300c, 0xe5932000, 0xe0800002, + 0xe12fff1e, 0xc0015c14, 0xc0015e48, 0x000fff00, 0xe59f300c, 0xe5933000, + 0xe2833a0b, 0xe6e30070, 0xe12fff1e, 0xc0015e4c, 0xe2003001, 0xe1a000a0, + 0xe2000001, 0xe1800083, 0xe12fff1e, 0xe1a03a00, 0xe1a0ca23, 0xe1a03b23, + 0xe3530026, 0xe59f2040, 0xca00000b, 0xe3510000, 0xe59f0038, 0x13a0c00c, + 0x102c039c, 0x1581c000, 0xe3a0100c, 0xe0230391, 0xe5920000, 0xe5933004, + 0xe0800003, 0xe2800905, 0xe12fff1e, 0xe5920000, 0xe2800905, 0xe080000c, + 0xe12fff1e, 0xc0015e4c, 0xc0015c68, 0xe59f3010, 0xe5933000, 0xe2833a22, + 0xe1a00a00, 0xe0830a20, 0xe12fff1e, 0xc0015e4c, 0xe59f3018, 0xe5933000, + 0xe283320a, 0xe3833206, 0xe3833a06, 0xe6ff0070, 0xe1830000, 0xe12fff1e, + 0xc0015e4c, 0xe59f300c, 0xe5933000, 0xe2833a21, 0xe6e30070, 0xe12fff1e, + 0xc0015e4c, 0xe3510000, 0xe1a03220, 0x1a000008, 0xe203300f, 0xe1a01180, + 0xe2011070, 0xe2002001, 0xe1813003, 0xe1833382, 0xe2000cff, 0xe1800003, + 0xe12fff1e, 0xe200100f, 0xe2033007, 0xe1a03083, 0xe1a02c00, 0xe1833201, + 0xe1833fa2, 0xe2000cff, 0xe1800003, 0xe12fff1e, 0xe59f3010, 0xe5933000, + 0xe2833b83, 0xe2833c02, 0xe6e30070, 0xe12fff1e, 0xc0015e4c, 0xe59f3010, + 0xe5933000, 0xe2833a16, 0xe1a00a00, 0xe0830a20, 0xe12fff1e, 0xc0015e4c, + 0xe6ef0070, 0xe59f2040, 0xe5923000, 0xe1500003, 0xe59f3038, 0x1a000007, + 0xe3510000, 0x15812000, 0xe5930000, 0xe5923004, 0xe0800003, 0xe2800b82, + 0xe2800c02, 0xe12fff1e, 0xe5933000, 0xe2833b82, 0xe2833c02, 0xe0830000, + 0xe12fff1e, 0xc0015e3c, 0xc0015e4c, 0xe59f3010, 0xe5933000, 0xe2833a0d, + 0xe1a00a00, 0xe0830a20, 0xe12fff1e, 0xc0015e48, 0xe59f3010, 0xe5933000, + 0xe2833b89, 0xe2833c02, 0xe6e30070, 0xe12fff1e, 0xc0015e4c, 0xe59f3010, + 0xe5933000, 0xe2833901, 0xe1a00a00, 0xe0830a20, 0xe12fff1e, 0xc0015e4c, + 0xe59f300c, 0xe5933000, 0xe2833815, 0xe6f30070, 0xe12fff1e, 0xc0015e48, + 0xe59f300c, 0xe5933000, 0xe2833811, 0xe6f30070, 0xe12fff1e, 0xc0015e48, + 0xe59f300c, 0xe5933000, 0xe2833812, 0xe6f30070, 0xe12fff1e, 0xc0015e48, + 0xe59f300c, 0xe5933000, 0xe2833816, 0xe6f30070, 0xe12fff1e, 0xc0015e48, + 0x00000000, 0xc0013318, 0xc0012264, 0xc0012230, 0xc00121fc, 0x00000001, + 0xc001339c, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0xc00135bc, + 0x00000000, 0x00000000, 0xc0013644, 0x00000003, 0xc0013678, 0x00000000, + 0x00000000, 0x00000000, 0x00000004, 0xc0013a60, 0x00000000, 0x00000000, + 0xc00121fc, 0x00000005, 0xc0013af0, 0x00000000, 0x00000000, 0x00000000, + 0x00000006, 0xc0013e00, 0x00000000, 0x00000000, 0xc00121fc, 0x00000007, + 0xc0013eb4, 0x00000000, 0x00000000, 0x00000000, 0x00000008, 0xc0013fac, + 0x00000000, 0x00000000, 0xc00121fc, 0x00000009, 0xc0014020, 0x00000000, + 0x00000000, 0x00000000, 0x0000000a, 0xc00140dc, 0x00000000, 0x00000000, + 0xc00121fc, 0x0000000b, 0xc001415c, 0x00000000, 0x00000000, 0x00000000, + 0x0000000c, 0xc00143a8, 0x00000000, 0x00000000, 0xc00121fc, 0x0000000d, + 0xc00147d8, 0x00000000, 0x00000000, 0xc00121fc, 0x0000000e, 0xc0014848, + 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0xc0014874, 0x00000000, + 0x00000000, 0xc00121fc, 0x00000010, 0xc00148d4, 0x00000000, 0x00000000, + 0x00000000, 0x00000011, 0xc00148f0, 0x00000000, 0x00000000, 0x00000000, + 0x00000012, 0xc0014914, 0x00000000, 0x00000000, 0x00000000, 0x00000013, + 0xc0014980, 0x00000000, 0x00000000, 0x00000000, 0x00000014, 0xc001499c, + 0x00000000, 0x00000000, 0x00000000, 0x00000015, 0xc00149b8, 0xc0012264, + 0xc0012230, 0xc00121fc, 0x00000016, 0xc0014a0c, 0x00000000, 0x00000000, + 0x00000000, 0x00000017, 0xc0013ecc, 0x00000000, 0x00000000, 0x00000000, + 0x00000018, 0xc0013f4c, 0x00000000, 0x00000000, 0x00000000, 0x00000019, + 0xc0014a28, 0x00000000, 0x00000000, 0x00000000, 0x0000001a, 0xc0013af0, + 0x00000000, 0x00000000, 0x00000000, 0x0000001b, 0xc0014264, 0x00000000, + 0x00000000, 0x00000000, 0x0000001c, 0xc00141e0, 0x00000000, 0x00000000, + 0x00000000, 0x0000001d, 0xc0014444, 0x00000000, 0x00000000, 0xc00121fc, + 0x0000001e, 0xc00144b8, 0x00000000, 0x00000000, 0xc00121fc, 0x0000001f, + 0xc0014a44, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0xc0014a60, + 0x00000000, 0x00000000, 0x00000000, 0x00000021, 0xc0014a78, 0x00000000, + 0x00000000, 0x00000000, 0x00000022, 0xc0014a90, 0x00000000, 0x00000000, + 0x00000000, 0x00000023, 0xc0014aa8, 0x00000000, 0x00000000, 0x00000000, + 0x00424841, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00060000, 0x01000000, 0x00000000, + 0x00425041, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00070000, 0x01000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000c, 0x00000004, + 0x00000000, 0x0000000a, 0x00000006, 0x00000000, 0x00000034, 0x00000008, + 0x00000000, 0x00000004, 0x0000000c, 0xc0012d2c, 0x00000016, 0x0000000e, + 0xc0013198, 0x0000001c, 0x00000010, 0x00000000, 0x0000001e, 0x00000012, + 0x00000000, 0x00000020, 0x00000014, 0x00000000, 0x00000022, 0x00000016, + 0x00000000, 0x00000024, 0x00000018, 0x00000000, 0x00000026, 0x0000001a, + 0x00000000, 0x00000028, 0x0000001c, 0x00000000, 0x0000002a, 0x0000001e, + 0x00000000, 0x00000040, 0x00000020, 0x00000000, 0x00000030, 0x00000024, + 0xc0012d7c, 0x0000002c, 0x00000028, 0xc0012e64, 0x0000002d, 0x00000029, + 0x00000000, 0x0000002e, 0x0000002a, 0xc0013240, 0x0000002f, 0x0000002b, + 0xc00132d0, 0x0000001a, 0x0000002c, 0x00000000, 0x00000018, 0x0000002e, + 0x00000000, 0x00000019, 0x0000002f, 0xc00131f8, 0x00000012, 0x00000030, + 0xc00130dc, 0x00000014, 0x00000032, 0x00000000, 0x0000000e, 0x00000034, + 0x00000000, 0x00000010, 0x00000036, 0xc0013038, 0x00000006, 0x00000038, + 0x00000000, 0x00000008, 0x0000003a, 0xc0012fa0, 0x0000003c, 0x0000003c, + 0xc0012f34, 0x00000038, 0x00000040, 0xc0012eb8, 0x00000304, 0x000003f0, + 0x00000000, 0x00000308, 0x00000380, 0x00000000, 0x0000030c, 0x00000384, + 0x00000000, 0x00000310, 0x00000388, 0x00000000, 0x00000314, 0x0000038c, + 0x00000000, 0x0000031c, 0x00000300, 0x00000000, 0x00000320, 0x00000304, + 0x00000000, 0x00000324, 0x00000308, 0x00000000, 0x00000328, 0x0000030c, + 0x00000000, 0x0000032c, 0x00000310, 0x00000000, 0x00000330, 0x00000314, + 0x00000000, 0x00000334, 0x00000318, 0x00000000, 0x00000338, 0x0000031c, + 0x00000000, 0x0000033c, 0x00000320, 0x00000000, 0x00000340, 0x00000324, + 0x00000000, 0x00000344, 0x00000328, 0x00000000, 0x00000348, 0x0000032c, + 0x00000000, 0x0000034c, 0x00000330, 0x00000000, 0x00000350, 0x00000334, + 0x00000000, 0x00000354, 0x00000338, 0x00000000, 0x00000358, 0x0000033c, + 0x00000000, 0x00000000, 0x00000010, 0xc0013464, 0x00000004, 0x00000014, + 0xc00134b8, 0x00000008, 0x00000018, 0xc00134f4, 0x0000000c, 0x00000004, + 0xc0013560, 0x00000010, 0x0000000c, 0x00000000, 0x00000014, 0x00000000, + 0x00000000, 0x00000018, 0x00000008, 0x00000000, 0x0000001c, 0x0000001c, + 0x00000000, 0x00000000, 0x00000020, 0xc0013694, 0x00000004, 0x00000058, + 0x00000000, 0x00000008, 0x00000000, 0x00000000, 0x0000000c, 0x00000008, + 0xc0013720, 0x00000010, 0x00000018, 0x00000000, 0x00000014, 0x00000028, + 0xc00137c4, 0x00000018, 0x0000003c, 0x00000000, 0x0000001c, 0x0000002c, + 0x00000000, 0x00000020, 0x00000030, 0x00000000, 0x00000024, 0x00000044, + 0xc0013818, 0x00000028, 0x00000050, 0xc0013870, 0x0000002c, 0x00000004, + 0xc00138cc, 0x00000030, 0x00000038, 0x00000000, 0x00000034, 0x00000040, + 0x00000000, 0x00000038, 0x00000048, 0xc0013920, 0x0000003c, 0x0000001c, + 0x00000000, 0x00000040, 0x0000004c, 0x00000000, 0x00000044, 0x00000010, + 0x00000000, 0x00000048, 0x00000054, 0xc001398c, 0x0000004c, 0x00000024, + 0xc00139a0, 0x00000050, 0x00000014, 0x00000000, 0x00000054, 0x00000034, + 0xc00139f4, 0x00000058, 0x0000000c, 0x00000000, 0x00000014, 0x00000000, + 0xc0013b10, 0x0000001c, 0x00000004, 0x00000000, 0x00000018, 0x0000000c, + 0x00000000, 0x00000000, 0x00000014, 0xc0013b58, 0x0000000c, 0x00000018, + 0x00000000, 0x00000004, 0x0000001c, 0x00000000, 0x00000054, 0x00000024, + 0xc0013ba0, 0x0000004c, 0x00000028, 0x00000000, 0x0000003c, 0x0000002c, + 0x00000000, 0x00000038, 0x00000030, 0x00000000, 0x00000034, 0x00000034, + 0x00000000, 0x00000028, 0x00000038, 0x00000000, 0x00000030, 0x0000003c, + 0x00000000, 0x0000002c, 0x0000004c, 0x00000000, 0x00000024, 0x00000054, + 0xc0013be8, 0x00000078, 0x00000058, 0x00000000, 0x00000084, 0x0000005c, + 0x00000000, 0x00000080, 0x00000060, 0x00000000, 0x00000068, 0x00000068, + 0x00000000, 0x00000058, 0x00000078, 0x00000000, 0x0000005c, 0x00000080, + 0x00000000, 0x00000060, 0x00000084, 0x00000000, 0x000000e4, 0x0000008c, + 0xc0013c30, 0x000000e8, 0x0000009c, 0x00000000, 0x000000ec, 0x000000a0, + 0x00000000, 0x000000bc, 0x000000bc, 0x00000000, 0x0000008c, 0x000000e4, + 0xc0013c8c, 0x0000009c, 0x000000e8, 0x00000000, 0x000000a0, 0x000000ec, + 0x00000000, 0x00000108, 0x00000100, 0xc0013cd4, 0x00000100, 0x00000108, + 0xc0013cd4, 0x00000118, 0x00000118, 0x00000000, 0x00000124, 0x0000011c, + 0xc0013cd4, 0x00000130, 0x00000124, 0xc0013cd4, 0x0000011c, 0x00000130, + 0xc0013cd4, 0x000001fc, 0x00000148, 0x00000000, 0x00000200, 0x00000198, + 0x00000000, 0x00000214, 0x0000019c, 0x00000000, 0x00000228, 0x000001e0, + 0xc0013d88, 0x000001e4, 0x000001e4, 0x00000000, 0x000001f4, 0x000001f4, + 0x00000000, 0x00000148, 0x000001fc, 0x00000000, 0x00000198, 0x00000200, + 0x00000000, 0x0000019c, 0x00000214, 0x00000000, 0x0000021c, 0x0000021c, + 0x00000000, 0x000001e0, 0x00000228, 0x00000000, 0x0000022c, 0x0000022c, + 0x00000000, 0x00000264, 0x00000230, 0xc0013dac, 0x00000260, 0x00000234, + 0xc0013dac, 0x0000025c, 0x00000238, 0xc0013dac, 0x00000258, 0x0000023c, + 0xc0013dac, 0x00000254, 0x00000240, 0xc0013dac, 0x00000250, 0x00000244, + 0xc0013dac, 0x0000024c, 0x00000248, 0xc0013dac, 0x00000248, 0x0000024c, + 0xc0013dac, 0x00000244, 0x00000250, 0xc0013dac, 0x00000240, 0x00000254, + 0xc0013dac, 0x0000023c, 0x00000258, 0xc0013dac, 0x00000238, 0x0000025c, + 0xc0013dac, 0x00000234, 0x00000260, 0xc0013dac, 0x00000230, 0x00000264, + 0xc0013dac, 0x00000270, 0x00000270, 0x00000000, 0x00000008, 0x0000000c, + 0x00000000, 0x00000018, 0x00000008, 0x00000000, 0x0000001c, 0x00000014, + 0x00000000, 0x00000034, 0x00000018, 0x00000000, 0x00000038, 0x0000001c, + 0x00000000, 0x0000003c, 0x00000020, 0x00000000, 0x00000040, 0x00000024, + 0x00000000, 0x00000044, 0x00000028, 0x00000000, 0x00000048, 0x0000002c, + 0x00000000, 0x0000004c, 0x00000030, 0x00000000, 0x00000020, 0x00000034, + 0x00000000, 0x00000054, 0x00000038, 0x00000000, 0x00000058, 0x0000003c, + 0x00000000, 0x0000005c, 0x00000040, 0x00000000, 0x00000068, 0x00000044, + 0x00000000, 0x00000060, 0x00000048, 0x00000000, 0x00000064, 0x0000004c, + 0x00000000, 0x0000006c, 0x00000060, 0x00000000, 0x00000070, 0x00000064, + 0x00000000, 0x00000074, 0x00000068, 0x00000000, 0x0000007c, 0x0000006c, + 0x00000000, 0x00000078, 0x00000070, 0x00000000, 0x0000000c, 0x00000140, + 0x00000000, 0x00000014, 0x00000144, 0x00000000, 0x00000080, 0x00000148, + 0x00000000, 0x00000084, 0x0000014c, 0x00000000, 0x00000088, 0x00000150, + 0x00000000, 0x0000008c, 0x00000154, 0x00000000, 0x00000024, 0x00000164, + 0x00000000, 0x00000028, 0x00000168, 0x00000000, 0x00000030, 0x0000016c, + 0x00000000, 0x0000a004, 0x00000000, 0xc0013f64, 0x0000a000, 0x00000004, + 0x00000000, 0x0000a00c, 0x00000008, 0xc0013f84, 0x0000a008, 0x0000000c, + 0xc0013f64, 0x0000b004, 0x00001000, 0xc0013f64, 0x0000b000, 0x00001004, + 0x00000000, 0x0000b00c, 0x00001008, 0xc0013f84, 0x0000b008, 0x0000100c, + 0xc0013f64, 0x0000c004, 0x00002000, 0xc0013f64, 0x0000c000, 0x00002004, + 0x00000000, 0x0000c00c, 0x00002008, 0xc0013f84, 0x0000c008, 0x0000200c, + 0xc0013f64, 0x0000d004, 0x00003000, 0xc0013f64, 0x0000d000, 0x00003004, + 0x00000000, 0x0000d00c, 0x00003008, 0xc0013f84, 0x0000d008, 0x0000300c, + 0xc0013f64, 0x0000e000, 0x0000e000, 0x00000000, 0x0000e00c, 0x0000e004, + 0x00000000, 0x0000e010, 0x0000e008, 0x00000000, 0x0000e014, 0x0000e00c, + 0x00000000, 0x0000e004, 0x0000e010, 0x00000000, 0x0000e008, 0x0000e014, + 0x00000000, 0x0000e018, 0x0000e018, 0x00000000, 0x0000e01c, 0x0000e01c, + 0x00000000, 0x0000e058, 0x0000e020, 0x00000000, 0x0000e040, 0x0000e040, + 0x00000000, 0x0000e044, 0x0000e044, 0x00000000, 0x0000e048, 0x0000e048, + 0x00000000, 0x0000e04c, 0x0000e04c, 0x00000000, 0x0000e050, 0x0000e050, + 0x00000000, 0x0000e054, 0x0000e054, 0x00000000, 0x0000f008, 0x0000f000, + 0x00000000, 0x0000f000, 0x0000f004, 0x00000000, 0x0000f004, 0x0000f008, + 0x00000000, 0x0000f00c, 0x0000f00c, 0x00000000, 0x0000f010, 0x0000f010, + 0x00000000, 0x0000f014, 0x0000f014, 0x00000000, 0x0000f020, 0x0000f018, + 0x00000000, 0x0000f01c, 0x0000f01c, 0x00000000, 0x0000f018, 0x0000f020, + 0x00000000, 0x0000f048, 0x0000f048, 0x00000000, 0x0000f04c, 0x0000f04c, + 0x00000000, 0x0000f040, 0x0000f050, 0x00000000, 0x0000f044, 0x0000f054, + 0x00000000, 0x00000000, 0x00000000, 0x0000000c, 0xc0014098, 0x00000004, + 0x00000010, 0x00000000, 0x00000008, 0x00000014, 0x00000000, 0x0000000c, + 0x00000000, 0x00000000, 0x00000010, 0x00000004, 0x00000000, 0x00000014, + 0x00000008, 0x00000000, 0x00000018, 0x00000018, 0x00000000, 0x0000000c, + 0x00000000, 0x00000000, 0x00000010, 0x00000004, 0x00000000, 0x00000008, + 0x00000008, 0x00000000, 0x00000014, 0x0000000c, 0x00000000, 0x00000060, + 0x00000010, 0x00000000, 0x00000018, 0x00000014, 0x00000000, 0x0000003c, + 0x00000018, 0x00000000, 0x00000048, 0x0000001c, 0x00000000, 0x00000040, + 0x00000020, 0x00000000, 0x0000004c, 0x00000024, 0x00000000, 0x00000004, + 0x00000028, 0x00000000, 0x0000001c, 0x0000002c, 0x00000000, 0x00000030, + 0x00000030, 0x00000000, 0x0000002c, 0x00000034, 0x00000000, 0x00000044, + 0x00000038, 0x00000000, 0x00000050, 0x0000003c, 0x00000000, 0x00000054, + 0x00000040, 0x00000000, 0x00000024, 0x00000044, 0x00000000, 0x00000020, + 0x00000048, 0x00000000, 0x00000028, 0x0000004c, 0x00000000, 0x00000034, + 0x00000050, 0x00000000, 0x00000058, 0x00000054, 0x00000000, 0x00000000, + 0x00000058, 0x00000000, 0x0000005c, 0x0000005c, 0x00000000, 0x00000038, + 0x00000060, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 0x00000000, + 0x00000004, 0x00000000, 0x0000000c, 0x00000008, 0x00000000, 0x00000008, + 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, + 0x00000008, 0x00000000, 0x00000008, 0x0000000c, 0x00000000, 0x0000000c, + 0x00000030, 0xc00142f0, 0x00000010, 0x000000ff, 0x00000000, 0x00000014, + 0x00000010, 0x00000000, 0x00000018, 0x00000018, 0x00000000, 0x0000001c, + 0x0000001c, 0x00000000, 0x00000020, 0x00000020, 0x00000000, 0x00000024, + 0x00000028, 0x00000000, 0x00000028, 0x0000002c, 0x00000000, 0x0000002c, + 0x000000ff, 0x00000000, 0x00000030, 0x00000004, 0x00000000, 0x00000034, + 0x00000014, 0x00000000, 0x00000038, 0x00000024, 0x00000000, 0x00000000, + 0x00000024, 0xc0014404, 0x00000004, 0x0000002c, 0xc0014404, 0x00000008, + 0x00000028, 0xc0014404, 0x0000000c, 0x0000000c, 0xc0014404, 0x00000010, + 0x00000010, 0xc0014404, 0x00000014, 0x00000014, 0xc0014404, 0x00000018, + 0x00000008, 0xc0014404, 0x0000001c, 0x00000018, 0xc0014404, 0x00000020, + 0x0000001c, 0xc0014404, 0x00000024, 0x00000020, 0x00000000, 0x00000028, + 0x00000030, 0x00000000, 0x0000002c, 0x00000034, 0x00000000, 0x00000030, + 0x00000000, 0xc0014404, 0x00000034, 0x00000004, 0xc0014404, 0x00000038, + 0x00000038, 0xc0014404, 0x00000000, 0x00000024, 0xc0014424, 0x00000004, + 0x0000002c, 0xc0014424, 0x00000008, 0x00000028, 0xc0014424, 0x0000000c, + 0x0000000c, 0xc0014424, 0x00000010, 0x00000010, 0xc0014424, 0x00000014, + 0x00000014, 0xc0014424, 0x00000018, 0x00000008, 0xc0014424, 0x0000001c, + 0x00000018, 0xc0014424, 0x00000020, 0x0000001c, 0xc0014424, 0x00000024, + 0x00000020, 0x00000000, 0x00000028, 0x00000030, 0x00000000, 0x0000002c, + 0x00000034, 0x00000000, 0x00000030, 0x00000000, 0xc0014424, 0x00000034, + 0x00000004, 0xc0014424, 0x00000038, 0x00000038, 0xc0014424, 0x00000000, + 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 0x00000008, + 0x00000008, 0x00000000, 0x0000000c, 0x00000010, 0xc0014568, 0x00000010, + 0x00000018, 0xc00145f0, 0x00000014, 0x00000014, 0xc00146a0, 0x00000018, + 0x0000000c, 0xc001473c, 0x00000000, 0x00000020, 0x00000000, 0x00000004, + 0x00000010, 0x00000000, 0x00000008, 0x00000004, 0x00000000, 0x0000000c, + 0x00000000, 0x00000000, 0x00000010, 0x0000000c, 0x00000000, 0x00000014, + 0x00000008, 0x00000000, 0x00000018, 0x00000014, 0x00000000, 0x0000001c, + 0x0000001c, 0x00000000, 0x00000020, 0x00000018, 0x00000000, 0x00000024, + 0x00000098, 0xc0014860, 0x00000028, 0x00000094, 0x00000000, 0x0000002c, + 0x0000007c, 0x00000000, 0x00000030, 0x00000068, 0x00000000, 0x00000034, + 0x00000064, 0x00000000, 0x00000038, 0x00000060, 0x00000000, 0x0000003c, + 0x0000005c, 0x00000000, 0x00000040, 0x00000058, 0x00000000, 0x00000044, + 0x00000054, 0x00000000, 0x00000048, 0x00000050, 0x00000000, 0x0000004c, + 0x0000004c, 0x00000000, 0x00000050, 0x00000048, 0x00000000, 0x00000054, + 0x00000044, 0x00000000, 0x00000058, 0x00000040, 0x00000000, 0x0000005c, + 0x0000003c, 0x00000000, 0x00000060, 0x00000038, 0x00000000, 0x00000064, + 0x00000034, 0x00000000, 0x00000068, 0x00000030, 0x00000000, 0x0000006c, + 0x0000002c, 0x00000000, 0x00000070, 0x00000028, 0x00000000, 0x00000074, + 0x00000024, 0x00000000, 0x00000078, 0x00000078, 0x00000000, 0x0000007c, + 0x00000074, 0x00000000, 0x00000080, 0x00000070, 0x00000000, 0x00000084, + 0x0000006c, 0x00000000, 0x00000088, 0x00000080, 0x00000000, 0x0000008c, + 0x00000090, 0x00000000, 0x00000090, 0x0000008c, 0x00000000, 0x00000094, + 0x00000088, 0x00000000, 0x00000098, 0x00000084, 0x00000000, 0x00000000, + 0x00000000, 0xc001492c, +}; diff --git a/arch/arm/mach-gk710x/include/mach/gk710x.h b/arch/arm/mach-gk710x/include/mach/gk710x.h new file mode 100644 index 000000000000..2b89f1180d8d --- /dev/null +++ b/arch/arm/mach-gk710x/include/mach/gk710x.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Goke GK7101 / GK7102: the silicon register map. + * + * The vendor U-Boot and kernel never touch these addresses. They go through + * a HAL blob (hal_data.h) that takes a fictitious map (AHB 0x90000000, APB + * 0xA0000000), moves each block to its real place, shuffles registers inside + * some blocks and permutes the bits of some registers. The addresses and + * values here are what the HAL itself writes, recovered by executing it + * (qemu-hisilicon's qemu-boot/gk710x-halmap.py). Underneath, the UART is a + * 16550, the MAC a Synopsys DWMAC and the timers and watchdog Ambarella's. + */ + +#ifndef __MACH_GK710X_H +#define __MACH_GK710X_H + +#define GK_DDR_BASE 0xC0000000 +#define GK_DDR_MAX 0x08000000 /* GK7101 */ + +/* AHB */ +#define GK_DDRC_BASE 0x60004000 +#define GK_DDRC_CFG (GK_DDRC_BASE + 0x04) /* from the boot header */ +#define GK_DDRC_CFG_128M 0x00100354 +#define GK_GMAC_BASE 0x6000E000 +#define GK_SFLASH_BASE 0x60016000 +#define GK_AHB_GENERAL0 0x60020E00 /* bit 1: external PHY */ +#define GK_EPHY_BASE 0x60022000 /* MII register n at +4n */ + +/* APB */ +#define GK_UART0_BASE 0x70005000 +#define GK_GPIO_BASE 0x70009000 +#define GK_TIMER_BASE 0x7000B000 +#define GK_WDT_BASE 0x7000C000 +#define GK_RCT_BASE 0x70170000 + +#define GK_UART_CLK 24000000 + +/* Timer 1 counts down at the APB clock; control is a nibble per timer */ +#define GK_APB_CLK 69000000 +#define GK_TIMER1_STATUS (GK_TIMER_BASE + 0x00) +#define GK_TIMER1_RELOAD (GK_TIMER_BASE + 0x04) +#define GK_TIMER_CTRL (GK_TIMER_BASE + 0x30) +#define GK_TIMER_CTRL_EN 0x1 + +#define GK_WDT_RELOAD (GK_WDT_BASE + 0x04) +#define GK_WDT_RESTART (GK_WDT_BASE + 0x08) +#define GK_WDT_CTRL (GK_WDT_BASE + 0x0C) +#define GK_WDT_MAGIC 0x4755 +#define GK_WDT_CTRL_EN 0x1 +#define GK_WDT_CTRL_RESET 0x2 + +/* GPIO: a function word per pin and a pin number per input function */ +#define GK_GPIO_IN_EN (GK_GPIO_BASE + 0x038) +#define GK_GPIO_PER_SEL (GK_GPIO_BASE + 0x03C) /* bit 0: external PHY */ +#define GK_GPIO_OUTPUT_CFG(n) (GK_GPIO_BASE + 0x100 + 4 * (n)) +#define GK_GPIO_INPUT_CFG(n) (GK_GPIO_BASE + 0x200 + 4 * (n)) + +/* RCT: clocks and pad control */ +#define GK_RCT_PLL_AUDIO_CTRL (GK_RCT_BASE + 0x054) +#define GK_RCT_PLL_AUDIO_FRAC (GK_RCT_BASE + 0x058) +#define GK_RCT_DIV_AUDIO_PST (GK_RCT_BASE + 0x05C) +#define GK_RCT_DIV_AUDIO_PRE (GK_RCT_BASE + 0x060) +#define GK_RCT_SCALER_UART (GK_RCT_BASE + 0x038) +#define GK_RCT_PLL_CORE (GK_RCT_BASE + 0x0E4) +#define GK_RCT_IOCTRL_MISC2 (GK_RCT_BASE + 0x200) +/* Pad drive and pull: one byte per pin, four pins per word */ +#define GK_RCT_IOCTRL_GPIO(n) (GK_RCT_BASE + 0x230 + 4 * ((n) / 4)) + +/* + * What the vendor U-Boot leaves for the kernel (include/configs/gk7101.h): + * the HAL, its address, and a few words of board parameters ("U2K") at the + * bottom of DDR; the board's GPIO map in its top 64 KiB. + */ +#define GK_HAL_ADDR (GK_DDR_BASE + 0x12000) +#define GK_U2K_PHY_TYPE (GK_DDR_BASE + 0x00) +#define GK_U2K_ARM_FREQ (GK_DDR_BASE + 0x04) +#define GK_U2K_HAL_ADDR (GK_DDR_BASE + 0x08) +#define GK_U2K_SOC (GK_DDR_BASE + 0x10) +#define GK_U2K_MEM (GK_DDR_BASE + 0x14) +#define GK_U2K_BSB (GK_DDR_BASE + 0x18) +#define GK_U2K_ENABLE (GK_DDR_BASE + 0x20) +#define GK_U2K_USR (GK_DDR_BASE + 0x24) +#define GK_U2K_TOTAL_MEM (GK_DDR_BASE + 0x28) +#define GK_U2K_MAGIC 0x7101 +#define GK_USR_SIZE 0x10000 + +/* The CPU PLL setting the vendor U-Boot programs, as the HAL takes it */ +#define GK_ARM_FREQ 0x00112032 + +#ifndef __ASSEMBLY__ +void gk_gpio_config(unsigned int pin, unsigned int type); +void gk_gpio_init(void); +/* board/goke/gk710x/gpio_map.c */ +void gk_gpio_map_apply(void); +void gk_gpio_map_save(void *dst); +#endif + +#endif diff --git a/arch/arm/mach-gk710x/kernel.c b/arch/arm/mach-gk710x/kernel.c new file mode 100644 index 000000000000..0172e17c4034 --- /dev/null +++ b/arch/arm/mach-gk710x/kernel.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * What the GK710x kernel needs from its boot loader besides ATAGs, as the + * vendor U-Boot leaves it (common/cmd_bootm.c, CONFIG_UBOOT_TO_KERNEL): + * - the HAL blob at GK_HAL_ADDR and that address in a U2K word; + * - the other U2K words: total DDR, the BSB (bitstream buffer) carved out + * above the kernel's mem=, the PHY type; + * - the board's GPIO map in the top 64 KiB of DDR, which the kernel + * applies itself (board/goke/gk710x). + * The kernel places its DSP memory from mem=, bsbsize and the total. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hal_data.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* "36M" -> 36: the environment spells these sizes in MiB */ +static ulong env_mib(const char *name, const char *def) +{ + const char *s = env_get(name); + + return simple_strtoul(s ? s : def, NULL, 10); +} + +void board_prep_linux(bootm_headers_t *images) +{ + const ulong top = GK_DDR_BASE + gd->ram_size; + + memcpy((void *)GK_HAL_ADDR, gk_hal_data, sizeof(gk_hal_data)); + + writel(env_get_ulong("phytype", 10, 0), GK_U2K_PHY_TYPE); + writel(GK_ARM_FREQ, GK_U2K_ARM_FREQ); + writel(GK_HAL_ADDR, GK_U2K_HAL_ADDR); + writel(0, GK_U2K_SOC); + writel(env_mib("osmem", OPENIPC_OSMEM) * SZ_1M, GK_U2K_MEM); + writel(env_mib("bsbsize", __stringify(GK_BSB_MIB)) * SZ_1M, GK_U2K_BSB); + writel(GK_U2K_MAGIC, GK_U2K_ENABLE); + writel(0, GK_U2K_USR); + writel(gd->ram_size / SZ_1M, GK_U2K_TOTAL_MEM); + + gk_gpio_map_save((void *)(top - GK_USR_SIZE)); +} diff --git a/arch/arm/mach-gk710x/lowlevel_init.S b/arch/arm/mach-gk710x/lowlevel_init.S new file mode 100644 index 000000000000..e732209b526f --- /dev/null +++ b/arch/arm/mach-gk710x/lowlevel_init.S @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The boot ROM has already run the PLL and DDR set-up from the flash + * header and copied U-Boot into DDR: nothing is left to do here. + */ + +#include + +ENTRY(lowlevel_init) + mov pc, lr +ENDPROC(lowlevel_init) diff --git a/arch/arm/mach-gk710x/soc.c b/arch/arm/mach-gk710x/soc.c new file mode 100644 index 000000000000..985eb2c2a6aa --- /dev/null +++ b/arch/arm/mach-gk710x/soc.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Goke GK7101 / GK7102: clocks, timer, reset and DRAM size. + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int arch_cpu_init(void) +{ + /* + * The CPU PLL and the UART divider as the vendor U-Boot sets them + * (arm_freq 0x00112032 and REG_PLL_SCALER_UART 1), in silicon bit + * order: the HAL permutes the PLL word on its way to the register. + */ + writel(0x01203201, GK_RCT_PLL_CORE); + writel(1, GK_RCT_SCALER_UART); + return 0; +} + +int timer_init(void) +{ + u32 ctrl = readl(GK_TIMER_CTRL) & ~0xf; + + /* Timer 1, free running over the whole 32 bits for lib/time.c */ + writel(ctrl, GK_TIMER_CTRL); + writel(0xffffffff, GK_TIMER1_STATUS); + writel(0xffffffff, GK_TIMER1_RELOAD); + writel(ctrl | GK_TIMER_CTRL_EN, GK_TIMER_CTRL); + gd->arch.tbl = 0; + gd->arch.tbu = 0; + return 0; +} + +void reset_cpu(void) +{ + writel(0xff, GK_WDT_RELOAD); + writel(GK_WDT_MAGIC, GK_WDT_RESTART); + writel(GK_WDT_CTRL_EN | GK_WDT_CTRL_RESET, GK_WDT_CTRL); + while (1) + ; +} + +/* The boot header's DDR controller set-up tells the 128 MiB GK7101 apart */ +int dram_init(void) +{ + ulong max = readl(GK_DDRC_CFG) == GK_DDRC_CFG_128M ? SZ_128M : SZ_64M; + + gd->ram_size = get_ram_size((long *)GK_DDR_BASE, max); + return 0; +} + +/* The top 64 KiB carry the GPIO map to the kernel: keep U-Boot below it */ +ulong board_get_usable_ram_top(ulong total_size) +{ + return gd->ram_top - GK_USR_SIZE; +} + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + printf("CPU: Goke %s\n", CONFIG_PRODUCT_SOC); + return 0; +} +#endif diff --git a/board/goke/gk710x/Makefile b/board/goke/gk710x/Makefile new file mode 100644 index 000000000000..195d83388844 --- /dev/null +++ b/board/goke/gk710x/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += gk710x.o gpio_map.o diff --git a/board/goke/gk710x/gk710x.c b/board/goke/gk710x/gk710x.c new file mode 100644 index 000000000000..ca70ab49112d --- /dev/null +++ b/board/goke/gk710x/gk710x.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Goke GK7101 / GK7102 camera board, after the vendor U-Boot 2012.10 + * (board/goke/gk7101/gk7101.c, drivers/net/goke_eth.c) with its HAL calls + * replaced by the silicon accesses they make. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + gd->bd->bi_boot_params = GK_DDR_BASE + 0x100; + return 0; +} + +int misc_init_r(void) +{ + gk_gpio_map_apply(); + return openipc_helper(); +} + +#ifdef CONFIG_ETH_DESIGNWARE +/* + * The internal 10/100 PHY is not on the GMAC's MDIO bus: its MII registers + * are memory mapped, register n in the low half of the word at +4n (the + * vendor kernel's gkhw_mdio_read() with phytype=0). It answers at address 0. + */ +static int gk_ephy_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + return addr ? 0xffff : readl(GK_EPHY_BASE + 4 * reg) & 0xffff; +} + +static int gk_ephy_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + if (!addr) + writel(val, GK_EPHY_BASE + 4 * reg); + return 0; +} + +/* The analog trim gk7101_ethphy_init() writes, byte by byte */ +static const struct { + u16 off; + u8 val; +} gk_ephy_trim[] = { + { 0x3bc, 0x59 }, { 0x3e8, 0x21 }, { 0x0e4, 0x80 }, { 0x3f8, 0x00 }, + { 0x3f9, 0x00 }, { 0x36d, 0x07 }, { 0x395, 0x11 }, { 0x398, 0x80 }, + { 0x399, 0xd1 }, { 0x3a8, 0x00 }, { 0x371, 0x40 }, { 0x375, 0x05 }, + { 0x3d4, 0x46 }, { 0x341, 0x00 }, { 0x474, 0x03 }, { 0x475, 0x00 }, + { 0x368, 0x56 }, /* gain shift */ + { 0x29d, 0x02 }, /* det max */ + { 0x2a1, 0x01 }, /* det min */ + { 0x2ed, 0x18 }, /* snr len (EMC noise) */ + { 0x285, 0x15 }, /* snr k */ + { 0x589, 0x00 }, /* 100 gat */ + { 0x460, 0x43 }, /* 200 gat */ + { 0x471, 0x41 }, /* en_100t_phase */ + { 0x055, 0x00 }, + { 0x3b0, 0xb0 }, { 0x3b1, 0x30 }, /* analog */ +}; + +static void gk_ephy_init(void) +{ + int i; + + /* Its reference clock: the audio PLL at 96 MHz / 4, out on a pin */ + writel(0x02402001, GK_RCT_PLL_AUDIO_CTRL); + writel(0, GK_RCT_PLL_AUDIO_FRAC); + writel(4, GK_RCT_DIV_AUDIO_PST); + writel(1, GK_RCT_DIV_AUDIO_PRE); + writel(readl(GK_GPIO_PER_SEL) & ~1, GK_GPIO_PER_SEL); + + writel(0, GK_EPHY_BASE + 0x540); /* MDIO error count */ + writel(0xc400, GK_EPHY_BASE + 0xc8); /* mux: test out */ + writel(0x810a, GK_EPHY_BASE + 0xe0); /* signal select */ + writel(7, GK_EPHY_BASE + 0x588); /* DAC 100M clock gate for 10M */ + for (i = 0; i < ARRAY_SIZE(gk_ephy_trim); i++) + writeb(gk_ephy_trim[i].val, GK_EPHY_BASE + gk_ephy_trim[i].off); + /* 10BASE-T waveform */ + writeb((readb(GK_EPHY_BASE + 0x5d0) & 0xf8) | 0x06, GK_EPHY_BASE + 0x5d0); + /* EEE off */ + writeb(readb(GK_EPHY_BASE + 0x059) | 0x40, GK_EPHY_BASE + 0x059); + writel(readl(GK_EPHY_BASE + 0x58) | BIT(12), GK_EPHY_BASE + 0x58); + + /* The MAC talks to the internal PHY, not the MII pins */ + writel(readl(GK_AHB_GENERAL0) & ~BIT(1), GK_AHB_GENERAL0); +} + +int board_eth_init(struct bd_info *bis) +{ + struct mii_dev *bus = mdio_alloc(); + int ret; + + if (!bus) + return -ENOMEM; + gk_ephy_init(); + + /* designware_initialize() takes a bus already named after its device */ + snprintf(bus->name, sizeof(bus->name), "dwmac.%x", GK_GMAC_BASE); + bus->read = gk_ephy_read; + bus->write = gk_ephy_write; + ret = mdio_register(bus); + if (ret) { + free(bus); + return ret; + } + + return designware_initialize(GK_GMAC_BASE, PHY_INTERFACE_MODE_MII); +} +#endif diff --git a/board/goke/gk710x/gpio_map.c b/board/goke/gk710x/gpio_map.c new file mode 100644 index 000000000000..54befe157374 --- /dev/null +++ b/board/goke/gk710x/gpio_map.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO maps of the Goke GK7101/GK7102 reference boards, which camera makers + * copied, and the copy the kernel takes over. + * + * The vendor U-Boot builds one image per board (arch-gk7101/gpio_rb_*.h) + * and leaves that board's map in the top 64 KiB of DDR; the vendor kernel, + * OpenIPC's included, reads it from there ("gpio map get from uboot") and + * configures every pin from it -- sensor I2C and reset, IR cut, SD, the + * Ethernet PHY pins. Without a map the camera boots with no sensor bus. + * + * The SDK's 20-odd board headers come down to two layouts: + * - v2 (the default): GK7102 rb-sc1035 v2.1, rb-sc1045, rb-imx225, + * rb-ov9750, rb-jxh42 v2.0, ak-gc1024, GK7101 rb-ov2710 v2.2. + * UART0 on GPIO 25/26, SD on 39-47. + * - v1: GK7102 rb-ov9712, rb-ar0130, rb-jxh42 v1.0, GK7101 rb-imx222. + * UART0 on GPIO 30/31, the external-PHY pins on 41-47. + * gpiomap=v1 in the environment selects the second. + * + * Pin types are the vendor's GPIO_TYPE_* words (mach-gk710x/gpio.c), named + * in the comments; the tables were generated from the SDK headers. + */ + +#include +#include +#include + +struct gk_gpio_pin { + u32 pin; + u32 type; +}; + +static const struct gk_gpio_pin v2_xref[] = { + { 0, 0xa0000024 }, /* output_sf_cs0 */ + { 1, 0xa0000025 }, /* output_sf_cs1 */ + { 2, 0x40010000 }, /* input */ + { 4, 0x40010000 }, /* input */ + { 5, 0x40010000 }, /* input */ + { 6, 0x40010000 }, /* input */ + { 7, 0x40010000 }, /* input */ + { 8, 0x40010000 }, /* input */ + { 9, 0x40010000 }, /* input */ + { 10, 0x40010000 }, /* input */ + { 11, 0x40010000 }, /* input */ + { 12, 0xa0000000 }, /* output_0 (IR_LED_CTRL) */ + { 13, 0x40010000 }, /* input */ + { 14, 0x40010000 }, /* input */ + { 15, 0x40010000 }, /* input (IR_DET_ADC) */ + { 16, 0x40010000 }, /* input */ + { 17, 0x40010000 }, /* input */ + { 18, 0x40010000 }, /* input */ + { 19, 0x40010000 }, /* input */ + { 20, 0xa0000000 }, /* output_0 (IR_CUT+) */ + { 21, 0x40010000 }, /* input */ + { 22, 0x40010000 }, /* input */ + { 23, 0xa0000000 }, /* output_0 (IR_CUT-) */ + { 24, 0x40010000 }, /* input */ + { 25, 0x50010900 }, /* input_uart0_rx */ + { 26, 0x90000009 }, /* output_uart0_tx */ + { 27, 0xa0000001 }, /* output_1 (Sensor reset) */ + { 28, 0xd0030300 }, /* inout_i2c_data (S D) */ + { 29, 0xd0040400 }, /* inout_i2c_clk (S C) */ + { 34, 0x40010000 }, /* input */ + { 37, 0x40010000 }, /* input */ + { 38, 0x40010000 }, /* input */ + { 39, 0x50010f00 }, /* input_sd_cd_n */ + { 40, 0x40010000 }, /* input */ + { 41, 0xd08b1319 }, /* inout_sd_data_3 */ + { 42, 0xd08a1218 }, /* inout_sd_data_2 */ + { 43, 0xd090181e }, /* inout_sd_cmd */ + { 44, 0x9000001f }, /* output_sdio_clk */ + { 45, 0xd0891117 }, /* inout_sd_data_1 */ + { 46, 0xa0000001 }, /* output_1 (SDIO_CARD_POWER_EN) */ + { 47, 0xd0881016 }, /* inout_sd_data_0 */ + { 55, 0x40010000 }, /* input */ +}; + +static const struct gk_gpio_pin v2_intphy[] = { + { 3, 0x40010000 }, /* input */ + { 30, 0x40010000 }, /* input */ + { 31, 0x40010000 }, /* input */ + { 32, 0x40010000 }, /* input */ + { 33, 0x40010000 }, /* input */ + { 35, 0x40010000 }, /* input */ + { 36, 0x40010000 }, /* input */ + { 48, 0xa0000020 }, /* output_aomclk */ + { 49, 0x40010000 }, /* input */ + { 50, 0x40010000 }, /* input */ + { 51, 0x40010000 }, /* input */ + { 52, 0x40010000 }, /* input */ + { 53, 0x40010000 }, /* input */ + { 54, 0xa0000029 }, /* output_ephy_led_3 */ +}; + +static const struct gk_gpio_pin v2_extphy[] = { + { 3, 0x60012400 }, /* input_enet_phy_rxdv */ + { 30, 0xa0000030 }, /* output_enet_phy_txen */ + { 31, 0xa000002c }, /* output_enet_phy_txd_1 */ + { 32, 0xa000002b }, /* output_enet_phy_txd_0 */ + { 33, 0x60012300 }, /* input_enet_phy_rxer */ + { 35, 0xa0000032 }, /* output_enet_gmii_mdc_o */ + { 36, 0xe0932531 }, /* inout_eth_mdio */ + { 48, 0x40010000 }, /* input */ + { 49, 0xa0000001 }, /* output_1 (ETH reset) */ + { 50, 0xa0000020 }, /* output_aomclk */ + { 51, 0x60011e00 }, /* input_enet_phy_rxd_1 */ + { 52, 0x60011f00 }, /* input_enet_phy_rxd_2 (CLK) */ + { 53, 0x60011d00 }, /* input_enet_phy_rxd_0 */ + { 54, 0x40010000 }, /* input */ +}; + +static const struct gk_gpio_pin v1_xref[] = { + { 0, 0xa0000024 }, /* output_sf_cs0 */ + { 1, 0xa0000025 }, /* output_sf_cs1 */ + { 4, 0x40010000 }, /* input */ + { 5, 0x40010000 }, /* input */ + { 6, 0x40010000 }, /* input */ + { 7, 0x40010000 }, /* input */ + { 8, 0x40010000 }, /* input */ + { 9, 0x40010000 }, /* input */ + { 10, 0x40010000 }, /* input */ + { 11, 0x40010000 }, /* input */ + { 12, 0xa0000000 }, /* output_0 (IR_LED_CTRL) */ + { 13, 0x40010000 }, /* input */ + { 14, 0x40010000 }, /* input */ + { 15, 0x40010000 }, /* input (IR_DET_ADC) */ + { 16, 0x40010000 }, /* input */ + { 17, 0x40010000 }, /* input */ + { 18, 0x40010000 }, /* input */ + { 19, 0x40010000 }, /* input */ + { 20, 0xa0000000 }, /* output_0 (IR_CUT+) */ + { 21, 0x40010000 }, /* input */ + { 22, 0x40010000 }, /* input */ + { 23, 0xa0000000 }, /* output_0 (IR_CUT-) */ + { 24, 0x40010000 }, /* input */ + { 25, 0x40010000 }, /* input */ + { 26, 0x40010000 }, /* input */ + { 27, 0xa0000001 }, /* output_1 (Sensor reset) */ + { 28, 0xd0030300 }, /* inout_i2c_data (S D) */ + { 29, 0xd0040400 }, /* inout_i2c_clk (S C) */ + { 30, 0x90000009 }, /* output_uart0_tx */ + { 31, 0x50010900 }, /* input_uart0_rx */ + { 34, 0x40010000 }, /* input */ + { 35, 0xd0050500 }, /* inout_i2c_data2 */ + { 36, 0xd0060600 }, /* inout_i2c_clk2 */ + { 37, 0x40010000 }, /* input */ + { 38, 0x40010000 }, /* input */ + { 39, 0x40010000 }, /* input */ + { 40, 0x40010000 }, /* input */ + { 42, 0x40010000 }, /* input */ + { 45, 0x40010000 }, /* input */ + { 53, 0x40010000 }, /* input (ALARM_OUT) */ + { 54, 0x40010000 }, /* input (ALARM_IN) */ + { 55, 0x40010000 }, /* input */ +}; + +static const struct gk_gpio_pin v1_intphy[] = { + { 2, 0x40010000 }, /* input */ + { 3, 0x40010000 }, /* input */ + { 32, 0x40010000 }, /* input */ + { 33, 0x40010000 }, /* input */ + { 41, 0x40010000 }, /* input */ + { 43, 0x40010000 }, /* input */ + { 44, 0x40010000 }, /* input */ + { 46, 0x40010000 }, /* input */ + { 47, 0x40010000 }, /* input */ + { 48, 0xa0000020 }, /* output_aomclk */ + { 49, 0xa0000029 }, /* output_ephy_led_3 */ + { 50, 0x40010000 }, /* input */ + { 51, 0x40010000 }, /* input */ + { 52, 0x40010000 }, /* input */ +}; + +static const struct gk_gpio_pin v1_extphy[] = { + { 2, 0x60012300 }, /* input_enet_phy_rxer */ + { 3, 0xa0000032 }, /* output_enet_gmii_mdc_o */ + { 32, 0x60011e00 }, /* input_enet_phy_rxd_1 */ + { 33, 0xe0932531 }, /* inout_eth_mdio */ + { 41, 0xa0000001 }, /* output_1 (ETH reset) */ + { 43, 0xa0000020 }, /* output_aomclk */ + { 44, 0xa0000030 }, /* output_enet_phy_txen */ + { 46, 0xa000002c }, /* output_enet_phy_txd_1 */ + { 47, 0xa000002b }, /* output_enet_phy_txd_0 */ + { 48, 0x40010000 }, /* input */ + { 49, 0x40010000 }, /* input */ + { 50, 0x60011f00 }, /* input_enet_phy_rxd_2 (CLK) */ + { 51, 0x60012400 }, /* input_enet_phy_rxdv */ + { 52, 0x60011d00 }, /* input_enet_phy_rxd_0 */ +}; + +struct gk_gpio_map { + const char *name; + const struct gk_gpio_pin *pins, *intphy, *extphy; + u32 npins, nintphy, nextphy; + /* the pins the kernel drives itself, in gpio_cfg_t order */ + u32 ir_led_ctl, ir_cut1, ir_cut2, sensor_reset, phy_reset, phy_speed_led; + u32 spi0_en0, spi1_en0, pwm[4], usb_host, sd_detect, sd_power, pmu_ctl; +}; + +#define MAP(v) .pins = v##_xref, .npins = ARRAY_SIZE(v##_xref), \ + .intphy = v##_intphy, .nintphy = ARRAY_SIZE(v##_intphy), \ + .extphy = v##_extphy, .nextphy = ARRAY_SIZE(v##_extphy) + +static const struct gk_gpio_map gk_maps[] = { + { + .name = "v2", MAP(v2), + .ir_led_ctl = 4, .ir_cut1 = 20, .ir_cut2 = 23, + .sensor_reset = 27, .phy_reset = 49, .phy_speed_led = 54, + .spi0_en0 = 5, .spi1_en0 = 6, .pwm = { 7, 8, 9, 10 }, + .usb_host = 11, .sd_detect = 39, .sd_power = 46, .pmu_ctl = 55, + }, { + .name = "v1", MAP(v1), + .ir_led_ctl = 12, .ir_cut1 = 20, .ir_cut2 = 23, + .sensor_reset = 27, .phy_reset = 41, .phy_speed_led = 49, + .spi0_en0 = 37, .spi1_en0 = 38, .pwm = { 39, 40, 42, 45 }, + .usb_host = 55, .sd_detect = 4, .sd_power = 5, .pmu_ctl = 55, + }, +}; + +/* The vendor's gpio_cfg_t (drivers/gpio/goke_gpio.c), as the kernel reads it */ +struct gk_gpio_cfg { + u32 gpio_count; + struct gk_gpio_pin gpio_chip[64]; + u32 extphy_gpio_count; + struct gk_gpio_pin ext_phy_gpio[16]; + u32 intphy_gpio_count; + struct gk_gpio_pin int_phy_gpio[16]; + u32 ir_led_ctl, ir_cut1, ir_cut2, sensor_reset, phy_reset, phy_speed_led; + u32 spi0_en0, spi1_en0, pwm[4], usb_host, sd_detect, sd_power; + u32 soc_type; + char board_type[32]; + u32 board_version; + u32 reserve1; + u32 ext_phy_clk; /* MHz; 0: the internal PHY */ + u32 reserve2; + u32 pmu_ctl; +}; + +static const struct gk_gpio_map *gk_map(void) +{ + const char *name = env_get("gpiomap"); + int i; + + for (i = 0; name && i < ARRAY_SIZE(gk_maps); i++) + if (!strcmp(name, gk_maps[i].name)) + return &gk_maps[i]; + return &gk_maps[0]; +} + +/* As the vendor U-Boot does at start: every pin, then the internal PHY's */ +void gk_gpio_map_apply(void) +{ + const struct gk_gpio_map *m = gk_map(); + int i; + + for (i = 0; i < m->npins; i++) + gk_gpio_config(m->pins[i].pin, m->pins[i].type); + for (i = 0; i < m->nintphy; i++) + gk_gpio_config(m->intphy[i].pin, m->intphy[i].type); + gk_gpio_init(); +} + +void gk_gpio_map_save(void *dst) +{ + const struct gk_gpio_map *m = gk_map(); + struct gk_gpio_cfg *c = dst; + + memset(c, 0, sizeof(*c)); + c->gpio_count = m->npins; + memcpy(c->gpio_chip, m->pins, m->npins * sizeof(*m->pins)); + c->extphy_gpio_count = m->nextphy; + memcpy(c->ext_phy_gpio, m->extphy, m->nextphy * sizeof(*m->extphy)); + c->intphy_gpio_count = m->nintphy; + memcpy(c->int_phy_gpio, m->intphy, m->nintphy * sizeof(*m->intphy)); + c->ir_led_ctl = m->ir_led_ctl; + c->ir_cut1 = m->ir_cut1; + c->ir_cut2 = m->ir_cut2; + c->sensor_reset = m->sensor_reset; + c->phy_reset = m->phy_reset; + c->phy_speed_led = m->phy_speed_led; + c->spi0_en0 = m->spi0_en0; + c->spi1_en0 = m->spi1_en0; + memcpy(c->pwm, m->pwm, sizeof(c->pwm)); + c->usb_host = m->usb_host; + c->sd_detect = m->sd_detect; + c->sd_power = m->sd_power; + c->pmu_ctl = m->pmu_ctl; + c->soc_type = IS_ENABLED(CONFIG_TARGET_GK7101) ? 0 : 1; + snprintf(c->board_type, sizeof(c->board_type), "openipc-%s", m->name); + c->board_version = 0; + c->ext_phy_clk = 0; +} diff --git a/include/configs/gk710x.h b/include/configs/gk710x.h new file mode 100644 index 000000000000..60b7a2188fe1 --- /dev/null +++ b/include/configs/gk710x.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Goke GK7101 / GK7102: memory map, console and timer. The environment and + * the rest of the OpenIPC configuration come from openipc-common.h. + */ + +#ifndef __GK710X_H +#define __GK710X_H + +#include + +#define CONFIG_SYS_SDRAM_BASE GK_DDR_BASE +#define PHYS_SDRAM_1_SIZE GK_DDR_MAX + +/* The boot ROM copies U-Boot to its link address and starts it there */ +#define CONFIG_SYS_UBOOT_BASE CONFIG_SYS_TEXT_BASE + +/* board_init_f() stack and global data, below U-Boot as the vendor's */ +#define CONFIG_SYS_INIT_RAM_ADDR (GK_DDR_BASE + 0x700000) +#define CONFIG_SYS_INIT_RAM_SIZE 0x100000 + +/* 16550 with 32-bit registers */ +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK GK_UART_CLK +#define CONFIG_SYS_NS16550_COM1 GK_UART0_BASE + +#define CONFIG_SYS_TIMER_RATE GK_APB_CLK +#define CONFIG_SYS_TIMER_COUNTER GK_TIMER1_STATUS +#define CONFIG_SYS_TIMER_COUNTS_DOWN + +/* Bitstream buffer above the kernel's mem=, as the vendor U-Boot sizes it */ +#ifdef CONFIG_TARGET_GK7101 +#define GK_BSB_MIB 4 +#else +#define GK_BSB_MIB 2 +#endif + +#include "openipc-common.h" + +#endif diff --git a/include/configs/openipc-common.h b/include/configs/openipc-common.h new file mode 100644 index 000000000000..5d2fa6ca203d --- /dev/null +++ b/include/configs/openipc-common.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Common OpenIPC configuration for the Goke GK7101/GK7102 targets. + * + * The single place for the default environment, kept in step with + * include/configs/openipc-common.h on the openipc-hisilicon branch: the + * update, recovery and boot-limit commands are the same, only the per-SoC + * parameters below differ. Per-SoC config headers include this last and must + * not define CONFIG_EXTRA_ENV_SETTINGS, CONFIG_BOOTARGS or + * CONFIG_BOOTCOMMAND themselves. + */ + +#ifndef __OPENIPC_COMMON_H +#define __OPENIPC_COMMON_H + +#include + +/* Default network configuration */ +#define CONFIG_IPADDR 192.168.1.10 +#define CONFIG_SERVERIP 192.168.1.107 +#define CONFIG_NETMASK 255.255.255.0 +#define CONFIG_GATEWAYIP 192.168.1.1 + +#define VENDOR "goke" + +/* + * Kernel memory (mem=), from 0xC0200000. Above it the kernel carves the + * bitstream buffer (bsbsize) and gives the rest to the DSP, so both are + * passed to it as well (mach-gk710x/kernel.c). The vendor U-Boot defaults. + */ +#if defined(CONFIG_TARGET_GK7101) +#define OPENIPC_OSMEM "50M" +#else +#define OPENIPC_OSMEM "36M" +#endif + +#define OPENIPC_BASEADDR 0xC1000000 + +/* NOR layout, shared with every OpenIPC NOR camera */ +#define OPENIPC_KERNADDR 0x50000 +#define OPENIPC_KERNSIZE 0x200000 +#define OPENIPC_ROOTADDR 0x250000 +#define OPENIPC_ROOTSIZE 0x500000 + +#define OPENIPC_FW_FILE "firmware.${soc}" + +#define OPENIPC_BOOTARGSNFS "mem=\\${osmem} console=ttySGK0,115200 panic=20 root=/dev/nfs rootfstype=nfs ip=${ipaddr}:::255.255.255.0::eth0 nfsroot=${serverip}:${nfsroot},v3,nolock rw \\${extras}" + +/* NOR partition list; the reserved 'mtdparts' variable holds the full + * ":" string, the bootargs compose it from mtdids/mtds. */ +#define OPENIPC_MTDPARTS "256k(boot),64k(env),2048k(kernel),5120k(rootfs),7168k@0x50000(firmware),-(rootfs_data)" + +/* + * Past bootlimit -- a boot loop: the image is intact, but userspace never + * comes up healthy, so nothing clears the DRAM counter -- boot the same + * kernel with "failsafe". openipc-failsafe then brings up network and SSH + * only, so the camera stays reachable. Firmware without that package ignores + * the word and boots as usual. Firmware the scan found broken (bootfail) + * goes to recovery first, as bootflash does. A kernel that does not load + * leaves the camera at this prompt rather than in a reset loop. + * OPENIPC_ALTBOOTCMD_RETIRED is the reflash this replaced on the + * openipc-hisilicon branch; openipc_helper() migrates an environment that + * still carries it. + */ +#define OPENIPC_ALTBOOTCMD "run fwrecovery; echo \"*** Boot limit exceeded -- entering FAILSAFE (network + SSH only) ***\"; setenv setargs setenv bootargs ${bootargs} failsafe; run setargs; if " OPENIPC_LOADKERNEL "; then bootm ${baseaddr}; fi" +#define OPENIPC_ALTBOOTCMD_RETIRED "echo \"*** Boot limit exceeded -- forcing firmware recovery ***\"; run fwupd" + +/* Environment shared by all boot media: identity, network boot, update + * source selection and the medium-agnostic update commands. The selected + * medium provides ubfile/ubwrite/ukwrite/urwrite/loadkernel/mtdids/ + * mtdparts/bootargs. */ +#define OPENIPC_ENV_COMMON \ + "baseaddr=" __stringify(OPENIPC_BASEADDR) "\0" \ + "osmem=" OPENIPC_OSMEM "\0" \ + "bsbsize=" __stringify(GK_BSB_MIB) "M\0" \ + "board_name\0" \ + "board=" CONFIG_PRODUCT_SOC "\0" \ + "vendor=" VENDOR "\0" \ + "soc=" CONFIG_PRODUCT_SOC "\0" \ + "socmodel=" CONFIG_PRODUCT_SOCMODEL "\0" \ + "nfsroot=/srv/nfs/" CONFIG_PRODUCT_SOC "\0" \ + "bootargsnfs=" OPENIPC_BOOTARGSNFS "\0" \ + "bootnfs=setenv setargs setenv bootargs ${bootargsnfs}; run setargs; ${source} ${baseaddr} uImage.${soc}; bootm ${baseaddr}\0" \ + "source=tftpboot\0" \ + "srcnet=setenv source tftpboot\0" \ + "srcmmc=setenv source fatload mmc 0\0" \ + "srcusb=usb start; setenv source fatload usb 0\0" \ + "ub=${source} ${baseaddr} ${ubfile} && run ubwrite\0" \ + "uk=if ${source} ${baseaddr} uImage.${soc}; then run ukwrite; elif ${source} ${baseaddr} fitImage.${soc}; then run ukwrite; fi\0" \ + "ur=${source} ${baseaddr} ${urfile} && run urwrite\0" \ + OPENIPC_FWUPD \ + "bootlimit=2\0" \ + "altbootcmd=" OPENIPC_ALTBOOTCMD "\0" \ + "fwrecovery=if env exists bootfail; then run fwupd; sleep 5; reset; fi\0" \ + "bootflash=run fwrecovery; setenv setargs setenv bootargs ${bootargs}; run setargs; run loadkernel; bootm ${baseaddr}; reset\0" + +/* The flash's MTD name in the vendor kernel (drivers/mtd/devices/gk_sflash) */ +#define SFC "gk_flash" + +#define CONFIG_BOOTARGS "mem=\\${osmem} console=ttySGK0,115200 panic=20 root=/dev/mtdblock3 rootfstype=squashfs init=/init mtdparts=\\${mtdparts} \\${extras}" + +/* Recovery: the rootfs is fetched first so its size selects the NOR schema */ +#define OPENIPC_FWUPD "fwupd=run ur; run uk\0" + +#define OPENIPC_LOADKERNEL "sf probe 0; sf read ${baseaddr} ${kernaddr} ${kernsize}" +#define OPENIPC_ENV_MEDIUM \ + "ubfile=u-boot-" CONFIG_PRODUCT_SOC "-nor.bin\0" \ + "urfile=rootfs.squashfs." CONFIG_PRODUCT_SOC "\0" \ + "kernaddr=" __stringify(OPENIPC_KERNADDR) "\0" \ + "kernsize=" __stringify(OPENIPC_KERNSIZE) "\0" \ + "rootaddr=" __stringify(OPENIPC_ROOTADDR) "\0" \ + "rootsize=" __stringify(OPENIPC_ROOTSIZE) "\0" \ + "mtdslite=setenv kernsize 0x200000; setenv rootaddr 0x250000; setenv rootsize 0x500000\0" \ + "mtdsultimate=setenv kernsize 0x300000; setenv rootaddr 0x350000; setenv rootsize 0xa00000\0" \ + "ubwrite=sf probe 0; sf erase 0x0 ${kernaddr}; sf write ${baseaddr} 0x0 ${filesize}\0" \ + "ukwrite=sf probe 0; sf erase ${kernaddr} ${kernsize}; sf write ${baseaddr} ${kernaddr} ${filesize}\0" \ + "urwrite=sf probe 0; if itest ${filesize} -gt 500000; then run mtdsultimate; fi; sf erase ${rootaddr} ${rootsize}; sf write ${baseaddr} ${rootaddr} ${filesize}\0" \ + "fwwrite=sf probe 0; sf erase ${kernaddr} ${filesize}; sf write ${baseaddr} ${kernaddr} ${filesize}\0" \ + "loadkernel=" OPENIPC_LOADKERNEL "\0" \ + "mtdids=" SFC "\0" \ + "mtds=" OPENIPC_MTDPARTS "\0" \ + "mtdparts=" SFC ":" OPENIPC_MTDPARTS "\0" \ + "bootargs=" CONFIG_BOOTARGS + +#define CONFIG_BOOTCOMMAND "run bootflash" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + OPENIPC_ENV_COMMON \ + OPENIPC_ENV_MEDIUM + +#endif /* __OPENIPC_COMMON_H */ From 0860751a6965da4ecc248d65792b82356b74788a Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:46 +0000 Subject: [PATCH 05/10] gk_sflash: add the Goke GK710x serial flash controller A register-driven SPI master with no memory window: COMMAND describes one transaction (opcode, address and dummy bytes, direction, 1-4 data bytes per DATA access) and DATA carries the address and the data. Like the vendor U-Boot this driver provides spi_flash_probe() itself and fills mtd->_read/_write/_erase, so mainline's non-DM spi_flash_*() wrappers, the sf command and the environment in SPI flash work without the SPI and spi-nor layers. CMD_SF, ENV_IS_IN_SPI_FLASH and the SF_DEFAULT_* options accept GK_SFLASH for that. The controller packs bytes MSB first, and the boot ROM and the vendor kernel move whole little-endian words through it. The driver does the same, for unaligned offsets and lengths too (reads through the covering words, programs padded with 0xff), so what it writes the ROM and the kernel read back unchanged. Single lane, parts up to 16 MiB; block protection left by a vendor loader is cleared. Under qemu-hisilicon's gk7102 machine: a 0x12345-byte write at 0x700003 reads back identical, with 0xff around it; saveenv survives a reset and fw_printenv reads it from Linux; the kernel and rootfs written by TFTP recovery boot. --- cmd/Kconfig | 2 +- drivers/mtd/spi/Kconfig | 16 ++- drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/gk_sflash.c | 280 ++++++++++++++++++++++++++++++++++++ env/Kconfig | 2 +- 5 files changed, 295 insertions(+), 6 deletions(-) create mode 100644 drivers/mtd/spi/gk_sflash.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 0e0be94f41f1..f21ddee00e60 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1412,7 +1412,7 @@ config CMD_SDRAM config CMD_SF bool "sf" - depends on DM_SPI_FLASH || SPI_FLASH + depends on DM_SPI_FLASH || SPI_FLASH || GK_SFLASH default y if DM_SPI_FLASH help SPI Flash support diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 096338f27bf1..aa61779cb7a3 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -36,9 +36,17 @@ config SPI_FLASH If unsure, say N +config GK_SFLASH + bool "Goke GK710x sflash SPI NOR controller" + depends on ARCH_GK710X && !SPI_FLASH && !DM_SPI_FLASH + help + The GK7101/GK7102 serial flash controller. It runs SPI NOR + transactions itself and provides spi_flash_probe() directly, + without the SPI and spi-nor layers. + config SF_DEFAULT_BUS int "SPI Flash default bus identifier" - depends on SPI_FLASH || DM_SPI_FLASH + depends on SPI_FLASH || DM_SPI_FLASH || GK_SFLASH default 0 help The default bus may be provided by the platform @@ -47,7 +55,7 @@ config SF_DEFAULT_BUS config SF_DEFAULT_CS int "SPI Flash default Chip-select" - depends on SPI_FLASH || DM_SPI_FLASH + depends on SPI_FLASH || DM_SPI_FLASH || GK_SFLASH default 0 help The default chip select may be provided by the platform @@ -56,7 +64,7 @@ config SF_DEFAULT_CS config SF_DEFAULT_MODE hex "SPI Flash default mode (see include/spi.h)" - depends on SPI_FLASH || DM_SPI_FLASH + depends on SPI_FLASH || DM_SPI_FLASH || GK_SFLASH default 0x0 help The default mode may be provided by the platform @@ -68,7 +76,7 @@ config SF_DEFAULT_MODE config SF_DEFAULT_SPEED int "SPI Flash default speed in Hz" - depends on SPI_FLASH || DM_SPI_FLASH + depends on SPI_FLASH || DM_SPI_FLASH || GK_SFLASH default 1000000 help The default speed may be provided by the platform diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 99cc41855223..6bc601eb2e98 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o +obj-$(CONFIG_GK_SFLASH) += gk_sflash.o diff --git a/drivers/mtd/spi/gk_sflash.c b/drivers/mtd/spi/gk_sflash.c new file mode 100644 index 000000000000..8ba8a3277aa5 --- /dev/null +++ b/drivers/mtd/spi/gk_sflash.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Goke GK7101/GK7102 serial flash controller ("sflash") with a SPI NOR + * behind it. + * + * A register-driven SPI master with no memory window. COMMAND describes one + * transaction -- opcode, address and dummy byte counts, direction, lane + * widths, 1-4 data bytes per DATA access -- and writing it starts the + * transaction. With address bytes, the first DATA write is the address; a + * command without data (an erase) runs then, reads and programs stream + * through DATA from there on. + * + * Bytes are packed MSB first: a four-byte read returns the first byte from + * flash in bits 31:24. Like the boot ROM and the vendor kernel, this driver + * moves whole little-endian words between memory and DATA, so the flash + * holds every 32-bit word of an image byte-swapped, and reads it back as it + * was written. A camera's flash dump reads as big-endian for that reason. + * + * After the vendor U-Boot's drivers/mtd/spi/gk7101_sflash.c and kernel + * gk_sflash_v1_00.c, single-lane only; like them it provides + * spi_flash_probe() itself, so mainline's non-DM spi_flash_*() wrappers, the + * sf command and the environment in SPI flash work without the SPI and + * spi-nor layers. Parts up to 16 MiB: the 4-byte/bank-register path of the + * vendor code is left out. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SF_DATA (GK_SFLASH_BASE + 0x00) +#define SF_COMMAND (GK_SFLASH_BASE + 0x04) +#define SF_CE (GK_SFLASH_BASE + 0x08) +#define SF_SPEED (GK_SFLASH_BASE + 0x0C) + +/* COMMAND */ +#define SF_SEND_CMD BIT(8) +#define SF_ADDR3 (3 << 9) +#define SF_RWN_READ (0 << 15) +#define SF_RWN_WRITE (1 << 15) +#define SF_RWN_NOTHING (3 << 15) +#define SF_BYTES(n) ((n) << 23) +#define SF_BYTES_4 SF_BYTES(0x1f) + +/* CE: chip select 0, WP and HOLD inactive (vendor value) */ +#define SF_CE_DEFAULT 0x0E +#define SF_SPEED_DIV2 0 + +#define SZ_PAGE 256 +#define SZ_SECTOR SZ_64K + +#define CMD_WRSR 0x01 +#define CMD_PP 0x02 +#define CMD_READ 0x03 +#define CMD_RDSR 0x05 +#define CMD_WREN 0x06 +#define CMD_RDSR2 0x35 +#define CMD_RDID 0x9F +#define CMD_SE_64K 0xD8 + +#define SR1_WIP BIT(0) +#define SR1_BP 0x7C /* GigaDevice/Winbond: BP0-4 */ +#define SR1_BP_OTHER 0x3C /* BP0-3 */ + +#define MFR_GIGADEVICE 0xc8 +#define MFR_WINBOND 0xef +#define MFR_XMC 0x20 + +static u32 sf_reg_read(u8 op, unsigned int nbytes) +{ + writel(op | SF_SEND_CMD | SF_RWN_READ | SF_BYTES(nbytes), SF_COMMAND); + return readl(SF_DATA); +} + +/* A command without address or data starts with the DATA access */ +static void sf_cmd(u8 op) +{ + writel(op | SF_SEND_CMD | SF_RWN_NOTHING, SF_COMMAND); + readl(SF_DATA); +} + +static void sf_wait_ready(void) +{ + while (sf_reg_read(CMD_RDSR, 1) & SR1_WIP) + ; +} + +static void sf_write_sr(u32 val, unsigned int nbytes) +{ + sf_cmd(CMD_WREN); + writel(CMD_WRSR | SF_SEND_CMD | SF_RWN_WRITE | SF_BYTES(nbytes), + SF_COMMAND); + writel(val, SF_DATA); + sf_wait_ready(); +} + +/* Clear the block protection a vendor loader may have left set */ +static void sf_unprotect(u32 jedec) +{ + const u8 mfr = jedec >> 16; + u32 sr1 = sf_reg_read(CMD_RDSR, 1) & 0xff; + + if (sr1 == 0xff) + return; + if (mfr == MFR_GIGADEVICE || mfr == MFR_WINBOND || mfr == MFR_XMC) { + /* QE lives in SR2, written as WRSR's second byte: keep it */ + if (sr1 & SR1_BP) { + u32 sr2 = sf_reg_read(CMD_RDSR2, 1) & 0xff; + + printf("SF: block protection (SR1 %02x), clearing\n", sr1); + sf_write_sr((sr1 & ~SR1_BP) << 8 | sr2, 2); + } + } else if (sr1 & SR1_BP_OTHER) { + printf("SF: block protection (SR1 %02x), clearing\n", sr1); + sf_write_sr(sr1 & ~SR1_BP_OTHER, 1); + } +} + +static void sf_erase_sector(u32 addr) +{ + sf_cmd(CMD_WREN); + writel(CMD_SE_64K | SF_SEND_CMD | SF_ADDR3 | SF_RWN_NOTHING, + SF_COMMAND); + writel(addr, SF_DATA); + sf_wait_ready(); +} + +/* Whole words, within one page */ +static void sf_program(u32 addr, const u8 *buf, unsigned int words) +{ + sf_cmd(CMD_WREN); + writel(CMD_PP | SF_SEND_CMD | SF_ADDR3 | SF_RWN_WRITE | SF_BYTES_4, + SF_COMMAND); + writel(addr, SF_DATA); + while (words--) { + writel(get_unaligned_le32(buf), SF_DATA); + buf += 4; + } + sf_wait_ready(); +} + +static int gk_sf_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + u32 addr = from & ~3; + unsigned int skip = from & 3; + + if (from + len > mtd->size) + return -EINVAL; + *retlen = len; + if (!len) + return 0; + + writel(CMD_READ | SF_SEND_CMD | SF_ADDR3 | SF_RWN_READ | SF_BYTES_4, + SF_COMMAND); + writel(addr, SF_DATA); + while (len) { + u32 w = readl(SF_DATA); + unsigned int n = min_t(size_t, len, 4 - skip); + + if (!skip && n == 4) { + put_unaligned_le32(w, buf); + } else { + u8 b[4]; + + put_unaligned_le32(w, b); + memcpy(buf, b + skip, n); + skip = 0; + } + buf += n; + len -= n; + } + return 0; +} + +/* + * The controller programs whole words, so a write that starts or ends + * inside one pads it with 0xff, which leaves those flash bytes as they are. + */ +static int gk_sf_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + u8 page[SZ_PAGE]; + u32 addr = to & ~3; + unsigned int head = to & 3; + + if (to + len > mtd->size) + return -EINVAL; + *retlen = len; + while (len) { + unsigned int room = SZ_PAGE - (addr & (SZ_PAGE - 1)); + unsigned int n = min_t(size_t, len, room - head); + unsigned int span = ALIGN(head + n, 4); + + memset(page, 0xff, span); + memcpy(page + head, buf, n); + sf_program(addr, page, span / 4); + addr += span; + buf += n; + len -= n; + head = 0; + WATCHDOG_RESET(); + } + return 0; +} + +static int gk_sf_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + u32 addr = instr->addr; + u32 end = instr->addr + instr->len; + + if (addr % SZ_SECTOR || instr->len % SZ_SECTOR || end > mtd->size) + return -EINVAL; + for (; addr < end; addr += SZ_SECTOR) { + sf_erase_sector(addr); + WATCHDOG_RESET(); + } + return 0; +} + +static struct spi_flash gk_flash; +static int gk_announced; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_flash *flash = &gk_flash; + struct mtd_info *mtd = &flash->mtd; + u32 jedec, size; + + writel(SF_CE_DEFAULT, SF_CE); + writel(SF_SPEED_DIV2, SF_SPEED); + jedec = sf_reg_read(CMD_RDID, 3) & 0xffffff; + if (!jedec || jedec == 0xffffff) { + printf("SF: no flash (JEDEC id %06x)\n", jedec); + return NULL; + } + /* The last ID byte is log2 of the size on the parts these boards carry */ + size = (jedec & 0xff) >= 0x14 && (jedec & 0xff) <= 0x18 ? + 1 << (jedec & 0xff) : SZ_8M; + + sf_unprotect(jedec); + + memset(flash, 0, sizeof(*flash)); + flash->name = "gk-sflash"; + flash->size = size; + flash->page_size = SZ_PAGE; + flash->sector_size = SZ_SECTOR; + flash->erase_size = SZ_SECTOR; + flash->erase_opcode = CMD_SE_64K; + flash->read_opcode = CMD_READ; + flash->program_opcode = CMD_PP; + + mtd->name = "gk-sflash"; + mtd->type = MTD_NORFLASH; + mtd->flags = MTD_CAP_NORFLASH; + mtd->size = size; + mtd->erasesize = SZ_SECTOR; + mtd->writesize = 1; + mtd->writebufsize = SZ_PAGE; + mtd->_read = gk_sf_read; + mtd->_write = gk_sf_write; + mtd->_erase = gk_sf_erase; + mtd->priv = flash; + + /* Once: the environment and common/openipc.c probe again and again */ + if (!gk_announced++) + printf("SF: Detected JEDEC %06x with page size %u Bytes, erase size %u KiB, total %u MiB\n", + jedec, SZ_PAGE, SZ_SECTOR >> 10, size >> 20); + return flash; +} + +void spi_flash_free(struct spi_flash *flash) +{ +} diff --git a/env/Kconfig b/env/Kconfig index 238e4c70cf05..69be54f8d74b 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -330,7 +330,7 @@ config ENV_IS_IN_REMOTE config ENV_IS_IN_SPI_FLASH bool "Environment is in SPI flash" - depends on !CHAIN_OF_TRUST && SPI + depends on !CHAIN_OF_TRUST && (SPI || GK_SFLASH) default y if ARMADA_XP default y if INTEL_BAYTRAIL default y if INTEL_BRASWELL From 0a893eeb51d68d222b2aa3709f18b120d50a4d82 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:46 +0000 Subject: [PATCH 06/10] openipc: build GK7101 and GK7102 NOR images build.sh as on openipc-xm: each SoC's .config is openipc/openipc_config followed by openipc/_config, then olddefconfig; `bash build.sh [soc...]` writes output/u-boot--nor.bin. The image is u-boot.bin behind the boot ROM's header (openipc/gk710x-image.py): magic and version, the U-Boot length, load and entry address, the DDR test words, then openipc/.rvs -- the eFuse, DDR PHY and DDR controller set-up, taken from the SDK's prebuilt U-Boots and the same on cameras in the field; GK7101 and GK7102 differ only in the DDR size word. The image is in CPU byte order, as `sf write` stores it. The base fragment carries the OpenIPC options: prompt "OpenIPC # ", autoboot stopped by Ctrl-C only, silent=1, hush, the environment at 0x40000 in SPI NOR, TFTP for recovery, a random MAC when none is set, and the DRAM boot counter at DDR + 0x1f20000. BOARD_SIZE_LIMIT keeps header and image within the 256 KiB boot partition; with no Thumb-2 on ARM1176 the image is about 237 KiB. Under qemu-hisilicon, from an 8 MiB flash image: gk7102 and gk7101 boot the OpenIPC gk7102 lite kernel and rootfs to login; an empty flash recovers by TFTP (ur, uk) and boots; two resets without a healthy boot take altbootcmd into failsafe. --- .gitignore | 3 ++ build.sh | 64 +++++++++++++++++++++++++++++ openipc/gk7101.rvs | 71 ++++++++++++++++++++++++++++++++ openipc/gk7101_config | 2 + openipc/gk7102.rvs | 71 ++++++++++++++++++++++++++++++++ openipc/gk7102_config | 2 + openipc/gk710x-image.py | 58 ++++++++++++++++++++++++++ openipc/openipc_config | 91 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 362 insertions(+) create mode 100755 build.sh create mode 100644 openipc/gk7101.rvs create mode 100644 openipc/gk7101_config create mode 100644 openipc/gk7102.rvs create mode 100644 openipc/gk7102_config create mode 100755 openipc/gk710x-image.py create mode 100644 openipc/openipc_config diff --git a/.gitignore b/.gitignore index eb769f144c3d..0183116964e3 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,6 @@ __pycache__ # pylint files /pylint.cur /pylint.out/ + +# OpenIPC build outputs +/output/ diff --git a/build.sh b/build.sh new file mode 100755 index 000000000000..e8cf4b34b8b2 --- /dev/null +++ b/build.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# +# Build U-Boot for the SoCs named on the command line, or for every +# supported SoC when invoked without arguments. Failures are collected: +# every requested SoC is attempted and the script exits non-zero if any +# of them failed. + +cd "$(dirname "$0")" + +export ARCH=arm +export CROSS_COMPILE=${CROSS_COMPILE:-arm-linux-gnueabi-} + +BOOT_SRCDIR=$(pwd) + +mkdir -p output + +# Concatenate the config fragments into the build directory's .config; +# later fragments override earlier ones. +mkconfig() { + builddir=$1 + shift + mkdir -p "${builddir}" + cat "$@" > "${builddir}/.config" +} + +# Goke GK710x: the boot ROM runs the DDR set-up in the image's header, then +# copies U-Boot to its link address and starts it there. +build_gk710x() { + soc=$1 + builddir=${BOOT_SRCDIR}/output/build-${soc}-nor + make_opts="-C ${BOOT_SRCDIR} O=${builddir} -j$(nproc)" + + rm -rf "${builddir}" + mkconfig "${builddir}" openipc/openipc_config openipc/${soc}_config && \ + make ${make_opts} olddefconfig /dev/null && \ + make ${make_opts} &2 + return 1 ;; + esac +} + +ALL_SOCS="gk7101 gk7102" + +SOCS="$@" +[ -z "${SOCS}" ] && SOCS="${ALL_SOCS}" + +rc=0 +for soc in ${SOCS}; do + build_soc "${soc}" || { echo "build failed for ${soc}" >&2; rc=1; } +done + +exit ${rc} diff --git a/openipc/gk7101.rvs b/openipc/gk7101.rvs new file mode 100644 index 000000000000..9fa92df228f2 --- /dev/null +++ b/openipc/gk7101.rvs @@ -0,0 +1,71 @@ +# GK7101 boot ROM set-up: the register writes the mask ROM makes before it +# copies U-Boot into DDR -- eFuse, DDR PHY, the RCT and the DDR controller. +# Taken from the header of the SDK's prebuilt uboot-gk7101-rb-ov2710_v2.2.bin +# (GK710X_LinuxSDK_v2.0.0 boot/prebuild), the table on GK710x cameras in the +# field. build.sh writes it into the boot header. +# +# setup: = write +# rdcom: = wait until the register reads +# +setup: 0x6000B100 = 0xFF39C119 +setup: 0x60021A68 = 0x00000300 +setup: 0x60021A60 = 0x00002B52 +setup: 0x60021A64 = 0x00000035 +setup: 0x60021A48 = 0x00001000 +setup: 0x60021A48 = 0x00000000 +setup: 0x60021B00 = 0x00000031 +setup: 0x60021A00 = 0x00000012 +setup: 0x60021A08 = 0x0000F080 +setup: 0x60021A70 = 0x00000033 +setup: 0x60021A74 = 0x00000000 +setup: 0x60021A04 = 0x00000000 +setup: 0x60021A78 = 0x00000200 +setup: 0x60021A7C = 0x00000022 +setup: 0x60021A1C = 0x000000E7 +setup: 0x60021A1C = 0x000000A7 +setup: 0x60021A1C = 0x000000E7 +setup: 0x60021A1C = 0x000000A7 +setup: 0x60021ADC = 0x00009999 +setup: 0x60021AE4 = 0x00000006 +setup: 0x60021AD4 = 0x0000004F +setup: 0x60021AD0 = 0x0000004F +setup: 0x60021AA8 = 0x00000000 +setup: 0x60021A2C = 0x00000000 +setup: 0x60021A00 = 0x00000002 +setup: 0x60021A04 = 0x0000AAAA +setup: 0x60021A10 = 0x0000007F +setup: 0x70170228 = 0x00000001 +setup: 0x60004004 = 0x00100354 +setup: 0x60004008 = 0x48FA368B +setup: 0x6000400C = 0x00002872 +setup: 0x60004010 = 0x0020903F +setup: 0x60004020 = 0x000000A0 +setup: 0x60004000 = 0x00000004 +setup: 0x60004014 = 0x00000001 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004018 = 0x01020000 +rdcom: 0x60004018 = 0x01020000 +setup: 0x60004018 = 0x01030000 +rdcom: 0x60004018 = 0x01030000 +setup: 0x60004018 = 0x01010044 +rdcom: 0x60004018 = 0x01010044 +setup: 0x60004018 = 0x01000B63 +rdcom: 0x60004018 = 0x01000B63 +setup: 0x60004014 = 0x00000001 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004018 = 0x01000A63 +rdcom: 0x60004018 = 0x01000A63 +setup: 0x60004000 = 0x00000006 +setup: 0x60004018 = 0x01010380 +rdcom: 0x60004018 = 0x01010380 +setup: 0x60004018 = 0x01010000 +rdcom: 0x60004018 = 0x01010000 +setup: 0x6000401C = 0x00000210 +setup: 0x60004000 = 0x00000007 +setup: 0x6000B104 = 0x00000001 diff --git a/openipc/gk7101_config b/openipc/gk7101_config new file mode 100644 index 000000000000..8a48fd3c6fdb --- /dev/null +++ b/openipc/gk7101_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_GK7101=y +CONFIG_PRODUCT_SOC="gk7101" diff --git a/openipc/gk7102.rvs b/openipc/gk7102.rvs new file mode 100644 index 000000000000..5cc534f13dcc --- /dev/null +++ b/openipc/gk7102.rvs @@ -0,0 +1,71 @@ +# GK7102 boot ROM set-up: the register writes the mask ROM makes before it +# copies U-Boot into DDR -- eFuse, DDR PHY, the RCT and the DDR controller. +# Taken from the header of the SDK's prebuilt uboot-gk7102-rb-jxh42_v2.0.bin +# (GK710X_LinuxSDK_v2.0.0 boot/prebuild), the table on GK710x cameras in the +# field. build.sh writes it into the boot header. +# +# setup: = write +# rdcom: = wait until the register reads +# +setup: 0x6000B100 = 0xFF39C119 +setup: 0x60021A68 = 0x00000300 +setup: 0x60021A60 = 0x00002B52 +setup: 0x60021A64 = 0x00000035 +setup: 0x60021A48 = 0x00001000 +setup: 0x60021A48 = 0x00000000 +setup: 0x60021B00 = 0x00000031 +setup: 0x60021A00 = 0x00000012 +setup: 0x60021A08 = 0x0000F080 +setup: 0x60021A70 = 0x00000033 +setup: 0x60021A74 = 0x00000000 +setup: 0x60021A04 = 0x00000000 +setup: 0x60021A78 = 0x00000200 +setup: 0x60021A7C = 0x00000022 +setup: 0x60021A1C = 0x000000E7 +setup: 0x60021A1C = 0x000000A7 +setup: 0x60021A1C = 0x000000E7 +setup: 0x60021A1C = 0x000000A7 +setup: 0x60021ADC = 0x00009999 +setup: 0x60021AE4 = 0x00000006 +setup: 0x60021AD4 = 0x0000004F +setup: 0x60021AD0 = 0x0000004F +setup: 0x60021AA8 = 0x00000000 +setup: 0x60021A2C = 0x00000000 +setup: 0x60021A00 = 0x00000002 +setup: 0x60021A04 = 0x0000AAAA +setup: 0x60021A10 = 0x0000007F +setup: 0x70170228 = 0x00000001 +setup: 0x60004004 = 0x00100344 +setup: 0x60004008 = 0x48FA368B +setup: 0x6000400C = 0x00002872 +setup: 0x60004010 = 0x0020903F +setup: 0x60004020 = 0x000000A0 +setup: 0x60004000 = 0x00000004 +setup: 0x60004014 = 0x00000001 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004018 = 0x01020000 +rdcom: 0x60004018 = 0x01020000 +setup: 0x60004018 = 0x01030000 +rdcom: 0x60004018 = 0x01030000 +setup: 0x60004018 = 0x01010044 +rdcom: 0x60004018 = 0x01010044 +setup: 0x60004018 = 0x01000B63 +rdcom: 0x60004018 = 0x01000B63 +setup: 0x60004014 = 0x00000001 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004014 = 0x00000002 +rdcom: 0x60004014 = 0x00000000 +setup: 0x60004018 = 0x01000A63 +rdcom: 0x60004018 = 0x01000A63 +setup: 0x60004000 = 0x00000006 +setup: 0x60004018 = 0x01010380 +rdcom: 0x60004018 = 0x01010380 +setup: 0x60004018 = 0x01010000 +rdcom: 0x60004018 = 0x01010000 +setup: 0x6000401C = 0x00000210 +setup: 0x60004000 = 0x00000007 +setup: 0x6000B104 = 0x00000001 diff --git a/openipc/gk7102_config b/openipc/gk7102_config new file mode 100644 index 000000000000..7e7363158a4c --- /dev/null +++ b/openipc/gk7102_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_GK7102=y +CONFIG_PRODUCT_SOC="gk7102" diff --git a/openipc/gk710x-image.py b/openipc/gk710x-image.py new file mode 100755 index 000000000000..39d0740dc60e --- /dev/null +++ b/openipc/gk710x-image.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""Wrap u-boot.bin in the GK7101/GK7102 boot ROM header. + + gk710x-image.py .rvs u-boot.bin + +The mask ROM reads the header from flash offset 0, in CPU words: + + 0, 1 "GK71" magic, version (0x474B3731, 0x30310801) + 2 U-Boot length in words + 3 load address, where it also starts U-Boot + 4 the load address in words + 5, 6 DDR test address and pattern + 7.. the .rvs table: to write, or 0xFFFFFFFE, + to wait for; 0 ends it + +and U-Boot follows the 0. Words 0, 1 and 4-6 are as in every SDK prebuilt +U-Boot and camera flash seen. The output is in CPU byte order, what `sf +write` and the vendor kernel's driver store; the flash chip itself then +holds every word byte-swapped (drivers/mtd/spi/gk_sflash.c). +""" +import re +import struct +import sys + +MAGIC = 0x474B3731 +VERSION = 0x30310801 +DDR_TEST = (0xC4000000, 0x5A5A5A5A) +POLL = 0xFFFFFFFE + + +def table(path): + words = [] + for line in open(path): + m = re.match(r'\s*(setup|rdcom):\s*(0x[0-9a-fA-F]+)\s*=\s*' + r'(0x[0-9a-fA-F]+)', line) + if not m: + continue + if m.group(1) == 'rdcom': + words.append(POLL) + words += [int(m.group(2), 16), int(m.group(3), 16)] + if not words: + sys.exit('%s: no setup lines' % path) + return words + [0] + + +def main(): + rvs, src, load, dst = sys.argv[1], sys.argv[2], int(sys.argv[3], 0), \ + sys.argv[4] + code = open(src, 'rb').read() + code += b'\0' * (-len(code) % 4) + head = [MAGIC, VERSION, len(code) // 4, load, load // 4, *DDR_TEST] + head += table(rvs) + with open(dst, 'wb') as f: + f.write(struct.pack('<%dI' % len(head), *head) + code) + + +if __name__ == '__main__': + main() diff --git a/openipc/openipc_config b/openipc/openipc_config new file mode 100644 index 000000000000..cda648c42a15 --- /dev/null +++ b/openipc/openipc_config @@ -0,0 +1,91 @@ +# OpenIPC base configuration for the Goke GK7101/GK7102 targets. build.sh +# appends the per-SoC fragment and runs olddefconfig, so a later line +# overrides an earlier one. +CONFIG_ARM=y +CONFIG_ARCH_GK710X=y +CONFIG_SYS_TEXT_BASE=0xC0800000 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_DM is not set +CONFIG_SYS_DCACHE_OFF=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_LEN=0x400000 +CONFIG_SYS_LOAD_ADDR=0xC1000000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_STATIC_MACH_TYPE=y +# GOKE_IPC: what the vendor kernels register +CONFIG_MACH_TYPE=3988 +CONFIG_SETUP_MEMORY_TAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y +CONFIG_DISPLAY_CPUINFO=y +CONFIG_MISC_INIT_R=y + +# Console +CONFIG_SYS_NS16550=y +CONFIG_SPECIFY_CONSOLE_INDEX=y +CONFIG_CONS_INDEX=1 +CONFIG_BAUDRATE=115200 +CONFIG_SYS_PROMPT="OpenIPC # " +CONFIG_SILENT_CONSOLE=y +CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC=y +CONFIG_HUSH_PARSER=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y + +# Autoboot: Ctrl-C only +CONFIG_BOOTDELAY=1 +CONFIG_AUTOBOOT=y +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Hit Ctrl-C to stop autoboot: %2d\n" +CONFIG_AUTOBOOT_STOP_STR="\x03" +CONFIG_AUTOBOOT_KEYED_CTRLC=y + +# OpenIPC boot layer: firmware scan, recovery, boot-limit failsafe +CONFIG_OPENIPC=y +CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_BOOTCOUNT_GENERIC=y +CONFIG_SYS_BOOTCOUNT_SINGLEWORD=y +# DRAM + 0x1f20000, as on the HiSilicon and Xiongmai targets +CONFIG_SYS_BOOTCOUNT_ADDR=0xC1F20000 +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_OF_LIBFDT=y + +# SPI NOR, and the environment in it +CONFIG_GK_SFLASH=y +CONFIG_CMD_SF=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_OFFSET=0x40000 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_SECT_SIZE=0x10000 +# Boot header (576 bytes) + image must end before the environment: fail the +# build, not the board +CONFIG_HAS_BOARD_SIZE_LIMIT=y +CONFIG_BOARD_SIZE_LIMIT=261568 + +# Commands +CONFIG_CMD_BOOTM=y +CONFIG_CMD_GO=y +CONFIG_CMD_RUN=y +CONFIG_CMD_ECHO=y +CONFIG_CMD_ITEST=y +CONFIG_CMD_SOURCE=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_EDITENV=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_ENV_EXISTS=y +CONFIG_CMD_MEMORY=y +CONFIG_CMD_CRC32=y +CONFIG_CMD_SLEEP=y + +# Network: the GMAC is a DesignWare MAC, the PHY the SoC's own +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_ETH_DESIGNWARE=y +CONFIG_PHYLIB=y +CONFIG_CMD_NET=y +CONFIG_CMD_TFTPBOOT=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_MII=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_LIB_RAND=y From 53b754bc8d65083121ed9eb6c9ae657e076a31e6 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:22:46 +0000 Subject: [PATCH 07/10] ci, docs: call build-gk710x.yml, add CLAUDE.md .github/workflows/ci.yml is the thin caller openipc-xm has: pushes and pull requests on this branch run build-gk710x.yml from the openipc branch with this revision. CLAUDE.md is guidance for Claude Code sessions on this branch: how it differs from mainline v2022.10, the HAL and how register values were recovered, the boot header and flash byte order, what the kernel is handed, the GPIO maps, and what qemu-hisilicon does and does not verify. --- .github/workflows/ci.yml | 25 +++++ CLAUDE.md | 233 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 CLAUDE.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..25277371affa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +# The build lives in build-gk710x.yml on the openipc branch (the default +# branch, so it can be dispatched). GitHub runs a pull request's +# workflows from the PR's own tree, so this branch needs this caller for +# its pushes and pull requests to be built and smoke-tested at all. +# It never releases: that workflow only uploads on workflow_dispatch. +on: + push: + branches: [openipc-gk710x] + pull_request: + branches: [openipc-gk710x] + +jobs: + build: + uses: OpenIPC/u-boot/.github/workflows/build-gk710x.yml@openipc + # github.sha: on pull_request the merge of the PR into the current + # base, so the PR is built as it would land; on push, that commit. + with: + ref: ${{ github.sha }} + # A called workflow is validated against what its caller grants, + # skipped jobs included; release/publish ask for these. + permissions: + contents: write + id-token: write diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000000..af2702ec3853 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,233 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this branch is + +`openipc-gk710x` is OpenIPC's U-Boot for Goke's own ARM1176 camera SoCs, the +GK7101 and GK7102. These are not the HiSilicon-derived GK7205/GK7605 that +`openipc-hisilicon` covers. The tree is **mainline U-Boot v2022.10**, the +same release as `openipc-hisilicon` and `openipc-xm`, plus: + +- the OpenIPC boot layer, carried over from `openipc-xm`, which took it from + `openipc-hisilicon`; +- the GK710x support, written from the vendor SDK (`GK710X_LinuxSDK_v2.0.0`, + U-Boot 2012.10 and Linux 3.4.43). + +No vendor driver comes along. The vendor's HAL blob is carried, for the +kernel only (see below). + +CI and user docs live on the `openipc` branch: + +- `.github/workflows/ci.yml` only calls `build-gk710x.yml@openipc`. +- `git show origin/openipc:CLAUDE.md` covers the workflow invariants. +- `git show origin/openipc-hisilicon:CLAUDE.md` covers the OpenIPC layer + (default environment, `common/openipc.c`, env compatibility). It applies + here unchanged. + +Adding or dropping a SoC needs both branches: + +- here: `build.sh` (`build_soc`, `ALL_SOCS`), `openipc/_config` and + `openipc/.rvs`; +- there: `build-gk710x.yml`'s matrices and the README. + +GK7101S/GK7102S (`gk7102s` in OpenIPC/firmware) are a different die with a +different HAL and register map. They are not supported here, and +qemu-hisilicon does not model them. + +## Relationship to mainline + +```sh +git diff --stat v2022.10 HEAD # the whole delta, small +git diff --diff-filter=M v2022.10 HEAD # the mainline files we patched +``` + +**Added** + +| Area | Location | +| --- | --- | +| SoC: clocks, timer, watchdog reset, DRAM size, pin functions | `arch/arm/mach-gk710x/` (`ARCH_GK710X`; `TARGET_GK7101`/`GK7102`; register map in `include/mach/gk710x.h`) | +| Kernel hand-off: HAL blob, U2K words | `arch/arm/mach-gk710x/kernel.c`, `hal_data.h` | +| Board: GPIO maps, internal Ethernet PHY, `misc_init_r` → `openipc_helper()` | `board/goke/gk710x/` | +| Memory map, console, timer | `include/configs/gk710x.h`, ending in `#include "openipc-common.h"` | +| SPI NOR controller, non-DM | `drivers/mtd/spi/gk_sflash.c` (`GK_SFLASH`). It provides `spi_flash_probe()` and fills `mtd->_read/_write/_erase`, as `xmsfc` does on `openipc-xm` | +| OpenIPC boot layer | `common/openipc.c`, `include/openipc.h` (as on `openipc-xm`), `include/configs/openipc-common.h` (GK rewrite, NOR only, same env commands) | +| Kconfig fragments, boot header, the build | `openipc/`, `build.sh` | + +**Patched mainline files**, each small: + +- `arch/arm/{Kconfig,Makefile}`: the `ARCH_GK710X` hook. +- `common/{Kconfig,Makefile}`: `OPENIPC`, `PRODUCT_SOC`, `PRODUCT_SOCMODEL`. +- `drivers/mtd/spi/{Kconfig,Makefile}`, `cmd/Kconfig` (`CMD_SF`) and + `env/Kconfig` (`ENV_IS_IN_SPI_FLASH`): accept `GK_SFLASH`. +- `drivers/net/Kconfig`: `NETDEVICES` selects `DM_ETH` only when `DM` is on, + as on `openipc-xm`. +- `drivers/net/designware.c`: the non-DM `designware_initialize()` uses an + MDIO bus the board has already registered under the device's name. The + GK710x PHY is not on the MAC's MDIO lines. + +The console (NS16550), the timer (`lib/time.c` over a raw counter) and +Ethernet (DesignWare) are mainline drivers. + +## The HAL, and why there is no vendor driver + +The vendor U-Boot and kernel never touch a register directly. Every access +goes through a HAL blob, written against a fictitious map (AHB `0x90000000`, +APB `0xA0000000`). The HAL: + +1. moves each block to its real place; +2. reorders registers inside some blocks; +3. permutes the bits of some registers (RCT PLLs, timer and watchdog + control, pad control). + +This tree programs the silicon directly. Every address and value in +`include/mach/gk710x.h`, `soc.c` and `board/goke/gk710x/gk710x.c` is the +store the HAL itself makes. It was found by executing the HAL's `hw_writel` +under Unicorn (qemu-hisilicon `qemu-boot/gk710x-halmap.py`). To port another +vendor register write, run it through the HAL the same way. Do not guess +from the vendor `*_reg.h`. + +The kernel still needs the blob (see "Hand-off to the kernel"). + +## Boot + +- The mask ROM reads the header at flash offset 0. It runs the register + writes and polls listed there (eFuse, DDR PHY, DDR controller), copies + U-Boot to `0xC0800000` (`SYS_TEXT_BASE`) and starts it. + - DDR is up before the first instruction, so there is no SPL, and + `lowlevel_init` is empty. +- `openipc/gk710x-image.py` builds that header: + - the words around the table are as in every SDK prebuilt and camera + flash seen; + - the table is `openipc/.rvs`, taken from the SDK's prebuilt + U-Boots, which matches what is on cameras in the field; + - GK7101 and GK7102 differ only in the DDR controller word at + `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; + - a camera dump reads as big-endian ("GK7101" in a hex editor); + - `output/u-boot--nor.bin` is in CPU order, which is what `sf write` + and the kernel's MTD driver expect; + - a raw image for a programmer, or for qemu's `flash-file=`, needs every + word swapped. + - `gk_sflash.c` keeps that mapping for unaligned offsets as well: whole + words only, writes padded with `0xff`. + +## Hand-off to the kernel + +The vendor kernel, OpenIPC's `gk7102` included, needs more than ATAGs. +`board_prep_linux()` in `mach-gk710x/kernel.c` provides: + +- **The HAL** at `0xC0012000`, with its address in U2K word `0xC0000008`. + The kernel calls `hal_init()` first thing and refuses a HAL older than + 20160324. The carried one is 20160913. +- **U2K words** at `0xC0000000`: + - total DDR in MiB; + - `mem=` in bytes, from `osmem`; + - the bitstream buffer, from `bsbsize`; + - `phytype`; + - the `0x7101` valid marker. + + The kernel places BSB, DSP and USR memory from these. `mem=` on the + command line still sets the kernel's own size. +- **The GPIO map** (vendor `gpio_cfg_t`) in the top 64 KiB of DDR. + - The kernel configures every pin from it ("gpio map get from uboot"): + sensor I2C and reset, IR cut, SD, Ethernet LED and PHY clock. + - Without it a camera boots with no sensor bus. + - `board_get_usable_ram_top()` keeps U-Boot below that 64 KiB. + +The SDK's 20-odd board GPIO headers come down to two layouts +(`board/goke/gk710x/gpio_map.c`): + +- `v2`, the default: rb-sc1035 v2.1, sc1045, imx225, ov9750, jxh42 v2.0, + gc1024, GK7101 rb-ov2710 v2.2; +- `v1`: rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222. + +`gpiomap=v1` in the environment selects the second. U-Boot also applies the +selected map at `misc_init_r()`, as the vendor U-Boot did, so its own +Ethernet gets its PHY clock pin. Other vendor boards (EVBs, rb-ov2710 v1/v2.0/v2.1, +ps1210, bg0703, ar0230) have other maps and are not covered. + +## Peripherals + +- **Console:** UART0 at `0x70005000`, a 16550 with 32-bit registers, 24 MHz. + `arch_cpu_init()` sets the vendor's CPU PLL and UART divider. +- **Timer:** timer 1 at `0x7000B000`, counting down at the 69 MHz APB + clock. **Reset:** the watchdog. +- **Ethernet:** a DesignWare GMAC at `0x6000E000` with the SoC's own + 10/100 PHY. + - The PHY's MII registers are memory mapped at `0x60022000 + 4n`. The + board registers them as the MDIO bus, PHY address 0. + - `gk_ephy_init()` does the vendor's PHY clock (audio PLL, out on a pin), + analog trim and MAC/PHY mux. + - External-PHY boards (`phytype=1/2`) are not handled. +- **SD:** not enabled. The vendor U-Boot had none, the controller's base + clock is unknown, and the SD pins depend on the board map. SD recovery in + `common/openipc.c` is compiled out with `CONFIG_MMC`. +- **SPI NAND:** not supported. OpenIPC's GK7102 firmware is NOR only. + +## Build + +```sh +bash build.sh # gk7101 gk7102; continues past failures, exits non-zero if any failed +bash build.sh gk7102 # one or more SoCs (CROSS_COMPILE defaults to arm-linux-gnueabi-) +``` + +- The output is `output/u-boot--nor.bin`, built out of tree in + `output/build--nor/`. +- `.config` is `openipc/openipc_config`, then `openipc/_config`, then + `olddefconfig`. +- There are no `configs/*_defconfig` for these targets. +- There is no Thumb-2 on ARM1176, so the image is ~237 KiB. + `BOARD_SIZE_LIMIT` keeps header + image under the 256 KiB boot + partition. Check the size after enabling anything. + +## Verification + +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 image +must be byte-swapped as described above. + +- **CI smoke:** two boots of an 8 MiB image holding only U-Boot. The second + must load the environment the first saved. +- **Checks to run by hand:** + - A full 8 MiB image reaches `login:`. It has U-Boot at 0, `uImage` at + 0x50000 and rootfs at 0x250000, from OpenIPC/firmware `latest` + `openipc.gk7102-nor-lite.tgz` (gk7101 boots the same). + - The kernel log shows `hal version = 20160913`, BSB/DSP/USR inside DDR, + and `[BOOT VERSION] GK7102 openipc-v2`. + - `sf erase/write/read` + `cmp.b` with an unaligned offset and length. + - `saveenv` + `reset`; `fw_printenv` from Linux. + - TFTP recovery from a flash holding only U-Boot + (`-nic user,net=192.168.1.0/24,host=192.168.1.107,tftp=`). + - The boot limit: two `reset`s, then `altbootcmd` boots with `failsafe`. +- **What qemu does not check:** + - DDR timing (the header is the vendor's, so this is low risk); + - PLL and clock values; + - pad control; + - the PHY's analog trim and real link. + + None of this has run on silicon yet. + +## Things to keep + +- `mem=` stays the first kernel argument, as on the other OpenIPC targets. + `osmem`/`bsbsize` must leave room for the DSP: + - GK7102: 36M + 2M of 64 MiB; + - GK7101: 50M + 4M of 128 MiB. +- The MTD name is `gk_flash`, the vendor kernel driver's (`SFC` in + `openipc-common.h`). The console is `ttySGK0`. +- The boot counter is the DRAM word at `0xC1F20000`, like the other + families' DDR + 0x1f20000. A healthy boot does not clear it, and the + GK7102 firmware ships no openipc-failsafe. After two reboots the boot + limit path therefore boots the same kernel with `failsafe`, which that + firmware ignores, as on `openipc-xm`. + +## Conventions + +- One topic per commit, `: ` (`gk710x:`, `gk_sflash:`, + `openipc:`, `net:`, `ci:`). +- Commit bodies say what was verified, and where: the qemu machine, or a + board. From 255b6672c5d29a57af28bcdd78bbda57d0a2a6ed Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:38:46 +0000 Subject: [PATCH 08/10] gk710x: set only the PHY clock pin, not the whole GPIO map misc_init_r() applied the selected GPIO map, as the vendor U-Boot did. Until gpiomap is set that map is the v2 default, and v2 makes GPIO 30/31 plain inputs and routes UART0 RX from pin 25. On a v1-layout board (rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222), where UART0 is on GPIO 30/31, the console then died before autoboot, so nobody could set gpiomap=v1. U-Boot only needs GPIO 48, the internal PHY's reference clock, which is the same in both layouts. Set that and leave the other pins as the boot ROM left them. The kernel still gets the full selected map. Under qemu-hisilicon gk7102: ping and TFTP still work, and the kernel still takes the v2 map, or the v1 one with gpiomap=v1 (PHY reset on pin 41). The machine does not model pin muxing, so the console fix itself is unverified. Reported by Qodo on #22. --- CLAUDE.md | 14 ++++++++++---- board/goke/gk710x/gpio_map.c | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index af2702ec3853..caf7e14d390b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -144,10 +144,16 @@ The SDK's 20-odd board GPIO headers come down to two layouts gc1024, GK7101 rb-ov2710 v2.2; - `v1`: rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222. -`gpiomap=v1` in the environment selects the second. U-Boot also applies the -selected map at `misc_init_r()`, as the vendor U-Boot did, so its own -Ethernet gets its PHY clock pin. Other vendor boards (EVBs, rb-ov2710 v1/v2.0/v2.1, -ps1210, bg0703, ar0230) have other maps and are not covered. +`gpiomap=v1` in the environment selects the second. Other vendor boards +(EVBs, rb-ov2710 v1/v2.0/v2.1, ps1210, bg0703, ar0230) have other maps and +are not covered. + +U-Boot itself sets only GPIO 48, the internal PHY's reference clock, the +same in both layouts. It does not apply the whole map, as the vendor U-Boot +did. The two layouts put UART0 on different pins, so with the wrong default +a v1 board would lose its console before `gpiomap=v1` could be set. A v1 +board still needs `gpiomap=v1` for the kernel's pins, its console +included. ## Peripherals diff --git a/board/goke/gk710x/gpio_map.c b/board/goke/gk710x/gpio_map.c index 54befe157374..b7ee9a0bf14d 100644 --- a/board/goke/gk710x/gpio_map.c +++ b/board/goke/gk710x/gpio_map.c @@ -247,16 +247,24 @@ static const struct gk_gpio_map *gk_map(void) return &gk_maps[0]; } -/* As the vendor U-Boot does at start: every pin, then the internal PHY's */ +/* + * U-Boot itself needs one pin: the internal PHY's reference clock, out on + * GPIO 48 in both layouts. The vendor U-Boot applied the whole map here, + * but the map is a guess until gpiomap is set, and the v2 map moves UART0 + * off GPIO 30/31 -- a v1 board would lose its console before anyone could + * set gpiomap=v1. The pins stay as the boot ROM left them; the kernel + * applies the full map it is handed. + */ +#define GK_EPHY_CLK_PIN 48 + void gk_gpio_map_apply(void) { const struct gk_gpio_map *m = gk_map(); int i; - for (i = 0; i < m->npins; i++) - gk_gpio_config(m->pins[i].pin, m->pins[i].type); for (i = 0; i < m->nintphy; i++) - gk_gpio_config(m->intphy[i].pin, m->intphy[i].type); + if (m->intphy[i].pin == GK_EPHY_CLK_PIN) + gk_gpio_config(m->intphy[i].pin, m->intphy[i].type); gk_gpio_init(); } From 5fbb0f04c8198733b993ac16f4c9a72d8943471a Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:38:46 +0000 Subject: [PATCH 09/10] gk_sflash: time out waiting for the flash, and report it sf_wait_ready() polled the status register until WIP cleared, with no limit. A flash that stayed busy, or a missing part reading 0xff, hung saveenv, the first-boot environment save and sf erase/write for good. Give up after 3 s, which is longer than any erase or program of the parts on these boards, and service the watchdog while waiting. Return -ETIMEDOUT through sf_program() and sf_erase_sector() to the MTD write/erase callbacks. Those now report how much was written, and the failing erase address. Under qemu-hisilicon gk7102: unaligned sf write/read and cmp, saveenv and reset, and TFTP recovery behave as before. Reported by Qodo on #22. --- drivers/mtd/spi/gk_sflash.c | 46 ++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/spi/gk_sflash.c b/drivers/mtd/spi/gk_sflash.c index 8ba8a3277aa5..7b4bc86ed048 100644 --- a/drivers/mtd/spi/gk_sflash.c +++ b/drivers/mtd/spi/gk_sflash.c @@ -67,6 +67,9 @@ #define SR1_BP 0x7C /* GigaDevice/Winbond: BP0-4 */ #define SR1_BP_OTHER 0x3C /* BP0-3 */ +/* Longer than any erase or program of the parts on these boards */ +#define SF_TIMEOUT_MS 3000 + #define MFR_GIGADEVICE 0xc8 #define MFR_WINBOND 0xef #define MFR_XMC 0x20 @@ -84,19 +87,27 @@ static void sf_cmd(u8 op) readl(SF_DATA); } -static void sf_wait_ready(void) +static int sf_wait_ready(void) { - while (sf_reg_read(CMD_RDSR, 1) & SR1_WIP) - ; + ulong start = get_timer(0); + + while (sf_reg_read(CMD_RDSR, 1) & SR1_WIP) { + if (get_timer(start) > SF_TIMEOUT_MS) { + printf("SF: timed out waiting for the flash\n"); + return -ETIMEDOUT; + } + WATCHDOG_RESET(); + } + return 0; } -static void sf_write_sr(u32 val, unsigned int nbytes) +static int sf_write_sr(u32 val, unsigned int nbytes) { sf_cmd(CMD_WREN); writel(CMD_WRSR | SF_SEND_CMD | SF_RWN_WRITE | SF_BYTES(nbytes), SF_COMMAND); writel(val, SF_DATA); - sf_wait_ready(); + return sf_wait_ready(); } /* Clear the block protection a vendor loader may have left set */ @@ -121,17 +132,17 @@ static void sf_unprotect(u32 jedec) } } -static void sf_erase_sector(u32 addr) +static int sf_erase_sector(u32 addr) { sf_cmd(CMD_WREN); writel(CMD_SE_64K | SF_SEND_CMD | SF_ADDR3 | SF_RWN_NOTHING, SF_COMMAND); writel(addr, SF_DATA); - sf_wait_ready(); + return sf_wait_ready(); } /* Whole words, within one page */ -static void sf_program(u32 addr, const u8 *buf, unsigned int words) +static int sf_program(u32 addr, const u8 *buf, unsigned int words) { sf_cmd(CMD_WREN); writel(CMD_PP | SF_SEND_CMD | SF_ADDR3 | SF_RWN_WRITE | SF_BYTES_4, @@ -141,7 +152,7 @@ static void sf_program(u32 addr, const u8 *buf, unsigned int words) writel(get_unaligned_le32(buf), SF_DATA); buf += 4; } - sf_wait_ready(); + return sf_wait_ready(); } static int gk_sf_read(struct mtd_info *mtd, loff_t from, size_t len, @@ -188,10 +199,11 @@ static int gk_sf_write(struct mtd_info *mtd, loff_t to, size_t len, u8 page[SZ_PAGE]; u32 addr = to & ~3; unsigned int head = to & 3; + int ret; if (to + len > mtd->size) return -EINVAL; - *retlen = len; + *retlen = 0; while (len) { unsigned int room = SZ_PAGE - (addr & (SZ_PAGE - 1)); unsigned int n = min_t(size_t, len, room - head); @@ -199,12 +211,14 @@ static int gk_sf_write(struct mtd_info *mtd, loff_t to, size_t len, memset(page, 0xff, span); memcpy(page + head, buf, n); - sf_program(addr, page, span / 4); + ret = sf_program(addr, page, span / 4); + if (ret) + return ret; addr += span; buf += n; len -= n; + *retlen += n; head = 0; - WATCHDOG_RESET(); } return 0; } @@ -213,12 +227,16 @@ static int gk_sf_erase(struct mtd_info *mtd, struct erase_info *instr) { u32 addr = instr->addr; u32 end = instr->addr + instr->len; + int ret; if (addr % SZ_SECTOR || instr->len % SZ_SECTOR || end > mtd->size) return -EINVAL; for (; addr < end; addr += SZ_SECTOR) { - sf_erase_sector(addr); - WATCHDOG_RESET(); + ret = sf_erase_sector(addr); + if (ret) { + instr->fail_addr = addr; + return ret; + } } return 0; } From 691a37e9bd0639c544d28b0101498d7ac2dd46d6 Mon Sep 17 00:00:00 2001 From: Dimasik Date: Sun, 18 Oct 2026 12:38:46 +0000 Subject: [PATCH 10/10] gk710x: read osmem and bsbsize the way the kernel reads mem= The U2K memory words were parsed as decimal MiB, ignoring any suffix. The same osmem string goes to the kernel as mem=, which takes bytes, hex and K/M/G. So mem=0x2400000 left a 0 in the word, and 36864K became 36864 MiB, and the kernel placed its BSB and DSP memory from a size that disagreed with its own. Parse both with ustrtoul(), as bytes. The defaults ("36M", "2M") give the same words as before: under qemu-hisilicon the gk7102 and gk7101 kernels still place BSB/DSP at 0xc2600000/0xc2800000 and 0xc3400000/0xc3800000. Reported by Qodo on #22. --- arch/arm/mach-gk710x/kernel.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-gk710x/kernel.c b/arch/arm/mach-gk710x/kernel.c index 0172e17c4034..fc640664ffa4 100644 --- a/arch/arm/mach-gk710x/kernel.c +++ b/arch/arm/mach-gk710x/kernel.c @@ -23,12 +23,13 @@ DECLARE_GLOBAL_DATA_PTR; -/* "36M" -> 36: the environment spells these sizes in MiB */ -static ulong env_mib(const char *name, const char *def) +/* A size as the kernel's mem= reads it: bytes, 0x for hex, K/M/G suffix */ +static ulong env_size(const char *name, const char *def) { const char *s = env_get(name); + char *end; - return simple_strtoul(s ? s : def, NULL, 10); + return ustrtoul(s ? s : def, &end, 0); } void board_prep_linux(bootm_headers_t *images) @@ -41,8 +42,8 @@ void board_prep_linux(bootm_headers_t *images) writel(GK_ARM_FREQ, GK_U2K_ARM_FREQ); writel(GK_HAL_ADDR, GK_U2K_HAL_ADDR); writel(0, GK_U2K_SOC); - writel(env_mib("osmem", OPENIPC_OSMEM) * SZ_1M, GK_U2K_MEM); - writel(env_mib("bsbsize", __stringify(GK_BSB_MIB)) * SZ_1M, GK_U2K_BSB); + writel(env_size("osmem", OPENIPC_OSMEM), GK_U2K_MEM); + writel(env_size("bsbsize", __stringify(GK_BSB_MIB) "M"), GK_U2K_BSB); writel(GK_U2K_MAGIC, GK_U2K_ENABLE); writel(0, GK_U2K_USR); writel(gd->ram_size / SZ_1M, GK_U2K_TOTAL_MEM);