Optional SD1 clock-consumer correction, 2026-10-02
Recorded at 2026-10-02T19:54:43Z. Evidence class: read-only host source
inspection and coordinator-reported physical comparison. No kernel/config
change, build, board input or serial access was performed here. A correction
without the diagnostic flag and specific-clock attribution remain UNVERIFIED.
Worktree /home/jadams/tmp/k230-mainline-sd1-clock-consumers, branch
audit/mainline-sd1-clock-consumers, base
9cd4a3f870a62c01d63abae60dc07b309e054c52. Only this note is owned; no board
or build slot was reserved. Start and handoff use cached tools/work-status.py
at idle priority, with output outside the repository.
Observation and source boundary
The coordinator reports the same asj7l4zj5jrjkgng4nrcx3y72p7jf7aa trial
bundle, 4wkhxf55y1abg1kg2xd0acsfjqr64j0h kernel and v9qc1sf0iz53s3x6g6vwfyaxghkfpnyk
system, with volatile clk_ignore_unused, printed clk: Not disabling unused clocks, advanced beyond the earlier MMC shutdown entry, printed
reboot: Restarting system, reached SPL and returned automatically to the
protected normal system. The controller exited 0; a fresh boot ID, profile,
kernel, services and all eight protected hashes passed. This supports dependence
on global unused-clock cleanup. It does not isolate SD1 or any particular gate.
The quiet baseline without the flag remains a failed automatic-return trial.
Physical provenance belongs to the coordinator’s committed comparison packet;
no private capture was read for this note.
The inspected exact source is
/nix/store/jvz4v73g8a67pqwm06v079h6s1cpqr9s-linux-mainline-k230-drm-src,
Linux pin 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e plus optional K230 patches.
Vendor source is /nix/store/pn7bm6ck5a3x6pnk1ng30hlf24qn85jx-source, pin
7d4e1f444f461dbe3833bd99a4640e7b6c2cd529. See the prior
MMC boundary audit and
vendor/mainline clock comparison.
Why three additional consumers are the smallest supported set
Pinned upstream
snps,dwcmshc-sdhci.yaml:115
requires five clocks for canaan,k230-emmc / canaan,k230-sdio, named
core, bus, axi, block, timer. Its
sdhci-of-dwcmshc.c:1947
explicitly obtains/enables the three additional K230 clocks. The current
candidate uses the distinct vendor compatible canaan,k230-dw-mshc and copied
Kendryte driver; that driver only obtains core/bus (:398–410).
The vendor clock-provider source (arch/riscv/boot/dts/canaan/k230_clock_provider.dtsi:465–538)
describes separate SD base, AXI, card-TX and timer branches. Its SD1 definitions
at :617,881,905,959,1081 agree with mainline’s register offset/bit/parent
definitions in drivers/clk/clk-k230.c:454,559,582,592,639:
| DT name | Mainline ID | Vendor role; retained purpose |
|---|---|---|
core | K230_HS_SD1_BASE_GATE = 31 | Base clock; keep existing rate source for sdhci_pltfm_clk_get_max_clock() (sdhci-pltfm.c:31). |
bus | K230_HS_SD1_AHB_GATE = 13 | Register-bus interface clock. |
axi | K230_HS_SD1_AXI_GATE = 29 | AXI branch, distinct from the base branch despite their shared upstream source. Relevant to controller/data traffic; this trial does not prove it alone blocked shutdown. |
block | K230_HS_SD1_CARD_GATE = 26 | Vendor card-TX branch from the SD card-clock source. This is the proposed semantic translation to the K230 binding’s block name; no upstream board DTS at this pin supplies a concrete ID-26 example. |
timer | K230_HS_SD1_TIMER_GATE = 35 | Separate oscillator-derived SD timer branch, not the Linux scheduler timer. Its necessity in the observed failure is unproved. |
All three extras currently have flags 0 and no consumer. Vendor clock init
adopts firmware-enabled gates (drivers/clk/clk-k230.c:538–547); mainline
ordinary gates do not. Claiming only AXI, card or timer would select a hypothesis
unsupported by the global comparison. Claiming the whole provider or marking
these clocks permanently critical would bypass device ownership. Five clocks
are the smallest source-supported host resource set, not a proven minimal
hardware subset.
Concrete proposed patch, not applied
Keep the existing base forward port and console/default DT outputs untouched.
Add an optional DRM-only patch to the existing applyPatches.patches list in
kernel-mainline-drm.nix, applied to the
already-copied drivers/mmc/host/sdhci-of-kendryte.c. Add this override only to
k230-tdisplay-mainline-drm.dts:
&mmc_sd1 {
clocks = <&sysclk K230_HS_SD1_BASE_GATE>,
<&sysclk K230_HS_SD1_AHB_GATE>,
<&sysclk K230_HS_SD1_AXI_GATE>,
<&sysclk K230_HS_SD1_CARD_GATE>,
<&sysclk K230_HS_SD1_TIMER_GATE>;
clock-names = "core", "bus", "axi", "block", "timer";
};
Extend the private driver state and acquire the extras before enabling them:
/* In struct dwcmshc_priv: */
struct clk_bulk_data other_clks[3];
/* In probe, after obtaining priv: */
priv->other_clks[0].id = "axi";
priv->other_clks[1].id = "block";
priv->other_clks[2].id = "timer";
err = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(priv->other_clks),
priv->other_clks);
if (err)
return dev_err_probe(&pdev->dev, err, "failed to get SD clocks\n");
/* After successful core/bus enable, before sdhci_add_host: */
err = clk_bulk_prepare_enable(ARRAY_SIZE(priv->other_clks), priv->other_clks);
if (err)
goto disable_bus_clk;
Use mandatory lookup for all five resources in this matched optional candidate, including checking bus lookup and enable errors. A missing resource or deferred provider must fail probe cleanly, rather than quietly recreating the defect. The upstream helper’s optional lookup preserves other-platform compatibility; the proposed candidate has a matching five-clock DT and no enabled SD0 host. Keep existing max-frequency, clock-rate/divider programming, PHY choice, IRQ, reset and DMA semantics. Do not swap the entire upstream host driver or change compatible: the upstream K230 path also requires USB-PHY/regmap integration and differs beyond resource ownership. The current legacy compatible is not accepted by the upstream schema; five names alone do not make the full node schema-valid.
| Lifecycle | Required ordering/error handling |
|---|---|
| Probe | Acquire resources with managed lifetime; enable core, bus, then bulk extras before registering the host. On later failure disable extras, bus, core. Failed bulk enable unwinds itself; do not disable that bulk twice. |
| Remove | sdhci_remove_host() completes first; then disable extras, bus, core. The host must retain resources while draining/removing requests. |
| Suspend | Call sdhci_suspend_host() first; on error retain clocks. Only on success disable extras, bus, core. |
| Resume | Enable core, bus, extras, then call sdhci_resume_host(). Every failed enable/host-resume step unwinds only successfully enabled resources in reverse order. Existing immediate bus-error return leaks a core enable; correct it as part of this lifecycle change. |
| Reboot | Add no clock-disabling .shutdown. MMC card shutdown precedes the platform host and can claim the host, issue SD commands and reset/power off the controller. Keep resources claimed through that sequence; existing platform driver has no shutdown callback. |
Narrow build and physical proof plan, not run
This fits the existing mainline usable-root and bounded restart diagnosis;
no new capability or normative clock policy is proposed. After review, prepare
the exact patched source/config and compile only drivers/mmc/host/sdhci-of-kendryte.o
with the matching RISC-V kernel toolchain before a full build. Host object/API
proof, full kernel, DTB and matched trial bundle are separate gates:
nix build .#kernelMainlineDrm .#deviceTreeMainlineDrm --no-link
nix build .#kernelMainlineDrmTrialBootFiles --no-link
Check the built SD1 node’s exact five IDs/names, absence of global clock flags, new source/kernel/DTB/system pins and per-artifact SHA/size manifest. Compare unchanged vendor/default and console derivation identities to the base. Review lookup/enable failure unwind and suspend/resume paths; static fake clock tests alone are not physical ownership proof.
The exclusive operator then stages only the reviewed matching optional bundle
and runs the same quiet minimal/runtime-trace controller with explicit --bundle
and --normal-report, without --ignore-unused-clocks. Require readiness,
minimal/runtime-Y gates, clk: Disabling unused clocks, real reboot, SPL,
fresh protected normal boot identity and all postflight checks within the same
180-second deadline. Any unknown child/return means stop input and preserve
manual recovery. A passing result tests this targeted correction, not per-gate
attribution. Only after baseline automatic recovery works proceed separately to
the returned read-only label and ro,noload root diagnostics. Usable root,
ordinary /init and deliberate touch remain task 5b.5’s open physical gates.
Host checks for this note: git diff --cached --check and
openspec validate the-board-runs-a-mainline-kernel --strict passed. Review,
merge/push, source implementation, build and physical proof remain; no source
change or new board claim is supplied by this document.