Skip to content

Latest commit

 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

postmarketOS на Samsung Galaxy Tab A 8.0 (2017) LTE — SM-T385 (gta2slte)

Полный порт mainline Linux (postmarketOS + phosh) на планшет Samsung SM-T385 (Qualcomm MSM8917 / Snapdragon 425). Здесь всё, что нужно, чтобы повторить: загрузчик, патчи ядра, пакет устройства, инструменты и документация всех раскопок.

Wi-Fi-версия SM-T380 электрически почти идентична (см. порт sapphicdisaster/t380-linux, от которого отпочковался этот) — отличия: модем, SoC ID и ревизия платы.

Что работает

Подсистема Статус Примечания
Загрузка (lk2nd → extlinux) сплэш postmarketOS, без отладочных полос
Экран + тач панель BOE TV080WXM, тач FTS8CD56 (свой инит + пинок после загрузки)
GPU (Adreno 306) freedreno, phosh ускорен
Wi-Fi / Bluetooth wcn36xx
LTE-модем: интернет + SMS bam-dmux + QMI; тумблер «мобильные данные» в phosh
Звук ⚠️ играет разговорный динамик у экрана — через него идёт всё, включая музыку
Громкоговоритель тракт до усилителя NXP TFA9890 работает; оборвана катушка самого динамика (доказано током)
Микрофон нужен был отдельный вывод питания смещения (в mainline его не было)
Зарядка + батарея свои драйверы sm5703 (зарядник + топливомер)
Обе камеры фронт S5K5E3 5Мп, тыл S5K4H5 8Мп — свои mainline-драйверы; видны приложениям через libcamera
Автофокус тыловой камеры dw9807-vcm, v4l2 focus_absolute
Вспышка / фонарик в шторке phosh, ток регулируется (в драйвере зарядника)
Датчик чехла закрыл — экран гаснет, открыл — проснулся
Поворот экрана lis2hh12 + iio-sensor-proxy
Карта microSD слот включён в device tree (был выключен с ранних версий)
Видеодекодер (venus)
Сон (suspend) s2idle; засыпает по чехлу, будят кнопка и открытие чехла
Голосовые вызовы звук идёт в обе стороны; кнопки микрофона и режима — своя служба вместо callaudiod

Как прошить

Всё ниже — на ваш страх и риск. KNOX-гарантия слетает необратимо.

  1. Разблокировать загрузчик (OEM unlock в настройках Android + Download mode).
  2. Прошить lk2nd в раздел boot через Odin/Heimdall: lk2nd/lk2nd-gta2slte.img (наша сборка — с фиксом Samsung XPU для smc, см. lk2nd/0001-samsung-xpu-smc-stub.patch). После этого планшет умеет fastboot (громкость вниз при старте).
  3. Собрать и установить postmarketOS через pmbootstrap:
    • взять свежие pmaports и наложить наши пакеты: kernel/device/testing/linux-postmarketos-qcom-msm89x7/ (патчи 0001-0011, конфиг, DTS), device/device/testing/device-samsung-gta2slte/;
    • pmbootstrap init (устройство samsung-gta2slte, UI phosh, systemd);
    • pmbootstrap install, затем pmbootstrap flasher flash_rootfs через fastboot lk2nd.
  4. Первая загрузка — и дальше всё обновляется обычным apk.

Структура репозитория

  • kernel/ — патчи ядра msm89x7 (0001-0011), конфиг, DTS устройства. Ключевое: инит тача FTS8CD56 (0001), зарядник+топливомер+вспышка sm5703 (0002), панель TV080WXM (0003), звук wcd-analog LINEOUT+bypass (0005), модем bam-dmux legacy-open (0006-0007), камеры s5k5e3/s5k4h5 (0009), vdd-supply для dw9807 (0011).
  • device/ — пакет устройства: deviceinfo (cmdline с clk_ignore_unused — без него нет сплэша), UCM-профили звука, сервисы-сторожа (звук, тач, экран-по-чехлу, DPM модема).
  • lk2nd/ — device tree для lk2nd, патч обхода Samsung XPU (без него smc из области загрузчика запрещён и lk2nd умирает), готовый образ.
  • tools/ — отладочные инструменты: битбанг-I2C через /dev/mem, GPIO-поке TLMM, съёмка камерой, свип автофокуса, декодер RAW10.
  • camera-ref/ — извлечённые из стоковых прошивок регистровые таблицы сенсоров (проприетарные библиотеки НЕ публикуются — см. docs/RAZBOR.md, откуда их взять).
  • docs/RAZBOR.mdглавный документ: полная история порта со всеми граблями, отладочными методиками и объяснениями каждого решения.

