Skip to content

← Firmware Downloads

Post-install setup · Reborn (Y2Linux) · Y2

Y2 storage hardware ceiling — eMMC and SD bus modes

Debian-based Linux with a fast clickwheel interface for the Innioasis Y2.

Instructions published by the project, shown here word for word.

Y2 storage hardware ceiling — eMMC and SD bus modes

> **Superseding physical evidence, 2026-10-04:** the installed Baseline02 now > passes bounded HS200 and SDR104 read/write/hash, fsync and runtime-PM checks. > See [the Platform 1.0 storage pass](Y2-PLATFORM-V1-STORAGE.md) for exact modes, > measurements and remaining qualification gaps. The record below preserves > the source-only state at its original date.

Source and software record, 2026-10-01. The ceilings below come from stock Y2 binaries, the MT6582 BSP source, the installed eMMC's EXT_CSD and the MT6323 regulator tables. The implementation is software-validated. No bus mode above 50 MHz has run on a Y2 under Linux yet. The candidate section records what was built. Physical results belong in a separate report.

Before this pass both hosts ran at 50 MHz SDR. The eMMC used 8-bit HS52 and the SD used 4-bit SD High Speed at 3.3 V. That limit came from our own device tree, not from the hardware.

Answers

QuestionAnswerBasis
Can the eMMC go beyond 50 MHz?YesHS200 at 200 MHz: host source 200 MHz, card type 0x57, IO fixed 1.8 V, stock msdc0 flags include MSDC_UHS1 (BSP maps it to the HS200 capability)
Is DDR52 possible?YesCard type bit 2 (DDR52 1.8/3 V); stock msdc0 flags include MSDC_DDR; DDR clock = source/4 = 50 MHz
Is 100 MHz / HS200 possible?Yes, HS200 at 200 MHzMainline CMD21 tuning on PAD_TUNE/IOCON (MSDC v4, mt8135_compat). An HS200 bus held at 100 MHz (y2_clock_limit_hz) moves as many bytes as DDR52, so the ladder falls from 200 MHz HS200 straight to the untuned DDR52
Is HS400 possible?NoThe card supports it (bit 6), but MT6582 MSDC has no data strobe / EMMC50 block
Can SD use 100 MHz?YesSDR50 runs at source/2 = 100 MHz
Is SDR50 possible?YesStock msdc1 flags include MSDC_UHS1 → SDR50/SDR104
Is 1.8 V UHS wired?YesStock msdc_sd_power_switch (0xc04f2b60) sets MT6323 VMC to 1800 mV and applies dedicated 1.8 V pad drive values; VMC's table is {1.8, 3.3 V}
Is SDR104 possible?Yes, at 200 MHzThe 200 MHz source is undivided. The spec allows up to 208 MHz, so 200 MHz is the host maximum. CMD19 tuning

These answers depend on the card that is inserted. A card without UHS-I, or one that refuses 1.8 V, negotiates SD High Speed at 3.3 V as before.

Evidence

