/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) ASPEED Technology Inc. */ #include #include #include #include /* SCU register offsets */ #define SCU_BASE 0x1e6e2000 #define SCU_PROT_KEY1 (SCU_BASE + 0x000) #define SCU_PROT_KEY2 (SCU_BASE + 0x010) #define SCU_SMP_BOOT (SCU_BASE + 0x180) #define SCU_HWSTRAP1 (SCU_BASE + 0x510) #define SCU_CA7_PARITY_CHK (SCU_BASE + 0x820) #define SCU_CA7_PARITY_CLR (SCU_BASE + 0x824) #define SCU_MMIO_DEC (SCU_BASE + 0xc24) /* FMC SPI register offsets */ #define FMC_BASE 0x1e620000 #define FMC_CE0_CTRL (FMC_BASE + 0x010) #define FMC_SW_RST_CTRL (FMC_BASE + 0x050) #define FMC_WDT1_CTRL_MODE (FMC_BASE + 0x060) #define FMC_WDT2_CTRL_MODE (FMC_BASE + 0x064) /* * The SMP mailbox provides a space with few instructions in it * for secondary cores to execute on and wait for the signal of * SMP core bring up. * * SMP mailbox * +----------------------+ * | | * | mailbox insn. for | * | cpuN polling SMP go | * | | * +----------------------+ 0xC * | mailbox ready signal | * +----------------------+ 0x8 * | cpuN GO signal | * +----------------------+ 0x4 * | cpuN entrypoint | * +----------------------+ SMP_MAILBOX_BASE */ #define SMP_MBOX_BASE (SCU_SMP_BOOT) #define SMP_MBOX_FIELD_ENTRY (SMP_MBOX_BASE + 0x0) #define SMP_MBOX_FIELD_GOSIGN (SMP_MBOX_BASE + 0x4) #define SMP_MBOX_FIELD_READY (SMP_MBOX_BASE + 0x8) #define SMP_MBOX_FIELD_POLLINSN (SMP_MBOX_BASE + 0xc) .macro scu_unlock movw r0, #(SCU_UNLOCK_KEY & 0xffff) movt r0, #(SCU_UNLOCK_KEY >> 16) ldr r1, =SCU_PROT_KEY1 str r0, [r1] ldr r1, =SCU_PROT_KEY2 str r0, [r1] .endm .macro timer_init ldr r1, =SCU_HWSTRAP1 ldr r1, [r1] and r1, #0x700 lsr r1, #0x8 /* 1.2GHz */ cmp r1, #0x0 movweq r0, #0x8c00 movteq r0, #0x4786 /* 1.6GHz */ cmp r1, #0x1 movweq r0, #0x1000 movteq r0, #0x5f5e /* 1.2GHz */ cmp r1, #0x2 movweq r0, #0x8c00 movteq r0, #0x4786 /* 1.6GHz */ cmp r1, #0x3 movweq r0, #0x1000 movteq r0, #0x5f5e /* 800MHz */ cmp r1, #0x4 movwge r0, #0x0800 movtge r0, #0x2faf mcr p15, 0, r0, c14, c0, 0 @; update CNTFRQ .endm .globl lowlevel_init lowlevel_init: #if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD) mov pc, lr #else /* setup ARM arch timer frequency */ timer_init /* reset SMP mailbox as early as possible */ mov r0, #0x0 ldr r1, =SMP_MBOX_FIELD_READY str r0, [r1] /* set ACTLR.SMP to enable cache use */ mrc p15, 0, r0, c1, c0, 1 orr r0, #0x40 mcr p15, 0, r0, c1, c0, 1 /* * we treat cpu0 as the primary core and * put secondary core (cpuN) to sleep */ mrc p15, 0, r0, c0, c0, 5 @; Read CPU ID register ands r0, #0xff @; Mask off, leaving the CPU ID field movw r2, #0xab00 movt r2, #0xabba orr r2, r0 beq do_primary_core_setup /* hold cpuN until mailbox is ready */ poll_mailbox_ready: wfe ldr r0, =SMP_MBOX_FIELD_READY ldr r0, [r0] movw r1, #0xcafe movt r1, #0xbabe cmp r1, r0 bne poll_mailbox_ready /* parameters for relocated SMP go polling insn. */ ldr r0, =SMP_MBOX_FIELD_GOSIGN ldr r1, =SMP_MBOX_FIELD_ENTRY /* no return */ ldr pc, =SMP_MBOX_FIELD_POLLINSN do_primary_core_setup: scu_unlock /* MMIO decode setting */ ldr r0, =SCU_MMIO_DEC mov r1, #0x2000 str r1, [r0] /* enable CA7 cache parity check */ mov r0, #0 ldr r1, =SCU_CA7_PARITY_CLR str r0, [r1] mov r0, #0x1 ldr r1, =SCU_CA7_PARITY_CHK str r0, [r1] /* do not fill FMC50[1] if boot from eMMC */ ldr r0, =SCU_HWSTRAP1 ldr r1, [r0] ands r1, #0x04 bne skip_fill_wip_bit /* fill FMC50[1] for waiting WIP idle */ mov r0, #0x02 ldr r1, =FMC_SW_RST_CTRL str r0, [r1] skip_fill_wip_bit: /* disable FMC WDT for SPI address mode detection */ mov r0, #0 ldr r1, =FMC_WDT1_CTRL_MODE str r0, [r1] /* relocate mailbox insn. for cpuN polling SMP go signal */ adrl r0, mailbox_insn adrl r1, mailbox_insn_end ldr r2, =#SMP_MBOX_FIELD_POLLINSN relocate_mailbox_insn: ldr r3, [r0], #0x4 str r3, [r2], #0x4 cmp r0, r1 bne relocate_mailbox_insn /* reset SMP go sign */ mov r0, #0 ldr r1, =SMP_MBOX_FIELD_GOSIGN str r0, [r1] /* notify cpuN mailbox is ready */ movw r0, #0xCAFE movt r0, #0xBABE ldr r1, =SMP_MBOX_FIELD_READY str r0, [r1] sev /* back to arch calling code */ mov pc, lr /* * insn. inside mailbox to poll SMP go signal. * * Note that as this code will be relocated, any * pc-relative assembly should NOT be used. */ mailbox_insn: /* * r0 ~ r3 are parameters: * r0 = SMP_MBOX_FIELD_GOSIGN * r1 = SMP_MBOX_FIELD_ENTRY * r2 = per-cpu go sign value * r3 = no used now */ poll_mailbox_smp_go: wfe ldr r4, [r0] cmp r2, r4 bne poll_mailbox_smp_go /* SMP GO signal confirmed, release cpuN */ ldr pc, [r1] mailbox_insn_end: /* should never reach */ b . #endif