Pull to refresh

Linux в устройстве на базе чипа Altera SoC FPGA: восстанавливаем утраченный функционал

Reading time 5 min
Views 21K
Terasic DE0-Nano-SoC

Некоторое время назад ко мне в руки попал набор разработчика DE0-Nano-SoC, построенный на базе чипа Altera Cyclone V. Данный набор используется мной не с какой-то одной целью — с его помощью решаются разные задачи. Для каждой из этих задач создаётся схема для FPGA и пишется программа для HPS. Схема для FPGA создаётся в среде Quartus II и в процессе разработки загружается в FPGA через JTAG-интерфейс посредством USB-бластера. Когда же схема окончательно отлажена, она записывается на SD-карточку в виде файла прошивки. Затем, когда нужно использовать плату с той или иной целью, берётся нужная прошивка, загружается в FPGA командой вида
cat hardware.rbf > /dev/fpga0
и затем запускается нужная программа.

Всё шло своим чередом, но однажды я обновил в плате ядро Linux — о чём рассказывал в этой статье. И вот спустя некоторое время обнаружилось, что из списка драйверов исчез FPGA-менеджер, позволявший загружать прошивку в FPGA подобным способом. Первой мыслью было то, что я забыл включить драйвер в конфигурацию при сборке ядра. Однако, к моему удивлению, скоро обнаружилось, что среди исходников ядра этого драйвера нет в принципе! Конечно, можно было бы грузить прошивку в FPGA другими способами, коих есть ещё как минимум три. Но этот способ был для меня наиболее оперативным и удобным, вот почему было принято решение восстановить утраченный функционал. Если Вам интересно, как это было сделано — добро пожаловать под кат.

Небольшое лирическое отступление


Для решения проблемы прежде всего нужно было найти исходные тексты FPGA-менеджера. Естественно, первым делом были обследованы репозитории Альтеры. И опять же я был удивлён тем, что этого драйвера в них не оказалось. Пришлось искать по всему гитхабу и в результате исходники были найдены в репозиториях Терасика. И тут опять образовались грабли: Терасик давно не публиковал ничего на гитхабе и самое свежее ядро было версии 3.12. Как следствие, взятые из этого репозитория исходники FPGA-менеджера отказывались компилироваться под новые ядра из-за того, что в них использовались некоторые «устаревшие» структуры, попросту ликвидированные из новых версий. Переделывать драйвер под новые реалии что-то меня никак не тянуло. Поэтому поиск был продолжен и в конце концов увенчался таки успехом — нашлись адаптированные исходники драйвера в репозитории некоего мистера из Канады с ником xaxaxa. За что ему низкий поклон.

Итак приступим


Подробности сборки ядра можно посмотреть в моей предыдущей статье — далее, чтобы не повторяться, я буду ссылаться на неё время от времени. Всё дальнейшее повествование будет построено на предположении, что весь процесс сборки ядра, описанный в той статье, уже выполнен и все исходники ядра лежат на прежнем месте в целости и сохранности.

1. Запускаем терминалку и входим в root-режим — чтобы не набирать каждый раз команду sudo:
sudo -i

При этом /root будет нашей домашней директорией — всё будем делать в ней.

2. Скачиваем исходники драйвера FPGA-менеджера отсюда и кладём в директорию /root/linux-socfpga-4.1/drivers/fpga/

Также забираем отсюда хидер fpga.h и записываем его в директорию /root/linux-socfpga-4.1/include/linux/

3. Редактируем файл /root/linux-socfpga-4.1/drivers/Kconfig — добавляем в него одну строку:
source "drivers/fpga/Kconfig"

Куда конкретно её добавить — особого значения не имеет. Главное, чтобы она была не самой первой и не самой последней строкой файла. Я добавил её сразу после первой строки. Получилось вот так:
menu "Device Drivers"
source "drivers/fpga/Kconfig"
source "drivers/amba/Kconfig"
...

4. Редактируем файл /root/linux-socfpga-4.1/drivers/Makefile — добавляем в него одну строку:
obj-$(CONFIG_FPGA) += fpga/