ItemFindingSource
msdc0 board flags0x3c0 = SYS_SUSPEND, HIGHSPEED, UHS1, DDR; 8 data pins; drive clk/cmd/dat 4/2/2hash-identified stock kernel msdc_hw record, out/platform-v1-physical-bringup/stock-reference/msdc-board-platform-data.json
msdc1 board flags0x3e3 = CD, WP, REMOVABLE, SYS_SUSPEND, HIGHSPEED, UHS1, DDR; 4 pins; drive 7/7/7 at 3.3 V, sd_18/sdr50/ddr50 drive 4same
Flag mappingUHS1 → MMC_CAP_UHS_SDR12/25/50/104 + MMC_CAP2_HS200_1_8V_SDR; DDR → UHS_DDR50, 1_8V_DDRMT6582 BSP mt6582/sd.c
eMMC powerStock powers only VEMC_3V3 (card VCC, 3.3 V). The VIO18 line is commented out: eMMC IO is the always-on 1.8 V VIO18 rail. msdc_ops_switch_volt returns 0 for eMMCBSP msdc_emmc_power, stock disassembly
eMMC IO rangeDVDD18_MSDC0 1.7–1.95 V; MediaTek's own reference board uses vqmmc = vio18MT6592 datasheet, mt8173-evb.dts
SD powerVMCH 3.3 V card supply, VMC IO supply 3.3 V → 1.8 V on switch; then Schmitt trigger, RDSEL/TDSEL (0 in both modes on MT6582) and the 1.8 V drive table; 10 ms after power-on and power-offstock msdc_sd_power, msdc_sd_power_switch, msdc_set_driving (0xc04f28c0)
EN18IO comparatorAbsent from MT6582 (REMOVEED_FOR_MT6582, no stock symbol)BSP, stock symbols
Pad drive cellsGPIO 0x10005000, bits 10:8; MSDC0 0xc00/0xc10/0xc20, MSDC1 0xc40/0xc50/0xc60stock msdc_set_driving
Source clockLK selector 1: MSDCPLL 400 MHz / 2 = 200 MHz; undivided 200, /2 = 100, DDR = src/4 = 50 MHzkernel/platform/clocks.c, LK
eMMC cardEXT_CSD[196] = 0x57: HS26, HS52, DDR52, HS200 1.8 V, HS400 1.8 Videntification readback
Stock tuningError-driven retune (msdc_tune_cmdrsp/read/write, AUTO_K), dropping modes after power-cycle failures. Mainline's CMD19/21 sweep uses the same PAD_TUNE/IOCON fieldsstock disassembly, mainline msdc_execute_tuning

Extracted disassembly is kept privately in out/storage-ceiling-source/stock/.

Implementation

PartSourceWhat it does
Ladders and policykernel/platform/storage-modes.hLadder levels, card-capability parsers, fallback rule, EXT_CSD identity bytes, stock pad drive table
Driverkernel/patches/0009-y2-msdc-readonly.patch (mtk-sd.c)Per-level caps (DT caps ∩ level) and clock cap; voltage switch with VMC and pad drive; tuning record; fault classification; fallback worker; post-negotiation readback; y2_storage status
Pad drivekernel/platform/pinctrl.c y2_msdc_pad_drive()The GPIO block owner writes the stock 3.3 V or 1.8 V drive values under its lock; probe returns -EPROBE_DEFER until pinctrl is up
Request firewallkernel/platform/storage-policy.hAdmits CMD21 (tuning block read, no address) and the CMD6 values HS200 needs: HS_TIMING ≤ 2 with default drive strength, BUS_WIDTH 5/6 (DDR). HS400 and drive-type changes stay denied
Device treekernel/dts/innioasis-y2-production.dtsmmc0: mmc-ddr-1_8v, mmc-hs200-1_8v, vqmmc = VIO18 (fixed, always-on), no vmmc. mmc1: all UHS-I modes, vmmc = VMCH 3.3 V, vqmmc = VMC 1.8–3.3 V. Rails exist only in the production DT, each with a consumer
Statustools/platform/y2_platform/observe.pystorage.controllers[].mode carries the decoded y2_storage line
Reborncrates/reborn-platform/src/client.rs (Reborn b92d312)Diagnostics → Storage shows mode, card, tuning and faults per host

Negotiation and fallback

The MMC core negotiates the highest mode both the host and the card admit. The current ladder level limits what the host offers.

HostLadder (highest → lowest)
eMMCHS200 200 MHz → DDR52 50 MHz DDR → HS52 50 MHz → HS 25 MHz → legacy 13 MHz
SDSDR104 200 MHz → DDR50 50 MHz DDR → SDR50 100 MHz → HS 50 MHz 3.3 V → HS 25 MHz → legacy 13 MHz

The SD ladder follows the core's own preference, SDR104 > DDR50 > SDR50, so SDR50 comes after DDR50. A 1.8 V switch failure skips every remaining UHS level.

