zynq (Zed board)でubuntuを動かす

ADV7511リファレンスデザインをインプリメントしたZed boardでUbuntuをSDカードからブートします。
HDMIディスプレイとUSBキーボードが使えます。
また、Ubuntuなのでapt-getがあります。pythonも最初から動きます。便利！

参考：
Avnetのチュートリアル
http://zedboard.org/content/zedboard-ubuntu-vivado-20134

Yet Another Guide to Running Linaro Ubuntu Linux Desktop on Xilinx Zynq on the ZedBoard
http://fpga.org/2013/05/24/yet-another-guide-to-running-linaro-ubuntu-desktop-on-xilinx-zynq-on-the-zedboard/

Embedded Linux Wiki - Parallella Linaro Nano
http://elinux.org/Parallella_Linaro_Nano

Xilinx wiki
http://www.wiki.xilinx.com/Build+kernel

# 前提
## 環境
- xubuntu 14.04
- Vivado 2015.2
- Zed board rev.D

## その他
基本的に上記のAvnetチュートリアルをやっていきます。ただし内容が古い部分が多く、そのままではできなかったので、そこを補足しながらやっていく感じです。
ハードウェアはADV7511リファレンスデザインを前提にしています。
（こちら：https://wiki.analog.com/resources/fpga/xilinx/kc705/adv7511）
（記事も書きました：http://qiita.com/yuichiroTCY/items/aa621b1b432f7ceaf909）
そのため、Linuxカーネルなどもこのリファレンスデザイン用に用意されたものを使います。カスタマイズはまた別の話で。

# 作業ディレクトリ
作業用に適当なディレクトリを用意します。
以下のパスはすべてそのディレクトリからの相対パスとして記述します。

# U-bootのビルド
second stage boot loaderであるu-bootをビルドします。

## ダウンロード
```bash
$ git clone git@github.com:Xilinx/u-boot-xlnx.git
$ cd u-boot-xlnx
$ git checkout xilinx-v2015.2
```

## ブートオプション編集
`include/configs/zynq-common.h`の内容が基本的な設定です。これが`zynq_zed.h`にインクルードされ、さらにその中でオーバーライドされます。
`zynq_zed.h`を編集してさらに必要な設定をオーバーライドします。
今回、ext4パーティション上にRoot file systemを用意してLinuxを立ち上げるので、そのための設定のようです。

1. `include/configs/zynq-common.h`から`CONFIG_EXTRA_ENV_SETTINGS`の定義（複数行の長い#define）をコピーして `include/configs/zynq_zed.h`の末尾に貼り付け。
2. `sdboot`でgrepし、当該部分を書き換え

    ```diff
    "sdboot=if mmcinfo; then " \
    			"run uenvboot; " \
    -			"echo Copying Linux from SD to RAM... && " \
    +			"echo Copying Linux from SD to RAM... RFS in ext4 && " \
    			"load mmc 0 ${kernel_load_address} ${kernel_image} && " \
    			"load mmc 0 ${devicetree_load_address} ${devicetree_image} && " \
    -			"load mmc 0 ${ramdisk_load_address} ${ramdisk_image} && " \
    -			"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " \
    +			"bootm ${kernel_load_address} - ${devicetree_load_address}; " \
    ```

3. `#define CONFIG_EXTRA_ENV_SETTINGS`の前に

    ```c
    #ifdef CONFIG_EXTRA_ENV_SETTINGS 
    #undef CONFIG_EXTRA_ENV_SETTINGS 
    #endif
    ```
を追記

4. (Optional) 自分の好みに応じて、同様に`#define CONFIG_SYS_PROMPT`や`#define CONFIG_BOOTDELAY`などをオーバーライドしてもよい

## ビルド

```bash
$ export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
$ make distclean
$ make zynq_zed_config
$ make
```

環境変数`CROSS_COMPILE`を正しく設定しないとビルドできません。`.bashrc`とかに書いてしまっても良いかも
参考：http://www.wiki.xilinx.com/Install+Xilinx+tools

ビルドが完了すると、`u-boot-xlnx`ディレクトリ直下に`u-boot`が生成されます。

また、`tools/mkimage`というファイルもできています。あとで使うので、パスを通しておきます。

```bash
$ export PATH=/path/to/dir/u-boot-xlnx/tools/:${PATH}
```
これも`.bashrc`に書いてしまって良いかも

# SDカードの準備

fdiskやGPartedでFAT32とext4のパーティションを１つずつ作ります。
FAT32の方を`ZED_BOOT`、ext4の方を`rootfs`と名づけました。
サイズは1GBと3GBにしました。多分こんなにいらない。特にFAT32の方。

# FSBLの作成

ADV7511のリファレンスデザインでビットストリームの作成、SDKにエクスポートまでやっておきます。
1. SDKを起動します。
2. メニューからNew->Application Projectを選びます
3. 適当に名前をつけます。今回は`zynq_fsbl_0`にします。Nextを押して次の画面に行きます。
4. Zynq FSBLを選んでFinishを押します。
5. ツリービューで`zynq_fsbl_0`を選択した状態で、メニューからXilinx Tools -> Create Zynq Boot Imageを選びます。
6. Output BIF file pathを適宜設定します。今回はファイル名を`ubuntu.bif`に変えました。
7. ダイアログ下部のBoot image partitionsにはすでにbootloaderとビットストリームが読み込まれているはずです。無ければ、適宜Addします。
8. 上で作ったu-bootを`u-boot.elf`とリネームして適当な場所にコピーしておきます。Boot image partitionsにAddします。Partition typeはdatafileです。
9. 適宜Output pathを設定します。
10. Create Imageを押します。Output pathで指定した場所に`BOOT.bin`ができます。