Самые ценные грабли (кратко)

  1. DTB собирался не тем ядром — номера клоков в 6.17 и 7.1.3 разные; месяцы «отдельных» багов (eMMC, BAM, I2C, USB) были одной ошибкой.
  2. Звук: аппаратный буст динамика сгорел (массовая болезнь модели) — лечится режимом BYPASS_MODE кодека, но ставить его можно только один раз при probe.
  3. Тыловая камера давала идеально чёрный кадр: MTK-таблицы «того же» сенсора не подходят — настоящая init-таблица добыта из бинарной vendor-библиотеки стоковой прошивки T385.
  4. CCI (камерный I2C) без power-domain VFE0_GDSC глух; подтяжки CCI1 питаются от камерного VIO.
  5. Сплэш при загрузке: ядро гасит «ничейные» клоки дисплея — clk_ignore_unused pd_ignore_unused обязательны.
  6. smc на Samsung SBOOT: XPU запрещает smc из памяти загрузчика — стаб копируется в HLOS-память (патч lk2nd).

Благодарности

Порт сделан в паре человек + Claude (Anthropic) — вся отладка велась по SSH на живом устройстве.

Известные шероховатости

  • Надпись «Unknown (FIXME!)» в меню загрузчика: SBOOT выбирает стоковый DTB (он приклеен к образу как совместимый), а в нём нет узла /lk2nd, по которому lk2nd опознаёт устройство. Косметика.
  • Звук поднимается ~1.5–2 мин после загрузки (ждёт звуковой сопроцессор). До этого регулировка громкости не отзывается — норма.

О сборке lk2nd

lk2nd-gta2slte.img — рабочий образ, проверенный на живом планшете. Он получен не прямой сборкой из исходников: пересборка этого дерева текущим окружением даёт бинарник, который не стартует (HALT: spinning forever), причина пока не найдена. Поэтому в образе сохранён проверенный код, а отладочные «пиксельные маркеры» (они рисовали цветные полосы при старте) обезврежены точечной правкой готового бинарника — скриптом patch-stripes.py:

python3 lk2nd/patch-stripes.py lk2nd-gta2slte-debug-stripes.img lk2nd-gta2slte.img

Скрипт находит маркерные циклы и заменяет в них инструкцию записи str rZ, [rX], #4 на add rX, rX, #4: указатель по-прежнему двигается, цикл завершается, но в кадровый буфер ничего не пишется. Длина кода не меняется, поэтому раскладка и тайминги остаются как в проверенном образе.

Два тупика, на которые ушло время (чтобы не повторять):

  • просто «занопить» запись нельзя — пост-инкремент указателя живёт внутри str, без него цикл становится бесконечным;
  • перенаправить запись за пределы кадрового буфера тоже нельзя — область за ним закрыта аппаратной защитой (XPU), и планшет виснет на логотипе Samsung без единого сообщения.

Исходный отладочный образ оставлен как lk2nd-gta2slte-debug-stripes.img: цветные полосы в нём показывают, до какого этапа дошёл загрузчик — это до сих пор лучший инструмент диагностики, если lk2nd перестанет стартовать.

