Skip to content

load_goke: opt-in sensor_dvp / sensor_mclk gate for DVP-wired boards - #2276

Open
bneigher wants to merge 3 commits into
OpenIPC:masterfrom
bneigher:w7-dvp-sensor-gate
Open

load_goke: opt-in sensor_dvp / sensor_mclk gate for DVP-wired boards#2276
bneigher wants to merge 3 commits into
OpenIPC:masterfrom
bneigher:w7-dvp-sensor-gate

Conversation

@bneigher

Copy link
Copy Markdown

Adds an opt-in env-var gate so DVP-wired boards can select the DVP pad
routing, without changing behaviour for anything that does not ask for it.

open_sys_config picks MIPI or DVP pad routing from its chip= and
g_cmos_yuv_flag= arguments. On a board that routes the sensor's parallel data,
sync, PCLK and i2c to the SoC's DVP pads, the MIPI arguments mux the i2c
controller to pads the sensor is not connected to — every address NACKs, no chip
ID is ever read, and no video is possible.

Per @widgetii's review note on #2074, this is keyed off an env
var rather than $CHIP_TYPE:

chip=gk7205v200 g_cmos_yuv_flag=1 is right for your W7 wiring but wrong for
MIPI-wired gk7202v300 boards, and there are some in the wild — a blanket change
would break them.

So a profile opts in with fw_setenv sensor_dvp 1. Unset — every existing board —
takes exactly the path it takes today.

sensor_mclk is gated the same way. open_sys_config reads MCLK only from its
module parameters and defaults to 27 MHz at this chip=, so a sensor init table
tuned for 24 MHz (the GC2053 ForCar tables are) runs against the wrong clock.
Worth noting for anyone who hits this: the .ini MCLK key is not consulted on
this path, so sweeping it produces identical results at every value — which is
indistinguishable from having ruled the cause out. That cost me a while.

Companion to the gk7202v300_lite_w7_8m device profile in OpenIPC/builder,
which is where the board-specific bring-up lives.

Verified on three GK-W7 boards (GK7202V300, 8 MB NOR, GC2053 in DVP mode with
SID strapped high): with sensor_dvp=1 and sensor_mclk=24 the i2c bus comes
up, the sensor answers at 7-bit 0x3f with chip ID 0x2053, and the pipeline
delivers 1920x1080 H.264 over RTSP at 25 fps with FrmErrCnt 0. With the vars
unset the script is byte-for-byte equivalent in behaviour to before.

sh -n clean.

Refs: #2074

open_sys_config picks MIPI or DVP pad routing from its chip= and
g_cmos_yuv_flag= arguments. On a board that wires the sensor to the DVP pads,
the MIPI arguments mux the i2c controller to pads the sensor is not connected
to, so every address NACKs and no sensor is ever detected.

Gated on an env var rather than $CHIP_TYPE deliberately: both wirings exist on
gk7202v300, so keying this off the SoC name would fix DVP boards by breaking
every MIPI one. Profiles opt in with 'fw_setenv sensor_dvp 1'; unset means the
current behaviour is unchanged.

sensor_mclk is gated the same way. open_sys_config reads MCLK only from its
module parameters and defaults to 27 MHz at this chip=, so a sensor init table
tuned for 24 MHz runs against the wrong clock -- and the ini's MCLK key is never
consulted on this path, which makes sweeping it look like a ruled-out cause.

Refs: OpenIPC#2074
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

load_goke: opt-in sensor_dvp/sensor_mclk gates for DVP-wired boards

🐞 Bug fix ✨ Enhancement ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Add opt-in sensor_dvp=1 gate to force DVP pad routing without changing defaults.
• Add opt-in sensor_mclk=24 gate to override MCLK when .ini MCLK is ignored.
• Document why env-var gating is used instead of $CHIP_TYPE to avoid regressions.
Diagram

graph TD
  Profile["Device profile"] --> Env[("U-Boot env vars") ] --> Script["load_goke"] --> SysCfg["open_sys_config"] --> I2C["Sensor I2C bus"] --> Sensor["DVP sensor"]
  Script --> Mclk{"sensor_mclk=24?"} --> Devmem["devmem MCLK reg"]
  subgraph Legend
    direction LR
    _cfg["Config/Script"] ~~~ _env[("Env storage")] ~~~ _dec{"Decision"}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Auto-detect DVP vs MIPI via probe fallback
  • ➕ No per-board env configuration required
  • ➕ Can self-heal on misconfigured profiles
  • ➖ Risky/slow boot path (extra probe attempts/timeouts)
  • ➖ Detection may be ambiguous across sensors/boards
  • ➖ Harder to reason about regressions vs explicit opt-in
