Home | History | Annotate | Download | only in aarch32
      1 /*
      2  * Copyright (c) 2016-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 <platform_def.h>
     10 #include "../drivers/pwrc/fvp_pwrc.h"
     11 #include "../fvp_def.h"
     12 
     13 	.globl	plat_secondary_cold_boot_setup
     14 	.globl	plat_get_my_entrypoint
     15 	.globl	plat_is_my_cpu_primary
     16 	.globl	plat_arm_calc_core_pos
     17 
     18 	/* --------------------------------------------------------------------
     19 	 * void plat_secondary_cold_boot_setup (void);
     20 	 *
     21 	 * For AArch32, cold-booting secondary CPUs is not yet
     22 	 * implemented and they panic.
     23 	 * --------------------------------------------------------------------
     24 	 */
     25 func plat_secondary_cold_boot_setup
     26 cb_panic:
     27 	b	cb_panic
     28 endfunc plat_secondary_cold_boot_setup
     29 
     30 	/* ---------------------------------------------------------------------
     31 	 * unsigned long plat_get_my_entrypoint (void);
     32 	 *
     33 	 * Main job of this routine is to distinguish between a cold and warm
     34 	 * boot. On FVP, this information can be queried from the power
     35 	 * controller. The Power Control SYS Status Register (PSYSR) indicates
     36 	 * the wake-up reason for the CPU.
     37 	 *
     38 	 * For a cold boot, return 0.
     39 	 * For a warm boot, read the mailbox and return the address it contains.
     40 	 *
     41 	 * TODO: PSYSR is a common register and should be
     42 	 * 	accessed using locks. Since it is not possible
     43 	 * 	to use locks immediately after a cold reset
     44 	 * 	we are relying on the fact that after a cold
     45 	 * 	reset all cpus will read the same WK field
     46 	 * ---------------------------------------------------------------------
     47 	 */
     48 func plat_get_my_entrypoint
     49 	/* ---------------------------------------------------------------------
     50 	 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
     51 	 * WakeRequest signal" then it is a warm boot.
     52 	 * ---------------------------------------------------------------------
     53 	 */
     54 	ldcopr	r2, MPIDR
     55 	ldr	r1, =PWRC_BASE
     56 	str	r2, [r1, #PSYSR_OFF]
     57 	ldr	r2, [r1, #PSYSR_OFF]
     58 	ubfx	r2, r2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
     59 	cmp	r2, #WKUP_PPONR
     60 	beq	warm_reset
     61 	cmp	r2, #WKUP_GICREQ
     62 	beq	warm_reset
     63 
     64 	/* Cold reset */
     65 	mov	r0, #0
     66 	bx	lr
     67 
     68 warm_reset:
     69 	/* ---------------------------------------------------------------------
     70 	 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
     71 	 * caches after every update using normal memory so it is safe to read
     72 	 * it here with SO attributes.
     73 	 * ---------------------------------------------------------------------
     74 	 */
     75 	ldr	r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE
     76 	ldr	r0, [r0]
     77 	cmp	r0, #0
     78 	beq	_panic
     79 	bx	lr
     80 
     81 	/* ---------------------------------------------------------------------
     82 	 * The power controller indicates this is a warm reset but the mailbox
     83 	 * is empty. This should never happen!
     84 	 * ---------------------------------------------------------------------
     85 	 */
     86 _panic:
     87 	b	_panic
     88 endfunc plat_get_my_entrypoint
     89 
     90 	/* -----------------------------------------------------
     91 	 * unsigned int plat_is_my_cpu_primary (void);
     92 	 *
     93 	 * Find out whether the current cpu is the primary
     94 	 * cpu.
     95 	 * -----------------------------------------------------
     96 	 */
     97 func plat_is_my_cpu_primary
     98 	ldcopr	r0, MPIDR
     99 	ldr	r1, =MPIDR_AFFINITY_MASK
    100 	and	r0, r1
    101 	cmp	r0, #FVP_PRIMARY_CPU
    102 	moveq	r0, #1
    103 	movne	r0, #0
    104 	bx	lr
    105 endfunc plat_is_my_cpu_primary
    106 
    107 	/* -----------------------------------------------------
    108 	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
    109 	 *
    110 	 * Function to calculate the core position on FVP.
    111 	 *
    112 	 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER) +
    113 	 * (CPUId * FVP_MAX_PE_PER_CPU) +
    114 	 * ThreadId
    115 	 * -----------------------------------------------------
    116 	 */
    117 func plat_arm_calc_core_pos
    118 	mov	r3, r0
    119 
    120 	/*
    121 	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
    122 	 * look as if in a multi-threaded implementation
    123 	 */
    124 	tst	r0, #MPIDR_MT_MASK
    125 	lsleq	r3, r0, #MPIDR_AFFINITY_BITS
    126 
    127 	/* Extract individual affinity fields from MPIDR */
    128 	mov	r2, #FVP_MAX_PE_PER_CPU
    129 	ubfx	r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
    130 	ubfx	r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
    131 	mla	r0, r1, r2, r0
    132 
    133 	mov	r1, #FVP_MAX_CPUS_PER_CLUSTER
    134 	ubfx	r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
    135 	mla	r0, r1, r2, r0
    136 
    137 	bx	lr
    138 endfunc plat_arm_calc_core_pos
    139