Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

# The build lives in build-gk710x.yml on the openipc branch (the default
# branch, so it can be dispatched). GitHub runs a pull request's
# workflows from the PR's own tree, so this branch needs this caller for
# its pushes and pull requests to be built and smoke-tested at all.
# It never releases: that workflow only uploads on workflow_dispatch.
on:
push:
branches: [openipc-gk710x]
pull_request:
branches: [openipc-gk710x]

jobs:
build:
uses: OpenIPC/u-boot/.github/workflows/build-gk710x.yml@openipc
# github.sha: on pull_request the merge of the PR into the current
# base, so the PR is built as it would land; on push, that commit.
with:
ref: ${{ github.sha }}
# A called workflow is validated against what its caller grants,
# skipped jobs included; release/publish ask for these.
permissions:
contents: write
id-token: write
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,6 @@ __pycache__
# pylint files
/pylint.cur
/pylint.out/

# OpenIPC build outputs
/output/
239 changes: 239 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this branch is

`openipc-gk710x` is OpenIPC's U-Boot for Goke's own ARM1176 camera SoCs, the
GK7101 and GK7102. These are not the HiSilicon-derived GK7205/GK7605 that
`openipc-hisilicon` covers. The tree is **mainline U-Boot v2022.10**, the
same release as `openipc-hisilicon` and `openipc-xm`, plus:

- the OpenIPC boot layer, carried over from `openipc-xm`, which took it from
`openipc-hisilicon`;
- the GK710x support, written from the vendor SDK (`GK710X_LinuxSDK_v2.0.0`,
U-Boot 2012.10 and Linux 3.4.43).

No vendor driver comes along. The vendor's HAL blob is carried, for the
kernel only (see below).

CI and user docs live on the `openipc` branch:

- `.github/workflows/ci.yml` only calls `build-gk710x.yml@openipc`.
- `git show origin/openipc:CLAUDE.md` covers the workflow invariants.
- `git show origin/openipc-hisilicon:CLAUDE.md` covers the OpenIPC layer
(default environment, `common/openipc.c`, env compatibility). It applies
here unchanged.

Adding or dropping a SoC needs both branches:

- here: `build.sh` (`build_soc`, `ALL_SOCS`), `openipc/<soc>_config` and
`openipc/<soc>.rvs`;
- there: `build-gk710x.yml`'s matrices and the README.

GK7101S/GK7102S (`gk7102s` in OpenIPC/firmware) are a different die with a
different HAL and register map. They are not supported here, and
qemu-hisilicon does not model them.

## Relationship to mainline

```sh
git diff --stat v2022.10 HEAD # the whole delta, small
git diff --diff-filter=M v2022.10 HEAD # the mainline files we patched
```

**Added**

| Area | Location |
| --- | --- |
| SoC: clocks, timer, watchdog reset, DRAM size, pin functions | `arch/arm/mach-gk710x/` (`ARCH_GK710X`; `TARGET_GK7101`/`GK7102`; register map in `include/mach/gk710x.h`) |
| Kernel hand-off: HAL blob, U2K words | `arch/arm/mach-gk710x/kernel.c`, `hal_data.h` |
| Board: GPIO maps, internal Ethernet PHY, `misc_init_r` → `openipc_helper()` | `board/goke/gk710x/` |
| Memory map, console, timer | `include/configs/gk710x.h`, ending in `#include "openipc-common.h"` |
| SPI NOR controller, non-DM | `drivers/mtd/spi/gk_sflash.c` (`GK_SFLASH`). It provides `spi_flash_probe()` and fills `mtd->_read/_write/_erase`, as `xmsfc` does on `openipc-xm` |
| OpenIPC boot layer | `common/openipc.c`, `include/openipc.h` (as on `openipc-xm`), `include/configs/openipc-common.h` (GK rewrite, NOR only, same env commands) |
| Kconfig fragments, boot header, the build | `openipc/`, `build.sh` |

**Patched mainline files**, each small:

- `arch/arm/{Kconfig,Makefile}`: the `ARCH_GK710X` hook.
- `common/{Kconfig,Makefile}`: `OPENIPC`, `PRODUCT_SOC`, `PRODUCT_SOCMODEL`.
- `drivers/mtd/spi/{Kconfig,Makefile}`, `cmd/Kconfig` (`CMD_SF`) and
`env/Kconfig` (`ENV_IS_IN_SPI_FLASH`): accept `GK_SFLASH`.
- `drivers/net/Kconfig`: `NETDEVICES` selects `DM_ETH` only when `DM` is on,
as on `openipc-xm`.
- `drivers/net/designware.c`: the non-DM `designware_initialize()` uses an
MDIO bus the board has already registered under the device's name. The
GK710x PHY is not on the MAC's MDIO lines.