Куда конкретно её добавить — опять же значения не имеет. Я добавил её сразу после начальных комментариев. Получилось вот так:
#
# Makefile for the Linux kernel device drivers.
#
# 15 Sep 2000, Christoph Hellwig <hch@infradead.org>
# Rewritten to use lists instead of if-statements.
#
obj-$(CONFIG_FPGA) += fpga/
obj-y += irqchip/
...

5. Запускаем альтеровский скрипт, который запустит новый BASH и подправит в нём некоторые переменные окружения (например, PATH). Все действия по компиляции будем проводить не выходя из этого BASH:
cd /root/altera/15.0/embedded
./embedded_command_shell.sh

6. Создаём несколько переменных окружения:
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export LOADADDR=0x8000

7. Переходим в директорию с исходниками ядра и добавляем драйвер FPGA-менеджера в конфигурацию ядра:
cd /root/linux-socfpga-4.1
make menuconfig

При этом откроется псевдографическое окно с менюшками. Заходим в подменю Device Drivers. Здесь увидим, что на первом месте появилось новое подменю FPGA devices — заходим в него. Внутри будет драйвер FPGA Framework — добавляем его в ядро: нажимаем на нём пробел дважды — при этом напротив него появится символ звёздочки, говорящий о том, что данный драйвер будет встроен в ядро. Сразу после выполнения этих действий в списке появится ещё один драйвер Altera — включаем и его тоже: нажимаем на нём дважды пробел:



Так как мы сейчас не выполняли сброс конфигурации в исходное состояние командой make socfpga_defconfig, то остальные настройки должны остаться в прежнем состоянии — как мы их установили в процессе сборки ядра.

Выходим из меню — нажимаем Exit пока не выйдем. На вопрос — надо ли сохранять конфигурацию — отвечаем Yes.

8. Компилируем ядро:
make uImage

Так как ядро компилировалось нами ранее, то теперь на его пересборку с новыми драйверами уйдёт совсем мало времени.

9. Добавляем в дерево устройств информацию о FPGA-менеджере.
Для этого добавляем в файл /root/linux-socfpga-4.1/arch/arm/boot/dts/socfpga.dtsi следующие строки:
  fpgamgr: fpgamgr@0xff706000 {
    compatible = "altr,fpga-mgr-1.0", "altr,fpga-mgr";
    transport = "mmio";
    reg = <0xFF706000 0x1000 0xFFB90000 0x1000>;
    interrupts = <0 175 4>;
  };

Эти строки можно добавить в блок soc.
Например, вот сюда.
...
      qspi_clk: qspi_clk {
        #clock-cells = <0>;
        compatible = "altr,socfpga-gate-clk";
        clocks = <&f2s_periph_ref_clk>, <&main_qspi_clk>, <&per_qspi_clk>;
        clk-gate = <0xa0 11>;
      };
    };
  };

  fpgamgr: fpgamgr@0xff706000 {
    compatible = "altr,fpga-mgr-1.0", "altr,fpga-mgr";
    transport = "mmio";
    reg = <0xFF706000 0x1000 0xFFB90000 0x1000>;
    interrupts = <0 175 4>;
  };

  gmac0: ethernet@ff700000 {
    compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
    altr,sysmgr-syscon = <&sysmgr 0x60 0>;
    reg = <0xff700000 0x2000>;
    interrupts = <0 115 4>;
...


10. Конвертируем файл дерева устройств в бинарный формат:
make socfpga_cyclone5_sockit.dtb

11. Копируем ядро и .dtb-файл на карточку в раздел FAT32. Повторяться не буду: о том, как это сделать, подробно описано в подразделе 13 раздела Сборка ядра этой статьи.

На этом всё — процесс сборки ядра в комплекте с драйвером FPGA-менеджера завершён.

Проверка работоспособности


Поставим SD-карточку в плату, загрузимся и проверим работоспособность.
Для этого сначала посмотрим содержимое директории /dev — в ней должен появиться файл драйвера fpga0:



Ну и в завершение загрузим какую-нибудь прошивку в FPGA:



Вуаля! Всё работает как положено.

Всем спасибо за внимание!
Tags:
Hubs:
+16
Comments 11
Comments Comments 11

Articles