HiMedia Q10 Pro chạy Linux mainline 6.18
🌿 buddingupdated 2026-10-14#linux#phan-cung#tv-box#mainline#hi3798cv200#tai-lieu
Viết cho ai đang cầm một con Q10 Pro, hay bất kỳ thiết bị Hi3798CV200 nào. Kết quả nào cũng đo trên máy thật và có bằng chứng ghi ngay bên cạnh. Chỗ nào mình chỉ suy ra, mình ghi rõ là suy ra.
English: HiMedia Q10 Pro on mainline Linux 6.18.

Tóm tắt
- Máy: HiMedia Q10 Pro (2016). Chip HiSilicon Hi3798CV200, RAM 2 GB, khay ổ cứng 3.5", đồng hồ VFD mặt trước, ra tiếng qua RCA, quang và HDMI. Firmware cuối cùng là Android 7, kernel 4.4 của hãng.
- Kết quả: Debian trixie (armhf) trên Linux 6.18.55, cộng một bộ patch tự làm. Màn hình, GPU, giải mã video phần cứng chuẩn từng bit, âm thanh ra đủ mọi cổng, mạng dây, WiFi, USB 3, remote và đồng hồ mặt trước đều chạy. Bật máy lên có menu trên TV để chọn Desktop, Nghe nhạc, Kodi, Web hoặc Android 13.
- Không lo brick. Mình chỉ sửa biến môi trường của U-Boot, và trả lại như cũ được. Rút USB ra là máy lại vào Android gốc.
- Thời gian: khoảng năm ngày, không có cổng serial.
Vấn đề
Phần cứng con này còn ngon, chỉ có phần mềm là đã chết. Câu hỏi đặt ra: làm sao cho nó chạy một hệ điều hành mới, còn được cập nhật, mà vẫn giữ được giải mã video phần cứng?
- Lên Android mới hơn là không thể. Blob video, HDMI và GPU đều build theo BSP 4.4 của HiSilicon. Hãng đã bỏ mảng set-top box, nên sẽ không bao giờ có BSP mới.
- Ghép kernel của hãng với Debian thì vào ngõ cụt. Blob dùng API MSP riêng của HiSilicon, không phải V4L2 hay DRM. Kodi, mpv, FFmpeg hay Chromium đều không gọi được, rốt cuộc vẫn giữ driver cũ mà không có video phần cứng.
- Không có cổng serial, và bootloader gốc để
bootdelay=0. Kernel treo hay kernel chạy ngon trông y như nhau: màn hình đen, ping không trả lời.
Hướng giải
Chạy Linux mainline (bản longterm 6.18) ở chế độ 32-bit, driver media nào thiếu thì port hoặc tự viết.
- Boot: sửa U-Boot để ưu tiên kernel trên USB, không có thì quay về Android trong eMMC.
- Debug khi không có console: dùng watchdog của chip làm kênh báo trạng thái.
- Video: port driver giải mã V4L2 (VDH) và khối hậu xử lý (VPSS) từ một cây kernel 6.12 của cộng đồng.
- Âm thanh: khối audio (AIAO) chưa có driver dùng được, nên mình viết một driver ALSA nhỏ dựa theo cách SDK của hãng lập trình thanh ghi.
- Userland: Debian, một menu chọn phiên trên TV, và chuỗi
kexecđể kernel lỗi không bao giờ làm máy hết boot được.
Vì sao 32-bit: firmware boot và TEE đều là 32-bit, nên kernel phải chạy AArch32. App chỉ có bản arm64 sẽ không chạy.
Các bước
Nên làm đúng thứ tự, vì bước trước cho bạn công cụ để làm bước sau.
1. Lấy root và sao lưu trước khi đụng vào bất cứ thứ gì
Firmware gốc là bản eng, có ro.debuggable=1, nên chỉ cần adb root là có root, không phải ghi gì vào máy. Dùng nó để dump cả 19 phân vùng eMMC, rồi so sha256 của từng file với sha256 tính ngay trên máy. Lưu luôn bản firmware gốc đúng phiên bản. Máy của mình chạy HMD-2.1.7, và fingerprint trong gói phải khớp với ro.build.fingerprint của máy.
2. Cho U-Boot boot từ USB trước
Bootloader gốc có sẵn USB host và đọc được FAT (usb start, fatload), chỉ là không ai cấu hình. Sửa bootcmd trong biến môi trường để nó:
- nạp
trustedcore(TEE) trước, như lệnh gốc; - thử
fatload+bootmfileuImagetrên USB; - nếu không được thì chạy tiếp các lệnh eMMC gốc, giữ nguyên từng chữ.
Không cắm USB, hoặc bootm từ chối kernel, thì máy vào Android như thường. Giữ lại bản dump biến môi trường gốc để ghi trả khi cần.
⚠️ Biến môi trường gốc có verify=n: bootm không kiểm CRC của uImage. Image hỏng vẫn được chạy chứ không bị từ chối, và máy đứng luôn. Hãy kiểm cả hai CRC và trường arch trước khi chép image vào USB.
3. Build kernel và device tree
- Linux 6.18,
ARCH=arm. Port device tree từ file arm64hi3798cv200.dtsicủa upstream; board Poplar là họ hàng gần nhất. - Driver nào cần để boot thì phải để
=y. Mình từng để reset controller của PHY mạng (RESET_TI_SYSCON) là=m, trong khi initramfs không nạp module nào, thế là PHY không bao giờ được reset. - MAC mạng chỉ quét node con trực tiếp để tìm bus MDIO, nên node PHY phải đặt ngay dưới MAC, không bọc trong
mdio {}. Thêmhisilicon,phy-reset-delays-uscùng lúc với reset. - WiFi (AP6255) cần GPIO4_6 (
WL_REG_ON) và chân SDIO ở mức 1.8 V. - Chạy thử kernel + initramfs + PID 1 trên QEMU (
-M virt) trước. Nhớ boot filezImagetrần, đừng dùnguImage: có DTB gắn kèm thì bộ giải nén sẽ bỏ qua device tree mà QEMU đưa vào.
4. Debug khi không có console: watchdog làm "thước đo"
Ở mỗi mốc trong giai đoạn boot sớm, kernel hẹn lại watchdog SP805 với một thời hạn khác nhau. Máy tự reset sau bao lâu thì biết nó đã chạy tới mốc nào. Sau bảy lần flash với 18 mốc:
| reset sau | mốc cuối | nghĩa là |
|---|---|---|
| ~19 s | stext | đã vào kernel |
| 134 s | __create_page_tables | xong phần chạy trước MMU |
| 194 s | __mmap_switched | MMU đã bật |
| 216 s | kernel_init_freeable | chạy hết initcall, sắp exec /init |
Mấy nguyên tắc để số đo đáng tin:
- Các thời hạn phải cách nhau hơn 10 s. Riêng việc nạp kernel đã mất 11–14 s, kernel càng to càng lâu.
- Mốc sâu nhất phải có thời hạn dài nhất. Sau mốc đó không còn ai cho watchdog "ăn", nên "boot ngon" và "chết ngay sau mốc" reset y hệt nhau.
- Mốc nào cũng phải có khả năng bắn. Mốc "PID 1 đã chạy" mà mở
/dev/memthì initramfs phải có node/dev/mem. - Trong
init.sh, mount/devđầu tiên và đừng thêm2>/dev/null. Lúc đó chưa có/dev/null, mà theo POSIX, chuyển hướng lỗi thì lệnh bị bỏ qua còn script vẫn chạy tiếp. Chỉ một dòng đó mà cả một giai đoạn boot im lặng không chạy. - Thời hạn nằm trong 1–178 s. 300 s × 24 MHz là tràn thanh ghi 32-bit.
5. CPU, reboot và nguồn
- Các nhân phụ được đánh thức qua TEE (SC_GEN1). Đường SRAM của hãng không ghi được từ phía non-secure.
- Reboot trên mainline bị treo vì chip không có trình xử lý restart. Cách làm: trong một hook tắt máy của systemd, cài SP805 với LOAD
0x100(bản SP805 của HiSilicon đếm từ 0 thì không bao giờ reset). Máy lên lại sau khoảng 65 s. - DVFS: CPU 396–1596 MHz ở 840–1150 mV; GPU 200–400 MHz.
6. Màn hình và GPU
- Driver DRM cho VDP tiếp quản chế độ 1080p60 mà bootloader đã dựng sẵn, có một lớp đồ hoạ G0 và một lớp video V0 (NV12). Chuyển qua lại 1080p 60/59.94/50 và 720p thì driver đã làm được, nhưng mình chưa kiểm trên TV.
- Panfrost chạy GPU Mali-T720: kmscube 59.9 fps, glmark2 được 90 điểm, không lỗi GPU nào.
7. Giải mã video phần cứng
Port VDH + VPSS từ HiSilicon-Development/linux-6.12.y sang 6.18 bản 32-bit, dùng FFmpeg có bộ patch v4l2-request của Kwiboo. Lần giải mã đầu "thành công" nhưng khung nào cũng xanh lè. Có hai lỗi chồng lên nhau:
- VDH báo lỗi đúng ở những ảnh có byte chống giả mã khởi đầu (emulation-prevention). Sửa: cho driver tự gỡ các byte đó.
- VPSS báo lỗi
state=0x8d. Sửa: ghi thanh ghi ở chế độ non-secure, và cấp bộ đệm ghi ngược thật thay vì địa chỉ vật lý 0.


Hai thiết lập quyết định tốc độ:
- Cho bộ đệm capture được cache. 1080p thực ra được mã hoá cao 1088 dòng, nên khung nào cũng phải cắt rồi chép lại. Đọc từ bộ nhớ không cache thì tốn 28.7 s CPU cho 300 khung. Bật cache lên: 94 fps, 3.6 s, md5 vẫn y nguyên.
- Hiển thị không chép (zero-copy). Qua framebuffer phải chép bằng CPU chỉ được 11.7 fps, tốn 34 s CPU. Đưa thẳng dmabuf đã giải mã vào lớp video của VDP thì được 48.5 fps, chỉ tốn 3.8 s.
8. Âm thanh
Một driver ALSA nhỏ: một ring buffer cho cả ba cổng cùng đọc, con trỏ đọc thì hỏi định kỳ bằng hrtimer, nên không cần ngắt và không cần node device tree. Âm thanh HDMI ở 48 kHz cần N=6144 (CTS đo được 148,351).
9. Userland và các phiên
- Debian trixie armhf, dựng bằng debootstrap. Hệ thống file gốc là một file image trên USB, initramfs mount nó qua loop.
- Chuỗi kexec: USB luôn giữ một kernel cố định, đã biết là chạy tốt. Kernel đó
kexecsang kernel mới nhất, có watchdog canh và bộ đếm số lần lỗi, nên kernel hỏng chỉ tốn một lần reset. - Menu chọn phiên chạy trên VT riêng, điều khiển bằng remote hoặc phím cảm ứng mặt trước. Bo phím cảm ứng gửi mã NEC thẳng vào mắt hồng ngoại, nên một keymap dùng cho cả hai.

Kết quả
| bộ phận | tình trạng | bằng chứng |
|---|---|---|
| 4 nhân CPU, DVFS | chạy | 396–1596 MHz, 840–1150 mV |
| Reboot | chạy | reset qua SP805, lên lại sau 65 s |
| Mạng dây, WiFi | chạy | AP6255, sau khi sửa GPIO và mức chân 1.8 V |
| USB 3 (cổng bên) | chạy | đo được 91.7 MB/s |
| Remote + phím cảm ứng | chạy | chung một keymap NEC |
| Đồng hồ VFD (TM1629A) | chạy | font 16 đoạn canh theo ảnh chụp |
| Màn hình, GPU | chạy | VDP DRM, Panfrost, kmscube 59.9 fps |
| Giải mã video phần cứng | chạy | xem bảng dưới |
| Âm thanh: RCA, quang, HDMI, DAC USB | chạy | nghe được tiếng thử trên từng cổng; DAC 16/48 bit-perfect, không bị hụt bộ đệm |
| HDMI-CEC | chỉ gửi | chưa thử nhận: không có TV hỗ trợ CEC |
| SATA | chạy tốt | hệ thống file gốc nằm trên ổ 3.5" (kernel k26) |
Giải mã video, so md5 của toàn bộ dữ liệu giải ra với FFmpeg giải bằng phần mềm:
| clip | số khung | so với phần mềm | fps |
|---|---|---|---|
| H.264 1080p60 | 2400/2400 | md5 trùng khớp | 75 |
| HEVC 1080p 8-bit | 300/300 | md5 trùng khớp | 51 |
| HEVC Main10 1080p | 300/300 | md5 trùng khớp (P010) | 31 |
| HEVC 2160p | 150/150 | md5 trùng khớp | 15 |
| VP9 1080p | 300/300 | md5 trùng khớp | 52 |
| MPEG-2 1080p / 576i | 300 / 250 | PSNR thấp nhất 68.4 / 66.1 dB | 41 / 68 |
Những gì đang chạy trên máy:






Để Android 13 chạy được trong Waydroid cần ba thứ:
- Bật
EXT4_FS_POSIX_ACLtrong kernel. Thiếu nó, vold không đặt được ACL mặc định và system_server cứ lặp lại "rebooting into recovery". - GPU chỉ hỗ trợ GLES 2.0. Phải đặt biến ép phiên bản của Mesa trong biến môi trường (qua một file init
.rctrong vendor overlay; đặt bằng property thì không ăn), và tắt việc dựng sẵn shader lúc boot. - Mạng của Waydroid mặc định dùng iptables kiểu cũ. Chuyển sang nftables thì chạy.
Hạn chế
- SATA: lỗi ở kernel, chẳng phải phần cứng. Bản đầu mình đổ cho cáp. Oan cho cáp. Mua hai cáp mới (83.200 ₫ — 2 × 52.000 ₫, trừ voucher Shopee 20.800 ₫) mà chẳng đổi gì: đọc thô 2 GB vẫn 6 lỗi CRC, 6 lần reset cứng, tụt về UDMA/100 ở 1.5 Gbps, y như hồi chưa đổi cáp. Mà 1.5 Gbps cũng chẳng phải lỗi: chính con Seagate này chỉ khai 1.5 Gb/s (
hdparm -I), còn mấy lần boot SATA êm trong log cũ là một ổ khác, ổ WD chạy 3.0 Gbps. Thủ phạm nằm trong driver combo-PHY của mainline: nó ghi đúng một giá trị tinh chỉnh,nano[0x1] = 0x8, cho mọi chế độ — giá trị bê từ cấu hình PCIe của board khác sang. Driver SATA của hãng ghi0x4. Tìm ra mà chẳng cần đọc ổ lấy một byte: đường SATA lúc rảnh vẫn chạy ký tự đệm, nên thanh ghi lỗi của controller (PxSERR) vẫn đếm lỗi giải mã 8b10b dù chẳng sector nào bị đọc — giá trị mainline: 4–33 giây-có-lỗi mỗi phút; giá trị của hãng: 0, qua năm lượt đo một phút. Quét hết 16 giá trị: 2, 4, 6 sạch; cái nào bật bit 3 là lỗi; số lẻ thì phập phù hoặc chẳng bắt tay nổi. Đặt giá trị của hãng rồi chạy driver thật: đọc 2 GB hai lượt, ghi lại tại chỗ 1 GB (ghi đúng bytes cũ, so checksum) — CRC +0, 0 ngoại lệ, 0 reset, UDMA/133, 75 MB/s. - Đường tới ổ gốc có một lần đi sai. Trước khi sửa trong kernel, mình xoá ổ, cho nó làm gốc, mà giá trị kia lại ghi từ userspace — sau khi driver bắt tay xong, và lúc ghi thì PHY nháy một nhịp. Đang có I/O của hệ thống gốc chạy, một lần boot rơi vào vòng reset đường truyền, cuối cùng ổ bị tắt và journal ext4 bỏ dở; kiểm lại thì hệ thống file vẫn sạch, và hôm đó máy về lại gốc trên USB. Kernel k26 đặt giá trị trước lần bắt tay đầu tiên (dmesg ghi
SATA mode: nano[0x1] = 0x4), và giờ máy boot thẳng từ ổ cứng: ba lần reboot liền, 0 ngoại lệ, 0 reset cứng, bộ đếm CRC của ổ không nhích, từ lúc cắm điện tới khi ssh được khoảng hai phút. Thư viện nhạc và dữ liệu Android giờ nằm trên ổ 229 GB, thay vì mấy file ảnh đĩa 4 GB trên USB. - Ổ nóng. Có miếng đệm tản nhiệt ở nắp, ổ nằm rảnh vẫn leo từ 35 °C lên 47 °C trong nửa tiếng, và còn nhích lên chậm chậm. Ngưỡng SMART là 55 °C.
- Android không vào được mạng. Kernel thiếu
IP_ADVANCED_ROUTER/IP_MULTIPLE_TABLES, mà netd cần định tuyến theo chính sách (policy routing). - Android chạy từ USB 2 rất chậm: lần đầu mất khoảng 50 phút, các lần sau 7 phút, trong khi từ SATA chỉ 100 s.
- Không xem được Netflix chất lượng cao. Firmware gốc chỉ có Widevine L3. Đó là bản
eng, không phải thiết bị được chứng nhận. - Chỉ 32-bit, như đã nói ở trên.
- Android 7 gốc qua kexec boot được nhưng TV chỉ hiện sọc nhiễu. Đây là tuỳ chọn, không bật sẵn.
- Chưa tìm hiểu: khung hình giải mã bằng phần mềm đưa qua bộ vẽ GL của mpv làm Panfrost báo lỗi
INSTR_INVALID_PC(356 lần mỗi clip 720p). Khung giải mã bằng phần cứng thì không lỗi lần nào.
Việc còn lại
- Đo nhiệt độ ổ lúc chạy tải (Kodi, Android), rồi tính xem hộp kín còn cần gì ngoài miếng đệm tản nhiệt ở nắp.
- Build kernel có policy routing để Android có mạng.
- Thử remote trong từng phiên, và thử cả chuỗi boot từ lúc cắm điện.
- Nhận lệnh HDMI-CEC, xuất 4K/HDR, passthrough AC3: cần một TV hỗ trợ mới thử được.
- Hình ảnh của Android 7 gốc sau khi kexec.
- Dọn lại bộ patch và gửi phần dùng chung lên upstream.
Bài học dùng được cho board khác
- Ping có trả lời chỉ chứng tỏ có cái gì đó trả lời. Lúc đầu mình tưởng kernel đã lên mạng, hoá ra là một camera IP đang dùng đúng địa chỉ mình chọn, và năm lần build liền dựa trên nhận định sai đó. Kiểm MAC bằng
arp. - Lệnh trả về 0 chưa chắc đã làm xong việc. Hãy xem kết quả thật: kích thước, mã băm, dòng log xác nhận.
- Công cụ dò chỉ biết một kiểu mã hoá lệnh sẽ báo thiếu code dù code có đó. Phải dò cả immediate xoay vòng,
movw/movtvà literal pool, ở cả ARM lẫn Thumb-2. - Khi reboot mà máy "không lên lại", trước khi đổ lỗi cho image, hãy chắc là có thứ gì đó thực sự reset board.
- Cáp mới là một phép thử, chẳng phải phép chữa. Đo cùng một bộ số trước và sau khi đổi; ở đây số chẳng nhích, và chính chỗ đó đẩy mối nghi ra khỏi phần cứng.
- Đo đường truyền mà chẳng cần vần ổ cứng: đường rảnh vẫn có tín hiệu chạy, nên cứ đếm lỗi trong thanh ghi lỗi của chính controller.
- Đừng chỉnh lại đường truyền khi hệ thống file đang mount. Giá trị an toàn với ổ đang rảnh lại làm treo đúng ổ đó lúc nó đang làm gốc.
- Thứ phải đặt xong trước khi đường truyền bắt tay thì thuộc về kernel. Userspace chỉ đổi được sau đó, lúc I/O đang chạy — đúng lúc không nên đổi nhất.
Tham khảo
- Device tree upstream: hi3798cv200.dtsi, hi3798cv200-poplar.dts
- Cây kernel 6.12 của cộng đồng, có driver VDEC, VPSS, VDP và HDMI: HiSilicon-Development/linux-6.12.y
- FFmpeg hỗ trợ V4L2 request API: Kwiboo/FFmpeg (nhánh
v4l2-request-n7.1.3) - Panfrost / Mesa
- Waydroid
- Chip điều khiển mặt trước: datasheet TM1629A
- Bài đánh giá phần cứng: CNX Software, Q10 Pro phần 1
- Liên quan, chạy trên kernel của hãng: leandrotsampa/e2d-hi3798cv200; bootloader tự build cho hộp CV200: hanwckf/bl-hi3798c
Nhật ký thay đổi
- 2026-10-14 — Bản đầu: ghi chép tại chỗ cùng ảnh bằng chứng.
- 2026-10-14 — Tìm ra gốc rễ chuyện SATA: tinh chỉnh PHY trong kernel mainline, chẳng phải cáp, cũng chẳng phải board. Trước đó mua hai cáp SATA mới (83.200 ₫), cả hai đều chẳng chữa được gì.
- 2026-10-14 — Thử cho ổ SATA làm hệ thống file gốc, rồi lùi lại ngay trong ngày.
- 2026-10-14 — Kernel k26: giá trị PHY SATA đặt trước lần bắt tay đầu tiên, và giờ máy chạy từ ổ 3.5". Ba lần reboot liền: 0 lỗi SATA, 0 lần reset đường truyền.
Chăm trồng bởi Ba rồng & AI nữa.