Zynq啟動CPU1的步驟(暫存器A9_CPU_RST_CTRLS)
阿新 • • 發佈:2019-02-05
最近要用到Zynq的AMP,看了xapp1079,關於CPU0啟動CPU1的介紹還是比較細膩的,摘錄之。
SDK中的程式碼:
print("CPU0: writing startaddress for cpu1\n\r"); { /* * Reset and start CPU1 * - Application for cpu1 exists at 0x00000000 per cpu1 linkerscript * */ #include "xil_misc_psreset_api.h" #include "xil_io.h" #define A9_CPU_RST_CTRL (XSLCR_BASEADDR + 0x244) #define A9_RST1_MASK 0x00000002 #define A9_CLKSTOP1_MASK 0x00000020 #define CPU1_CATCH 0x00000024 #define XSLCR_LOCK_ADDR (XSLCR_BASEADDR + 0x4) #define XSLCR_LOCK_CODE 0x0000767B u32 RegVal; /* * Setup cpu1 catch address with starting address of app_cpu1. The FSBL initialized the vector table at 0x00000000 * using a boot.S that checks for cpu number and jumps to the address stored at the * end of the vector table in cpu0_catch and cpu1_catch entries. * Note: Cache has been disabled at the beginning of main(). Otherwise * a cache flush would have to be issued after this write */ Xil_Out32(CPU1_CATCH, APP_CPU1_ADDR); /* Unlock the slcr register access lock */ Xil_Out32(XSLCR_UNLOCK_ADDR, XSLCR_UNLOCK_CODE); // the user must stop the associated clock, de-assert the reset, and then restart the clock. During a // system or POR reset, hardware automatically takes care of this. Therefore, a CPU cannot run the code // that applies the software reset to itself. This reset needs to be applied by the other CPU or through // JTAG or PL. Assuming the user wants to reset CPU1, the user must to set the following fields in the // slcr.A9_CPU_RST_CTRL (address 0xF8000244) register in the order listed: // 1. A9_RST1 = 1 to assert reset to CPU1 // 2. A9_CLKSTOP1 = 1 to stop clock to CPU1 // 3. A9_RST1 = 0 to release reset to CPU1 // 4. A9_CLKSTOP1 = 0 to restart clock to CPU1 /* Assert and deassert cpu1 reset and clkstop using above sequence*/ RegVal = Xil_In32(A9_CPU_RST_CTRL); RegVal |= A9_RST1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal |= A9_CLKSTOP1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal &= ~A9_RST1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal &= ~A9_CLKSTOP1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); /* lock the slcr register access */ Xil_Out32(XSLCR_LOCK_ADDR, XSLCR_LOCK_CODE); }
上述著重注意兩部分:
其一為Xil_Out32(CPU1_CATCH, APP_CPU1_ADDR);這句中CPU1_CATCH巨集定義為0x24,看程式碼中註釋即可明白,其實這個0x24是在boot.s的彙編中起作用。跳到boot.s:
按理說應該對應.globl _cpu1_catch才對,而且boot.s中下面的執行程式碼也的確用到了這個量,不過怎麼數.globl _cpu1_catch也是0x2C,這個疑問留待以後吧。#include "xparameters.h" #include "xil_errata.h" .globl MMUTable .global _prestart .global _boot .global __stack .global __irq_stack .global __supervisor_stack .global __abort_stack .global __fiq_stack .global __undef_stack .global _vector_table .globl _cpu0_catch .globl _cpu1_catch .globl OKToRun .globl EndlessLoop0
其二是啟動CPU1的部分:
RegVal = Xil_In32(A9_CPU_RST_CTRL); RegVal |= A9_RST1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal |= A9_CLKSTOP1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal &= ~A9_RST1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal); RegVal &= ~A9_CLKSTOP1_MASK; Xil_Out32(A9_CPU_RST_CTRL, RegVal);
這部分的註釋也說的很明白,要想啟動一個CPU,首先不能自己去啟動自己,其次按步驟走即可:
1、停止與該CPU相關聯的時鐘;
2、禁能該CPU的復位;
3、重啟該CPU的時鐘;
上述程式碼也分別是做這三件事的。