[Перевод] USB-C хаб за 40 евро стал доком Switch 2: 540 байт в прошивке питания и 108 байт ради HDR

Я люблю брать Nintendo Switch 2 в поездки, и каждый раз упираюсь в одно и то же: официальный док громоздкий и выглядит хрупким, поэтому с собой я его не вожу. Обидно, потому что док работает через DisplayPort Alt Mode по USB-C, а у меня уже есть USB-C хаб, который это умеет и без проблем работает со всеми остальными моими устройствами. Но Nintendo, как это с ней часто бывает, пошла своим путём, и обычный хаб доком не станет.

Недавно друг подарил мне сниффер USB-PD. Я решил посмотреть, что именно делает консоль и почему она соглашается работать только с официальным доком.

Хаб

Хаб у меня — Cable Matters 7-in-1 на три монитора: DP, HDMI и VGA, питание до 60 Вт. Я разобрал его и посмотрел, что внутри:

  • VL103 — контроллер USB-PD;

  • VL817 — USB-хаб;

  • RTD2142 — MST-хаб DisplayPort (здесь он работает конвертером DP→HDMI);

  • флеш-память XT25F16B с прошивками.

От этого хаба Switch уже заряжается, значит, обычный USB-PD он понимает. Можно предположить, что фирменное «рукопожатие» дока Nintendo идёт поверх USB-PD, в сообщениях, которые определяет сам производитель (vendor-defined messages).

Со стоковой прошивкой Switch заходит на удивление далеко. Она договаривается о питании, входит в DisplayPort Alt Mode и даже настраивает pin assignment D, и хаб всё это подтверждает. А дальше ничего: ни режима телевизора, ни картинки. Одного DisplayPort Alt Mode мало, сначала должно произойти что-то ещё.

Инструменты

Сниффер USB-PD. Это WITRN K2: он включается в разрыв USB-C кабеля и показывает PD-трафик. К нему есть только приложение для Windows, поэтому я попросил Claude написать маленькую консольную утилиту для Linux. Она читает HID-отчёты в отдельном потоке, декодирует их через usbpdparser и пишет JSONL, который потом можно воспроизвести.

Прошивка контроллера PD. В VL103 стоит микроконтроллер 8051 с 32 КиБ прошивки. Плагин vli в fwupd уже умеет снимать и заливать её через хаб VL817, ему не хватало только записи quirk с USB ID этого хаба. В конце образа лежит CRC-16/USB, а свободного стёртого места под новый код много.

sudo fwupdtool --plugins vli firmware-dump OUT.bin sudo fwupdtool --plugins vli --allow-reinstall --prepare --cleanup  install-blob patched.bin 

Для реверса я взял процессорный модуль 8051 в Ghidra для дизассемблирования, ассемблер из SDCC для патчей и симулятор 8051 uCsim, чтобы гонять настоящую прошивку на записанных дампах трафика.

Опыт программирования под 8051 у меня есть, но Claude и GPT я использовал в этом проекте очень активно: они помогали с дизассемблированием, патчами и разбором того, что делает родная прошивка хаба. Без них довести дело до конца было бы куда тяжелее.

Слушаем официальный док

Подключаю сниффер, запускаю на ПК скрипт и смотрю на трафик USB-PD:

14:19:11.863 SOP Source_Capabilities Source/DFP id=0 [F 5.0V@3.0A, F 9.0V@3.0A, F 15.0V@2.8A]14:19:11.868 SOP Request Sink/UFP id=0 [[3] F 15.0V@2.8A]14:19:12.070 SOP Vendor_Defined Sink/DFP id=4 VDM PD SID(0xFF00) Discover Identity REQ14:19:12.073 SOP Vendor_Defined Source/UFP id=5 VDM PD SID(0xFF00) Discover Identity ACK VDOs: 0x5460057E 0x00000000 0x20620000 0x65000031 0x0000000014:19:12.080 SOP Vendor_Defined Source/UFP id=6 VDM PD SID(0xFF00) Discover SVIDs ACK SVIDs: DisplayPort(0xFF01), Nintendo(0x057E)14:19:12.162 SOP Vendor_Defined Sink/DFP id=0 VDM Nintendo(0x057E) Enter Mode REQ mode #114:19:12.183 SOP Vendor_Defined Sink/DFP id=1 VDM DisplayPort(0xFF01) Enter Mode REQ mode #114:19:12.210 SOP Vendor_Defined Sink/DFP id=3 VDM DisplayPort(0xFF01) 17 REQ VDOs: 0x0000080614:19:12.228 SOP Vendor_Defined Sink/DFP id=4 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x0000002014:19:12.240 SOP Vendor_Defined Source/UFP id=5 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000020 0x0000000014:19:12.249 SOP Vendor_Defined Sink/DFP id=5 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x0000000114:19:12.260 SOP Vendor_Defined Source/UFP id=6 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000001 0x0301050314:19:12.438 SOP Vendor_Defined Sink/DFP id=6 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x0000000214:19:12.450 SOP Vendor_Defined Source/UFP id=7 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000002 0x0003006E14:19:12.458 SOP Vendor_Defined Sink/DFP id=7 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x0000000614:19:12.471 SOP Vendor_Defined Source/UFP id=0 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000006 0x330107DA 0x06016D68 0x330107DA 0x06016D68

Сразу бросается в глаза несколько вещей:

  • Discover Identity. Док представляется как устройство Nintendo (VID 057E), продукт 2062, тип «периферия».

  • Discover SVIDs. Кроме DisplayPort (FF01) док объявляет собственный SVID Nintendo, 057E. Switch входит в режим Nintendo раньше, чем в режим DisplayPort.

  • Сообщения Nintendo. После настройки DP консоль шлёт серию неструктурированных vendor-сообщений. Каждый запрос — это 057E0001 плюс номер команды, а док отвечает 057E0041, той же командой и данными.

Команда

Ответ дока

Примечание

20

00000000

ещё и опрашивается периодически

01

03010503

29, 44, 41, 49, 23, 131, 51

эхо

02

0003006E

похоже на номер версии

06

330107DA 06016D68 ×2

запись о версии, тег hm

04

330107DA 06016D61 ×2

запись о версии, тег am

Что значит большая часть этого, я не знаю. Записи о версиях совпадают по формату с версиями прошивок Cypress/Infineon CCGx, а в другом проекте по патчингу доков видели, что ответ на 02 менялся после обновления официального дока.

Учим хаб рукопожатию

Начал я с того, что снял прошивку VL103 и попросил Claude её декомпилировать и разобрать. Когда он попытался запустить Ghidra, сработал классификатор безопасности и работу остановил. Поэтому декомпиляцией занимался GPT.

В прошивку VL103 я добавил обработчик: около 540 байт кода 8051 в стёртой области, встроенных в стоковый PD-стек. Он отвечает на сообщения Nintendo, а всё остальное оставляет родному коду. Дальше я менял по одной вещи за раз:

Версия

Что изменил

Результат

v1/v2

отвечаю на Discover/Enter Mode от Nintendo и на эхо-команды

на линии подтверждения, DP настроен, картинки нет

v3

предлагаю 15 В / 2,8 А, как док (стоковый хаб: 2,53 А)

картинки нет

v4

отдаю vendor ID Nintendo вместо VIA

картинки нет

v5

отдаю полную идентификацию официального дока

режим телевизора работает!

v6

отвечаю на 02 версией дока

теперь Switch застревает на 06

v7

отвечаю на 06 и 04 записями дока

последовательность совпадает целиком, док подключается быстрее

Самое интересное — разница между v4 и v5: одного vendor ID мало, Switch проверяет идентификацию шире. v7 убрала паузу примерно в 3 секунды: с v5 консоль запрашивала 02, получала «Not supported» и ждала, прежде чем продолжить.

Ответы с версиями скопированы с официального дока. Это не настоящие версии чего-либо в этом хабе, и за этими командами ничего не реализовано. На любую команду, которую я не распознаю, по-прежнему уходит стоковый ответ «Not supported».

HDR выглядит блёклым

Режим телевизора заработал, но с включённым HDR цвета были заметно бледнее. Официальный док на том же мониторе и в той же игре выдавал нормальную картинку. Что я исключил:

  • Дисплей. То же самое и на мониторе, и на телевизоре, и оба показывают значок HDR.

  • Диапазон RGB. С ограниченным становится хуже, с полным всё равно блёкло.

  • Хаб в целом. Мой ПК с Linux выводит HDR через этот же хаб правильно.

  • Контроллер PD. PD-трафик с HDR и без него одинаковый.

Картинка выглядела так, будто перепутано цветовое пространство. Моя гипотеза была такой: Switch отдаёт цвет в BT.2020, а дисплею сообщают, что это BT.709, и он сжимает цвета. Сторона DisplayPort контроллер PD вообще не задевает, она идёт прямо в RTD2142. Значит, следующий на очереди этот чип.

Внутри RTD2142

Сначала нужно было снять его прошивку. В flashrom есть программатор realtek_mst_i2c_spi, который общается с чипом по I²C поверх DP AUX, через тот же USB-C кабель. Два чтения дали одинаковые образы по 2 МиБ. Прошивка не подписана, так что изменённый образ можно просто залить (запасным планом была клипса SOIC-8).

flashrom -p realtek_mst_i2c_spi:bus=7,allow_brick=yes,reset_mcu=1 -r rtd2142.bin