Что добавилось в этой версии (ядро r57, device r25)

  • Сон. Работает s2idle: закрыл чехол — планшет заснул, открыл или нажал питание — проснулся. Мешал наш же драйвер автофокуса: его обработчик засыпания шёл к актуатору по I2C, когда шина CCI уже обесточена, отваливался по таймауту и ядро отменяло весь suspend (патч 0011). Тачскрин после пробуждения глохнет — лечится перепривязкой драйвера, служба t385-touch-resume.
  • Карта microSD. Слот стоял выключенным в device tree с раннего этапа порта (тогда ядро умирало сразу после инициализации карты — на самом деле из-за неверных номеров тактовых сигналов). Включён: карта определяется и монтируется. Учтите: нумерация mmcblk при этом сдвигается, eMMC становится mmcblk1.
  • Загрузка ускорена: 42 → 34 секунды. Наша служба реинита тача была Type=oneshot с паузой и держала multi-user.target лишних 12 секунд. Сообщения ядра с экрана убраны через loglevel=0 и vt.global_cursor_default=0.
  • Звонки: половина пути. Разговорный тракт живёт внутри звукового сопроцессора: модем и кодек соединяются там напрямую, а поднимает тракт сам сопроцессор в момент, когда кто-то открывает голосовой поток VoiceMMode1 (в драйвере q6voice это startup у DAI). Никто этого не делал: ModemManager отвечает за сигнализацию, callaudiod — только за переключение профилей. Служба t385-callaudio следит за вызовами и держит поток открытым; в UCM добавлены голосовые точки маршрутизации. Приём звука заработал, микрофон — пока нет.
  • Вспышка перестала мигать сама. feedbackd брал единственный светодиод системы (а это вспышка камеры) под индикацию пропущенных уведомлений. Своя схема откликов без светодиода: device/feedbackd-gta2slte.json.

Открытое: микрофон в разговоре

Собеседника слышно, а нас — нет. Рабочая гипотеза: PulseAudio у нас настроен никогда не отпускать звуковую карту (иначе глохнет тракт динамика), поэтому порт TERT_MI2S_TX постоянно занят на 44,1 кГц, а голосовой сессии он нужен в своём режиме. Попытка отпускать источник на время звонка (pactl suspend-source) убила и приём — откачено. Следующие шаги: пробовать другие TX-порты в VoiceMMode1 Capture Mixer и ловить момент освобождения порта. Не работают также громкая связь и удержание вызова в интерфейсе.

Обновление (ядро r58, device r28)

  • Микрофон заработал. Он не работал вообще — ни в записи, ни в звонках. Кодек при этом честно включал вход, АЦП и своё внутреннее смещение, а сигнала не было. Причина: аналоговым микрофонам нужно отдельное питание смещения, которое в стоке подаётся с ножек GPIO68 (основной) и GPIO99 (второй), а в mainline-дереве их не было вовсе. Добавлены как regulator-fixed. Замер до и после: уровень сигнала вырос с ~7 (шум) до ~150.

  • Кнопки в интерфейсе звонка ожили. Громкая связь и отключение микрофона не нажимались, потому что в звуковом профиле не было режима «Voice Call» — служба callaudiod работает только с ним. Профиль добавлен (device/ucm-VoiceCall.conf).

    Важная тонкость, стоившая отдельного круга отладки: в этом профиле потоки должны указывать на обычные PCM (hw:X,0 и hw:X,1), а не на голосовой hw:X,6. Голосовой поток данных не принимает — он лишь переключатель для звукового сопроцессора; если указать его, система звука считает выход неисправным («card has no usable sink») и кнопки остаются серыми.

Как проверять без второго телефона

  • Микрофон: tools/ — проиграть шум в динамик и замерить уровень записи; рабочий микрофон даёт рост в 4–5 раз.
  • Управление вызовом: busctl --user call org.mobian_project.CallAudio /org/mobian_project/CallAudio org.mobian_project.CallAudio SelectMode u 1 (а также EnableSpeaker b true, MuteMic b true) — все три должны вернуть true.

Про сборку в этом окружении

Если pmbootstrap падает с urlopen error, а apk add на планшете подвисает — это не поломка порта, а недоступный HTTP (HTTPS при этом работает). Собирать с --offline, ставить с --no-network.

Восстановление, если планшет не грузится

Раздел boot всегда можно вернуть из TWRP:

