OpenWrt - запись в EV-iMX287-NANO

В последнее время часто возникают вопросы о сборке OpenWrt для плат семейства EV-iMX287-NANO/EV-iMX280-NANO/EV-iMX287-SODIMM. Большей частью вопросы не о самом процессе сборки, а о том как записать полученные файлы в плату. Предложенный ниже метод не является самым оптимальным, но он весьма прост. Итак, устанавливаем OpenWRT:

Загружаем и устанавливаем необходимые пакеты:

 

 

 

  • sudo apt-get update;
  • sudo apt-get -y install git openssl unzip;
  • sudo apt-get -y install binutils flex bison autoconf gettext texinfo;
  • sudo apt-get -y install sharutils subversion libncurses5-dev ncurses-term zlib1g-dev gawk;
  • sudo apt-get -y install build-essential;
  • sudo apt-get -y install libssl-dev;
  • git clone git://git.openwrt.org/15.05/openwrt.git;

 

переходим в каталог openwrt (здесь и далее - команды всегда запускаем в /openwrt !!!)

 

  • cd openwrt

 

выполняем следующие команды:

 

  • openwrt$ ./scripts/feeds update –a
  • openwrt$ ./scripts/feeds install -a

 

запустим меню конфиг и выберем тип процессора. В openwrt есть единственная плата на процессоре mx28, которая называется duckbill. Именно на базе нее мы и попытаемся запуститься...

 

  • openwrt$ make menuconfig

 

сохраняем изменения и выходим. Выполняем следующие команды:

 

  • openwrt$ make defconfig
  • openwrt$ make prereq
  • openwrt$ make kernel_menuconfig (это менюконфиг ядра)
  • openwrt$ make V=s

 

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

 

  • openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs/boot/uImage - собранное ядро
  • openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs/boot/zImage - собранное ядро в elf формате
  • openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs/boot/imx28-duckbill.dtb файл описания железа

 

Помимо это в папке openwrt/bin/mxs можно найти следующие файлы:

 

  • openwrt-mxs-duckbill-rootfs.tar.gz2 - запакованная файловая система
  • openwrt-mxs-duckbill-sdcard-vfat-ext4.img - имидж для записи SD карты памяти. Для нас он не имеет смысла, поскольку наша задача записать фалы в микросхему NAND Flash
  • openwrt-mxs-uImage - собранное ядро (тоже самое что и uImage выше, но с другим названием)
  • u-boot-mxs-duckbill.sb - загрузчик u-boot

 

Сразу скажу, что собранный u-boot у меня не заработал, как я предполагаю по причине отсутствия в его конфиге поддержки NAND Flash. Я взял свой старый u-boot 2014 для платы EV-iMX287-NANO, записал его с помощью MFGTool в модуль и стал размышлять как и куда записать остальные файлы. Здесь возникла небольшая проблема, дело в том, что MFGTool (точнее его ядро которое пишет NAND Flash) делает следующее (если заглянуть в ucl файл):

 

  • <CMD type="push" body="$ flash_eraseall /dev/mtd0">Erasing rootfs partition</CMD>
  • <CMD type="push" body="$ flash_eraseall /dev/mtd1">Erasing rootfs partition</CMD>

 

Форматирует две партиции (mtd0 и mtd1). В mtd0 пишет загрузочный *.sb файл (u-boot.sb или kernel.sb), а в mtd1 пишет файловую систему ubi. Нам же этих партиций надо больше, а именно -

 

  • Для загрузочного u-boot.sb
  • Для переменных u-boot
  • Для ядра uImage
  • Для dtb
  • Для файловой системы

 

Это можно легко организовать, если пересобрать ядро, которое используется для MFGTool. Но, очень не хотелось искать это ядро, менять его и т.д. Поэтому, все что нам необходимо мы проделаем прямо в u-boot, который уже записали в NAND Flash.

Итак, включаем питание, стартует u-boot, останавливаем его нажатием любой кнопки и выполняем:

setenv mtdparts mtdparts=gpmi-nand:3m(bootloader)ro,512k(environment),512k(redundant-environment),4m(kernel),512k(fdt),8m(ramdisk),-(rootfs)

Обьявим 7 партиций:

  • bootloader - здесь у нас будет находиться u-boot.sb. Или точнее он уже тут находится, плата же запустилась)
  • environment - здесь у нас будут лежать переменные окружения
  • redundant-environment
  • kernel- сюда запишем uImage
  • fdt - место для хранения dtb файла
  • ramdisk - так, на всякий случай
  • rootfs - файловая система
Наш u-boot имеет команды для записи в NAND Flash - nand write. Но чтобы записать файловую систему в ubi формате нужен ubi образ, а его, как показал беглый осмотр openwrt он генерить не может или не хочет. Поэтому создадим его сами.
Напомню, что развернутая файловая система openwrt лежит в openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs/
Вот ее мы и превратим в ubi образ. Для этого, в папке /openwrt с помощью любого текстового редактора (vi, например) создадим конфигурационный файл ubinize.cfg со следующим содержимым:
[rootfs]
mode=ubi
image=ubifs.img
vol_id=1
vol_size=80MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
а рядом создадим скрипт make_ubi.sh

mkfs.ubifs -r /home/user/Projects/EV-iMX6UL/openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs -m 2048 -e 126976 -c 1900 -o ubifs.img;
ubinize -o ubi.img -m 2048 -p 128KiB -s 2048 ubinize.cfg;

Обратите внимание на первую строку, у вас путь к файловой системе будет другой!!! Зайдите в openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/root-mxs/
и выполните команду pwd для того чтобы точно узнать путь, и скопируйте его в скрипт.
Сохраняем наш скрипт и делаем его исполняемым chmod +x make_ubi.sh
Запускаем его на исполнение (./make_ubi.sh) и получаем файл ubi.img. Это и есть файловая система созданная openwrt в ubi формате, которую мы можем записать. Теперь нам понадобится любая SD карточка (или USB Flash Drive). На нее скопируем следующие файлы:
uImage (собранное ядро), imx28-duckbill.dtb (файл описания железа) и созданный нами ubi.img. Вставляем карточку в держатель платы, подаем питание,
останавливаем выполнение u-boot и выполняем:
u-boot>setenv mtdparts mtdparts=gpmi-nand:3m(bootloader)ro,512k(environment),512k(redundant-environment),4m(kernel),512k(fdt),8m(ramdisk),-(rootfs)создание партиций, если вы уже это делали, то пропускаем.

u-boot>nand erase.part rootfs; стирание партиции файловой системы
u-boot>nand erase.part kernel; стирание партиции ядра Линукс (uImage)
u-boot>nand erase.part fdt; стирание партиции описания железа (dtb)
u-boot>fatload mmc 0 $loadaddr uimage; считываем ядро с SD карты
u-boot>nand write $loadaddr kernel $filesize; пишем его в партицию kernel
u-boot>fatload mmc 0 $loadaddr imx28-duckbill.dtb; считываем с SD карты dtb файл
u-boot>nand write $loadaddr fdt $filesize; пишем его
u-boot>fatload mmc 0 $loadaddr ubi.img; считываем образ файловой системы
u-boot>nand write.trimffs $loadaddr rootfs $filesize; пишем его (обратите внимание на trimffs!)
Создадим переменную окружения, чтобы ядро знало, где лежит наша файловая система:
u-boot>setenv bootargs 'console=ttyAMA0,115200 ubi.mtd=6 root=ubi0:rootfs rootfstype=ubifs rw gpmi'
ubi.mtd=6 (Шестая партиция! Считать начинаем от 0!)
root=ubi0:rootfs (rootfs - имя нашей партиции! Если вы назвали ее по другому, то и здесь надо изменить название!)
командой saveenv сохраняем переменную окружения.
теперь создадим командную строку загрузки:
u-boot>setenv bootcmd 'nand read 0x42000000 kernel 0x18a4e8;nand read 0x41000000 fdt 0x586d; bootm 0x42000000 - 0x41000000'
считываем из партиции kernel ядро (у меня его размер 0x18a4e8 ) и dtb файл (у меня его размер 0x586d ) и стартуем командой bootm.
Если вы последовательно выполняли все что здесь описано, то в консоле увидите лог загрузки ядра и в конце Kernel Panic...Kernel Panic возник от того,
что плата duckbill ничего не знает о NAND Flash, не имеет драйверов NAND Flash и ничего не знает
о созданных нами партициях. Беглый взгляд на imx28-duckbill.dts (а исходники ядра лежат в
openwrt/build_dir/target-arm_arm926ej-s_uClibc-0.9.33.2_eabi/linux-mxs/linux-3.18.44/arch/arm/boot/dts) показал, что в нем
описаны только SD карточка, I2C интерфейс, USB интерфейс. Чтобы его не править, он был благополучно переименован

