Pull to refresh

Запуск Линукс на TV-боксе на чипе RK3528

Level of difficultyMedium
Reading time8 min
Views11K

Мне удалось запустить Armbian сборку Ubuntu на TV-боксе с новым чипсетом RK3528. Используя конфиги для Hinlink H28K, первого поддерживаемого в Armbian устройства на этом чипе.

Это продолжение статьи, где я описал несколько способов достать Device Tree файлы из Андроид установленного на TV-боксе. Нужно для запуска на конкретном устройстве, даже для одной и той же модели - компоненты устройства могут отличаться, эти детали есть в Device Tree. Эта инструкция рассказывает как собрать и запустить Armbian используя полученный Device Tree файл. Написано для пользователей Линукс, средней сложности - почти всё подробно описано по шагам.

Инструкция для запуска в том числе с USB накопителя, что по умолчанию отключено в загрузчике U-Boot.

Сборка Armbian для RK3528

Рекомендую почитать статью по сборке Armbian для TV-бокса на чипе Amlogic, которая мне немного помогла.

Но мы немного отклонимся от инструкций из той статьи.

$ git clone --depth=1 https://github.com/armbian/build armbian-build
$ cd armbian-build

Используйте --depth=1 где можно, вряд ли вам нужна вся история коммитов, а в некоторых репозиториях история занимает в десятки раз больше последнего состояния, достаточного для сборки.

Будем использовать конфиг для мини-роутера Hinlink H28K.

$ ./compile.sh build BOARD=hinlink-h28k EXPERT=yes KERNEL_GIT=shallow

KERNEL_GIT=shallow означает --depth=1 для исходников ядра, чтобы не потратить много времени на выкачивания их из интернета и кучу места на диске для хранения ~миллиона мелких файлов.

Вам будет предложено выбрать дистрибутив что вам нравится. У меня заработал Ubuntu 20.04 focal с Xfce десктопом. Потом я попробовал Ubuntu 22.04 jammy с Mate десктопом (который мне больше нравится) - не запускается. Подумал, что может быть это из-за jammy, и собрал focal с Mate - тоже не запускается. Собрал jammy с Xfce - запустился! Так что, имейте в виду, что не все варианты сборки Armbian, что можно выбрать - у вас заработают. (причину нашел - добавил решение в конце статьи)

Скрипт напишет как повторить выбранные опции, например:

./compile.sh build BOARD=hinlink-h28k BRANCH=legacy BUILD_DESKTOP=yes BUILD_MINIMAL=no DESKTOP_ENVIRONMENT=xfce DESKTOP_ENVIRONMENT_CONFIG_NAME=config_base EXPERT=yes KERNEL_GIT=shallow RELEASE=jammy

Сборка Armbian будет компилировать только ядро Линукс, остальные пакеты будут скачаны в готовом виде.

Готовые образы дисков будут лежать в output/images, например с таким именем:

Armbian_23.11.0-trunk_Hinlink-h28k_jammy_legacy_5.10.160_xfce_desktop.img

Добавление своего Device Tree

Как его получить - читайте в моей предыдущей статье.

Можно добавить прямо в образ диска, до записи:

$ sudo mount -o rw,loop,offset=16M <образ-armbian.img> /mnt/loopimage

Или после записи на USB/карту (у меня автоматически раздел не монтируется):

$ sudo mount /dev/sdX1 <директория>

Заходим в примонтированный раздел, в директории dtb/rockchip хранятся .dtb, сюда надо скопировать свой, полученный из boot раздела Андроид.

Например, с таким именем: dtb/rockchip/rk3528-tvbox.dtb

Настройки бута хранятся в armbianEnv.txt, будет примерно такое содержимое (UUID раздела меняется для разных сборок Armbian):

verbosity=1
bootlogo=true
overlay_prefix=rk35xx
fdtfile=rockchip/rk3528-hinlink-h28k.dtb
rootdev=UUID=813764a1-91f7-4247-992f-2ade953afa7d
rootfstype=ext4

