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