TriggerAction
Tuning failure (CMD19/21)tuning event; the next level is applied to the caps. The core then falls back on this init
1.8 V switch failure (SD)voltage event; skip to 3.3 V HS
CRC / timeout at a tuned timingThe core retunes first; a second strike at the same level downgrades
CRC / timeout at an untuned timing, controller data errorImmediate downgrade
Readback mismatchverify event, downgrade with card re-init. 500 ms after any high timing is set, eMMC re-reads EXT_CSD and compares the identity bytes the core itself treats as read-only (plus SEC_COUNT). SD reads SD_STATUS twice; both copies must match and report 4-bit width

A downgrade lowers the caps first. If the current timing is still admitted, only the clock changes. Otherwise the card is re-initialised with mmc_hw_reset(). The core flushes the cache first. On eMMC its "power cycle" changes no rail (no vmmc, VIO18 always-on), so the card sees a CMD0 re-initialisation. SD is power-cycled through VMCH. If re-init fails, the next level is tried. The filesystem never stays on a mode that failed.

Safety

Boot controls

ParameterEffect
y2.emmc_mode=<level>eMMC ceiling, e.g. HS52 for the previous behaviour
y2.sd_mode=<level>SD ceiling, e.g. HS for 3.3 V 50 MHz
y2.mmc_safe=1Existing safe storage mode: 26 MHz source, legacy 13 MHz, no high-speed caps

y2_clock_limit_hz also accepts 13/25/50/100/200 MHz at runtime.

Diagnostics

/sys/bus/platform/devices/1123{0,4}0000.mmc/y2_storage is one line of key=value:

`host level ceiling timing width clock_hz actual_hz cap_hz signal_mv vqmmc_mv card_level card_caps hs400_card tuning tuning_runs tuning_failures tune_iocon tune_pad tune_rddly0 voltage_switches verify fallbacks resets reset_error clock_error drive_before crc_events timeout_events controller_events tuning_events voltage_events verify_events`

y2-platform status exposes it as storage.controllers[].mode, and Reborn Diagnostics shows it as plain text. No register decoding is needed.

Tests

TestCovers
tests/test_storage_ceiling.py (11)Ladder invariants, card parsing (EXT_CSD type, SD bus modes), pad table, caps never exceed DT, safe mode, fallback with re-init and repeated failure, fault classification, retune strikes, voltage/tuning hooks, SD_STATUS readback, empty-slot reset, runtime-PM retained registers incl. DDR, status parsing, DT rails
tests/test_mmc_requests.pyCMD21 is the only new read; CMD6 183/185 admitted values
tests/test_mmc_context.pyEXT_CSD identity copy saved at legacy timing only
Existing storage and overlay testsUnchanged contracts still pass

Candidate receipt

FieldValue
Linux built source540ae029b13940d4b2dfe21902bed71b89cb117a (later commit 2c1ab53 changes only tests/test_storage_recovery.py; validation ran there)
Reborn built sourceb92d312cc2dc4b74f57a1a9a7b1407e34707137a (0.2.0)
Kernel6.18.0-y2linux-storage-ceiling
Root / release / build2025.02.18-platform-v1.11 / 1.0.0-storage-ceiling-candidate.1 / Y2LINUX-STORAGE-CEILING
BaseReborn Product UI v2 candidate (Linux 5cfe04cb, Reborn bd8436dd)
FallbackExact Hardware02 pair (6.18.0-y2linux-hardware-02, 2025.02.18-platform-v1.4)

The shipped DTB declares mmc0 mmc-ddr-1_8v, mmc-hs200-1_8v and vqmmc→VIO18 (1.8 V, always-on). It declares mmc1 sd-uhs-sdr12/25/50/104 and sd-uhs-ddr50 with vmmc→VMCH (3.3 V) and vqmmc→VMC (1.8–3.3 V). Both hosts allow 200 MHz. No VEMC_3V3 node exists.

CheckResult
Kernel build (mtk-sd.c, pinctrl.c also W=1)PASS, no warnings in storage sources
DT gate (dev_dtb.py, reviewed storage rails/modes)PASS on the built DTB; mutation test rejects HS400, unknown modes, changed supply, switchable eMMC IO
Production/platform regression (tools/production/tests.sh, container)PASS, 281 tests, 3 explicit native-dependency skips
Native host-dependency tests (test_system_update_fallback)PASS
Reborn cargo fmt --check, clippy --workspace --all-targets --locked -D warnings, cargo test --workspace --lockedPASS, 212 tests
Reborn ARM QEMU check, installed ARM modules, ELF closurePASS
Release inventory (at the built commit), legal-infoPASS
Preserving package (system_update.py)PASS: clean ext4, BOOTIMG/Y2ROOT only, no Y2DATA payload, exact Hardware02 fallback

The first build, from 0e62046, was stopped by the DT gate. That gate still pinned 50 MHz and admitted no MMC supply. 540ae02 taught the gate the reviewed set. The first container run then failed one stale test, which 2c1ab53 fixed. Logs are kept in out/storage-ceiling/superseded-*.

out/y2linux-storage-ceiling-candidate/: MT6582_preserve_data_scatter.txt selects only BOOTIMG and ANDROID/Y2ROOT. Nothing was flashed or pushed.

FileSHA-256
BOOTIMG.img4332d4f284e9ee76b4d76985480c184ebaacd7c674a3656925ff290ef3cd501c
Y2ROOT.img72eab34a39255a1b7f2eba0fe0a6abd891a0b089f8fb847cf42ad8eec033ba72
fallback/BOOTIMG.imgb2a2c3bcb7cc7783828882e447e8b867453cb5b65846ce63577076b1ca4afeea
fallback/Y2ROOT.img63dbd0a198cd86e847c10ed163fd14b2cbe269595fa1988c99ac8393160bb547

First boot checks for the owner

  1. cat /sys/bus/platform/devices/11230000.mmc/y2_storage should show

    `level=HS200 timing=hs200 width=8 actual_hz=200000000 signal_mv=1800 tuning=pass verify=passwith all*_events=0`. Reborn shows the same under Diagnostics → Storage.

  2. With a UHS-I card inserted, 11240000.mmc/y2_storage should show

    level=SDR104 (or DDR50/SDR50, as the card supports) with signal_mv=1800 and voltage_switches ≥ 1. With a non-UHS card it should show HS at 3300 mV.

  3. Run the existing storage hash rounds on /data and /media/sd. Then

    remove the card and insert another; the SD level should start from the ceiling again.

  4. Any fallbacks > 0 names the failing level and event in the kernel log

    (Y2 storage fallback <from> -> <to> (<event>)). If boot itself fails, boot the fallback pair, or add y2.emmc_mode=HS52 y2.sd_mode=HS (previous modes) or y2.mmc_safe=1.

First device check and candidate 2

The first candidate booted on 2026-10-01.

Commit 61a353b admits only VMC enable (DIGLDO_CON3 bit 12), VMCH enable (CON5 bit 14), the VMC 1.8/3.3 V selector (CON24 bit 4) and the VMCH selector pinned to 3.3 V (CON26 bit 7). VEMC_3V3 stays unwritable. A PWRAP test drives the exact regulator writes through the gate.

FieldValue
Linux built source4db6d6dee8e8b21d85f4f7dfa8e6b7aac82d5e56
Reborn built sourceb92d312cc2dc4b74f57a1a9a7b1407e34707137a
Kernel / root / release / build6.18.0-y2linux-storage-ceiling-02 / 2025.02.18-platform-v1.12 / 1.0.0-storage-ceiling-candidate.2 / Y2LINUX-STORAGE-CEILING-02
ValidationProduction/platform 281 tests PASS (3 native skips); Reborn ARM QEMU, installed ARM, ELF, release inventory, legal-info, preserving package PASS
BOOTIMG.img5c17f744a0569feb16f6954531024ae7dcafee10bf14cbdb2eb18ba5d083fd36
Y2ROOT.imgdc611011ce6f129cf18a61a28f9435e2504ade1d416f0b78d6db26764fd20a59

Package: out/y2linux-storage-ceiling-02-candidate/. It supersedes the first candidate. Not flashed by this pass.

Published by the schulzcode/y2linux project [1] [3]