uboot/arch/arm/mach-stm32mp/psci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
   4 */
   5
   6#include <config.h>
   7#include <common.h>
   8#include <asm/armv7.h>
   9#include <asm/gic.h>
  10#include <asm/io.h>
  11#include <asm/psci.h>
  12#include <asm/secure.h>
  13
  14#define BOOT_API_A7_CORE0_MAGIC_NUMBER  0xCA7FACE0
  15#define BOOT_API_A7_CORE1_MAGIC_NUMBER  0xCA7FACE1
  16
  17#define MPIDR_AFF0                      GENMASK(7, 0)
  18
  19#define RCC_MP_GRSTCSETR                (STM32_RCC_BASE + 0x0404)
  20#define RCC_MP_GRSTCSETR_MPUP1RST       BIT(5)
  21#define RCC_MP_GRSTCSETR_MPUP0RST       BIT(4)
  22#define RCC_MP_GRSTCSETR_MPSYSRST       BIT(0)
  23
  24#define STM32MP1_PSCI_NR_CPUS           2
  25#if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS
  26#error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS"
  27#endif
  28
  29u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = {
  30         PSCI_AFFINITY_LEVEL_ON,
  31         PSCI_AFFINITY_LEVEL_OFF};
  32
  33static inline void psci_set_state(int cpu, u8 state)
  34{
  35        psci_state[cpu] = state;
  36        dsb();
  37        isb();
  38}
  39
  40static u32 __secure stm32mp_get_gicd_base_address(void)
  41{
  42        u32 periphbase;
  43
  44        /* get the GIC base address from the CBAR register */
  45        asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
  46
  47        return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET;
  48}
  49
  50static void __secure stm32mp_raise_sgi0(int cpu)
  51{
  52        u32 gic_dist_addr;
  53
  54        gic_dist_addr = stm32mp_get_gicd_base_address();
  55
  56        /* ask cpu with SGI0 */
  57        writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR);
  58}
  59
  60void __secure psci_arch_cpu_entry(void)
  61{
  62        u32 cpu = psci_get_cpu_id();
  63
  64        psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
  65
  66        /* reset magic in TAMP register */
  67        writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
  68}
  69
  70s32 __secure psci_features(u32 function_id, u32 psci_fid)
  71{
  72        switch (psci_fid) {
  73        case ARM_PSCI_0_2_FN_PSCI_VERSION:
  74        case ARM_PSCI_0_2_FN_CPU_OFF:
  75        case ARM_PSCI_0_2_FN_CPU_ON:
  76        case ARM_PSCI_0_2_FN_AFFINITY_INFO:
  77        case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
  78        case ARM_PSCI_0_2_FN_SYSTEM_OFF:
  79        case ARM_PSCI_0_2_FN_SYSTEM_RESET:
  80                return 0x0;
  81        }
  82        return ARM_PSCI_RET_NI;
  83}
  84
  85u32 __secure psci_version(void)
  86{
  87        return ARM_PSCI_VER_1_0;
  88}
  89
  90s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity,
  91                                u32  lowest_affinity_level)
  92{
  93        u32 cpu = target_affinity & MPIDR_AFF0;
  94
  95        if (lowest_affinity_level > 0)
  96                return ARM_PSCI_RET_INVAL;
  97
  98        if (target_affinity & ~MPIDR_AFF0)
  99                return ARM_PSCI_RET_INVAL;
 100
 101        if (cpu >= STM32MP1_PSCI_NR_CPUS)
 102                return ARM_PSCI_RET_INVAL;
 103
 104        return psci_state[cpu];
 105}
 106
 107u32 __secure psci_migrate_info_type(void)
 108{
 109        /*
 110         * in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
 111         * return 2 = Trusted OS is either not present or does not require
 112         * migration, system of this type does not require the caller
 113         * to use the MIGRATE function.
 114         * MIGRATE function calls return NOT_SUPPORTED.
 115         */
 116        return 2;
 117}
 118
 119s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
 120                         u32 context_id)
 121{
 122        u32 cpu = target_cpu & MPIDR_AFF0;
 123
 124        if (target_cpu & ~MPIDR_AFF0)
 125                return ARM_PSCI_RET_INVAL;
 126
 127        if (cpu >= STM32MP1_PSCI_NR_CPUS)
 128                return ARM_PSCI_RET_INVAL;
 129
 130        if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON)
 131                return ARM_PSCI_RET_ALREADY_ON;
 132
 133        /* reset magic in TAMP register */
 134        if (readl(TAMP_BACKUP_MAGIC_NUMBER))
 135                writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
 136        /*
 137         * ROM code need a first SGI0 after core reset
 138         * core is ready when magic is set to 0 in ROM code
 139         */
 140        while (readl(TAMP_BACKUP_MAGIC_NUMBER))
 141                stm32mp_raise_sgi0(cpu);
 142
 143        /* store target PC and context id*/
 144        psci_save(cpu, pc, context_id);
 145
 146        /* write entrypoint in backup RAM register */
 147        writel((u32)&psci_cpu_entry, TAMP_BACKUP_BRANCH_ADDRESS);
 148        psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING);
 149
 150        /* write magic number in backup register */
 151        if (cpu == 0x01)
 152                writel(BOOT_API_A7_CORE1_MAGIC_NUMBER,
 153                       TAMP_BACKUP_MAGIC_NUMBER);
 154        else
 155                writel(BOOT_API_A7_CORE0_MAGIC_NUMBER,
 156                       TAMP_BACKUP_MAGIC_NUMBER);
 157
 158        /* Generate an IT to start the core */
 159        stm32mp_raise_sgi0(cpu);
 160
 161        return ARM_PSCI_RET_SUCCESS;
 162}
 163
 164s32 __secure psci_cpu_off(void)
 165{
 166        u32 cpu;
 167
 168        cpu = psci_get_cpu_id();
 169
 170        psci_cpu_off_common();
 171        psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);
 172
 173        /* reset core: wfi is managed by BootRom */
 174        if (cpu == 0x01)
 175                writel(RCC_MP_GRSTCSETR_MPUP1RST, RCC_MP_GRSTCSETR);
 176        else
 177                writel(RCC_MP_GRSTCSETR_MPUP0RST, RCC_MP_GRSTCSETR);
 178
 179        /* just waiting reset */
 180        while (1)
 181                wfi();
 182}
 183
 184void __secure psci_system_reset(void)
 185{
 186        /* System reset */
 187        writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
 188        /* just waiting reset */
 189        while (1)
 190                wfi();
 191}
 192
 193void __secure psci_system_off(void)
 194{
 195        /* System Off is not managed, waiting user power off
 196         * TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
 197         */
 198        while (1)
 199                wfi();
 200}
 201