mv imx28-duckbill.dts imx28-duckbill-orig.dts
а вместо него взять файл imx28-evk-dts. Который переименовали в
mv imx28-evk.dts imx28-duckbill.dts

В этот новый файл добавим описание партиций, созданных нами в u-boot
apb@80000000 {
apbh@80000000 {
gpmi-nand@8000c000 {
pinctrl-names = "default";
pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg
&gpmi_pins_evk>;
status = "okay";
partition@0 {
label = "bootloader";
reg = <0x0 0x300000>;
};
partition@300000 {
label = "environment";
reg = <0x300000 0x80000>;
};
partition@380000 {
label = "redundant-environment";
reg = <0x380000 0x80000>;
};
partition@400000 {
label = "kernel";
reg = <0x400000 0x400000>;
};
partition@800000 {
label = "fdt";
reg = <0x800000 0x80000>;
};
partition@880000 {
label = "ramdisk";
reg = <0x880000 0x800000>;
};
partition@d00000 {
label = "rootfs";
reg = <0x1080000 0xef80000>;
};
};

ssp0: ssp@80010000 {
Сохраним измененный файл и запустим menuconfig (находясь в папке openwrt выполним)
make kernel_menuconfig
Включим поддержку NAND Flash и UBI в Device Driver
и в Filesystem
Запустим заново сборку openwrt (make V=s в папке openwrt)
С помощью нашего скрипта опять создадим образ ubi файловой системы и запишем все файлы на SD карту. Перезапустим u-boot и заново запишем. Вот только мне не нравится каждый раз смотреть на количество считанных байт и переводить его в хекс. Поэтому строим следующую конструкцию:
Стираем партиции:
u-boot>nand erase.part rootfs; стирание партиции файловой системы.
u-boot>nand erase.part fdt; стирание партиции описания железа (dtb).
u-boot>nand erase.part kernel; стирание партиции ядра Линукс (uImage).

u-boot>fatload mmc 0 $loadaddr uimage; считываем ядро с SD карты. В переменной $filesize у нас сейчас хранится число считанных байт. Им и воспользуемся.
u-boot>setenv nand_read_kernel nand read 0x42000000 kernel $filesize; создадим команду чтения ядра в переменных окружения
u-boot>saveenv
u-boot>nand write $loadaddr kernel $filesize; пишем ядро в партицию kernel

тоже самое с dtb файлом
u-boot>fatload mmc 0 $loadaddr imx28-duckbill.dtb; считываем с SD карты dtb файл
u-boot>setenv nand_read_dtb nand read 0x41000000 fdt $filesize; создадим команду чтения dtb в переменных окружения
u-boot>saveenv
u-boot>nand write $loadaddr fdt $filesize; запишем dtb файл в NAND Flash
теперь файловая система
u-boot>fatload mmc 0 $loadaddr ubi.img; считываем образ файловой системы
u-boot>nand write.trimffs $loadaddr rootfs $filesize; пишем его (обратите внимание на trimffs!)

Теперь изменим командную строку:
u-boot>setenv bootcmd '$nand_read_kernel;$nand_read_dtb; bootm 0x42000000 - 0x41000000'
saveenv;

Перегружаем плату и смотрим в консоль...