Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Nintendo Switch OLED — что мешает поднять частоту панели выше 64 Гц

Short version (EN): a complete, measurement-backed map of what blocks the Nintendo Switch OLED panel (Samsung AMS699VC01, ID 0x2050) above ~64 Hz. Everything here was verified by reading hardware back, not inferred. Includes the DSI timing algorithm used by the Switch display driver, the location of the mode structure inside nvservices, a hard-coded field that silently forces 60 Hz timings, and twelve refuted hypotheses. We are looking for the register map of this panel's DDIC — see the last section.


Что тут есть

Панель Switch OLED — Samsung AMS699VC01, идентификатор 0x2050 (сырой 50 9B 20). Геометрия: строка 72+72+720+136 = 1000, кадр 1+9+1280+10 = 1300, пиксельный клок 78 МГц = ровно 60.000 Гц.

Здесь — карта того, что проверено измерением на пути к частоте выше 64 Гц: что работает, что не работает, и где именно стоит стена.

Отрицательные результаты приведены наравне с положительными. Их тут больше, и они ценнее: каждый закрывает направление, в которое иначе полезет следующий.


Рабочее: 64 Гц

Достигается патчем пиксельного клока в образе nvservices (exefs-патч Atmosphere).

файловое смещение 0x000F29FC, 4 байта  ->  pclk в кГц
   78000 = 60 Гц (сток)
   83200 = 64 Гц

Смещение в файле включает 0x100 байт заголовка NSO; патчер вычитает их сам, отображённый адрес — 0xF28FC. Работает end-to-end, проверено.

Выше 64 Гц тот же патч даёт зелень и замирание.


Алгоритм таймингов D-PHY

Драйвер Switch считает тайминги DSI тем же алгоритмом, что ядро L4T (drivers/video/tegra/dc/dsi.h). Его константы найдены в образе nvservices по смещениям 0x3A090..0x3A17C.

период_бита(пс) = 1e12 / (пиксельный_клок * бит_на_пиксель / линий)
tbyte           = 8 * период_бита
поле            = округл(значение_пс / tbyte) - аппаратный_инкремент

Значения по умолчанию, пикосекунды:

поле значение инкремент
HS-EXIT 120000 1
HS-TRAIL 3 + conv(max(8*бит, 60000 + 4*бит)) 0
HS-ZERO 145000 + 5*бит 3
HS-PREPARE 65000 + 5*бит 1
CLK-TRAIL 80000 1
CLK-POST 70000 + 52*бит 1
CLK-ZERO 260000 1
TLPX 60000 1
CLK-PREPARE 65000 1
WAKEUP 1970000 (из дерева устройства) 1

Проверка. Расчёт воспроизводит регистры живого железа побайтово на двух независимых частотах:

60 Гц (468 Мбит/с на линию, бит 2137 пс) -> T0=06070603  T1=040A0E03
64 Гц (499 Мбит/с,          бит 2003 пс) -> T0=06070704  T1=040A0F03

Раскладка слов:

PHY_TIMING_0 = HS-EXIT<<24 | HS-TRAIL<<16 | HS-ZERO<<8 | HS-PREPARE
PHY_TIMING_1 = CLK-TRAIL<<24 | CLK-POST<<16 | CLK-ZERO<<8 | TLPX
PHY_TIMING_2 = CLK-PREPARE<<16 | CLK-PRE<<8 | WAKEUP
BTA_TIMING   = TAGET<<16 | TASURE<<8 | TAGO   (из наносекунд дерева: 450/180/360)

Значения для 90 и 120 Гц:

 90 Гц (702 Мбит/с, бит 1425 пс): T0=0A090A05 T1=060C1604 T2=0501AC BTA=260F1F
120 Гц (936 Мбит/с, бит 1068 пс): T0=0D0B0F07 T1=080E1D06 T2=0701E6 BTA=341429

Считается скриптом src/phy_timings.py.


Структура режима внутри nvservices

Отображённое смещение 0xF2A08 (файловое 0xF2B08), рядом с пиксельным клоком. Область записываемых данных. Регистры D-PHY собираются из её полей кодом по +0x39FD4:

