3

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.

robsn
  • 700
  • 4
  • 17
  • Can you specify the u-boot commands you use to load the binaries. – R.k. Lohana Apr 15 '20 at 17:15
  • @R.k.Lohana Thank you for the comment. It turned out that CPU1 wasn't in WFE state. I suppose it was already woken up by u-boot although I can't see the reason why it should do this as the CPU1 state was not SMP. I'll put the steps that actually succeeded in an answer. – robsn Apr 16 '20 at 09:51

1 Answers1

0

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:

  • Backup the registers that are overwritten in the next steps.
  • Restore the WFE (wait for event) code in the OCM area. (I used assembly instead of the shown xilinx xsct commands as I don't have access to their IDE):
mwr 0xFFFFFF00 0xe3e0000f
mwr 0xFFFFFF04 0xe3a01000
mwr 0xFFFFFF08 0xe5801000
mwr 0xFFFFFF0C 0xe320f002
mwr 0xFFFFFF10 0xe5902000
mwr 0xFFFFFF14 0xe1520001
mwr 0xFFFFFF18 0x0afffffb
mwr 0xFFFFFF1C 0xe1a0f002
  • Write the jump instruction to 0x0 that takes cpu1 from 0x0 to the wfe area at 0xffffff00:
mwr 0x00000000 0xe3e0f0ff
  • Perform a software reset on cpu1:
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
  • Write the cpu1 start address to 0xfffffff0.
  • Issue sev.
  • Ensure that cpu1 actually started or just wait a few cycles.
  • Restore the backed up registers.
robsn
  • 700
  • 4
  • 17