adb push boot_backup.img /tmp/
adb shell dd if=/tmp/boot_backup.img of=/dev/block/bootdevice/by-name/boot bs=1048576
adb reboot

Снимайте бэкап до каждой прошивки загрузчика:

adb shell dd if=/dev/block/bootdevice/by-name/boot of=/tmp/boot_backup.img bs=1M count=8
adb pull /tmp/boot_backup.img

Итоги 28.08.2026

Звонки заработали в обе стороны

Собеседник долго не слышал ничего, и причина оказалась не в железе. В системе есть штатная служба разговорного тракта q6voiced, и общий пакет soc-qcom-msm89x7-modem задаёт ей голосовой поток номером 4:

/usr/share/q6voiced/q6voiced.conf:  q6voice_device=4

А на этой карте VoiceMMode1 — устройство 6, четвёртого нет вовсе. Тракт передачи не открывался никогда, и журнал говорил об этом прямо:

q6voiced: Failed to open tx: No such file or directory

Лечится пере­определением службы (device/q6voiced-t385.conf). Туда же вынесено включение голосовых микшеров: пока они сброшены, голосовой поток не открывается вообще — arecord -D hw:0,6 отвечает «недопустимый аргумент».

Кнопки в интерфейсе звонка

Стандартный callaudiod на этом железе неработоспособен: ему нужен отдельный режим звуковой карты для разговора, а такой режим здесь невозможен — система звука либо молча отбрасывает его, либо делает из него негодный выход («card has no usable sink»). Написана замена device/t385-callaudiod.py, занимающая то же имя на шине.

Две тонкости, на которых легко потерять день:

  • у dbus-python нужно держать ссылку на занятое имя, иначе сборщик мусора его отпускает и на каждый вызов запускается новая копия службы — состояние кнопок теряется;
  • стандартное описание объекта не перечисляет свойства, его пришлось дописать вручную, иначе состояние не читается извне.

Чинить нечего у кнопок «удержание» и «добавить звонок»: в самой оболочке (libcall-ui, cui-call-display.ui) они объявлены выключенными — <property name="sensitive">False</property>.

Громкоговоритель: прежний вывод был неверен

Раньше здесь было написано, что у динамика сгорел повышающий преобразователь, а звук идёт через LINEOUT. Это опровергнуто опытом. Ровный тон с поочерёдным отключением излучателей показал: при выключенном разговорном динамике тишина при любом состоянии LINEOUT, а при выключенном LINEOUT звук есть. То есть LINEOUT молчит тоже, и единственный живой излучатель — разговорный динамик у экрана.

Разгадка нашлась в стоковом дереве Samsung: динамик подключён не к кодеку, а к отдельному усилителю. Там есть шина, подписанная «HW I2C for AMP» (BLSP1 QUP5, 0x7af6000, ножки GPIO22/23), включены линии MI2S (GPIO12, 13, 94, 95), а в qcom,audio-routing динамика нет вообще — только микрофоны.

Живое сканирование этой шины дало NXP TFA9890 по адресу 0x34 (регистр ревизии 0x03 = 0x0080), который поддерживает штатный mainline-драйвер tfa989x — без фирменной прошивки. Драйвер к нему привязывается и при проигрывании выводит его из спящего режима (регистр управления 0x82010x8208).

Заодно убран фиктивный регулятор tlmm94_vreg на GPIO94 — наследие порта T380, без единого потребителя. GPIO94 входит в группу линий MI2S к этому усилителю, и держать её как обычный выход было ошибкой.

Чем закончилось: динамик заработал. Причин оказалось две, и обе в ядре.

Первая — описка в mainline. Функция выбора тактового сигнала выдаёт для четверичного порта идентификатор третичного:

case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
        return Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT;   /* должен быть QUAD */

Константа Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT в ядре есть и не используется нигде. Сопроцессор на такую просьбу отвечает отказом (cmd 0x100f3 -> error 0x2), и порт остаётся без такта. Стоковый драйвер Qualcomm возвращает здесь правильный идентификатор.