поле +0  -> HS-EXIT        поле +16 -> CLK-TRAIL
поле +4  -> HS-TRAIL       поле +20 -> CLK-POST
поле +8  -> HS-ZERO        поле +24 -> CLK-ZERO
поле +12 -> HS-PREPARE     поле +32 -> CLK-PREPARE
                           поле +36 -> CLK-PRE

Сток: 6 7 6 3 | 4 10 14 | 1 3 1.

Рядом, по +0xF28DC, лежит вся геометрия режима — это таблица режимов, её нулевая запись:

720 1280 72 1 136 10 72 9 <pclk>

Следом идёт телевизионный режим 480p (720 480 ... 27027).


Зашитая константа, из-за которой 90 Гц не поднимаются штатно

HS-PREPARE не вычисляется от клока — оно прибито константой:

39f58: mov   w24, #0x3
39f70: csinc w8, w24, wzr, eq     ; ==2 -> 1, иначе 3
39f74: str   w8, [x9, #12]        ; запись HS-PREPARE в структуру

Формула с константами 65000/120000 лежит в соседней ветке (0x3A084), которая при обычной конфигурации не выполняется.

Следствие: патч данных не держится — структуру перезаписывает эта ветка при каждой настройке режима. Патч самой инструкции работает:

файловое 0x0003A058:  52800078 -> 528000B8   (mov w24,#3 -> mov w24,#5)

Проверено чтением памяти: поле становится 5, все десять полей структуры совпадают с расчётом.

Тот же w24 задаёт и TLPX через csel по +0x39FAC — одна константа на две величины, а нужны разные.


Отправка DCS-пакетов так, как это делает драйвер

Функция по +0x3A2E0 в образе nvservices:

ldr w10,[x8,#60]          ; DSI_HOST_CONTROL -> сохранить
ldr w11,[x8,#64]          ; DSI_CONTROL      -> сохранить
and w10,w10,#0xffffcfff   ; сбросить TX_TRIG
orr w10,w10,#0x2000       ; TX_TRIG = HOST
mov w9,#0xfffffff4        ; маска ~(бит0|бит1|бит3)
and w9,w11,w9             ; сбросить HOST_ENABLE, VIDEO_ENABLE, DCS_ENABLE
orr w9,w9,#0x1            ; поднять HOST_ENABLE
str w10,[x8,#60] ; str w9,[x8,#64]
   ожидание очистки DSI_TRIGGER, шаг 10 мкс
   длинный пакет:  (длина<<8) | (канал<<6) | тип -> DSI_WR_DATA, затем данные по 4 байта
   короткий:       тип | канал<<6 | данные0<<8 | данные1<<16
str #2,[x8,#76]           ; DSI_TRIGGER = HOST
   обе сохранённые величины возвращаются

Ключевое: драйвер гасит VIDEO_ENABLE на время пакета. Без этого host-команды под HOS не уходят — именно поэтому распространённое мнение «под HOS в панель не записать» неверно.


Панель: что удалось

Замок 0xE2 — вендорское расширение, пять 16-битных групп, 5A открыто, A5 закрыто. Снятие третьего уровня требует семибайтного пакета (заголовок 0x739), hekate шлёт пятибайтный и достаёт только до второго. Подробности и дамп сорока регистров: https://github.com/Dimasick-git/switch-oled-panel-lvl3

Канал записи подтверждён обратным чтением. Идиома B0 (смещение) + B1 (байт), в загрузчике:

B1[0x27] до записи: 05  ->  после: 04  ->  восстановлено: 05

Линия сброса панели: порт V, вывод 2 (в дереве устройства nvidia,panel-rst-gpio, вывод 0xAA = 170). Полный переподъём панели под HOS работает: сброс, повторная отправка заводской последовательности из дерева, возврат видеорежима — 9 команд из 9, картинка возвращается.

Таблица развёртки: регистр B1, смещения 0x27..0x3A — десять подряд 16-битных значений 0x0514 = 1300, то есть вертикальный итог. Правится, панель слушается: уменьшение вдвое заставляет её прогонять 650 строк вместо 1280, кадр обрывается. Это усечение развёртки, не ускорение.


Опровергнутое (проверено железом)

направление итог
подъём пиксельного клока 65 Гц срыв в полосы, 66 замирание
пересчёт таймингов D-PHY все параметры в допуске, срыв остаётся
преэмфазис 1 -> 3 из 3 эффект есть, стену не двигает
сила драйверов площадок 0x77777 -> 0xFFFFF без изменений
ужимание горизонтального гашения тот же срыв при стоковой скорости линии
холодный старт на 90 / 120 из загрузчика чёрный экран
последовательность Cooler3D F0 5A5A / F2 01 / 60 00 / F7 0F уходит доказуемо, эффекта нет
кодировки S6E3FC3 (F2 00/60 08) и S6E3HC4 (F2 01/60 00) не работают
MAUCCTR (F0 5A5A) дамп с ним и без него побайтово одинаков
таблица развёртки B1 усекает кадр, частоту не меняет
правка полей E0 (счётчики строк и мелкие поля) все записи уходят, картина не меняется
удержание регистров против драйвера не выигрывается: 7 захватов генератора и 6 подмен таймингов за 30 с

Отдельно: рабочая сборка L4T на 90 Гц, о которой ходят слухи, при разборе оказалась обычной. Её загрузчик (HekateUnlocked) содержит стоковые тайминги панели байт в байт, а в дереве устройства nvidia,dsi-refresh-rate = <0x3C> = 60. Драйвер панели в ядре L4T (panel-s-720p-7-0.c) не содержит команд частоты вообще — только яркость 0x51 и цветовой режим 0xA0.


Где стена

Единственная величина, которая росла при всех способах — строк в секунду:

60 Гц:  78 000 строк/с  ->  12.82 мкс на строку   чисто
64 Гц:  83 200 строк/с  ->  12.02 мкс             чисто
65 Гц:  84 500 строк/с  ->  11.83 мкс             полосы
66 Гц:  85 800 строк/с  ->  11.65 мкс             замирание

1280 активных строк по 12.82 мкс — это 16.4 мс даже при нулевом гашении, то есть 61 Гц физического потолка. Запас около восьми процентов выбирается на 64.

Для 120 Гц строка должна идти 6.4 мкс — вдвое быстрее. Это не подстройка, это другой режим работы строчного драйвера.


Что нужно

Карта регистров DDIC панели AMS699VC01 (идентификатор 0x2050, сырой 209B50).

Публичных данных нет: поиск по всему открытому коду на идиому замка 0xE2, 0x5A, 0x5A даёт ноль совпадений. Ни одно известное семейство Samsung её не использует — у S6E3FC3, S6E3HC4, S6E3HA8 ключ F0/FC. Наша панель по способу доступа к регистрам не совпадает ни с чем опубликованным.

Всё остальное готово: канал записи подтверждён, измеритель частоты по импульсам кадра честный, инструмент проб работает без пересборок, переподъём панели отлажен, алгоритм таймингов сверен с железом.

Если у вас есть эта карта регистров или вы знаете, какой DDIC стоит в этой панели — откройте issue. Одного документа хватит, чтобы превратить перебор в работу.


Метод

Всё здесь проверено чтением из железа или измерением, а не выведено рассуждением. Частота меряется счётом импульсов вертикальной синхронизации (опорный замер на стоке: 59.971 Гц при заявленных 60). Запросы режима у драйвера измерением не считаются — на них мы однажды потеряли неделю: строка сообщала 90 Гц, пока панель шла на 60.

Отдельно про ошибки: они тут тоже перечислены. Молчащий кламп, который месяцами срезал всё выше 64 Гц из-за неотображённой апертуры MIPI_CAL. Замер, который измерял запрос режима вместо частоты. Приписывание эффекта не тому регистру, когда в одном прогоне менялись два места. Каждая из них стоила недели.

About

Nintendo Switch OLED (Samsung AMS699VC01): measurement-backed map of what blocks the panel above ~64 Hz. DSI timing algorithm, nvservices mode structure, a hard-coded field forcing 60 Hz timings, and ten refuted hypotheses. Looking for the DDIC register map.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages