summaryrefslogtreecommitdiffstats
path: root/plat/nxp/soc-ls1088a/aarch64
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plat/nxp/soc-ls1088a/aarch64/ls1088a.S1817
-rw-r--r--plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S69
2 files changed, 1886 insertions, 0 deletions
diff --git a/plat/nxp/soc-ls1088a/aarch64/ls1088a.S b/plat/nxp/soc-ls1088a/aarch64/ls1088a.S
new file mode 100644
index 0000000..0c6b7ea
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/aarch64/ls1088a.S
@@ -0,0 +1,1817 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.section .text, "ax"
+
+#include <asm_macros.S>
+#include <lib/psci/psci.h>
+#include <nxp_timer.h>
+#include <plat_gic.h>
+
+#include "bl31_data.h"
+#include "plat_psci.h"
+#include "platform_def.h"
+
+/*
+ * the BASE address for these offsets is AUX_01_DATA in the
+ * bootcore's psci data region
+ */
+#define DEVDISR2_MASK_OFFSET 0x0 /* references AUX_01_DATA */
+#define DEVDISR5_MASK_OFFSET 0x8 /* references AUX_02_DATA */
+
+/*
+ * the BASE address for these offsets is AUX_04_DATA in the
+ * bootcore's psci data region
+ */
+#define GICD_BASE_ADDR_OFFSET 0x0 /* references AUX_04_DATA */
+#define GICC_BASE_ADDR_OFFSET 0x8 /* references AUX_05_DATA */
+
+#define IPSTPACK_RETRY_CNT 0x10000
+#define DDR_SLEEP_RETRY_CNT 0x10000
+#define CPUACTLR_EL1 S3_1_C15_C2_0
+#define DDR_SDRAM_CFG_2_FRCSR 0x80000000
+#define DDR_SDRAM_CFG_2_OFFSET 0x114
+#define DDR_TIMING_CFG_4_OFFSET 0x160
+#define DDR_CNTRL_BASE_ADDR 0x01080000
+
+#define DLL_LOCK_MASK 0x3
+#define DLL_LOCK_VALUE 0x2
+
+#define ERROR_DDR_SLEEP -1
+#define ERROR_DDR_WAKE -2
+#define ERROR_NO_QUIESCE -3
+
+#define CORE_RESTARTABLE 0
+#define CORE_NOT_RESTARTABLE 1
+
+.global soc_init_lowlevel
+.global soc_init_percpu
+
+.global _soc_core_release
+.global _soc_core_restart
+.global _soc_ck_disabled
+.global _soc_sys_reset
+.global _soc_sys_off
+
+.global _soc_core_prep_off
+.global _soc_core_entr_off
+.global _soc_core_exit_off
+
+.global _soc_core_prep_stdby
+.global _soc_core_entr_stdby
+.global _soc_core_exit_stdby
+.global _soc_core_prep_pwrdn
+.global _soc_core_entr_pwrdn
+.global _soc_core_exit_pwrdn
+.global _soc_clstr_prep_stdby
+.global _soc_clstr_exit_stdby
+.global _soc_clstr_prep_pwrdn
+.global _soc_clstr_exit_pwrdn
+.global _soc_sys_prep_stdby
+.global _soc_sys_exit_stdby
+.global _soc_sys_prep_pwrdn
+.global _soc_sys_pwrdn_wfi
+.global _soc_sys_exit_pwrdn
+
+.global _set_platform_security
+.global _soc_set_start_addr
+
+.equ TZPCDECPROT_0_SET_BASE, 0x02200804
+.equ TZPCDECPROT_1_SET_BASE, 0x02200810
+.equ TZPCDECPROT_2_SET_BASE, 0x0220081C
+
+.equ TZASC_REGION_ATTRIBUTES_0_0, 0x01100110
+
+.equ MPIDR_AFFINITY0_MASK, 0x00FF
+.equ MPIDR_AFFINITY1_MASK, 0xFF00
+.equ CPUECTLR_DISABLE_TWALK_PREFETCH, 0x4000000000
+.equ CPUECTLR_INS_PREFETCH_MASK, 0x1800000000
+.equ CPUECTLR_DAT_PREFETCH_MASK, 0x0300000000
+.equ OSDLR_EL1_DLK_LOCK, 0x1
+.equ CNTP_CTL_EL0_EN, 0x1
+.equ CNTP_CTL_EL0_IMASK, 0x2
+/* shifted value for incrementing cluster count in mpidr */
+.equ MPIDR_CLUSTER, 0x100
+
+/*
+ * This function initialize the soc,
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11
+ */
+func soc_init_lowlevel
+ /*
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ /*
+ * make sure the personality has been established by releasing cores
+ * that are marked "to-be-disabled" from reset
+ */
+ bl release_disabled
+
+ /* set SCRATCHRW7 to 0x0 */
+ ldr x0, =DCFG_SCRATCHRW7_OFFSET
+ mov x1, xzr
+ bl _write_reg_dcfg
+
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ret
+endfunc soc_init_lowlevel
+
+/*
+ * void soc_init_percpu(void)
+ * this function performs any soc-specific initialization that is needed on
+ * a per-core basis
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func soc_init_percpu
+ stp x4, x30, [sp, #-16]!
+
+ bl plat_my_core_mask
+ mov x2, x0
+
+ /* x2 = core mask */
+
+ /* see if this core is marked for prefetch disable */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A53
+1:
+ mov x0, #NXP_PMU_ADDR
+ bl enable_timer_base_to_cluster
+ ldp x4, x30, [sp], #16
+ ret
+endfunc soc_init_percpu
+
+/*
+ * this function sets the security mechanisms in the SoC to implement the
+ * Platform Security Policy
+ */
+func _set_platform_security
+ mov x3, x30
+
+#if (!SUPPRESS_TZC)
+ /* initialize the tzpc */
+ bl init_tzpc
+#endif
+
+#if (!SUPPRESS_SEC)
+ /* initialize secmon */
+ bl initSecMon
+#endif
+ mov x30, x3
+ ret
+endfunc _set_platform_security
+
+/*
+ * this function writes a 64-bit address to bootlocptrh/l
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * out: none
+ * uses x0, x1, x2
+ */
+func _soc_set_start_addr
+ /* get the 64-bit base address of the dcfg block */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* write the 32-bit BOOTLOCPTRL register */
+ mov x1, x0
+ str w1, [x2, #DCFG_BOOTLOCPTRL_OFFSET]
+
+ /* write the 32-bit BOOTLOCPTRH register */
+ lsr x1, x0, #32
+ str w1, [x2, #DCFG_BOOTLOCPTRH_OFFSET]
+ ret
+endfunc _soc_set_start_addr
+
+/*
+ * part of CPU_ON
+ * this function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0, x1, x2, x3
+ */
+_soc_core_release:
+ mov x3, x30
+
+ /* x0 = core mask */
+
+ ldr x1, =NXP_SEC_REGFILE_ADDR
+ /*
+ * write to CORE_HOLD to tell the bootrom that we want this core
+ * to run
+ */
+ str w0, [x1, #CORE_HOLD_OFFSET]
+
+ /* x0 = core mask */
+
+ /* read-modify-write BRRL to release core */
+ mov x1, #NXP_RESET_ADDR
+ ldr w2, [x1, #BRR_OFFSET]
+ orr w2, w2, w0
+ str w2, [x1, #BRR_OFFSET]
+ dsb sy
+ isb
+
+ /* send event */
+ sev
+ isb
+
+ mov x30, x3
+ ret
+
+/*
+ * this function determines if a core is disabled via COREDISABLEDSR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1
+ */
+_soc_ck_disabled:
+ /* get base addr of dcfg block */
+ ldr x1, =NXP_DCFG_ADDR
+
+ /* read COREDISABLEDSR */
+ ldr w1, [x1, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* test core bit */
+ and w0, w1, w0
+
+ ret
+
+/*
+ * part of CPU_ON
+ * this function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_core_restart:
+ mov x6, x30
+ mov x4, x0
+
+ /* x4 = core mask lsb */
+
+ /* pgm GICD_CTLR - enable secure grp0 */
+ mov x5, #NXP_GICD_ADDR
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ orr w2, w2, #GICD_CTLR_EN_GRP_0
+ str w2, [x5, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+ /* poll on RWP til write completes */
+4:
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ tst w2, #GICD_CTLR_RWP
+ b.ne 4b
+
+ /*
+ * x4 = core mask lsb
+ * x5 = gicd base addr
+ */
+
+ mov x0, x4
+ bl get_mpidr_value
+
+ /*
+ * x0 = mpidr of target core
+ * x4 = core mask lsb of target core
+ * x5 = gicd base addr
+ */
+
+ /* generate target list bit */
+ and x1, x0, #MPIDR_AFFINITY0_MASK
+ mov x2, #1
+ lsl x2, x2, x1
+ /* get the affinity1 field */
+ and x1, x0, #MPIDR_AFFINITY1_MASK
+ lsl x1, x1, #8
+ orr x2, x2, x1
+ /* insert the INTID for SGI15 */
+ orr x2, x2, #ICC_SGI0R_EL1_INTID
+ /* fire the SGI */
+ msr ICC_SGI0R_EL1, x2
+ dsb sy
+ isb
+
+ /* load '0' on success */
+ mov x0, xzr
+
+ mov x30, x6
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7
+ */
+_soc_core_prep_off:
+ mov x8, x30
+ mov x7, x0
+
+ /* x7 = core mask lsb */
+
+ mrs x1, CPUECTLR_EL1
+ /* set smp and disable L2 snoops in cpuectlr */
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ orr x1, x1, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ bic x1, x1, #CPUECTLR_INS_PREFETCH_MASK
+ bic x1, x1, #CPUECTLR_DAT_PREFETCH_MASK
+ /* set retention control in cpuectlr */
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ msr CPUECTLR_EL1, x1
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x7
+ bl get_gic_rd_base
+ mov x6, x0
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x7
+ bl get_gic_sgi_base
+ mov x5, x0
+
+ /* x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w3, #GICR_ICENABLER0_SGI15
+ str w3, [x5, #GICR_ICENABLER0_OFFSET]
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* disable GRP1 interrupts at cpu interface */
+ msr ICC_IGRPEN1_EL3, xzr
+
+ /* disable GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* program the redistributor - poll on GICR_CTLR.RWP as needed */
+
+ /* define SGI 15 as Grp0 - GICR_IGROUPR0 */
+ ldr w4, [x5, #GICR_IGROUPR0_OFFSET]
+ bic w4, w4, #GICR_IGROUPR0_SGI15
+ str w4, [x5, #GICR_IGROUPR0_OFFSET]
+
+ /* define SGI 15 as Grp0 - GICR_IGRPMODR0 */
+ ldr w3, [x5, #GICR_IGRPMODR0_OFFSET]
+ bic w3, w3, #GICR_IGRPMODR0_SGI15
+ str w3, [x5, #GICR_IGRPMODR0_OFFSET]
+
+ /* set priority of SGI 15 to highest (0x0) - GICR_IPRIORITYR3 */
+ ldr w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+ bic w4, w4, #GICR_IPRIORITYR3_SGI15_MASK
+ str w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+
+ /* enable SGI 15 at redistributor - GICR_ISENABLER0 */
+ mov w3, #GICR_ISENABLER0_SGI15
+ str w3, [x5, #GICR_ISENABLER0_OFFSET]
+ dsb sy
+ isb
+3:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 3b
+
+ /* quiesce the debug interfaces */
+ mrs x3, osdlr_el1
+ orr x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ /* enable grp0 ints */
+ mov x3, #ICC_IGRPEN0_EL1_EN
+ msr ICC_IGRPEN0_EL1, x3
+
+ /*
+ * x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* clear any pending interrupts */
+ mvn w1, wzr
+ str w1, [x5, #GICR_ICPENDR0_OFFSET]
+
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 4f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+4:
+ /* enable the core timer and mask timer interrupt */
+ mov x1, #CNTP_CTL_EL0_EN
+ orr x1, x1, #CNTP_CTL_EL0_IMASK
+ msr cntp_ctl_el0, x1
+
+ mov x30, x8
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+_soc_core_entr_off:
+ mov x5, x30
+ mov x4, x0
+
+ /* x4 = core mask */
+1:
+ /* enter low-power state by executing wfi */
+ wfi
+
+ /* see if SGI15 woke us up */
+ mrs x2, ICC_IAR0_EL1
+ mov x3, #ICC_IAR0_EL1_SGI15
+ cmp x2, x3
+ b.ne 2f
+
+ /* deactivate the int */
+ msr ICC_EOIR0_EL1, x2
+
+ /* x4 = core mask */
+2:
+ /* check if core has been turned on */
+ mov x0, x4
+ bl _getCoreState
+
+ /* x0 = core state */
+
+ cmp x0, #CORE_WAKEUP
+ b.ne 1b
+
+ /* if we get here, then we have exited the wfi */
+
+ mov x30, x5
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_core_exit_off:
+ mov x6, x30
+ mov x5, x0
+
+ /* disable forwarding of GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x5
+ bl get_gic_sgi_base
+ mov x4, x0
+
+ /*
+ * x4 = gicr sgi base addr
+ * x5 = core mask
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w1, #GICR_ICENABLER0_SGI15
+ str w1, [x4, #GICR_ICENABLER0_OFFSET]
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x5
+ bl get_gic_rd_base
+ mov x4, x0
+
+ /* x4 = gicr rd base addr */
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w2, [x4, #GICR_CTLR_OFFSET]
+ tst w2, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* x4 = gicr rd base addr */
+
+ /* unlock the debug interfaces */
+ mrs x3, osdlr_el1
+ bic x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ dsb sy
+ isb
+ mov x30, x6
+ ret
+
+/*
+ * this function requests a reset of the entire SOC
+ * in: none
+ * out: none
+ * uses: x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_sys_reset:
+ mov x3, x30
+
+ /* make sure the mask is cleared in the reset request mask register */
+ mov x0, #RST_RSTRQMR1_OFFSET
+ mov w1, wzr
+ bl _write_reg_reset
+
+ /* set the reset request */
+ mov x4, #RST_RSTCR_OFFSET
+ mov x0, x4
+ mov w1, #RSTCR_RESET_REQ
+ bl _write_reg_reset
+
+ /* x4 = RST_RSTCR_OFFSET */
+
+ /*
+ * just in case this address range is mapped as cacheable,
+ * flush the write out of the dcaches
+ */
+ mov x2, #NXP_RESET_ADDR
+ add x2, x2, x4
+ dc cvac, x2
+ dsb st
+ isb
+
+ /* this function does not return */
+ b .
+
+/*
+ * this function turns off the SoC
+ * Note: this function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_sys_off:
+ /*
+ * A-009810: LPM20 entry sequence might cause
+ * spurious timeout reset request
+ * workaround: MASK RESET REQ RPTOE
+ */
+ ldr x0, =NXP_RESET_ADDR
+ ldr w1, [x0, #RST_RSTRQMR1_OFFSET]
+ orr w1, w1, #RSTRQMR_RPTOE_MASK
+ str w1, [x0, #RST_RSTRQMR1_OFFSET]
+
+ /* disable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, =DCFG_DEVDISR3_QBMAIN
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /* set TPMWAKEMR0 */
+ ldr x0, =TPMWAKEMR0_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* disable L2 prefetches */
+ mrs x0, CPUECTLR_EL1
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ /* disable CCN snoop domain */
+ ldr x0, =NXP_CCI_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ mov x2, #DAIF_SET_MASK
+
+ mrs x1, spsr_el1
+ orr x1, x1, x2
+ msr spsr_el1, x1
+
+ mrs x1, spsr_el2
+ orr x1, x1, x2
+ msr spsr_el2, x1
+
+ bl get_pmu_idle_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+
+ /* x3 = pmu base addr */
+
+ /* idle the ACP interfaces */
+ str w0, [x3, #PMU_CLAINACTSETR_OFFSET]
+
+ /* force the debug interface to be quiescent */
+ mrs x0, osdlr_el1
+ orr x0, x0, #0x1
+ msr osdlr_el1, x0
+
+ bl get_pmu_flush_cluster_mask
+ /* x3 = pmu base addr */
+ mov x3, #NXP_PMU_ADDR
+
+ /* clear flush request and status */
+ ldr x2, =PMU_CLSL2FLUSHCLRR_OFFSET
+ str w0, [x3, x2]
+
+ /* close the Skyros master port */
+ ldr x2, =PMU_CLSINACTSETR_OFFSET
+ str w0, [x3, x2]
+
+ /* request lpm20 */
+ ldr x0, =PMU_POWMGTCSR_OFFSET
+ ldr w1, =PMU_POWMGTCSR_VAL
+ str w1, [x3, x0]
+
+ /* this function does not return */
+1:
+ wfi
+ b 1b
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_core_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_stdby:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_core_prep_pwrdn:
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_pwrdn:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses
+ */
+_soc_core_exit_pwrdn:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_clstr_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_clstr_prep_pwrdn:
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses
+ */
+_soc_clstr_exit_pwrdn:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_sys_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_sys_prep_pwrdn:
+ /* set retention control */
+ mrs x0, CPUECTLR_EL1
+ bic x0, x0, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8
+ */
+_soc_sys_pwrdn_wfi:
+ /* Save LR to stack */
+ stp x18, x30, [sp, #-16]!
+
+ /* Poll PCPW20SR for all secondary cores to be placed in PW20 */
+ bl get_tot_num_cores
+ mov x3, #0x1
+ lsl x3, x3, x0
+ sub x3, x3, #2
+1:
+ mov x0, #NXP_PMU_ADDR
+ ldr w1, [x0, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w3
+ b.ne 1b
+
+ /* backup EPU registers to stack */
+ mov x3, #NXP_PMU_ADDR
+ ldr x2, =NXP_EPU_ADDR
+ ldr w4, [x2, #EPU_EPIMCR10_OFFSET]
+ ldr w5, [x2, #EPU_EPCCR10_OFFSET]
+ ldr w6, [x2, #EPU_EPCTR10_OFFSET]
+ ldr w7, [x2, #EPU_EPGCR_OFFSET]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = epu base addr
+ * x3 = pmu base addr
+ */
+
+ /* set up EPU event to receive the wake signal from PMU */
+ mov w4, #EPU_EPIMCR10_VAL
+ mov w5, #EPU_EPCCR10_VAL
+ mov w6, #EPU_EPCTR10_VAL
+ mov w7, #EPU_EPGCR_VAL
+ str w4, [x2, #EPU_EPIMCR10_OFFSET]
+ str w5, [x2, #EPU_EPCCR10_OFFSET]
+ str w6, [x2, #EPU_EPCTR10_OFFSET]
+ str w7, [x2, #EPU_EPGCR_OFFSET]
+
+ /*
+ * A-010194: There is logic problem
+ * in the path of GIC-to-PMU to issue
+ * wake request to core0
+ * Workaround: Re-target the wakeup interrupts
+ * to a core other than the last active core0
+ */
+ ldr x2, =NXP_GICD_ADDR
+
+ /* backup flextimer/mmc/usb interrupt router */
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ ldr w4, [x2, x0]
+ ldr w5, [x2, x1]
+ ldr x0, =GICD_IROUTER112_OFFSET
+ ldr x1, =GICD_IROUTER113_OFFSET
+ ldr w6, [x2, x0]
+ ldr w7, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = gicd base addr
+ * x0 = GICD_IROUTER112_OFFSET
+ * x1 = GICD_IROUTER113_OFFSET
+ */
+
+ /* re-route interrupt to cluster 1 */
+ ldr w4, =GICD_IROUTER_VALUE
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ dsb sy
+ isb
+
+ /* backup flextimer/mmc/usb interrupt enabler */
+ ldr x0, =GICD_ISENABLER_1
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ISENABLER_2
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ ldr x0, =GICD_ISENABLER_3
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ICENABLER_1
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ ldr x0, =GICD_ICENABLER_2
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ICENABLER_3
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ /* enable related interrupt routing */
+ ldr w4, =GICD_ISENABLER_1_VALUE
+ ldr x0, =GICD_ISENABLER_1
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ ldr w4, =GICD_ISENABLER_2_VALUE
+ ldr x0, =GICD_ISENABLER_2
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ ldr w4, =GICD_ISENABLER_3_VALUE
+ ldr x0, =GICD_ISENABLER_3
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ /* set POWMGTDCR [STP_PV_EN] = 1 */
+ ldr x2, =NXP_POWMGTDCR
+ ldr w4, =0x01
+ str w4, [x2]
+
+ /* program IPSTPCR for override stop request (except DDR) */
+ mov x3, #NXP_PMU_ADDR
+
+ /* build an override mask for IPSTPCR4/IPSTPACK4/DEVDISR5 */
+ ldr x2, =PMU_IPPDEXPCR4_OFFSET
+ ldr w7, [x3, x2]
+
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR4_MASK
+ and x6, x6, x7
+ cbz x6, 1f
+
+ /*
+ * x5 = override mask
+ * x6 = IPPDEXPCR bits for DEVDISR5
+ * x7 = IPPDEXPCR
+ */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR5_FLX_TMR
+ tst x6, #IPPDEXPCR_FLX_TMR
+ csel x5, x5, x4, EQ
+1:
+ /* store the DEVDISR5 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR5_MASK_OFFSET]
+
+ mov x3, #NXP_PMU_ADDR
+
+ /* write IPSTPCR0 - no overrides */
+ ldr x2, =PMU_IPSTPCR0_OFFSET
+ ldr w5, =IPSTPCR0_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR1 - no overrides */
+ ldr x2, =PMU_IPSTPCR1_OFFSET
+ ldr w5, =IPSTPCR1_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR2 - no overrides */
+ ldr x2, =PMU_IPSTPCR2_OFFSET
+ ldr w5, =IPSTPCR2_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR3 - no overrides */
+ ldr x2, =PMU_IPSTPCR3_OFFSET
+ ldr w5, =IPSTPCR3_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR4 - overrides possible */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ ldr w6, [x2, #DEVDISR5_MASK_OFFSET]
+ ldr x2, =PMU_IPSTPCR4_OFFSET
+ ldr w5, =IPSTPCR4_VALUE
+ bic x5, x5, x6
+ str w5, [x3, x2]
+
+ /* write IPSTPCR5 - no overrides */
+ ldr x2, =PMU_IPSTPCR5_OFFSET
+ ldr w5, =IPSTPCR5_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR6 - no overrides */
+ ldr x2, =PMU_IPSTPCR6_OFFSET
+ ldr w5, =IPSTPCR6_VALUE
+ str w5, [x3, x2]
+
+ /* poll IPSTPACK for IP stop acknowledgment (except DDR) */
+ mov x3, #NXP_PMU_ADDR
+
+ /* poll on IPSTPACK0 */
+ ldr x2, =PMU_IPSTPACK0_OFFSET
+ ldr x4, =IPSTPCR0_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+3:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 14f
+ sub x7, x7, #1
+ cbnz x7, 3b
+
+14:
+ /* poll on IPSTPACK1 */
+ ldr x2, =PMU_IPSTPACK1_OFFSET
+ ldr x4, =IPSTPCR1_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+4:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 15f
+ sub x7, x7, #1
+ cbnz x7, 4b
+
+15:
+ /* poll on IPSTPACK2 */
+ ldr x2, =PMU_IPSTPACK2_OFFSET
+ ldr x4, =IPSTPCR2_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+5:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 16f
+ sub x7, x7, #1
+ cbnz x7, 5b
+
+16:
+ /* poll on IPSTPACK3 */
+ ldr x2, =PMU_IPSTPACK3_OFFSET
+ ldr x4, =IPSTPCR3_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+6:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 17f
+ sub x7, x7, #1
+ cbnz x7, 6b
+
+17:
+ /* poll on IPSTPACK4 */
+ ldr x2, =PMU_IPSTPACK4_OFFSET
+ ldr x4, =IPSTPCR4_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+7:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 18f
+ sub x7, x7, #1
+ cbnz x7, 7b
+
+18:
+ /* poll on IPSTPACK5 */
+ ldr x2, =PMU_IPSTPACK5_OFFSET
+ ldr x4, =IPSTPCR5_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+8:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 19f
+ sub x7, x7, #1
+ cbnz x7, 8b
+
+19:
+ /* poll on IPSTPACK6 */
+ ldr x2, =PMU_IPSTPACK6_OFFSET
+ ldr x4, =IPSTPCR6_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+9:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 20f
+ sub x7, x7, #1
+ cbnz x7, 9b
+
+20:
+ /* save current DEVDISR states to DDR. */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* save DEVDISR1 and load new value */
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, [x2, x0]
+ mov w13, w1
+ ldr x1, =DEVDISR1_VALUE
+ str w1, [x2, x0]
+ /* save DEVDISR2 and load new value */
+ ldr x0, =DCFG_DEVDISR2_OFFSET
+ ldr w1, [x2, x0]
+ mov w14, w1
+ ldr x1, =DEVDISR2_VALUE
+ str w1, [x2, x0]
+
+ /* x6 = DEVDISR5 override mask */
+
+ /* save DEVDISR3 and load new value */
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, [x2, x0]
+ mov w15, w1
+ ldr x1, =DEVDISR3_VALUE
+ str w1, [x2, x0]
+
+ /* save DEVDISR4 and load new value */
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, [x2, x0]
+ mov w16, w1
+ /* not stop uart print */
+ ldr x1, =0x0000332
+ str w1, [x2, x0]
+
+ /* save DEVDISR5 and load new value */
+ ldr x0, =DCFG_DEVDISR5_OFFSET
+ ldr w1, [x2, x0]
+ mov w17, w1
+ /* Enable this wakeup will fail, should enable OCRAM */
+ ldr x1, =0x00102300
+ str w1, [x2, x0]
+
+ /* save DEVDISR6 and load new value */
+ ldr x0, =DCFG_DEVDISR6_OFFSET
+ ldr w1, [x2, x0]
+ mov w18, w1
+ ldr x1, =DEVDISR6_VALUE
+ str w1, [x2, x0]
+
+ /*
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ * w18 = DEVDISR6 saved value
+ */
+ /*
+ * A-009810: LPM20 entry sequence might cause
+ * spurious timeout reset request
+ * workaround: MASK RESET REQ RPTOE
+ */
+ ldr x0, =NXP_RESET_ADDR
+ ldr w1, =RSTRQMR_RPTOE_MASK
+ str w1, [x0, #RST_RSTRQMR1_OFFSET]
+
+ /* disable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, =DCFG_DEVDISR3_QBMAIN
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /*
+ * write the GICR_WAKER.ProcessorSleep bits to 1
+ * enable the WakeRequest signal
+ * x3 is cpu mask starting from cpu7
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ orr w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cmp w1, #GICR_WAKER_ASLEEP
+ b.ne 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* x3 = pmu base addr */
+
+ /* perform Icache Warming Sequence */
+ ldr x5, =IPSTPCR4_VALUE
+ mov x6, DDR_CNTRL_BASE_ADDR
+ mov x7, #NXP_PMU_ADDR
+ mov x8, #NXP_DCFG_ADDR
+ mov x10, #PMU_IPSTPCR4_OFFSET
+ mov x11, #PMU_IPSTPACK4_OFFSET
+ mov x12, #PMU_IPSTPCR3_OFFSET
+ mov x18, #PMU_IPSTPCR2_OFFSET
+ mov x19, #PMU_IPSTPCR1_OFFSET
+ mov x21, #PMU_IPSTPCR0_OFFSET
+ ldr x22, =DCFG_DEVDISR5_OFFSET
+ ldr x23, =NXP_EPU_ADDR
+ mov x9, #CORE_RESTARTABLE
+ bl final_pwrdown
+
+ /*
+ * disable the WakeRequest signal on cpu 0-7
+ * x3 is cpu mask starting from cpu7
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ bic w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cbnz w1, 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* set SGI for secondary core wakeup */
+ ldr x0, =0x1000002
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x2000004
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x3000008
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x4010001
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x5010002
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x6010004
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x7010008
+ msr S3_0_C12_C11_7, x0
+
+ /* enable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ str wzr, [x2, #DCFG_DEVDISR1_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR3_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR4_OFFSET]
+
+ /* clear POWMGTDCR [STP_PV_EN] */
+ ldr x2, =NXP_POWMGTDCR
+ ldr w4, [x2]
+ bic w4, w4, #0x01
+ str w4, [x2]
+
+ /* restore flextimer/mmc/usb interrupt enabler */
+ ldr x3, =NXP_GICD_ADDR
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ICENABLER_2
+ mvn w0, w0
+ str w0, [x3, x1]
+ ldr x1, =GICD_ICENABLER_3
+ mvn w2, w2
+ str w2, [x3, x1]
+
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ISENABLER_3
+ str w0, [x3, x1]
+ ldr x1, =GICD_ICENABLER_1
+ mvn w2, w2
+ str w0, [x3, x1]
+
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ISENABLER_1
+ str w0, [x3, x1]
+ ldr x1, =GICD_ISENABLER_2
+ str w0, [x3, x1]
+
+ /* restore flextimer/mmc/usb interrupt router */
+ ldr x3, =NXP_GICD_ADDR
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER113_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER112_OFFSET
+ str w0, [x3, x1]
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER60_OFFSET
+ str w0, [x3, x1]
+
+ /* restore EPU registers */
+ ldr x3, =NXP_EPU_ADDR
+ ldp x0, x2, [sp], #16
+ str w2, [x3, #EPU_EPGCR_OFFSET]
+ str w0, [x3, #EPU_EPCTR10_OFFSET]
+ ldp x2, x1, [sp], #16
+ str w1, [x3, #EPU_EPCCR10_OFFSET]
+ str w2, [x3, #EPU_EPIMCR10_OFFSET]
+
+ isb
+ /* Restor LR */
+ ldp x18, x30, [sp], #16
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_exit_pwrdn:
+ mrs x1, SCTLR_EL1
+ orr x1, x1, #SCTLR_I_MASK
+ msr SCTLR_EL1, x1
+ isb
+ ret
+
+/*
+ * this function checks to see if cores which are to be disabled have been
+ * released from reset - if not, it releases them
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8
+ */
+release_disabled:
+ mov x8, x30
+
+ /* read COREDISABLESR */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w4, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* get the number of cpus on this device */
+ mov x6, #PLATFORM_CORE_COUNT
+
+ mov x0, #NXP_RESET_ADDR
+ ldr w5, [x0, #BRR_OFFSET]
+
+ /* load the core mask for the first core */
+ mov x7, #1
+
+ /*
+ * x4 = COREDISABLESR
+ * x5 = BRR
+ * x6 = loop count
+ * x7 = core mask bit
+ */
+2:
+ /* check if the core is to be disabled */
+ tst x4, x7
+ b.eq 1f
+
+ /* see if disabled cores have already been released from reset */
+ tst x5, x7
+ b.ne 1f
+
+ /* if core has not been released, then release it (0-3) */
+ mov x0, x7
+ bl _soc_core_release
+
+ /* record the core state in the data area (0-3) */
+ mov x0, x7
+ mov x1, #CORE_DISABLED
+ bl _setCoreState
+
+1:
+ /* decrement the counter */
+ subs x6, x6, #1
+ b.le 3f
+
+ /* shift the core mask to the next core */
+ lsl x7, x7, #1
+ /* continue */
+ b 2b
+3:
+ mov x30, x8
+ ret
+
+/*
+ * write a register in the DCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * read a register in the DCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+_read_reg_dcfg:
+ ldr x1, =NXP_DCFG_ADDR
+ ldr w0, [x1, x0]
+ ret
+
+/*
+ * this function sets up the TrustZone Address Space Controller (TZASC)
+ * in: none
+ * out: none
+ * uses x0, x1
+ */
+init_tzpc:
+ /*
+ * set Non Secure access for all devices protected via TZPC
+ * decode Protection-0 Set Reg
+ */
+ ldr x1, =TZPCDECPROT_0_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-1 Set Reg */
+ ldr x1, =TZPCDECPROT_1_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-2 Set Reg */
+ ldr x1, =TZPCDECPROT_2_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /*
+ * entire SRAM as NS
+ * secure RAM region size Reg
+ */
+ ldr x1, =NXP_OCRAM_TZPC_ADDR
+ /* 0x00000000 = no secure region */
+ mov w0, #0x00000000
+ str w0, [x1]
+
+ ret
+
+/* this function performs initialization on SecMon for boot services */
+initSecMon:
+ /* read the register hpcomr */
+ ldr x1, =NXP_SNVS_ADDR
+ ldr w0, [x1, #SECMON_HPCOMR_OFFSET]
+ /* turn off secure access for the privileged registers */
+ orr w0, w0, #SECMON_HPCOMR_NPSWAEN
+ /* write back */
+ str w0, [x1, #SECMON_HPCOMR_OFFSET]
+
+ ret
+
+/*
+ * this function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor rd base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_rd_base:
+ /* get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+
+ ldr x0, =NXP_GICR_ADDR
+ mov x1, #GIC_RD_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * this function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor sgi base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_sgi_base:
+ /* get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+
+ ldr x0, =NXP_GICR_SGI_ADDR
+ mov x1, #GIC_SGI_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * this function returns an mpidr value for a core, given a core_mask_lsb
+ * in: x0 = core mask lsb
+ * out: x0 = affinity2:affinity1:affinity0, where affinity is 8-bits
+ * uses x0, x1
+ */
+get_mpidr_value:
+ /* convert a core mask to an SoC core number */
+ clz w0, w0
+ mov w1, #31
+ sub w0, w1, w0
+
+ /* w0 = SoC core number */
+
+ mov w1, wzr
+2:
+ cmp w0, #CORES_PER_CLUSTER
+ b.lt 1f
+ sub w0, w0, #CORES_PER_CLUSTER
+ add w1, w1, #MPIDR_CLUSTER
+ b 2b
+
+ /* insert the mpidr core number */
+1:
+ orr w0, w1, w0
+ ret
+
+/*
+ * write a register in the RESET block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_reset:
+ ldr x2, =NXP_RESET_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * read a register in the RESET block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+_read_reg_reset:
+ ldr x1, =NXP_RESET_ADDR
+ ldr w0, [x1, x0]
+ ret
+
+/*
+ * this function will pwrdown ddr and the final core - it will do this
+ * by loading itself into the icache and then executing from there
+ * in: x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = NXP_PMU_ADDR
+ * x8 = NXP_DCFG_ADDR
+ * x9 = 0, restartable
+ * = 1, non-restartable
+ * x10 = PMU_IPSTPCR4_OFFSET
+ * x11 = PMU_IPSTPACK4_OFFSET
+ * x12 = PMU_IPSTPCR3_OFFSET
+ * x18 = PMU_IPSTPCR2_OFFSET
+ * x19 = PMU_IPSTPCR1_OFFSET
+ * x21 = PMU_IPSTPCR0_OFFSET
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ * x22 = DCFG_DEVDISR5_OFFSET
+ * x23 = NXP_EPU_ADDR
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x13, x14, x15, x16, x17
+ * x10, x11, x12, x18, x19, x21, x22, x23
+ */
+
+final_pwrdown:
+ /* delay */
+ mov w4, #0xffffff
+554:
+ sub w4, w4, #1
+ cmp w4, #0
+ b.ge 554b
+
+ mov x0, xzr
+ b touch_line_0
+
+/* 4Kb aligned */
+.align 12
+start_line_0:
+ mov x0, #1
+ /* put ddr in self refresh - start */
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ orr w3, w3, w2
+ /* put ddr in self refresh - end */
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ nop
+ nop
+touch_line_0:
+ cbz x0, touch_line_1
+
+start_line_1:
+ /* quiesce ddr clocks - start */
+ orr w3, w5, #DCFG_DEVDISR5_MEM
+ mov w4, w3
+ /* quiesce ddr clocks - end */
+ str w4, [x7, x10]
+ mov w3, #DCFG_DEVDISR5_MEM
+ /* poll on ipstpack4 - start */
+ mov x2, #DDR_SLEEP_RETRY_CNT
+ nop
+ nop
+touch_line_1:
+ cbz x0, touch_line_2
+
+start_line_2:
+ /* x11 = PMU_IPSTPACK4_OFFSET */
+ ldr w1, [x7, x11]
+ tst w1, w3
+ b.ne 5f
+ subs x2, x2, #1
+ /* poll on ipstpack4 - end */
+ b.gt start_line_2
+
+ /* if we get here, we have a timeout err */
+ mov w4, w5
+ /* x10 = PMU_IPSTPCR4_OFFSET re-enable ddr clks interface */
+ str w4, [x7, x10]
+touch_line_2:
+ cbz x0, touch_line_3
+
+start_line_3:
+ /* load error code */
+ mov x0, #ERROR_DDR_SLEEP
+ b 2f
+5:
+ wfe
+ ldr w1, [x23, #EPU_EPCTR10_OFFSET]
+ cbz w1, 5b
+
+ mov w4, w5
+touch_line_3:
+ cbz x0, touch_line_4
+
+start_line_4:
+ /* re-enable ddr in devdisr5 */
+ str w4, [x8, x22]
+ /* re-enable ddr clk in ipstpcr4 */
+ str w4, [x7, x10]
+13:
+ /* poll on ipstpack4 - start */
+ ldr w1, [x7, x11]
+ tst w1, w3
+ b.eq 2f
+ nop
+ b 13b
+ /* poll on ipstpack4 - end */
+2:
+touch_line_4:
+ cbz x0, touch_line_5
+
+start_line_5:
+ /* take ddr out-of self refresh - start */
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ mov w4, w3
+ bic w4, w4, w2
+ mov w3, w4
+ /* wait for ddr cntrlr clock- start */
+ mov x1, #DDR_SLEEP_RETRY_CNT
+3:
+ subs x1, x1, #1
+touch_line_5:
+ cbz x0, touch_line_6
+
+start_line_6:
+ /* wait for ddr cntrlr clock - end */
+ b.gt 3b
+ /* take ddr out-of self refresh - end */
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ mov w1, w17
+ /* reset devdisr5 */
+ str w1, [x8, #DCFG_DEVDISR5_OFFSET]
+ mov w1, w16
+ /* reset devdisr4 */
+ str w1, [x8, #DCFG_DEVDISR4_OFFSET]
+ mov w1, w15
+touch_line_6:
+ cbz x0, touch_line_7
+
+start_line_7:
+ /* reset devdisr3 */
+ str w1, [x8, #DCFG_DEVDISR3_OFFSET]
+ mov w1, w14
+ /* reset devdisr2 */
+ str w1, [x8, #DCFG_DEVDISR2_OFFSET]
+ mov w1, w13
+ /* reset devdisr1 */
+ str w1, [x8, #DCFG_DEVDISR1_OFFSET]
+ /* reset ipstpcr4 */
+ str wzr, [x7, x10]
+ /* reset ipstpcr3 */
+ str wzr, [x7, x12]
+touch_line_7:
+ cbz x0, touch_line_8
+
+start_line_8:
+ /* reset ipstpcr2 */
+ str wzr, [x7, x18]
+ /* reset ipstpcr1 */
+ str wzr, [x7, x19]
+ /* reset ipstpcr0 */
+ str wzr, [x7, x21]
+
+touch_line_8:
+ cbz x0, touch_line_9
+
+start_line_9:
+ b continue_restart
+touch_line_9:
+ cbz x0, start_line_0
+
+/* execute here after ddr is back up */
+continue_restart:
+ /*
+ * if x0 = 1, all is well
+ * if x0 < 1, we had an error
+ */
+ cmp x0, #1
+ b.ne 4f
+ mov x0, #0
+4:
+ ret
diff --git a/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S b/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S
new file mode 100644
index 0000000..890cf81
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl plat_reset_handler
+ .globl platform_mem_init
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func apply_platform_errata
+ ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+ mov x29, x30
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the sACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ mov x30, x29
+ ret
+endfunc plat_reset_handler
+
+ /*
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* ls1088a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+ /*
+ * unsigned int plat_is_my_cpu_primary (void);
+ *
+ * Find out whether the current cpu is the primary
+ * cpu.
+ */
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary