Home | History | Annotate | Download | only in aarch64
      1 /*
      2  * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch.h>
      8 #include <asm_macros.S>
      9 #include <assert_macros.S>
     10 #ifdef IMAGE_BL31
     11 #include <cpu_data.h>
     12 #endif
     13 #include <cpu_macros.S>
     14 #include <debug.h>
     15 #include <errata_report.h>
     16 
     17  /* Reset fn is needed in BL at reset vector */
     18 #if defined(IMAGE_BL1) || defined(IMAGE_BL31)
     19 	/*
     20 	 * The reset handler common to all platforms.  After a matching
     21 	 * cpu_ops structure entry is found, the correponding reset_handler
     22 	 * in the cpu_ops is invoked.
     23 	 * Clobbers: x0 - x19, x30
     24 	 */
     25 	.globl	reset_handler
     26 func reset_handler
     27 	mov	x19, x30
     28 
     29 	/* The plat_reset_handler can clobber x0 - x18, x30 */
     30 	bl	plat_reset_handler
     31 
     32 	/* Get the matching cpu_ops pointer */
     33 	bl	get_cpu_ops_ptr
     34 #if ENABLE_ASSERTIONS
     35 	cmp	x0, #0
     36 	ASM_ASSERT(ne)
     37 #endif
     38 
     39 	/* Get the cpu_ops reset handler */
     40 	ldr	x2, [x0, #CPU_RESET_FUNC]
     41 	mov	x30, x19
     42 	cbz	x2, 1f
     43 
     44 	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
     45 	br	x2
     46 1:
     47 	ret
     48 endfunc reset_handler
     49 
     50 #endif /* IMAGE_BL1 || IMAGE_BL31 */
     51 
     52 #ifdef IMAGE_BL31 /* The power down core and cluster is needed only in  BL31 */
     53 	/*
     54 	 * void prepare_cpu_pwr_dwn(unsigned int power_level)
     55 	 *
     56 	 * Prepare CPU power down function for all platforms. The function takes
     57 	 * a domain level to be powered down as its parameter. After the cpu_ops
     58 	 * pointer is retrieved from cpu_data, the handler for requested power
     59 	 * level is called.
     60 	 */
     61 	.globl	prepare_cpu_pwr_dwn
     62 func prepare_cpu_pwr_dwn
     63 	/*
     64 	 * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the
     65 	 * power down handler for the last power level
     66 	 */
     67 	mov_imm	x2, (CPU_MAX_PWR_DWN_OPS - 1)
     68 	cmp	x0, x2
     69 	csel	x2, x2, x0, hi
     70 
     71 	mrs	x1, tpidr_el3
     72 	ldr	x0, [x1, #CPU_DATA_CPU_OPS_PTR]
     73 #if ENABLE_ASSERTIONS
     74 	cmp	x0, #0
     75 	ASM_ASSERT(ne)
     76 #endif
     77 
     78 	/* Get the appropriate power down handler */
     79 	mov	x1, #CPU_PWR_DWN_OPS
     80 	add	x1, x1, x2, lsl #3
     81 	ldr	x1, [x0, x1]
     82 	br	x1
     83 endfunc prepare_cpu_pwr_dwn
     84 
     85 
     86 	/*
     87 	 * Initializes the cpu_ops_ptr if not already initialized
     88 	 * in cpu_data. This can be called without a runtime stack, but may
     89 	 * only be called after the MMU is enabled.
     90 	 * clobbers: x0 - x6, x10
     91 	 */
     92 	.globl	init_cpu_ops
     93 func init_cpu_ops
     94 	mrs	x6, tpidr_el3
     95 	ldr	x0, [x6, #CPU_DATA_CPU_OPS_PTR]
     96 	cbnz	x0, 1f
     97 	mov	x10, x30
     98 	bl	get_cpu_ops_ptr
     99 #if ENABLE_ASSERTIONS
    100 	cmp	x0, #0
    101 	ASM_ASSERT(ne)
    102 #endif
    103 	str	x0, [x6, #CPU_DATA_CPU_OPS_PTR]!
    104 	mov x30, x10
    105 1:
    106 	ret
    107 endfunc init_cpu_ops
    108 #endif /* IMAGE_BL31 */
    109 
    110 #if defined(IMAGE_BL31) && CRASH_REPORTING
    111 	/*
    112 	 * The cpu specific registers which need to be reported in a crash
    113 	 * are reported via cpu_ops cpu_reg_dump function. After a matching
    114 	 * cpu_ops structure entry is found, the correponding cpu_reg_dump
    115 	 * in the cpu_ops is invoked.
    116 	 */
    117 	.globl	do_cpu_reg_dump
    118 func do_cpu_reg_dump
    119 	mov	x16, x30
    120 
    121 	/* Get the matching cpu_ops pointer */
    122 	bl	get_cpu_ops_ptr
    123 	cbz	x0, 1f
    124 
    125 	/* Get the cpu_ops cpu_reg_dump */
    126 	ldr	x2, [x0, #CPU_REG_DUMP]
    127 	cbz	x2, 1f
    128 	blr	x2
    129 1:
    130 	mov	x30, x16
    131 	ret
    132 endfunc do_cpu_reg_dump
    133 #endif
    134 
    135 	/*
    136 	 * The below function returns the cpu_ops structure matching the
    137 	 * midr of the core. It reads the MIDR_EL1 and finds the matching
    138 	 * entry in cpu_ops entries. Only the implementation and part number
    139 	 * are used to match the entries.
    140 	 * Return :
    141 	 *     x0 - The matching cpu_ops pointer on Success
    142 	 *     x0 - 0 on failure.
    143 	 * Clobbers : x0 - x5
    144 	 */
    145 	.globl	get_cpu_ops_ptr
    146 func get_cpu_ops_ptr
    147 	/* Get the cpu_ops start and end locations */
    148 	adr	x4, (__CPU_OPS_START__ + CPU_MIDR)
    149 	adr	x5, (__CPU_OPS_END__ + CPU_MIDR)
    150 
    151 	/* Initialize the return parameter */
    152 	mov	x0, #0
    153 
    154 	/* Read the MIDR_EL1 */
    155 	mrs	x2, midr_el1
    156 	mov_imm	x3, CPU_IMPL_PN_MASK
    157 
    158 	/* Retain only the implementation and part number using mask */
    159 	and	w2, w2, w3
    160 1:
    161 	/* Check if we have reached end of list */
    162 	cmp	x4, x5
    163 	b.eq	error_exit
    164 
    165 	/* load the midr from the cpu_ops */
    166 	ldr	x1, [x4], #CPU_OPS_SIZE
    167 	and	w1, w1, w3
    168 
    169 	/* Check if midr matches to midr of this core */
    170 	cmp	w1, w2
    171 	b.ne	1b
    172 
    173 	/* Subtract the increment and offset to get the cpu-ops pointer */
    174 	sub	x0, x4, #(CPU_OPS_SIZE + CPU_MIDR)
    175 error_exit:
    176 	ret
    177 endfunc get_cpu_ops_ptr
    178 
    179 /*
    180  * Extract CPU revision and variant, and combine them into a single numeric for
    181  * easier comparison.
    182  */
    183 	.globl	cpu_get_rev_var
    184 func cpu_get_rev_var
    185 	mrs	x1, midr_el1
    186 
    187 	/*
    188 	 * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them
    189 	 * as variant[7:4] and revision[3:0] of x0.
    190 	 *
    191 	 * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then
    192 	 * extract x1[3:0] into x0[3:0] retaining other bits.
    193 	 */
    194 	ubfx	x0, x1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
    195 	bfxil	x0, x1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
    196 	ret
    197 endfunc cpu_get_rev_var
    198 
    199 /*
    200  * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
    201  * application purposes. If the revision-variant is less than or same as a given
    202  * value, indicates that errata applies; otherwise not.
    203  */
    204 	.globl	cpu_rev_var_ls
    205 func cpu_rev_var_ls
    206 	mov	x2, #ERRATA_APPLIES
    207 	mov	x3, #ERRATA_NOT_APPLIES
    208 	cmp	x0, x1
    209 	csel	x0, x2, x3, ls
    210 	ret
    211 endfunc cpu_rev_var_ls
    212 
    213 /*
    214  * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
    215  * application purposes. If the revision-variant is higher than or same as a
    216  * given value, indicates that errata applies; otherwise not.
    217  */
    218 	.globl	cpu_rev_var_hs
    219 func cpu_rev_var_hs
    220 	mov	x2, #ERRATA_APPLIES
    221 	mov	x3, #ERRATA_NOT_APPLIES
    222 	cmp	x0, x1
    223 	csel	x0, x2, x3, hs
    224 	ret
    225 endfunc cpu_rev_var_hs
    226 
    227 #if REPORT_ERRATA
    228 /*
    229  * void print_errata_status(void);
    230  *
    231  * Function to print errata status for CPUs of its class. Must be called only:
    232  *
    233  *   - with MMU and data caches are enabled;
    234  *   - after cpu_ops have been initialized in per-CPU data.
    235  */
    236 	.globl print_errata_status
    237 func print_errata_status
    238 #ifdef IMAGE_BL1
    239 	/*
    240 	 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
    241 	 * directly.
    242 	 */
    243 	stp	xzr, x30, [sp, #-16]!
    244 	bl	get_cpu_ops_ptr
    245 	ldp	xzr, x30, [sp], #16
    246 	ldr	x1, [x0, #CPU_ERRATA_FUNC]
    247 	cbnz	x1, .Lprint
    248 #else
    249 	/*
    250 	 * Retrieve pointer to cpu_ops from per-CPU data, and further, the
    251 	 * errata printing function. If it's non-NULL, jump to the function in
    252 	 * turn.
    253 	 */
    254 	mrs	x0, tpidr_el3
    255 	ldr	x1, [x0, #CPU_DATA_CPU_OPS_PTR]
    256 	ldr	x0, [x1, #CPU_ERRATA_FUNC]
    257 	cbz	x0, .Lnoprint
    258 
    259 	/*
    260 	 * Printing errata status requires atomically testing the printed flag.
    261 	 */
    262 	stp	x19, x30, [sp, #-16]!
    263 	mov	x19, x0
    264 
    265 	/*
    266 	 * Load pointers to errata lock and printed flag. Call
    267 	 * errata_needs_reporting to check whether this CPU needs to report
    268 	 * errata status pertaining to its class.
    269 	 */
    270 	ldr	x0, [x1, #CPU_ERRATA_LOCK]
    271 	ldr	x1, [x1, #CPU_ERRATA_PRINTED]
    272 	bl	errata_needs_reporting
    273 	mov	x1, x19
    274 	ldp	x19, x30, [sp], #16
    275 	cbnz	x0, .Lprint
    276 #endif
    277 .Lnoprint:
    278 	ret
    279 .Lprint:
    280 	/* Jump to errata reporting function for this CPU */
    281 	br	x1
    282 endfunc print_errata_status
    283 #endif
    284