Remix Mini PC: 1년간 난관을 겪은 뒤 eMMC가 드디어 작동.
출처: Dev.to
소스 파일: GitHub
1년 넘게 Remix Mini PC 프로젝트에서 같은 벽에 부딪히고 있었다. SD 카드에서 정상적인 Linux를 사이드로드는 할 수 있었지만, 내부 eMMC는 검은 상자였다. 읽으려는 모든 시도는 I/O 오류를 반환했다. 쓰기 방지 비트, NAND 블랙리스트, 하드웨어 리셋 특이점, Android가 남긴 락아웃 상태 등 모든 이론을 시도했지만 어디에도 도달하지 못했다.
원인은 그 어떤 것도 아니었다. 디바이스 트리의 한 줄이 빠져 있었던 것이다.
Remix Mini PC는 Allwinner SoC(“H64”라는 이름으로 마케팅되며, 보다 흔한 A64와 동일한 실리콘) 기반의 2015년형 Android 데스크톱 박스다. 기본 펌웨어는 제조사가 오래 전에 포기한 잠긴 Android 변형이었다. 프로젝트 목표: 내부 eMMC에 영구적으로 Armbian을 설치한다.
세션 시작 시 상태
FEL 모드에서 메인라인 U‑Boot 사이드로드가 작동함( BananaPi‑M64 defconfig 로 빌드)
SD 카드 부팅이 로그인 프롬프트까지 정상 동작(Armbian 24.11.1, 커널 6.6.62)
내부 eMMC에서 읽으려 하면 즉시 커널 오류 발생:
sunxi-mmc 1c11000.mmc: data error, sending stop command sunxi-mmc 1c11000.mmc: send stop command failed mmc2: cache flush error -110 mmc2: tried to HW reset card, got error -110 mmcblk2: recovery failed!
커널은 칩을 인식한다—CID, CSD, 14.6 GiB 용량, 파트명(AGND3R) 등을 읽어오지만, 호스트가 실제 데이터를 요청하는 순간 버스가 붕괴된다. **시도한 조정들** | 조정 항목 | 시도 | 결과 | |---|---|---| | 버스 클럭 | 150 MHz → 25 MHz → 1 MHz | 동일한 실패 | | 버스 모드 | HS200, HS400, 1.8 V 신호 비활성화 | 동일한 실패 | | 버스 폭 | 8‑bit → 4‑bit | 동일한 실패 | | HW 리셋 기능 | cap‑mmc‑hw‑reset 제거 | 동일한 실패 | | 핀 멀티플렉싱 | HS400 데이터‑스트로브 핀 제거 | 동일한 실패 | 실패 양상이 전혀 변하지 않았다. 이는 “신호 속도 조정이 전혀 효과가 없으면 문제는 신호 계층이 아니다”라는 힌트를 주었다. 웹 검색을 통해 알게 된 사실: Remix Mini PC는 메인라인 Linux에서 `sun50i-h64-remix-mini-pc.dts` 라는 이름으로 지원되고 있었으며, 이는 ARM의 Andre Przywara가 기여한 것이다. 해당 DTS는 커널 트리 `arch/arm64/boot/dts/allwinner/`에 위치한다. 대응되는 U‑Boot 패치는 2024년 4월에 적용되었다. 공식 Remix DTS를 가져와서 내가 사용하던 BananaPi‑M64 DTS와 나란히 비교했다. eMMC 블록 부분의 차이가 눈에 띄었다: ```dts &mmc2 { pinctrl-names = "default"; pinctrl-0 = <...>, <...>; vmmc-supply = <®_vcc>; // 칩 Vcc, 3.3V — 존재함 vqmmc-supply = <...>; // I/O 전압, 1.8V — **누락됨** bus-width = <8>; non-removable; mmc-hs200-1_8v; mmc-hs400-1_8v; cap-mmc-hw-reset; };BananaPi‑M64 DTB는
vmmc-supply(eMMC 칩 자체에 전원을 공급하는 레귤레이터)만 선언하고,vqmmc-supply(eMMC 버스 신호 라인을 구동하는 별도 레귤레이터)에 대해서는 전혀 언급하지 않는다.eMMC는 두 개의 전압 도메인을 사용한다. Vcc(
vmmc레일)는 칩 내부 로직에 전원을 공급하고, VccQ(vqmmc레일)는 CLK, CMD, DAT0‑7 등 I/O 라인에 전압을 제공한다. Remix 보드에서는 이 레일이 다른 레귤레이터(eldo1, 1.8 V)와 연결되어 있다. 커널이 이 레귤레이터를 알지 못하면 전원이 켜지지 않아 데이터 버스 라인에 구동 전압이 공급되지 않는다.이 설명이 모든 것을 밝혀 주었다. 명령/응답 채널은 이미 전원이 공급돼 초기화가 성공했지만, 호스트가 DAT0‑3을 통해 데이터 전송을 시도하자마자 버스가 붕괴된 것이다. 받을 것이 없었기 때문이다.
누락된 속성을 SD 카드에 있는 라이브 DTB에 추가했다:
sudo fdtput -t i /boot/dtb/allwinner/sun50i-a64-bananapi-m64.dtb \ /soc/mmc@1c11000 vqmmc-supply 0x4e
0x4e는 같은 DTB에 정의된eldo1레귤레이터 노드의 phandle이며, BananaPi‑M64 보드에서는 오디오 코덱에 사용되지만 Remix에서는 eMMC I/O 레일에 해당한다. 동일한 레귤레이터 하드웨어를 올바른 소비자에 연결한 것뿐이다.재부팅 → FEL을 통해 U‑Boot 사이드로드 → 로그인 → 테스트 실행:
sudo dd if=/dev/mmcblk2 bs=1M count=1 of=/tmp/test.bin status=progress 1+0 records in 1+0 records out 1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,0482 s, 21,7 MB/s1 MiB를 50 ms 만에 읽어냈다. 1년 넘게 한 바이트도 읽히지 않던 칩에서 나온 결과다.
추가로 EXT_CSD 레지스터를 조회했는데, 이는 블록 읽기와 다른 MMC 명령 경로를 사용한다—역시 정상 작동했다. 그리고 기대하지 않았던 정보를 얻었다:
BOOT_WP_STATUS: 0x00 // 쓰기 보호되지 않음 BOOT_WP: 0x00 // 쓰기 보호되지 않음 USER_WP: 0x00 // 쓰기 보호되지 않음 BOOT_CONFIG_PROT: 0x00 // 부트 설정 변경 가능 PARTITION_SETTING_COMPLETED: 0x00칩은 잠겨 있지 않다. 한 번도 잠긴 적이 없으며, Linux 수준의
force_ro플래그와 I/O 오류만으로 “영구 쓰기 보호”라고 생각했던 것은 잘못된 추론이었다. 버스가 데이터를 전송하지 못했기 때문에 칩 자체를 볼 수 없었던 것이다.이번 세션에서 얻은 교훈
- 공식 upstream 문서를 먼저 찾자 – 디버깅 세션에서 가장 가치 있는 아티팩트는 메인라인에 있는
sun50i-h64-remix-mini-pc.dts파일이었다. 15분 정도 읽는 데서 며칠을 절약할 수 있었다. Remix Mini PC가 2023년부터 메인라인 지원을 받고 있었다는 사실을 몰랐던 것은 내 책임이다.- 튜닝이 실패 모드를 바꾸지 않으면, 그 레이어가 원인이 아니다 – 클럭 속도를 5배, 30배, 150배까지 바꿨지만 증상이 변하지 않았다면, 문제는 “버스 신호” 아래에 있다는 신호다.
- 칩이 스스로 말하는 것과 호스트가 보는 것을 구분하라 –
force_ro같은 블록 디바이스 플래그는 소프트웨어 수준의 안전 장치일 뿐이다. 실제 쓰기 보호 상태는 EXT_CSD 레지스터에 있으며mmc-utils로 조회할 수 있다. vqmmc 문제가 해결되기 전까지는 이 레지스터도 읽을 수 없었다.- 두 개의 전압 레일을 기억하라 – eMMC는 항상 Vcc와 VccQ 두 레일을 가진다. 하나만 설정하면 칩은 열거는 되지만 모든 데이터 전송을 조용히 거부한다. 이제는 이 사실을 절대 잊지 않을 것이다.
eMMC가 읽히게 된 것은 큰 이정표지만, 프로젝트의 최종 목표는 USB‑OTG FEL 트리거 없이 내부 저장소에서 Linux를 부팅하게 하는 것이다. 이는 별개의 문제다—Allwinner A64 부트 ROM이
TOC0라는 서명된 이미지 포맷을