Загрузка ядра Linux/ppc без Open Firmware

Использование данных модели дерева устройств в Linux

Benjamin Herrenschmidt

Аннотация

Построение дерева устройств для ядра Linux/ppc64


Содержание

Введение
Точка входа для arch/arm
Точка входа для arch/powerpc
Точка входа для arch/x86
Формат болка DT
Заголовок
Общие понятия дерева устройств
Блок "structure" дерева устройств
Блок "strings" дерева устройств
Требования к содержанию дерева устройств
Замечания о клетках и представлении адресов
Замечание по поводу имён свойств и узлов и кодировки символов
Обязательные узлы и свойства
"dtc", компилятор дерева устройств
Рекомендации по загрузчику
System-on-a-chip и узлы
Определение дочерних узлов SOC
Представление устройств, у которых нет OF спецификацииn
Определение информации о прерываниях для SoC устройств
Свойства перываний
Свойство interrupt-parent
Контроллер прерываний OpenPIC
Контроллер прерываний ISA
Задание информации об экономичных режимах питания (сойство sleep)
A. Приложение - Простой узел SOC MPC8540

ToDo:

Введение

Во время разработки ядра Linux/ppc64 kernel, и особенно, при добавлении платформ новых типов, вне старой пары IBM pSeries/iSeries, было принято решение ввести некоторые ограничивающие правила относительно ядра и интерфейса ядро <-> загрузчик, для того, что бы избежать проблем, которые возникли в API ядра ppc32 и открыть дорогу для добавления новых платформ в ядро. Наследие платформы iSeries нарушало эти правила, так как предшествовало им по времени, но не будет поддержки новых плат, главное дерево которых не строго следует этим правилам. Кроме того, так как в точке arch/powerpc слились архитектуры ppc32 и ppc64, новые 32-битные платформы и 32-битные платформы, которые перемещаются в arch/powerpc должны строго соблюдать эти правила.

Главное требование, которое будет ниже опредлено более детально, заключается в присутствии дерева устройств, чей формат определяется после спецификаций Open Firmware. Однако, для облегчения жизни продавцам встраиваемых плат, ядро не требует, что бы дерево устройств представляло каждое устройство в системе, а были представлены только некотрые узлы и свойства. Детально это будет описано в разделе III, но, к примеру, ядро не требует, что бы Вы создавали узлы для каждого PCI устройства в системе. Оно требует, что бы присутствовали узлы для главных PCI мостов, предоставляющие информацию для маршрутизации прерываний и диапазонов памяти В/В, среди прочего. Так же рекомендуется определять узлы для устройств SoC и других шин, которые не особенно соответствуют существующим OF спецификациям. Это создаёт большую гибкость и ядро может проверять их соответствующими им драйверами, без обладания точно заданными всеми типами таблиц. Кроме того, поставщики встроенных плат, приобретают большую свободу при внесении малозначительных обновлений аппаратуры, без значительной переделки кода ядра или помех в специальных случаях.

Точка входа для arch/arm

Когда стартует образ ядра, имеется всего одна точка входа. Эта точка поддерживает два соглашения о вызове. Сводка интерфейса приведена здесь. Полное описание требований загрузки содержится в документе Documentation/arm/Booting.

  1. ATAGS интерфейс. Минимальная информация поступает от встроенных программ в ядро как помеченный список предопределённых параметров.

    • r0 : 0

    • r1 : Номер типа машины

    • r2 : Физический адрес помеченного списка в системной RAM

  2. Точка входа блока плоского дерева устройств. Встроенная программа загружает физический адрес блока плоского дерева устройств (dtb) в r2, r1 не используется, но считается хорошей практикой использовать правильный номер машины в как описано в Documentation/arm/Booting

    • r0 : 0

    • r1 : Правильный номер типа машины. При использовании устройств, зачастую, единственный номер типа машины, будет представлять класс, или семейство SoCs.

    • r2 : Физический указатель на блок памяти, содержащий дерево устройств (определено в главе II). Дерево устройств может быть расположено в любом месте системной RAM, но он должен быть выравнен на 64 бита.

Ядро отличает загрузку по ATAGS от загрузки по дереву устройств, путём чтения указателя памяти из r2 и проверки, имеется ли "магический код" (0xd00dfeed) плоского дерева устройств, или же, со смещением 0x4 от адреса в r2 находится значение ATAG_CORE (0x54410001).

Точка входа для arch/powerpc

Когда стартует образ ядра, имеется всего одна точка входа. Эта точка поддерживает два соглашения о вызове:

  1. Загрузка через Open Firmware. Если Ваши встроенные микропрограммы совместимы с Open Firmware (IEEE 1275), или предаставляет совместимый с OF клиентский интерфейс - API (короче говоря - поддержку коллбэка "interpret"), Вы можете войти в ядро следующими путями:

    • r5 : Указатель коллбэка из OF, определённый в IEEE 1275, в части powerpc. В настоящее время поддерживается только 32-битный интерфейс клиента.

    • r3, r4 : адрес & длина initrd, если есть, или ноль.

    MMU либо включено, либо выключено; ядро будет выполнять действия из arch/powerpc/kernel/prom_init.c для того, что бы выбрать дерево устройств и другую информацию из OF и построить плоское дерево устройств, как описано в b). После этого, будет вновь вызвана ядром prom_init(), используя второй метод. Этот код работает в контексте встроенных микропрограмм, которые поддреживают управление исключениями, которые происходят в это время.

  2. Прямой вход через блок плоского дерева устройств. Эта точка входа вызывается из а) после отработки OF и может быть вызвана напрямую загрузчиком, который не поддерживает интерфейс клиента OF. Она так же используется "kexec" для реализации "горячей" перезагрузки новой версии ядра из работающей предыдущей. Этот метод я опишу более детально в этом документе, так как метод a) это просто стандарт OF и, таким образом, должен быть реализован согласно различным документам стандарта, определяющим его и его связь с архитектурой платформы powerPC. Таким образом, эта точка входа определяется так :

    • r3 : физический указатель на блок дерева устройств (определённый в главе II) в RAM.

    • r4 : физический указатель на само ядро. Он используется для сборки кода, правильно запрещающего MMU, в случае, когда Вы вводите ядро с разрешённым MMU и мапирование не 1:1.

    • r5 : NULL ( в отличие от метода a)

    Замечание относительно точки входа SMP: Либо встроенные микропрограммы переводят другой ЦП в некоторый цикл засыпания, или спин-блокировку в ROM, вывести его из этого состояния вы сможете только программной перезагрузкой, или некоторым другим способом, в этом случае Вам не нужно беспокоиться, либо Вы входите в ядро со всеми ЦП. Этот путь называется метод б) и будет описан в более поздних версиях этого документа.

