1. 程式人生 > >Zynq啟動CPU1的步驟(暫存器A9_CPU_RST_CTRLS)

Zynq啟動CPU1的步驟(暫存器A9_CPU_RST_CTRLS)

最近要用到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的時鐘;

上述程式碼也分別是做這三件事的。