Анализ. Внутри снова 8051, на этот раз с восемью банками кода по 64 КиБ, которые переключаются через трамплины. Я доработал свой симулятор, чтобы он отслеживал переключения банков.

Больше всего помогла база данных инструмента Realtek для родственного RTD2172, которую я нашёл в публичном репозитории на GitHub: там есть имена и описания аппаратных регистров, и они совпали с тем, что делает эта прошивка.

Выход HDMI описывает цвет картинки в AVI InfoFrame — небольшом пакете, который идёт вместе с видео. Поля колориметрии в нём говорили BT.709. Конвертер берёт BT.2020 из входящего потока DisplayPort, только если он объявлен одним конкретным стандартным способом, а цветовую метку на HDMI обновляет только при запуске выхода. Метаданные яркости HDR идут отдельным пакетом, поэтому телевизор всё равно переключался в режим HDR.

Я посмотрел, как с этим справляются другие сторонние доки. Они выпускали обновления прошивки, которые «исправляют серый или тусклый HDR». В одном из них есть отладочная строка «switch2 color space patch»: увидев Switch 2 и поток, где BT.2020 не помечен стандартным способом, прошивка берёт колориметрию из EDID дисплея. Так что не я один на это наткнулся.

Исправление HDR

Мой патч не пытается распознать Switch, а смотрит на сами метаданные HDR:

  • если метаданные HDR есть и передаточная функция у них PQ или HLG, каждый AVI InfoFrame помечается как BT.2020, а его контрольная сумма пересчитывается;

  • InfoFrame пересобирается при каждом включении и выключении HDR;

  • больше ничего не меняется: те же пиксели, те же пакеты для SDR, ничего в пути DP и при запуске.

Это 108 байт в одном банке: три небольших хука и немного кода в стёртом заполнении. Перед прошивкой я прогнал оригинальную прошивку с патчем в симуляторе: все форматы пикселей, переключения HDR туда и обратно и полную цепочку от входа до выхода.

Результат: HDR выглядит правильно. С пикселями всё было в порядке с самого начала, неправильной была только метка.

Выход DisplayPort у хаба идёт другим путём, который я не патчил, поэтому HDR через порт DP по-прежнему блёклый. Я решил, что мне это не настолько важно, чтобы чинить 🙂

А VRR?

Раз хаб теперь притворяется официальным доком, Switch предлагает и VRR. Если его включить, картинка через порт DP замирает, а на HDMI частота так и остаётся 60 Гц. Судя по прошивке, поддержки VRR в ней нет вообще: она никогда не сообщает источнику, что умеет переменные тайминги, и никогда не отправляет HDMI-пакет VRR.

Я хотел полноценный док, так что я всё же попробовал. У прошивки RTD2142 нашёлся отладочный интерфейс на I²C-адресе 0x35 через тот же канал AUX: одна команда читает любой регистр, другая записывает. Это позволило читать живое состояние чипа и трогать регистры, ничего не прошивая.

Чтобы получить источник, который действительно использует VRR, я сделал второй патч, с которым хаб объявляет поддержку Adaptive-Sync, и подсунул Linux подменённый EDID. amdgpu радостно включил VRR, и экран погас, как только частота кадров начала реально меняться. Главный цикл чипа переставал отвечать, пока тайминги снова не становились стабильными. Он не перезагружался, и отключение сторожевого таймера FIFO и прерываний не помогло. Лучшая моя догадка — цикл повторного захвата тактовой частоты, который так и не устаканивается.

Чтобы это заработало, пришлось бы переписать то, как чип захватывает входной сигнал, надеяться, что его генератор таймингов справится с переменными кадрами, и добавить HDMI-пакет VRR. На этом я остановился и вернулся к прошивке только с исправлением HDR. При работе через такой хаб я просто выключаю VRR в настройках Switch.

Итог

Теперь хаб работает дорожным доком для того, что мне важно: режим телевизора и HDR по HDMI, и Switch при этом заряжается. USB-порты и Ethernet я толком не проверял. VRR не работает, поэтому я держу его выключенным в настройках Switch. Всего хабу понадобилось около 540 байт в контроллере PD и 108 байт в RTD2142.

Хотя хаб теперь представляется официальным доком Nintendo, с моим ПК и телефоном он по-прежнему работает как обычно.

Отдельное спасибо VIA и Realtek за то, что ставят туда 8051: с ними взлом становится куда проще и доступнее 🙂

Обновление: код опубликован. Патчер лежит на GitHub: https://github.com/mkopec/switch2-hub-patcher. Пробуйте.

Источник: habr.com

0 0 голоса
Рейтинг новости
1
0
Подписаться
Уведомить о
0 комментариев