Device Tree

Материал из ALT Linux Wiki

Введение

Данная статья посвящена механизму описания структуры периферии, использующемуся в частности в ядре Linux для архитектур armh и aarch64.

Одноплатные компьютеры семейств RaspberryPi и OrangePi и многие прочие подобные используют в качестве процессора микросхему - систему на кристалле (SoC). Микросхема SoC нуждается только во внешнем ОЗУ, при этом она реализует в одном чипе множество возможных, часто взаимоисключающих конфигураций периферии интерфейсов ввода-вывода.

Таким образом должен быть механизм, позволяющий передать ядру, какая из конфигураций соответствует тому, что распаяно на печатной плате, а также какое поведение инженер-разработчик ожидает от внешних универсальных контактов (штырьков) ввода-вывода платы (GPIO). Данным механизмом и является описываемое здесь дерево устройств - Device Tree.

Форматы файлов

*.dtb файл

Device Tree Binary - иерархическое описание структуры периферии в бинарном формате. Именно в таком формате оно подргужается в ядро Linux в качестве аргумента через загрузчик. Ядро использует структуру, чтобы узнать о периферийных устройствах - какие включены, какие модули ядра задействовать, символические имена.

*.dts файл

Device Tree Strings - представление дерева устройств в человекочитаемом формате. Синтаксис языка похож на JSON. Для связи с описанием в *.dtb формате используется утилита dtc.

Компилятор/декомпилятор dtc

Для работы с описанием дерева устройств предназначен компилятор dtc (пакет dtc).

Для конвертации бинарного дерева устройств в текстовое представление:

dtc $NAME.dtb -o $NAME.dts

Для компиляции текстового описания дерева устройств обратно в бинарное представление:

dtc $NAME.dts -o $NAME.dtb

Оверлеи *.dtbo

В специализированном дистрибутиве Raspbian реализован механизм, позволяющий во время загрузки накладывать на *.dtb файлы патчи. Такой патч, включающий какую-то аппаратную возможность платы, называется оверлеем. Формат файла - такой же, как у .dtb - файл можно прочитать при помощи утилиты dtc.

Файлы находятся в папке /boot/dtb/overlay системы Raspbian. Исследование их помогает понять, как исправить дерево устройств, чтобы включить какую-либо нужную фичу.

Вроде бы, загрузчик U-Boot умеет их применять. Данный вопрос требует дальнейшего исследования.

Настройки

Ванильные *.dtb файлы ядра

Вместе с ядром Linux (проверено для ядер для 5.*) поставляется библиотека *.dtb файлов под разные одноплатные компьютеры, модули и системы. При установке ядра файлы оказываются в папке

/lib/devicetree/`uname -r`

Для каждого чипа и платы имеется свой файл - одна и та же микросхема может оказаться на разных платах разных производителей.

Настройка устройств под себя

Конфигурации *.dtb, поставляемые вместе с ядром для каждой платы, описывают некоторую базовую конфигурацию, которая подойдёт всем. Учитывая настраиваемость платы, однако же, может потребоваться эту конфигурацию изменить. Для этого следует вскрыть *.dtb файл утилитой dtc, отредактировать его в *.dts формате и сохранить обратно. Какой из многих файлов загружается - можно посмотреть в выводе загрузчика U-Boot во время старта системы, этот файл будет единственный с именем, соответствующем модели платы.

Обновление ядра

Очевидна проблема - при обновлении ядра исправления будут утеряны. Это не является проблемой, если сборка подготавливается для встраиваемой системы, которую не будут обновлять. Иначе следовало бы написать скрипт, делающий исправления автоматически, и прописать его как-то в механизм /etc/initrd.mk. Эта секция требует уточнения.

Синтаксис

Синтаксис *.dts файла достаточно понятен (очевидно!) =) Лучший способ исследования - вскрыть файл и посмотреть, что там внутри.

Приглашаю всех практикующих инженеров писать сюда свои примеры ;)

Включение и отключение устройств

В исходном, "ванильном" дереве многие устройства описаны, но отключены. Примеры таких устройств - контроллеры шины i2c, контроллер uart (serial). Для включения устройства достаточно поправить один параметр.

Отключённое устройство имеет в своём описании поле:

{
 status = "disabled";
}

Для включения устройства следует исправить:

{
 status = "okay";
}