Надо изменить строку fdtfile=, указав на .dtb со своего устройства:

fdtfile=rockchip/rk3528-tvbox.dtb

Когда закончили, не забудьте отмонтировать раздел, чтобы все данные сохранились на диск:

$ sudo umount <устройство или директория>

Если на вашем TV-боксе вас есть разъём под карту памяти, то можете вставить карту с записанным образом в него, и пропустить пару следующих разделов этой инструкции.

Порядок загрузки Rockchip устройств

Сначала загрузка идёт с карты памяти, если есть разъём для карты памяти и вставленна карта. Карта памяти подключенная через USB картридер - работает как обычный USB накопитель, поэтому в начальной загрузке не учитывается. Если карта памяти не обнаружена - то загружается с EMMC.

С карты/EMMC должен загрузиться начальный загрузчик SPL, который далее запускает U-Boot, и если U-Boot был собран с опцией CONFIG_ROCKCHIP_USB_BOOT=y , то пытается загрузиться с первого найденного USB устройства в котором на 64 секторе (0x8000 в байтах) стоит один из заголовков Rockchip загрузчиков. В коде U-Boot есть ограничение, что если загрузка началась с карты, то загружаться с USB накопителей уже не будет. Если был найден USB носитель с системой, то SPL и U-Boot записанные на USB накопитель - не выполняются, U-Boot уже загруженный с EMMC сразу переходит к поиску скриптов для загрузки ядра на USB накопителе.

Сборка своего U-Boot с поддержкой загрузки с USB

Нужно для загрузки Linux с USB носителя или для дампа разделов с EMMC без хаков. Описано в предыдущей статье, но повторю.

$ sudo apt-get install gcc-aarch64-linux-gnu
$ git clone --depth=1 https://github.com/rockchip-linux/u-boot.git
$ git clone --depth=1 https://github.com/rockchip-linux/rkbin.git
$ cd u-boot

Заменяем в начале make.sh кросс-компилятор на системный, из пакета gcc-aarch64-linux-gnu: CROSS_COMPILE_ARM64=/usr/bin/aarch64-linux-gnu-

В Armbian есть патчи для hinlink-h28k, лежат они тут:

armbian-build/patch/u-boot/legacy/board_hinlink-h28k

Устанавливаем их находясь в директории u-boot:

$ cat <path-to-armbian-build>/patch/u-boot/legacy/board_hinlink-h28k/*.patch | patch -p1

Патчи добавляют исправления загрузки Линукс и конфиг для Hinlink-H28K. Без этих патчей у вас даже комплектный Андроид из EMMC не станет грузиться.

Перед сборкой сначала уберём ограничение чтения в режиме download:

$ sed -i 's/(blkstart + blkcnt) > RKUSB_READ_LIMIT_ADDR/0/' cmd/rockusb.c

И добавим в конфиг для H28K поддержку загрузки с USB накопителей:

$ sed -i '1i CONFIG_ROCKCHIP_USB_BOOT=y' configs/hinlink_rk3528_defconfig

Можно собирать: $ ./make.sh hinlink_rk3528

Загружаем на устройство: $ rkflashtool w 0x4000 0x2000 < uboot.img

Про rkflashtool рассказано в предыдущей статье. Для U-Boot на Rockchip есть стандартный адрес на диске - 8МБ от начала (в Андроиде он оформлен как раздел, на Линукс - нет), занимает 4МБ - в которых повторяется два раза.

Первый запуск Armbian

При первом запуске нужно подключить устройство к локальной сети, если нет Ethernet разъёма - то через USB адаптер.

При первом подключении по ssh, с именем root и паролем 1234, вас спросят: новый пароль для рута, имя первого пользователя (с правами рута) и пароль для него, язык и часовой пояс. После этого заработает графическая оболочка.

Нечитаемые флэшки

У меня есть USB 3.0 флэшка Kingston на 32Гб - почему-то она как загрузочная не определяется. А вот новая карта на 32Гб через картридер работает. Правда картридер USB 2.0 - возможно в этом дело.

Скорее всего, U-Boot при проверке USB носителей проверяет на наличие интерфейса USB 1.1, а на упаковке флэшки было написано только про USB 2.0/3.0/3.1/3.2. Даже если ОС сможет эту флэшку читать - всё равно для U-Boot нужна поддержка старого стандарта.

Xfce проблемы

Оказалось, что в Xfce из сборки Armbian не работают программы что должны показывать окно для ввода пароля для получения рута. Это множество системных утилит. Решается установкой этого пакета:

sudo apt-get install policykit-1-gnome

После этого надо сделать logout и войти по новой (перезагрузка системы не нужна).

Другие проблемы

У меня нашелся поддельный USB 2.0 хаб, поддельность в том, что работает он явно не со скоростью USB 2.0, а более низкой. В результате чего загрузка Линукс страшно тормозит. Через него я подключал картридер с картой, на которой был записан Линукс.

Через другой USB 2.0 хаб грузится быстро. У меня худший вариант TV-бокса по количеству портов - разъёма карты памяти нет, и один USB 2.0 порт.

Еще один патч для U-Boot

Добавил в статью после публикации. Решает проблему загрузки, что зависит от каких-то случайностей, наверное от мусора в памяти. Именно из-за этого у меня не загружался Armbian с Mate десктопом. По UART в логе такие ошибки:

No resource file: 
VP0 fail to load kernel logo
No resource file: 
VP1 fail to load kernel logo

А потом падение, на разыменовании нулевого указателя.

U-Boot для Rockchip если скомпилирован с CONFIG_DRM_ROCKCHIP (по умолчанию включено) инициализирует дисплей и показывает лого. Лого читается из boot раздела Android, в собственном формате ресурсов от Rockchip. При загрузке Linux с USB накопителя или карты памяти - лого ищется уже в них, и не находится. Они плохо проверяли такой вариант развития событий, может произойти падение в U-Boot.

Данный патч использует вместо лого серый квадрат, который либо рисуется по центру или растягивается на весь экран (зависит от содержимого Device Tree).

--- a/drivers/video/drm/rockchip_display.c
+++ b/drivers/video/drm/rockchip_display.c
@@ -1169,6 +1169,17 @@ static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
        if (!header)
                return -ENOMEM;
 
+#if 1
+       logo->width = logo->height = 256; logo->bpp = 24;
+       dst_size = logo->width * logo->height * logo->bpp >> 3;
+       dst = get_display_buffer(dst_size);
+       if (!dst) { ret = -ENOMEM; goto free_header; }
+       memset(dst, 127, dst_size);
+       logo->offset = logo->ymirror = 0; logo->mem = dst;
+       memcpy(&logo_cache->logo, logo, sizeof(*logo));
+       flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
+       goto free_header;
+#endif
        len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
        if (len != RK_BLK_SIZE) {
                ret = -EINVAL;

Не пробовал запускать Линукс на сборке U-Boot без CONFIG_DRM_ROCKCHIP, но у меня не запускается Андроид без CONFIG_DRM_ROCKCHIP. Подозреваю, что с экраном инициализируется что-то важное, поэтому лучше не отключать этот код.

Обновить U-Boot в образе Armbian можно так:

dd if=uboot.img of=Armbian.img bs=1M count=4 seek=8

Включение 3D ускорения

В конфиге для <armbian-build>/config/kernel/linux-rk35xx-legacy.config при сборке Armbian включить сборку драйвера под названием Lima, что поддерживает 3D ускорение для Mali-400 и Mali-450. После этого нужно пересобрать образ ОС. (=y означает собрать в составе ядра, =m собрать отдельным модулем).

# CONFIG_TINYDRM_ST7735R is not set
# CONFIG_DRM_PL111 is not set
-# CONFIG_DRM_LIMA is not set
-CONFIG_DRM_PANFROST=m
+CONFIG_DRM_LIMA=y
+# CONFIG_DRM_PANFROST is not set
# CONFIG_DRM_TIDSS is not set
# CONFIG_DRM_LEGACY is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y

Но драйвер Lima ожидает, что в Device Tree будут старые названия. Которые Rockchip переименовал в RK3528, чтобы соответствовали названиям для их более новых GPU. Поэтому декомпилируем .dtb полученный из Android:

$ dtc -I dtb -O dts rk3528.dtb -o rk3528.dts

Далее надо заменить interrupt-names и clock-names на старые. В массиве clocks стало шесть чисел (два числа на одно название). Я оставил новые имена для clocks, добавив старые в конец ("bus", "core"). Также скопировал первые 4 числа из массива clocks и добавил в конец массива (0x07 0x16 0x02 0x113), теперь по старым названиям будут читаться они.

 	gpu@ff700000 {
 		compatible = "arm,mali-450";
 		reg = <0x00 0xff700000 0x00 0x40000>;
 		interrupts = <0x00 0x58 0x04 0x00 0x59 0x04 0x00 0x56 0x04 0x00 0x5c 0x04 0x00 0x5d 0x04 0x00 0x5a 0x04 0x00 0x5b 0x04>;
-		interrupt-names = "Mali_GP_IRQ\0Mali_GP_MMU_IRQ\0IRQPP\0Mali_PP0_IRQ\0Mali_PP0_MMU_IRQ\0Mali_PP1_IRQ\0Mali_PP1_MMU_IRQ";
-		clocks = <0x07 0x16 0x02 0x113 0x02 0x10e>;
-		clock-names = "clk_mali\0aclk_gpu_mali\0pclk_gpu";
+		interrupt-names = "gp\0gpmmu\0pp\0pp0\0ppmmu0\0pp1\0ppmmu1";
+		clocks = <0x07 0x16 0x02 0x113 0x02 0x10e  0x07 0x16 0x02 0x113>;
+		clock-names = "clk_mali\0aclk_gpu_mali\0pclk_gpu", "bus", "core";
 		assigned-clocks = <0x07 0x16>;
 		assigned-clock-rates = <0x11e1a300>;
 		power-domains = <0x26 0x04>;

Компилируем обратно: $ dtc -I dts -O dtb rk3528.dts -o rk3528-new.dtb

Видеокарта Mali-450 старая (2012-го) и слабая, так что не ожидайте от неё слишком многого. Например, Quake 3 работает с низким FPS. Doom 3 не запустится вообще, драйвер не поддерживает нужные OpenGL расширения.

Дальнейшие доработки

Разместил здесь. Я нашел все расхождения Device Tree с теми что есть в Линукс, в Линуксе представлены конфиги для демо-плат, и названия этих демо-плат в конфигах на TV-боксах поленились менять на название устройства. Конфиги в Линуксе имеют больше информации для правильной работы драйверов. Скомбинировав Device Tree из Линукс и с устройства - я исправил пару падений драйверов, что видел в логе.

Также я добавил в конфиг ядра Линукс все драйвера что заметил в Андроид. Таким образом заработал нужный драйвер для звука и ТВ-выход. HDMI-аудио при этом не работает, хотя драйвер есть, где происходит затык - я не знаю, звук через драйвер воспроизводится, но на колонки монитора ничего не приходит. Звук из выхода на телевизор работает. И видео на телевизор работает.

Также я включил драйвера для аппаратного ускорения декодирования/кодирования видео, но не знаю как их проверить. Также какой-то драйвер для аппаратного ускорения алгоритмов шифрования.

В логах WiFi драйвер многократно жалуется что не может найти прошивку. Пробовал взять прошивку из предустановленного Android, она загружается, но потом следует ошибка что драйвер не может включить устройство, видимо в драйвере (или Device Tree) чего-то не хватает.

Tags:
Hubs:
Total votes 27: ↑26 and ↓1+25
Comments28

Articles