Статус U-Boot
- текущая миграция из файла заголовка платы определяется параметрами Kconfig
- постоянная миграция с manual драйверов (выполняется вручную) относительно модели драйвера
Каталоги U-Boot
- arch/
– Все, что связано с архитектурой или платформой: DTS, CPU init, pinmux контроллер, DRAM, тактирование, …
- board/
– Спецификация для платы (init, настройка pinmuxing и т. д.), настройка файла Kconfig
заголовочные файлы платы (*.h), файлы платы, пути, Makefile для плат
- configs/
– Все файлы defconfigs
- drivers/
- include/
– Все заголовочные файлы
- include/configs/
– Все заголовочные файлы плат
…
Рабочий процесс подкрепления (добавления) новой платы в U-Boot
1. создайте файл платы
2. создайте Kconfig файл платы
3. создайте Makefile файл платы
4. создайте defconfig файл платы
5. создайте заголовочный файл платы
6. исходники платы для Вашего Kconfig в разрядности архитектуры для Kconfig
7. определите TARGET Kconfig в Kconfig своего процессора для платформы (например, sunxi (Allwinner) обмениваться общими файлами, как только defconfig сформирует запрос на необходимый файл)
Создайте файл платы
board/my_vendor/my_board/my_board.c
#include < ...> DECLARE_GLOBAL_DATA_PTR; int dram_init(void) { gd->ram_size = imx_ddr_size(); return 0; } int board_init(void) { return 0; }
Глобальные данные
- DECLARE_GLOBAL_DATA_PTR
- использование в коде с глобальной переменной gd
- на ARM архитектуре, равно аппаратному регистру r9 для ARM32 и x18 для ARM64,
- используется для хранения информации в «некоторой области памяти, которая доступна очень рано (внутренняя память), сразу после загрузки. Разрешен минимальный набор глобальных переменных во время инициализации системы (пока мы настраиваем контроллер памяти, для использования внешнего ОЗУ)
- include/asm-generic/global_data.h необходим для поиска информации на хранение
Создайте для платы файл Kconfig
board/my_vendor/my_board/Kconfig
if TARGET_MY_BOARD config SYS_BOARD default "my_board" config SYS_VENDOR default "my_vendor" config SYS_CONFIG_NAME default "my_board" endif
Параметры Kconfig
- SYS_VENDOR и SYS_BOARD используются для идентификации каталога, в котором make ищет файлы необходимые для компиляции
- если оба присутствуют
- board/SYS_VENDOR/SYS_BOARD/
- если SYS_VENDOR опущен
- board/SYS_BOARD/
- если SYS_BOARD опущен
- board/SYS_VENDOR/common/
- SYS_CONFIG_NAME используется для идентификации файла заголовка платы
- include/configs/SYS_CONFIG_NAME.h
- если оба присутствуют
Создание Makefile платы
board/my_vendor/my_board/Makefile
obj-y := my_board.o
obj-y := my_board.o
Создание defconfig платы
configs/my_board_defconfig
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MY_BOARD=y
CONFIG_MXC_UART=y
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MY_BOARD=y
CONFIG_MXC_UART=y
- поместите здесь все, что является выбираемым элементом для Kconfig (menuconfig)
- драйверы, функции, поведение U-Boot, libs, и т.д
Создайте заголовочный файл платы (минимальный пример для i.MX6 Solo)
include/configs/my_board.h
#ifndef __MY_BOARD_CONFIG_H__ #define __MY_BOARD_CONFIG_H__ #define CONFIG_MXC_UART_BASE UART5_BASE #include "mx6_common.h" #define CONFIG_NR_DRAM_BANKS 1 #define CONFIG_SYS_MAX_FLASH_BANKS 1 #define CONFIG_SYS_MALLOC_LEN (10 * SZ_1M) #define CONFIG_SYS_FSL_ESDHC_ADDR 0 #define PHYS_SDRAM MMDC0_ARB_BASE_ADDR #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM #define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR #define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE #define CONFIG_SYS_INIT_SP_OFFSET \ (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) #define CONFIG_SYS_INIT_SP_ADDR \ (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET) #endif
Файл Kconfig исходной платы
arch/arm/Kconfig или
arch/arm/mach-imx/mx6/Kconfig
arch/arm/mach-imx/mx6/Kconfig
…
source “board/imx31_phycore/Kconfig”
source “board/isee/igep003x/Kconfig”
source “board/my_vendor/my_board/Kconfig”
source “board/olimex/mx23_olinuxino/Kconfig”
source “board/phytec/pcm051/Kconfig”
…
source “board/imx31_phycore/Kconfig”
source “board/isee/igep003x/Kconfig”
source “board/my_vendor/my_board/Kconfig”
source “board/olimex/mx23_olinuxino/Kconfig”
source “board/phytec/pcm051/Kconfig”
…
Определите параметр TARGET Kconfig платы
arch/arm/mach-imx/mx6/Kconfig
choice
…
config TARGET_MY_BOARD
bool “My awesome board”
select MX6S
…
endchoice
…
config TARGET_MY_BOARD
bool “My awesome board”
select MX6S
…
endchoice
Последовательная инициализация U-Boot
- в U-Boot работает два списка функций, цель которых заключается в инициализации или настройки конкретных IP блоков до того, как пользователь получит доступ к консоли
- первый список определяется в common/board_f.c в массиве static init_fnc_t init_sequence_f[]
- первый список берет на себя инициализацию памяти DRAM, отображение его и перемещение кода загрузчика, когда тот работает
- второй список определяется в common/board_r.c в массиве static init_fnc_t init_sequence_r[]
- некоторые функции выполняются только тогда, когда константа определена (например, CONFIG_BOARD_EARLY_INIT_F определена чтобы запустить board_early_init_f ())
- любые функции возвращаемые ненулевое значение остановят последовательность инициализации и U-Boot не будет дальше загружаться
- определите DEBUG, когда возникают проблемы с последовательностью инициализации
- не все «особенности» доступны во всех функциях (т.е. нет udelay в board_early_init_f ())
Выбор драйвера
- черпайте вдохновение (анализируйте текущие исходники) из boards с тем же IP
- проверяйте драйверы для соответствующей подсистемы
- сконцентрированное свое внимание на поведение драйвера
- затем проверите регистры, битовые смещения, маски и т.д.
- сделайте проверку для неопределенных макросов или констант
- проверка для участков кода в окружении #ifdef блоков
- ищите объектный файл этого драйвера в Makefile подсистемы
- OBJ – $ (CONFIG_MY_DRIVER) + = my_driver.o
- grep для CONFIG_MY_DRIVER,
- видимый символ в файле Kconfig => добавить для платы (board) defconfig
- невидимый символ в файле Kconfig или символ который не определен =>для файла заголовка платы
- убедитесь, что ваш драйвер скомпилирован (ищите my_driver.o)
Выбор драйвера – пример NAND
- drivers/mtd/nand/nand_mxs.c
- CONFIG_NAND_MXS для компиляции драйвера
- CONFIG_SYS_MAX_NAND_DEVICE и CONFIG_SYS_NAND_BASE константы для конфигурирования устройства
configs/my_board_defconfig
CONFIG_ARM = у
CONFIG_ARCH_MX6 = у
CONFIG_TARGET_MY_BOARD = у
CONFIG_MXC_UART = у
CONFIG_NAND_MXS = у
include/configs/my_board.h
... /* Определить настройки NAND */ /* Максимальное количество поддерживаемых устройств NAND */ #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_BASE 0x00112000 ...
board/my_vendor/my_board.c
... static iomux_v3_cfg_t const nand_pads[] = {...}; ... int board_init(void) { imx_iomux_v3_setup_multiple_pads(nand_pads, ARRAY_SIZE(nand_pads)); return 0; }
Примечание о деревьях устройств (device tree)
- переход на деревья устройств началось еще в 2012 году, код медленно переносится (“мигрирует”), драйвер за драйвером, подсистема за подсистемой
- нужно для модели драйвера использовать дерево устройств
- большинство драйверов имеют большие количество #ifdef блоков для CONFIG_DM (Driver Model – DM)
- вы не можете выбрать на основе каждого драйвера включение поддержки DM
- упомянутое ранее для основного кода подсистем
- полная поддержка дерева устройств и фреймворк NAND не переносятся в DM
Усилия, необходимые для поддержки U-Boot (из опыта)
- Ethernet, EEPROM, NAND, EMMC, считыватель SD карт, USB устройства, GPIO, UART, аудио (I2S), PMIC и т.д.
$ wc -l board/my_vendor/my_board/* configs/my_board_defconfig include/configs/my_board.h
15 board/my_vendor/my_board/Kconfig
8 board/my_vendor/my_board/Makefile
159 board/my_vendor/my_board/my_board.cfg #DCD conf for DDR controller and memory
218 board/my_vendor/my_board/my_board.c
39 configs/my_board_defconfig
110 include/configs/my_board.h
510 total
+ 1 строка в arch/ ARM/ Kconfig
+4 строки в arch/arm/ CPU/ ARMv7/ mx6/ Kconfig
- собственно ~ 100 строк «реального» кода (PHY и платы инициализации, настройки ММС)
- запрещается модификация исходного кода U-Boot
- получил некоторые странные ошибки с Lib RSA при проверке подписей fitImage в U-Boot
- обновление от 2017.03 до 2017.07 было очень легко:
- портретирование платы: заголовочные файлы, файлы платы, Makefile, Kconfig и обновление
- Kconfig архитектуры
- убедитесь, что все параметры определенные в заголовочных файлах платы
Проблемы
- последовательность инициализации платы трудоемкий процесс
- все сигналы (даже UART) проходят через FPGA (в том случае, если у Вас FPGA)
- отсутствии платы последовательность инициализации, нет FPGA, нет UART
- запрещаются udelay в board_early_init_f
- обходной путь заключается в использовании forloop с cpurelax ()
Оригинал статьи на английском языке по ссылке.