Вторая — недостающий бит мультиплексора у msm8917. Сток пишет в регистр mic_iomux значение 0x02020002, а mainline только 0x00020002 — не хватает BIT(25). Без него сигнал до ножек не доходит.

Обе правки в kernel/0012-quat-mi2s-clk-id.patch. После них линии MI2S ожили, а усилитель доложил о себе сам:

ножка 94: [0, 1] ДРЕБЕЗЖИТ
усилитель: состояние=0xd85f  ФАПЧ=1  выходной каскад работает=1

Регистр состояния из мёртвого 0x0bdd стал 0xd85f, и микросхема начала измерять напряжение батареи и собственную температуру (до этого там намертво стояли значения по умолчанию). Динамик подключён к звуковому профилю: разговорный оставлен включённым вторым излучателем.

Чем закончилось на самом деле. Тракт до усилителя удалось починить полностью, а динамик всё равно молчит.

Что проверено объективно, без ушей:

  • линии MI2S ожили — чтение уровней TLMM показывает дребезг;
  • ножка данных найдена: на цифровой тишине её уровень 0 %, на тоне 25 % — значит звук до усилителя доходит;
  • усилитель захватывает ФАПЧ и включает выходной каскад (регистр состояния 0x0bdd -> 0xd85f), начинает измерять напряжение батареи и собственную температуру;
  • пробовали и на максимальной громкости, и с включённым повышающим преобразователем усилителя.

Звука нет ни при одном сочетании. Похоже, оборван сам динамик — это согласуется с тем, что он замолчал ещё в августе. В звуковой профиль он поэтому не подключён; строки для попытки оставлены в комментарии device/ucm-HiFi.conf.

Камеры не видели приложения: не хватало одного запроса

Приложение «Камера» писало «камера не найдена», хотя снимки напрямую получались. Причина — в наших драйверах датчиков не был реализован .enum_frame_size:

VIDIOC_SUBDEV_ENUM_MBUS_CODE  -> 0x300a: SGRBG10_1X10   есть
VIDIOC_SUBDEV_ENUM_FRAME_SIZE -> пусто                  нет

libcamera собирает список форматов как «код плюс доступные размеры». Размеров нет — значит нет и форматов: No image format found, и дальше камера не появляется нигде, потому что через libcamera их получает и PipeWire, и все приложения.

Режим у обоих датчиков один — полный кадр (3264x2448 и 2576x1932), так что обработчик тривиален; он в kernel/0013-sensors-enum-frame-size.patch. После него обе камеры видны и отдают кадры на 30 к/с.

VLC: всплывающие меню и касание ломал XWayland

Окно VLC жило в XWayland, а всплывающие меню Qt — это отдельные окна поверх; phoc при каждом ругался xwayland/xwm.c: xcb error: op 2:0, code 3 (BadWindow). Касание до окна тоже не доходило.

Виноват не Qt. Обычная программа на Qt5 (qmlscene) слушается QT_QPA_PLATFORM безупречно даже при выставленном DISPLAY: просят offscreen — получает offscreen, просят waylandwayland. А VLC при DISPLAY=:0 берёт libqxcb.so при любом значении переменной, даже когда просят minimal или offscreen, к X11 отношения не имеющие.

Причина в самом VLC. В libqt_plugin.so есть строки -platform и unknown Qt platform: %s: модуль не читает переменную окружения, а сам передаёт Qt аргумент командной строки -platform, а аргумент старше переменной. Выбирает VLC по наличию DISPLAY — модуль собран с X11 (libQt5X11Extras, libX11, libX11-xcb) и при доступном X-сервере предпочитает его.

Лечится тем, что DISPLAY убирается из окружения только для VLC — тогда выбрать X11 ему нечем:

Exec=env -u DISPLAY /usr/bin/vlc --started-from-file %U

Проверено: с DISPLAY=:0 грузится libqxcb.so, с env -u DISPLAYlibqwayland-generic.so. Файл device/vlc-override.desktop кладётся в /usr/local/share/applications/ — этот каталог система просматривает раньше /usr/share, поэтому запись в меню остаётся одна, а обновление пакета VLC правку не затирает.

