前言
虽可使用Petalinux进行移植,简单方便,但为了更清楚明白的了解整个流程,还是尝试了一波手动移植。
参考资料
ZYNQ Linux 移植:包含petalinux移植和手动移植debian9
ZYNQ #5 - 从vivado工程开始,从emmc启动Linux_里先森-CSDN博客
流程
对于手动移植,所需的文件为:
BOOT.bin(FSBL+fpga_bit文件+u_boot.elf)、uImage、devicetree.dtb、uEnv.txt、文件系统
文件放置位置说明:
FLASH:BOOT.bin(FSBL+fpga_bit文件+u_boot.elf)
EMMC:
第一个分区放置:uImage、devicetree.dtb、uEnv.txt第二个分区放置:文件系统
启动流程为:板子设置为QSPI启动模式,FSBL执行调u-boot执行,u-boot根据uEnv.txt调EMMC分区1中的内核执行,内核最后跳到分区二中的文件系统。
FSBL、bit文件、uImage、文件系统都可复用SD卡移植模式下的内容:参考参考资料第一个链接。
本文章主要讲述的重点在于:u-boot、设备树、uEnv.txt的更改部分
板子主要信息说明:板子芯片:ZYNQ7035,板子的调试打印串口为PS0,板子上有SD卡(SD0)、EMMC(SD1),板子上有FLASH。其他外设不赘述。
u-boot移植说明:
1.下载u-boot源码:git clone https://github.com/Xilinx/u-boot-xlnx.git
NOTE:u-boot xilinx-v2018.3版本的zynq-common.h跟xilinx-v2018.1版本的不一样,这里检出v2018.1版本使用。
主要是CONFIG_EXTRA_ENV_SETTINGS 环境变量不一致。
默认的如下所示:
/* Default environment */#ifndef CONFIG_EXTRA_ENV_SETTINGS#define CONFIG_EXTRA_ENV_SETTINGS \ "ethaddr=00:0a:35:00:01:22\0" \ "kernel_image=uImage\0" \ "kernel_load_address=0x2080000\0" \ "ramdisk_image=uramdisk.image.gz\0" \ "ramdisk_load_address=0x4000000\0" \ "devicetree_image=devicetree.dtb\0" \ "devicetree_load_address=0x2000000\0" \ "bitstream_image=system.bit.bin\0" \ "boot_image=BOOT.bin\0" \ "loadbit_addr=0x100000\0" \ "loadbootenv_addr=0x2000000\0" \ "kernel_size=0x500000\0" \ "devicetree_size=0x20000\0" \ "ramdisk_size=0x5E0000\0" \ "boot_size=0xF00000\0" \ "fdt_high=0x20000000\0" \ "initrd_high=0x20000000\0" \ "bootenv=uEnv.txt\0" \ "loadbootenv=load mmc 0 ${loadbootenv_addr} ${bootenv}\0" \ "importbootenv=echo Importing environment from SD ...; " \ "env import -t ${loadbootenv_addr} $filesize\0" \ "sd_uEnvtxt_existence_test=test -e mmc 0 /uEnv.txt\0" \ "preboot=if test $modeboot = sdboot && env run sd_uEnvtxt_existence_test; " \ "then if env run loadbootenv; " \ "then env run importbootenv; " \ "fi; " \ "fi; \0" \ "mmc_loadbit=echo Loading bitstream from SD/MMC/eMMC to RAM.. && " \ "mmcinfo && " \ "load mmc 0 ${loadbit_addr} ${bitstream_image} && " \ "fpga load 0 ${loadbit_addr} ${filesize}\0" \ "norboot=echo Copying Linux from NOR flash to RAM... && " \ "cp.b 0xE2100000 ${kernel_load_address} ${kernel_size} && " \ "cp.b 0xE2600000 ${devicetree_load_address} ${devicetree_size} && " \ "echo Copying ramdisk... && " \ "cp.b 0xE2620000 ${ramdisk_load_address} ${ramdisk_size} && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "qspiboot=echo Copying Linux from QSPI flash to RAM... && " \ "sf probe 0 0 0 && " \ "sf read ${kernel_load_address} 0x100000 ${kernel_size} && " \ "sf read ${devicetree_load_address} 0x600000 ${devicetree_size} && " \ "echo Copying ramdisk... && " \ "sf read ${ramdisk_load_address} 0x620000 ${ramdisk_size} && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "uenvboot=" \ "if run loadbootenv; then " \ "echo Loaded environment from ${bootenv}; " \ "run importbootenv; " \ "fi; " \ "if test -n $uenvcmd; then " \ "echo Running uenvcmd ...; " \ "run uenvcmd; " \ "fi\0" \ "sdboot=if mmcinfo; then " \ "run uenvboot; " \ "echo Copying Linux from SD to RAM... && " \ "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}; " \ "fi\0" \ "usbboot=if usb start; then " \ "run uenvboot; " \ "echo Copying Linux from USB to RAM... && " \ "load usb 0 ${kernel_load_address} ${kernel_image} && " \ "load usb 0 ${devicetree_load_address} ${devicetree_image} && " \ "load usb 0 ${ramdisk_load_address} ${ramdisk_image} && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " \ "fi\0" \ "nandboot=echo Copying Linux from NAND flash to RAM... && " \ "nand read ${kernel_load_address} 0x100000 ${kernel_size} && " \ "nand read ${devicetree_load_address} 0x600000 ${devicetree_size} && " \ "echo Copying ramdisk... && " \ "nand read ${ramdisk_load_address} 0x620000 ${ramdisk_size} && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "jtagboot=echo TFTPing Linux to RAM... && " \ "tftpboot ${kernel_load_address} ${kernel_image} && " \ "tftpboot ${devicetree_load_address} ${devicetree_image} && " \ "tftpboot ${ramdisk_load_address} ${ramdisk_image} && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "rsa_norboot=echo Copying Image from NOR flash to RAM... && " \ "cp.b 0xE2100000 0x100000 ${boot_size} && " \ "zynqrsa 0x100000 && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "rsa_nandboot=echo Copying Image from NAND flash to RAM... && " \ "nand read 0x100000 0x0 ${boot_size} && " \ "zynqrsa 0x100000 && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "rsa_qspiboot=echo Copying Image from QSPI flash to RAM... && " \ "sf probe 0 0 0 && " \ "sf read 0x100000 0x0 ${boot_size} && " \ "zynqrsa 0x100000 && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "rsa_sdboot=echo Copying Image from SD to RAM... && " \ "load mmc 0 0x100000 ${boot_image} && " \ "zynqrsa 0x100000 && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ "rsa_jtagboot=echo TFTPing Image to RAM... && " \ "tftpboot 0x100000 ${boot_image} && " \ "zynqrsa 0x100000 && " \ "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \ DFU_ALT_INFO \ BOOTENV#endif
可以看到其上定义了一堆的东西及不同的启动指令。
不同的启动指令由#define CONFIG_BOOTCOMMAND指定。
这里想FLASH+EMMC启动,则可以选择sdboot,同时因为EMMC是SD1,所以上述的文件需要进行更改:更改uEnv.txt的存储位置为mmc 1;去掉sdboot中的ramdisk,及存储kernel、设备树位置为mmc 1;修改bootm参数。
"loadbootenv=load mmc 1 ${loadbootenv_addr} ${bootenv}\0" \ "importbootenv=echo Importing environment from SD ...; " \ "env import -t ${loadbootenv_addr} $filesize\0" \ "sd_uEnvtxt_existence_test=test -e mmc 1 /uEnv.txt\0" \
"sdboot=if mmcinfo; then " \ "run uenvboot; " \ "echo Copying Linux from hahahah SD to RAM... && " \ "load mmc 1 ${kernel_load_address} ${kernel_image} && " \ "load mmc 1 ${devicetree_load_address} ${devicetree_image} && " \ "bootm ${kernel_load_address} - ${devicetree_load_address}; " \ "fi\0" \
上述命令的执行逻辑为:u-boot启动后,执行sdboot指令:
(1)装载uEnv.txt文件并运行;
(2)装载内核、设备树;
(3)运行;
2.由于是自己做的板子,则可以基于类似的板子defconfig进行修改适配u-boot:这里使用zynq_zed_defconfig文件:
(1)增加传统镜像文件支持:CONFIG_IMAGE_FORMAT_LEGACY=y
(2)因为已经知道是从EMMC启动相关文件,则可直接指定:CONFIG_BOOTCOMMAND="mmc dev 1;run sdboot"
mmc dev 1是为了避免u-boot死锁bug(移植petalinux中u-boot存在,为官方bug,这里加上,不知道有没有用);sdboot会直接调用执行zynq-common.h中的对应选项。
(3)因为板子上串口使用的是PS0,修改:CONFIG_DEBUG_UART_BASE=0xe0000000(地址可在设备树中查看)
文件参考:
CONFIG_ARM=yCONFIG_ARCH_ZYNQ=yCONFIG_SYS_TEXT_BASE=0x4000000CONFIG_SPL_STACK_R_ADDR=0x200000CONFIG_DEFAULT_DEVICE_TREE="zynq-zed"CONFIG_DEBUG_UART=yCONFIG_DISTRO_DEFAULTS=yCONFIG_IMAGE_FORMAT_LEGACY=yCONFIG_FIT=yCONFIG_FIT_SIGNATURE=yCONFIG_FIT_VERBOSE=yCONFIG_BOOTCOMMAND="mmc dev 1;run sdboot"# CONFIG_DISPLAY_CPUINFO is not setCONFIG_SPL=yCONFIG_SPL_STACK_R=yCONFIG_SPL_OS_BOOT=yCONFIG_SYS_PROMPT="Zynq> "CONFIG_CMD_THOR_DOWNLOAD=yCONFIG_CMD_DFU=y# CONFIG_CMD_FLASH is not setCONFIG_CMD_FPGA_LOADBP=yCONFIG_CMD_FPGA_LOADFS=yCONFIG_CMD_FPGA_LOADMK=yCONFIG_CMD_FPGA_LOADP=yCONFIG_CMD_GPIO=yCONFIG_CMD_MMC=yCONFIG_CMD_SF=yCONFIG_CMD_USB=y# CONFIG_CMD_SETEXPR is not setCONFIG_CMD_TFTPPUT=yCONFIG_CMD_CACHE=yCONFIG_CMD_EXT4_WRITE=yCONFIG_OF_EMBED=yCONFIG_ENV_IS_IN_SPI_FLASH=yCONFIG_NET_RANDOM_ETHADDR=yCONFIG_SPL_DM_SEQ_ALIAS=yCONFIG_DFU_MMC=yCONFIG_DFU_RAM=yCONFIG_FPGA_XILINX=yCONFIG_DM_GPIO=yCONFIG_MMC_SDHCI=yCONFIG_MMC_SDHCI_ZYNQ=yCONFIG_SPI_FLASH=yCONFIG_SPI_FLASH_BAR=yCONFIG_SF_DUAL_FLASH=yCONFIG_SPI_FLASH_SPANSION=yCONFIG_SPI_FLASH_STMICRO=yCONFIG_SPI_FLASH_WINBOND=yCONFIG_PHY_MARVELL=yCONFIG_PHY_REALTEK=yCONFIG_PHY_XILINX=yCONFIG_ZYNQ_GEM=yCONFIG_DEBUG_UART_ZYNQ=yCONFIG_DEBUG_UART_BASE=0xe0000000CONFIG_DEBUG_UART_CLOCK=50000000CONFIG_ZYNQ_SERIAL=yCONFIG_ZYNQ_QSPI=yCONFIG_USB=yCONFIG_USB_EHCI_HCD=yCONFIG_USB_ULPI_VIEWPORT=yCONFIG_USB_ULPI=yCONFIG_USB_STORAGE=yCONFIG_USB_GADGET=yCONFIG_USB_GADGET_MANUFACTURER="Xilinx"CONFIG_USB_GADGET_VENDOR_NUM=0x03fdCONFIG_USB_GADGET_PRODUCT_NUM=0x0300CONFIG_CI_UDC=yCONFIG_USB_GADGET_DOWNLOAD=y
3.修改u-boot的设备树:实际上u-boot也带了设备树,这里需要进行修改:
(1)修改uart为uart0;
(2)修改SD为mmc1;
(3)去除QSPI中的分区表;
文件参考:
/* * Xilinx ZED board DTS * * Copyright (C) 2011 - 2015 Xilinx * Copyright (C) 2012 National Instruments Corp. * * SPDX-License-Identifier: GPL-2.0+ *//dts-v1/;#include "zynq-7000.dtsi"/ { model = "Zynq Zed Development Board"; compatible = "xlnx,zynq-zed", "xlnx,zynq-7000"; aliases { ethernet0 = &gem0; serial0 = &uart0; spi0 = &qspi; mmc1 = &sdhci1; }; memory@0 { device_type = "memory"; reg = <0x0 0x20000000>; }; chosen { bootargs = ""; stdout-path = "serial0:115200n8"; }; usb_phy0: phy0@e0002000 { compatible = "ulpi-phy"; #phy-cells = <0>; reg = <0xe0002000 0x1000>; view-port = <0x0170>; drv-vbus; };};&clkc { ps-clk-frequency = <33333333>;};&gem0 { status = "okay"; phy-mode = "rgmii-id"; phy-handle = <ðernet_phy>; ethernet_phy: ethernet-phy@0 { reg = <0>; device_type = "ethernet-phy"; };};&qspi { u-boot,dm-pre-reloc; status = "okay"; is-dual = <0>; num-cs = <1>; flash@0 { compatible = "n25q128a11"; reg = <0x0>; spi-tx-bus-width = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <50000000>; #address-cells = <1>; #size-cells = <1>; };};&sdhci1 { u-boot,dm-pre-reloc; status = "okay";};&uart0 { u-boot,dm-pre-reloc; status = "okay";};&usb0 { status = "okay"; dr_mode = "host"; usb-phy = <&usb_phy0>;};
- 编译u-boot:
清除中间编译:
make distclean
使用配置文件:
make CROSS_COMPILE=arm-linux-gnueabihf- zynq_zed_defconfig
通过下述指令可在界面中uboot进行进一步修改配置:改defconfig文件也可以,暂时默认即可
make CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
工具编译:
make CROSS_COMPILE=arm-linux-gnueabihf- tools
编译u-boot:
make CROSS_COMPILE=arm-linux-gnueabihf-
- 修改总设备树的boottags:console=ttyPS0,115200n8 root=/dev/mmcblk1p2 rw noinitrd rootfstype=ext4 rootwait
- 修改uEnv.txt为:mmc 0修改为mmc 1;root=/dev/mmcblk1p2
bootargs=console=ttyPS0,115200 root=/dev/mmcblk1p2 rw earlyprintk rootfstype=ext4 rootwaitload_image=fatload mmc 1 ${kernel_load_address} ${kernel_image} && fatload mmc 1 ${devicetree_load_address} ${devicetree_image}uenvcmd=echo Copying Linux from SD to RAM... && mmcinfo && run load_image && bootm ${kernel_load_address} - ${devicetree_load_address}
- 组装BOOT.bin,不赘述。
- 烧录BOOT.bin到FLASH,对EMMC进行分区,EMMC分区一中放置uImage、devicetree.dtb、uEnv.txt,EMMC分区二中放置文件系统即可。
- 启动。
U-Boot 2018.01-dirty (Jul 26 2021 - 20:05:00 +0800)Model: Zynq Zed Development BoardBoard: Xilinx ZynqSilicon: v3.1DRAM: ECC disabled 512 MiBMMC: sdhci_transfer_data: Error detected in status(0x208000)!sdhci@e0101000: 1 (eMMC)SF: Detected s25fl128s_64k with page size 256 Bytes, erase size 64 KiB, total 16 MiB*** Warning - bad CRC, using default environmentIn: serial@e0000000Out: serial@e0000000Err: serial@e0000000Net: ZYNQ GEM: e000b000, phyaddr 0, interface rgmii-ideth0: ethernet@e000b000Hit any key to stop autoboot: 0 sdhci_transfer_data: Error detected in status(0x208000)!switch to partitions #0, OKmmc1(part 0) is current deviceDevice: sdhci@e0101000Manufacturer ID: 13OEM: 14eName: Q2J55 Tran Speed: 25000000Rd Block Len: 512MMC version 5.0High Capacity: YesCapacity: 7.1 GiBBus Width: 4-bitErase Group Size: 512 KiBHC WP Group Size: 8 MiBUser Capacity: 7.1 GiB WRRELBoot Capacity: 16 MiB ENHRPMB Capacity: 4 MiB ENHreading uEnv.txt356 bytes read in 11 ms (31.3 KiB/s)Loaded environment from uEnv.txtImporting environment from SD ...Running uenvcmd ...Copying Linux from SD to RAM...Device: sdhci@e0101000Manufacturer ID: 13OEM: 14eName: Q2J55 Tran Speed: 25000000Rd Block Len: 512MMC version 5.0High Capacity: YesCapacity: 7.1 GiBBus Width: 4-bitErase Group Size: 512 KiBHC WP Group Size: 8 MiBUser Capacity: 7.1 GiB WRRELBoot Capacity: 16 MiB ENHRPMB Capacity: 4 MiB ENHreading uImage4001616 bytes read in 377 ms (10.1 MiB/s)reading devicetree.dtb17052 bytes read in 18 ms (924.8 KiB/s)## Booting kernel from Legacy Image at 02080000 ... Image Name: Linux-4.14.0-xilinx Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4001552 Bytes = 3.8 MiB Load Address: 00008000 Entry Point: 00008000 Verifying Checksum ... OK## Flattened Device Tree blob at 02000000 Booting using the fdt blob at 0x2000000 Loading Kernel Image ... OK Loading Device Tree to 1eb12000, end 1eb1929b ... OK
以上。