最近要用到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:
#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
按理说应该对应.globl _cpu1_catch才对,而且boot.s中下面的执行代码也的确用到了这个量,不过怎么数.globl _cpu1_catch也是0x2C,这个疑问留待以后吧。
其二是启动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的时钟;
上述代码也分别是做这三件事的。