Попутно: окно первого запуска про доступ в сеть на планшете неработоспособно (закрыть его нечем), отключается в ~/.config/vlc/vlcrc:

[core]
metadata-network-access=0

[qt]
qt-privacy-ask=0

Другого места для этой настройки нет: в libvlccore зашиты только пути ~/.config/vlc/vlcrc и ~/.vlc/vlcrc, общесистемного файла у сборки не предусмотрено.

Камера падала не сама — падала служба звука и видео

Жалобы выглядели как разные: «приложение тормозит», «камера не отвечает», «задняя камера не работает», «не удалось воспроизвести потоковые данные». Причина у всех одна: с дампом падал WirePlumber. Вместе с ним исчезали узлы камер в PipeWire, и приложение теряло изображение. Задняя камера при этом исправна — служба умирала на остановке предыдущей камеры, то есть ровно при переключении.

Проверять так:

systemctl --user show wireplumber -p NRestarts --value

Убивали её две ошибки libcamera, одна за другой.

Первая. FATAL pipeline_handler.cpp:398 assertion "data->queuedRequests_.empty()" failed in stop()

SoftwareIsp::stop() сначала глушит модуль автоматики, и лишь потом возвращает отменённые буферы. Завершение запроса упирается в проверку:

if (info->metadataRequired && !info->metadataProcessed)
	return;

Метаданных эти кадры уже не получат — автоматика мертва. Запрос навсегда остаётся в очереди. Штатная уборка clearIncompleteRequests() их не ловит: она чистит только очередь на обработку, а кадры, отданные обработчику, оттуда уже сняты. В журнале рядом видно WARN FCQueue Obtained an uninitialised FrameContext.

Лечится патчем 0005-complete-requests-on-stop.patch: требование метаданных снимается со всех кадров в работе до остановки обработчика.

Вторая открылась сразу за первой: FATAL egl.cpp:474 assertion "tid_ == Thread::currentId()" failed in makeCurrent() из DebayerEGL::debayerGPU. По умолчанию цвет собирает видеоядро, а контекст EGL создан в одном потоке и используется в другом.

Лечится настройкой в /etc/libcamera/configuration.yaml (файл входит в пакет устройства):

---
version: 1
configuration:
  software_isp:
    mode: cpu

После обеих правок: десять запусков и остановок вперемежку обеими камерами, ни одного падения.

Сколько кадров тянет обработка

Неожиданный итог: процессор быстрее видеоядра. Кадров в секунду, задняя камера:

размер кадра видеоядро процессор
3264x2448 (полный) 5,6 9,3
2048x1536 ~25 28,5
1632x1224 21,2 28,5

Полный кадр не тянется всё равно, и каждый такой кадр занимает 32 МБ — при гигабайте памяти поток из них её вычерпывал, отчего система вставала намертво и уходила в сброс по сторожевому таймеру. Поэтому размер обработанного потока ограничен до 2048x1536 патчем 0004-cap-softisp-size.patch: 24-28 кадров в секунду и 12,6 МБ на кадр. Необработанный поток не тронут.

Полезный признак при разборе таких зависаний: pstore пуст и записи об ошибке нет, журнал просто обрывается. Это отличает жёсткий зависон от паники ядра — искать ошибку ядра там незачем.

Паника ядра от собственного патча: указатель на режим

Сразу после того, как заработала автоэкспозиция, планшет начал падать в панику при запуске камеры. Причина оказалась в патче режимов, а не в libcamera: поле «текущий режим» задавалось только в set_fmt, а обработчик управляющих элементов обращается к нему раньше:

int max = s5k->mode->height + ctrl->val - ...;   /* mode == NULL */

Пока автоматика не управляла усилением, до этой строки почти не доходило — ошибка тихо ждала своего часа. Как только AGC заработала и начала трогать элементы при запуске потока, ядро упало по пустому указателю. Лечится заданием режима по умолчанию в probe, до создания элементов.

Урок общий: указатель, который заполняется «когда-нибудь позже» в колбэке, надо инициализировать при создании устройства.

Автоэкспозиция: libcamera не знала эти датчики

