В телефоне стоит Android, а загрузчика, по сути, нет. Ну, есть — но это такая штука, с которой ничего не сделать. Transsion (это Infinix, это TECNO, это всё такое) кладёт в разделы lk_a и lk_b свой Little Kernel. Он умеет ровно две вещи: показать логотип и передать управление ядру. Ни fastboot, ни консоли, ни меню. Всё, что ты можешь — воткнуть UART в тестпойнты рядом со сканером отпечатков и читать, как летит лог.
Мне это надоело. Телефон я покупал не для того, чтобы любоваться анимацией загрузки. Через Android много не узнаешь: adb про загрузчик не расскажет, а переменные ядра про LK молчат как партизаны.
Значит, менять загрузчик. Стоковый LK → U-Boot.
Спойлер: получилось больше, чем я думал. Сейчас телефон грузит U-Boot, который рисует меню прямо на AMOLED, отдаёт консоль по USB-кабелю, умеет fastboot и работает как UMS-накопитель. Не работает SD-карта, об этом в отдельной статье и с подробностями, потому что там самая интересная часть.
Железо, чтобы понимать масштаб
- Модель: Infinix Note 12 Pro, X676B
- SoC: MediaTek Helio G99 (MT6789)
- Экран: AMOLED 1080×2400, панель ILI7835F
- Память: 8 ГБ RAM, UFS 2.2
- Android: 12, XOS, разметка A/B
У MediaTek нет документации на MT6789. Вообще. Ни схем, ни описания регистров, ни списка совместимых строк. Отдельная боль — потом.
С чего началось
Заготовка была простая: взять форк U-Boot под MediaTek, добавить устройство, собрать. Форк нашёлся сразу — ellyq/u-boot-mtk-g99, U-Boot 2025.10-rc5, сто тысяч коммитов истории. Осталось придумать две вещи: .dts и defconfig.
Первый device tree я написал за вечер. Он даже запустился: U-Boot грузился, UART показывал меню. Первая победа и первая иллюзия, что дальше будет легко.
Дальше началось интересное.
Три источника правды, и ни один не врёт
Их три, и они между собой не совпадают:
1. Реальный DT телефона. Android грузит ядро с device tree, и этот DT можно достать на живом устройстве:
adb shell su -c 'strings /sys/firmware/fdt'
Это правда. Но не стопроцентная: производитель вправе написать в DT что угодно, и иногда пишет.
2. Формовый mt6789.dtsi от ellyq. Написан для MT6789, но местами для MT8183, местами для MT8781.
3. Драйверы U-Boot в форке. А вот тут начинается настоящая жесть.
Смотрите, что получается:
| Что | В телефоне | В dtsi форка | На что биндится драйвер |
|---|---|---|---|
| SD-карта | mt6789-mmc |
mt6789-mmc |
mt8183-mmc |
| USB | mt6789-usb20 |
mt8518-musb |
mt8518-musb |
| UFS | mt8183-ufshci |
mt6789-ufshci |
оба |
| Кнопки | mt6779-keypad |
— | ничего |
Прочитать это можно так: телефон от Transsion, а форк от постороннего человека, который тоже кое-что дописывал по сходным SoC. Реальное железо отличается от dtsi, и это нормально.
Но третья колонка — это то, из-за чего пришлось потеть. drivers/mmc/mtk-sd.c вообще не содержит строки mt6789-mmc. Вообще. Есть mt7620, mt7621, mt7622, mt7623, mt7981, mt7986, mt7987, mt8512, mt8516 и mt8183. С реальной строкой контроллер SD не поднимется — драйвер просто не забиндится и всё.
Выбора нет. Оставляем mt8183-mmc и дописываем mt8183_compat под MT6789. И да, имя mt8183_compat в коде врёт — но менять его в форке нельзя, это сломает чужие платы.
С USB ровно та же история. Реальный DT говорит mt6789-usb20, а musb-new содержит один-единственный драйвер mt85xx.c, и он биндится на одну строку — mediatek,mt8518-musb. Драйвера под mt6789-usb20 в форке просто нет, это другое семейство. Ядро MUSB общее, обвязка PHY разная.
Весь этот расклад я расписал построчно в docs/compatibility.md — там каждое расхождение с объяснением, почему выбран именно такой вариант.
Что пришлось написать с нуля
Трёх драйверов в форке не было вообще. Каждый писал сам.
Дисплей. 453 строки, drivers/video/mediatek/mtk_disp_g99.c. Отдельная история, ей будет посвящена следующая статья.
Кнопки. drivers/button/button-mtk-kp.c, 204 строки. В U-Boot есть button-adc, button-gpio и button-qcom-pmic, и ни один не подходит к матричной клавиатуре MTK. Взял Linux-драйвер mt6779-keypad.c, повторил раскладку регистров. Заработало с v88, в меню кнопки появились с v89.
Часы. А вот это отдельная история, на целую статью.
# drivers/clk/mediatek/Makefile в форке ellyq
//obj-$(CONFIG_TARGET_MT6789) += clk-mt6789.o
Файл лежит. Три драйвера объявлены. В DTS есть узлы. Файл не собирается. Строка «закомментирована» двойным слэшем — в Makefile комментарий это #, а не // — и привязана к CONFIG_TARGET_MT6789, которого не существует. Плюс в самом файле имя функции mt6789-infracfg_ao_probe с дефисом, а дефис в идентификаторе C не компилируется. Плюс таблицы от другого чипа: 13 PLL, включая ARMPLL, CCIPLL и MPLL, которых на MT6789 в природе нет.
Ни дисплей, ни SD, ни USB без часов не включаются. Так что это было первое настоящее препятствие.
Что работает
| Подсистема | Состояние |
|---|---|
| Дисплей | текст U-Boot на AMOLED 1080×2400 |
| USB fastboot | телефон перечисляется на ПК |
| Консоль по USB | CDC ACM, UART-кабель больше не нужен |
| UMS | память телефона видна как диск |
| Кнопки | Volume Up/Down листают меню |
| Часы | три драйвера, всё тактируется |
Меню загрузки теперь появляется на экране телефона без единого провода. Это тот самый момент, когда телефон перестаёт быть чёрным ящиком и становится нормальной железкой.
Что не работает
SD-карта. Контроллер поднимается, mmc info молчит, CMD8 даёт INT=0x400, RSP=0. Сорок попыток с разными подходами. В пятой статье расскажу подробно, потому что там самое интересное: значения регистров уже сведены к живому Android один в один, а ответа всё равно нет.
Загрузка Android. Ядро стартует и паникует Attempted to kill init. Передаётся не тот DTB. До этой работы я не дошёл.
Где всё это лежит
github.com/mnnoee/u-boot-mtk-g99 — исходники, ветка mt6789-stable, 84 коммита поверх форка. Внутри docs/ на двух языках: как устроено железо, почему именно такие решения и что уже проверено.
Готовый образ для прошивки — релиз v219, 2.6 МБ.
Обязательное условие: перед прошивкой сохраните стоковый LK из lk_a и lk_b. Без него отката не будет — сам U-Boot живёт в этих разделах. Это не страшилка, это буквально так.
Остальное по полочкам:
образы и состояние проекта ·
заметки и живые дампы ·
скрипты и разборы
Дальше будет про дисплей: 453 строки, Synchronous Abort и смещение 0xd00, которое едва не стоило мне недели.