2. Key routing off `$CHIP_TYPE` or SoC table
  • ➕ Simple implementation; no tooling dependency on U-Boot env
  • ➖ Incorrect when multiple wirings exist for the same SoC (explicitly noted for gk7202v300)
  • ➖ High regression risk for existing MIPI-wired boards
3. Fix in `open_sys_config` to read `.ini` MCLK / add explicit DVP flag
  • ➕ Moves policy into the driver/module where the behavior originates
  • ➕ Avoids devmem register pokes from userland
  • ➖ Requires kernel/module changes and broader validation across boards
  • ➖ Longer turnaround; potentially larger blast radius

Recommendation: Keep the current env-var opt-in gates in load_goke: it’s the lowest-regression approach given mixed DVP/MIPI wiring on the same SoC family. If this pattern expands, consider a follow-up to make open_sys_config accept an explicit DVP/MCLK override (or consult .ini MCLK) to eliminate the devmem workaround.

Files changed (1) +23 / -0

Bug fix (1) +23 / -0
load_gokeAdd opt-in DVP routing and 24 MHz MCLK override via U-Boot env +23/-0

Add opt-in DVP routing and 24 MHz MCLK override via U-Boot env

• Introduces an opt-in 'sensor_dvp=1' gate that forces 'CHIP_TYPE=gk7205v200' and 'YUV_TYPE0=1' so 'open_sys_config' selects DVP pad routing on DVP-wired boards, while preserving default behavior when unset. Adds an opt-in 'sensor_mclk=24' gate to write the MCLK register via 'devmem' because this path does not consult the '.ini' MCLK key and defaults to 27 MHz.

general/package/goke-osdrv-gk7205v200/files/script/load_goke

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 16, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Silent MCLK write failure ✓ Resolved 🐞 Bug ☼ Reliability
Description
insert_ko adds a devmem write when sensor_mclk=24 but does not check whether devmem exists or
whether the write succeeded, so the script can continue with the wrong MCLK while giving no
diagnostic. This can make sensor bring-up fail with little/no signal in logs.
Code

general/package/goke-osdrv-gk7205v200/files/script/load_goke[R188-190]

+	case "$(fw_printenv -n sensor_mclk 2>/dev/null)" in
+		24) devmem 0x120100F0 32 0x0000000D ;;
+	esac
Evidence
The new MCLK path performs a raw devmem write with no || report_error handling, while the script
otherwise uses report_error for module load failures, indicating this omission is an introduced
reliability gap.

general/package/goke-osdrv-gk7205v200/files/script/load_goke[82-106]
general/package/goke-osdrv-gk7205v200/files/script/load_goke[179-190]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new `devmem`-based MCLK override is executed without checking for tool presence or write success. If the write fails, the script continues silently, leaving the system misconfigured.
### Issue Context
This is a shared boot-time module loader script; failures should be explicit to avoid hard-to-debug field breakage.
### Fix Focus Areas
- general/package/goke-osdrv-gk7205v200/files/script/load_goke[184-190]
### Suggested fix
- Check `command -v devmem` before use.
- Check `devmem` exit status; on failure, emit a `logger` message (daemon.err) and either `report_error` or explicitly continue with a warning (but do not fail silently).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. CHIP_TYPE role conflation ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The sensor_dvp opt-in block overwrites the detected CHIP_TYPE globally, conflating the actual SoC
identity with the value intended to steer open_sys_config routing. This makes later CHIP_TYPE-based
logic (present now or added later) harder to reason about and increases the risk of unintended
behavior changes when extending the script.
Code

general/package/goke-osdrv-gk7205v200/files/script/load_goke[R35-38]

+if [ "$(fw_printenv -n sensor_dvp 2>/dev/null)" = "1" ]; then
+	CHIP_TYPE=gk7205v200
+	YUV_TYPE0=1
+fi
Evidence
CHIP_TYPE is initially derived from ipcinfo --chip-name, then globally overwritten by the new
sensor_dvp gate, and subsequently reused as the chip= argument to open_sys_config (and as a
general chip discriminator elsewhere in the script).

general/package/goke-osdrv-gk7205v200/files/script/load_goke[4-10]
general/package/goke-osdrv-gk7205v200/files/script/load_goke[24-38]
general/package/goke-osdrv-gk7205v200/files/script/load_goke[109-115]
general/package/goke-osdrv-gk7205v200/files/script/load_goke[179-184]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`sensor_dvp=1` currently mutates `CHIP_TYPE` (the detected SoC name) for the remainder of the script. This mixes two concepts:
- detected SoC (used for chip-specific branching)
- desired `open_sys_config chip=` selector (used for pad routing selection)
### Issue Context
This script is shared across multiple Goke SoCs/boards; minimizing global state mutation reduces future regressions.
### Fix Focus Areas
- general/package/goke-osdrv-gk7205v200/files/script/load_goke[4-10]
- general/package/goke-osdrv-gk7205v200/files/script/load_goke[24-38]
- general/package/goke-osdrv-gk7205v200/files/script/load_goke[109-115]
- general/package/goke-osdrv-gk7205v200/files/script/load_goke[179-184]
### Suggested fix
- Introduce e.g. `SYS_CONFIG_CHIP="$CHIP_TYPE"` after detection.
- In the `sensor_dvp` block, set `SYS_CONFIG_CHIP=gk7205v200` (and keep `CHIP_TYPE` unchanged).
- Pass `chip=$SYS_CONFIG_CHIP` to `modprobe open_sys_config` in both `insert_detect` and `insert_ko`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread general/package/goke-osdrv-gk7205v200/files/script/load_goke Outdated
Comment thread general/package/goke-osdrv-gk7205v200/files/script/load_goke
…rite MCLK blind

Two findings from review:

1. CHIP_TYPE role conflation. The opt-in was overwriting CHIP_TYPE, which is the
   DETECTED SoC, with the value wanted for open_sys_config's chip= pad-routing
   selector. Those are two different things that happen to coincide by default:
   a DVP board needs the gk7205v200 routing tables while still BEING a
   gk7202v300. Conflating them makes every existing and future CHIP_TYPE branch
   harder to reason about. Now a dedicated SYSCFG_CHIP carries the selector and
   CHIP_TYPE keeps meaning exactly one thing.

2. Silent MCLK write. devmem was called without checking that it exists or that
   the write succeeded. A wrong MCLK does not fail loudly — it yields a corrupted
   or absent image while every log line still looks healthy — so this is exactly
   the case that must not pass quietly. Both failures now log to daemon.err.

Still opt-in and still keyed off env vars: with sensor_dvp unset the script is
behaviourally identical to before.

Refs: OpenIPC#2074
@bneigher

Copy link
Copy Markdown
Author

Thanks — both findings on this PR were fair and are now addressed in f67e5c2.

1. CHIP_TYPE role conflation. Agreed, and this one mattered more than it
looks. The opt-in was overwriting CHIP_TYPE, which is the detected SoC, with
the value wanted for open_sys_config's chip= pad-routing selector. Those are
two different things that merely coincide by default: a DVP board needs the
gk7205v200 routing tables while still being a gk7202v300. A dedicated
SYSCFG_CHIP now carries the selector, so CHIP_TYPE keeps meaning exactly one
thing and existing/future chip branches are untouched by this opt-in. That also
better serves @widgetii's original review note — the whole point is that boards
which do not set sensor_dvp are behaviourally identical to before.

2. Silent MCLK write. Also agreed, and this is precisely the failure mode
worth guarding: a wrong MCLK does not fail loudly, it produces a corrupted or
absent image while every log line still looks healthy. devmem presence and exit
status are both checked now, and either failure logs to daemon.err.

For context on why the MCLK hook exists at all: open_sys_config reads MCLK only
from its module parameters and defaults to 27 MHz at this chip=, while the
GC2053 ForCar PLL tables are 24 MHz values. The .ini MCLK key is never
consulted on this path — so sweeping it produces identical results at every
value, which is indistinguishable from having ruled the cause out. That cost me
a while, and it is the kind of thing worth having in the tree's history.

@widgetii widgetii left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay on this one — you did the hard part and then waited, which is the wrong way round.

I checked this against the pinned SDK source (openhisilicon @ 2d637e35, kernel/sys_config/sys_config.c) rather than just reading the diff. The approach is right and your diagnosis is exactly correct. Two changes I'd like before merge, then this goes in.

What checks out

The DVP lever is the only one that exists. pinmux() dispatches on chip=, and per kernel/compat/compat.h in the goke build C_HI3518EV300 is "gk7202v300". That branch is MIPI-only and ignores cmos_yuv_flag entirely — it unconditionally calls i2c0_for_mipi_sensor_pin_mux_gk7205v200(), sensor_cfg_for_mipi_sensor_mux(), vi_mipi_rx_mux(). There is no DVP path reachable for chip=gk7202v300 at any g_cmos_yuv_flag. Only the gk7205v200 branch honours cmos_yuv_flag == 1i2c0_for_vi_raw_sensor_pin_mux() + vi_raw_mode_mux_gk7205v200(). Your i2c-NACK symptom falls straight out of that. This isn't a hack, it's the only lever.

The SYSCFG_CHIP separation is provably as contained as you say. chip_list feeds only pinmux() and clkcfg() — and clkcfg()'s C_HI3518EV300 and C_HI3516EV200 branches write byte-identical values (0x00A0=0x00240400, 0x00F4=0x00110000, 0x00FC=0x8). So the swap moves pinmux and nothing else. Splitting it out of CHIP_TYPE was the right call.

The MCLK story is confirmed. parse_sensor_clock() returns 0x6 for gc2053, and the file's own table says 0x6: 27MHz. MCLK is sourced only from that sensor-name table, so the .ini key genuinely is never consulted on this path. Your note that sweeping it gives identical results at every value — indistinguishable from having ruled it out — is accurate and worth having in the history. Thanks for writing it down.

1. The devmem write is a blind store to a read-modify-write register

void sensor_clock_config(int index, unsigned int clock)
{
	reg_write32(clock << 2, 0xF << 2, reg_crg_base + 0x00F0);  /* RMW bits [5:2] */
}

reg_crg_base = ioremap(0x12010000), so 0x120100F0 is the right address, and the sns0 select field is bits [5:2] only.

devmem 0x120100F0 32 0x0000000D stores the whole word. Decomposed: 0xD = 0b1101 → bits[5:2] = 0b0011 = 0x3, and the table reads 0x3: 24MHz — so you are selecting the clock you intend, which is why it works on your three boards. But the same store also sets bit 0 and forces bits [31:6] to zero, and nothing in the driver ever writes that register wholesale.

Could you mask to the field instead? It also removes the magic constant and makes the var extensible to the other seven values:

# CRG PERI_CRG60 @ 0x120100F0, sns0 clock select = bits [5:2].
# 0x0:74.25 0x1:72 0x2:54 0x3:24 0x4:37.125 0x5:36 0x6:27 0x7:12 (MHz)
# open_sys_config's sensor_clock_config() read-modify-writes just this
# field -- match that rather than storing the whole word.
cur=$(devmem 0x120100F0)
devmem 0x120100F0 32 $(( (cur & ~0x3C) | (3 << 2) ))

While you're there — add a *) arm that logs a non-empty unsupported value. Right now sensor_mclk=37 does nothing silently, which is the same failure class the rest of this PR is guarding against.

2. sensor_dvp=1 shouldn't unconditionally force gk7205v200

gk7205v300 has its own DVP path (vi_raw_mode_mux_gk7205v300() under cmos_yuv_flag == 1). A DVP-wired v300 that sets sensor_dvp=1 would get pushed onto the v200 VI pad table — the same bug this PR fixes, pointing the other way. Only gk7202v300 lacks a DVP branch and needs to borrow:

if [ "$(fw_printenv -n sensor_dvp 2>/dev/null)" = "1" ]; then
	YUV_TYPE0=1
	# gk7202v300's pinmux() branch is MIPI-only -- it ignores g_cmos_yuv_flag.
	# Borrow gk7205v200's tables (same die family, and they do honour it).
	# gk7205v200/v300 already have their own DVP paths.
	if [ "$CHIP_TYPE" = "gk7202v300" ]; then
		SYSCFG_CHIP=gk7205v200
	fi
fi

Minor

  • logger -p daemon.err -t load_goke — the file's convention is logger -s -p ... -t goke (lines 356, 360, 366, 377). The -s matters here: a failed MCLK write is bring-up-fatal and should reach the console the way "SENSOR is not detected" does.
  • The command -v devmem guard is harmless, but CONFIG_DEVMEM=y is set in general/package/busybox/busybox.config, so it is always present. Keep it if you prefer belt and braces.
  • Asymmetry worth a comment rather than a change: sensor_dvp applies to both insert_detect and insert_ko, but sensor_mclk only to insert_ko, so first-boot autodetect probes at the default clock. Probably fine since i2c is master-clocked, but it will surprise someone eventually.