libcamera писала в журнал:

WARN CameraSensorProperties: No static properties available for 's5k4h5'
WARN IPASoft: Failed to create camera sensor helper for s5k4h5

Второе означало, что автоматика не умеет управлять усилением вообще и может менять только выдержку. В темноте это тупик: выдержку уже некуда растягивать, а усиление поднять нечем. Первое — что неизвестны размер пикселя и задержки датчика, из-за чего экспозиция «рыскает» при смене освещения: libcamera не знает, через сколько кадров подействует её команда.

Формула пересчёта усиления вшита в саму библиотеку, файлом её не добавить, поэтому libcamera пересобрана с патчем libcamera/0003-add-t385-sensors.patch. У обоих датчиков усиление линейное — регистр 0x0204, база 32 соответствует однократному, потолок 512 = 16x:

gain_ = AnalogueGainLinear{ 1, 0, 0, 32 };
blackLevel_ = 4096;   /* пьедестал 64 при 10 битах */

Плюс запись в базе свойств: размер пикселя 1.12 мкм и задержки датчика. После пересборки жалоб не осталось.

Чего это не даёт: цветовой калибровки. Для неё нужны замеры по эталонным мишеням, поэтому приложение по-прежнему берёт общий профиль uncalibrated.yaml — баланс белого и цветопередача остаются приблизительными.

Сборка libcamera требует двух оговорок: ускоритель кросс-компиляции на ней ломается (cannot execute cc1), нужен pmbootstrap --no-cross; и при шестнадцати потоках сборщику не хватает памяти на python-обвязке (Killed signal terminated program cc1plus) — помогает pmbootstrap config jobs 3.

Предпросмотр камеры: режим 816x460 вместо восьми мегапикселей

Приложение «Камера» находило камеры, но показ шёл на 5–6 кадрах в секунду и утягивал за собой весь планшет — вплоть до перезагрузки. При этом в журнале ядра не было ни одной ошибки камеры, зато оставался процесс вывода изображения: захлёбывалось видеоядро.

Причина простая: драйвер отдавал единственный режим — полный кадр 3264x2448. После обработки это 32 МБ на кадр, и всё это считает процессор, а потом заливает в видеоядро. На планшете с 1.3 ГБ памяти такого не выдерживает никто.

В стоковых библиотеках нашлись готовые таблицы уменьшенных режимов: у задней камеры 816x460 (прореживание 1 к 4), у фронтальной 640x480 (биннинг 4x4). Полезная подробность: тактовые настройки у всех режимов одинаковы, различается только число строк в кадре, так что частоты менять не пришлось.

Фронтальная камера до этого не запускалась вовсе — её единственный режим 2576x1932 не проходил согласование формата (not-negotiated).

было стало
размер кадра 32 МБ 1.2 МБ
скорость 5–6 к/с 28.5 к/с

Патч — kernel/0015-s5k4h5-preview-mode.patch (обе камеры); полный кадр остался для съёмки, уменьшенный выбирается по запрошенному размеру. После правки обе камеры проходят весь тракт до приложения: по десять кадров за 0.6 с каждая.

Как искать такие таблицы: записи в библиотеке идут восьмёрками байт {адрес (2), значение (2), задержка (4)}; разрешение режима читается из регистров 0x034c и 0x034e, тайминги — из 0x0342 и 0x0340.

Обе камеры делили приёмник — развели

Переключение между камерами подвешивало приложение:

Failed to setup link 'msm_csiphy1'[1] -> 'msm_csid0'[0]: Resource busy

Драйвер CAMSS связывает каждый приёмопередатчик со всеми приёмниками, и libcamera при обходе графа выдавала обеим камерам первый попавшийся — один и тот же csid0. Вторая тогда не запускалась, пока работает первая. Стоковая настройка Qualcomm разводит их один к одному (qcom,csid-sd-index: задняя 0, фронтальная 1).

Патч kernel/0016-camss-one-csid-per-csiphy.patch делает так же: csiphy0 -> csid0, csiphy1 -> csid1, а приёмники сверх числа передатчиков остаются доступны всем. После него обе камеры работают одновременно — вторая запускается поверх первой без ошибок.

