diff --git a/fdts/a5ds.dts b/fdts/a5ds.dts index 8bc4adf..91212e8 100644 --- a/fdts/a5ds.dts +++ b/fdts/a5ds.dts @@ -12,14 +12,40 @@ interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; + method = "smc"; + cpu_on = <0x84000003>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a5"; + enable-method = "psci"; reg = <0>; }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + enable-method = "psci"; + reg = <1>; + }; + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + enable-method = "psci"; + reg = <2>; + }; + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + enable-method = "psci"; + reg = <3>; + }; }; memory@80000000 { diff --git a/plat/arm/board/a5ds/a5ds_pm.c b/plat/arm/board/a5ds/a5ds_pm.c index 5fd443b..98de77d 100644 --- a/plat/arm/board/a5ds/a5ds_pm.c +++ b/plat/arm/board/a5ds/a5ds_pm.c @@ -6,6 +6,38 @@ #include #include +#include +#include + +/******************************************************************************* + * Platform handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + ******************************************************************************/ +static int a5ds_pwr_domain_on(u_register_t mpidr) +{ + unsigned int pos = plat_core_pos_by_mpidr(mpidr); + uint64_t *hold_base = (uint64_t *)A5DS_HOLD_BASE; + + hold_base[pos] = A5DS_HOLD_STATE_GO; + dsbish(); + sev(); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Platform handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + ******************************************************************************/ +void a5ds_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + /* TODO: This setup is needed only after a cold boot*/ + gicv2_pcpu_distif_init(); + + /* Enable the gic cpu interface */ + gicv2_cpuif_enable(); +} /******************************************************************************* * Export the platform handlers via a5ds_psci_pm_ops. The ARM Standard @@ -14,11 +46,16 @@ plat_psci_ops_t a5ds_psci_pm_ops = { /* dummy struct */ .validate_ns_entrypoint = NULL, + .pwr_domain_on = a5ds_pwr_domain_on, + .pwr_domain_on_finish = a5ds_pwr_domain_on_finish }; int __init plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { + uintptr_t *mailbox = (void *)A5DS_TRUSTED_MAILBOX_BASE; + *mailbox = sec_entrypoint; + *psci_ops = &a5ds_psci_pm_ops; return 0; diff --git a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S index 23a22d9..ed7ad9c 100644 --- a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S +++ b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S @@ -12,17 +12,36 @@ .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary - /* -------------------------------------------------------------------- + /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * - * For AArch32, cold-booting secondary CPUs is not yet - * implemented and they panic. - * -------------------------------------------------------------------- + * 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 -cb_panic: - wfi - b cb_panic + /* Calculate address of our hold entry */ + bl plat_my_core_pos + lsl r0, r0, #A5DS_HOLD_ENTRY_SHIFT + mov_imm r2, A5DS_HOLD_BASE + /* Clear the value stored in the hold address for the specific core */ + mov_imm r3, A5DS_HOLD_STATE_WAIT + str r3, [r2, r0] + dmb ish + + /* Wait until we have a go */ +poll_mailbox: + ldr r1, [r2, r0] + cmp r1, #A5DS_HOLD_STATE_WAIT + beq 1f + mov_imm r0, A5DS_TRUSTED_MAILBOX_BASE + ldr r1, [r0] + bx r1 +1: + wfe + b poll_mailbox endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- @@ -56,3 +75,52 @@ movne r0, #0 bx lr endfunc plat_is_my_cpu_primary + + /* --------------------------------------------------------------------- + * Loads MPIDR in r0 and calls plat_arm_calc_core_pos + * --------------------------------------------------------------------- + */ +func plat_my_core_pos + ldcopr r0, MPIDR + b plat_arm_calc_core_pos + +endfunc plat_my_core_pos + + /* --------------------------------------------------------------------- + * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) + * + * Function to calculate the core position on A5DS. + * + * (ClusterId * A5DS_MAX_CPUS_PER_CLUSTER * A5DS_MAX_PE_PER_CPU) + + * (CPUId * A5DS_MAX_PE_PER_CPU) + + * ThreadId + * + * which can be simplified as: + * + * ((ClusterId * A5DS_MAX_CPUS_PER_CLUSTER + CPUId) * A5DS_MAX_PE_PER_CPU) + * + ThreadId + * --------------------------------------------------------------------- + */ +func plat_arm_calc_core_pos + mov r3, r0 + + /* + * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it + * look as if in a multi-threaded implementation + */ + tst r0, #MPIDR_MT_MASK + lsleq r3, r0, #MPIDR_AFFINITY_BITS + + /* Extract individual affinity fields from MPIDR */ + ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS + ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS + ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS + + /* Compute linear position */ + mov r3, #A5DS_MAX_CPUS_PER_CLUSTER + mla r1, r2, r3, r1 + mov r3, #A5DS_MAX_PE_PER_CPU + mla r0, r1, r3, r0 + + bx lr +endfunc plat_arm_calc_core_pos diff --git a/plat/arm/board/a5ds/include/platform_def.h b/plat/arm/board/a5ds/include/platform_def.h index db65c37..e9e4b9a 100644 --- a/plat/arm/board/a5ds/include/platform_def.h +++ b/plat/arm/board/a5ds/include/platform_def.h @@ -97,9 +97,9 @@ /* Default number of threads per CPU on A5DS */ #define A5DS_MAX_PE_PER_CPU 1 -#define A5DS_CORE_COUNT 1 +#define A5DS_CORE_COUNT 4 -#define A5DS_PRIMARY_CPU 0x0 +#define A5DS_PRIMARY_CPU 0x0 #define FLASH1_BASE UL(0x8000000) #define FLASH1_SIZE UL(0x2800000) @@ -229,11 +229,11 @@ #define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) /* Required platform porting definitions */ -#define PLATFORM_CORE_COUNT 1 -#define PLAT_NUM_PWR_DOMAINS (A5DS_CLUSTER_COUNT + \ +#define PLATFORM_CORE_COUNT A5DS_CORE_COUNT +#define PLAT_NUM_PWR_DOMAINS (A5DS_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) + 1 -#define PLAT_MAX_PWR_LVL 2 +#define PLAT_MAX_PWR_LVL 2 /* * Other platform porting definitions are provided by included headers @@ -325,6 +325,14 @@ /* Mailbox base address */ #define A5DS_TRUSTED_MAILBOX_BASE A5DS_SHARED_RAM_BASE +#define A5DS_TRUSTED_MAILBOX_SIZE (8 + A5DS_HOLD_SIZE) +#define A5DS_HOLD_BASE (A5DS_TRUSTED_MAILBOX_BASE + 8) +#define A5DS_HOLD_SIZE (PLATFORM_CORE_COUNT * \ + A5DS_HOLD_ENTRY_SIZE) +#define A5DS_HOLD_ENTRY_SHIFT 3 +#define A5DS_HOLD_ENTRY_SIZE (1 << A5DS_HOLD_ENTRY_SHIFT) +#define A5DS_HOLD_STATE_WAIT 0 +#define A5DS_HOLD_STATE_GO 1 /* * GIC related constants to cater for GICv2