Поддержка платы (платформы) заключается не только в опциях конфигурации. Можно построить произвольный набор поддерживаемых плат в одном образе ядра. Ядро будет "знать" какой набор функций используется для заданной платформы на основании содержимого дерева устройств. Таким образом, Вы должны:

  1. добавить поддержку Вашей платфоры как boolean опцию в файл arch/powerpc/Kconfig следуя примерам для PPC_PSERIES, PPC_PMAC and PPC_MAPLE. Последний, возможно, является наилучшим примером поддержки платы, с которого надо начинать.

  2. Создайте Ваш главный файл платформы вроде этого: arch/powerpc/platforms/myplatform/myboard_setup.c и добавьте его в Makefile под условием, управляемым Вашей булевой CONFIG_ опцией. Этот файл должен определять структуру типа "ppc_md", различные обратные вызовы, которые будут использоваться общейчастью кода для доступа к Вашему коду, специфичному для платформы.

Образ ядра может поддерживать множество платформ, но только если особенности платформ одинаковы в архитектуре ядра. Один релиз ядра не может поддерживать конфигурационные опции как для "Book E" так и для классической архитектуры PowerPC.

Точка входа для arch/x86

Здесь есть только одна единственная точка входа в декомпрессор ядра code32_start (точка входа реального режима ведёт в ту же самую 32-битную точку входа, после того, как она переключается в защищённый режим). Эта точка входа поддерживает одно соглашение о вызове, которое описано в Documentation/x86/boot.txt

Физический указатель на блок дерева устройств (определённый в главе II) передаётся посредством запроса setup_data which, начиная с версии протокола 2.09. Тип этого поля опредлён как

#define SETUP_DTB                      2

Это дерево устройств используется как расширение "страницы загрузки" Само по себе оно не рассматривает / разбирает данные, которые уже представлены на странице загрузки. Это включает размер памяти, резервируемые диапазоны, аргументы командной строки или адрес initrd. Она просто содержит информацию, которую невозможно получить иначе, вроде обработки прерываний или списка устройств, подключённых к шине I2C.

Формат болка DT

В этой главе определяется действующий формат выровненного дерева устройств, передаваемого ядру. Его фактическое содержание и требвания к ядру будут описаны позже. Вы можете найти примеры кода, работающего с этим форматом, в различных местах, включая arch/powerpc/kernel/prom_init.c который генерирует выровненное дерево устройств из представления Open Firmware, или утилита fs2dt, которая является частью инструментария kexec, которая будет генерировать дерево из представления файловой системы. Предполагается, что загрузчик типа uBoot обеспечит немного более поддержки, которая будет подробно обсуждаться позднее.

Примечание

Блок должен быть в главной памяти. Он должен быть доступен во время загрузки как в реальном, так и в виртуальном режиме, и не должен мапироваться никуда, кроме главной памяти. Если Вы пишите простой загрузчик с флэш, то он должен копировать блок в RAM до передачи его ядру.

Заголовок

Ядру передаётся физический адрес, указывающий на область памяти, в общих чертах описанную в include/linux/of_fdt.h и содержащую структуру boot_param_header:

struct boot_param_header {
        u32     magic;                  /* magic word OF_DT_HEADER */
        u32     totalsize;              /* total size of DT block */
        u32     off_dt_struct;          /* offset to structure */
        u32     off_dt_strings;         /* offset to strings */
        u32     off_mem_rsvmap;         /* offset to memory reserve map   */
        u32     version;                /* format version */
        u32     last_comp_version;      /* last compatible version */
        /* version 2 fields below */
        u32     boot_cpuid_phys;        /* Which physical CPU id we're booting on */
        /* version 3 fields below */
        u32     size_dt_strings;        /* size of the strings block */
        /* version 17 fields below */
        u32	size_dt_struct;		/* size of the DT structure block */
};

Определения констант:

/* Definitions used by the flattened device tree */
#define OF_DT_HEADER            0xd00dfeed      /* 4: version, 4: total size */
#define OF_DT_BEGIN_NODE        0x1             /* Start node: full nam  */
#define OF_DT_END_NODE          0x2             /* End node */
#define OF_DT_PROP              0x3             /* Property: name off,  size, content */
#define OF_DT_END               0x9

Все значения в этом файле заголовков заданы в "big endian" формате, различные поля этого заголовка более точно описаны ниже. Все значения "offset" заданы в байтах от начала заголовка; то есть от физического базового адреса блока дерева устройств.

- magic

Это "магическое" значение, которое помечает начало заголовка блока дерева устройств. Оно содержит значение 0xd00dfeed и должно определено как константа OF_DT_HEADER

- totalsize

Общий размер блока DT, включая заголовок. Блок DT должен включать в себя все структуры данных, определённые в этой главе (которые задаются смещениями в заголовке). Т.е. саму стрктуру дерева устройств, строки и карту резервирования памяти.

- off_dt_struct

Задаёт смещение от начала заголовка до начала части "structure" в дереве устройств (см раздел 2 дерева устройств).

- off_dt_strings

Задаёт смещение от начала заголовка до начала части "strings" в дереве устройств.

- off_mem_rsvmap

Задаёт смещение от начала заголовка до начала памяти, зарезервированные под карту памяти. Карта представляет собой список пар 64-битных целых. Каждая пара представляет собой физический адрес и размер. Список заканчивается элементом с нулевой длинной. Карта предоставляет ядру список областей физической памяти, которые должны быть "зарезервированны" и не могут быть использованы при выделении памяти, особенно при начальной инициализации. Ядро обязано выделить память во время загрузки для таких вещей, как не выровненное дерево устройств, MMU хэш-таблиц и т.д. Такое выделение делается как путь, для того. что бы избежать переписывания критических вещей, подобных машине способностей Open Firmware, экземпляров RTAS или, на некотрых pSeries, таблицы TSE, используемые в iommu. Обычно, резервируемая память должна содержать, как минимум, сам блок DT (адрес заголовка, полный размер). Если Вы передаёте ядру initrd, то его Вы тоже должны зарезервировать в этой таблице. Нет нужды резервировать память под само ядро. Карта должна быть выровненна на 64 бита.

- version

Версия этой структуры. Верся 1 заканчивалась здесь. В версии 2 добавилось поле boot_cpuid_phys. В версии 3 добавился размер блока строк, что позволило ядру легко переместить его во время загрузки и освободить не используемые выравненные структуры после раширения. Версия 16 ввела новый, более "компактный" формат самого дерева, который, однако, не обладал обратной совместимостью. В версии 17 появилось дополнительное поле size_dt_struct, делающее перемещение или удаление блоков более лёгким (в частности, это полезно для загрузчиков, которым необходимо настроить дерево устройств на основе опрашиваемой информации). Вы должны всегда создавать структуру наивысшей версии, определённой в момент разработки. В настоящий момент, это версия 17, за исключением вариантов, когда Вашей целью является обратная совместимость.

- last_comp_version

последняя совместимая версия. Указываетдо какой, самой старой, версии обеспичивается совместимость этим блоком DT. Например, версия 2 обратно совместима с версией 1 (Это означает, что ядро, собранное для версии 1, способно загрузить DT формата версии 2). Вы должны задат 1 в этом поле, если Вы генерируете дерево устройств для версий от 1 до 3, или 16, если версии 16 и 17 используют новый формат формат имён единиц.

- boot_cpuid_phys

Это поле появилось заголовке версии 2. Оно задаёт ID того ЦПУ, который должен быть запущен при входе в ядро. Это используется, среди прочего, при вызове kexec. Если вы работаете на SMP системе, то это значение должно соответствовать свойству "reg" узла CPU в дереве устройств, соответствующего тому процессору, который должен запускаться при входе в ядро.(см. следующие разделы для более детальной информации требованиях к содержимому устройств).

- size_dt_strings

Это поле существует только в версии 3 и более поздних. Оно задаёт размер секции строк ("strings") дерева устройств. Начало секции задаётся смещением, указанным в off_dt_strings.

- size_dt_struct

Это поле существет только в версии 17 и более поздних. Оно задаёт размер секции структур ("structure") дерева устройств, которая начинается адресом, заданным в off_dt_struct.

Так выглядит типичный блок DT (его различные части не обязаны идти в этой последовательности). Адресация идёт сверху вниз:

             ------------------------------
     base -> |  struct boot_param_header  |
             ------------------------------
             |      (alignment gap) (*)   |
             ------------------------------
             |      memory reserve map    |
             ------------------------------
             |      (alignment gap)       |
             ------------------------------
             |                            |
             |    device-tree structure   |
             |                            |
             ------------------------------
             |      (alignment gap)       |
             ------------------------------
             |                            |
             |     device-tree strings    |
             |                            |
      -----> ------------------------------
      |
      |
      --- (base + totalsize)

(*)

Выравнивающие промежутки (alignment gaps) не являются обязательными. Их наличие и размер зависят от различных требований по выравниванию конкретных блоков данных.

Общие понятия дерева устройств

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

Для начала, давайте быстро опишем концепцию дерева устройств, до детального рассмотрения формата хранения. В этой главе не даются детали требуемых типов узлов и свойств для ядра, это будет сделано позже, в главе III.

Основные идеи дерева устройств были унаследованы из дерева устройств Open Firmware IEEE 1275. В своей основе, это дерево, состоящее из узлов. Каждый узел имеет два или более именованых свойства. Свойство может иметь или не иметь значения.

Так как это дерево, то какждый узел имеет одно и только одного родителя. Исключение составляет только корневой узел, не имеющий родителя.

Узел имеет два имени. Фактически, имя узла обычно содержится в свойстве типа "name" в списке свойств узла, чьё значение должно быть нуль-терминированной строкой, и обязательно для версий от 1 до 3 определения формата (Как это сделано в Open Firmware). Версия 16 делает это не обязательным, так как оно может быть сгенерировано из имени устройства, определённого ниже.

Мы можем использовать одно "имя устройства" для узлов с одним именем, находящихся на однеом уровне, обычно имя таких узлов состоит из имени узла, знака "@" и последующим адресом устройства, который определяется конкретно для каждого типа шины, к которой подключено это устройство.

Имя устройства не существует само по себе, как свойство, но оно включается в структуру дерева. Типичным является использование представления "пути" в дереве устройств. Фактический формат будет описан ниже более детально.

Обычный код ядра никак не использует формальные адреса устройств (что может быть осуществлено путём выполнения некоторого кода поддержки платы), так что реальным требованием к адресу устройства только то, что имена всех устройств на данном уровне дерева являются уникальными. Узлы, у которых не задан адрес, не могут иметь братьев с таким же именем на этом уровне дерева (Например - /memory или /cpu) могут пропускать адрес устройства в контексте этой спецификации, или использовать адрес по умолчанию "@0". Имя устройства используется для определения полного пути к устройству, который представляет собой конкатенацию имён всех узлов, разделённых знаком "/".

Корневой узел не имеет определённого имени, и не обязан иметь "name", даже если Вы используете версию 3 или более ранний формат. У него так же нет и адреса устройства (нет символа "@" следующего за именем устройства). Именем узла корневого устройства является пустая строка. Полный путь к корневому узлу обозначается "/".

Каждый узел, который на самом деле представляет конкретное устройство, (это узлы, которые являются не просто виртуальными контейнерами для для других узлов, например - "/cpus"), обязаны иметь свойство "compatible", указывающее на конкретное оборудование и необязательный список устройств, с которыми обеспечивается полная обратная совместимость.

Наконец, каждый узел, на который допустимо ссылаться из свойств другого узла, должен иметь свойство "phandle" (указатель) или "linux,phandle". Настоящие реализации Open Firmware предоставляют уникальное значение "phandle", для каждого узла, который включает стартовый код "prom_init()" в свойство "linux,phandle". Однако, это становится не обязательным если напрямую используется плоское дерево устройств. Примером узла, ссылающегося на другой узел посредством "phandle", является набросок дерева прерываний, который будет опсан в следующих версиях этого документа.

Свойство "phandle" является 32-битным значение, которое однозначно идентифицирует узел. Вы вольны использовать любые значения, или систему значений, внутренние указатели, или любые сгенерированные значения, единственное требование заключается в том, что бы Вы обеспечили каждому узлу уникальное значение этого свойства.

Здесь приводится пример простейшего дерева устройств. В этом примере символ "o" обозначает узел, следующий за именем узла устройства. Свойства представлены как имя, за которым следует содержимое этого свойства. "Содержимое" представляется ASCII строкой ( с нулевым завершителем), в то время, как <содержимое> представляет 32-битное значение, заданное в десятичном или шестнадцатиричном формате (определяется префиксом 0x). Различные узлы в этом дереве будут обсуждаться позднее в этой главе. Пока я хочу дать Вам только общий смысл идеи того, как выглядит дерево устройств. Я намереваюсь сохранить свойства "name" и "linux,phandle" хотя это и не является необходимым с точки зрения понимания того, как дерево устройств выглядит на практике.

  / o device-tree
      |- name = "device-tree"
      |- model = "MyBoardName"
      |- compatible = "MyBoardFamilyName"
      |- #address-cells = <2>
      |- #size-cells = <2>
      |- linux,phandle = <0>
      |
      o cpus
      | | - name = "cpus"
      | | - linux,phandle = <1>
      | | - #address-cells = <1>
      | | - #size-cells = <0>
      | |
      | o PowerPC,970@0
      |   |- name = "PowerPC,970"
      |   |- device_type = "cpu"
      |   |- reg = <0>
      |   |- clock-frequency = <0x5f5e1000>
      |   |- 64-bit
      |   |- linux,phandle = <2>
      |
      o memory@0
      | |- name = "memory"
      | |- device_type = "memory"
      | |- reg = <0x00000000 0x00000000 0x00000000 0x20000000>
      | |- linux,phandle = <3>
      |
      o chosen
        |- name = "chosen"
        |- bootargs = "root=/dev/sda2"
        |- linux,phandle = <4>

Это дерево - почти минимально возможное. Его достоинство заключается в том, что оно содержит минимальный набор узлов и свойств, требуемых для загрузки ядра; таким образом, оно представляет собой базовую модель информации о корне, процессорах и физической памяти. Оно так же включает в себя некотрую дополнительную информацию, передаваемую через узел /chosen, как в этом примере, тип платформы (бязательно) и аргументы командной строки ядра (опционально).

Свойство /cpus/PowerPC,970@0/64-bit является примером свойства без значения. Все другие свойства имеют значения. Смысл значений свойств #address-cells и #size-cells будет пояснён в главе V, которая точно определяет требования к узлам и свойствам и их содержимому.

Блок "structure" дерева устройств

Структурой дерева устройств является линеаризованная структура дерева. Токен "OF_DT_BEGIN_NODE" начинает новый узел, а токен "OF_DT_END_NODE" завершает определение узла. Потомки этого узла определяются до завершающего токена "OF_DT_END_NODE" (они являются узлами внутри узла). Токены представляют собой 32-битные значения. Дерево должно заврешаться токеном OF_DT_END.

Здесь Вы видете базовую структуру одного узла:

  • Токен OF_DT_BEGIN_NODE (это число 0x00000001)

  • В версиях от 1 до 3, здесь находится полный путь к узлу в виде нуль-терминированной строки, начинающаяся с '/'. Для версии 16 и более поздних, здесь находится только имя устройства (или пустая строка для корня дерева).

  • [Необязательный заполняющий промежуток на границу 4 байт]

  • Для каждого свойства:

    • Токен OF_DT_PROP (это число 0x00000003)

    • 32-битное значение размера свойства в байтах (или 0, если значения нет)

    • 32-битное значение смещения имени свойства в блоке строк

    • Данные, образующие значение свойства, если оно есть.

    • [Необязательный заполняющий промежуток на границу 4 байт]

  • [Дочерние узлы, если они есть]

  • Токен OF_DT_END_NODE (Это число 0x00000002)

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

Порядок свойств и субузлов

Определение выше требует, что бы все определения свойств конкретного узла, предшествовали опрелелениям любых дочерних узлов. Несмотря на то, что перемешивание свойств и субузлов безопасно, парсер ядра требует, что бы свойства шли первыми (до версии ядра 2.6.22). Любые инструменты манипулирования с плоским деревом должны сохранять это ограничение.

Блок "strings" дерева устройств

В целях экономии памяти, имена свойств, которые обычно являются избыточными, хранятся в отдельном блоке "strings". Этот блок - просто набор нуль-терминированных строк, для всех имён строк, объединённый в единое целое. Определения свойств дерева устройств в блоке структур содержат смещения от начала блока строк.

Требования к содержанию дерева устройств

Предупреждение

Все свойства "linux,*" определённые в этом документе, применимы только к плоскому дереву устройств. Если на Вашей платформе используется реализация клиентского интерфейса Open Firmware, или совместимая с ним, то эти свойства будут создаваться загрузочным кодом в файле ядра prom_init(). Здесь, например, Вы должны добавить код для определения модели платы и установки номера платформы. Однако, если используется точка входа через плоское дерево устройств, то невозможно пройти через prom_init() и поэтому, Вы должны задать эти свойства самостоятельно.

Замечания о клетках и представлении адресов

Универсальное правило задано в различных документах Open Firmware. Если Вы решите описывать шину посредством дерева устройств и существует описание этой шины в OF, то Вы должны следовать этим спецификациям. Однако ядро не требует, что бы все устройства и шины были описаны в дереве устройств.

Как правило, формат адреса устройства определяется типом родительской шины, на основе свойств #address-cells и #size-cells. Необходимо отметить, что "дедовские" определения свойств #address-cells и #size-cells (т.е. определения в родителе родителя) не наследуются теми узлами, чьи наследники должны задавать эти свойства. Ядро требует, что бы корневой узел имел эти свойства определения формата адреса устройств, прямо подключенных к шине процессора.

Эти два свойства определяют "клетку" ( 'cell') для представления адреса и размера. Любая 'cell' - 32-битное число. Например, если оба свойства содержат значение 2, как в вышеприведённом примере, то это означает, что и адрес и размер состоят из двух клеток, т.е. каждый из них является 64-битным числом (клетки конкатенируются, подразумевается формат big endian format). Другим примером может быть путь Apple в её микропрограммах, где под адрес отводится две клетки и одна - под размер. Большинство 32-битных реализаций должны определять #address-cells и #size-cells как 1, что и означает 32-битное значение. Некоторые 32-битные процессоры допускают адресацию более 32 бит; такие процессоры должны определять #address-cells как 2.

Свойство "reg" всегда задаётся парой типа "address size", в которых количество клеток адреса и размера определяется свойствами #address-cells и #size-cells шины. Если шина поддерживает различные адресные пространства и другие флаги, относящиеся к выделению адресов на данной шине (такие, как например 'prefetchable' и т.д.) то эти флаги обычно добавляются на верхнюю часть физического адреса. Например, физический адрес PCI состоит из трёх клеток. две нижние содеражт сам фактический адрес, в то время, как старшая клетка содержит индикаторы адресного пространства, флаги и номера шины & устройства.

Для тех шин, которые поддерживают динамическое выделение адресов, на практике принято не передавать адреса в "reg" (сохраняя его нулевым), а задавать флаг, указывающий на динамическое выделение адресов и затем устанавливать специальное свойство "assigned-addresses", которое содержит правильно установленный адрес. Подробности можно посмотреть в привязке OF для PCI.

Обычно предпочтительнее использовать шины без динамического выделения адресов и битов адресного пространства, если это отражает Вашу аппаратуру, так как существующие функции разбора адресного пространства ядра будут вынуждены работать за границами. Если Вы определяете тип шины с более сложным адресным форматом, влючающим такие вещи, как биты адресного пространства, Вы должны добавить транслятор шины в файл prom_parse.c в новейшие версии ядра для обслуживания Вашей шины.

Свойство "reg" определяет адреса и размеры ( если #size-cells равно 0) только внутри заданной шины. Для перевода адресов вверх ( адресное пространство шины старшего уровня, или в физические адреса ЦП), все шины должны содержать свойство "ranges". Если это свойство отсутствует на некотором уровне, то подразумевается, что трансляция адресов невозможна, т.е. что регистры не видны на родительской шине. Формат свойства "ranges" для шины представляет собой список:

	  адрес на шине, адрес на родительской шине, размер

"адрес на шине" - формат шины, которую определяет этот узел, для PCI моста это будет PCI адрес. Таким образом (адрес на шине, размер) определяют диапазон адресов для устройств. "адрес на родительской шине" задаёт формат родительской шины, по отношению к этой шине. Например, длч хост-контролера PCI, здесь должен быть адрес ЦП. Для мостов PCI<->ISA здесь будет PCI адрес. Таким образом опеределяется базовый адрес на родительской шине, с которого начинается диапазон мапирования.

Для поддержки новых 64-битных плат, я бы рекомендовал либо формат 2/2, либо формат Apple 2/1, который чуть более компактен, так как размер обычно не превышает 32 бита. Новые 32-битные платы должны использовать формат 1/1, исключая те процессоры, которые поддерживают физическую адресацию более 32 бит, для которых рекомендовано использование формата 2/1.

Alternatively, the "ranges" property may be empty, indicating that the registers are visible on the parent bus using an identity mapping translation. In other words, the parent bus address space is the same as the child bus address space.

О свойстве "compatible"

Это свойство не обязательно, но рекомендовано для корневого узла и узлов устройств. Форматом свойства "compatible" является список нуль-терминированных строк, конкатенированных в одну строку. Это свойство позволяет указать для устройства его совместимость с семейством или аналогичными устройствами, что в некоторых случах, позволяет одному драйверу обслуживать несколько разных устройств, не обращая внимания на реальные имена устройсты.

О свойстве "name"

В то время, как старые пользователи Open Firmware, вроде Macintosh, стремятся использовать фактические имена устройств в свойстве "name", в наши дни считается хорошей практикой использовать имена устройств, которые покрывают целый класс (часто соответствущие типу устройств). Например, сегодня все Ethernet контроллеры в свойсте "name" содержат "ethernet" и имеют дополнительной свойство "model", точно определяющее тип/модель микросхемы и свойство "compatible", задающее семейство, для одного типа драйвера, который может управлять более чем одним типом микросхем. Однако, обычно ядро не должно налагать любые ограничения на свойство "name"; просто считается хорошей практикой следовать стандарту и его измениям, насколько это возможно.

Новая версия 16

Необходимо отметить, что в новой версии 16, свойство "name" не является обязательным. Если в некотором узле оно отсутствует, то для создания этого имени используется имя устройства этого узла. Это та часть имени устройства, которая стоит перед символом "@" (или всё имя устройства, если знака "@" нет).

Замечание по поводу имён свойств и узлов и кодировки символов

В то время, как Open Firmware предоставляет возможность более гибкого использования 8859-1, эта спецификация накладывает более строгие правила. Узлы и свойства должны включать в себя только ASCII символы от 'a' до 'z', от '0' до '9', ',', '.', '_', '+', '#', '?', и '-'. В именах узлов дополнительно разрешается использовать буквы верхнего регистра от 'A' до 'Z' (имена свойств должны быть в нижнем регистре. Тот факт, что производители типа Apple не одобрят это правило, к делу не относится). Кроме того, имена узлов и свойств всегда должны начинаться с символов из диапазона от 'a' до 'z' ( или от 'A' до 'Z' для имён узлов).

Максимальное количество символов в именах узлов или свойств равно 31. Для случая имён узлов, имеется в виду только самая левая часть имени устройства (т.е. настоящее свойство "name"), оно не должно включать адрес устройства, который может выйти за это ограничение.

Обязательные узлы и свойства

Здесь описаны все требования, которые предъявляются в настоящее время. Однако, настоятельно рекомнедуется, что бы отображали PCI хост-мосты, как это задокументировано в привязке PCI к Open Firmware, а Ваше дерево прерываний - как задокументровано в спецификации дерева в OF.

Корневой узел

В корневом узле обязательно должны быть представлены следующие свойства:

  • - model : /модель Вашей платы

  • - #address-cells : Отводится для представления адреса корневых устройств

  • - #size-cells: Отводится для "размера" устройств на "root"

  • - compatible : поведение "семейства" плат обычно определяется здесь, например, если у Вас есть две платы похожей архитектуры, то обычно они будут управляться в ядре одинаково, если имеют один код платформы, Вы должны точно указать модель платы в свойстве "compatible", после которого следует сущность, представляющая модель SoC.

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

Узел /cpus

Этот узел является родительским для всех узлов индивидуальных ЦП. К нему не предъявляется каких-то особых требований, но считается хорошей практикой задавать, как миниммум:

               #address-cells = <00000001>
               #size-cells    = <00000000>

Это указывает, что "адрес" в этом ЦП одной "клеткой" и не имеет осмысленного размера. Это не является обязательным, но ядро будет предполагать, что формат, при чтении свойства "reg" этого узла ЦП будет таким, как описано ниже.

Узлы /cpus/*

Предполагается, что под узлом /cpus Вы будете узлы для каждого ЦП на Вашей машине. Не существует специальных ограничений на имена ЦП, думается, что в общем виде они должны называться <архитектура>,<ядро>. Так например, Apple использует PowerPC,G5, в то время. как IBM использует PowerPC,970FX. Однако, соглашение об Общих Именах считает лучшим использовать просто имя 'cpu' для каждого процессора, и использовать свойство 'compatible' для идентификации конкретного ядра ЦПУ.

Требуемые свойства:

  • - device_type : Должно быть "cpu"

  • - reg : Это физический номер ЦП, одна 32-битная клетка используется "как есть" в качестве номера устройства, при конструировании имени устройства в пути. Например, с двумя ЦП Вы будете иметь следующий полный путь:

    • /cpus/PowerPC,970FX@0

    • /cpus/PowerPC,970FX@1

    (В адресе устройства не обязательно использовать лидирующие нули)

  • - d-cache-block-size : одна клетка, размер блока кэша данных L1 в байтах(*)

  • - i-cache-block-size : одна клетка, размер блока кэша команд L1 в байтах

  • - d-cache-size : одна клетка, размер кэша данных L1 в байтах

  • - i-cache-size : одна клетка, размер кэша команд L1 в байтах

(*)

Размер "блока" этот тот размер, с которым работают команды управления кэшем. Исторически, в документе используется размер "строки" кэша, что не корректно. Ядро ожидает размер блока кэша и будет откатываться к размеру строки кэша, для целей обратьной совместимости.

Рекомендуемые свойства:

  • - timebase-frequency : ячейка, указывающая частоту базы времени в Гц. Это свойство не используется напрямую для генерации кода, но Вам предлагается копировать код из pSeries для организации калибровки timebase/decrementer на основе этого значения.

  • - clock-frequency : ячейка, указывающая частоту генератора ядра ЦП в Гц. Новое свойство может быть определено как 64-битное значение, но если частота Вашего процессора < 4ГГц, то одной ячейки вполне достаточно. Здесь, так же как и выше, общий код не использует это свойство, но Вам предлагается повторно использовать код от pSeries или Maple. Будущие версии ядра должны должны представить общие функции для этого свойства.

  • - d-cache-line-size : одна клетка, размер строки кэша данных L1 в байтах, если отличается от размера блока

  • - i-cache-line-size : одна клетка, размер строки кэша команд L1 в байтах, если отличается от размера блока

Вы приглашаетесь добавлять любые свойства, которые Вы сочтёте подходящими для Вашей платы, вроде информации о механизмах, используемых для программного сброса ЦП. Например, Apple помещает здесь номер линии GPIO для программного сброса ЦП, как свойство "soft-reset", так как запуск второго ЦП начинается с этого.

Узлы /memory

Для того, что бы определить схему организации памяти на Вашей плате, Вы должны создать один, или несколько, узлов /memory. Вы можете либо создать один узел /memory, в котором перечислите все регионы памяти в свойствах 'reg' , либо Вы можете создать несколько узлов, по Вашему желанию. Адрес устройства (часть '@'), используемый в полном пути, является адресом первого диапазона памяти, определённого в данном узле. Если Вы используете единственный узел памяти, то обычно это будет @0.

Требуемые свойства:

  • - device_type : должен быть "memory"

  • - reg : Это свойство содержит все физические диапазоны памяти Вашей платы. Оно представляет собой список пар "адрес/размер" объединённых в одну строку, размер (в клетках) каждого элемента этой пары определён в #address-cells и #size-cells в корневом узле. например, если оба эти свойства установлены в 2, как в примере, приведённом выше, то машины на базе 970 с 6 ГБ памяти RAM должны, обычно, иметь свойство "reg", выглядещее как-то так :

      00000000 00000000 00000000 80000000
      00000001 00000000 00000001 00000000

Первый диапазон начинается с 0 и содержит 0x80000000 байт, а второй диапазон начинается с 0x100000000 и содержит 0x100000000 байт. Вы можете видеть, что между 2Gb и 4Gb имеется "дыра", которая ничем не закрыта. Некоторые поставщики предпочитают разделять такие диапазоны на более мелкие сегменты, но ядро это не заботит.

Узел /chosen

Этот узел немного особый. Обычно, Open Firmware помещает именно сюда информацию о некоторых переменных окружения, вроде аргументов, или устройств ввода/вывода по умолчанию.

Данная спецификация делает некоторые из них обязательными, но так же определяет некоторые свойства, специфичные для linux, которые обычно должны быть созданы с помощью prom_init() загрузчиком, когда загрузка выполняется с OF клиентским интерфейсом, Вы должны предоставить их самостоятльно, если используется плоский формат.

Рекомендуемые свойства:

  • - bootargs : Нультерминированная строка, передаваемая ядру, как командная строка.

  • - linux,stdout-path : Это должен быть полный путь устройству стандарной консоли, если она имеется. Обычно, если есть последовательный порт на вашей плате, то Вы пожелаете поместить полный путь к нему, задав его как консоль по умолчанию, для всех программ загрузки, для ядра, указав его как собственную консоль по умолчанию.

Примечание

Заметим, что u-boot создаёт и заполняет узел /chosen для платформ, которые используют этот узел

Примечание

Практика, когда свойство узла /chosen, называемое interrupt-controller, чьё значение указывало на главный контроллер прерываний, считается устаревшей.

Узел /soc<SOCname>

Этот узел используется для описания системы на кристалле (system-on-a-chip - SoC) и должен присутствовать, если процессор является SoC. Верхний уровень узла /soc содержит глобальную информацию о всех устройствах, входящих в SoC. Имя узла должно содержать адрес SoC устройства, который является базовым адресом для набора регистров SoC, отмапированных на память. Имя узла SoC должно начинаться с символов "soc", а оставшая часть имени должна представлять номер устройства на SoC. Например, SoC устройство MPC8540 будет называться "soc8540".

Требуемые свойства:

  • - ranges : Должно быть определено, как описано в 1) для задания перевода SoC адресов для мапирования на память SoC регистров.

  • - bus-frequency: Содержит частоту шины данногоSoC узла. Обычно, значение этого поля заполняется загрузчиком.

  • - compatible : Точное название модели SoC

Рекомендуемые свойства:

  • - reg : Это свойство определяет адрес и размер области регистров самого SoC узла, которые мапируются на память. Регистры дочерних устройств не должны включаться сюда - они должны быть опеределны внутри соотвествующих дочерних узлов. Адреса, заданные в свойстве "reg" должны соответствовать адресам устройства узла SoC.

  • - #address-cells : Представление адреса для устройства "soc". Формат этого поля может изменяться в зависимости от того, являются ли регистры устройства мапируемыми на память. Для мапируемых на память регистров это поле задаёт количество клеток, необходимое для пердставления адреса регистра. Для тех SoC устройств, которые не используют MMIO, должен быть определён специальный формат адреса, котрый содержит достаточно клеток для представления требуемой информации. Для более детальной информации об #address-cells смотри раздел 1) выше.

  • - #size-cells : Количество клеток, необходимое для представления размера "soc" устройства

  • - #interrupt-cells : Определяет ширину клеток, используемых для представления перывания. Обычным значением является <2>, которое включает 32 бита для представления номера прерывания и 32 бита для числа, задающего смысл и уровень прерывания. Это поле необходимо только для SoC, содержащих контроллер прерываний.

Узел soc может содержать дочерние узлы для каждого SoC устройства, которое используется платформой. Не должны создаваться узлы для устройств, которые существуют на SoC, но используются только в конкретных платформах. Сморти главу VI для подробной информации о том, как задавать устройства, которые являются частью SoC.

Пример 1. SOC node for the MPC8540:

	soc8540@e0000000 {
		#address-cells = <1>;
		#size-cells = <1>;
		#interrupt-cells = <2>;
		device_type = "soc";
		ranges = <0x00000000 0xe0000000 0x00100000>
		reg = <0xe0000000 0x00003000>;
		bus-frequency = <0>;
	}

"dtc", компилятор дерева устройств

Примечание

Исходный код dtc найти тут: Исходный код dtc

Предупреждение

Текущая версия находится на ранней стадии разработки: результирующий двоичный объект даже не проверяется на совместиость с ядром. Блоку DT, который генерируется в настоящее время, недостаёт весьма полезной карты резервирования (предполагается исправить ситуацию, путём генерации пустой карты, которая будет передаваться загрузчику для заполения её) и некоторых других возможностей. Необходимо драбатывать систему обработки ошибок, сейчас ошибки просто скрываются, и т.д...

По сути, dtc берёт дерево устройств в одном формате и выводит это же дерево устройств в другом формате. В настоящее время поддреживаются следующие форматы:

Форматы на входе:

  • - "dtb": это обысный "blob", который содержит заголовок, же, как у других blob-объектов.

  • - "dts": "исходный" формат. Это обычный текстовый файл, который содержит исходный текст дерева устройств. Этот формат определяется ниже в этой главе.

  • - "fs" формат. Это представление эквивалентно выводу файла /proc/device-tree, чьи узлы являуься каталогами, а свойства - файлами.

Выходные форматы:

  • - "dtb": "blob" формат

  • - "dts": "source" исходный формат

  • - "asm": файл на языке ассемблераe. Этот файл может являться исходным для ассемблера "gas", создающего из него "blob" дерево устройств. Кроме того, ассемблерный файл экспортирует некоторые символы, которые могут быть полезны в дальнейшем.

Утилита dtc имеет следующий синтаксис командной строки:

    dtc [-I <input-format>] [-O <output-format>]
        [-o output-filename] [-V output_version] input_filename

Параметр "output_version" определяет, какая ферсия "blob" формата генерироваться. Поддерживаются версии 1,2,3 и 16. Версией по умолчанию, в настоящее время, является 3, но в будущем она может быть заменена на 16.

Кроме того, dtc выполняет различные разумные проверки дерева, вроде уникальности свойств linux и phandle, правильности строк и т.д...

Формат .dts "исходного" файла подобен "С" и поддерживает стили комментариев как С, так и С++.

/ {
}

Выше приведено определение "device-tree". В настоящее время, это единственный оператор, поддерживаемый на верхнем уровне.

/ {
  property1 = "string_value";	/* Определяет свойство, содержащее нуль-терминированную строку */

  property2 = <0x1234abcd>;	/* Определяет свойство, содержащее числовое, 32-битное значение (16-ричное) */

  property3 = <0x12345678 0x12345678 0xdeadbeef>;
                                /* Определяет свойство, содержащее 3
                                 * числовых 32-битных значения (клетки)  
                                 *  ричном формате */
                                 
  property4 = [0x0a 0x0b 0x0c 0x0d 0xde 0xea 0xad 0xbe 0xef];
                                /* Определяет свойство, которое содержит 
                                 * произвольный массив байт
                                 */

  childnode@address {	/* Определяет дочерний узел "childnode"
                                 * имя устройства которого - "childnode@address"
                                 */

    childprop = "hello\n";      /* Определяет свойство "childprop" узла
                                 * "childnode" (в данном случае - строковое)
                                 */
  };
};

Узлы могут содержать другие узлы и т.д... Таким образом задаётся иерархическая структура дерева.

В строках разрешается искользовать обычные Esc-последовательности языка C: "\n", "\t", "\r", "\( значение)", "\x( значение)".

Так же предполагается, что Вы пропустите Ваш исходный файл cpp/gcc препроцессор, так что Вы сможете использовать #include, #define констант и т.д...

Ну и наконец, планируются различные опции, которые пока не реализованы, подобно автоматической генерации phandles, меток (экспортируемых в asm файл, благодря чему Вы можете указать на содержимое свойства и легко его изменить, независмо от способа доступа к дереву), метки и пути вместо числовых значений некоторых клеток, укзывющих на узел (замещаемых на phandle во время компиляции), экспор карты резервирования в asm файл, возможность определять карту резервирования во время компиляции и т.д...

Мы можем представить include файл .h содержащий общие определения, что доказывает полезность некоторых свойств (подобных построению свойств PC в отношении карты прерываний), хотя возможно, ещё лучше, добавить описание этих структур непосредственно в компилятор...

Рекомендации по загрузчику

Здесь содержатся различные идеи и рекомендации, которые были предложены, в то время, пока всё это разарабатывалось и реализовывалось.

  • - Загрузчик может пожелать использовать дерево устройств самостоятельно и иметь возможность манипулировать им (добавляя/редактируя некоторые свойства, вроде размера доступной памяти, или аргуметов командной строки ядра). В этом случае, возможно два варианта. Либо загрузчик работает непосредственно с плоским деревом, или же он имеет своё собственное внутреннее представление дерева с указателями (подобными аналогичными для ядра) и тогда он должен выполнить перезагрузку DTB перед загрузкой ядра. Первый вариант немного более сложен при редактировании/модификации, зато второй требует возможно более сложного кода для управления структурой дерева. Заметим, что формат структур проектировался таким образом, что бы облегчить "вставку" узла или свойства или удаление их просто путём пересвлки памяти. Они не содержат внутренних смещений или указателей для этих целей.

  • - Пример кода, содержащего итерации по узлам & выборку свойств непосредственно из дерева в плоском формате, можно найти в исходах ядра drivers/of/fdt.c. Посмотрите на функцию of_scan_flat_dt(), она используется в early_init_devtree(), и соответсвует набору early_init_dt_scan_*() функций обратного вызова. Этот код можно повторно использовать в GPL загрузчиках и, так же как автор этого кода, я буду рад обсудить возможные свободные лицензии любым поставщикам, которые пожелают интьегрировать всё, или часть этого кода в свои не-GPL загрузчики. (Необходима ссылка - кто есть "Я" - в данном случае - gcl Jan 31, 2011)

System-on-a-chip и узлы

В настоящее время многие компании начинают разработку процессоров "system-on-a-chip" (SoC), в которых процессор ядра (ЦП) и множество перефирийных устройств сосуществуют на одной пластине кремния. Для таких систем должен использоваться узел SOC, в котором будут определяться дочерние узлы устройств, составляющих SoC. В то время как платформа не тербует использовать эту модель при загрузке ядра, настоятельно рекомендуется, что бы все SoC реализации определяли законченное плоское дерево устройств, предоставляя возможность описывать устройства на SoC. Это позволит обобщить большое количество кода ядра.

Определение дочерних узлов SOC

Любое устройство, являющееся частью SoC, может иметь свой собственный узел внутри узла SOC. Для каждого устройства, которое включено в SOC, свойство адреса устройства представляет смещение адреса для регистров этого устройства, которые мапируются на память, в адресном пространстве родителя. Это адресное пространство родителя определяется свойством "ranges" на верхнем уровне soc узла. Свойство "reg" всех узлов, которые существуют непосредственно под узлом SOC, должно содержать адрес мапирования из дочернего адресного пространства на родительское адресное пространство SoC и размер файла мапируемых регистров этого устро

Для многих устройств, которые могут существовать внутри SoC, имеются заранее определённые спецификации в формате узла дерева устройств. Все дочерние SoC узлы должны следовать этим спецификациям, исключения из этого правила отмечены в этом документе.

Смотри приложение A в качестве примера частичного определения SOC узла для MPC8540.

Представление устройств, у которых нет OF спецификацииn

В настоящее время есть много устройств, которые не имеют стандартного представления, определённого как часть Open Firmware спецификации, главным образом потому, что платы, на которых используются эти SoC устройства, загружаются без использования Open Firmware. Документация по установке для новых устройств должна добавляться в папку Documentation/devicetree/bindings. Эта папка будет расширятся по мере того, как поддержка дерева устройств будет добавляться к всё большему числу SoC устройств.

Определение информации о прерываниях для SoC устройств

Дерево устройств представляет шины и устройства аппаратной системы форме, подобной физической топологии аппаратуры.

Кроме того, существует логическое "дерево прерываний", которое представляет иерархию и прохождение прерываний в аппаратуре.

Модель дерева перываний полностью описана в документе "Open Firmware Recommended Practice: Interrupt Mapping Version 0.9". Этот документ доступен по адресу: Модель дерева прерываний.

Свойства перываний

Устройства, которые генерируют прерывания в одном контроллере прерываний, должны использовать традиционное OF представление, описанное в OF документации по мапированию прерываний.

Каждое устройство, которое генрирует преывания, должно иметь свойство 'interrupt'. Значением этого свойства является произвольное число 'interrupt specifier' значений, которые описывают прерывание или прерывания для данного устройства.

Способ кодирования спецификации прерывания зависит от области прерываний, в которой находится устройство в дереве прерываний. Корень области прерываний описывается значением #interrupt-cells требующем ячеку для хранения 32-битного числа, кодирующего спецификатор прерывания. Смотрите документацию по OF мапированию прерываний для детального ознакомления с этой областью.

Например, установки для контроллера прерываний OpenPIC задаются значением 2 для переменной #interrupt-cells, что означает выделение двух ячеек для кодирования номера прерывания и информации об уровне и смысле этого прерывания. Все дочерние прерывания в области прерываний OpenPIC используют 2 ячейки на прерывание, в их свойствах прерываний.

Установки для шины PCI задают значение #interrupt-cell 1 для кодирования того, ккая именно ножка (INTA,INTB,INTC,INTD) используется.

Свойство interrupt-parent

Свойство interrupt-parent задаётся для установления явной связи между узлом устройства и его родительским прерыванием в дереве прерываний. Значением interrupt-parent является phandle, указывающий на родительский узел.

Если свойство interrupt-parent не опредлено в узле, то его родительское прерывание наследуется через иерархию узло в дереве устройств.

Контроллер прерываний OpenPIC

Контроллер прерываний OpenPIC требует 2 ячейки для кодирования информации о прерывании. Первая ячейка задаёт номер прерывания. Вторая ячейка описывает тип чувствительности и уровень прерывания.

Информация о типе чувствительности и уровне прерывания должна кодироваться следующим образом:

  • 0 = тип чувствительности - переход с низкого уровня на высокий

  • 1 = тип чувствительности - низкий уровень

  • 2 = тип чувствительности - высокий уровень

  • 3 = тип чувствительности - переход с высокого уровня на низкий

Контроллер прерываний ISA

ISA PIC interrupt controllers require 2 cells to encode interrupt information. The first cell defines the interrupt number. The second cell defines the sense and level information.

Контроллер прерываний ISA PIC поддерживать коды ISA PIC перечисленные ниже:

  • 0 = тип чувствительности - низкий уровень

  • 1 = тип чувствительности - высокий уровень

  • 2 = тип чувствительности - переход с высокого уровня на низкий

  • 3 = тип чувствительности - переход с низкого уровня на высокий

Задание информации об экономичных режимах питания (сойство sleep)

SoC устройства зачастую имеют механизмы для переключения их в состояние низкого энергопотребления, которое является ответвлением от основного блока описания регистров этого устройства. Иногда эта информация является слишком сложной для того, что бы свойство cell-index могло её правильно описать. Поэтому, каждое устройство, управляемое таким образом, может содержать свойство sleep, которое описывает эти связи.

Свойство sleep состоит из одного, или нескольких ресурсов sleep, каждый из которых содержит указатель phandle на sleep-контроллер, за которым следует, зависящая от контроллера спецификация из нуля или нескольких ячеек.

Семантика типов энергосбережения, возможно, определяется sleep-контроллером. Некотрые примеры различных типов режимов энергосбережения, которые могут поддерживаться:

  • - Dynamic: Устройство может быть включено или выключено в любое время.

  • - System Suspend: Устройство может запросить выключение, или оставаться во включенном состоянии во время приостановки системы, не будет запрещено.

  • - Permanent: Устройство отключается навсегда (до следующего жёсткого рестарта).

Некоторые устройства могут разделять область часов с какими либо другими устройствами, так что они должны быть приостановлены только если ни одно из этих устройств не используется. В этом заключается причина, по которой узлы должны быть помещены виртуальную шину, которая имеет свойство "sleep". Если область часов разделяется несколькими устройствами, которые не могут быть разумным образом сгруппированы таким образом, то необходимо создать виртуальный sleep-контроллер (подобный прерыванию nexus, за исключением того, что определение стандартной sleep-карты должно подождать до тех пор, пока не будет показана необходимость в этом).

A. Приложение - Простой узел SOC MPC8540

	soc@e0000000 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "fsl,mpc8540-ccsr", "simple-bus";
		device_type = "soc";
		ranges = <0x00000000 0xe0000000 0x00100000>
		bus-frequency = <0>;
		interrupt-parent = <&pic>;

		ethernet@24000 {
			#address-cells = <1>;
			#size-cells = <1>;
			device_type = "network";
			model = "TSEC";
			compatible = "gianfar", "simple-bus";
			reg = <0x24000 0x1000>;
			local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x00 ];
			interrupts = <0x29 2 0x30 2 0x34 2>;
			phy-handle = <&phy0>;
			sleep = <&pmc 0x00000080>;
			ranges;

			mdio@24520 {
				reg = <0x24520 0x20>;
				compatible = "fsl,gianfar-mdio";

				phy0: ethernet-phy@0 {
					interrupts = <5 1>;
					reg = <0>;
					device_type = "ethernet-phy";
				};

				phy1: ethernet-phy@1 {
					interrupts = <5 1>;
					reg = <1>;
					device_type = "ethernet-phy";
				};

				phy3: ethernet-phy@3 {
					interrupts = <7 1>;
					reg = <3>;
					device_type = "ethernet-phy";
				};
			};
		};

		ethernet@25000 {
			device_type = "network";
			model = "TSEC";
			compatible = "gianfar";
			reg = <0x25000 0x1000>;
			local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x01 ];
			interrupts = <0x13 2 0x14 2 0x18 2>;
			phy-handle = <&phy1>;
			sleep = <&pmc 0x00000040>;
		};

		ethernet@26000 {
			device_type = "network";
			model = "FEC";
			compatible = "gianfar";
			reg = <0x26000 0x1000>;
			local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x02 ];
			interrupts = <0x41 2>;
			phy-handle = <&phy3>;
			sleep = <&pmc 0x00000020>;
		};

		serial@4500 {
			#address-cells = <1>;
			#size-cells = <1>;
			compatible = "fsl,mpc8540-duart", "simple-bus";
			sleep = <&pmc 0x00000002>;
			ranges;

			serial@4500 {
				device_type = "serial";
				compatible = "ns16550";
				reg = <0x4500 0x100>;
				clock-frequency = <0>;
				interrupts = <0x42 2>;
			};

			serial@4600 {
				device_type = "serial";
				compatible = "ns16550";
				reg = <0x4600 0x100>;
				clock-frequency = <0>;
				interrupts = <0x42 2>;
			};
		};

		pic: pic@40000 {
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			reg = <0x40000 0x40000>;
			compatible = "chrp,open-pic";
			device_type = "open-pic";
		};

		i2c@3000 {
			interrupts = <0x43 2>;
			reg = <0x3000 0x100>;
			compatible  = "fsl-i2c";
			dfsrr;
			sleep = <&pmc 0x00000004>;
		};

		pmc: power@e0070 {
			compatible = "fsl,mpc8540-pmc", "fsl,mpc8548-pmc";
			reg = <0xe0070 0x20>;
		};
	};