/* * Copyright 2020-2022 NXP * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include #include #include #include #include #include #include #define DAIF_DATA AUX_01_DATA #define TIMER_CNTRL_DATA AUX_02_DATA .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_set_start_addr .global _getGICC_BaseAddr .global _getGICD_BaseAddr .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 /* This function initialize the soc * in: void * out: void */ func soc_init_lowlevel 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 mov x3, x30 bl plat_my_core_mask mov x2, x0 /* see if this core is marked for prefetch disable */ mov x0, #PREFETCH_DIS_OFFSET bl _get_global_data /* 0-1 */ tst x0, x2 b.eq 1f bl _disable_ldstr_pfetch_A72 /* 0 */ 1: mov x30, x3 ret endfunc soc_init_percpu /* part of CPU_ON * this function releases a secondary core from reset * in: x0 = core_mask_lsb * out: none * uses: x0, x1, x2, x3 */ func _soc_core_release #if (TEST_BL31) rbit w2, w0 /* x2 = core mask msb */ #else mov x2, x0 #endif /* write COREBCR */ mov x1, #NXP_SCFG_ADDR rev w3, w2 str w3, [x1, #SCFG_COREBCR_OFFSET] isb /* read-modify-write BRR */ mov x1, #NXP_DCFG_ADDR ldr w2, [x1, #DCFG_BRR_OFFSET] rev w3, w2 orr w3, w3, w0 rev w2, w3 str w2, [x1, #DCFG_BRR_OFFSET] isb /* send event */ sev isb ret endfunc _soc_core_release /* 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 */ func _soc_core_restart mov x5, x30 mov x3, x0 /* * unset ph20 request in RCPM_PCPH20CLEARR * this is an lsb-0 register */ ldr x1, =NXP_RCPM_ADDR rev w2, w3 str w2, [x1, #RCPM_PCPH20CLRR_OFFSET] dsb sy isb bl _getGICD_BaseAddr mov x4, x0 /* enable forwarding of group 0 interrupts by setting GICD_CTLR[0] = 1 */ ldr w1, [x4, #GICD_CTLR_OFFSET] orr w1, w1, #GICD_CTLR_EN_GRP0 str w1, [x4, #GICD_CTLR_OFFSET] dsb sy isb /* * fire SGI by writing to GICD_SGIR the following values: * [25:24] = 0x0 (forward interrupt to the CPU interfaces * specified in CPUTargetList field) * [23:16] = core mask lsb[7:0] (forward interrupt to target cpu) * [15] = 0 (forward SGI only if it is configured as group 0 interrupt) * [3:0] = 0xF (interrupt ID = 15) */ lsl w1, w3, #16 orr w1, w1, #0xF str w1, [x4, #GICD_SGIR_OFFSET] dsb sy isb /* load '0' on success */ mov x0, xzr mov x30, x5 ret endfunc _soc_core_restart /* * This function determines if a core is disabled via COREDISR * in: w0 = core_mask_lsb * out: w0 = 0, core not disabled * w0 != 0, core disabled * uses x0, x1, x2 */ func _soc_ck_disabled /* get base addr of dcfg block */ mov x1, #NXP_DCFG_ADDR /* read COREDISR */ ldr w1, [x1, #DCFG_COREDISR_OFFSET] rev w2, w1 /* test core bit */ and w0, w2, w0 ret endfunc _soc_ck_disabled /* *This function resets the system via SoC-specific methods * in: none * out: none * uses x0, x1, x2, x3 */ func _soc_sys_reset ldr x2, =NXP_DCFG_ADDR /* make sure the mask is cleared in the reset request mask register */ mov w1, wzr str w1, [x2, #DCFG_RSTRQMR1_OFFSET] /* set the reset request */ ldr w1, =RSTCR_RESET_REQ ldr x3, =DCFG_RSTCR_OFFSET rev w0, w1 str w0, [x2, x3] /* * just in case this address range is mapped as cacheable, * flush the write out of the dcaches */ add x3, x2, x3 dc cvac, x3 dsb st isb /* Note: this function does not return */ 1: wfi b 1b endfunc _soc_sys_reset /* * Part of SYSTEM_OFF * this function turns off the SoC clocks * Note: this function is not intended to return, and the only allowable * recovery is POR * in: none * out: none * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 */ func _soc_sys_off /* mask interrupts at the core */ mrs x1, DAIF mov x0, #DAIF_SET_MASK orr x0, x1, x0 msr DAIF, 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 dcache for EL3 */ mrs x1, SCTLR_EL3 bic x1, x1, #SCTLR_C_MASK /* make sure icache is enabled */ orr x1, x1, #SCTLR_I_MASK msr SCTLR_EL3, x1 isb /* Enable dynamic retention ctrl (CPUECTLR[2:0]) and SMP (CPUECTLR[6]) */ mrs x0, CORTEX_A72_ECTLR_EL1 orr x0, x0, #CPUECTLR_TIMER_8TICKS orr x0, x0, #CPUECTLR_SMPEN_EN msr CORTEX_A72_ECTLR_EL1, x0 /* set WFIL2EN in SCFG_CLUSTERPMCR */ ldr x0, =SCFG_COREPMCR_OFFSET ldr x1, =COREPMCR_WFIL2 bl write_reg_scfg /* request LPM20 */ mov x0, #RCPM_POWMGTCSR_OFFSET bl read_reg_rcpm orr x1, x0, #RCPM_POWMGTCSR_LPM20_REQ mov x0, #RCPM_POWMGTCSR_OFFSET bl write_reg_rcpm dsb sy isb 1: wfi b 1b endfunc _soc_sys_off /* * Write a register in the RCPM block * in: x0 = offset * in: w1 = value to write * uses x0, x1, x2, x3 */ func write_reg_rcpm ldr x2, =NXP_RCPM_ADDR /* swap for BE */ rev w3, w1 str w3, [x2, x0] ret endfunc write_reg_rcpm /* * Read a register in the RCPM block * in: x0 = offset * out: w0 = value read * uses x0, x1, x2 */ func read_reg_rcpm ldr x2, =NXP_RCPM_ADDR ldr w1, [x2, x0] /* swap for BE */ rev w0, w1 ret endfunc read_reg_rcpm /* * Write a register in the SCFG block * in: x0 = offset * in: w1 = value to write * uses x0, x1, x2, x3 */ func write_reg_scfg mov x2, #NXP_SCFG_ADDR /* swap for BE */ rev w3, w1 str w3, [x2, x0] ret endfunc write_reg_scfg /* * Read a register in the SCFG block * in: x0 = offset * out: w0 = value read * uses x0, x1, x2 */ func read_reg_scfg mov x2, #NXP_SCFG_ADDR ldr w1, [x2, x0] /* swap for BE */ rev w0, w1 ret endfunc read_reg_scfg /* * 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 */ func _soc_core_prep_off mov x7, x30 mov x6, x0 /* Set retention control in CPUECTLR make sure smpen bit is set */ mrs x4, CORTEX_A72_ECTLR_EL1 bic x4, x4, #CPUECTLR_RET_MASK orr x4, x4, #CPUECTLR_TIMER_8TICKS orr x4, x4, #CPUECTLR_SMPEN_EN msr CORTEX_A72_ECTLR_EL1, x4 /* save timer control current value */ mov x5, #NXP_TIMER_ADDR ldr w4, [x5, #SYS_COUNTER_CNTCR_OFFSET] mov w2, w4 mov x0, x6 mov x1, #TIMER_CNTRL_DATA bl _setCoreData /* enable the timer */ orr w4, w4, #CNTCR_EN_MASK str w4, [x5, #SYS_COUNTER_CNTCR_OFFSET] bl _getGICC_BaseAddr mov x5, x0 /* disable signaling of ints */ ldr w3, [x5, #GICC_CTLR_OFFSET] bic w3, w3, #GICC_CTLR_EN_GRP0 bic w3, w3, #GICC_CTLR_EN_GRP1 str w3, [x5, #GICC_CTLR_OFFSET] dsb sy isb /* * set retention control in SCFG_RETREQCR * Note: this register is msb 0 */ ldr x4, =SCFG_RETREQCR_OFFSET mov x0, x4 bl read_reg_scfg rbit w1, w6 orr w1, w0, w1 mov x0, x4 bl write_reg_scfg /* set the priority filter */ ldr w2, [x5, #GICC_PMR_OFFSET] orr w2, w2, #GICC_PMR_FILTER str w2, [x5, #GICC_PMR_OFFSET] /* setup GICC_CTLR */ bic w3, w3, #GICC_CTLR_ACKCTL_MASK orr w3, w3, #GICC_CTLR_FIQ_EN_MASK orr w3, w3, #GICC_CTLR_EOImodeS_MASK orr w3, w3, #GICC_CTLR_CBPR_MASK str w3, [x5, #GICC_CTLR_OFFSET] /* setup the banked-per-core GICD registers */ bl _getGICD_BaseAddr mov x5, x0 /* define SGI15 as Grp0 */ ldr w2, [x5, #GICD_IGROUPR0_OFFSET] bic w2, w2, #GICD_IGROUP0_SGI15 str w2, [x5, #GICD_IGROUPR0_OFFSET] /* set priority of SGI 15 to highest... */ ldr w2, [x5, #GICD_IPRIORITYR3_OFFSET] bic w2, w2, #GICD_IPRIORITY_SGI15_MASK str w2, [x5, #GICD_IPRIORITYR3_OFFSET] /* enable SGI 15 */ ldr w2, [x5, #GICD_ISENABLER0_OFFSET] orr w2, w2, #GICD_ISENABLE0_SGI15 str w2, [x5, #GICD_ISENABLER0_OFFSET] /* enable the cpu interface */ bl _getGICC_BaseAddr mov x2, x0 orr w3, w3, #GICC_CTLR_EN_GRP0 str w3, [x2, #GICC_CTLR_OFFSET] /* clear any pending SGIs */ ldr x2, =GICD_CPENDSGIR_CLR_MASK add x0, x5, #GICD_CPENDSGIR3_OFFSET str w2, [x0] /* * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR * this is an lsb-0 register */ mov x1, x6 mov x0, #RCPM_PCPH20SETR_OFFSET bl write_reg_rcpm dsb sy isb mov x30, x7 ret endfunc _soc_core_prep_off /* * 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 */ func _soc_core_entr_off mov x5, x30 mov x4, x0 bl _getGICD_BaseAddr mov x3, x0 3: /* enter low-power state by executing wfi */ wfi /* see if we got hit by SGI 15 */ add x0, x3, #GICD_SPENDSGIR3_OFFSET ldr w2, [x0] and w2, w2, #GICD_SPENDSGIR3_SGI15_MASK cbz w2, 4f /* clear the pending SGI */ ldr x2, =GICD_CPENDSGIR_CLR_MASK add x0, x3, #GICD_CPENDSGIR3_OFFSET str w2, [x0] 4: /* check if core has been turned on */ mov x0, x4 bl _getCoreState cmp x0, #CORE_WAKEUP b.ne 3b /* if we get here, then we have exited the wfi */ dsb sy isb mov x30, x5 ret endfunc _soc_core_entr_off /* * 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 */ func _soc_core_exit_off mov x6, x30 mov x5, x0 /* * Clear ph20 request in RCPM_PCPH20CLRR - no need * to do that here, it has been done in _soc_core_restart */ bl _getGICC_BaseAddr mov x1, x0 /* read GICC_IAR */ ldr w0, [x1, #GICC_IAR_OFFSET] /* write GICC_EIOR - signal end-of-interrupt */ str w0, [x1, #GICC_EOIR_OFFSET] /* write GICC_DIR - disable interrupt */ str w0, [x1, #GICC_DIR_OFFSET] /* disable signaling of grp0 ints */ ldr w3, [x1, #GICC_CTLR_OFFSET] bic w3, w3, #GICC_CTLR_EN_GRP0 str w3, [x1, #GICC_CTLR_OFFSET] /* * Unset retention request in SCFG_RETREQCR * Note: this register is msb-0 */ ldr x4, =SCFG_RETREQCR_OFFSET mov x0, x4 bl read_reg_scfg rbit w1, w5 bic w1, w0, w1 mov x0, x4 bl write_reg_scfg /* restore timer ctrl */ mov x0, x5 mov x1, #TIMER_CNTRL_DATA bl _getCoreData /* w0 = timer ctrl saved value */ mov x2, #NXP_TIMER_ADDR str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET] dsb sy isb mov x30, x6 ret endfunc _soc_core_exit_off /* * Function loads a 64-bit execution address of the core in the soc registers * BOOTLOCPTRL/H * in: x0, 64-bit address to write to BOOTLOCPTRL/H * uses x0, x1, x2, x3 */ func _soc_set_start_addr /* get the 64-bit base address of the scfg block */ ldr x2, =NXP_SCFG_ADDR /* write the 32-bit BOOTLOCPTRL register */ mov x1, x0 rev w3, w1 str w3, [x2, #SCFG_BOOTLOCPTRL_OFFSET] /* write the 32-bit BOOTLOCPTRH register */ lsr x1, x0, #32 rev w3, w1 str w3, [x2, #SCFG_BOOTLOCPTRH_OFFSET] ret endfunc _soc_set_start_addr /* * This function returns the base address of the gic distributor * in: none * out: x0 = base address of gic distributor * uses x0 */ func _getGICD_BaseAddr #if (TEST_BL31) /* defect in simulator - gic base addresses are on 4Kb boundary */ ldr x0, =NXP_GICD_4K_ADDR #else ldr x0, =NXP_GICD_64K_ADDR #endif ret endfunc _getGICD_BaseAddr /* * This function returns the base address of the gic controller * in: none * out: x0 = base address of gic controller * uses x0 */ func _getGICC_BaseAddr #if (TEST_BL31) /* defect in simulator - gic base addresses are on 4Kb boundary */ ldr x0, =NXP_GICC_4K_ADDR #else ldr x0, =NXP_GICC_64K_ADDR #endif ret endfunc _getGICC_BaseAddr /* * Part of CPU_SUSPEND * this function puts the calling core into standby state * in: x0 = core mask lsb * out: none * uses x0 */ func _soc_core_entr_stdby dsb sy isb wfi ret endfunc _soc_core_entr_stdby /* * Part of CPU_SUSPEND * this function performs SoC-specific programming prior to standby * in: x0 = core mask lsb * out: none * uses x0, x1 */ func _soc_core_prep_stdby /* clear CORTEX_A72_ECTLR_EL1[2:0] */ mrs x1, CORTEX_A72_ECTLR_EL1 bic x1, x1, #CPUECTLR_TIMER_MASK msr CORTEX_A72_ECTLR_EL1, x1 ret endfunc _soc_core_prep_stdby /* * Part of CPU_SUSPEND * this function performs any SoC-specific cleanup after standby state * in: x0 = core mask lsb * out: none * uses none */ func _soc_core_exit_stdby ret endfunc _soc_core_exit_stdby /* * 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, x4, x5 */ func _soc_core_prep_pwrdn mov x5, x30 mov x4, x0 /* enable CPU retention + set smp */ mrs x1, CORTEX_A72_ECTLR_EL1 orr x1, x1, #0x1 orr x1, x1, #CPUECTLR_SMPEN_MASK msr CORTEX_A72_ECTLR_EL1, x1 /* * set the retention request in SCFG_RETREQCR * this is an msb-0 register */ ldr x3, =SCFG_RETREQCR_OFFSET mov x0, x3 bl read_reg_scfg rbit w1, w4 orr w1, w0, w1 mov x0, x3 bl write_reg_scfg /* * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR * this is an lsb-0 register */ mov x1, x4 mov x0, #RCPM_PCPH20SETR_OFFSET bl write_reg_rcpm mov x30, x5 ret endfunc _soc_core_prep_pwrdn /* * Part of CPU_SUSPEND * this function puts the calling core into a power-down state * in: x0 = core mask lsb * out: none * uses x0 */ func _soc_core_entr_pwrdn dsb sy isb wfi ret endfunc _soc_core_entr_pwrdn /* * Part of CPU_SUSPEND * this function cleans up after a core exits power-down * in: x0 = core mask lsb * out: none * uses x0, x1, x2, x3, x4, x5 */ func _soc_core_exit_pwrdn mov x5, x30 mov x4, x0 /* * Set the PC_PH20_REQ bit in RCPM_PCPH20CLRR * this is an lsb-0 register */ mov x1, x4 mov x0, #RCPM_PCPH20CLRR_OFFSET bl write_reg_rcpm /* * Unset the retention request in SCFG_RETREQCR * this is an msb-0 register */ ldr x3, =SCFG_RETREQCR_OFFSET mov x0, x3 bl read_reg_scfg rbit w1, w4 bic w1, w0, w1 mov x0, x3 bl write_reg_scfg mov x30, x5 ret endfunc _soc_core_exit_pwrdn /* * Part of CPU_SUSPEND * this function performs SoC-specific programming prior to standby * in: x0 = core mask lsb * out: none * uses none */ func _soc_clstr_prep_stdby /* clear CORTEX_A72_ECTLR_EL1[2:0] */ mrs x1, CORTEX_A72_ECTLR_EL1 bic x1, x1, #CPUECTLR_TIMER_MASK msr CORTEX_A72_ECTLR_EL1, x1 ret endfunc _soc_clstr_prep_stdby /* * Part of CPU_SUSPEND * this function performs any SoC-specific cleanup after standby state * in: x0 = core mask lsb * out: none * uses none */ func _soc_clstr_exit_stdby ret endfunc _soc_clstr_exit_stdby /* * 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, x4, x5 */ func _soc_clstr_prep_pwrdn mov x5, x30 mov x4, x0 /* enable CPU retention + set smp */ mrs x1, CORTEX_A72_ECTLR_EL1 orr x1, x1, #0x1 orr x1, x1, #CPUECTLR_SMPEN_MASK msr CORTEX_A72_ECTLR_EL1, x1 /* * Set the retention request in SCFG_RETREQCR * this is an msb-0 register. */ ldr x3, =SCFG_RETREQCR_OFFSET mov x0, x3 bl read_reg_scfg rbit w1, w4 orr w1, w0, w1 mov x0, x3 bl write_reg_scfg /* * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR * this is an lsb-0 register. */ mov x1, x4 mov x0, #RCPM_PCPH20SETR_OFFSET bl write_reg_rcpm mov x30, x5 ret endfunc _soc_clstr_prep_pwrdn /* * Part of CPU_SUSPEND * this function cleans up after a core exits power-down * in: x0 = core mask lsb * out: none * uses x0, x1, x2, x3, x4, x5 */ func _soc_clstr_exit_pwrdn mov x5, x30 mov x4, x0 /* * Set the PC_PH20_REQ bit in RCPM_PCPH20CLRR * this is an lsb-0 register. */ mov x1, x4 mov x0, #RCPM_PCPH20CLRR_OFFSET bl write_reg_rcpm /* * Unset the retention request in SCFG_RETREQCR * this is an msb-0 register. */ ldr x3, =SCFG_RETREQCR_OFFSET mov x0, x3 bl read_reg_scfg rbit w1, w4 bic w1, w0, w1 mov x0, x3 bl write_reg_scfg mov x30, x5 ret endfunc _soc_clstr_exit_pwrdn /* * Part of CPU_SUSPEND * this function performs SoC-specific programming prior to standby * in: x0 = core mask lsb * out: none * uses none */ func _soc_sys_prep_stdby /* clear CORTEX_A72_ECTLR_EL1[2:0] */ mrs x1, CORTEX_A72_ECTLR_EL1 bic x1, x1, #CPUECTLR_TIMER_MASK msr CORTEX_A72_ECTLR_EL1, x1 ret endfunc _soc_sys_prep_stdby /* Part of CPU_SUSPEND * this function performs any SoC-specific cleanup after standby state * in: x0 = core mask lsb * out: none * uses none */ func _soc_sys_exit_stdby ret endfunc _soc_sys_exit_stdby /* * 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, x1, x2, x3, x4 */ func _soc_sys_prep_pwrdn mov x4, x30 /* Enable dynamic retention contrl (CPUECTLR[2:0]) and SMP (CPUECTLR[6]) */ mrs x0, CORTEX_A72_ECTLR_EL1 bic x0, x0, #CPUECTLR_TIMER_MASK orr x0, x0, #CPUECTLR_TIMER_8TICKS orr x0, x0, #CPUECTLR_SMPEN_EN msr CORTEX_A72_ECTLR_EL1, x0 /* Set WFIL2EN in SCFG_CLUSTERPMCR */ ldr x0, =SCFG_COREPMCR_OFFSET ldr x1, =COREPMCR_WFIL2 bl write_reg_scfg isb mov x30, x4 ret endfunc _soc_sys_prep_pwrdn /* * 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 */ func _soc_sys_pwrdn_wfi mov x4, x30 /* request LPM20 */ mov x0, #RCPM_POWMGTCSR_OFFSET bl read_reg_rcpm orr x1, x0, #RCPM_POWMGTCSR_LPM20_REQ mov x0, #RCPM_POWMGTCSR_OFFSET bl write_reg_rcpm dsb sy isb wfi mov x30, x4 ret endfunc _soc_sys_pwrdn_wfi /* * Part of CPU_SUSPEND * this function performs any SoC-specific cleanup after power-down * in: x0 = core mask lsb * out: none * uses x0, x1 */ func _soc_sys_exit_pwrdn /* clear WFIL2_EN in SCFG_COREPMCR */ mov x1, #NXP_SCFG_ADDR str wzr, [x1, #SCFG_COREPMCR_OFFSET] ret endfunc _soc_sys_exit_pwrdn