Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  linux/arch/arm/kernel/smp_scu.c
0004  *
0005  *  Copyright (C) 2002 ARM Ltd.
0006  *  All Rights Reserved
0007  */
0008 #include <linux/init.h>
0009 #include <linux/io.h>
0010 
0011 #include <asm/smp_plat.h>
0012 #include <asm/smp_scu.h>
0013 #include <asm/cacheflush.h>
0014 #include <asm/cputype.h>
0015 
0016 #define SCU_CTRL        0x00
0017 #define SCU_ENABLE      (1 << 0)
0018 #define SCU_STANDBY_ENABLE  (1 << 5)
0019 #define SCU_CONFIG      0x04
0020 #define SCU_CPU_STATUS      0x08
0021 #define SCU_CPU_STATUS_MASK GENMASK(1, 0)
0022 #define SCU_INVALIDATE      0x0c
0023 #define SCU_FPGA_REVISION   0x10
0024 
0025 #ifdef CONFIG_SMP
0026 /*
0027  * Get the number of CPU cores from the SCU configuration
0028  */
0029 unsigned int __init scu_get_core_count(void __iomem *scu_base)
0030 {
0031     unsigned int ncores = readl_relaxed(scu_base + SCU_CONFIG);
0032     return (ncores & 0x03) + 1;
0033 }
0034 
0035 /*
0036  * Enable the SCU
0037  */
0038 void scu_enable(void __iomem *scu_base)
0039 {
0040     u32 scu_ctrl;
0041 
0042 #ifdef CONFIG_ARM_ERRATA_764369
0043     /* Cortex-A9 only */
0044     if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090) {
0045         scu_ctrl = readl_relaxed(scu_base + 0x30);
0046         if (!(scu_ctrl & 1))
0047             writel_relaxed(scu_ctrl | 0x1, scu_base + 0x30);
0048     }
0049 #endif
0050 
0051     scu_ctrl = readl_relaxed(scu_base + SCU_CTRL);
0052     /* already enabled? */
0053     if (scu_ctrl & SCU_ENABLE)
0054         return;
0055 
0056     scu_ctrl |= SCU_ENABLE;
0057 
0058     /* Cortex-A9 earlier than r2p0 has no standby bit in SCU */
0059     if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090 &&
0060         (read_cpuid_id() & 0x00f0000f) >= 0x00200000)
0061         scu_ctrl |= SCU_STANDBY_ENABLE;
0062 
0063     writel_relaxed(scu_ctrl, scu_base + SCU_CTRL);
0064 
0065     /*
0066      * Ensure that the data accessed by CPU0 before the SCU was
0067      * initialised is visible to the other CPUs.
0068      */
0069     flush_cache_all();
0070 }
0071 #endif
0072 
0073 static int scu_set_power_mode_internal(void __iomem *scu_base,
0074                        unsigned int logical_cpu,
0075                        unsigned int mode)
0076 {
0077     unsigned int val;
0078     int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(logical_cpu), 0);
0079 
0080     if (mode > 3 || mode == 1 || cpu > 3)
0081         return -EINVAL;
0082 
0083     val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu);
0084     val &= ~SCU_CPU_STATUS_MASK;
0085     val |= mode;
0086     writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);
0087 
0088     return 0;
0089 }
0090 
0091 /*
0092  * Set the executing CPUs power mode as defined.  This will be in
0093  * preparation for it executing a WFI instruction.
0094  *
0095  * This function must be called with preemption disabled, and as it
0096  * has the side effect of disabling coherency, caches must have been
0097  * flushed.  Interrupts must also have been disabled.
0098  */
0099 int scu_power_mode(void __iomem *scu_base, unsigned int mode)
0100 {
0101     return scu_set_power_mode_internal(scu_base, smp_processor_id(), mode);
0102 }
0103 
0104 /*
0105  * Set the given (logical) CPU's power mode to SCU_PM_NORMAL.
0106  */
0107 int scu_cpu_power_enable(void __iomem *scu_base, unsigned int cpu)
0108 {
0109     return scu_set_power_mode_internal(scu_base, cpu, SCU_PM_NORMAL);
0110 }
0111 
0112 int scu_get_cpu_power_mode(void __iomem *scu_base, unsigned int logical_cpu)
0113 {
0114     unsigned int val;
0115     int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(logical_cpu), 0);
0116 
0117     if (cpu > 3)
0118         return -EINVAL;
0119 
0120     val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu);
0121     val &= SCU_CPU_STATUS_MASK;
0122 
0123     return val;
0124 }