Before this can merge

  • CI has never run on this branch — fork PRs need workflow approval, so the umbrella gate has nothing to go on. I'll approve the run once you push.
  • The branch is behind master; please rebase.

The firmware/builder split is right — generic mechanism here, board profile in OpenIPC/builder#119. I'll pick that one up next.

Addresses @widgetii's review, which checked this against the pinned SDK source
rather than the diff. Both findings were correct.

1. The devmem write was a blind whole-word store to a register the driver only
   ever read-modify-writes. sensor_clock_config() is
   reg_write32(clock << 2, 0xF << 2, base+0xF0) — bits [5:2] and nothing else.
   0x0000000D happens to put 0x3 (24MHz) in that field, so it worked, but it also
   cleared bits [31:6] and set bit 0. Now masks: (cur & ~0x3C) | (sel << 2).

   Also extended to the full documented table (74.25/72/54/24/37.125/36/27/12)
   instead of a lone magic constant, and an unsupported value now logs instead of
   doing nothing silently — that was the same failure class the rest of this PR
   guards against.

2. sensor_dvp=1 no longer forces gk7205v200 unconditionally. Only gk7202v300
   lacks a DVP branch: its pinmux() case is MIPI-only and ignores
   g_cmos_yuv_flag entirely. gk7205v200 and gk7205v300 have their own DVP paths,
   and pushing a DVP-wired v300 onto the v200 VI pad table would be this very bug
   pointing the other way.

Minor, also from review: logger now follows the file's convention
(logger -s -p ... -t goke). The -s matters — a failed MCLK write is bring-up
fatal and should reach the console the way 'SENSOR is not detected' does. The
command -v devmem guard is kept as belt and braces even though CONFIG_DEVMEM=y,
since the read is now load-bearing too.

The insert_detect/insert_ko asymmetry is documented rather than changed:
first-boot autodetect probes at the sensor table's default clock, which is fine
because i2c is master-clocked, but it is the kind of thing that surprises people.

Refs: OpenIPC#2074
@bneigher

Copy link
Copy Markdown
Author

Thanks for going to the SDK source rather than the diff — that turned a "looks
plausible" review into a checkable one, and both findings were right. Pushed in
1084143.

1. The MCLK write

You're right, and the way it was wrong is worth stating: 0x0000000D selects the
correct clock by accident of the constant, not by writing the field.
Decomposed, bits [5:2] are 0x3 = 24 MHz — but the same store also cleared bits
[31:6] and set bit 0, which sensor_clock_config() never does. It worked on
three boards, which is exactly how a blind store survives review.

Now masked to the field the driver actually touches:

mclk_cur="$(devmem 0x120100F0)"
devmem 0x120100F0 32 $(( (mclk_cur & ~0x3C) | (mclk_sel << 2) ))

I also took your suggestion to make it extensible and filled in the whole table
(74.25/72/54/24/37.125/36/27/12), with a *) arm that logs. You were right that
sensor_mclk=37 silently doing nothing was the same failure class this PR is
supposed to be guarding against — it was inconsistent to guard the write and not
the value.

2. sensor_dvp forcing gk7205v200

This one I should have caught. I generalised a fix from the only board I had.
Only gk7202v300 lacks a DVP branch and needs to borrow; a DVP-wired gk7205v300
setting sensor_dvp=1 would have been pushed onto the v200 VI pad table — the
same bug, mirrored, and harder to diagnose because the flag would look correct.
Now gated on CHIP_TYPE = gk7202v300.

Minor

  • logger -s -p ... -t goke throughout, per the file's convention. Agreed on
    -s: a failed MCLK write is bring-up fatal and should reach the console the
    way "SENSOR is not detected" does.
  • Kept the command -v devmem guard. CONFIG_DEVMEM=y so it is redundant, but
    the read is now load-bearing too, and I would rather a missing tool say so than
    produce an empty $mclk_cur and a nonsense arithmetic expansion.
  • Documented the insert_detect / insert_ko asymmetry in a comment rather than
    changing it, as you suggested — autodetect probes at the sensor table's default
    clock, which is fine because i2c is master-clocked, but now it is written down.

One thing I have not verified

The masked write is correct by inspection and sh -n clean, but it is not yet
tested on hardware
— my three boards are running the previous whole-word store.
I will flash and confirm the sensor still comes up before this merges, and report
back either way. Given the failure mode here is a silently corrupted image rather
than a loud error, I would rather not have "it compiles" standing in for "it
works".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants