root/arch/arm/mach-exynos/mcpm-exynos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exynos_cpu_powerup
  2. exynos_cluster_powerup
  3. exynos_cpu_powerdown_prepare
  4. exynos_cluster_powerdown_prepare
  5. exynos_cpu_cache_disable
  6. exynos_cluster_cache_disable
  7. exynos_wait_for_powerdown
  8. exynos_cpu_is_up
  9. exynos_pm_power_up_setup
  10. exynos_mcpm_setup_entry_point
  11. exynos_mcpm_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
   3 //              http://www.samsung.com
   4 //
   5 // Based on arch/arm/mach-vexpress/dcscb.c
   6 
   7 #include <linux/arm-cci.h>
   8 #include <linux/delay.h>
   9 #include <linux/io.h>
  10 #include <linux/of_address.h>
  11 #include <linux/syscore_ops.h>
  12 #include <linux/soc/samsung/exynos-regs-pmu.h>
  13 
  14 #include <asm/cputype.h>
  15 #include <asm/cp15.h>
  16 #include <asm/mcpm.h>
  17 #include <asm/smp_plat.h>
  18 
  19 #include "common.h"
  20 
  21 #define EXYNOS5420_CPUS_PER_CLUSTER     4
  22 #define EXYNOS5420_NR_CLUSTERS          2
  23 
  24 #define EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN   BIT(9)
  25 #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE      BIT(29)
  26 #define EXYNOS5420_USE_L2_COMMON_UP_STATE       BIT(30)
  27 
  28 static void __iomem *ns_sram_base_addr __ro_after_init;
  29 
  30 /*
  31  * The common v7_exit_coherency_flush API could not be used because of the
  32  * Erratum 799270 workaround. This macro is the same as the common one (in
  33  * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
  34  */
  35 #define exynos_v7_exit_coherency_flush(level) \
  36         asm volatile( \
  37         "stmfd  sp!, {fp, ip}\n\t"\
  38         "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
  39         "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
  40         "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
  41         "isb\n\t"\
  42         "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
  43         "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
  44         "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
  45         /* Dummy Load of a device register to avoid Erratum 799270 */ \
  46         "ldr    r4, [%0]\n\t" \
  47         "and    r4, r4, #0\n\t" \
  48         "orr    r0, r0, r4\n\t" \
  49         "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
  50         "isb\n\t" \
  51         "dsb\n\t" \
  52         "ldmfd  sp!, {fp, ip}" \
  53         : \
  54         : "Ir" (pmu_base_addr + S5P_INFORM0) \
  55         : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
  56           "r9", "r10", "lr", "memory")
  57 
  58 static int exynos_cpu_powerup(unsigned int cpu, unsigned int cluster)
  59 {
  60         unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
  61 
  62         pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
  63         if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
  64                 cluster >= EXYNOS5420_NR_CLUSTERS)
  65                 return -EINVAL;
  66 
  67         if (!exynos_cpu_power_state(cpunr)) {
  68                 exynos_cpu_power_up(cpunr);
  69 
  70                 /*
  71                  * This assumes the cluster number of the big cores(Cortex A15)
  72                  * is 0 and the Little cores(Cortex A7) is 1.
  73                  * When the system was booted from the Little core,
  74                  * they should be reset during power up cpu.
  75                  */
  76                 if (cluster &&
  77                     cluster == MPIDR_AFFINITY_LEVEL(cpu_logical_map(0), 1)) {
  78                         unsigned int timeout = 16;
  79 
  80                         /*
  81                          * Before we reset the Little cores, we should wait
  82                          * the SPARE2 register is set to 1 because the init
  83                          * codes of the iROM will set the register after
  84                          * initialization.
  85                          */
  86                         while (timeout && !pmu_raw_readl(S5P_PMU_SPARE2)) {
  87                                 timeout--;
  88                                 udelay(10);
  89                         }
  90 
  91                         if (timeout == 0) {
  92                                 pr_err("cpu %u cluster %u powerup failed\n",
  93                                        cpu, cluster);
  94                                 exynos_cpu_power_down(cpunr);
  95                                 return -ETIMEDOUT;
  96                         }
  97 
  98                         pmu_raw_writel(EXYNOS5420_KFC_CORE_RESET(cpu),
  99                                         EXYNOS_SWRESET);
 100                 }
 101         }
 102 
 103         return 0;
 104 }
 105 
 106 static int exynos_cluster_powerup(unsigned int cluster)
 107 {
 108         pr_debug("%s: cluster %u\n", __func__, cluster);
 109         if (cluster >= EXYNOS5420_NR_CLUSTERS)
 110                 return -EINVAL;
 111 
 112         exynos_cluster_power_up(cluster);
 113         return 0;
 114 }
 115 
 116 static void exynos_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
 117 {
 118         unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
 119 
 120         pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
 121         BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
 122                         cluster >= EXYNOS5420_NR_CLUSTERS);
 123         exynos_cpu_power_down(cpunr);
 124 }
 125 
 126 static void exynos_cluster_powerdown_prepare(unsigned int cluster)
 127 {
 128         pr_debug("%s: cluster %u\n", __func__, cluster);
 129         BUG_ON(cluster >= EXYNOS5420_NR_CLUSTERS);
 130         exynos_cluster_power_down(cluster);
 131 }
 132 
 133 static void exynos_cpu_cache_disable(void)
 134 {
 135         /* Disable and flush the local CPU cache. */
 136         exynos_v7_exit_coherency_flush(louis);
 137 }
 138 
 139 static void exynos_cluster_cache_disable(void)
 140 {
 141         if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
 142                 /*
 143                  * On the Cortex-A15 we need to disable
 144                  * L2 prefetching before flushing the cache.
 145                  */
 146                 asm volatile(
 147                 "mcr    p15, 1, %0, c15, c0, 3\n\t"
 148                 "isb\n\t"
 149                 "dsb"
 150                 : : "r" (0x400));
 151         }
 152 
 153         /* Flush all cache levels for this cluster. */
 154         exynos_v7_exit_coherency_flush(all);
 155 
 156         /*
 157          * Disable cluster-level coherency by masking
 158          * incoming snoops and DVM messages:
 159          */
 160         cci_disable_port_by_cpu(read_cpuid_mpidr());
 161 }
 162 
 163 static int exynos_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
 164 {
 165         unsigned int tries = 100;
 166         unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
 167 
 168         pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
 169         BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
 170                         cluster >= EXYNOS5420_NR_CLUSTERS);
 171 
 172         /* Wait for the core state to be OFF */
 173         while (tries--) {
 174                 if ((exynos_cpu_power_state(cpunr) == 0))
 175                         return 0; /* success: the CPU is halted */
 176 
 177                 /* Otherwise, wait and retry: */
 178                 msleep(1);
 179         }
 180 
 181         return -ETIMEDOUT; /* timeout */
 182 }
 183 
 184 static void exynos_cpu_is_up(unsigned int cpu, unsigned int cluster)
 185 {
 186         /* especially when resuming: make sure power control is set */
 187         exynos_cpu_powerup(cpu, cluster);
 188 }
 189 
 190 static const struct mcpm_platform_ops exynos_power_ops = {
 191         .cpu_powerup            = exynos_cpu_powerup,
 192         .cluster_powerup        = exynos_cluster_powerup,
 193         .cpu_powerdown_prepare  = exynos_cpu_powerdown_prepare,
 194         .cluster_powerdown_prepare = exynos_cluster_powerdown_prepare,
 195         .cpu_cache_disable      = exynos_cpu_cache_disable,
 196         .cluster_cache_disable  = exynos_cluster_cache_disable,
 197         .wait_for_powerdown     = exynos_wait_for_powerdown,
 198         .cpu_is_up              = exynos_cpu_is_up,
 199 };
 200 
 201 /*
 202  * Enable cluster-level coherency, in preparation for turning on the MMU.
 203  */
 204 static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
 205 {
 206         asm volatile ("\n"
 207         "cmp    r0, #1\n"
 208         "bxne   lr\n"
 209         "b      cci_enable_port_for_self");
 210 }
 211 
 212 static const struct of_device_id exynos_dt_mcpm_match[] = {
 213         { .compatible = "samsung,exynos5420" },
 214         { .compatible = "samsung,exynos5800" },
 215         {},
 216 };
 217 
 218 static void exynos_mcpm_setup_entry_point(void)
 219 {
 220         /*
 221          * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
 222          * as part of secondary_cpu_start().  Let's redirect it to the
 223          * mcpm_entry_point(). This is done during both secondary boot-up as
 224          * well as system resume.
 225          */
 226         __raw_writel(0xe59f0000, ns_sram_base_addr);     /* ldr r0, [pc, #0] */
 227         __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx  r0 */
 228         __raw_writel(__pa_symbol(mcpm_entry_point), ns_sram_base_addr + 8);
 229 }
 230 
 231 static struct syscore_ops exynos_mcpm_syscore_ops = {
 232         .resume = exynos_mcpm_setup_entry_point,
 233 };
 234 
 235 static int __init exynos_mcpm_init(void)
 236 {
 237         struct device_node *node;
 238         unsigned int value, i;
 239         int ret;
 240 
 241         node = of_find_matching_node(NULL, exynos_dt_mcpm_match);
 242         if (!node)
 243                 return -ENODEV;
 244         of_node_put(node);
 245 
 246         if (!cci_probed())
 247                 return -ENODEV;
 248 
 249         node = of_find_compatible_node(NULL, NULL,
 250                         "samsung,exynos4210-sysram-ns");
 251         if (!node)
 252                 return -ENODEV;
 253 
 254         ns_sram_base_addr = of_iomap(node, 0);
 255         of_node_put(node);
 256         if (!ns_sram_base_addr) {
 257                 pr_err("failed to map non-secure iRAM base address\n");
 258                 return -ENOMEM;
 259         }
 260 
 261         /*
 262          * To increase the stability of KFC reset we need to program
 263          * the PMU SPARE3 register
 264          */
 265         pmu_raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
 266 
 267         ret = mcpm_platform_register(&exynos_power_ops);
 268         if (!ret)
 269                 ret = mcpm_sync_init(exynos_pm_power_up_setup);
 270         if (!ret)
 271                 ret = mcpm_loopback(exynos_cluster_cache_disable); /* turn on the CCI */
 272         if (ret) {
 273                 iounmap(ns_sram_base_addr);
 274                 return ret;
 275         }
 276 
 277         mcpm_smp_set_ops();
 278 
 279         pr_info("Exynos MCPM support installed\n");
 280 
 281         /*
 282          * On Exynos5420/5800 for the A15 and A7 clusters:
 283          *
 284          * EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN ensures that all the cores
 285          * in a cluster are turned off before turning off the cluster L2.
 286          *
 287          * EXYNOS5420_USE_ARM_CORE_DOWN_STATE ensures that a cores is powered
 288          * off before waking it up.
 289          *
 290          * EXYNOS5420_USE_L2_COMMON_UP_STATE ensures that cluster L2 will be
 291          * turned on before the first man is powered up.
 292          */
 293         for (i = 0; i < EXYNOS5420_NR_CLUSTERS; i++) {
 294                 value = pmu_raw_readl(EXYNOS_COMMON_OPTION(i));
 295                 value |= EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN |
 296                          EXYNOS5420_USE_ARM_CORE_DOWN_STATE    |
 297                          EXYNOS5420_USE_L2_COMMON_UP_STATE;
 298                 pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
 299         }
 300 
 301         exynos_mcpm_setup_entry_point();
 302 
 303         register_syscore_ops(&exynos_mcpm_syscore_ops);
 304 
 305         return ret;
 306 }
 307 
 308 early_initcall(exynos_mcpm_init);

/* [<][>][^][v][top][bottom][index][help] */