Приговор динамику: измерение тока

Слуховые проверки давали тишину на всех пяти путях, но слух — довод слабый. Решающим стало измерение тока батареи: живая катушка потребляет, оборванная — нет.

Мерили парами «тишина / громкий тон», три круга подряд, чтобы вычесть дрейф; экран пригашен, поэтому фон низкий. Обязательно от батареи — с подключённой зарядкой датчик нагрузки не показывает вовсе (все состояния дают одинаковые −7.8 мА).

Излучатель Прирост тока на громком тоне
Разговорный динамик (заведомо живой) +38.7 мА
Громкоговоритель через усилитель, максимум громкости + буст +8.1 мА

Крошечный разговорный динамик потребляет впятеро больше, чем большой громкоговоритель на полной громкости. Восемь миллиампер — это собственное потребление усилителя вхолостую. Ток в катушку не идёт.

Вместе с тем, что усилитель при этом рапортует полную исправность (захват ФАПЧ, работающий выходной каскад, живые показания батареи и температуры), вывод однозначен: неисправен сам динамик, а не порт.

Что показала стоковая прошивка

Прошивку скачали и распотрошили, не устанавливая (samloader-rs, SM-T385/SER, версия T385DXS4CUD3).

Порт сделан правильно. В стоковых настройках звука путь speaker у кодека пуст:

<path name="speaker">
</path>

а звук к динамику направляется ровно так же, как у нас: QUAT_MI2S_RX Audio Mixer MultiMedia1 = 1. То есть и порт, и линия данных, и сам усилитель выбраны верно.

Единственное отличие — сток загружает в усилитель контейнер vendor/etc/Tfa9890.cnt (4400 байт: заплатка, настройки, модель динамика) силами libtfa98xx.so, а mainline-драйвер не грузит туда ничего и работает в упрощённом режиме. Но с тем же усилителем в mainline работают Shift6mq и OnePlus — без всякого контейнера, — так что тишину это не объясняет. Загрузка контейнера пригодилась бы разве что ради встроенного измерения сопротивления динамика; после замера тока в этом уже нет нужды.

Как я сломал весь звук и чем это поучительно

Добавляя ножки MI2S, я объявил у звуковой карты свой pinctrl-0 — и тем самым вытеснил уже объявленный в msm8937-qdsp6.dtsi:

&sound {
        pinctrl-0 = <&cdc_pdm_lines_default>;
        pinctrl-1 = <&cdc_pdm_lines_sleep>;
};

Кодек остался без ножек, и звук пропал весь — при внешне безупречной картине: все узлы включены, поток идёт, регистры верные. Нашлось это сравнением состояния всех 134 ножек процессора между рабочим и сломанным ядром: у линий кодека 69–74 настройка 0x000000c9 превратилась в 0x00000001. Правильно — перечислять оба набора:

pinctrl-0 = <&cdc_pdm_lines_default &quat_mi2s_default>;

Хуже того, эта поломка держалась несколько сборок подряд, и весь разбор с усилителем шёл на планшете, где звука не было вообще. Все выводы вида «динамик не звучит», сделанные в это время, оказались бессмысленными. Отсюда правило: после каждой правки звука — контрольное прослушивание, и только потом следующий шаг.

Осторожно с измерениями

Микрофон ноутбука как «уши» здесь не работает: контрольный опыт на заведомо рабочем излучателе тоже дал «тишину». Микрофон самого планшета через звуковой сервер отдаёт ровные нули. Проверять звук можно только ушами человека — все выводы «тишина», сделанные приборами, недостоверны.

Передача файлов на планшет: scp и ssh "cat > файл" при большом объёме молча ничего не пишут (код возврата 0, файла нет). Работает только скачивание самим планшетом — поднять HTTP-раздачу в WSL и забрать wget.

About

postmarketOS na Samsung Galaxy Tab A 8.0 (2017) LTE - SM-T385 (gta2slte): kernel patches, lk2nd, tools and full porting documentation

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages