diff --git a/CLAUDE.md b/CLAUDE.md index 43c0621b4c06..2fd87a9e0a70 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,17 +5,37 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this branch is `openipc-sigmastar` is OpenIPC's U-Boot for SigmaStar's (MStar's) -Cortex-A7 camera SoCs of the infinity3 die: the MSC313E, MSC316DC and -MSC316DM. The tree is **mainline U-Boot v2022.10**, the same release as -`openipc-hisilicon`, `openipc-xm`, `openipc-gk710x` and `openipc-anyka`, -plus: +Cortex-A7 camera SoCs. The tree is **mainline U-Boot v2022.10**, the same +release as `openipc-hisilicon`, `openipc-xm`, `openipc-gk710x` and +`openipc-anyka`, plus: - the OpenIPC boot layer, carried over from `openipc-anyka`, which took it from `openipc-xm` and `openipc-hisilicon`; -- the infinity3 support, written from the vendor SDK - `MSC3XX_SDK_V_1711291828-I3` (U-Boot 2015.01 - `arch/arm/cpu/armv7/infinity3` and `drivers/mstar`, kernel 3.18.30 - `drivers/mstar`). +- the SigmaStar support, written from the vendor SDKs: U-Boot 2015.01 + `arch/arm/cpu/armv7/` and `drivers/mstar`, and the kernels' + `drivers/mstar`. + +| Die | SoCs | Boot stages from | Status | +| --- | --- | --- | --- | +| infinity3 | `msc313e` `msc316dc` `msc316dm` | SDK `MSC3XX_SDK_V_1711291828-I3` | qemu, see "Verification" | +| infinity2m | `ssd201` `ssd202d` | SDK `i2m` `project/board/i2m/boot/ipl` | qemu, IPL to kernel | +| infinity6 | `ssc325` | OpenIPC/u-boot-sigmastar `ipl/` | **no silicon**; qemu per-die machine | +| infinity6b0 | `ssc333` `ssc335` `ssc335de` `ssc337` `ssc337de` | same | **no silicon**; qemu per-die machine | +| infinity6e | `ssc30kd` `ssc30kq` `ssc338q` | same | **no silicon**; qemu per-die machine | +| infinity6c | `ssc377` `ssc377d` `ssc377de` `ssc377qe` `ssc378de` `ssc378qe` | same | **no silicon**; qemu per-die machine | +| infinity2m | `ssr621q` | SDK `i2m` | **no silicon**; qemu `ssr621q` | +| infinity6 | `ssc325de` `ssc327de` | as `ssc325` | **no silicon**; qemu per-part machine | +| Iford | `ssc029a` `ssc029b` `ssc029c` | Iford SDK IMD00V2.1.0 boot.bin, `board/iford/boot/nor/ipl` | **no silicon**; only `ssc029c` boots in qemu | +| Ifado | `ssc375` | Dahua IPC-HDW1433V-A-IL2 NOR (IPL, CIS, IPL_CUST) | **no silicon**; qemu `ssc375`, to the vendor kernel's userspace | +| Ifliegen | `ssc034a` `ssc034b`, NOR and SPI NAND | Ifliegen SDK ILSSV01C12 `board/ifliegen/boot` (IPL, IPL_CUST, TF-A `u-bl32.bin`, flash.nri/flash.sni, flash lists) | **no silicon**; qemu `ssc034a`/`ssc034b`, to the SDK kernel's shell | +| SPI NAND | `-nand` for every infinity2m, 6, 6b0, 6e, 6c part | published images, i2m and Maruko SDKs | **no silicon**; qemu | + +OpenIPC/u-boot-sigmastar, the vendor's U-Boot 2015.01 with OpenIPC's +environment, is what OpenIPC ships for the infinity6 dies today, and it +publishes `u-boot-ssc*-nor.bin` to OpenIPC/firmware `latest`. This branch's +images go only to the CI repository's own `sigmastar` release: the publish +job of `build-sigmastar.yml` on `openipc` is commented out for now (and its +`PUBLISH_GLOB` kept to `u-boot-msc31*` for when it returns). No vendor driver comes along. The vendor's first boot stages, IPL and IPL_CUST, are carried as binaries (see "Boot"). @@ -34,8 +54,9 @@ Adding or dropping a SoC needs both branches: `TARGET_*` in `arch/arm/mach-sigmastar/Kconfig`; - there: `build-sigmastar.yml`'s matrices and the README. -The later SigmaStar dies (infinity2m, infinity6/6b0/6e: SSD20x, SSC33x) -have another boot chain and are not covered. +Not covered: the dies with no OpenIPC use or no IPL in the SDKs at hand +(infinity5, infinity7, pioneer3, mercury6, souffle); Iford's 029b/029c SPI +NAND (only RTOS/dual-OS sets in the SDK); Mercury6 (no IPL at hand). ## Relationship to mainline @@ -48,15 +69,15 @@ git diff --diff-filter=M v2022.10 HEAD # the mainline files we patched | Area | Location | | --- | --- | -| SoC: timer, reset, DRAM size, MIU flush | `arch/arm/mach-sigmastar/` (`ARCH_SIGMASTAR`; `TARGET_MSC313E/MSC316DC/MSC316DM`, `SS_INFINITY3`; register map in `include/mach/sigmastar.h`) | -| Board: `misc_init_r` → `openipc_helper()`, `board_eth_init`, `board_mmc_init` | `board/sigmastar/infinity3/` | +| SoC: timer, reset, DRAM size, MIU flush, `memlx`/`memsz` | `arch/arm/mach-sigmastar/` (`ARCH_SIGMASTAR`; `TARGET_` selecting `SS_`; register map in `include/mach/sigmastar.h`) | +| Board: `misc_init_r` → `openipc_helper()`, `board_eth_init`, `board_mmc_init` | `board/sigmastar/ipc/` | | SPI NOR on the FSP, non-DM | `drivers/mtd/spi/ms_sflash.c` (`MS_SFLASH`). It provides `spi_flash_probe()` and fills `mtd->_read/_write/_erase`, as `ak_sflash` does on `openipc-anyka` | | Ethernet, non-DM | `drivers/net/ms_emac.c` (`MS_EMAC`) | | SD card on SDIO0, non-DM | `drivers/mmc/ms_sdmmc.c` (`MMC_MS_SDMMC`), registered from `board_mmc_init()` | | xz decompression | `lib/xz/` (xz-embedded, 0BSD, with CRC64; `XZ`), `include/linux/xz.h`, `unxz()` in `include/unxz.h` | | Memory map, console, timer | `include/configs/sigmastar.h`, ending in `#include "openipc-common.h"` | | OpenIPC boot layer | `common/openipc.c`, `include/openipc.h` (as on `openipc-anyka`), `include/configs/openipc-common.h` (SigmaStar rewrite, NOR only, same env commands) | -| Kconfig fragments, vendor boot stages, the image packer, the build | `openipc/`, `build.sh` | +| Kconfig fragments, vendor boot stages, the image packers (`infinity3-image.py`, `sigmastar-image.py`), the build | `openipc/`, `build.sh` | **Patched mainline files**, each small: @@ -77,7 +98,9 @@ The console is mainline `ns16550`, non-DM. ## Boot -The vendor boot chain is kept; only the MXP partition `UBOOT` is ours. +The vendor boot chain is kept on every die; only the partition `UBOOT` is +ours. What follows up to "Hand-off" is infinity3; "Later dies" says what +differs. - The mask ROM looks for the IPL at flash offset `0x4000` (the first 16 KiB are zeros on every image seen). The **IPL** trains and sizes the @@ -111,8 +134,208 @@ The vendor boot chain is kept; only the MXP partition `UBOOT` is ours. - **DRAM size**: probed up to the part's (`PHYS_SDRAM_1_SIZE`: 64 MiB on the MSC313E, 128 MiB on the MSC316s); the DDR wraps past its end. +### Later dies (infinity2m, infinity6*) + +`openipc/sigmastar-image.py` packs the same 256 KiB boot partition as +OpenIPC/u-boot-sigmastar's `make_boot_spinor.sh`, with the same bytes for +everything but the uImage: IPL at `0`, `openipc/sigmastar-mxp.bin` at `0xF000` +(infinity6c: `infinity6c-gcis.bin`, a table of flash parts, at `0x9000`), +IPL_CUST at `0x10000`, the uImage at `0x20000`. + +- All parts of a die run the same IPL and IPL_CUST: the images in OpenIPC/firmware + `latest` are byte-identical in that area, part to part. +- The MXP table is the one blob for all of them, and also serves infinity2m, + whose SDK has no such layout (it has MXP at `0x20000`, U-Boot at `0x30000`, + environment at `0x5D000`, which collide with OpenIPC's). Its entries for IPL + (`0x4000`) and MXPT (`0x3000`) do not say where those are in this layout; + infinity2m's stages boot from it regardless under qemu. +- The uImage: `xz -z` data (preset 6, an 8 MiB dictionary, CRC64), not the + preset 9e of infinity3, and a 32-byte `MVX4##...#CM_UBT1501#XVM` name, as + `create_img.sh` gives it. + +### SPI NAND + +`./build.sh -nand` adds `openipc/nand_config` and gives +`output/u-boot--nand.bin`, the 2 MiB of `make_boot_spinand.sh`: SNI at `0`, +PNI at `0x800`, IPL at `0x40000` and `0x80000`, IPL_CUST at `0xC0000` and +`0x100000`, the same uImage at `0x140000` and `0x1A0000`. The stages are the NOR +images' own: the published NAND images hold the same bytes, and +`openipc/-nand-{sni,pni}.bin` are the vendor's `GCIS.bin`, `PARTINFO.pni`. + +- Environment at `0x200000`, 128 KiB, in a 256 KiB range, as a saved one sits. +- UBI after it, as the firmware's `rootfs.ubi` lays it out: volumes `kernel`, + `rootfs` (a squashfs, not UBIFS), `rootfs_data`, `other`. + `CONFIG_OPENIPC_NAND_KERNEL_VOLUME` makes `common/openipc.c` check and + recover those, and not `/boot/fitImage` as on HiSilicon. +- `ms_spinand` takes geometry from the SNI, since the published images carry one + generic SNI whose ID is `0xEE`. The bad-block table stays in memory, like the + vendor's: nothing is written to the last blocks, which UBI owns. +- A page load holds the chip select by QSPI's burst bit, and OUT_SIZE counts one + more than BDMA sends. Whole page and spare go by BDMA; the vendor sends those + through the FSP, so a spare write takes a path it never does. +- No infinity6c or infinity2m NAND is published to compare against. Run + instead (qemu): `ssc377-nand` with mstar-06's Maruko kernel, the UBI + written by `run ur` over TFTP (`nand erase`/`write` through infinity6c's + software chip select), booted to `login:` with the `ubiblock` override; + `ssd202d-nand` with the i2m SDK kernel from a UBI, its UBIFS root mounted. + A part whose SNI gives a spare other than 64 or 128 bytes is refused: the + core has no layout for it. +- `root=` follows the partition count (`OPENIPC_NAND_ROOTDEV`): the published + kernels have gluebi, which makes each UBI volume an MTD after the partitions, + `kernel` then `rootfs`. So `mtdblock5` behind the default four partitions, + `mtdblock6` on infinity6c and Iford (five), `mtdblock4` on infinity2m (three). + A kernel without gluebi (Maruko's, the i2m and Iford SDKs') takes + `extras='ubi.block=0,rootfs root=/dev/ubiblock0_1 rootfstype=squashfs'` + (the later `root=` wins), or `root=ubi0:rootfs rootfstype=ubifs` for a + UBIFS rootfs. + +### Iford + +`openipc/sigmastar-image.py --iford-cis`: the SDK's NOR boot.bin as it is, IPL at +`0`, the CIS area (flash.nri, PNI, flash list) at `0xE000`, IPL_CUST at +`0x18000`, our UBOOT at `0x1F000`, the environment at `0x40000`. Its IPL_CUST +takes the xz uImage like the older dies, but by the header's load address, +`0x23E00000`. Iford shares infinity6c's paths (`SS_I6C_FAMILY`): the chip select +in software, the PHY at bank `0x1518`; its FSP is at `0x100D`/`0x100E`, BDMA from +MIU reads channel 1 (path `0x2B41`), SD has its own pads (vendor +`mmc_host/src/iford`, SD0 defaults) and the SD clock's SCGP is bank `0x1135`. +The DDR size is bank `0x1659` reg `0x0D`, log2 MiB, which the IPL finds by +fill-and-wrap test; `dram_init()` still probes if it reads outside 64 MiB-2 GiB +(the kernel's decode takes [7:4] as a second term). `memlx`/`memsz` are the SDK +images' own (`set_config`) for 128, 256 and 512 MiB. No kernel hand-off was tried: its 5.10 kernel takes a DTB. +Under qemu `ssc029` (029b at `bond=0x10`, its IPL refuses other bonds; which a +real part carries is unknown): all three through their own IPL chain, `sf`, env +across reset, ping, TFTP, SD card detect, FAT load and raw read-back. 029a's IPL +logs a DQ training failure the model does not train for. + +### Ifado + +`ssc375` (Ifado, SSC032B, QFN88 DDR3). No SDK: the stages are Dahua's, from +an IPC-HDW1433V-A-IL2 NOR (`openipc/ifado-*.bin`, the flash's `0-0x8000`, +`0x8000-0x10000` and `0x10000-0x15000`, trailing `0xFF` cut). `--ifado-cis`: +IPL at `0`, the CIS area (NRI records, PNI at `0x9000`, NRIB) at `0x8000`, +IPL_CUST at `0x10000`, our xz uImage in the PNI's UBOOT at `0x20000` +(`0x23E00000`), the environment at `0x40000`, where Dahua's 8 KiB one was. +The Dahua `sbot` wrapper is not needed: IPL_CUST checks its magic only on a +path the shipped image does not take. The die is the infinity2m map +(`SS_IFADO`: DDR probed up to 128 MiB, PHY at bank `0x31`, SD at `0x1413`, +EMAC and FSP where infinity2m has them) with infinity6c's software chip +select (`SS_FSP_SW_CS`). No SD: the camera has no slot and the pads are +unread. Its IPL_CUST jumps with the MMU and D-cache on, page table at +`0x20004000`, where the kernel builds its own; `lowlevel_init.S` +`save_boot_params` cleans the cache and turns both off (a branch on the +other dies, whose loaders leave SCTLR.M clear; checked on each machine). +qemu `ssc375`: chain, `sf` unaligned write/read, raw file, env across +reset, `memlx` for 128 MiB, ping, TFTP CRC; Dahua's 4.9.84 kernel by +`bootm` with its built-in DTB passed, through the squashfs mount to Dahua's +userspace (which reboots without DHBoot's partitions). The Dahua dump is +for tests and reverse engineering only: U-Boot is not changed to run +Dahua's firmware, and on a flash still holding it the layout scan may take +Dahua's backup U-Boot at `0xC0000` for a kernel; that stays as it is. + +### Ifliegen + +`ssc034a` (QFN128, 128 MiB DDR3) and `ssc034b` (QFN88, 64 MiB), Cortex-A55 +in AArch32. The SDK ships no images; `--ifliegen-tfa`/`-nri`/`-list` build +what its image.mk would, at offsets both packages' IPLs fit: IPL at `0`, the +CIS at `0xC000` (flash.nri, the PNI at `+0x1000`, the flash list with +nrigenerator's CRC32 at `+0x2000`), IPL_CUST at `0x16000`, TF-A's SP_MIN at +`0x1D000`, our xz uImage at `0x24000` (`0x23E00000`), the environment at +`0x40000`. The IPL runs TF-A, TF-A runs IPL_CUST, IPL_CUST U-Boot, in the +normal world. The die is Iford's in the SDK (`SS_IFORD_FAMILY`: FSP at +`0x100D`, BDMA from MIU by channel 1, no MIU pipe to flush, EMAC MCG off; +not Iford's MCM write at bank `0x1132`), with: + +- UART0 left in the URDMA's DMA mode, the IPL's bytes going through its TX + FIFO (bank `0x1107` reg `0x17`): `board_early_init_f()` waits for the FIFO, + stops both DMAs and leaves DMA mode, as the SDK's `hal_uart_config()`, and + clears PM sleep reg 9 bit 11 (RX off); the 8250 then serves the console. +- SP_MIN stays at `0x23FE0000` as the kernel's PSCI: U-Boot keeps to the first + 48 MiB, as the SDK's (`CONFIG_SGS_RAM_SIZE`), or the kernel hangs at its + first PSCI call. DDR is probed (no size register known), up to 128 MiB. +- `memlx`/`memsz`: the SDK's set_config, `0x7FE0000`/`0x5000000` at 128 MiB, + `0x3FE0000`/`0x2000000` at 64 MiB. Machine 5120 (MACH_TYPE_IFACKEL, its + U-Boot's); the 4.9 kernel turns the ATAGs into its built-in DT. +- SD: SD0, the board's mmc0 (`mmc_host/src/ifliegen`): PADGPIO pads from + `0x0F`, card detect at `0x16`, power on PAD_FUART_RTS (`0x34`), the clock + as Iford's but SC_GP_CTRL at bank `0x1133`, the host's MCG off. +- SPI NAND (`ssc034a-nand`, `ssc034b-nand`): `--ifliegen-sni` builds the CIS + in ten blocks (SNIB and SNIF, the PNI, the flash list, with snigenerator's + boot blocks 10 and 25 and CRCs), BOOT at `0x140000` (IPL and IPL_CUST three + blocks each, SP_MIN, a 1 MiB UBOOT), BOOT_BAK at `0x320000`, the + environment at `0x500000`, UBI from `0x540000`. The IPL takes its + timeouts from the SNIF: the CIS carries the flash list's W25N01GV, record + 57; the SDK's generic record has none and the IPL fails to load. + +The SGS kernels (Iford, Ifliegen, Ifado: `drivers/sgs_common/flash/nor`) name +the NOR `nor0`, not the older `NOR_FLASH`: `SFC` in +`openipc-common.h`. qemu `ssc034a`/`ssc034b`: the chain, `sf` unaligned +write/read and the raw file, env across reset, ping, TFTP CRC, the SDK's +4.9.84 kernel (mstar-06's build) from OpenIPC's NOR layout, both CPUs by +PSCI, the six partitions, squashfs root to a shell (`extras=init=/linuxrc` +for its rootfs). SD (mstar-06's model): detect, 4-bit, FAT load CRC, raw +write and read-back. NAND: the chain, `nand` erase/write/read against the +raw file, env across reset, the SDK kernel from an OpenIPC UBI to a shell +with the `ubiblock` override. + +### Iford SPI NAND + +`ssc029a-nand` only: the one SDK spinand set for a part with plain Linux +(`ipc_iford.spinand...ssc029a.512.bga12_ddr4_optee`). Its `cis.bin` in the ten +CIS blocks (SNIB header, page 0; the SNIF of `flash_list-fb.sni` record 1, +W25N01JW, in place of the empty generic one; PNI, page 1), its IPL, IPL_CUST +and OP-TEE from `0x140000`, our uImage in UBOOT at `0x260000`, the environment at +`0x580000`. U-Boot runs after OP-TEE. `ms_spinand` reads the SNIB's geometry and +turns a W25N's buffer mode back on, which this IPL leaves off. qemu `ssc029a`: +the chain, `nand` erase/write/read against the raw file, env across reset. +Its `mtdparts` are `1280k(cis),2176k(boot0),2176k(boot1),256k(env),-(ubi)`: +each boot copy is IPL, IPL_CUST, OP-TEE (`0x60000` each) and UBOOT +(`0x100000`), so `env` lands at `0x580000` and `ubi` at `0x5C0000`, where +U-Boot keeps them. The SDK's 5.10 kernel, from a UBI of its `kernel` and +`rootfs.sqfs`, lists those five partitions and, without gluebi, mounts the +squashfs through the `ubiblock` override (qemu `ssc029a`). +029b and 029c have only RTOS/dual-OS NAND sets in the SDK; not built. + +### SPI NAND on infinity2m and infinity6c + +Nothing is published, so the layouts are the SDKs': infinity2m by its PNI +(stages repeated over their blocks, `writecis ... 10 0 0 5`: part record 2 in +blocks 0-8); infinity6c by Maruko's `spinand.squashfs` config, the SNI from its +flash list (record 1, GD5F1GQ4UEYIH) in all ten CIS blocks. A board with another +part needs its own record in page 0, as the SDK's `nand probe` writes it. + ## Hand-off to the kernel +On the later dies: + +- ATAGs at `0x20000000`, machine number per die (`openipc/_config`: + infinity6c passes MERCURY6, 1399, as its vendor U-Boot does). +- No `mem=`. `LX_MEM=${memlx} mma_heap=...,sz=${memsz} cma=2M`, the arguments + of OpenIPC/u-boot-sigmastar, whose saved environments have to keep working. + `ss_set_mem_env()` sets `memlx` and `memsz` at every boot, before the + environment is used, from its table of those values by DDR size. infinity2m has + no such table upstream; its row uses infinity6c's, since its kernel warns + about an LX_MEM that is not 1 MiB aligned. +- `CONFIG_ENV_OFFSET`/`SIZE` are those of OpenIPC/u-boot-sigmastar, so a + saved environment loads as it is. Its `bootcmd` and `bootargs` are kept. +- **Flash on infinity6c:** its IPL leaves the chip select in software, held + high (QSPI bank `0x17` reg `0x0a` = 3), and the vendor's driver frames each + flash command by hand. `ms_sflash` does the same and leaves that state to the + kernel. It reads by BDMA, or the FSP when short or unaligned, not by XIU; + OUT_SIZE is the count plus one. The published U-Boot runs + `flash/nor/drvSPINOR.c` + `fsp_qspi`: `flash_isp/infinity6c` is not its code. +- **DDR size:** on infinity6, 6b0 and 6e `1 << (MIU 0x1012 reg 0x69 >> 12)` MiB, + on infinity6c `1 << (bank 0x1659 reg 0x0D)` MiB, since its IPL writes a fixed + `0x6000` to reg 0x69. The IPL sets both; each is what that die's vendor + `dram_init()` reads. infinity2m has no such register + in its vendor code and probes as infinity3 does. +- **U-Boot stays in the first 64 MiB** (`board_get_usable_ram_top()`), like the + vendor's `CONFIG_UBOOT_RAM_SIZE`. BDMA's address registers are wider than the + 12-bit mask in the IPLs: the vendor kernel's reach MIU `0x30000000`, on the + qemu machines 31 bits. + +On infinity3: + - The vendor kernels (3.18.30) take ATAGs at `0x20000100` and turn them into their built-in DTB (`early_atags_to_fdt`); machine number 1391 (`INFINITY3`), as the vendor U-Boot passes. @@ -133,6 +356,26 @@ The vendor boot chain is kept; only the MXP partition `UBOOT` is ours. ## Peripherals +What differs by die is in `include/mach/sigmastar.h`, or under `CONFIG_SS_` +in the driver: + +| | infinity3 | infinity2m | infinity6, 6b0 | infinity6e | infinity6c | +| --- | --- | --- | --- | --- | --- | +| FSP bank | `0x16` | `0x16` | `0x16` | `0x16` on QFN88, else `0x100D` (CHIPTOP `0x48`) | `0x16` | +| BDMA reg 3 | untouched | 0 | `0x8000` | `0x8000` | `0x8000` | +| PHY banks | `0x31`- | `0x31`- | `0x31`- | `0x1514`- | `0x1518`- | +| EMAC clocks (SCGPCTRL) | `0x44`, `0x46` | same | same | same | `0x54`, `0x56` | +| PHY sadc timer | written | RMW | RMW | RMW, and LMS scale | RMW | +| SD host bank | `0x1410` | `0x1410` | `0x1413` | `0x1413` | `0x1413` | +| SD clock (CLKGEN) | `0x45` | `0x45` | `0x43` | `0x43` | `0x43` | +| SD `DDR_MOD` | 0 (bypass) | `0x6400` | `0x6400` | `0x6400` | `0x2400` | +| SD mode | CHIPTOP `0x08` | CHIPTOP | CHIPTOP | PADTOP `0x67`, `0x68` | PADTOP `0x67`, `0x68` | +| SD pads | PADTOP `0x50`- | same | same | PADTOP `0x12`- | PADGPIO `0x00`- | +| SD power | PADTOP `0x17` | PADTOP `0x20` | PADTOP `0x17` | PADTOP `0x25` and `0x10` | PADGPIO `0x22` | +| SD card detect | PM GPIO `0x47` | same | same | PADTOP `0x11` | PADGPIO `0x06` | + +The rest of this section is infinity3's, which the table adjusts. + Everything is on the RIU, 16-bit registers: bank B at `0x1F000000 + B * 0x200`, register R at `+ R * 4`. The vendor sources name a register by its byte address `0xBBBB00 + R * 2`. @@ -195,14 +438,14 @@ a register by its byte address `0xBBBB00 + R * 2`. ## Build ```sh -bash build.sh # all three; continues past failures, exits non-zero if any failed +bash build.sh # all SoCs; continues past failures, exits non-zero if any failed bash build.sh msc313e # one or more SoCs (CROSS_COMPILE defaults to arm-linux-gnueabi-) ``` - The output is `output/u-boot--nor.bin`, the 256 KiB boot partition, 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. +- `.config` is `openipc/openipc_config`, then `openipc/_config` on the + later dies, then `openipc/_config`, then `olddefconfig`. There are no `configs/*_defconfig` for these targets. - Thumb-2 (`SYS_THUMB_BUILD`): `u-boot.bin` is about 180 KiB, 96 KiB in the uImage (SD, FAT, LZMA and xz included); the `UBOOT` partition holds 128 KiB. The image packer fails the build past that. @@ -213,8 +456,11 @@ bash build.sh msc313e # one or more SoCs (CROSS_COMPILE defaults to arm-li The emulator is OpenIPC/qemu-hisilicon, machine `msc313e` (`docs/sigmastar.md` there). `-M msc313e,flash-file=` does the mask ROM's job, so it boots exactly the flashed bytes, IPL and IPL_CUST -included. There is no MSC316 machine; the MSC316 images boot on `msc313e` -(their IPL sizes its 64 MiB), which checks everything but the DDR set-up. +included. qemu-hisilicon master has no MSC316 machine. On `msc313e` the MSC316 +IPL takes the efuse path that skips DDR set-up altogether. Branch +`sigmastar-i6-dies` adds `msc316dc` and `msc316dm`, where the IPL programs the +DDR PHY and MIU (`D-02.`); qemu trains nothing, so that runs the IPL's tables +without proving them. - **CI smoke:** two boots of an 8 MiB image holding only U-Boot. The second must load the environment the first saved. @@ -248,9 +494,64 @@ included. There is no MSC316 machine; the MSC316 images boot on `msc313e` real timing, the SD pads and card power, whether the bootcount word in DDR survives the IPL after a real reset. +### The later dies + +Run under qemu-hisilicon master plus its Iford machine (`ssc029`, not yet +upstream at the time). **Nothing here has run on silicon.** + +- `ssd201`, `ssd202d`: the image boots through the real IPL and IPL_CUST, also + with the MXP table above. `saveenv` + `reset`; TFTP of 300000 bytes with the + right CRC; `ping`; `mii read`; an unaligned `sf write` of 300000 bytes + `sf + read` + `cmp.b`. The SDK's 4.9.84 kernel by `bootm`: ATAGs, LX_MEM and + mma_heap taken, two CPUs, up to the missing root file system. +- `ssc337` U-Boot under the infinity2m stages on `ssd202d`: DDR size from the + MIU, `memlx`, `sf`, `ping`, TFTP. A flash holding the environment of + OpenIPC/u-boot-sigmastar (stale `memlx` and `memsz` included): it loads, the + values are refreshed, the saved `bootcmd` boots the kernel. +- The infinity6* U-Boots loaded in DDR on `ssc029`, with the MIU size register + set by a stub (the IPL does not run): banner, DRAM, the 64 MiB top, `memlx` + and `memsz` for 6, 6b0, 6e and 6c; SD at bank `0x1413` for 6, 6b0 and 6e. + With its bond test inverted in a scratch copy, 6e's `sf` on the FSP at `0x100D` + erases and reads; an unaligned write came back one byte short per partial + page because `ssc029`'s FSP counts OUT_SIZE plus one. infinity6e does not: + its vendor `halSERFLASH.c` writes the plain length, and `ssc338q` below is + clean. +- SD with the `ssd201` U-Boot on the `msc313e` host: `mmc info`, write, read. +- On the per-die machines of qemu-hisilicon branch `sigmastar-i6-dies` (not + merged at the time), `ssc325`, `ssc337`, `ssc338q` and `ssc377`, each also + with the published vendor image as a control. Real IPL chain; `sf` erase, an + unaligned write of 74565 bytes, read back, `cmp.b`, the raw flash file + compared; `saveenv`, `reset`; ping and TFTP; SD; an OpenIPC kernel to `login:` + (not past it, so no shell-side checks); a saved vendor environment upgraded. + `memlx` and `memsz` per RAM size match the vendor's on 6 and 6b0 (64-256), + 6e (128-1024) and 6c (64-256). At 512 MiB the vendor's infinity6c falls + back to its 64 MiB values; this takes the largest row under the size + (256 MiB), as for any size a table lacks. The other parts of these dies reach their + prompts, and `ssd201`/`ssd202d` pass SD at `0x1410`. +- SPI NAND, on the same branch: `ssc325de`, `ssc337de` and `ssc338q` boot the + published `rootfs.ubi` to `login:`, also after `saveenv` + `reset`; `ssc30kq`, + with no firmware published, to U-Boot. On `ssc337de`: `nand` erase, write and + read against the raw file; an environment the vendor's U-Boot saved; a factory + bad block and `markbad`, surviving a reboot, UBI seeing both; an injected + uncorrectable read (-74), a corrected one and a failed erase; TFTP recovery + from blank; SD recovery from a FAT card, also on NOR (`ssc337`). +- **Not run on any machine:** media (ISP, encoders); `ssc378*` kernels; 4 KiB page + NAND; the infinity2m card power pad as a real pad (PAD_TTL0, taken as already + GPIO). A `ssc338q` at bond 0 (QFN88) boots U-Boot, but both the vendor's and + this U-Boot then lose the kernel: see "Things to keep". From NAND at bond 0, + both images stop in the vendor's IPL (`init failed!`). + ## Things to keep -- `mem=` stays the first kernel argument, as on the other OpenIPC targets. +- infinity6e's bond: U-Boot follows the strap (FSP `0x16` at QFN88), but the + vendor kernel's `halSERFLASH.c` hard-codes `u8BoundID = 0x10` and always takes + FSP `0x100D`, so a QFN88 board panics at root mount under qemu. Reported by the + qemu work; the only package evidence is that vendor's configs list QFN88 as + FPGA-only (`SSC012A`), which needs a real board to settle. +- `mem=` stays the first kernel argument on infinity3, as on the other + OpenIPC targets. The later dies have none (see "Hand-off"). +- `u-boot-ssc*` must not reach OpenIPC/firmware `latest` from here before a + board has run them. - The boot counter is the DRAM word at `0x21F20000`, like the other families' DDR + 0x1f20000. A healthy boot does not clear it. Whether the IPL's BIST leaves it alone on silicon is not known. diff --git a/arch/arm/mach-sigmastar/Kconfig b/arch/arm/mach-sigmastar/Kconfig index af1920b69248..62d330383102 100644 --- a/arch/arm/mach-sigmastar/Kconfig +++ b/arch/arm/mach-sigmastar/Kconfig @@ -24,11 +24,227 @@ config TARGET_MSC316DM infinity3, QFN, 128 MiB of DDR in the package (the SDK's QFN128M board). +config TARGET_SSC325 + bool "SSC325" + select SS_INFINITY6 + help + infinity6. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC325DE + bool "SSC325DE" + select SS_INFINITY6 + help + infinity6, as the SSC325. OpenIPC ships it on SPI NAND. + +config TARGET_SSC327DE + bool "SSC327DE" + select SS_INFINITY6 + help + infinity6, as the SSC325. + +config TARGET_SSR621Q + bool "SSR621Q" + select SS_INFINITY2M + help + infinity2m with 256 MiB of DDR, on Xiongmai's NVRs. + +config TARGET_SSC375 + bool "SSC375" + select SS_IFADO + help + Ifado (SSC032B), QFN88 with 128 MiB of DDR3, in Dahua cameras. + The infinity2m map with infinity6c's FSP-QSPI. + +config TARGET_SSC029A + bool "SSC029A" + select SS_IFORD + help + Iford, BGA with 512 MiB of DDR4. + +config TARGET_SSC029B + bool "SSC029B" + select SS_IFORD + help + Iford, BGA with 256 MiB of DDR3. + +config TARGET_SSC029C + bool "SSC029C" + select SS_IFORD + help + Iford, QFN128 with 128 MiB of DDR3. + +config TARGET_SSC034A + bool "SSC034A" + select SS_IFLIEGEN + help + Ifliegen, QFN128 with 128 MiB of DDR3. + +config TARGET_SSC034B + bool "SSC034B" + select SS_IFLIEGEN + help + Ifliegen, QFN88 with 64 MiB of DDR3. + +config TARGET_SSC333 + bool "SSC333" + select SS_INFINITY6B0 + help + infinity6b0. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC335 + bool "SSC335" + select SS_INFINITY6B0 + help + infinity6b0. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC335DE + bool "SSC335DE" + select SS_INFINITY6B0 + help + infinity6b0. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC337 + bool "SSC337" + select SS_INFINITY6B0 + help + infinity6b0. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC337DE + bool "SSC337DE" + select SS_INFINITY6B0 + help + infinity6b0. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC30KD + bool "SSC30KD" + select SS_INFINITY6E + help + infinity6e. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC30KQ + bool "SSC30KQ" + select SS_INFINITY6E + help + infinity6e. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC338Q + bool "SSC338Q" + select SS_INFINITY6E + help + infinity6e. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC377 + bool "SSC377" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC377D + bool "SSC377D" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC377DE + bool "SSC377DE" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC377QE + bool "SSC377QE" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC378DE + bool "SSC378DE" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSC378QE + bool "SSC378QE" + select SS_INFINITY6C + help + infinity6c. The IPL sets up the DDR; dram_init() reads its size + from the MIU. + +config TARGET_SSD201 + bool "SSD201" + select SS_INFINITY2M + help + infinity2m, 64 MiB of DDR in the package. + +config TARGET_SSD202D + bool "SSD202D" + select SS_INFINITY2M + help + infinity2m, 128 MiB of DDR in the package. + endchoice config SS_INFINITY3 bool +config SS_INFINITY2M + bool + +config SS_INFINITY6 + bool + +config SS_INFINITY6B0 + bool + +config SS_INFINITY6E + bool + +config SS_INFINITY6C + bool + +config SS_IFORD + bool + +config SS_IFADO + bool + +config SS_IFLIEGEN + bool + +# Iford and Ifliegen: the FSP at 0x100D, BDMA from MIU by channel 1, no MIU +# write pipe to flush +config SS_IFORD_FAMILY + def_bool SS_IFORD || SS_IFLIEGEN + +# What infinity6c, Iford and Ifliegen share: the boot flash's chip select in +# software, the Ethernet PHY at bank 0x1518 (and, but on Ifliegen, the DDR +# size in bank 0x1659) +config SS_I6C_FAMILY + def_bool SS_INFINITY6C || SS_IFORD || SS_IFLIEGEN + +# The FSP-QSPI whose chip select the boot flash's driver holds in software +config SS_FSP_SW_CS + def_bool SS_I6C_FAMILY || SS_IFADO + +# The dies booted with OpenIPC's LX_MEM/mma_heap arguments, whose values +# depend on the DDR size +config SS_MMA_BOOTARGS + def_bool SS_INFINITY2M || SS_INFINITY6 || SS_INFINITY6B0 || SS_INFINITY6E || SS_I6C_FAMILY || SS_IFADO + config SYS_SOC default "sigmastar" @@ -36,7 +252,7 @@ config SYS_VENDOR default "sigmastar" config SYS_BOARD - default "infinity3" + default "ipc" config SYS_CONFIG_NAME default "sigmastar" diff --git a/arch/arm/mach-sigmastar/Makefile b/arch/arm/mach-sigmastar/Makefile index aa1026bf7d81..278699382862 100644 --- a/arch/arm/mach-sigmastar/Makefile +++ b/arch/arm/mach-sigmastar/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += soc.o +obj-y += lowlevel_init.o diff --git a/arch/arm/mach-sigmastar/include/mach/sigmastar.h b/arch/arm/mach-sigmastar/include/mach/sigmastar.h index c850c6c8e1fe..a8215cb9693c 100644 --- a/arch/arm/mach-sigmastar/include/mach/sigmastar.h +++ b/arch/arm/mach-sigmastar/include/mach/sigmastar.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * SigmaStar (MStar) infinity3: MSC313E, MSC316DC, MSC316DM. + * SigmaStar (MStar) camera SoCs: infinity3 (MSC313E, MSC316DC, MSC316DM), + * infinity2m (SSD201, SSD202D), infinity6 (SSC325), infinity6b0 (SSC333, + * SSC335, SSC337), infinity6e (SSC30K, SSC338Q) and infinity6c (SSC377, + * SSC378). They share the memory map and most of the register map; what + * differs is under the die's name below. * * Every peripheral sits on the RIU, a bus of 16-bit registers: bank B * (256 bytes of register space, 128 registers) at 0x1F000000 + B * 0x200, @@ -23,20 +27,40 @@ /* Banks */ #define SS_BANK_PMSLEEP 0x000E #define SS_BANK_PMGPIO 0x000F -#define SS_BANK_FSP 0x0016 +#define SS_BANK_FSP_PM 0x0016 +#define SS_BANK_FSP_NONPM 0x100D /* infinity6e, past QFN88 */ #define SS_BANK_PMTOP 0x001E #define SS_BANK_TIMER0 0x0030 /* the PIU timers, timer 0 at reg 0x10 */ -#define SS_BANK_ALBANY0 0x0031 /* the internal Ethernet PHY */ +/* The internal Ethernet PHY */ +#if defined(CONFIG_SS_I6C_FAMILY) +#define SS_BANK_ALBANY0 0x1518 +#define SS_BANK_ALBANY1 0x1519 +#define SS_BANK_ALBANY2 0x151A +#elif defined(CONFIG_SS_INFINITY6E) +#define SS_BANK_ALBANY0 0x1514 +#define SS_BANK_ALBANY1 0x1515 +#define SS_BANK_ALBANY2 0x1516 +#else +#define SS_BANK_ALBANY0 0x0031 #define SS_BANK_ALBANY1 0x0032 #define SS_BANK_ALBANY2 0x0033 +#endif #define SS_BANK_BDMA 0x1002 /* channel 0 */ #define SS_BANK_CHIPTOP 0x101E +#define SS_BANK_MIU 0x1012 #define SS_BANK_L3BRIDGE 0x1022 #define SS_BANK_CLKGEN0 0x1038 #define SS_BANK_PADTOP 0x103C #define SS_BANK_UART0 0x1108 #define SS_BANK_SCGPCTRL 0x1133 -#define SS_BANK_SDIO0 0x1410 /* the SD host (FCIE5) */ +#define SS_BANK_SCGPCTRL_SD 0x1135 /* Iford: the SD clock's own */ +#define SS_BANK_PADGPIO 0x103E /* infinity6c */ +/* The SD host (FCIE5) */ +#if defined(CONFIG_SS_INFINITY3) || defined(CONFIG_SS_INFINITY2M) +#define SS_BANK_SDIO0 0x1410 +#else +#define SS_BANK_SDIO0 0x1413 +#endif #define SS_BANK_EMAC0 0x1510 #define SS_BANK_EMAC1 0x1511 @@ -47,6 +71,21 @@ #define SS_PM_RESET SS_REG(SS_BANK_PMSLEEP, 0x2E) #define SS_PM_RESET_KEY 0x79 +/* infinity6e: the bond, which says which FSP the flash is on */ +#define SS_CHIP_BOND SS_REG(SS_BANK_CHIPTOP, 0x48) +#define SS_CHIP_BOND_MASK 0x30 +#define SS_CHIP_BOND_QFN88 0x00 + +/* + * The DDR's size as the IPL left it, log2 of MiB. infinity6c's IPL writes a + * fixed 0x6000 to MIU reg 0x69 and the size to bank 0x1659 reg 0x0D. + */ +#ifdef CONFIG_SS_I6C_FAMILY +#define SS_DDR_LOG2_MB readw(SS_REG(0x1659, 0x0d)) +#else +#define SS_DDR_LOG2_MB (readw(SS_REG(SS_BANK_MIU, 0x69)) >> 12) +#endif + /* PIU timer 0, 32 bits at the 12 MHz crystal rate */ #define SS_XTAL_HZ 12000000 #define SS_TIMER0_CTRL SS_REG(SS_BANK_TIMER0, 0x10) @@ -60,6 +99,23 @@ #define SS_UART0_BASE SS_BANK(SS_BANK_UART0) #define SS_UART_HZ 172800000 +/* + * Ifliegen: the IPL leaves UART0 in the URDMA's DMA mode, its console + * bytes going through the TX FIFO at reg 0x17; out of DMA mode UART0 is the + * 8250 again. PM sleep reg 9 bit 11 holds its RX off (the SDK's + * hal_uart_force_rx_disable() for digmux 0). + */ +#define SS_URDMA_CTRL SS_REG(0x1107, 0x00) +#define SS_URDMA_DMA_MODE BIT(1) +#define SS_URDMA_TX_DMA_EN BIT(2) +#define SS_URDMA_RX_DMA_EN BIT(3) +#define SS_URDMA_TX_BUSY BIT(12) +#define SS_URDMA_RX_BUSY BIT(13) +#define SS_URDMA_TXFIFO_STS SS_REG(0x1107, 0x1C) +#define SS_URDMA_TXFIFO_EMPTY BIT(0) +#define SS_UART0_RX_OFF SS_REG(SS_BANK_PMSLEEP, 0x09) +#define SS_UART0_RX_OFF_BIT BIT(11) + /* L3 bridge: flushes the MIU write pipe, so DMA sees what the CPU wrote */ #define SS_L3_FLUSH SS_REG(SS_BANK_L3BRIDGE, 0x05) #define SS_L3_FLUSH_STATUS SS_REG(SS_BANK_L3BRIDGE, 0x10) @@ -68,8 +124,17 @@ /* DMA engines take MIU addresses: DDR from 0 */ #define SS_MIU_ADDR(p) ((unsigned long)(p) - SS_DDR_BASE) +/* ATAGs, where each vendor U-Boot leaves them */ +#ifdef CONFIG_SS_INFINITY3 +#define SS_BOOT_PARAMS (SS_DDR_BASE + 0x100) +#else +#define SS_BOOT_PARAMS SS_DDR_BASE +#endif + #ifndef __ASSEMBLY__ void ss_miu_flush(void); +unsigned int ss_fsp_bank(void); +void ss_set_mem_env(void); int ms_sdmmc_initialize(void); #endif diff --git a/arch/arm/mach-sigmastar/lowlevel_init.S b/arch/arm/mach-sigmastar/lowlevel_init.S new file mode 100644 index 000000000000..270ce16a34e5 --- /dev/null +++ b/arch/arm/mach-sigmastar/lowlevel_init.S @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * U-Boot is started by the vendor's IPL_CUST, and skips the CP15 setup + * (SKIP_LOWLEVEL_INIT). Ifado's IPL_CUST jumps with the MMU and the data + * cache still on, its page table at 0x20004000, where the kernel later + * builds its own: clean the data cache and turn both off before anything + * runs, as cpu_init_cp15 would. Where the MMU is already off this is a + * branch. + */ +#include + +ENTRY(save_boot_params) + mrc p15, 0, r0, c1, c0, 0 @ SCTLR + tst r0, #(1 << 0) @ M + beq 1f + push {r1-r12, lr} @ IPL_CUST's stack + bl v7_flush_dcache_all + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #(1 << 2) @ C + bic r0, r0, #(1 << 0) @ M + mcr p15, 0, r0, c1, c0, 0 + isb + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ TLBIALL + mcr p15, 0, r0, c7, c5, 0 @ ICIALLU + mcr p15, 0, r0, c7, c5, 6 @ BPIALL + dsb + isb + pop {r1-r12, lr} +1: b save_boot_params_ret +ENDPROC(save_boot_params) diff --git a/arch/arm/mach-sigmastar/soc.c b/arch/arm/mach-sigmastar/soc.c index 555f6a4537eb..512719147b89 100644 --- a/arch/arm/mach-sigmastar/soc.c +++ b/arch/arm/mach-sigmastar/soc.c @@ -1,15 +1,17 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SigmaStar infinity3: timer, reset, DRAM size, MIU pipe flush. - * After the vendor U-Boot 2015.01 (arch/arm/cpu/armv7/infinity3). + * SigmaStar: timer, reset, DRAM size, MIU pipe flush. + * After the vendor U-Boot 2015.01 (arch/arm/cpu/armv7/). */ #include #include +#include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -49,14 +51,147 @@ void reset_cpu(void) } /* - * The IPL has sized and trained the DDR in the package. It wraps past its - * end, which get_ram_size() sees. + * The IPL has sized and trained the DDR in the package. On infinity3 and + * infinity2m it wraps past its end, which get_ram_size() sees; the later + * dies keep the size where their vendor U-Boot reads it. */ int dram_init(void) { +#if defined(CONFIG_SS_INFINITY3) || defined(CONFIG_SS_INFINITY2M) || \ + defined(CONFIG_SS_IFADO) || defined(CONFIG_SS_IFLIEGEN) gd->ram_size = get_ram_size((long *)SS_DDR_BASE, PHYS_SDRAM_1_SIZE); +#else + unsigned int log2 = SS_DDR_LOG2_MB; + + /* + * Iford's vendor U-Boot takes a fixed size and nothing documents the + * register there: trust it only when it reads as 64 MiB to 2 GiB + */ + if (IS_ENABLED(CONFIG_SS_IFORD) && (log2 < 6 || log2 > 11)) + gd->ram_size = get_ram_size((long *)SS_DDR_BASE, SZ_512M); + else + gd->ram_size = SZ_1M * (1UL << log2); +#endif + return 0; +} + +#ifdef CONFIG_SS_MMA_BOOTARGS +/* + * U-Boot stays in the first 64 MiB, as the vendor's does + * (CONFIG_UBOOT_RAM_SIZE). + */ +ulong board_get_usable_ram_top(ulong total_size) +{ +#ifdef CONFIG_SS_IFLIEGEN + /* + * Ifliegen's IPL leaves TF-A's SP_MIN, the kernel's PSCI, at + * 0x23FE0000: its SDK's U-Boot keeps to 48 MiB (CONFIG_SGS_RAM_SIZE) + */ + return min_t(ulong, gd->ram_top, SS_DDR_BASE + SZ_32M + SZ_16M); +#endif + return min_t(ulong, gd->ram_top, SS_DDR_BASE + SZ_64M); +} +#endif + +#ifdef CONFIG_SS_IFLIEGEN +/* + * Before the console: UART0 out of the URDMA's DMA mode, as the SDK's + * hal_uart_config() takes it, once the IPL's last bytes have left. + */ +int board_early_init_f(void) +{ + int spins = 1000000; + + if (!(readw(SS_URDMA_CTRL) & SS_URDMA_DMA_MODE)) + return 0; + while (!(readw(SS_URDMA_TXFIFO_STS) & SS_URDMA_TXFIFO_EMPTY) && --spins) + ; + clrbits_le16(SS_URDMA_CTRL, SS_URDMA_TX_DMA_EN | SS_URDMA_RX_DMA_EN); + spins = 1000000; + while ((readw(SS_URDMA_CTRL) & (SS_URDMA_TX_BUSY | SS_URDMA_RX_BUSY)) && + --spins) + ; + clrbits_le16(SS_URDMA_CTRL, SS_URDMA_DMA_MODE); + clrbits_le16(SS_UART0_RX_OFF, SS_UART0_RX_OFF_BIT); return 0; } +#endif + +/* The bank of the FSP the flash is on */ +unsigned int ss_fsp_bank(void) +{ +#ifdef CONFIG_SS_IFORD_FAMILY + return SS_BANK_FSP_NONPM; +#else +#ifdef CONFIG_SS_INFINITY6E + if ((readw(SS_CHIP_BOND) & SS_CHIP_BOND_MASK) != SS_CHIP_BOND_QFN88) + return SS_BANK_FSP_NONPM; +#endif + return SS_BANK_FSP_PM; +#endif +} + +#ifdef CONFIG_SS_MMA_BOOTARGS +/* + * What the arguments LX_MEM and mma_heap take, by the DDR's size: the + * values of OpenIPC's vendor U-Boot (OpenIPC/u-boot-sigmastar, board_late_init() + * in arch/arm/cpu/armv7//chip.c), which saved environments rely on. + * LX_MEM is the kernel's memory, a little under the DDR's size on most + * dies; memsz the MMA heap inside it. + */ +struct ss_mem_row { + u16 mib; + const char *memlx; + const char *memsz; +}; + +static const struct ss_mem_row ss_mem_table[] = { +#if defined(CONFIG_SS_INFINITY6) + { 256, "0xFFC6000", "0xA000000" }, + { 128, "0x7FC6000", "0x4600000" }, + { 0, "0x3FC6000", "0x2000000" }, +#elif defined(CONFIG_SS_INFINITY6E) + { 1024, "0x3FFE0000", "0x1FE9C000" }, + { 512, "0x1FFE0000", "0x0FE9C000" }, + { 256, "0xFFE0000", "0x9E9C000" }, + { 128, "0x7FE0000", "0x4E9C000" }, + { 0, "0x3FE0000", "0x1E9C000" }, +#elif defined(CONFIG_SS_IFORD) + /* The Iford SDK's own images (set_config) by DDR size; 64 MiB has none */ + { 512, "0x1FC00000", "0x10000000" }, + { 256, "0x10000000", "0x7000000" }, + { 128, "0x8000000", "0x4000000" }, + { 0, "0x4000000", "0x2000000" }, +#elif defined(CONFIG_SS_IFLIEGEN) + /* The SDK's set_config by package: QFN128 128 MiB, QFN88 64 MiB */ + { 128, "0x7FE0000", "0x5000000" }, + { 0, "0x3FE0000", "0x2000000" }, +#elif defined(CONFIG_SS_I6C_FAMILY) || defined(CONFIG_SS_INFINITY2M) || \ + defined(CONFIG_SS_IFADO) + /* infinity2m has no OpenIPC values; its kernel wants 1 MiB alignment */ + { 256, "0x10000000", "0x0A000000" }, + { 128, "0x8000000", "0x4600000" }, + { 0, "0x4000000", "0x2000000" }, +#else /* infinity6b0 */ + { 256, "0xFFE0000", "0xA000000" }, + { 128, "0x7FE0000", "0x4600000" }, + { 0, "0x3FE0000", "0x2000000" }, +#endif +}; + +void ss_set_mem_env(void) +{ + unsigned int mib = gd->ram_size / SZ_1M; + const struct ss_mem_row *row = ss_mem_table; + + /* The row for this size, or the largest below it: a size the vendor + * has no row for keeps to memory it has */ + while (row->mib && row->mib > mib) + row++; + env_set("memlx", row->memlx); + env_set("memsz", row->memsz); +} +#endif /* * The MIU buffers writes: what the CPU stored is in DDR, for a DMA engine @@ -64,6 +199,10 @@ int dram_init(void) */ void ss_miu_flush(void) { +#ifdef CONFIG_SS_IFORD_FAMILY + /* No MIU pipe to flush, as the vendor's chip.c says */ + return; +#endif int spins = 1000000; writew(0x10, SS_L3_FLUSH); diff --git a/board/sigmastar/infinity3/Makefile b/board/sigmastar/ipc/Makefile similarity index 63% rename from board/sigmastar/infinity3/Makefile rename to board/sigmastar/ipc/Makefile index 1aa36e4a3076..fcdb7efeb409 100644 --- a/board/sigmastar/infinity3/Makefile +++ b/board/sigmastar/ipc/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-y += infinity3.o +obj-y += ipc.o diff --git a/board/sigmastar/infinity3/infinity3.c b/board/sigmastar/ipc/ipc.c similarity index 73% rename from board/sigmastar/infinity3/infinity3.c rename to board/sigmastar/ipc/ipc.c index 9385d9756f49..6a27a273ddf9 100644 --- a/board/sigmastar/infinity3/infinity3.c +++ b/board/sigmastar/ipc/ipc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SigmaStar infinity3 camera board, after the vendor U-Boot 2015.01 - * (arch/arm/cpu/armv7/infinity3/board.c). + * SigmaStar camera board, after the vendor U-Boot 2015.01 + * (arch/arm/cpu/armv7//board.c). */ #include @@ -16,12 +16,15 @@ DECLARE_GLOBAL_DATA_PTR; int board_init(void) { - gd->bd->bi_boot_params = SS_DDR_BASE + 0x100; + gd->bd->bi_boot_params = SS_BOOT_PARAMS; return 0; } int misc_init_r(void) { +#ifdef CONFIG_SS_MMA_BOOTARGS + ss_set_mem_env(); +#endif return openipc_helper(); } diff --git a/build.sh b/build.sh index 9f119c8f0587..659d19755327 100755 --- a/build.sh +++ b/build.sh @@ -41,20 +41,213 @@ build_infinity3() { "${builddir}/u-boot.bin" "${soc}" "output/u-boot-${soc}-nor.bin" } +# SigmaStar infinity2m and infinity6*: the same IPL and IPL_CUST, the layout +# of OpenIPC's vendor U-Boot (openipc/sigmastar-image.py). All parts of a die +# share its stages; only U-Boot's Kconfig target differs. +build_die() { + soc=$1 + die=$2 + tag=$3 + table=$4 + 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/${die}_config \ + openipc/${soc}_config && \ + make ${make_opts} olddefconfig /dev/null && \ + make ${make_opts} /dev/null) && \ + make ${make_opts} olddefconfig /dev/null && \ + make ${make_opts} /dev/null && \ + make ${make_opts} /dev/null && \ + make ${make_opts} /dev/null && \ + make ${make_opts} /dev/null && \ + make ${make_opts} /dev/null && \ + make ${make_opts} &2 return 1 ;; esac } -ALL_SOCS="msc313e msc316dc msc316dm" +NOR_SOCS="msc313e msc316dc msc316dm ssd201 ssd202d ssr621q ssc325 ssc325de + ssc327de ssc333 ssc335 ssc335de ssc337 ssc337de ssc30kd ssc30kq ssc338q + ssc377 ssc377d ssc377de ssc377qe ssc378de ssc378qe ssc029a ssc029b + ssc029c ssc375 ssc034a ssc034b" +NAND_SOCS="ssd201 ssd202d ssr621q ssc325 ssc325de ssc327de ssc333 ssc335 + ssc335de ssc337 ssc337de ssc30kd ssc30kq ssc338q ssc377 ssc377d ssc377de + ssc377qe ssc378de ssc378qe" +ALL_SOCS="${NOR_SOCS} $(for s in ${NAND_SOCS}; do echo "${s}-nand"; done) + ssc029a-nand ssc034a-nand ssc034b-nand" SOCS="$@" [ -z "${SOCS}" ] && SOCS="${ALL_SOCS}" diff --git a/common/Kconfig b/common/Kconfig index b6f754d9fdf8..f2855a3b3264 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1014,6 +1014,14 @@ config OPENIPC (common/openipc.c), driven from the board's misc_init_r(), with the default environment in include/configs/openipc-common.h. +config OPENIPC_NAND_KERNEL_VOLUME + bool "NAND firmware keeps the kernel in its own UBI volume" + depends on OPENIPC + help + The layout of OpenIPC's SigmaStar NAND images: UBI volumes kernel + and rootfs, a squashfs. Without it, the kernel is a file in the + UBIFS rootfs. + config PRODUCT_SOC string "Product SoC name" default SYS_CONFIG_NAME diff --git a/common/openipc.c b/common/openipc.c index 87ff4f7b82a7..fc09372961c3 100644 --- a/common/openipc.c +++ b/common/openipc.c @@ -48,19 +48,24 @@ static int check_squashfs(void *buf) { } #ifdef CONFIG_ENV_IS_IN_NAND +#ifndef CONFIG_OPENIPC_NAND_KERNEL_VOLUME #define UBIFS_SB_MAGIC 0x06101831 static int check_ubifs(void *buf) { return get_unaligned_le32(buf) == UBIFS_SB_MAGIC; } +#endif /* Check for the UBI marker without attaching: attaching an empty MTD - * would create a fresh UBI on flash. */ + * would create a fresh UBI on flash. UBI writes an EC header to every + * good eraseblock, so the first good one tells; a corrected read + * (-EUCLEAN) still holds the data. */ static int ubi_marker_present(void) { struct mtd_info *mtd; u8 buf[4]; - size_t retlen; - int ret; + size_t retlen = 0; + loff_t off; + int ret = -ENODEV; /* Register the mtdparts partitions before looking one up by name */ mtd_probe_devices(); @@ -68,10 +73,15 @@ static int ubi_marker_present(void) { if (IS_ERR(mtd)) return 0; - ret = mtd_read(mtd, 0, sizeof(buf), &retlen, buf); + for (off = 0; off < mtd->size; off += mtd->erasesize) { + if (mtd_block_isbad(mtd, off) > 0) + continue; + ret = mtd_read(mtd, off, sizeof(buf), &retlen, buf); + break; + } put_mtd_device(mtd); - return !ret && retlen == sizeof(buf) && + return (!ret || ret == -EUCLEAN) && retlen == sizeof(buf) && get_unaligned_be32(buf) == UBI_EC_HDR_MAGIC; } #endif @@ -212,6 +222,10 @@ static int recovery_mount(const char *ifname) { } #ifdef CONFIG_ENV_IS_IN_NAND +#ifndef OPENIPC_KERNEL_VOLUME_SIZE +#define OPENIPC_KERNEL_VOLUME_SIZE "0x300000" +#endif + static int recovery_ensure_volume(const char *name, const char *size) { struct ubi_volume_desc *desc; char cmd[64]; @@ -332,7 +346,7 @@ static int recovery_write(const char *name, int type) { printf("Recovery: wrote %s (%lu bytes) to rootfs volume\n", name, size); } else { - ret = recovery_recreate_volume("kernel", "0x300000", false); + ret = recovery_recreate_volume("kernel", OPENIPC_KERNEL_VOLUME_SIZE, false); if (ret) { printf("Recovery: cannot recreate kernel volume (%d)\n", ret); return -1; @@ -479,7 +493,8 @@ static int recovery_try(void) { if (recovery_run_script("script.txt")) return 1; -#ifndef CONFIG_ENV_IS_IN_NAND +#if !defined(CONFIG_ENV_IS_IN_NAND) || \ + defined(CONFIG_OPENIPC_NAND_KERNEL_VOLUME) /* Kernel: uImage preferred, FIT fallback */ sprintf(name, "uImage.%s.img", CONFIG_PRODUCT_SOC); ret = recovery_write(name, RECOVERY_KERNEL); @@ -495,7 +510,8 @@ static int recovery_try(void) { /* 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 +#if defined(CONFIG_ENV_IS_IN_NAND) && \ + !defined(CONFIG_OPENIPC_NAND_KERNEL_VOLUME) sprintf(name, "rootfs.ubifs.%s.img", CONFIG_PRODUCT_SOC); #else sprintf(name, "rootfs.squashfs.%s.img", CONFIG_PRODUCT_SOC); @@ -565,6 +581,21 @@ int firmware_scan(void) { return 0; } +#ifdef CONFIG_OPENIPC_NAND_KERNEL_VOLUME + /* The kernel in its volume, a squashfs rootfs in its own */ + ret = ubi_volume_read("kernel", (char *)buf, sizeof(buf)); + if (ret || !check_kernel(buf)) { + printf("Firmware is absent/corrupt (kernel volume)\n"); + env_set("bootfail", "1"); + return 0; + } + ret = ubi_volume_read("rootfs", (char *)buf, sizeof(buf)); + if (ret || !check_squashfs(buf)) { + printf("Firmware is absent/corrupt (rootfs volume)\n"); + env_set("bootfail", "1"); + return 0; + } +#else /* 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)); @@ -588,6 +619,7 @@ int firmware_scan(void) { env_set("bootfail", "1"); return 0; } +#endif env_set("bootfail", NULL); diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ec99cc6e9753..d183978a9f3a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -78,10 +78,10 @@ config MMC_SPI_CRC_ON If unsure, say N. config MMC_MS_SDMMC - bool "SigmaStar infinity3 SD card (SDIO0)" + bool "SigmaStar SD card (SDIO0)" depends on ARCH_SIGMASTAR && MMC && !DM_MMC help - SDIO0, the FCIE5 SD host of the SigmaStar infinity3 SoCs, on the + SDIO0, the FCIE5 SD host of the SigmaStar SoCs, on the SD pads: 4-bit, DMA. config ARM_PL180_MMCI diff --git a/drivers/mmc/ms_sdmmc.c b/drivers/mmc/ms_sdmmc.c index 4fa511bdee47..a959e1fd9bb3 100644 --- a/drivers/mmc/ms_sdmmc.c +++ b/drivers/mmc/ms_sdmmc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SD card on SDIO0, the FCIE5 SD host of the SigmaStar infinity3. + * SD card on SDIO0, the FCIE5 SD host of the SigmaStar SoCs. * * One job runs a command and, with DTRX_EN, its data: the command goes in * through the CMD/RSP FIFO (byte 0 = 0x40 | index, then the argument most @@ -11,8 +11,10 @@ * with JOB_DIR set. * * After the vendor U-Boot 2015.01 (drivers/mstar/sdmmc: hal_sdmmc_v5.c, - * hal_card_platform_iNF3.c and ms_sdmmc_ub.c, which drives U-Boot's mmc + * hal_card_platform_.c and ms_sdmmc_ub.c, which drives U-Boot's mmc * core the same way): the SDIO0 IP on the SD pads, DMA, bypass timing. + * The host is the same on every die; its bank, clock, pad mux, card power + * and card detect are not, and are under "Platform" below. */ #include @@ -87,28 +89,84 @@ #define RST_SOFT BIT(0) #define RST_STS (BIT(1) | BIT(2) | BIT(3)) +/* + * DDR_MOD at every speed up to HS: bypass timing on infinity3; the later + * vendor trees have left bypass mode, without the falling-edge latch on + * infinity6c + */ +#define DDR_PAD_CLK_SEL BIT(10) +#define DDR_PAD_IN_SEL BIT(13) +#define DDR_FALL_LATCH BIT(14) +#if defined(CONFIG_SS_INFINITY3) +#define SD_DDR_MOD_TIMING 0 +#elif defined(CONFIG_SS_I6C_FAMILY) +#define SD_DDR_MOD_TIMING (DDR_PAD_CLK_SEL | DDR_PAD_IN_SEL) +#else +#define SD_DDR_MOD_TIMING (DDR_PAD_CLK_SEL | DDR_PAD_IN_SEL | DDR_FALL_LATCH) +#endif + /* Platform: clock, pads, card power and card detect */ -#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x45) -#define SD_CLKGEN_MASK 0x3f /* [5:2] select, [1] invert, [0] gate */ +#define PAD_OEN BIT(5) /* set: input, the pad to the IP */ +#define PAD_OUT BIT(4) +#define CHIPTOP_ALLPAD SS_REG(SS_BANK_CHIPTOP, 0x50) +#define CHIPTOP_ALLPAD_IN BIT(15) #define CHIPTOP_SD_MODE SS_REG(SS_BANK_CHIPTOP, 0x08) -#define CHIPTOP_SD_MODE2 BIT(3) -#define CHIPTOP_SDIO_MODE1 BIT(8) #define CHIPTOP_SD_PULL_DRV SS_REG(SS_BANK_CHIPTOP, 0x32) #define CHIPTOP_SD_PULL (0x1f << 8) /* D3-D0, CMD pull-ups */ #define CHIPTOP_SD_DRV 0x3f /* CLK, D3-D0, CMD drive */ -#define CHIPTOP_ALLPAD SS_REG(SS_BANK_CHIPTOP, 0x50) -#define CHIPTOP_ALLPAD_IN BIT(15) +#define CHIPTOP_FUART_MODE SS_REG(SS_BANK_CHIPTOP, 0x03) #define PADTOP_SD_POWER SS_REG(SS_BANK_PADTOP, 0x17) #define PADTOP_SD_PAD(i) SS_REG(SS_BANK_PADTOP, 0x50 + (i)) /* CLK, CMD, D0-D3 */ -#define PAD_OEN BIT(5) /* set: input, the pad to the IP */ -#define PAD_OUT BIT(4) +#define PADTOP(r) SS_REG(SS_BANK_PADTOP, r) +#define PADGPIO(r) SS_REG(SS_BANK_PADGPIO, r) #define PM_SD_CDZ_MODE SS_REG(SS_BANK_PMSLEEP, 0x28) #define PM_SD_CDZ_EN BIT(14) #define PM_GPIO_SD_CDZ SS_REG(SS_BANK_PMGPIO, 0x47) #define CDZ_OEN BIT(0) #define CDZ_IN BIT(2) /* low: a card is in */ +/* SCGPCTRL reg 0x25: the SD clock leaves the boot clock */ +#ifdef CONFIG_SS_IFORD +#define SCGP_SD_CLK SS_REG(SS_BANK_SCGPCTRL_SD, 0x25) +#else +#define SCGP_SD_CLK SS_REG(SS_BANK_SCGPCTRL, 0x25) +#endif + +/* + * SD_CLKGEN: [4:2] or [5:2] select, [1] invert, [0] gate, and on the + * infinity6 dies a "boot" select above them that stays set + */ +#if defined(CONFIG_SS_INFINITY3) +#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x45) +#define SD_CLKGEN_MASK 0x3f +#define SD_CLKGEN_BOOT 0 +#elif defined(CONFIG_SS_INFINITY2M) +#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x45) +#define SD_CLKGEN_MASK 0x3f +#define SD_CLKGEN_BOOT 0 +#define SCGP_SD_BOOTCLK BIT(3) +#elif defined(CONFIG_SS_IFORD_FAMILY) +/* + * Iford's and Ifliegen's hal_card_platform.c: bit 7 set once at init; + * each clock change clears the gate and the select and sets bit 6, the + * glitch-free select, again + */ +#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x43) +#define SD_CLKGEN_MASK 0x7f +#define SD_CLKGEN_BOOT BIT(6) +#define SD_CLKGEN_ON BIT(7) +#define SCGP_SD_BOOTCLK BIT(7) +#elif defined(CONFIG_SS_I6C_FAMILY) +#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x43) +#define SD_CLKGEN_MASK 0x7f +#define SD_CLKGEN_BOOT BIT(6) +#define SCGP_SD_BOOTCLK BIT(7) +#else +#define SD_CLKGEN SS_REG(SS_BANK_CLKGEN0, 0x43) +#define SD_CLKGEN_MASK 0x3f +#define SD_CLKGEN_BOOT BIT(5) +#define SCGP_SD_BOOTCLK BIT(7) +#endif -/* The vendor's waits */ #define WT_RESET_MS 100 #define WT_RSP_MS 10 #define WT_READ_MS 2000 @@ -229,8 +287,7 @@ static void sd_setup_job(struct mmc_cmd *cmd, struct mmc_data *data) writew(rsp_ctl | (data && data->flags & MMC_DATA_WRITE ? CTL_JOB_DIR : 0), SD_CTL); writew(MMA_PRI_RW, SD_MMA_PRI); - /* Bypass timing, as the vendor runs every speed up to HS */ - writew(0, SD_DDR_MOD); + writew(SD_DDR_MOD_TIMING, SD_DDR_MOD); clrbits_le16(SD_BOOT_MOD, BOOT_MOD_BOOT); clrbits_le16(SD_BOOT, BOOT_NAND_SRAM_IMI); udelay(sd_nrc_us); @@ -318,20 +375,353 @@ static int ms_sd_set_ios(struct mmc *mmc) for (sel = 0; sel < ARRAY_SIZE(sd_clocks) - 1; sel++) if (sd_clocks[sel] <= mmc->clock) break; - clrsetbits_le16(SD_CLKGEN, SD_CLKGEN_MASK, sel << 2); + clrsetbits_le16(SD_CLKGEN, SD_CLKGEN_MASK, + SD_CLKGEN_BOOT | sel << 2); sd_nrc_us = sd_nrc_for(sd_clocks[sel]); } sd_bus_width = mmc->bus_width == 4 ? MODE_BUS_4 : 0; return 0; } -static int ms_sd_getcd(struct mmc *mmc) +#if defined(CONFIG_SS_INFINITY6E) + +/* The SD pads' GPIO registers, PADTOP: D1, D0, CLK, CMD, D3, D2 */ +#define SD6E_PAD_FIRST 0x12 +#define SD6E_PAD_LAST 0x17 +#define SD6E_PAD_CLK 0x14 +#define SD6E_PULL BIT(4) +#define SD6E_OEN BIT(2) +#define SD6E_OUT BIT(1) +#define SD6E_DRV BIT(7) +#define SD6E_CDZ 0x11 +#define SD6E_CDZ_IN BIT(0) +#define SD6E_POWER_A 0x25 +#define SD6E_POWER_B 0x10 +#define SD6E_MODE 0x67 +#define SD6E_MODE_MASK (BIT(13) | BIT(12) | BIT(9) | BIT(8)) +#define SD6E_MODE_SD (BIT(9) | BIT(8)) +#define SD6E_MODE2 0x68 +#define SD6E_SPI1_MODE (BIT(2) | BIT(1) | BIT(0)) +#define SD6E_FUART_MODE 0x6E + +static int sd_card_in(void) +{ + setbits_le16(PADTOP(SD6E_CDZ), SD6E_OEN); + return !(readw(PADTOP(SD6E_CDZ)) & SD6E_CDZ_IN); +} + +static void sd_plat_init(void) +{ + unsigned int r; + + setbits_le16(SCGP_SD_CLK, SCGP_SD_BOOTCLK); + clrsetbits_le16(SD_CLKGEN, SD_CLKGEN_MASK, SD_CLKGEN_BOOT); + clrsetbits_le16(PADTOP(SD6E_MODE), SD6E_MODE_MASK, SD6E_MODE_SD); + clrbits_le16(PADTOP(SD6E_MODE2), BIT(9)); + /* reg_spi1_mode 3 takes these pads */ + if ((readw(PADTOP(SD6E_MODE2)) & 7) == 3) + clrbits_le16(PADTOP(SD6E_MODE2), SD6E_SPI1_MODE); + for (r = SD6E_PAD_FIRST; r <= SD6E_PAD_LAST; r++) { + if (r != SD6E_PAD_CLK) + setbits_le16(PADTOP(r), SD6E_PULL); + clrbits_le16(PADTOP(r), SD6E_DRV); + } +} + +static void sd_pads(bool on) +{ + unsigned int r; + + for (r = SD6E_PAD_FIRST; r <= SD6E_PAD_LAST; r++) { + if (r != SD6E_PAD_CLK) { + if (on) + setbits_le16(PADTOP(r), SD6E_PULL); + else + clrbits_le16(PADTOP(r), SD6E_PULL); + } + if (on) + setbits_le16(PADTOP(r), SD6E_OEN); + else + clrbits_le16(PADTOP(r), SD6E_OEN | SD6E_OUT); + } + clrbits_le16(PADTOP(SD6E_MODE), SD6E_MODE_MASK); + clrbits_le16(PADTOP(SD6E_MODE2), BIT(9) | BIT(8)); + if (on) + setbits_le16(PADTOP(SD6E_MODE), SD6E_MODE_SD); +} + +/* Card power, low active: on the fuart pad on some boards, sd0 on others */ +static void sd_power(bool on, unsigned int ms) +{ + static const u8 regs[] = { SD6E_POWER_A, SD6E_POWER_B }; + unsigned int i; + + /* reg_fuart_mode 1 takes the power pad */ + if (on && (readw(PADTOP(SD6E_FUART_MODE)) & 0x70) == 0x10) + setbits_le16(PADTOP(SD6E_FUART_MODE), BIT(6)); + for (i = 0; i < ARRAY_SIZE(regs); i++) { + clrbits_le16(PADTOP(regs[i]), SD6E_OEN); + if (on) + clrbits_le16(PADTOP(regs[i]), SD6E_OUT); + else + setbits_le16(PADTOP(regs[i]), SD6E_OUT); + } + mdelay(ms); +} + +#elif defined(CONFIG_SS_IFLIEGEN) + +/* + * Ifliegen's SD0 (mmc_host/src/ifliegen, IP_SD and PAD_SD_MD1, the + * board's mmc0): PADGPIO CLK at 0x0F, CMD, D0-D3 from 0x10, card detect + * at 0x16 (PAD_PM_SD_CDZ), the mode in PADTOP 0x61 (its cdz-pad given: + * SD and CDZ mode, bits 0 and 4), the card powered from PAD_FUART_RTS, + * PADGPIO 0x34, low active. SC_GP_CTRL is bank 0x1133 here. + */ +#define SDLG_PAD_CLK 0x0F +#define SDLG_PAD_FIRST 0x10 /* CMD, D0, D1, D2, D3 */ +#define SDLG_PAD_LAST 0x14 +#define SDLG_PULL BIT(4) +#define SDLG_DRV BIT(7) +#define SDLG_CDZ 0x16 +#define SDLG_CDZ_IN BIT(0) +#define SDLG_CDZ_OEN BIT(2) +#define SDLG_MODE 0x61 +#define SDLG_MODE_MASK (BIT(12) | BIT(9) | BIT(8) | BIT(4) | BIT(0)) +#define SDLG_MODE_SD BIT(0) +#define SDLG_MODE_CDZ BIT(4) +#define SDLG_POWER 0x34 +#define SDLG_POWER_GPIO BIT(3) +#define SDLG_POWER_OEN BIT(2) +#define SDLG_POWER_OUT BIT(1) +#define SD_CLK_EN_REG SD_REG(0x3E) +#define SD_MCG_OFF BIT(14) + +static int sd_card_in(void) +{ + setbits_le16(PADGPIO(SDLG_CDZ), SDLG_CDZ_OEN); + return !(readw(PADGPIO(SDLG_CDZ)) & SDLG_CDZ_IN); +} + +static void sd_plat_init(void) +{ + unsigned int r; + + setbits_le16(SD_CLK_EN_REG, SD_MCG_OFF); + /* The SD clock off the 12 MHz boot clock */ + setbits_le16(SCGP_SD_CLK, SCGP_SD_BOOTCLK); + clrsetbits_le16(SD_CLKGEN, 0xff, SD_CLKGEN_ON); + setbits_le16(PADGPIO(SDLG_CDZ), BIT(5) | BIT(4)); + setbits_le16(PADGPIO(SDLG_PAD_CLK), SDLG_DRV); + for (r = SDLG_PAD_FIRST; r <= SDLG_PAD_LAST; r++) + setbits_le16(PADGPIO(r), SDLG_PULL | SDLG_DRV); +} + +static void sd_pads(bool on) +{ + clrsetbits_le16(PADTOP(SDLG_MODE), SDLG_MODE_MASK, + SDLG_MODE_CDZ | (on ? SDLG_MODE_SD : 0)); +} + +/* Card power, low active */ +static void sd_power(bool on, unsigned int ms) +{ + setbits_le16(PADGPIO(SDLG_POWER), SDLG_POWER_GPIO); + clrbits_le16(PADGPIO(SDLG_POWER), SDLG_POWER_OEN); + if (on) + clrbits_le16(PADGPIO(SDLG_POWER), SDLG_POWER_OUT); + else + setbits_le16(PADGPIO(SDLG_POWER), SDLG_POWER_OUT); + mdelay(ms); +} + +#elif defined(CONFIG_SS_IFORD) + +/* + * Iford's SD0 pads (mmc_host/src/iford, IP_SD and PAD_SD_MD1): PADGPIO + * D1, D0, CLK, CMD, D3, D2 from reg 0x15, card detect at 0x14, the mode in + * PADTOP 0x61, the card powered from PAD_PM_GPIO11, PADGPIO 0x2C. Which pads + * a board wires is in its device tree; these are the vendor's SD0 defaults. + */ +#define SDIF_PAD_FIRST 0x15 +#define SDIF_PAD_LAST 0x1A +#define SDIF_PAD_CLK 0x17 +#define SDIF_PULL BIT(4) +#define SDIF_DRV BIT(7) +#define SDIF_CDZ 0x14 +#define SDIF_CDZ_IN BIT(0) +#define SDIF_CDZ_OEN BIT(2) +#define SDIF_MODE 0x61 +#define SDIF_MODE_MASK (BIT(12) | BIT(11) | BIT(9) | BIT(8) | BIT(5) | \ + BIT(4) | BIT(1) | BIT(0)) +#define SDIF_MODE_SD BIT(0) +#define SDIF_MODE_CDZ BIT(4) +#define SDIF_POWER 0x2C +#define SDIF_POWER_GPIO BIT(3) +#define SDIF_POWER_OEN BIT(2) +#define SDIF_POWER_OUT BIT(1) + +static int sd_card_in(void) +{ + clrsetbits_le16(PADTOP(SDIF_MODE), BIT(5) | SDIF_MODE_CDZ, + SDIF_MODE_CDZ); + setbits_le16(PADGPIO(SDIF_CDZ), SDIF_CDZ_OEN); + return !(readw(PADGPIO(SDIF_CDZ)) & SDIF_CDZ_IN); +} + +static void sd_plat_init(void) +{ + unsigned int r; + + clrbits_le16(CHIPTOP_ALLPAD, CHIPTOP_ALLPAD_IN); + /* The SD clock off the 12 MHz boot clock (SC_GP_CTRL bank 0x1135) */ + setbits_le16(SCGP_SD_CLK, SCGP_SD_BOOTCLK); + clrsetbits_le16(SD_CLKGEN, 0xff, SD_CLKGEN_ON); + setbits_le16(PADGPIO(SDIF_CDZ), BIT(5) | BIT(4)); + for (r = SDIF_PAD_FIRST; r <= SDIF_PAD_LAST; r++) { + if (r != SDIF_PAD_CLK) + setbits_le16(PADGPIO(r), SDIF_PULL); + setbits_le16(PADGPIO(r), SDIF_DRV); + } +} + +static void sd_pads(bool on) +{ + clrsetbits_le16(PADTOP(SDIF_MODE), SDIF_MODE_MASK, + SDIF_MODE_CDZ | (on ? SDIF_MODE_SD : 0)); +} + +/* Card power, low active */ +static void sd_power(bool on, unsigned int ms) +{ + setbits_le16(PADGPIO(SDIF_POWER), SDIF_POWER_GPIO); + clrbits_le16(PADGPIO(SDIF_POWER), SDIF_POWER_OEN); + if (on) + clrbits_le16(PADGPIO(SDIF_POWER), SDIF_POWER_OUT); + else + setbits_le16(PADGPIO(SDIF_POWER), SDIF_POWER_OUT); + mdelay(ms); +} + +#elif defined(CONFIG_SS_INFINITY6C) + +/* The SD pads' GPIO registers, PADGPIO: D1, D0, CLK, CMD, D3, D2 */ +#define SD6C_PAD_FIRST 0x00 +#define SD6C_PAD_LAST 0x05 +#define SD6C_PAD_CLK 0x02 +#define SD6C_PULL BIT(4) +#define SD6C_OEN BIT(2) +#define SD6C_OUT BIT(1) +#define SD6C_DRV BIT(7) +#define SD6C_CDZ 0x06 +#define SD6C_CDZ_IN BIT(0) +#define SD6C_POWER 0x22 +#define SD6C_POWER_GPIO BIT(3) +#define SD6C_MODE 0x67 +#define SD6C_MODE_SD BIT(8) +#define SD6C_MODE_CDZ BIT(11) +#define SD6C_MODE_MASK (BIT(10) | BIT(9) | BIT(8)) +#define SD6C_MODE2 0x68 + +static int sd_card_in(void) +{ + setbits_le16(PADGPIO(SD6C_CDZ), SD6C_OEN); + return !(readw(PADGPIO(SD6C_CDZ)) & SD6C_CDZ_IN); +} + +static void sd_plat_init(void) +{ + unsigned int r; + + setbits_le16(SCGP_SD_CLK, SCGP_SD_BOOTCLK); + clrsetbits_le16(SD_CLKGEN, SD_CLKGEN_MASK, SD_CLKGEN_BOOT); + clrsetbits_le16(PADTOP(SD6C_MODE), + BIT(12) | BIT(11) | SD6C_MODE_MASK, + SD6C_MODE_SD | SD6C_MODE_CDZ); + clrbits_le16(PADTOP(SD6C_MODE2), BIT(13) | BIT(12)); + for (r = SD6C_PAD_FIRST; r <= SD6C_PAD_LAST; r++) { + if (r != SD6C_PAD_CLK) + setbits_le16(PADGPIO(r), SD6C_PULL); + setbits_le16(PADGPIO(r), SD6C_DRV); + } + setbits_le16(PADGPIO(SD6C_CDZ), SD6C_PULL); +} + +static void sd_pads(bool on) +{ + unsigned int r; + + for (r = SD6C_PAD_FIRST; r <= SD6C_PAD_LAST; r++) { + if (r != SD6C_PAD_CLK) { + if (on) + setbits_le16(PADGPIO(r), SD6C_PULL); + else + clrbits_le16(PADGPIO(r), SD6C_PULL); + } + if (on) + setbits_le16(PADGPIO(r), SD6C_OEN); + else + clrbits_le16(PADGPIO(r), SD6C_OEN | SD6C_OUT); + } + if (on) + setbits_le16(PADTOP(SD6C_MODE), SD6C_MODE_SD); + else + clrbits_le16(PADTOP(SD6C_MODE), SD6C_MODE_MASK); +} + +/* Card power, low active */ +static void sd_power(bool on, unsigned int ms) +{ + setbits_le16(PADGPIO(SD6C_POWER), SD6C_POWER_GPIO); + clrbits_le16(PADGPIO(SD6C_POWER), SD6C_OEN); + if (on) + clrbits_le16(PADGPIO(SD6C_POWER), SD6C_OUT); + else + setbits_le16(PADGPIO(SD6C_POWER), SD6C_OUT); + mdelay(ms); +} + +#else /* infinity3, infinity2m, infinity6, infinity6b0: CHIPTOP's SD modes */ + +#if defined(CONFIG_SS_INFINITY3) +#define SD_MODE_CLR BIT(3) +#define SD_MODE_SET BIT(8) +#elif defined(CONFIG_SS_INFINITY2M) +#define SD_MODE_CLR (BIT(9) | BIT(8)) +#define SD_MODE_SET BIT(8) +#else +#define SD_MODE_CLR (BIT(8) | BIT(3) | BIT(2)) +#define SD_MODE_SET BIT(2) +#endif + +/* infinity2m powers the card from PAD_TTL0, the rest from PAD_FUART_RTS */ +#ifdef CONFIG_SS_INFINITY2M +#define SD_POWER_PAD PADTOP(0x20) +#else +#define SD_POWER_PAD PADTOP_SD_POWER +#endif + +static int sd_card_in(void) { setbits_le16(PM_SD_CDZ_MODE, PM_SD_CDZ_EN); setbits_le16(PM_GPIO_SD_CDZ, CDZ_OEN); return !(readw(PM_GPIO_SD_CDZ) & CDZ_IN); } +static void sd_plat_init(void) +{ +#ifdef SCGP_SD_BOOTCLK + setbits_le16(SCGP_SD_CLK, SCGP_SD_BOOTCLK); +#endif + clrsetbits_le16(SD_CLKGEN, SD_CLKGEN_MASK, SD_CLKGEN_BOOT); + clrsetbits_le16(CHIPTOP_SD_MODE, SD_MODE_CLR, SD_MODE_SET); +#if defined(CONFIG_SS_INFINITY2M) || defined(CONFIG_SS_INFINITY6B0) + setbits_le16(CHIPTOP_SD_PULL_DRV, CHIPTOP_SD_DRV | CHIPTOP_SD_PULL); +#else + clrsetbits_le16(CHIPTOP_SD_PULL_DRV, CHIPTOP_SD_DRV, CHIPTOP_SD_PULL); +#endif +} + /* The pads to the IP with pull-ups (on), or driven low (off) */ static void sd_pads(bool on) { @@ -347,24 +737,34 @@ static void sd_pads(bool on) else clrbits_le16(PADTOP_SD_PAD(i), PAD_OEN | PAD_OUT); } - clrbits_le16(CHIPTOP_SD_MODE, CHIPTOP_SD_MODE2); + clrbits_le16(CHIPTOP_SD_MODE, SD_MODE_CLR); if (on) - setbits_le16(CHIPTOP_SD_MODE, CHIPTOP_SDIO_MODE1); - else - clrbits_le16(CHIPTOP_SD_MODE, CHIPTOP_SDIO_MODE1); + setbits_le16(CHIPTOP_SD_MODE, SD_MODE_SET); } /* Card power, low active */ static void sd_power(bool on, unsigned int ms) { - clrbits_le16(PADTOP_SD_POWER, PAD_OEN); +#if defined(CONFIG_SS_INFINITY6) || defined(CONFIG_SS_INFINITY6B0) + /* reg_fuart_mode 1 takes the power pad */ + if (on && (readw(CHIPTOP_FUART_MODE) & 7) == 1) + setbits_le16(CHIPTOP_FUART_MODE, BIT(2)); +#endif + clrbits_le16(SD_POWER_PAD, PAD_OEN); if (on) - clrbits_le16(PADTOP_SD_POWER, PAD_OUT); + clrbits_le16(SD_POWER_PAD, PAD_OUT); else - setbits_le16(PADTOP_SD_POWER, PAD_OUT); + setbits_le16(SD_POWER_PAD, PAD_OUT); mdelay(ms); } +#endif + +static int ms_sd_getcd(struct mmc *mmc) +{ + return sd_card_in(); +} + /* * As the vendor's mmc_core_init(): the clock and the SD pads to SDIO0, * the card powered off, then, with a card in, powered up with the clock @@ -373,10 +773,7 @@ static void sd_power(bool on, unsigned int ms) static int ms_sd_init(struct mmc *mmc) { clrbits_le16(CHIPTOP_ALLPAD, CHIPTOP_ALLPAD_IN); - clrbits_le16(SD_CLKGEN, SD_CLKGEN_MASK); - clrbits_le16(CHIPTOP_SD_MODE, CHIPTOP_SD_MODE2); - setbits_le16(CHIPTOP_SD_MODE, CHIPTOP_SDIO_MODE1); - clrsetbits_le16(CHIPTOP_SD_PULL_DRV, CHIPTOP_SD_DRV, CHIPTOP_SD_PULL); + sd_plat_init(); writew(FUNC_SDIO_MODE, SD_MIE_FUNC_CTL); clrbits_le16(SD_MODE, MODE_CLK_EN); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index ce67d1abde25..6bb55aa6583e 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -37,6 +37,14 @@ config SYS_NAND_USE_FLASH_BBT help Enable the BBT (Bad Block Table) usage. +config NAND_MS_SPINAND + bool "SPI NAND on the SigmaStar FSP" + depends on ARCH_SIGMASTAR + select SYS_NAND_SELF_INIT + help + SPI NAND behind the FSP of the SigmaStar infinity6 family, with the + chip's own ECC and its geometry from the SNI the ROM boots from. + config NAND_ATMEL bool "Support Atmel NAND controller" select SYS_NAND_SELF_INIT diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index a398aa9d8864..08734e37846b 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -47,6 +47,7 @@ ifdef NORMAL_DRIVERS obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o +obj-$(CONFIG_NAND_MS_SPINAND) += ms_spinand.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o obj-$(CONFIG_NAND_BRCMNAND) += brcmnand/ diff --git a/drivers/mtd/nand/raw/ms_spinand.c b/drivers/mtd/nand/raw/ms_spinand.c new file mode 100644 index 000000000000..0bdaf6f0de93 --- /dev/null +++ b/drivers/mtd/nand/raw/ms_spinand.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SPI NAND behind the FSP of the SigmaStar infinity6 family. + * + * After the vendor U-Boot's drivers/mstar/spinand (hal/common and the + * per-die HAL_SPINAND_Init()). The FSP sends a flash command and reads the + * answer back; the page cache comes over BDMA, from the flash's read-from- + * cache in QSPI's fast read mode, and goes back the same way. The ECC is the + * chip's own: it reports its verdict in the status register. + * + * Geometry comes from the SNI the ROM boots from, not from the chip's ID: + * the published images carry one generic SNI for every part. The bad-block + * table stays in memory, built from the marks in the spare area, since the + * vendor's U-Boot writes none and UBI owns those last blocks. + * + * infinity6c differs as its NOR does: the chip select stays in software, each + * flash command framed by hand (flash/nand/drvSPINAND.c, fsp_qspi), the cache + * read in QSPI's normal mode and the FSP fired before BDMA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FSP_REG(r) SS_REG(ss_fsp_bank(), r) +#define FSP_WBF(i) FSP_REG(0x60 + (i) / 2) +#define FSP_RBF(i) FSP_REG(0x65 + (i) / 2) +#define FSP_WBF_SIZE FSP_REG(0x6a) +#define FSP_RBF_SIZE FSP_REG(0x6b) +#define FSP_CTRL FSP_REG(0x6c) +#define FSP_TRIGGER FSP_REG(0x6d) +#define FSP_DONE FSP_REG(0x6e) +#define FSP_DONE_CLR FSP_REG(0x6f) +#define FSP_CTRL2 FSP_REG(0x75) +#define FSP_CTRL4 FSP_REG(0x76) +#define FSP_OUT_SIZE FSP_REG(0x78) +#define FSP_OUT FSP_REG(0x79) + +#define CTRL_BASE (BIT(0) | BIT(1) | BIT(2)) +#define OUT_EN BIT(12) +#define FSP_BUF_SIZE 10 + +/* QSPI: the next bank up from the FSP, PM or not */ +#define QSPI_REG(r) SS_REG(ss_fsp_bank() + 1, r) +#define QSPI_BURST QSPI_REG(0x0a) +#define QSPI_BURST_ON 0x01 +#define QSPI_BURST_OFF 0x02 +#define QSPI_CS_SW BIT(0) +#define QSPI_CS_HIGH BIT(1) +#define QSPI_TIMEOUT_H QSPI_REG(0x67) +#define QSPI_TIMEOUT_EN BIT(15) +#define QSPI_TIMEOUT_OFF 0x4000 +#define QSPI_CKG QSPI_REG(0x70) +#define QSPI_CKG_DUMMY 0x17 /* 8 cycles */ +#define QSPI_MODE QSPI_REG(0x72) +#define QSPI_MODE_FAST 0x01 +#define QSPI_MODE_NORMAL 0x00 +#define QSPI_CS_SEL QSPI_REG(0x7a) +#define QSPI_FUNC QSPI_REG(0x7d) +#define QSPI_FUNC_CACHE 0x1800 /* 2-byte address, dummy */ + +#define PM_SPI_CZ SS_REG(SS_BANK_PMSLEEP, 0x35) +#define CHIP_ALL_PAD_IN SS_REG(SS_BANK_CHIPTOP, 0x50) + +#define BDMA_REG(r) SS_REG(SS_BANK_BDMA, r) +#define BDMA_CTRL BDMA_REG(0x00) +#define BDMA_STATUS BDMA_REG(0x01) +#define BDMA_PATH BDMA_REG(0x02) +#define BDMA_PATH2 BDMA_REG(0x03) +#define BDMA_SRC_L BDMA_REG(0x04) +#define BDMA_SRC_H BDMA_REG(0x05) +#define BDMA_DST_L BDMA_REG(0x06) +#define BDMA_DST_H BDMA_REG(0x07) +#define BDMA_LEN_L BDMA_REG(0x08) +#define BDMA_LEN_H BDMA_REG(0x09) +#define BDMA_TRIGGER BIT(0) +#define BDMA_DONE BIT(3) +#ifdef CONFIG_SS_IFORD_FAMILY +#define BDMA_PATH_MIU_FSP 0x2B41 +#else +#define BDMA_PATH_MIU_FSP 0x2B40 +#endif +#ifdef CONFIG_SS_I6C_FAMILY +#define BDMA_PATH_SPI_MIU 0x4135 +#else +#define BDMA_PATH_SPI_MIU 0x4035 +#endif +/* One outside-buffer run takes this much, as the vendor's driver splits it */ +#define BDMA_CHUNK 2048 + +#define CMD_RDID 0x9F +#define CMD_WREN 0x06 +#define CMD_RESET 0xFF +#define CMD_GET_FEATURE 0x0F +#define CMD_SET_FEATURE 0x1F +#define CMD_PAGE_READ 0x13 +#define CMD_PROGRAM_LOAD 0x02 +#define CMD_PROGRAM_EXEC 0x10 +#define CMD_BLOCK_ERASE 0xD8 +#define CMD_DIE_SELECT 0xC2 + +#define REG_PROTECT 0xA0 +#define REG_STATUS 0xC0 +#define REG_CONFIG 0xB0 +#define CFG_BUF BIT(3) +#define ST_BUSY BIT(0) +#define ST_E_FAIL BIT(2) +#define ST_P_FAIL BIT(3) +#define ST_ECC (3 << 4) +#define ST_ECC_ERR (2 << 4) + +#define SF_TIMEOUT_MS 1000 + +/* The SNI, at the start of block 0, or of one of its backups */ +#define SNI_TAG "MSTARSEMIUSFDCIS" +#define SNI_TAG_LEN 16 +#define SNI_COPIES 5 +#define SNI_DEFAULT_BLK_PAGES 64 + +struct ms_sni { + u8 id_len; + u8 id[15]; + __le16 spare; + __le16 page; + __le16 blk_pages; + __le16 blocks; + __le16 sector; + u8 planes; +} __packed; + +struct ms_spinand { + struct nand_chip chip; + struct nand_flash_dev ids[2]; + u8 *buf; /* page and spare */ + unsigned int pos; + unsigned int page_size, spare_size, blk_pages, blocks; + u8 planes; + bool dies; /* two dies behind one chip select */ + int page; /* of the write in progress */ + u8 status; /* of the last read, program or erase */ + bool failed; /* the last program or erase */ + bool show_status; + u8 id[8]; +}; + +static struct ms_spinand ms_nand; + +static int fsp_wait(void) +{ + int ret = wait_for_bit_le16((void *)FSP_DONE, BIT(0), true, + SF_TIMEOUT_MS, false); + + writew(BIT(0), FSP_DONE_CLR); + return ret; +} + +static void fsp_setup(void) +{ + writew(CTRL_BASE, FSP_CTRL); + writew(0, FSP_CTRL2); + writew(0, FSP_CTRL4); +} + +static void fsp_load(const u8 *wbuf, unsigned int wlen) +{ + unsigned int i; + + for (i = 0; i < wlen; i += 2) + writew(wbuf[i] | (i + 1 < wlen ? wbuf[i + 1] << 8 : 0), + FSP_WBF(i)); +} + +#ifdef CONFIG_SS_I6C_FAMILY +static void sn_cs(bool high) +{ + clrsetbits_le16(QSPI_BURST, QSPI_CS_SW | QSPI_CS_HIGH, + QSPI_CS_SW | (high ? QSPI_CS_HIGH : 0)); +} +#else +static void sn_cs(bool high) +{ +} +#endif + +/* One FSP run: wlen bytes out, then rlen back, up to 10 of each */ +static int fsp_run(const u8 *wbuf, unsigned int wlen, u8 *rbuf, + unsigned int rlen) +{ + unsigned int i; + int ret; + + fsp_setup(); + fsp_load(wbuf, wlen); + writew(wlen, FSP_WBF_SIZE); + writew(rlen, FSP_RBF_SIZE); + writew(BIT(0), FSP_TRIGGER); + ret = fsp_wait(); + for (i = 0; !ret && i < rlen; i++) + rbuf[i] = readw(FSP_RBF(i)) >> (i & 1 ? 8 : 0); + return ret; +} + +/* One flash command */ +static int fsp_cmd(const u8 *wbuf, unsigned int wlen, u8 *rbuf, + unsigned int rlen) +{ + int ret; + + sn_cs(false); + ret = fsp_run(wbuf, wlen, rbuf, rlen); + sn_cs(true); + return ret; +} + +static int sn_cmd_addr(u8 op, u32 row) +{ + u8 cmd[4] = { op, row >> 16, row >> 8, row }; + + return fsp_cmd(cmd, sizeof(cmd), NULL, 0); +} + +static int sn_get_status(u8 *status) +{ + u8 cmd[2] = { CMD_GET_FEATURE, REG_STATUS }; + ulong start = get_timer(0); + int ret; + + do { + ret = fsp_cmd(cmd, sizeof(cmd), status, 1); + if (ret) + return ret; + if (!(*status & ST_BUSY)) + return 0; + WATCHDOG_RESET(); + } while (get_timer(start) < SF_TIMEOUT_MS); + return -ETIMEDOUT; +} + +static int sn_unlock(void) +{ + u8 op = CMD_WREN; + u8 cmd[3] = { CMD_SET_FEATURE, REG_PROTECT, 0 }; + int ret = fsp_cmd(&op, 1, NULL, 0); + + return ret ? ret : fsp_cmd(cmd, sizeof(cmd), NULL, 0); +} + +static void sn_die_select(struct ms_spinand *ms, u32 row) +{ + u8 cmd[2] = { CMD_DIE_SELECT, row >= ms->blocks * ms->blk_pages / 2 }; + + if (ms->dies) + fsp_cmd(cmd, sizeof(cmd), NULL, 0); +} + +/* On two-plane parts odd blocks are in plane 1, a column address bit */ +static u16 sn_column(struct ms_spinand *ms, u32 row) +{ + return ms->planes && (row / ms->blk_pages & 1) ? BIT(12) : 0; +} + +static void bdma_start(u16 path, u32 src, u32 dst, u32 len) +{ + writew(0, BDMA_CTRL); + writew(path, BDMA_PATH); + /* channel 0 to MIU0: 0 on every die, as the vendor's SPI NAND driver + * (drvSPINAND_common_hal.c) writes it, unlike its NOR flash_isp */ + writew(0, BDMA_PATH2); + writew(src & 0xffff, BDMA_SRC_L); + writew(src >> 16, BDMA_SRC_H); + writew(dst & 0xffff, BDMA_DST_L); + writew(dst >> 16, BDMA_DST_H); + writew(len & 0xffff, BDMA_LEN_L); + writew(len >> 16, BDMA_LEN_H); + writew(BDMA_TRIGGER, BDMA_CTRL); +} + +static int bdma_wait(void) +{ + int ret = wait_for_bit_le16((void *)BDMA_STATUS, BDMA_DONE, true, + SF_TIMEOUT_MS, false); + + writew(BDMA_DONE, BDMA_STATUS); + return ret; +} + +/* Read from the page cache, the buffer aligned for BDMA */ +static int sn_cache_read(u16 column, u8 *buf, unsigned int len) +{ + int ret; + + writew(QSPI_FUNC_CACHE, QSPI_FUNC); + writew(QSPI_CKG_DUMMY, QSPI_CKG); + writew(IS_ENABLED(CONFIG_SS_I6C_FAMILY) ? QSPI_MODE_NORMAL : + QSPI_MODE_FAST, QSPI_MODE); + + sn_cs(false); + bdma_start(BDMA_PATH_SPI_MIU, column, SS_MIU_ADDR(buf), len); + ret = bdma_wait(); + sn_cs(true); + return ret; +} + +static int sn_page_read(struct ms_spinand *ms, u32 row, bool main_area) +{ + u16 column = sn_column(ms, row); + int ret; + + sn_die_select(ms, row); + ret = sn_cmd_addr(CMD_PAGE_READ, row); + if (!ret) + ret = sn_get_status(&ms->status); + if (!ret && main_area) + ret = sn_cache_read(column, ms->buf, ms->page_size); + if (!ret) + ret = sn_cache_read(column + ms->page_size, + ms->buf + ms->page_size, ms->spare_size); + return ret; +} + +#ifdef CONFIG_SS_I6C_FAMILY +/* A page load, the chip select held by hand around it; the FSP fires first */ +static int sn_program_load(u16 column, const u8 *buf, unsigned int len) +{ + u8 cmd[3] = { CMD_PROGRAM_LOAD, column >> 8, column }; + unsigned int off = 0; + int ret; + + sn_cs(false); + ret = fsp_run(cmd, sizeof(cmd), NULL, 0); + + while (!ret && off < len) { + unsigned int n = min_t(unsigned int, len - off, BDMA_CHUNK); + int bdma; + + writew(OUT_EN, FSP_OUT); + writew(n + 1, FSP_OUT_SIZE); + fsp_setup(); + writew(0, FSP_WBF_SIZE); + writew(0, FSP_RBF_SIZE); + writew(BIT(0), FSP_TRIGGER); + + bdma_start(BDMA_PATH_MIU_FSP, SS_MIU_ADDR(buf + off), 0, n); + bdma = bdma_wait(); + ret = fsp_wait(); + if (!ret) + ret = bdma; + off += n; + } + + writew(0, FSP_OUT); + writew(0, FSP_OUT_SIZE); + sn_cs(true); + return ret; +} +#else +/* + * A page load: the command in one FSP run, the data in as many outside-buffer + * runs from BDMA, the load held open across them by QSPI's burst bit. QSPI's + * chip select timeout is off meanwhile. OUT_SIZE counts one more than BDMA + * sends here, where it replaces the whole of an empty command. + */ +static int sn_program_load(u16 column, const u8 *buf, unsigned int len) +{ + u8 cmd[3] = { CMD_PROGRAM_LOAD, column >> 8, column }; + u16 timeout = readw(QSPI_TIMEOUT_H); + unsigned int off = 0; + int ret; + + if (timeout & QSPI_TIMEOUT_EN) + writew(QSPI_TIMEOUT_OFF, QSPI_TIMEOUT_H); + + writew(0, FSP_OUT_SIZE); + writew(0, FSP_OUT); + ret = fsp_run(cmd, sizeof(cmd), NULL, 0); + + while (!ret && off < len) { + unsigned int n = min_t(unsigned int, len - off, BDMA_CHUNK); + int bdma; + + writew(n + 1, FSP_OUT_SIZE); + writew(OUT_EN, FSP_OUT); + writew(QSPI_BURST_ON, QSPI_BURST); + writew(0, FSP_WBF_SIZE); + writew(0, FSP_RBF_SIZE); + writew(0, FSP_CTRL2); + + bdma_start(BDMA_PATH_MIU_FSP, SS_MIU_ADDR(buf + off), 0, n); + writew(BIT(0), FSP_TRIGGER); + + bdma = bdma_wait(); + ret = fsp_wait(); + if (!ret) + ret = bdma; + off += n; + } + + writew(0, FSP_OUT_SIZE); + writew(0, FSP_OUT); + writew(QSPI_BURST_OFF, QSPI_BURST); + if (timeout & QSPI_TIMEOUT_EN) + writew(timeout, QSPI_TIMEOUT_H); + return ret; +} + +#endif + +/* The page and, unless it is blank, its spare area */ +static int sn_page_program(struct ms_spinand *ms, u32 row) +{ + unsigned int len = ms->page_size + ms->spare_size; + u16 column = sn_column(ms, row); + u8 op = CMD_WREN; + int ret; + + if (memchr_inv(ms->buf + ms->page_size, 0xff, ms->spare_size) == NULL) + len = ms->page_size; + + ss_miu_flush(); + sn_die_select(ms, row); + ret = sn_unlock(); + if (!ret) + ret = sn_program_load(column, ms->buf, len); + if (!ret) + ret = fsp_cmd(&op, 1, NULL, 0); + if (!ret) + ret = sn_cmd_addr(CMD_PROGRAM_EXEC, row); + if (!ret) + ret = sn_get_status(&ms->status); + return ret ? ret : ms->status & ST_P_FAIL ? -EIO : 0; +} + +static int sn_block_erase(struct ms_spinand *ms, u32 row) +{ + u8 op = CMD_WREN; + int ret; + + sn_die_select(ms, row); + ret = sn_unlock(); + if (!ret) + ret = fsp_cmd(&op, 1, NULL, 0); + if (!ret) + ret = sn_cmd_addr(CMD_BLOCK_ERASE, row); + if (!ret) + ret = sn_get_status(&ms->status); + return ret ? ret : ms->status & ST_E_FAIL ? -EIO : 0; +} + +static void ms_cmdfunc(struct mtd_info *mtd, unsigned int command, int column, + int page) +{ + struct ms_spinand *ms = nand_get_controller_data(mtd_to_nand(mtd)); + u8 cmd[2] = { CMD_RDID, 0 }; + + ms->show_status = false; + switch (command) { + case NAND_CMD_RESET: + cmd[0] = CMD_RESET; + fsp_cmd(cmd, 1, NULL, 0); + sn_get_status(&ms->status); + break; + case NAND_CMD_READID: + memset(ms->buf, 0, sizeof(ms->id)); + if (!column) + memcpy(ms->buf, ms->id, sizeof(ms->id)); + ms->pos = 0; + break; + case NAND_CMD_READ0: + ms->pos = column; + if (sn_page_read(ms, page, true)) + ms->status = ST_ECC_ERR; + break; + case NAND_CMD_READOOB: + ms->pos = ms->page_size + column; + if (sn_page_read(ms, page, false)) + ms->status = ST_ECC_ERR; + break; + case NAND_CMD_RNDOUT: + ms->pos = column; + break; + case NAND_CMD_SEQIN: + memset(ms->buf, 0xff, ms->page_size + ms->spare_size); + ms->page = page; + ms->pos = column; + break; + case NAND_CMD_RNDIN: + ms->pos = column; + break; + case NAND_CMD_PAGEPROG: + ms->failed = !!sn_page_program(ms, ms->page); + break; + case NAND_CMD_ERASE1: + ms->failed = !!sn_block_erase(ms, page); + break; + case NAND_CMD_ERASE2: + break; + case NAND_CMD_STATUS: + ms->show_status = true; + break; + } +} + +static u8 ms_status(struct ms_spinand *ms) +{ + return NAND_STATUS_READY | NAND_STATUS_WP | + (ms->failed ? NAND_STATUS_FAIL : 0); +} + +static u8 ms_read_byte(struct mtd_info *mtd) +{ + struct ms_spinand *ms = nand_get_controller_data(mtd_to_nand(mtd)); + + if (ms->show_status) + return ms_status(ms); + if (ms->pos >= ms->page_size + ms->spare_size) + return 0xff; + return ms->buf[ms->pos++]; +} + +static unsigned int ms_clamp(struct ms_spinand *ms, unsigned int len) +{ + unsigned int size = ms->page_size + ms->spare_size; + + return ms->pos >= size ? 0 : min(len, size - ms->pos); +} + +static void ms_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct ms_spinand *ms = nand_get_controller_data(mtd_to_nand(mtd)); + unsigned int n = ms_clamp(ms, len); + + memcpy(buf, ms->buf + ms->pos, n); + memset(buf + n, 0xff, len - n); + ms->pos += n; +} + +static void ms_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct ms_spinand *ms = nand_get_controller_data(mtd_to_nand(mtd)); + unsigned int n = ms_clamp(ms, len); + + memcpy(ms->buf + ms->pos, buf, n); + ms->pos += n; +} + +static void ms_select_chip(struct mtd_info *mtd, int chip) +{ +} + +static int ms_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +{ + return ms_status(nand_get_controller_data(chip)); +} + +/* + * The core's READ0 has brought the page in: hand it over with what the + * chip's ECC said of it. A corrected read is counted without looking like + * wear, like the vendor's driver; the chip does not say how many bits. + */ +static int ms_read_page(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + struct ms_spinand *ms = nand_get_controller_data(chip); + u8 ecc = ms->status & ST_ECC; + + memcpy(buf, ms->buf, ms->page_size); + if (oob_required) + memcpy(chip->oob_poi, ms->buf + ms->page_size, ms->spare_size); + + if (ecc == ST_ECC_ERR) { + mtd->ecc_stats.failed++; + return 0; + } + if (ecc) { + mtd->ecc_stats.corrected++; + return 1; + } + return 0; +} + +static int ms_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + u8 *buf, int oob_required, int page) +{ + struct ms_spinand *ms = nand_get_controller_data(chip); + + memcpy(buf, ms->buf, ms->page_size); + if (oob_required) + memcpy(chip->oob_poi, ms->buf + ms->page_size, ms->spare_size); + return 0; +} + +static int ms_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const u8 *buf, int oob_required, int page) +{ + struct ms_spinand *ms = nand_get_controller_data(chip); + + memcpy(ms->buf, buf, ms->page_size); + memcpy(ms->buf + ms->page_size, chip->oob_poi, ms->spare_size); + return 0; +} + +/* The chip's on-die ECC, in the spare area */ +static struct nand_ecclayout ms_ecclayout = { + .eccbytes = 32, + .eccpos = { 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 }, + .oobfree = { { 2, 6 }, { 16, 8 }, { 32, 8 }, { 48, 8 } }, +}; + +/* BDMA needs its buffer here, so the SNI's page goes through ms->buf */ +static int ms_read_sni(struct ms_spinand *ms) +{ + const struct ms_sni *sni = (void *)(ms->buf + SNI_TAG_LEN); + unsigned int i; + + ms->blk_pages = SNI_DEFAULT_BLK_PAGES; + ms->blocks = 1; + for (i = 0; i < SNI_COPIES; i++) { + u32 row = i * 2 * ms->blk_pages; + u8 cmd[4] = { CMD_PAGE_READ, row >> 16, row >> 8, row }; + + if (fsp_cmd(cmd, sizeof(cmd), NULL, 0) || + sn_get_status(&ms->status) || + (ms->status & ST_ECC) == ST_ECC_ERR || + sn_cache_read(0, ms->buf, 512)) + continue; + if (!memcmp(ms->buf, "SNIB", 4)) { + /* Iford's CIS: the boot header, then the SNIF profile */ + ms->spare_size = get_unaligned_le16(ms->buf + 0x34); + ms->page_size = get_unaligned_le16(ms->buf + 0x36); + ms->blk_pages = get_unaligned_le16(ms->buf + 0x3A); + ms->blocks = get_unaligned_le16(ms->buf + 0x3C); + ms->planes = 0; + return 0; + } + if (memcmp(ms->buf, SNI_TAG, SNI_TAG_LEN)) + continue; + + ms->page_size = le16_to_cpu(sni->page); + ms->spare_size = le16_to_cpu(sni->spare); + ms->blk_pages = le16_to_cpu(sni->blk_pages); + ms->blocks = le16_to_cpu(sni->blocks); + ms->planes = sni->planes; + return 0; + } + return -ENODEV; +} + +static int ms_nand_probe(struct ms_spinand *ms) +{ + static const u8 rdid[2] = { CMD_RDID, 0 }; + u8 op = CMD_RESET; + int ret; + + if (!IS_ENABLED(CONFIG_SS_I6C_FAMILY)) { + writew(0, CHIP_ALL_PAD_IN); + writew(0, QSPI_CS_SEL); + writew(0x08, PM_SPI_CZ); + } + + ret = fsp_cmd(&op, 1, NULL, 0); + if (!ret) + ret = sn_get_status(&ms->status); + if (!ret) + ret = fsp_cmd(rdid, sizeof(rdid), ms->id, 3); + if (ret) + return ret; + + /* + * Winbond W25N: an IPL may leave the buffer mode off (feature 0xB0 + * bit 3), and then a cache read streams on and ignores the column + */ + if (ms->id[0] == 0xEF) { + u8 get[2] = { CMD_GET_FEATURE, REG_CONFIG }; + u8 set[3] = { CMD_SET_FEATURE, REG_CONFIG, 0 }; + u8 cfg; + + if (!fsp_cmd(get, sizeof(get), &cfg, 1) && !(cfg & CFG_BUF)) { + set[2] = cfg | CFG_BUF; + fsp_cmd(set, sizeof(set), NULL, 0); + } + } + + /* Winbond W25M and GigaDevice's stacked parts: the vendor's test */ + ms->dies = (ms->id[0] == 0xEF && ms->id[1] == 0xAB && + ms->id[2] == 0x21) || + (ms->id[0] == 0xC8 && ms->id[1] == 0x0A); + return ms_read_sni(ms); +} + +void board_nand_init(void) +{ + struct ms_spinand *ms = &ms_nand; + struct nand_chip *chip = &ms->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_flash_dev *dev = &ms->ids[0]; + + ms->buf = memalign(ARCH_DMA_MINALIGN < 16 ? 16 : ARCH_DMA_MINALIGN, + SZ_16K); + if (!ms->buf) + return; + if (ms_nand_probe(ms)) { + printf("NAND: no SPI NAND with an SNI\n"); + return; + } + /* 64 bytes take ms_ecclayout, 128 the core's; it has none for others */ + if (ms->page_size + ms->spare_size > SZ_16K || + (ms->spare_size != 64 && ms->spare_size != 128) || + !ms->page_size || !ms->blk_pages || !ms->blocks) { + printf("NAND: SNI says %u+%u bytes, %u pages, %u blocks\n", + ms->page_size, ms->spare_size, ms->blk_pages, + ms->blocks); + return; + } + + dev->name = "SPI NAND"; + dev->mfr_id = ms->id[0]; + dev->dev_id = ms->id[1]; + dev->id_len = 2; + dev->pagesize = ms->page_size; + dev->chipsize = ms->page_size * ms->blk_pages / 1024 * ms->blocks / + 1024; + dev->erasesize = ms->page_size * ms->blk_pages; + dev->oobsize = ms->spare_size; + + nand_set_controller_data(chip, ms); + chip->cmdfunc = ms_cmdfunc; + chip->read_byte = ms_read_byte; + chip->read_buf = ms_read_buf; + chip->write_buf = ms_write_buf; + chip->select_chip = ms_select_chip; + chip->waitfunc = ms_waitfunc; + chip->options = NAND_NO_SUBPAGE_WRITE; + + if (nand_scan_ident(mtd, 1, ms->ids)) + return; + + /* The ID's third byte is the part's, not an ONFI cell type */ + chip->bits_per_cell = 1; + chip->bbt_options &= ~NAND_BBT_SCANLASTPAGE; + + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = ms->page_size; + chip->ecc.bytes = ms_ecclayout.eccbytes; + chip->ecc.strength = 4; + if (ms->spare_size == 64) + chip->ecc.layout = &ms_ecclayout; + chip->ecc.read_page = ms_read_page; + chip->ecc.read_page_raw = ms_read_page_raw; + chip->ecc.write_page = ms_write_page; + chip->ecc.write_page_raw = ms_write_page; + + if (nand_scan_tail(mtd)) + return; + nand_register(0, mtd); +} diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index 4dece1b20676..bf8e04484a85 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -192,6 +192,8 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_SANDISK, "SanDisk"}, {NAND_MFR_INTEL, "Intel"}, {NAND_MFR_ATO, "ATO"}, + {NAND_MFR_GIGADEVICE, "GigaDevice"}, + {NAND_MFR_WINBOND, "Winbond"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 39057b749688..da89e1d46ee9 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -37,10 +37,10 @@ config SPI_FLASH If unsure, say N config MS_SFLASH - bool "SigmaStar infinity3 SPI NOR on the FSP" + bool "SigmaStar SPI NOR on the FSP" depends on ARCH_SIGMASTAR && !SPI_FLASH && !DM_SPI_FLASH help - The SPI NOR the SigmaStar infinity3 SoCs boot from: read through + The SPI NOR the SigmaStar SoCs boot from: read through the XIU window, erased and programmed by the FSP and BDMA. The driver provides spi_flash_probe() directly, without the SPI and spi-nor layers. diff --git a/drivers/mtd/spi/ms_sflash.c b/drivers/mtd/spi/ms_sflash.c index bbf7ff447f4d..71c8bebe360c 100644 --- a/drivers/mtd/spi/ms_sflash.c +++ b/drivers/mtd/spi/ms_sflash.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SPI NOR behind the FSP of the SigmaStar infinity3. + * SPI NOR behind the FSP of the SigmaStar SoCs. * * The FSP ("flash serial programmer") runs up to three flash commands in * one go from a 10-byte write buffer: sizes 0-2 say how many of its bytes @@ -14,12 +14,20 @@ * Reads go through the XIU window, the flash mapped at 0x14000000 in the * read mode the IPL set up, as the vendor kernel reads it. * - * After the vendor U-Boot and kernel drivers/mstar/flash_isp (infinity3 - * halSERFLASH.c: FSP_READ_DIRECT, FSP_WRITE_BDMA). Like ak_sflash on + * After the vendor U-Boot and kernel drivers/mstar/flash_isp ( + * halSERFLASH.c: FSP_READ_DIRECT, FSP_WRITE_BDMA; the same FSP and BDMA + * registers on every die, the FSP's bank apart on infinity6e). Like ak_sflash on * openipc-anyka, this driver 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. * 3-byte addresses: parts up to 16 MiB. + * + * infinity6c differs: its IPL hands over with the chip select in software, + * so one FSP run is no longer one flash command. After the vendor's + * flash/nor/drvSPINOR.c and fsp_qspi, what its published U-Boot runs (its + * flash_isp/infinity6c does not describe that binary): each flash command + * is framed by hand, reads go by BDMA or the FSP since the XIU window would + * start a command per burst, and OUT_SIZE counts one more than BDMA sends. */ #include @@ -33,7 +41,7 @@ #include #include -#define FSP_REG(r) SS_REG(SS_BANK_FSP, r) +#define FSP_REG(r) SS_REG(ss_fsp_bank(), r) #define FSP_WBF(i) FSP_REG(0x60 + (i) / 2) /* bytes 0-9 */ #define FSP_RBF(i) FSP_REG(0x65 + (i) / 2) /* bytes 0-9 */ #define FSP_WBF_SIZE FSP_REG(0x6a) @@ -62,11 +70,24 @@ #define OUT_MODE_BDMA (1 << 8) #define OUT_EN BIT(12) +/* infinity6c: the QSPI bank next to the FSP, the chip select in software */ +#define QSPI_REG(r) SS_REG(ss_fsp_bank() + 1, r) +#define QSPI_CS QSPI_REG(0x0a) +#define QSPI_CS_SW BIT(0) +#define QSPI_CS_HIGH BIT(1) +#define QSPI_CKG QSPI_REG(0x70) +#define QSPI_CKG_DUMMY(n) (BIT(4) | ((n) - 1)) +#define QSPI_MODE QSPI_REG(0x72) +#define QSPI_MODE_FAST 0x01 +#define QSPI_FUNC QSPI_REG(0x7d) +#define QSPI_FUNC_DUMMY 0x1000 + /* BDMA channel 0 */ #define BDMA_REG(r) SS_REG(SS_BANK_BDMA, r) #define BDMA_CTRL BDMA_REG(0x00) #define BDMA_STATUS BDMA_REG(0x01) #define BDMA_PATH BDMA_REG(0x02) +#define BDMA_PATH2 BDMA_REG(0x03) #define BDMA_SRC_L BDMA_REG(0x04) #define BDMA_SRC_H BDMA_REG(0x05) #define BDMA_DST_L BDMA_REG(0x06) @@ -75,7 +96,13 @@ #define BDMA_LEN_H BDMA_REG(0x09) #define BDMA_TRIGGER BIT(0) #define BDMA_DONE BIT(3) +#ifdef CONFIG_SS_IFORD_FAMILY +#define BDMA_PATH_MIU_FSP 0x2B41 /* MIU by channel 1, to the FSP */ +#else #define BDMA_PATH_MIU_FSP 0x2B40 /* MIU, 16 bytes wide, to the FSP */ +#endif +#define BDMA_PATH_SPI_MIU 0x4135 /* flash, 8 wide, to MIU, 16 wide */ +#define BDMA_PATH2_CH0_MIU 0x8000 /* infinity6*: channel 0 to the MIU */ #define SZ_PAGE 256 #define SZ_SECTOR SZ_64K @@ -84,6 +111,7 @@ #define CMD_PP 0x02 #define CMD_RDSR 0x05 #define CMD_RDSR2 0x35 +#define CMD_FAST_READ 0x0B #define CMD_WREN 0x06 #define CMD_RDID 0x9F #define CMD_SE_64K 0xD8 @@ -94,6 +122,10 @@ /* Longer than any 64 KiB erase or page program of the parts in use */ #define SF_TIMEOUT_MS 3000 +/* A BDMA read of a whole 16 MiB part, at the slowest clock an IPL sets */ +#define SF_READ_TIMEOUT_MS 30000 + +#define FSP_BUF_SIZE 10 static int fsp_wait(void) { @@ -127,12 +159,104 @@ static int fsp_run(const u8 *wbuf, unsigned int wlen, u16 wsizes, u16 rsizes, return ret; } +/* BDMA channel 0; the DDR's address is the MIU's */ +static void bdma_start(u16 path, u32 src, u32 dst, u32 len) +{ + writew(0, BDMA_CTRL); + writew(path, BDMA_PATH); +#if defined(CONFIG_SS_INFINITY2M) || defined(CONFIG_SS_IFADO) || \ + defined(CONFIG_SS_I6C_FAMILY) + writew(0, BDMA_PATH2); +#elif !defined(CONFIG_SS_INFINITY3) + writew(BDMA_PATH2_CH0_MIU, BDMA_PATH2); +#endif + writew(src & 0xffff, BDMA_SRC_L); + writew(src >> 16, BDMA_SRC_H); + writew(dst & 0xffff, BDMA_DST_L); + writew(dst >> 16, BDMA_DST_H); + writew(len & 0xffff, BDMA_LEN_L); + writew(len >> 16, BDMA_LEN_H); + writew(BDMA_TRIGGER, BDMA_CTRL); +} + +static int bdma_wait(unsigned int timeout_ms) +{ + int ret = wait_for_bit_le16((void *)BDMA_STATUS, BDMA_DONE, true, + timeout_ms, false); + + writew(BDMA_DONE, BDMA_STATUS); + return ret; +} + +#ifdef CONFIG_SS_FSP_SW_CS +static void sf_cs(bool high) +{ + clrsetbits_le16(QSPI_CS, QSPI_CS_SW | QSPI_CS_HIGH, + QSPI_CS_SW | (high ? QSPI_CS_HIGH : 0)); +} + +/* With the chip select held: bytes out, as many FSP runs as they take */ +static int sf_send(const u8 *buf, unsigned int len) +{ + while (len) { + unsigned int n = min_t(unsigned int, len, FSP_BUF_SIZE); + int ret = fsp_run(buf, n, FSP_SIZES(n, 0, 0), 0, 0, NULL, 0); + + if (ret) + return ret; + buf += n; + len -= n; + } + return 0; +} + +static int sf_recv(u8 *buf, size_t len) +{ + while (len) { + unsigned int n = min_t(size_t, len, FSP_BUF_SIZE); + int ret = fsp_run(NULL, 0, 0, FSP_SIZES(n, 0, 0), 0, buf, n); + + if (ret) + return ret; + WATCHDOG_RESET(); + buf += n; + len -= n; + } + return 0; +} + +/* One flash command, framed by the chip select */ +static int sf_cmd(const u8 *tx, unsigned int txlen, u8 *rx, size_t rxlen) +{ + int ret; + + sf_cs(false); + ret = sf_send(tx, txlen); + if (!ret) + ret = sf_recv(rx, rxlen); + sf_cs(true); + return ret; +} + +static int sf_wren(void) +{ + u8 op = CMD_WREN; + + return sf_cmd(&op, 1, NULL, 0); +} + +static int sf_read_cmd(u8 op, u8 *buf, unsigned int len) +{ + return sf_cmd(&op, 1, buf, len); +} +#else /* A command alone, reading len (up to 10) bytes back */ static int sf_read_cmd(u8 op, u8 *buf, unsigned int len) { return fsp_run(&op, 1, FSP_SIZES(1, 0, 0), FSP_SIZES(len, 0, 0), 0, buf, len); } +#endif static int sf_wait_ready(void) { @@ -149,6 +273,104 @@ static int sf_wait_ready(void) return -ETIMEDOUT; } +/* BDMA reads its source from DDR: a page goes through here */ +static u8 sf_page[SZ_PAGE] __aligned(64); + +#ifdef CONFIG_SS_FSP_SW_CS +/* Short of this, or unaligned, the vendor's driver goes by the FSP */ +#define SF_BDMA_MIN 64 +#define SF_BDMA_ALIGN 16 + +static int sf_erase_sector(u32 addr) +{ + u8 cmd[4] = { CMD_SE_64K, addr >> 16, addr >> 8, addr }; + int ret = sf_wren(); + + return ret ? ret : sf_cmd(cmd, sizeof(cmd), NULL, 0); +} + +/* The rest of a page program, chip select held; sf_page is aligned */ +static int sf_program_bdma(unsigned int len) +{ + int ret, bdma; + + ss_miu_flush(); + writew(CTRL_BASE, FSP_CTRL); + writew(0, FSP_WBF_SIZE); + writew(0, FSP_RBF_SIZE); + writew(OUT_EN, FSP_OUT); + writew(len + 1, FSP_OUT_SIZE); + writew(BIT(0), FSP_TRIGGER); + + bdma_start(BDMA_PATH_MIU_FSP, SS_MIU_ADDR(sf_page), 0, len); + bdma = bdma_wait(SF_TIMEOUT_MS); + ret = fsp_wait(); + + writew(0, FSP_OUT); + writew(0, FSP_OUT_SIZE); + return ret ? ret : bdma; +} + +static int sf_program_page(u32 to, const u8 *buf, unsigned int len) +{ + u8 cmd[4] = { CMD_PP, to >> 16, to >> 8, to }; + int ret; + + memcpy(sf_page, buf, len); + ret = sf_wren(); + if (ret) + return ret; + + sf_cs(false); + ret = sf_send(cmd, sizeof(cmd)); + if (!ret) + ret = len < SF_BDMA_MIN ? sf_send(sf_page, len) : + sf_program_bdma(len); + sf_cs(true); + return ret ? ret : sf_wait_ready(); +} + +static int sf_read_fsp(u32 from, u8 *buf, size_t len) +{ + u8 cmd[5] = { CMD_FAST_READ, from >> 16, from >> 8, from, 0 }; + + return sf_cmd(cmd, sizeof(cmd), buf, len); +} + +/* QSPI's fast read, 8 dummy cycles: what the vendor's driver reads with */ +static int sf_read_bdma(u32 from, u8 *buf, size_t len) +{ + int ret; + + writew(QSPI_FUNC_DUMMY, QSPI_FUNC); + writew(QSPI_CKG_DUMMY(8), QSPI_CKG); + writew(QSPI_MODE_FAST, QSPI_MODE); + + sf_cs(false); + bdma_start(BDMA_PATH_SPI_MIU, from, SS_MIU_ADDR(buf), len); + ret = bdma_wait(SF_READ_TIMEOUT_MS); + sf_cs(true); + return ret; +} + +static int ms_sf_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + int ret; + + if (from > mtd->size || len > mtd->size - from) + return -EINVAL; + if (len < SF_BDMA_MIN || from % SF_BDMA_ALIGN || + (ulong)buf % SF_BDMA_ALIGN) + ret = sf_read_fsp(from, buf, len); + else + ret = sf_read_bdma(from, buf, len); + if (ret) + return ret; + *retlen = len; + return 0; +} +#else /* * WREN, the command with its address, RDSR polled to the end: an erase, * and a page program whose data comes from BDMA (the dummy byte 5 is @@ -165,19 +387,11 @@ static int sf_wren_cmd(u8 op, u32 addr, bool bdma) NULL, 0); } -static int ms_sf_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int sf_erase_sector(u32 addr) { - if (from > mtd->size || len > mtd->size - from) - return -EINVAL; - memcpy(buf, (void *)(SS_XIU_FLASH_BASE + (ulong)from), len); - *retlen = len; - return 0; + return sf_wren_cmd(CMD_SE_64K, addr, false); } -/* BDMA reads its source from DDR: a page goes through here */ -static u8 sf_page[SZ_PAGE] __aligned(64); - static int sf_program_page(u32 to, const u8 *buf, unsigned int len) { int ret, bdma; @@ -185,28 +399,29 @@ static int sf_program_page(u32 to, const u8 *buf, unsigned int len) memcpy(sf_page, buf, len); ss_miu_flush(); - writew(0, BDMA_CTRL); - writew(BDMA_PATH_MIU_FSP, BDMA_PATH); - writew(SS_MIU_ADDR(sf_page) & 0xffff, BDMA_SRC_L); - writew(SS_MIU_ADDR(sf_page) >> 16 & 0x0fff, BDMA_SRC_H); - writew(0, BDMA_DST_L); - writew(0, BDMA_DST_H); - writew(len, BDMA_LEN_L); - writew(0, BDMA_LEN_H); - writew(BDMA_TRIGGER, BDMA_CTRL); + bdma_start(BDMA_PATH_MIU_FSP, SS_MIU_ADDR(sf_page), 0, len); writew(len, FSP_OUT_SIZE); writew(OUT_REPLACE(5) | OUT_MODE_BDMA | OUT_EN, FSP_OUT); ret = sf_wren_cmd(CMD_PP, to, true); - bdma = wait_for_bit_le16((void *)BDMA_STATUS, BDMA_DONE, true, - SF_TIMEOUT_MS, false); - writew(BDMA_DONE, BDMA_STATUS); + bdma = bdma_wait(SF_TIMEOUT_MS); writew(0, FSP_OUT_SIZE); writew(0, FSP_OUT); return ret ? ret : bdma ? bdma : sf_wait_ready(); } +static int ms_sf_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + if (from > mtd->size || len > mtd->size - from) + return -EINVAL; + memcpy(buf, (void *)(SS_XIU_FLASH_BASE + (ulong)from), len); + *retlen = len; + return 0; +} +#endif + static int ms_sf_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -242,7 +457,7 @@ static int ms_sf_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; end = instr->addr + instr->len; for (; addr < end; addr += SZ_SECTOR) { - ret = sf_wren_cmd(CMD_SE_64K, addr, false); + ret = sf_erase_sector(addr); if (!ret) ret = sf_wait_ready(); if (ret) { @@ -257,6 +472,20 @@ static int ms_sf_erase(struct mtd_info *mtd, struct erase_info *instr) #define MFR_GIGADEVICE 0xc8 #define MFR_WINBOND 0xef +/* wbuf: WREN, WRSR, n status bytes, RDSR */ +static int sf_write_status(const u8 *wbuf, unsigned int n) +{ +#ifdef CONFIG_SS_FSP_SW_CS + int ret = sf_wren(); + + return ret ? ret : sf_cmd(wbuf + 1, 1 + n, NULL, 0); +#else + return fsp_run(wbuf, 3 + n, FSP_SIZES(1, 1 + n, 1), FSP_SIZES(0, 0, 1), + CTRL_CMD2 | CTRL_CMD3 | CTRL_RDSR(2) | CTRL_FSCHK, + NULL, 0); +#endif +} + /* * Block protection left on by a vendor loader: the BP and SRWD bits * cleared, every other status bit kept (Macronix's quad enable is in @@ -280,9 +509,7 @@ static void sf_unprotect(u8 mfr) n = 2; } wbuf[2 + n] = CMD_RDSR; - if (fsp_run(wbuf, 3 + n, FSP_SIZES(1, 1 + n, 1), FSP_SIZES(0, 0, 1), - CTRL_CMD2 | CTRL_CMD3 | CTRL_RDSR(2) | CTRL_FSCHK, NULL, 0) || - sf_wait_ready()) + if (sf_write_status(wbuf, n) || sf_wait_ready()) printf("SF: could not clear the block protection (SR %02x)\n", sr); } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1d81a3297959..5d2fce46e7e2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -439,10 +439,10 @@ config KSZ9477 of GbE switches using the I2C interface. config MS_EMAC - bool "SigmaStar infinity3 EMAC" + bool "SigmaStar EMAC" depends on ARCH_SIGMASTAR && !DM_ETH help - The 10/100 MAC of the SigmaStar infinity3 SoCs with their internal + The 10/100 MAC of the SigmaStar SoCs with their internal PHY, an Atmel AT91RM9200-style EMAC behind the RIU. config MVGBE diff --git a/drivers/net/ms_emac.c b/drivers/net/ms_emac.c index 3b76830aba56..9a541ad5aa87 100644 --- a/drivers/net/ms_emac.c +++ b/drivers/net/ms_emac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * The EMAC of the SigmaStar infinity3 and its internal ("Albany") PHY. + * The EMAC of the SigmaStar SoCs and their internal ("Albany") PHY. * * An Atmel AT91RM9200-style 10/100 MAC behind the RIU: register G (the AT91 * numbering) is two 16-bit RIU registers, bits 15:0 at +2G and 31:16 at @@ -14,8 +14,9 @@ * "ms_emac" for the mii command. * * After the vendor U-Boot 2015.01 (drivers/mstar/emac, mhal_emac.c of - * infinity3, CONFIG_ETHERNET_ALBANY and SOFTWARE_DESCRIPTOR as its - * infinity3_defconfig builds it). + * each die, CONFIG_ETHERNET_ALBANY and SOFTWARE_DESCRIPTOR as its + * _defconfig builds it). The dies differ in the PHY's banks + * (mach/sigmastar.h), the MAC clocks' registers and two PHY settings. */ #include @@ -33,6 +34,15 @@ #define EMAC_BASE SS_BANK(SS_BANK_EMAC0) +/* CLK_EMAC_RX and _TX in SCGPCTRL */ +#ifdef CONFIG_SS_I6C_FAMILY +#define SCGP_EMAC_RX 0x54 +#define SCGP_EMAC_TX 0x56 +#else +#define SCGP_EMAC_RX 0x44 +#define SCGP_EMAC_TX 0x46 +#endif + /* Registers, by their 32-bit (AT91) offset */ #define EMAC_CTL 0x00 #define EMAC_CFG 0x04 @@ -198,8 +208,8 @@ static const struct { u8 val; } ms_albany_init[] = { { SS_BANK_CLKGEN0, 0x84, 0x00 }, /* CLK_EMAC_AHB 123 MHz */ - { SS_BANK_SCGPCTRL, 0x44, 0x00 }, /* CLK_EMAC_RX from the PHY */ - { SS_BANK_SCGPCTRL, 0x46, 0x00 }, /* CLK_EMAC_TX from the PHY */ + { SS_BANK_SCGPCTRL, SCGP_EMAC_RX, 0x00 }, /* from the PHY */ + { SS_BANK_SCGPCTRL, SCGP_EMAC_TX, 0x00 }, /* from the PHY */ { SS_BANK_ALBANY1, 0xb4, 0x02 }, /* gain shift */ { SS_BANK_ALBANY1, 0x4f, 0x02 }, /* det max */ { SS_BANK_ALBANY1, 0x51, 0x01 }, /* det min */ @@ -244,6 +254,9 @@ static const struct { { SS_BANK_ALBANY1, 0x8e, 0x0e }, { SS_BANK_ALBANY1, 0x90, 0x04 }, { SS_BANK_ALBANY1, 0xc7, 0x80 }, /* clock source hv */ +#ifdef CONFIG_SS_INFINITY6E + { SS_BANK_ALBANY1, 0x10, 0x53 }, /* LMS and LPF scale factor */ +#endif }; static void ms_emac_clk_init(void) @@ -256,10 +269,29 @@ static void ms_emac_clk_init(void) /* RX shift and TX underrun fixes */ riu_writeb(riu_readb(SS_BANK_EMAC1, 0x00) | 0x10, SS_BANK_EMAC1, 0x00); riu_writeb(riu_readb(SS_BANK_EMAC1, 0x39) | 0x01, SS_BANK_EMAC1, 0x39); - - for (i = 0; i < ARRAY_SIZE(ms_albany_init); i++) - riu_writeb(ms_albany_init[i].val, ms_albany_init[i].bank, - ms_albany_init[i].reg); +#ifdef CONFIG_SS_IFORD_FAMILY + /* Iford's and Ifliegen's mhal_emac.c: the clock gate open, its RX/TX + * gating off */ + riu_writeb(riu_readb(SS_BANK_EMAC1, 0x00) | 0x01, SS_BANK_EMAC1, 0x00); + riu_writeb(riu_readb(SS_BANK_EMAC1, 0xf2) & ~0x05, SS_BANK_EMAC1, 0xf2); +#endif +#ifdef CONFIG_SS_IFORD + /* and on Iford the MCM control that drops the first frame after an + * RBQP reset */ + riu_writeb(0x00, 0x1132, 0x16); +#endif + + for (i = 0; i < ARRAY_SIZE(ms_albany_init); i++) { + u8 val = ms_albany_init[i].val; + +#ifndef CONFIG_SS_INFINITY3 + /* The sadc timer shares its register on the later dies */ + if (ms_albany_init[i].bank == SS_BANK_ALBANY2 && + ms_albany_init[i].reg == 0x80) + val |= riu_readb(SS_BANK_ALBANY2, 0x80) & 0x0f; +#endif + riu_writeb(val, ms_albany_init[i].bank, ms_albany_init[i].reg); + } /* CHIPTOP allpad_in off */ riu_writeb(riu_readb(SS_BANK_CHIPTOP, 0xa1) & 0x7f, SS_BANK_CHIPTOP, diff --git a/include/configs/openipc-common.h b/include/configs/openipc-common.h index 9b10960e9cab..6b8ca8a36899 100644 --- a/include/configs/openipc-common.h +++ b/include/configs/openipc-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Common OpenIPC configuration for the SigmaStar infinity3 targets. + * Common OpenIPC configuration for the SigmaStar targets. * * The single place for the default environment, kept in step with * include/configs/openipc-common.h on the openipc-hisilicon branch: the @@ -24,13 +24,16 @@ #define VENDOR "sigmastar" /* - * Kernel memory (mem=): all of it, as the vendor U-Boot passes. The media - * drivers take their buffers from the kernel. + * infinity3 kernel memory (mem=): all of it, as the vendor U-Boot passes. + * The media drivers take their buffers from the kernel. On the later dies + * ss_set_mem_env() sets memlx and memsz at every boot instead. */ -#if PHYS_SDRAM_1_SIZE == 0x08000000 -#define OPENIPC_OSMEM "128M" +#ifdef CONFIG_SS_MMA_BOOTARGS +#define OPENIPC_ENV_OSMEM "" +#elif PHYS_SDRAM_1_SIZE == 0x08000000 +#define OPENIPC_ENV_OSMEM "osmem=128M\0" #else -#define OPENIPC_OSMEM "64M" +#define OPENIPC_ENV_OSMEM "osmem=64M\0" #endif /* @@ -47,7 +50,19 @@ #define OPENIPC_FW_FILE "firmware.${soc}" -#define OPENIPC_BOOTARGSNFS "mem=\\${osmem} console=ttyS0,115200 panic=20 root=/dev/nfs rootfstype=nfs ip=${ipaddr}:::255.255.255.0::eth0 nfsroot=${serverip}:${nfsroot},v3,nolock rw \\${extras}" +/* + * What the kernel is told about memory: mem= on infinity3; LX_MEM and the + * MMA heap on the later dies, as OpenIPC's vendor U-Boot passes them. + */ +#ifdef CONFIG_SS_MMA_BOOTARGS +#define OPENIPC_MEMARGS_HEAD "" +#define OPENIPC_MEMARGS_TAIL " LX_MEM=\\${memlx} mma_heap=mma_heap_name0,miu=0,sz=\\${memsz} cma=2M" +#else +#define OPENIPC_MEMARGS_HEAD "mem=\\${osmem} " +#define OPENIPC_MEMARGS_TAIL "" +#endif + +#define OPENIPC_BOOTARGSNFS OPENIPC_MEMARGS_HEAD "console=ttyS0,115200 panic=20 root=/dev/nfs rootfstype=nfs ip=${ipaddr}:::255.255.255.0::eth0 nfsroot=${serverip}:${nfsroot},v3,nolock rw" OPENIPC_MEMARGS_TAIL " \\${extras}" /* NOR partition list; the reserved 'mtdparts' variable holds the full * ":" string, the bootargs compose it from mtdids/mtds. */ @@ -74,7 +89,7 @@ * mtdparts/bootargs. */ #define OPENIPC_ENV_COMMON \ "baseaddr=" __stringify(OPENIPC_BASEADDR) "\0" \ - "osmem=" OPENIPC_OSMEM "\0" \ + OPENIPC_ENV_OSMEM \ "board_name\0" \ "board=" CONFIG_PRODUCT_SOC "\0" \ "vendor=" VENDOR "\0" \ @@ -96,13 +111,93 @@ "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" +#ifdef CONFIG_ENV_IS_IN_NAND + +/* + * SPI NAND, in the layout of OpenIPC/u-boot-sigmastar, whose saved + * environments have to keep working: the boot partitions, the environment + * and one UBI device, with the kernel and a squashfs rootfs in volumes of + * their own. "mtdparts" holds the kernel argument whole. + */ +#ifdef CONFIG_SS_INFINITY2M +/* Its PNI puts the stages further up: env in blocks 34-36, then ubi */ +#define OPENIPC_NAND_MTDPARTS "nand0:4352k(boot),384k(env),-(ubi)" +#define OPENIPC_NAND_BOOTSIZE 0x440000 +#define OPENIPC_NAND_ROOTADDR 0x4A0000 +#define OPENIPC_NAND_ROOTSIZE 0x7B60000 +#define OPENIPC_NAND_ROOTDEV "mtdblock4" +#elif defined(CONFIG_SS_IFLIEGEN) +/* The Ifliegen SDK's: CIS, BOOT and BOOT_BAK, the environment at 0x500000 */ +#define OPENIPC_NAND_MTDPARTS "nand0:1280k(cis),1920k(boot0),1920k(boot1),256k(env),-(ubi)" +#define OPENIPC_NAND_BOOTSIZE 0x500000 +#define OPENIPC_NAND_ROOTADDR 0x540000 +#define OPENIPC_NAND_ROOTSIZE 0x7AC0000 +#define OPENIPC_NAND_ROOTDEV "mtdblock6" +#elif defined(CONFIG_SS_IFORD) +/* The Iford SDK's: CIS, BOOT and its copy, the environment at 0x580000, ubi */ +#define OPENIPC_NAND_MTDPARTS "nand0:1280k(cis),2176k(boot0),2176k(boot1),256k(env),-(ubi)" +#define OPENIPC_NAND_BOOTSIZE 0x580000 +#define OPENIPC_NAND_ROOTADDR 0x5C0000 +#define OPENIPC_NAND_ROOTSIZE 0x7A40000 +#define OPENIPC_NAND_ROOTDEV "mtdblock6" +#elif defined(CONFIG_SS_I6C_FAMILY) +/* The SDK's: the CIS, BOOT and BOOT_BAK, the environment, ubi */ +#define OPENIPC_NAND_MTDPARTS "nand0:1280k(cis),1792k(boot0),1792k(boot1),256k(env),-(ubi)" +#define OPENIPC_NAND_BOOTSIZE 0x4C0000 +#define OPENIPC_NAND_ROOTADDR 0x500000 +#define OPENIPC_NAND_ROOTSIZE 0x7B00000 +#define OPENIPC_NAND_ROOTDEV "mtdblock6" +#else +#define OPENIPC_NAND_MTDPARTS "nand0:1024k(boot0),1024k(boot1),256k(env),-(ubi)" +#define OPENIPC_NAND_BOOTSIZE 0x200000 +#define OPENIPC_NAND_ROOTADDR 0x240000 +#define OPENIPC_NAND_ROOTSIZE 0x7DC0000 +#define OPENIPC_NAND_ROOTDEV "mtdblock5" +#endif +/* + * The rootfs volume as the OpenIPC kernels number it: gluebi makes each + * UBI volume an MTD after the partitions, kernel then rootfs. A kernel + * without gluebi takes extras="ubi.block=0,rootfs root=/dev/ubiblock0_1 + * rootfstype=squashfs", the later root= winning. + */ + +/* As the firmware's own volume holds it, 34 LEBs of 126976 bytes */ +#define OPENIPC_KERNEL_VOLUME_SIZE "0x400000" + +#define CONFIG_BOOTARGS "console=ttyS0,115200 panic=20 root=/dev/" OPENIPC_NAND_ROOTDEV " init=/init ubi.mtd=ubi \\${mtdparts}" OPENIPC_MEMARGS_TAIL " \\${extras}" + +/* rootfs.ubi carries the kernel volume too */ +#define OPENIPC_FWUPD "fwupd=run ur\0" + +#define OPENIPC_LOADKERNEL "ubi part ubi; ubi read ${baseaddr} kernel" +#define OPENIPC_ENV_MEDIUM \ + "ubfile=u-boot-" CONFIG_PRODUCT_SOC "-nand.bin\0" \ + "urfile=rootfs.ubi." CONFIG_PRODUCT_SOC "\0" \ + "rootaddr=" __stringify(OPENIPC_NAND_ROOTADDR) "\0" \ + "rootsize=" __stringify(OPENIPC_NAND_ROOTSIZE) "\0" \ + "ubwrite=nand erase 0x0 " __stringify(OPENIPC_NAND_BOOTSIZE) "; nand write ${baseaddr} 0x0 ${filesize}\0" \ + "ukwrite=ubi part ubi; ubi write ${baseaddr} kernel ${filesize}\0" \ + "urwrite=nand erase ${rootaddr} ${rootsize}; nand write ${baseaddr} ${rootaddr} ${filesize}\0" \ + "loadkernel=" OPENIPC_LOADKERNEL "\0" \ + "mtdids=nand0=nand0\0" \ + "mtdparts=mtdparts=" OPENIPC_NAND_MTDPARTS "\0" \ + "bootargs=" CONFIG_BOOTARGS + +#else /* !CONFIG_ENV_IS_IN_NAND */ + /* * The flash's MTD name in the vendor kernels: drivers/mstar/flash_isp's - * (the vendor U-Boot passes mtdparts=NOR_FLASH:...) + * (the vendor U-Boot passes mtdparts=NOR_FLASH:...); the SGS kernels, which + * carry Iford, Ifliegen and Ifado (drivers/sgs_common/flash/nor), call it + * nor0. */ +#if defined(CONFIG_SS_IFORD_FAMILY) || defined(CONFIG_SS_IFADO) +#define SFC "nor0" +#else #define SFC "NOR_FLASH" +#endif -#define CONFIG_BOOTARGS "mem=\\${osmem} console=ttyS0,115200 panic=20 root=/dev/mtdblock3 rootfstype=squashfs init=/init mtdparts=\\${mtdparts} \\${extras}" +#define CONFIG_BOOTARGS OPENIPC_MEMARGS_HEAD "console=ttyS0,115200 panic=20 root=/dev/mtdblock3 rootfstype=squashfs init=/init mtdparts=\\${mtdparts}" OPENIPC_MEMARGS_TAIL " \\${extras}" /* Recovery: the rootfs is fetched first so its size selects the NOR schema */ #define OPENIPC_FWUPD "fwupd=run ur; run uk\0" @@ -127,6 +222,8 @@ "mtdparts=" SFC ":" OPENIPC_MTDPARTS "\0" \ "bootargs=" CONFIG_BOOTARGS +#endif /* CONFIG_ENV_IS_IN_NAND */ + #define CONFIG_BOOTCOMMAND "run bootflash" #define CONFIG_EXTRA_ENV_SETTINGS \ diff --git a/include/configs/sigmastar.h b/include/configs/sigmastar.h index 764464d50e87..a3389e998581 100644 --- a/include/configs/sigmastar.h +++ b/include/configs/sigmastar.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * SigmaStar infinity3: memory map, console and timer. The environment and + * SigmaStar: memory map, console and timer. The environment and * the rest of the OpenIPC configuration come from openipc-common.h. */ @@ -10,8 +10,16 @@ #include #define CONFIG_SYS_SDRAM_BASE SS_DDR_BASE -/* The DDR in the package: the MSC316s carry twice as much */ -#if defined(CONFIG_TARGET_MSC316DC) || defined(CONFIG_TARGET_MSC316DM) +/* + * The most DDR the part carries, for get_ram_size() on the dies that probe; + * the MSC316s and the SSD202D carry twice as much as their siblings. The + * later dies read the DDR's size from the MIU. + */ +#if defined(CONFIG_TARGET_SSR621Q) +#define PHYS_SDRAM_1_SIZE 0x10000000 +#elif defined(CONFIG_TARGET_MSC316DC) || defined(CONFIG_TARGET_MSC316DM) || \ + defined(CONFIG_TARGET_SSD202D) || defined(CONFIG_TARGET_SSC375) || \ + defined(CONFIG_TARGET_SSC034A) #define PHYS_SDRAM_1_SIZE 0x08000000 #else #define PHYS_SDRAM_1_SIZE 0x04000000 @@ -27,6 +35,10 @@ #define CONFIG_SYS_NS16550_CLK SS_UART_HZ #define CONFIG_SYS_NS16550_COM1 SS_UART0_BASE +#ifdef CONFIG_ENV_IS_IN_NAND +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#endif + /* PIU timer 0, read by timer_read_counter() */ #define CONFIG_SYS_TIMER_RATE SS_XTAL_HZ diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index aa45558b3d41..a174edfc94a2 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1040,6 +1040,8 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip) #define NAND_MFR_SANDISK 0x45 #define NAND_MFR_INTEL 0x89 #define NAND_MFR_ATO 0x9b +#define NAND_MFR_GIGADEVICE 0xc8 +#define NAND_MFR_WINBOND 0xef /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 diff --git a/openipc/ifado-cis.bin b/openipc/ifado-cis.bin new file mode 100644 index 000000000000..8a451b900a9f Binary files /dev/null and b/openipc/ifado-cis.bin differ diff --git a/openipc/ifado-ipl-cust.bin b/openipc/ifado-ipl-cust.bin new file mode 100644 index 000000000000..1a11ad59c92e Binary files /dev/null and b/openipc/ifado-ipl-cust.bin differ diff --git a/openipc/ifado-ipl.bin b/openipc/ifado-ipl.bin new file mode 100644 index 000000000000..0d31e2392898 Binary files /dev/null and b/openipc/ifado-ipl.bin differ diff --git a/openipc/ifado_config b/openipc/ifado_config new file mode 100644 index 000000000000..2ba0bf855307 --- /dev/null +++ b/openipc/ifado_config @@ -0,0 +1,6 @@ +# Ifado: what Dahua's U-Boot passes; the kernel takes a device tree +CONFIG_MACH_TYPE=1395 +# No SD slot on the camera the stages come from, and its pads unread +# CONFIG_MMC is not set +# CONFIG_MMC_MS_SDMMC is not set +# CONFIG_CMD_MMC is not set diff --git a/openipc/ifliegen-flash-list.nri b/openipc/ifliegen-flash-list.nri new file mode 100644 index 000000000000..343119b459e0 Binary files /dev/null and b/openipc/ifliegen-flash-list.nri differ diff --git a/openipc/ifliegen-flash.nri b/openipc/ifliegen-flash.nri new file mode 100644 index 000000000000..2e5a5c467ed3 Binary files /dev/null and b/openipc/ifliegen-flash.nri differ diff --git a/openipc/ifliegen-nand-ipl-cust.bin b/openipc/ifliegen-nand-ipl-cust.bin new file mode 100644 index 000000000000..cd6bd85a07f6 Binary files /dev/null and b/openipc/ifliegen-nand-ipl-cust.bin differ diff --git a/openipc/ifliegen-nand-ipl.bin b/openipc/ifliegen-nand-ipl.bin new file mode 100644 index 000000000000..0558f7bb6903 Binary files /dev/null and b/openipc/ifliegen-nand-ipl.bin differ diff --git a/openipc/ifliegen-nand-sni-list.bin b/openipc/ifliegen-nand-sni-list.bin new file mode 100644 index 000000000000..0fdaec3bdbb4 Binary files /dev/null and b/openipc/ifliegen-nand-sni-list.bin differ diff --git a/openipc/ifliegen-nand-sni.bin b/openipc/ifliegen-nand-sni.bin new file mode 100644 index 000000000000..d767b359e366 Binary files /dev/null and b/openipc/ifliegen-nand-sni.bin differ diff --git a/openipc/ifliegen-ssc034a-ipl-cust.bin b/openipc/ifliegen-ssc034a-ipl-cust.bin new file mode 100644 index 000000000000..d6cb7b374af8 Binary files /dev/null and b/openipc/ifliegen-ssc034a-ipl-cust.bin differ diff --git a/openipc/ifliegen-ssc034a-ipl.bin b/openipc/ifliegen-ssc034a-ipl.bin new file mode 100644 index 000000000000..4292f9c0740d Binary files /dev/null and b/openipc/ifliegen-ssc034a-ipl.bin differ diff --git a/openipc/ifliegen-ssc034b-ipl-cust.bin b/openipc/ifliegen-ssc034b-ipl-cust.bin new file mode 100644 index 000000000000..8773a1ef5f61 Binary files /dev/null and b/openipc/ifliegen-ssc034b-ipl-cust.bin differ diff --git a/openipc/ifliegen-ssc034b-ipl.bin b/openipc/ifliegen-ssc034b-ipl.bin new file mode 100644 index 000000000000..88532956229f Binary files /dev/null and b/openipc/ifliegen-ssc034b-ipl.bin differ diff --git a/openipc/ifliegen-tf-a.bin b/openipc/ifliegen-tf-a.bin new file mode 100644 index 000000000000..b4ed7f65412f Binary files /dev/null and b/openipc/ifliegen-tf-a.bin differ diff --git a/openipc/ifliegen_config b/openipc/ifliegen_config new file mode 100644 index 000000000000..06ec2ec45264 --- /dev/null +++ b/openipc/ifliegen_config @@ -0,0 +1,5 @@ +# Ifliegen: what its SDK's U-Boot passes (MACH_TYPE_IFACKEL); the kernel +# takes a device tree +CONFIG_MACH_TYPE=5120 +# UART0 out of the URDMA's DMA mode before the console +CONFIG_BOARD_EARLY_INIT_F=y diff --git a/openipc/ifliegen_nand_config b/openipc/ifliegen_nand_config new file mode 100644 index 000000000000..c0945605899c --- /dev/null +++ b/openipc/ifliegen_nand_config @@ -0,0 +1,4 @@ +# The Ifliegen SDK's layout (spinand.squashfs.tfa.partition.config): CIS, +# BOOT and BOOT_BAK of 0x1E0000 each, the environment at 0x500000, then ubi +CONFIG_ENV_OFFSET=0x500000 +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:1280k(cis),1920k(boot0),1920k(boot1),256k(env),-(ubi)" diff --git a/openipc/iford-cis.bin b/openipc/iford-cis.bin new file mode 100644 index 000000000000..303f93556d64 Binary files /dev/null and b/openipc/iford-cis.bin differ diff --git a/openipc/iford-ssc029a-ipl-cust.bin b/openipc/iford-ssc029a-ipl-cust.bin new file mode 100644 index 000000000000..d399e3ae4b8c Binary files /dev/null and b/openipc/iford-ssc029a-ipl-cust.bin differ diff --git a/openipc/iford-ssc029a-ipl.bin b/openipc/iford-ssc029a-ipl.bin new file mode 100644 index 000000000000..f1c72968304c Binary files /dev/null and b/openipc/iford-ssc029a-ipl.bin differ diff --git a/openipc/iford-ssc029a-nand-boot.bin b/openipc/iford-ssc029a-nand-boot.bin new file mode 100644 index 000000000000..152baf56977e Binary files /dev/null and b/openipc/iford-ssc029a-nand-boot.bin differ diff --git a/openipc/iford-ssc029a-nand-cis.bin b/openipc/iford-ssc029a-nand-cis.bin new file mode 100644 index 000000000000..a901a473d5cf Binary files /dev/null and b/openipc/iford-ssc029a-nand-cis.bin differ diff --git a/openipc/iford-ssc029b-ipl-cust.bin b/openipc/iford-ssc029b-ipl-cust.bin new file mode 100644 index 000000000000..d399e3ae4b8c Binary files /dev/null and b/openipc/iford-ssc029b-ipl-cust.bin differ diff --git a/openipc/iford-ssc029b-ipl.bin b/openipc/iford-ssc029b-ipl.bin new file mode 100644 index 000000000000..16e548fc3902 Binary files /dev/null and b/openipc/iford-ssc029b-ipl.bin differ diff --git a/openipc/iford-ssc029c-ipl-cust.bin b/openipc/iford-ssc029c-ipl-cust.bin new file mode 100644 index 000000000000..d243ac35bd4e Binary files /dev/null and b/openipc/iford-ssc029c-ipl-cust.bin differ diff --git a/openipc/iford-ssc029c-ipl.bin b/openipc/iford-ssc029c-ipl.bin new file mode 100644 index 000000000000..c816617eb65e Binary files /dev/null and b/openipc/iford-ssc029c-ipl.bin differ diff --git a/openipc/iford_config b/openipc/iford_config new file mode 100644 index 000000000000..2fc17a0c07bc --- /dev/null +++ b/openipc/iford_config @@ -0,0 +1,2 @@ +# Iford: its kernel takes a device tree, the machine number is not looked at +CONFIG_MACH_TYPE=1399 diff --git a/openipc/iford_nand_config b/openipc/iford_nand_config new file mode 100644 index 000000000000..ed435a9ab0a1 --- /dev/null +++ b/openipc/iford_nand_config @@ -0,0 +1,3 @@ +# The Iford SDK's layout: CIS, BOOT0, BOOT1, the environment, then ubi +CONFIG_ENV_OFFSET=0x580000 +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:1280k(cis),2176k(boot0),2176k(boot1),256k(env),-(ubi)" diff --git a/openipc/infinity2m-ipl-cust.bin b/openipc/infinity2m-ipl-cust.bin new file mode 100755 index 000000000000..2ece8895d12b Binary files /dev/null and b/openipc/infinity2m-ipl-cust.bin differ diff --git a/openipc/infinity2m-ipl.bin b/openipc/infinity2m-ipl.bin new file mode 100755 index 000000000000..a2a45f73c972 Binary files /dev/null and b/openipc/infinity2m-ipl.bin differ diff --git a/openipc/infinity2m-nand-ipl-cust.bin b/openipc/infinity2m-nand-ipl-cust.bin new file mode 100755 index 000000000000..2ece8895d12b Binary files /dev/null and b/openipc/infinity2m-nand-ipl-cust.bin differ diff --git a/openipc/infinity2m-nand-ipl.bin b/openipc/infinity2m-nand-ipl.bin new file mode 100755 index 000000000000..a2a45f73c972 Binary files /dev/null and b/openipc/infinity2m-nand-ipl.bin differ diff --git a/openipc/infinity2m-nand-pni.bin b/openipc/infinity2m-nand-pni.bin new file mode 100755 index 000000000000..d58b7decc17f Binary files /dev/null and b/openipc/infinity2m-nand-pni.bin differ diff --git a/openipc/infinity2m-nand-sni-list.bin b/openipc/infinity2m-nand-sni-list.bin new file mode 100755 index 000000000000..badafd6da6c9 Binary files /dev/null and b/openipc/infinity2m-nand-sni-list.bin differ diff --git a/openipc/infinity2m-nand-sni.bin b/openipc/infinity2m-nand-sni.bin new file mode 100755 index 000000000000..cfcf5ab385a3 Binary files /dev/null and b/openipc/infinity2m-nand-sni.bin differ diff --git a/openipc/infinity2m_config b/openipc/infinity2m_config new file mode 100644 index 000000000000..9ee2d643be44 --- /dev/null +++ b/openipc/infinity2m_config @@ -0,0 +1,2 @@ +# INFINITY2M: what the vendor U-Boot passes +CONFIG_MACH_TYPE=1395 diff --git a/openipc/infinity2m_nand_config b/openipc/infinity2m_nand_config new file mode 100644 index 000000000000..8792d2764008 --- /dev/null +++ b/openipc/infinity2m_nand_config @@ -0,0 +1,4 @@ +# Its PNI: the environment in blocks 34-36 +CONFIG_ENV_OFFSET=0x440000 +CONFIG_ENV_RANGE=0x60000 +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:4352k(boot),384k(env),-(ubi)" diff --git a/openipc/infinity6-ipl-cust.bin b/openipc/infinity6-ipl-cust.bin new file mode 100644 index 000000000000..e22b473e96cc Binary files /dev/null and b/openipc/infinity6-ipl-cust.bin differ diff --git a/openipc/infinity6-ipl.bin b/openipc/infinity6-ipl.bin new file mode 100644 index 000000000000..fa6d81a94072 Binary files /dev/null and b/openipc/infinity6-ipl.bin differ diff --git a/openipc/infinity6-nand-pni.bin b/openipc/infinity6-nand-pni.bin new file mode 100644 index 000000000000..9ed3d001271f Binary files /dev/null and b/openipc/infinity6-nand-pni.bin differ diff --git a/openipc/infinity6-nand-sni.bin b/openipc/infinity6-nand-sni.bin new file mode 100644 index 000000000000..f7089b8d4800 Binary files /dev/null and b/openipc/infinity6-nand-sni.bin differ diff --git a/openipc/infinity6_config b/openipc/infinity6_config new file mode 100644 index 000000000000..138d59fc8899 --- /dev/null +++ b/openipc/infinity6_config @@ -0,0 +1,2 @@ +# INFINITY6: what the vendor U-Boot passes +CONFIG_MACH_TYPE=1394 diff --git a/openipc/infinity6b0-ipl-cust.bin b/openipc/infinity6b0-ipl-cust.bin new file mode 100755 index 000000000000..1f1f91021fb5 Binary files /dev/null and b/openipc/infinity6b0-ipl-cust.bin differ diff --git a/openipc/infinity6b0-ipl.bin b/openipc/infinity6b0-ipl.bin new file mode 100755 index 000000000000..838649bcb281 Binary files /dev/null and b/openipc/infinity6b0-ipl.bin differ diff --git a/openipc/infinity6b0-nand-pni.bin b/openipc/infinity6b0-nand-pni.bin new file mode 100644 index 000000000000..5838dd4b8dce Binary files /dev/null and b/openipc/infinity6b0-nand-pni.bin differ diff --git a/openipc/infinity6b0-nand-sni.bin b/openipc/infinity6b0-nand-sni.bin new file mode 100644 index 000000000000..5c58a099abcd Binary files /dev/null and b/openipc/infinity6b0-nand-sni.bin differ diff --git a/openipc/infinity6b0_config b/openipc/infinity6b0_config new file mode 100644 index 000000000000..2e8ecf9de00b --- /dev/null +++ b/openipc/infinity6b0_config @@ -0,0 +1,2 @@ +# INFINITY6B0: what the vendor U-Boot passes +CONFIG_MACH_TYPE=1397 diff --git a/openipc/infinity6c-gcis.bin b/openipc/infinity6c-gcis.bin new file mode 100644 index 000000000000..b86d7181a384 Binary files /dev/null and b/openipc/infinity6c-gcis.bin differ diff --git a/openipc/infinity6c-ipl-cust.bin b/openipc/infinity6c-ipl-cust.bin new file mode 100644 index 000000000000..d144af0db719 Binary files /dev/null and b/openipc/infinity6c-ipl-cust.bin differ diff --git a/openipc/infinity6c-ipl.bin b/openipc/infinity6c-ipl.bin new file mode 100644 index 000000000000..a18354e3d6ff Binary files /dev/null and b/openipc/infinity6c-ipl.bin differ diff --git a/openipc/infinity6c-nand-ipl-cust.bin b/openipc/infinity6c-nand-ipl-cust.bin new file mode 100644 index 000000000000..c7f0e5378b26 Binary files /dev/null and b/openipc/infinity6c-nand-ipl-cust.bin differ diff --git a/openipc/infinity6c-nand-ipl.bin b/openipc/infinity6c-nand-ipl.bin new file mode 100644 index 000000000000..b0f848be5f1a Binary files /dev/null and b/openipc/infinity6c-nand-ipl.bin differ diff --git a/openipc/infinity6c-nand-pni.bin b/openipc/infinity6c-nand-pni.bin new file mode 100755 index 000000000000..5a966ce14fc0 Binary files /dev/null and b/openipc/infinity6c-nand-pni.bin differ diff --git a/openipc/infinity6c-nand-sni-list.bin b/openipc/infinity6c-nand-sni-list.bin new file mode 100644 index 000000000000..594bedf79230 Binary files /dev/null and b/openipc/infinity6c-nand-sni-list.bin differ diff --git a/openipc/infinity6c-nand-sni.bin b/openipc/infinity6c-nand-sni.bin new file mode 100644 index 000000000000..639bcccdee48 Binary files /dev/null and b/openipc/infinity6c-nand-sni.bin differ diff --git a/openipc/infinity6c_config b/openipc/infinity6c_config new file mode 100644 index 000000000000..60dd5a34f699 --- /dev/null +++ b/openipc/infinity6c_config @@ -0,0 +1,2 @@ +# MERCURY6: what the vendor U-Boot passes on infinity6c, not INFINITY6C +CONFIG_MACH_TYPE=1399 diff --git a/openipc/infinity6c_nand_config b/openipc/infinity6c_nand_config new file mode 100644 index 000000000000..4b79b79509a3 --- /dev/null +++ b/openipc/infinity6c_nand_config @@ -0,0 +1,3 @@ +# The SDK's layout: the CIS, BOOT, BOOT_BAK, then the environment +CONFIG_ENV_OFFSET=0x4C0000 +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:1280k(cis),1792k(boot0),1792k(boot1),256k(env),-(ubi)" diff --git a/openipc/infinity6e-ipl-cust.bin b/openipc/infinity6e-ipl-cust.bin new file mode 100644 index 000000000000..cb5769761660 Binary files /dev/null and b/openipc/infinity6e-ipl-cust.bin differ diff --git a/openipc/infinity6e-ipl.bin b/openipc/infinity6e-ipl.bin new file mode 100644 index 000000000000..c139ec44dd5a Binary files /dev/null and b/openipc/infinity6e-ipl.bin differ diff --git a/openipc/infinity6e-nand-pni.bin b/openipc/infinity6e-nand-pni.bin new file mode 100644 index 000000000000..5838dd4b8dce Binary files /dev/null and b/openipc/infinity6e-nand-pni.bin differ diff --git a/openipc/infinity6e-nand-sni.bin b/openipc/infinity6e-nand-sni.bin new file mode 100644 index 000000000000..5c58a099abcd Binary files /dev/null and b/openipc/infinity6e-nand-sni.bin differ diff --git a/openipc/infinity6e_config b/openipc/infinity6e_config new file mode 100644 index 000000000000..89a3bce2f6eb --- /dev/null +++ b/openipc/infinity6e_config @@ -0,0 +1,2 @@ +# INFINITY6E: what the vendor U-Boot passes +CONFIG_MACH_TYPE=1396 diff --git a/openipc/nand_config b/openipc/nand_config new file mode 100644 index 000000000000..c00e471f2bbe --- /dev/null +++ b/openipc/nand_config @@ -0,0 +1,21 @@ +# On SPI NAND, in place of the SPI NOR of openipc_config. The layout and the +# environment are OpenIPC/u-boot-sigmastar's: boot0, boot1, env at 2 MiB, ubi. +# CONFIG_MS_SFLASH is not set +# CONFIG_CMD_SF is not set +# CONFIG_ENV_IS_IN_SPI_FLASH is not set +CONFIG_ENV_IS_IN_NAND=y +CONFIG_ENV_OFFSET=0x200000 +CONFIG_ENV_SIZE=0x20000 +CONFIG_ENV_SECT_SIZE=0x20000 +CONFIG_ENV_RANGE=0x40000 +CONFIG_MTD=y +CONFIG_MTD_RAW_NAND=y +CONFIG_NAND_MS_SPINAND=y +CONFIG_CMD_NAND=y +CONFIG_MTD_UBI=y +CONFIG_CMD_UBI=y +CONFIG_CMD_MTDPARTS=y +CONFIG_MTDIDS_DEFAULT="nand0=nand0" +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:1024k(boot0),1024k(boot1),256k(env),-(ubi)" +# The firmware's kernel is in a UBI volume, the rootfs a squashfs +CONFIG_OPENIPC_NAND_KERNEL_VOLUME=y diff --git a/openipc/openipc_config b/openipc/openipc_config index 2fdcfb235c7f..b614fa113060 100644 --- a/openipc/openipc_config +++ b/openipc/openipc_config @@ -1,5 +1,5 @@ -# OpenIPC base configuration for the SigmaStar infinity3 targets. build.sh -# appends the per-SoC fragment and runs olddefconfig, so a later line +# OpenIPC base configuration for the SigmaStar targets. build.sh +# appends the per-die and per-SoC fragments and runs olddefconfig, so a later line # overrides an earlier one. CONFIG_ARM=y CONFIG_ARCH_SIGMASTAR=y diff --git a/openipc/sigmastar-image.py b/openipc/sigmastar-image.py new file mode 100755 index 000000000000..c97e54666737 --- /dev/null +++ b/openipc/sigmastar-image.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0+ +""" +Build the boot partition of a SigmaStar NOR flash from infinity2m on, the +layout of OpenIPC's vendor U-Boot (make_boot_spinor.sh): + + 0x00000 IPL the vendor's: trains the DDR, loads IPL_CUST + 0x09000 GCIS the flash table, infinity6c only (--gcis) + 0x0F000 MXP partition table, the others (--mxp) + 0x10000 IPL_CUST the vendor's: finds UBOOT, unpacks it + 0x20000 UBOOT U-Boot, xz-compressed in a legacy uImage + ... 0xFF up to 0x40000, where the environment starts + +IPL_CUST takes the uImage as the vendor's create_img.sh makes it: `xz -z` +data (preset 6, CRC64) under compression type "lzma", load and entry 0, +named by the 32-byte MVX tag. It unpacks it to where U-Boot is linked, +0x23E00000. + + sigmastar-image.py --ipl F --ipl-cust F (--mxp F | --gcis F) + --tag TAG --uboot u-boot.bin --soc SOC --out F + +On SPI NAND (--nand), the SNI (--gcis) in page 0 and the PNI (--pni) in page 1, +then make_boot_spinand.sh's 2 MiB: IPL at 0x40000 and 0x80000, IPL_CUST at +0xC0000 and 0x100000, U-Boot at 0x140000 and 0x1A0000. That is what OpenIPC +publishes, whatever the PNI says: infinity6's table has its stages further up +and its images boot regardless. Nothing is published for infinity2m, so +--pni-layout puts each stage where its SDK's PNI says. +""" + +import argparse +import lzma +import struct +import sys +import time +import zlib + +BOOT_SIZE = 0x40000 +GCIS_OFF, MXP_OFF = 0x9000, 0xF000 +CUST_OFF, CUST_SIZE = 0x10000, 0xF000 +UBOOT_OFF, UBOOT_SIZE = 0x20000, 0x20000 + +NAND_BOOT_SIZE = 0x200000 +NAND_IPL_OFFS = (0x40000, 0x80000) +NAND_CUST_OFFS = (0xC0000, 0x100000) +NAND_UBOOT_OFFS = (0x140000, 0x1A0000) + +# The PNI's partition types +PNI_IPL_CUST, PNI_IPL, PNI_UBOOT, PNI_ENV = 1, 3, 6, 13 + + +def pni_layout(pni): + """Each partition's copies, in bytes, from the IPL's own table.""" + spare, page, pages, blocks, count, unit = struct.unpack_from("<6H", pni, 4) + block = page * pages + recs = [struct.unpack_from("<4H", pni, 16 + i * 8) for i in range(count)] + parts = {} + for start, cnt, kind, backup in recs: + # a partition holds its piece once per cnt blocks, backups included + for k in range((cnt + backup) // cnt if cnt else 1): + parts.setdefault(kind, []).append((start + k * cnt) * block) + return parts + + +def uimage(data, name, load=0): + """A legacy uImage: ARM, OS U-Boot, type kernel, "lzma" (xz data).""" + hdr = struct.pack(">IIIIIIIBBBB32s", 0x27051956, 0, int(time.time()), + len(data), load, load, zlib.crc32(data), 17, 2, 2, 3, + name.encode()[:32]) + hdr = hdr[:4] + struct.pack(">I", zlib.crc32(hdr)) + hdr[8:] + return hdr + data + + +def iford(args, ipl, cust): + """ + Iford's NOR, as its SDK's boot.bin: IPL at 0, the CIS area (flash.nri, + the PNI, the flash list) at 0xE000, IPL_CUST at 0x18000, UBOOT at 0x1F000, + up to OpenIPC's environment at 0x40000. Its IPL_CUST unpacks the uImage + to the load address the header gives. + """ + cis = read(args.iford_cis) + payload = lzma.compress(read(args.uboot), format=lzma.FORMAT_XZ, + check=lzma.CHECK_CRC64, preset=6) + tag = ("MVX4##%-4s" % args.tag).replace(" ", "#") + "openIPC#CM_UBT2110#XVM" + img = uimage(payload, tag[:32], 0x23E00000) + for what, size, room in (("IPL", len(ipl), 0xE000), + ("CIS", len(cis), 0xA000), + ("IPL_CUST", len(cust), 0x7000), + ("UBOOT", len(img), 0x21000)): + if size > room: + sys.exit("%s: %u bytes, it has %u" % (what, size, room)) + boot = bytearray(b"\xff" * BOOT_SIZE) + boot[:len(ipl)] = ipl + boot[0xE000:0xE000 + len(cis)] = cis + boot[0x18000:0x18000 + len(cust)] = cust + boot[0x1F000:0x1F000 + len(img)] = img + with open(args.out, "wb") as f: + f.write(boot) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), 0x21000)) + + +def ifado(args, ipl, cust): + """ + Ifado's NOR, as Dahua's (IPC-HDW1433V-A-IL2): IPL at 0, the CIS area + (the NRI records, the PNI at 0x9000, NRIB) at 0x8000, IPL_CUST at + 0x10000, and UBOOT, the PNI's, at 0x20000 up to the environment at + 0x40000. Its IPL_CUST unpacks the uImage to the load address it gives. + """ + cis = read(args.ifado_cis) + payload = lzma.compress(read(args.uboot), format=lzma.FORMAT_XZ, + check=lzma.CHECK_CRC64, preset=6) + tag = ("MVX4##%-4s" % args.tag).replace(" ", "#") + "openIPC#CM_UBT2110#XVM" + img = uimage(payload, tag[:32], 0x23E00000) + for what, size, room in (("IPL", len(ipl), 0x8000), + ("CIS", len(cis), 0x8000), + ("IPL_CUST", len(cust), 0x10000), + ("UBOOT", len(img), 0x20000)): + if size > room: + sys.exit("%s: %u bytes, it has %u" % (what, size, room)) + boot = bytearray(b"\xff" * BOOT_SIZE) + boot[:len(ipl)] = ipl + boot[0x8000:0x8000 + len(cis)] = cis + boot[0x10000:0x10000 + len(cust)] = cust + boot[0x20000:0x20000 + len(img)] = img + with open(args.out, "wb") as f: + f.write(boot) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), 0x20000)) + + +def ifliegen(args, ipl, cust): + """ + Ifliegen's NOR, as its SDK's image.mk and nor.squashfs.tfa.partition.config + lay it out, at offsets that fit both packages' IPLs: IPL at 0, the CIS + area at 0xC000 (flash.nri, the PNI at +0x1000, the flash list with the + CRC32 nrigenerator adds at +0x2000), IPL_CUST at 0x16000, TF-A's SP_MIN + at 0x1D000, UBOOT at 0x24000 up to OpenIPC's environment at 0x40000. + The IPL starts TF-A, which runs IPL_CUST; that unpacks the uImage to the + load address its header gives. + """ + tfa = read(args.ifliegen_tfa) + nri = read(args.ifliegen_nri) + flist = bytearray(read(args.ifliegen_list)) + for i in range(0, len(flist), 1024): + if flist[i + 0x100:i + 0x104] == b"NRIF": + struct.pack_into(" 0x1000 or len(pni) > 0x1000 or 0x2000 + len(flist) > len(cis): + sys.exit("Ifliegen: the CIS does not fit") + cis[0:len(nri)] = nri + cis[0x1000:0x1000 + len(pni)] = pni + cis[0x2000:0x2000 + len(flist)] = flist + boot = bytearray(b"\xff" * BOOT_SIZE) + for name, off, room, data in parts: + data = bytes(cis) if data is None else data + if len(data) > room: + sys.exit("%s: %u bytes, it has %u" % (name, len(data), room)) + boot[off:off + len(data)] = data + with open(args.out, "wb") as f: + f.write(boot) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), 0x1C000)) + + +def bdma_crc32(buf, crc=0xFFFFFFFF, poly=0xEDB88320): + """snigenerator's FLASH_IMPL_BDMA_SW_CRC32, the SNIB's own.""" + for b in buf: + for i in range(8): + if ((crc >> 31) ^ (b >> i)) & 1: + crc = (((crc << 1) & 0xFFFFFFFF) >> 1) ^ (poly >> 1) + crc = ((crc << 1) | 1) & 0xFFFFFFFF + else: + crc = (crc << 1) & 0xFFFFFFFF + return crc + + +def snigen(data, bl0, bl1, page=0, spare=0): + """What the SDK's snigenerator does to each 1 KiB SNI record: the boot + blocks BL0PBA and BL1PBA (and one block per image, three backups one + apart) in the SNIB and every SNIF, then their CRCs.""" + boot = bytes([bl0, bl1, 0, 3, 1]) + out = bytearray() + for i in range(0, len(data) - 1023, 1024): + r = bytearray(data[i:i + 1024]) + if r[0x100:0x104] != b"SNIF": + break + snib = r[0:4] == b"SNIB" + if snib: + r[0x3F:0x44] = boot + if page: + struct.pack_into(" step: + sys.exit("%s: %u bytes, it has %u" % (name, len(data), step)) + for c in range(copies): + out[off + c * step:off + c * step + len(data)] = data + off += room + parts.append(("ENV", env_off, 0x40000, (0, 1, 1, 0))) + parts.append(("ubi", env_off + 0x40000, 0x8000000 - env_off - 0x40000, + (0, 1, 1, 0))) + recs = b"".join(name.encode().ljust(16, b"\0") + bytes(flags) + + struct.pack(" blk: + sys.exit("Ifliegen NAND: the CIS does not fit a block") + for b in range(10): + out[b * blk:b * blk + len(cis)] = cis + with open(args.out, "wb") as f: + f.write(out) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), 0x100000)) + + +def iford_nand(args): + """ + Iford's SPI NAND, as the SDK's OnebinnandBurnImgConfig.cfg writes it: its + cis.bin in each of the ten CIS blocks (page 0 SNIB with the part's SNIF, + page 1 the PNI), then its boot.bin from 0x140000, IPL, IPL_CUST and + OP-TEE three blocks each, with our uImage in UBOOT at 0x260000. The + second boot copy stays empty, as the SDK leaves it. + """ + cis = read(args.iford_nand_cis) + stages = read(args.iford_nand_boot) + payload = lzma.compress(read(args.uboot), format=lzma.FORMAT_XZ, + check=lzma.CHECK_CRC64, preset=6) + tag = ("MVX4##%-4s" % args.tag).replace(" ", "#") + "openIPC#CM_UBT2110#XVM" + img = uimage(payload, tag[:32], 0x23E00000) + if len(img) > 0x100000 or len(stages) > 0x120000: + sys.exit("Iford NAND: a stage does not fit") + boot = bytearray(b"\xff" * 0x580000) + for blk in range(10): + boot[blk * 0x20000:blk * 0x20000 + len(cis)] = cis + boot[0x140000:0x140000 + len(stages)] = stages + boot[0x260000:0x260000 + len(img)] = img + with open(args.out, "wb") as f: + f.write(boot) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), 0x100000)) + + +def read(path): + with open(path, "rb") as f: + return f.read() + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + ap.add_argument("--ipl") + ap.add_argument("--ipl-cust") + table = ap.add_mutually_exclusive_group(required=False) + table.add_argument("--mxp") + table.add_argument("--gcis") + ap.add_argument("--iford-cis", help="Iford: CIS area, 0xE000-0x18000") + ap.add_argument("--ifado-cis", help="Ifado: CIS area, 0x8000-0x10000") + ap.add_argument("--ifliegen-tfa", help="Ifliegen: TF-A's u-bl32.bin") + ap.add_argument("--ifliegen-nri", help="Ifliegen: flash.nri") + ap.add_argument("--ifliegen-list", help="Ifliegen: flash_list.nri") + ap.add_argument("--ifliegen-sni", help="Ifliegen NAND: flash.sni") + ap.add_argument("--ifliegen-sni-list", help="Ifliegen NAND: flash_list.sni") + ap.add_argument("--iford-nand-cis", help="Iford NAND: the SDK's cis.bin") + ap.add_argument("--iford-nand-boot", + help="Iford NAND: IPL, IPL_CUST, OP-TEE from 0x140000") + ap.add_argument("--nand", action="store_true") + ap.add_argument("--pni", help="partition table, with --nand") + ap.add_argument("--pni-layout", action="store_true") + ap.add_argument("--sni-list", help="flash table for infinity6c, page 2") + ap.add_argument("--nand-6c", action="store_true") + ap.add_argument("--nand-i2m", action="store_true") + ap.add_argument("--sni-part", type=int, default=1, + help="infinity6c: the flash list's record for page 0") + ap.add_argument("--tag", required=True, help="die in the MVX tag, 4 chars") + ap.add_argument("--uboot", required=True) + ap.add_argument("--soc", required=True) + ap.add_argument("--out", required=True) + args = ap.parse_args() + + if args.iford_nand_cis: + return iford_nand(args) + if args.ifliegen_sni: + return ifliegen_nand(args) + ipl, cust = read(args.ipl), read(args.ipl_cust) + if args.iford_cis: + return iford(args, ipl, cust) + if args.ifado_cis: + return ifado(args, ipl, cust) + if args.ifliegen_tfa: + return ifliegen(args, ipl, cust) + tab = read(args.gcis or args.mxp) + payload = lzma.compress(read(args.uboot), format=lzma.FORMAT_XZ, + check=lzma.CHECK_CRC64, preset=6) + tag = ("MVX4##%-4s" % args.tag).replace(" ", "#") + "openIPC#CM_UBT1501#XVM" + img = uimage(payload, tag[:32]) + + if args.nand: + pni = read(args.pni) + parts = {PNI_IPL: NAND_IPL_OFFS, PNI_IPL_CUST: NAND_CUST_OFFS, + PNI_UBOOT: NAND_UBOOT_OFFS, PNI_ENV: (NAND_BOOT_SIZE,)} + if args.pni_layout: + parts = pni_layout(pni) + if args.nand_6c: + # image/configs/general/spinand.*: three copies of each stage, + # one block apart, then U-Boot, and the same again for BOOT_BAK + ipls = [0x140000 + i * 0x20000 for i in range(3)] + custs = [0x1A0000 + i * 0x20000 for i in range(3)] + parts = {PNI_IPL: ipls + [o + 0x1C0000 for o in ipls], + PNI_IPL_CUST: custs + [o + 0x1C0000 for o in custs], + PNI_UBOOT: (0x200000, 0x3C0000), PNI_ENV: (0x4C0000,)} + size = parts[PNI_ENV][0] + uboot = parts[PNI_UBOOT] + limit = min(uboot[1] - uboot[0], 0x100000) + for what, have, room in (("SNI", len(tab), 0x800), + ("PNI", len(pni), 0x800), + ("UBOOT", len(img), limit)): + if have > room: + sys.exit("%s: %u bytes, it has %u" % (what, have, room)) + boot = bytearray(b"\xff" * size) + boot[:len(tab)] = tab + boot[0x800:0x800 + len(pni)] = pni + if args.sni_list and args.nand_6c: + sni_list = read(args.sni_list) + boot[0x1000:0x1000 + len(sni_list)] = sni_list + if args.nand_6c: + # infinity6c's IPL wants a part's own SNI in page 0 (the SDK's + # "nand probe" writes it from the list), with its boot block + # fields and CRC32, and the CIS in each of the ten CIS blocks + rec = bytearray(sni_list[args.sni_part * 512: + (args.sni_part + 1) * 512]) + rec[0x2F:0x34] = tab[0x2F:0x34] + struct.pack_into(" limit: + sys.exit("%s: %u bytes, it has %u" % (what, size, limit)) + + boot = bytearray(b"\xff" * BOOT_SIZE) + boot[:len(ipl)] = ipl + boot[tab_off:tab_off + len(tab)] = tab + boot[CUST_OFF:CUST_OFF + len(cust)] = cust + boot[UBOOT_OFF:UBOOT_OFF + len(img)] = img + with open(args.out, "wb") as f: + f.write(boot) + print("%s: UBOOT %u of %u bytes" % (args.out, len(img), UBOOT_SIZE)) + + +if __name__ == "__main__": + main() diff --git a/openipc/sigmastar-mxp.bin b/openipc/sigmastar-mxp.bin new file mode 100644 index 000000000000..ac73d840727c Binary files /dev/null and b/openipc/sigmastar-mxp.bin differ diff --git a/openipc/ssc029a_config b/openipc/ssc029a_config new file mode 100644 index 000000000000..2bedda6f7834 --- /dev/null +++ b/openipc/ssc029a_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC029A=y +CONFIG_PRODUCT_SOC="ssc029a" diff --git a/openipc/ssc029b_config b/openipc/ssc029b_config new file mode 100644 index 000000000000..d3e04a766cb5 --- /dev/null +++ b/openipc/ssc029b_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC029B=y +CONFIG_PRODUCT_SOC="ssc029b" diff --git a/openipc/ssc029c_config b/openipc/ssc029c_config new file mode 100644 index 000000000000..01664a38c1c4 --- /dev/null +++ b/openipc/ssc029c_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC029C=y +CONFIG_PRODUCT_SOC="ssc029c" diff --git a/openipc/ssc034a_config b/openipc/ssc034a_config new file mode 100644 index 000000000000..fb8e85ed0e24 --- /dev/null +++ b/openipc/ssc034a_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC034A=y +CONFIG_PRODUCT_SOC="ssc034a" diff --git a/openipc/ssc034b_config b/openipc/ssc034b_config new file mode 100644 index 000000000000..53d07235fb1e --- /dev/null +++ b/openipc/ssc034b_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC034B=y +CONFIG_PRODUCT_SOC="ssc034b" diff --git a/openipc/ssc30kd_config b/openipc/ssc30kd_config new file mode 100644 index 000000000000..eef9db9d1df3 --- /dev/null +++ b/openipc/ssc30kd_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC30KD=y +CONFIG_PRODUCT_SOC="ssc30kd" diff --git a/openipc/ssc30kq_config b/openipc/ssc30kq_config new file mode 100644 index 000000000000..8049c063d5fe --- /dev/null +++ b/openipc/ssc30kq_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC30KQ=y +CONFIG_PRODUCT_SOC="ssc30kq" diff --git a/openipc/ssc325_config b/openipc/ssc325_config new file mode 100644 index 000000000000..86cdb851a5e8 --- /dev/null +++ b/openipc/ssc325_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC325=y +CONFIG_PRODUCT_SOC="ssc325" diff --git a/openipc/ssc325de_config b/openipc/ssc325de_config new file mode 100644 index 000000000000..0cbad37e8404 --- /dev/null +++ b/openipc/ssc325de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC325DE=y +CONFIG_PRODUCT_SOC="ssc325de" diff --git a/openipc/ssc327de_config b/openipc/ssc327de_config new file mode 100644 index 000000000000..1c60967b063e --- /dev/null +++ b/openipc/ssc327de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC327DE=y +CONFIG_PRODUCT_SOC="ssc327de" diff --git a/openipc/ssc333_config b/openipc/ssc333_config new file mode 100644 index 000000000000..1034f009182b --- /dev/null +++ b/openipc/ssc333_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC333=y +CONFIG_PRODUCT_SOC="ssc333" diff --git a/openipc/ssc335_config b/openipc/ssc335_config new file mode 100644 index 000000000000..49db0c61b3dc --- /dev/null +++ b/openipc/ssc335_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC335=y +CONFIG_PRODUCT_SOC="ssc335" diff --git a/openipc/ssc335de_config b/openipc/ssc335de_config new file mode 100644 index 000000000000..fdd85eeca682 --- /dev/null +++ b/openipc/ssc335de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC335DE=y +CONFIG_PRODUCT_SOC="ssc335de" diff --git a/openipc/ssc337_config b/openipc/ssc337_config new file mode 100644 index 000000000000..ce3e0b1456df --- /dev/null +++ b/openipc/ssc337_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC337=y +CONFIG_PRODUCT_SOC="ssc337" diff --git a/openipc/ssc337de_config b/openipc/ssc337de_config new file mode 100644 index 000000000000..430f2f8ad113 --- /dev/null +++ b/openipc/ssc337de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC337DE=y +CONFIG_PRODUCT_SOC="ssc337de" diff --git a/openipc/ssc338q_config b/openipc/ssc338q_config new file mode 100644 index 000000000000..873fdf3d6027 --- /dev/null +++ b/openipc/ssc338q_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC338Q=y +CONFIG_PRODUCT_SOC="ssc338q" diff --git a/openipc/ssc375_config b/openipc/ssc375_config new file mode 100644 index 000000000000..cdea2aff17a5 --- /dev/null +++ b/openipc/ssc375_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC375=y +CONFIG_PRODUCT_SOC="ssc375" diff --git a/openipc/ssc377_config b/openipc/ssc377_config new file mode 100644 index 000000000000..0088a505b6cd --- /dev/null +++ b/openipc/ssc377_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC377=y +CONFIG_PRODUCT_SOC="ssc377" diff --git a/openipc/ssc377d_config b/openipc/ssc377d_config new file mode 100644 index 000000000000..6051284e88d1 --- /dev/null +++ b/openipc/ssc377d_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC377D=y +CONFIG_PRODUCT_SOC="ssc377d" diff --git a/openipc/ssc377de_config b/openipc/ssc377de_config new file mode 100644 index 000000000000..784b43225fb6 --- /dev/null +++ b/openipc/ssc377de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC377DE=y +CONFIG_PRODUCT_SOC="ssc377de" diff --git a/openipc/ssc377qe_config b/openipc/ssc377qe_config new file mode 100644 index 000000000000..78549c55d992 --- /dev/null +++ b/openipc/ssc377qe_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC377QE=y +CONFIG_PRODUCT_SOC="ssc377qe" diff --git a/openipc/ssc378de_config b/openipc/ssc378de_config new file mode 100644 index 000000000000..46517a518e55 --- /dev/null +++ b/openipc/ssc378de_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC378DE=y +CONFIG_PRODUCT_SOC="ssc378de" diff --git a/openipc/ssc378qe_config b/openipc/ssc378qe_config new file mode 100644 index 000000000000..046df6277c69 --- /dev/null +++ b/openipc/ssc378qe_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSC378QE=y +CONFIG_PRODUCT_SOC="ssc378qe" diff --git a/openipc/ssd201_config b/openipc/ssd201_config new file mode 100644 index 000000000000..f39fac84612c --- /dev/null +++ b/openipc/ssd201_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSD201=y +CONFIG_PRODUCT_SOC="ssd201" diff --git a/openipc/ssd202d_config b/openipc/ssd202d_config new file mode 100644 index 000000000000..ad9b46848fe5 --- /dev/null +++ b/openipc/ssd202d_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSD202D=y +CONFIG_PRODUCT_SOC="ssd202d" diff --git a/openipc/ssr621q_config b/openipc/ssr621q_config new file mode 100644 index 000000000000..1c7e7410d46b --- /dev/null +++ b/openipc/ssr621q_config @@ -0,0 +1,2 @@ +CONFIG_TARGET_SSR621Q=y +CONFIG_PRODUCT_SOC="ssr621q"