Xilinx官方的Zynq AMP configure XAPP1078實現Linux+Baremetal方法有些麻煩,介紹一種可以通過在常規FSBL下來實現CPU0啟動CPU1的方法。
預備知識:UG585, section 6.1.10 Starting Code on CPU 1
The steps for CPU 0 to start an application on CPU 1 are as follows: 1. Write the address of the application for CPU 1 to 0xFFFFFFF0. 2. Execute the SEV instruction to cause CPU 1 to wake up and jump to the application.
具體實現步驟:
Step1:通過Vivado建立CPU0的FSBL ,見下圖,同時自動生成對應的BSP
Step2:在FSBL -> src -> main.c中最下方添加如下函數申明
/**************************************************************/ * * This function Starting Code/Applications on CPU 1* * ****************************************************************/ #define sev() __asm__("sev") #define CPU1STARTADR 0xFFFFFFF0 #define CPU1STARTMEM 0x30000000 void StartCpu1(void) { #if 1 fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r"); Xil_Out32(CPU1STARTADR, CPU1STARTMEM); dmb(); //waits until write has finished fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r"); sev(); #endif }
Step3:在FSBL -> src -> main.c 的int main(void)函數中,幾乎最尾部,在Load boot image之后執行StartCpu1()
/* * Load boot image */ HandoffAddress = LoadBootImage(); fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress); StartCpu1(); /*add starting cpu1*/
Step4: 建立CPU1的GPIO-LED點燈應用程序,對應的BSP中編譯選項中設置-g -DUSE_AMP=1,
--直接打開給AMP工程建立FSBL時自動生成的對應的BSP中的system.mss,然后找到你想要的example程序,直接 Import Examples,見下圖紅色方框標識
Step5::修改GPIO-LED下的lscripts.ld下的ddr內存空間: Base Address -> 0x30000000
--0x30000000,這個地址就是是FSBL將CPU1的應用程序helloworld搬運到ddr的內存起始地址0x30000000,
--StartCpu1()中給地址0xFFFFFFF0寫入的CPU1的應用程序起始地址,到現在就串起來了
Step6: 修改devicetree:linux-xlnx-xilinx-v2017.1\arch\arm\boot\dts目錄下復制zynq-zc702.dts,重命名zynq-zc702-amp.dts並編譯生成zynq-zc702-amp.dtb,並更名為devicetree.dtb
--具體的修改內容:
1. 修改cpu0 的ddr空間為低0x00000000 - 0x30000000
memory {
device_type = "memory";
reg = <0x00000000 0x30000000>;
};
2. 注釋/刪除GPIO/LED相關的部分(根據你自己的情況修改不同的接口,由於是GPIO的例子,對應處理GPIO/LED的部分)
3. 修改bootargs參數
bootargs = "console=ttyPS0,115200 maxcpus=1 clk_ingore_unused root=/dev/ram rw ip=:::::eth0:dhcp earlyprintk";
--說明一下:現在linux kernel在功耗管理者一塊提升很大,新版本的kernel會將沒有用的設備clock關掉,這樣會導致CPU1用的外設無法訪問而帶來一系列問題,解決方法有2個:
a. 在bootargs中添加 clk_ingore_unused 參數,告訴linux內核不要關閉沒有用的clock
https://www.kernel.org/doc/Documentation/clk.txt ======================================= Disabling clock gating of unused clocks ======================================= Sometimes during development it can be useful to be able to bypass the default disabling of unused clocks. For example, if drivers aren't enabling clocks properly but rely on them being on from the bootloader, bypassing the disabling means that the driver will remain functional while the issues are sorted out. To bypass this disabling, include "clk_ignore_unused" in the bootargs to the kernel.
b. 在make menuconfig中將power management option中uncheck,不同版本的名字可能會有差別,如果不在乎功耗,直接全部uncheck,或者自己讀help,針對性的uncheck
Step6:正常編譯uboot,kernel,並使用ramdisk文件,
Step7:在XSDK下用Xilinx tools -> Creat Boot Image, 將amp_fsbl.elf,app_cpu1_bsp_xgpiops_polled_example_1.elf,u-boot.elf生成BOOT.BIN
--Notes:生成BOOT.BIN的時候,add文件的順序有一點小技巧,請按照 FSBL --> uboot.elf --> cpu1_app.elf的順序,這樣確保cpu0的linux正常啟動。
Step8:將BOOT.BIN, uImage, uramdisk.image.gz, devicetree.dtb ,設置成SD啟動