I'm trying to figure out the minimum requirements to initialize cpu1 from cpu0 in an amp configuration on a zynq-7000.
I have a given FSBL that hands over to u-boot with which I copy both programs (cpu0/1) from flash to different locations in ram (with sf read ...
).
I can run both programs on cpu0 out of u-boot with go [adr]
where adr is the start address of either program. I get the expected output on the uarts.
What does not work is that cpu0 should start cpu1 by writing its start address to register 0xffff_fff0
and after that issuing a system event sev
.
I do not enable any caches, MMUs or the SCU because I want to keep it as simple as possible (no synchronizations or flushes) until I achieved to start up cpu1. Or is this actually the problem and I do need any of these?
Currently I only initialize the vector table, print to the uart and additionally for core 0 try to start core 1:
/* CPU 0 */
.section .vector_table, "x"
.global _init
_init:
b reset /* reset handler */
b . /* software interrupt */
b . /* prefetch abort */
b . /* data abort */
b . /* reserved */
b . /* irq */
b . /* fiq */
/* ASCII control chars */
.equ asciiLF, 0x0a
.equ asciiCR, 0x0d
.section .text
uart1fifo: .word 0xe0001030 /* UART 1 rx/tx fifo register */
reset:
/* Output "0" on UART 1 */
ldr r0, uart1fifo
mov r1, #'0'
str r1, [r0]
mov r1, #asciiCR
str r1, [r0]
mov r1, #asciiLF
str r1, [r0]
/* Set cpu1 start address */
ldr r0, =0x20000000 /* CPU 1 start address */
ldr r1, =0xfffffff0 /* Register to point to the CPU 1 start address */
str r0, [r1]
/* I added a 0.5s wait here which did not help */
sev /* Execute SEV to cause CPU 1 to wake up */
/* Output "." on UART 1 to indicate that we actually went so far */
ldr r0, uart1fifo
mov r1, #'.'
str r1, [r0]
mov r1, #asciiCR
str r1, [r0]
mov r1, #asciiLF
str r1, [r0]
b . /* Endless loop */
I can see the '0' and the '.' on uart 1 when I run the above code on cpu 0.
/* CPU 1 */
.section .vector_table, "x"
.global _init
_init:
b reset /* reset handler */
b . /* software interrupt */
b . /* prefetch abort */
b . /* data abort */
b . /* reserved */
b . /* irq */
b . /* fiq */
/* ASCII control chars */
.equ asciiLF, 0x0a
.equ asciiCR, 0x0d
.section .text
uart0fifo: .word 0xe0000030 /* UART 0 rx/tx fifo register */
reset:
/* Output "1" on UART 0 */
ldr r0, uart0fifo
mov r1, #'1'
str r1, [r0]
mov r1, #asciiCR
str r1, [r0]
mov r1, #asciiLF
str r1, [r0]
b . /* Endless loop */
Here I can see the '1' on uart 0 when I run it on cpu 0.
I'm new to this and I'm a bit lost. Am I missing something fundamental? What can I try to get this to work?
I've been looking at xapp-1079 but this uses Xilinx' Standalone Libs and it's very difficult for me to filter out what is actually needed. I need a minimum working example so that I can port it to the exotic OS that we run on the first core.
It turned out that cpu1 wasn't in wfe state. I suppose u-boot has already woken it up although it wasn't using it i.e. the state of cpu1 was not smp.
I had to execute a software reset on cpu 1 and bring it back into wfe state before issuing the sev
command according to AR#53828 from xilinx.
The steps should the link die were:
mwr 0xFFFFFF00 0xe3e0000f
mwr 0xFFFFFF04 0xe3a01000
mwr 0xFFFFFF08 0xe5801000
mwr 0xFFFFFF0C 0xe320f002
mwr 0xFFFFFF10 0xe5902000
mwr 0xFFFFFF14 0xe1520001
mwr 0xFFFFFF18 0x0afffffb
mwr 0xFFFFFF1C 0xe1a0f002
0x0
that takes cpu1 from 0x0
to the wfe area at 0xffffff00
:mwr 0x00000000 0xe3e0f0ff
mwr 0xf8000008 0xdf0d # slcr unlock
mwr 0xf8000244 0x2 # A9_RST1_ASSERT
mwr 0xf8000244 0x22 # A9_RST1_ASSERT | A9_CLKSTOP1
mwr 0xf8000244 0x20 # A9_CLKSTOP1
mwr 0xf8000244 0x0 # de-assert / start all
mwr 0xf8000004 0x767b # slcr lock
0xfffffff0
.sev
.