この段階で、u-bootの起動までを確認してみます。
SDカードの`ZED_BOOT`パーティション（FAT32のパーティション）に上で作成した`BOOT.bin`をコピーします。
次にZed BoardのピンをSDブートモードにし、SDカードを挿し、PCとUSBケーブルでつないで電源を入れます。
PCからシリアルコンソールで見ると、ブートの様子が見えます。
この段階ではまだLinuxのファイルを用意していないので、

```
Copying Linux from SD to RAM...RFS in ext4
reading uImage
** Unable to read file uImage **
```
という出力を吐いてとまり、入力受付状態になります。

この状態で

```
env default –a –f
printenv sdboot
saveenv
```
と打って環境変数を保存するらしいです。Avnetのチュートリアルにそう書いてありました。
もし将来u-bootの設定などを変えてビルドしなおしたとき、この操作をやり直さないと古い設定が残ったままになってしまう（？）

ちなみに、Zed boardのBTN7はPS_RSTボタンなので、押すとブートをやり直せます。

# Linuxカーネルのビルド
```bash
$ git clone git@github.com:analogdevicesinc/linux.git analogdevices_linux
$ cd analogdevices_linux
$ git checkout xcomm_zynq
$ make ARCH=arm distclean
$ make ARCH=arm zynq_xcomm_adv7511_defconfig
$ make ARCH=arm uImage LOADADDR=0x8000
```

ここで上で作った`mkimage`が使われるので、エラーが出る場合はパスが通っているかチェック。

`arch/arm/boot/uImage`ができるので、SDカードの`ZED_BOOT`パーティションにコピー。

# devicetree作成
作業ディレクトリは前章と同じ。

```bash
$ make ARCH=arm zynq-zed-adv7511.dtb
```

`arch/arm/boot/dts/zynq‐zed‐adv7511.dtb`ができるので、`devicetree.dtb`とリネームしてSDカードの`ZED_BOOT`パーティションにコピーする。

# Root file system作成
## ダウンロード
Avnetのチュートリアルで使っているubuntu desktop 12.04はリンク切れだったので、http://elinux.org/Parallella_Linaro_Nano を参考に使用するRFSを変更しました。
nanoという名前から察するにたぶんこちらのほうがコンパクト。GUI入っていないし。
自分の用途にはそれで十分。

```bash
$ wget http://releases.linaro.org/15.04/ubuntu/utopic-images/nano/linaro-utopic-nano-20150421-702.tar.gz
```

他のイメージを使いたい場合、
http://www.linaro.org/downloads/historic/
から好きなのを探してください。
あまり古いとサポートが切れていてaptのリポジトリがなくなっていたりするのでおすすめしません。設定をいじる場所が増えます。

## SDカードへ展開
SDカードをPCに挿し、マウントした状態で以下を実行します。
`/media/foo/rootfs`はSDカードの`rootfs`パーティションがマウントされた場所です。自分の環境に合わせて適宜変えます。

```bash
$ sudo tar --strip-components=1 -C /media/foo/rootfs -xzpf linaro-utopic-nano-20150421-702.tar.gz
```

わりと時間がかかります。
また、展開後は

```bash
$ sudo sync
```
を実行します。（メモリ上のキャッシュをすべてSDに書き込んでいる？）結構時間がかかります。
もしくは、GUIでSDカードのマウントを解除してもよいです。多分内部で`sync`しているので、それでも時間はかかります。

# Ubuntu起動
以上までで準備は完了です。
作成したSDカードをZed boardに挿し、電源を入れるとubuntuが起動します。
HDMIディスプレイを接続しておくと画面にコンソールが表示されますし、
USBキーボードをUSB OTGポートに接続しておくと直接キーボードから入力できます。（USB->mini USB変換ケーブルはZed boardについています）

もしブートシーケンスが途中で止まって、u-bootが入力待ち状態になってしまう場合は、その状態で`reset`コマンドを入力するとブートがやり直され、うまく行く場合があります。

# ネットワーク設定
http://elinux.org/Parallella_Linaro_Nano#Extract_rootfs そのままです。

Zed boardの電源を切り、SDカードをPCにマウントします。
`/media/foo/rootfs`にマウントされるとします。

```bash
$ sudo vi /media/foo/rootfs/etc/network/interfaces
```

以下のように設定します。適宜自分のネットワーク環境に合わせて書き換えます。

```
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

auto eth0

# static network settings
iface eth0 inet static
   address 192.168.0.2
   netmask 255.255.255.0
   gateway 192.168.0.1
   up sleep 3; mii-tool -F 1000baseT-FD

# If you prefer DHCP, comment out the above 5 lines, uncomment the below.
#iface eth0 inet dhcp
#   up sleep 3; mii-tool -F 1000baseT-FD
```

```bash
$ sudo vi /media/foo/rootfs/etc/resolv.conf
```

以下のように設定します。自分のネットワーク環境に合わせて適宜書き換えます。

```
nameserver 192.168.0.1
```

`sudo sync`の後SDをカードをアンマウントし、EthernetケーブルをZed boardに挿して再度Linuxを起動します。
今度はネットも使えます。`apt-get`が使える！
IPアドレスが固定なのでDHCPの設定など注意してください。

# 最後に
チュートリアルを見ながら何とか起動できたという感じなので、理解が甘かったり記述が間違っていたりするところもあると思います。
変なところを見つけたらぜひ指摘してください。