/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #if IMAGE_BL31 #include #endif #include #include /* Reset fn is needed in BL at reset vector */ #if IMAGE_BL1 || IMAGE_BL31 /* * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler * in the cpu_ops is invoked. * Clobbers: x0 - x19, x30 */ .globl reset_handler func reset_handler mov x19, x30 /* The plat_reset_handler can clobber x0 - x18, x30 */ bl plat_reset_handler /* Get the matching cpu_ops pointer */ bl get_cpu_ops_ptr #if ASM_ASSERTION cmp x0, #0 ASM_ASSERT(ne) #endif /* Get the cpu_ops reset handler */ ldr x2, [x0, #CPU_RESET_FUNC] mov x30, x19 cbz x2, 1f /* The cpu_ops reset handler can clobber x0 - x19, x30 */ br x2 1: ret endfunc reset_handler #endif /* IMAGE_BL1 || IMAGE_BL31 */ #if IMAGE_BL31 /* The power down core and cluster is needed only in BL31 */ /* * void prepare_cpu_pwr_dwn(unsigned int power_level) * * Prepare CPU power down function for all platforms. The function takes * a domain level to be powered down as its parameter. After the cpu_ops * pointer is retrieved from cpu_data, the handler for requested power * level is called. */ .globl prepare_cpu_pwr_dwn func prepare_cpu_pwr_dwn /* * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the * power down handler for the last power level */ mov_imm x2, (CPU_MAX_PWR_DWN_OPS - 1) cmp x0, x2 csel x2, x2, x0, hi mrs x1, tpidr_el3 ldr x0, [x1, #CPU_DATA_CPU_OPS_PTR] #if ASM_ASSERTION cmp x0, #0 ASM_ASSERT(ne) #endif /* Get the appropriate power down handler */ mov x1, #CPU_PWR_DWN_OPS add x1, x1, x2, lsl #3 ldr x1, [x0, x1] br x1 endfunc prepare_cpu_pwr_dwn /* * Initializes the cpu_ops_ptr if not already initialized * in cpu_data. This can be called without a runtime stack, but may * only be called after the MMU is enabled. * clobbers: x0 - x6, x10 */ .globl init_cpu_ops func init_cpu_ops mrs x6, tpidr_el3 ldr x0, [x6, #CPU_DATA_CPU_OPS_PTR] cbnz x0, 1f mov x10, x30 bl get_cpu_ops_ptr #if ASM_ASSERTION cmp x0, #0 ASM_ASSERT(ne) #endif str x0, [x6, #CPU_DATA_CPU_OPS_PTR]! mov x30, x10 1: ret endfunc init_cpu_ops #endif /* IMAGE_BL31 */ #if IMAGE_BL31 && CRASH_REPORTING /* * The cpu specific registers which need to be reported in a crash * are reported via cpu_ops cpu_reg_dump function. After a matching * cpu_ops structure entry is found, the correponding cpu_reg_dump * in the cpu_ops is invoked. */ .globl do_cpu_reg_dump func do_cpu_reg_dump mov x16, x30 /* Get the matching cpu_ops pointer */ bl get_cpu_ops_ptr cbz x0, 1f /* Get the cpu_ops cpu_reg_dump */ ldr x2, [x0, #CPU_REG_DUMP] cbz x2, 1f blr x2 1: mov x30, x16 ret endfunc do_cpu_reg_dump #endif /* * The below function returns the cpu_ops structure matching the * midr of the core. It reads the MIDR_EL1 and finds the matching * entry in cpu_ops entries. Only the implementation and part number * are used to match the entries. * Return : * x0 - The matching cpu_ops pointer on Success * x0 - 0 on failure. * Clobbers : x0 - x5 */ .globl get_cpu_ops_ptr func get_cpu_ops_ptr /* Get the cpu_ops start and end locations */ adr x4, (__CPU_OPS_START__ + CPU_MIDR) adr x5, (__CPU_OPS_END__ + CPU_MIDR) /* Initialize the return parameter */ mov x0, #0 /* Read the MIDR_EL1 */ mrs x2, midr_el1 mov_imm x3, CPU_IMPL_PN_MASK /* Retain only the implementation and part number using mask */ and w2, w2, w3 1: /* Check if we have reached end of list */ cmp x4, x5 b.eq error_exit /* load the midr from the cpu_ops */ ldr x1, [x4], #CPU_OPS_SIZE and w1, w1, w3 /* Check if midr matches to midr of this core */ cmp w1, w2 b.ne 1b /* Subtract the increment and offset to get the cpu-ops pointer */ sub x0, x4, #(CPU_OPS_SIZE + CPU_MIDR) error_exit: ret endfunc get_cpu_ops_ptr #if LOG_LEVEL >= LOG_LEVEL_VERBOSE .section .rodata.rev_verbose_str, "aS" rev_verbose_str: .asciz "VERBOSE: Skipping CPU specific reset operation for non-matching CPU revision number.\n" /* * This function prints the above warning message to the crash console. * It should be called when a CPU specific operation is enabled in the * build but doesn't apply to this CPU revision/part number. * * Clobber: x30, x0 - x5 */ .globl print_revision_warning func print_revision_warning mov x5, x30 /* Ensure the console is initialized */ bl plat_crash_console_init /* Check if the console is initialized */ cbz x0, 1f /* The console is initialized */ adr x4, rev_verbose_str bl asm_print_str 1: ret x5 endfunc print_revision_warning #endif