The console (NS16550), the timer (`lib/time.c` over a raw counter) and
Ethernet (DesignWare) are mainline drivers.

## The HAL, and why there is no vendor driver

The vendor U-Boot and kernel never touch a register directly. Every access
goes through a HAL blob, written against a fictitious map (AHB `0x90000000`,
APB `0xA0000000`). The HAL:

1. moves each block to its real place;
2. reorders registers inside some blocks;
3. permutes the bits of some registers (RCT PLLs, timer and watchdog
control, pad control).

This tree programs the silicon directly. Every address and value in
`include/mach/gk710x.h`, `soc.c` and `board/goke/gk710x/gk710x.c` is the
store the HAL itself makes. It was found by executing the HAL's `hw_writel`
under Unicorn (qemu-hisilicon `qemu-boot/gk710x-halmap.py`). To port another
vendor register write, run it through the HAL the same way. Do not guess
from the vendor `*_reg.h`.

The kernel still needs the blob (see "Hand-off to the kernel").

## Boot

- The mask ROM reads the header at flash offset 0. It runs the register
writes and polls listed there (eFuse, DDR PHY, DDR controller), copies
U-Boot to `0xC0800000` (`SYS_TEXT_BASE`) and starts it.
- DDR is up before the first instruction, so there is no SPL, and
`lowlevel_init` is empty.
- `openipc/gk710x-image.py` builds that header:
- the words around the table are as in every SDK prebuilt and camera
flash seen;
- the table is `openipc/<soc>.rvs`, taken from the SDK's prebuilt
U-Boots, which matches what is on cameras in the field;
- GK7101 and GK7102 differ only in the DDR controller word at
`0x60004004` (128 vs 64 MiB). `dram_init()` reads the same word back.
- **Byte order.** The flash controller packs bytes MSB first. U-Boot, the
ROM and the vendor kernel all move whole little-endian words through it, so:
- the chip holds every 32-bit word byte-swapped;
- a camera dump reads as big-endian ("GK7101" in a hex editor);
- `output/u-boot-<soc>-nor.bin` is in CPU order, which is what `sf write`
and the kernel's MTD driver expect;
- a raw image for a programmer, or for qemu's `flash-file=`, needs every
word swapped.
- `gk_sflash.c` keeps that mapping for unaligned offsets as well: whole
words only, writes padded with `0xff`.

## Hand-off to the kernel

The vendor kernel, OpenIPC's `gk7102` included, needs more than ATAGs.
`board_prep_linux()` in `mach-gk710x/kernel.c` provides:

- **The HAL** at `0xC0012000`, with its address in U2K word `0xC0000008`.
The kernel calls `hal_init()` first thing and refuses a HAL older than
20160324. The carried one is 20160913.
- **U2K words** at `0xC0000000`:
- total DDR in MiB;
- `mem=` in bytes, from `osmem`;
- the bitstream buffer, from `bsbsize`;
- `phytype`;
- the `0x7101` valid marker.

The kernel places BSB, DSP and USR memory from these. `mem=` on the
command line still sets the kernel's own size.
- **The GPIO map** (vendor `gpio_cfg_t`) in the top 64 KiB of DDR.
- The kernel configures every pin from it ("gpio map get from uboot"):
sensor I2C and reset, IR cut, SD, Ethernet LED and PHY clock.
- Without it a camera boots with no sensor bus.
- `board_get_usable_ram_top()` keeps U-Boot below that 64 KiB.

The SDK's 20-odd board GPIO headers come down to two layouts
(`board/goke/gk710x/gpio_map.c`):

- `v2`, the default: rb-sc1035 v2.1, sc1045, imx225, ov9750, jxh42 v2.0,
gc1024, GK7101 rb-ov2710 v2.2;
- `v1`: rb-ov9712, ar0130, jxh42 v1.0, GK7101 imx222.

`gpiomap=v1` in the environment selects the second. Other vendor boards
(EVBs, rb-ov2710 v1/v2.0/v2.1, ps1210, bg0703, ar0230) have other maps and
are not covered.

U-Boot itself sets only GPIO 48, the internal PHY's reference clock, the
same in both layouts. It does not apply the whole map, as the vendor U-Boot
did. The two layouts put UART0 on different pins, so with the wrong default
a v1 board would lose its console before `gpiomap=v1` could be set. A v1
board still needs `gpiomap=v1` for the kernel's pins, its console
included.

## Peripherals

- **Console:** UART0 at `0x70005000`, a 16550 with 32-bit registers, 24 MHz.
`arch_cpu_init()` sets the vendor's CPU PLL and UART divider.
- **Timer:** timer 1 at `0x7000B000`, counting down at the 69 MHz APB
clock. **Reset:** the watchdog.
- **Ethernet:** a DesignWare GMAC at `0x6000E000` with the SoC's own
10/100 PHY.
- The PHY's MII registers are memory mapped at `0x60022000 + 4n`. The
board registers them as the MDIO bus, PHY address 0.
- `gk_ephy_init()` does the vendor's PHY clock (audio PLL, out on a pin),
analog trim and MAC/PHY mux.
- External-PHY boards (`phytype=1/2`) are not handled.
- **SD:** not enabled. The vendor U-Boot had none, the controller's base
clock is unknown, and the SD pins depend on the board map. SD recovery in
`common/openipc.c` is compiled out with `CONFIG_MMC`.
- **SPI NAND:** not supported. OpenIPC's GK7102 firmware is NOR only.

## Build

```sh
bash build.sh # gk7101 gk7102; continues past failures, exits non-zero if any failed
bash build.sh gk7102 # one or more SoCs (CROSS_COMPILE defaults to arm-linux-gnueabi-)
```

- The output is `output/u-boot-<soc>-nor.bin`, built out of tree in
`output/build-<soc>-nor/`.
- `.config` is `openipc/openipc_config`, then `openipc/<soc>_config`, then
`olddefconfig`.
- There are no `configs/*_defconfig` for these targets.
- There is no Thumb-2 on ARM1176, so the image is ~237 KiB.
`BOARD_SIZE_LIMIT` keeps header + image under the 256 KiB boot
partition. Check the size after enabling anything.

## Verification

The emulator is widgetii/qemu-hisilicon, machines `gk7101` and `gk7102`
(`docs/goke-gk710x.md` there). `-M gk7102,flash-file=<image>` does the boot
ROM's job from the header, so it boots exactly the flashed bytes. The image
must be byte-swapped as described above.

- **CI smoke:** two boots of an 8 MiB image holding only U-Boot. The second
must load the environment the first saved.
- **Checks to run by hand:**
- A full 8 MiB image reaches `login:`. It has U-Boot at 0, `uImage` at
0x50000 and rootfs at 0x250000, from OpenIPC/firmware `latest`
`openipc.gk7102-nor-lite.tgz` (gk7101 boots the same).
- The kernel log shows `hal version = 20160913`, BSB/DSP/USR inside DDR,
and `[BOOT VERSION] GK7102 openipc-v2`.
- `sf erase/write/read` + `cmp.b` with an unaligned offset and length.
- `saveenv` + `reset`; `fw_printenv` from Linux.
- TFTP recovery from a flash holding only U-Boot
(`-nic user,net=192.168.1.0/24,host=192.168.1.107,tftp=<dir>`).
- The boot limit: two `reset`s, then `altbootcmd` boots with `failsafe`.
- **What qemu does not check:**
- DDR timing (the header is the vendor's, so this is low risk);
- PLL and clock values;
- pad control;
- the PHY's analog trim and real link.

None of this has run on silicon yet.

## Things to keep

- `mem=` stays the first kernel argument, as on the other OpenIPC targets.
`osmem`/`bsbsize` must leave room for the DSP:
- GK7102: 36M + 2M of 64 MiB;
- GK7101: 50M + 4M of 128 MiB.
- The MTD name is `gk_flash`, the vendor kernel driver's (`SFC` in
`openipc-common.h`). The console is `ttySGK0`.
- The boot counter is the DRAM word at `0xC1F20000`, like the other
families' DDR + 0x1f20000. A healthy boot does not clear it, and the
GK7102 firmware ships no openipc-failsafe. After two reboots the boot
limit path therefore boots the same kernel with `failsafe`, which that
firmware ignores, as on `openipc-xm`.

## Conventions

- One topic per commit, `<area>: <what changed>` (`gk710x:`, `gk_sflash:`,
`openipc:`, `net:`, `ci:`).
- Commit bodies say what was verified, and where: the qemu machine, or a
board.
12 changes: 12 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,16 @@ config ARCH_U8500
imply SYS_THUMB_BUILD
imply SYSRESET_SYSCON

config ARCH_GK710X
bool "Goke GK7101/GK7102 IP camera SoCs"
select CPU_ARM1176
select CREATE_ARCH_SYMLINK
select SUPPORT_PASSING_ATAGS
help
Goke's own ARM1176 camera SoCs (not the HiSilicon-derived
GK7205/GK7605). The boot ROM runs the DDR set-up listed in the
flash header, copies U-Boot into DDR and starts it there.

config ARCH_VERSAL
bool "Support Xilinx Versal Platform"
select ARM64
Expand Down Expand Up @@ -2284,6 +2294,8 @@ source "arch/arm/mach-zynqmp/Kconfig"

source "arch/arm/mach-versal/Kconfig"

source "arch/arm/mach-gk710x/Kconfig"

source "arch/arm/mach-zynqmp-r5/Kconfig"

source "arch/arm/cpu/armv7/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions arch/arm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ machine-$(CONFIG_ARCH_BCMBCA) += bcmbca
machine-$(CONFIG_ARCH_BCMSTB) += bcmstb
machine-$(CONFIG_ARCH_DAVINCI) += davinci
machine-$(CONFIG_ARCH_EXYNOS) += exynos
machine-$(CONFIG_ARCH_GK710X) += gk710x
machine-$(CONFIG_ARCH_GXP) += hpe
machine-$(CONFIG_ARCH_HIGHBANK) += highbank
machine-$(CONFIG_ARCH_IPQ40XX) += ipq40xx
Expand Down
31 changes: 31 additions & 0 deletions arch/arm/mach-gk710x/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
if ARCH_GK710X

choice
prompt "Goke SoC"
default TARGET_GK7102

config TARGET_GK7101
bool "GK7101"
help
GK7101: ARM1176 with 128 MiB of external DDR2.

config TARGET_GK7102
bool "GK7102"
help
GK7102: the GK7101 die with 64 MiB of DDR2 in the package.

endchoice

config SYS_SOC
default "gk710x"

config SYS_VENDOR
default "goke"

config SYS_BOARD
default "gk710x"

config SYS_CONFIG_NAME
default "gk710x"

endif
3 changes: 3 additions & 0 deletions arch/arm/mach-gk710x/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+

obj-y += lowlevel_init.o soc.o gpio.o kernel.o
55 changes: 55 additions & 0 deletions arch/arm/mach-gk710x/gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Goke GK710x pin functions, from the vendor U-Boot's drivers/gpio/
* goke_gpio.c (gk7101_gpio_func_config()) with the HAL undone.
*
* A pin type is the vendor's GPIO_TYPE_* word: output function [7:0], input
* function + 2 [15:8], output-enable source [21:16], output and enable
* inversion [23:22], pad control [29:24] and direction [31:30]. The kernel
* decodes the same words from the map U-Boot leaves it (board/goke/gk710x).
*/

#include <common.h>
#include <asm/io.h>
#include <asm/arch/gk710x.h>

#define TYPE_OUT_SEL(t) ((t) & 0xff)
#define TYPE_IN_SEL(t) (((t) >> 8) & 0xff)
#define TYPE_OEN_SEL(t) (((t) >> 16) & 0x3f)
#define TYPE_OUT_INV(t) (((t) >> 22) & 1)
#define TYPE_OEN_INV(t) (((t) >> 23) & 1)
#define TYPE_IOCTRL(t) (((t) >> 24) & 0x3f)
#define TYPE_FUNC(t) ((t) >> 30)

#define FUNC_OUT 2

void gk_gpio_config(unsigned int pin, unsigned int type)
{
unsigned int shift = 8 * (pin % 4);
u32 v;

if (!type)
return;

/* Input functions >= 2 are routed from a pin; 0 and 1 are constants */
if (TYPE_FUNC(type) != FUNC_OUT && TYPE_IN_SEL(type) >= 2)
writel(pin, GK_GPIO_INPUT_CFG(TYPE_IN_SEL(type) - 2));

writel(TYPE_OUT_SEL(type) | TYPE_OEN_SEL(type) << 8 |
TYPE_OUT_INV(type) << 14 | TYPE_OEN_INV(type) << 15,
GK_GPIO_OUTPUT_CFG(pin));

if (TYPE_IOCTRL(type)) {
v = readl(GK_RCT_IOCTRL_GPIO(pin));
v &= ~(0x3f << shift);
v |= TYPE_IOCTRL(type) << shift;
writel(v, GK_RCT_IOCTRL_GPIO(pin));
}
}

/* After a map is applied, as the vendor gk7101_gpio_initialize() ends */
void gk_gpio_init(void)
{
writel(1, GK_GPIO_IN_EN);
writel(0x11, GK_RCT_IOCTRL_MISC2);
}
Loading