root/arch/arm/mach-meson/platsmp.c

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

DEFINITIONS

This source file includes following definitions.
  1. meson_smp_get_core_reset
  2. meson_smp_set_cpu_ctrl
  3. meson_smp_prepare_cpus
  4. meson8b_smp_prepare_cpus
  5. meson8_smp_prepare_cpus
  6. meson_smp_begin_secondary_boot
  7. meson_smp_finalize_secondary_boot
  8. meson8_smp_boot_secondary
  9. meson8b_smp_boot_secondary
  10. meson8_smp_cpu_die
  11. meson8_smp_cpu_kill
  12. meson8b_smp_cpu_kill

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2015 Carlo Caione <carlo@endlessm.com>
   4  * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
   5  */
   6 
   7 #include <linux/delay.h>
   8 #include <linux/init.h>
   9 #include <linux/io.h>
  10 #include <linux/of.h>
  11 #include <linux/of_address.h>
  12 #include <linux/regmap.h>
  13 #include <linux/reset.h>
  14 #include <linux/smp.h>
  15 #include <linux/mfd/syscon.h>
  16 
  17 #include <asm/cacheflush.h>
  18 #include <asm/cp15.h>
  19 #include <asm/smp_scu.h>
  20 #include <asm/smp_plat.h>
  21 
  22 #define MESON_SMP_SRAM_CPU_CTRL_REG             (0x00)
  23 #define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c)     (0x04 + ((c - 1) << 2))
  24 
  25 #define MESON_CPU_AO_RTI_PWR_A9_CNTL0           (0x00)
  26 #define MESON_CPU_AO_RTI_PWR_A9_CNTL1           (0x04)
  27 #define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0         (0x14)
  28 
  29 #define MESON_CPU_PWR_A9_CNTL0_M(c)             (0x03 << ((c * 2) + 16))
  30 #define MESON_CPU_PWR_A9_CNTL1_M(c)             (0x03 << ((c + 1) << 1))
  31 #define MESON_CPU_PWR_A9_MEM_PD0_M(c)           (0x0f << (32 - (c * 4)))
  32 #define MESON_CPU_PWR_A9_CNTL1_ST(c)            (0x01 << (c + 16))
  33 
  34 static void __iomem *sram_base;
  35 static void __iomem *scu_base;
  36 static struct regmap *pmu;
  37 
  38 static struct reset_control *meson_smp_get_core_reset(int cpu)
  39 {
  40         struct device_node *np = of_get_cpu_node(cpu, 0);
  41 
  42         return of_reset_control_get_exclusive(np, NULL);
  43 }
  44 
  45 static void meson_smp_set_cpu_ctrl(int cpu, bool on_off)
  46 {
  47         u32 val = readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
  48 
  49         if (on_off)
  50                 val |= BIT(cpu);
  51         else
  52                 val &= ~BIT(cpu);
  53 
  54         /* keep bit 0 always enabled */
  55         val |= BIT(0);
  56 
  57         writel(val, sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
  58 }
  59 
  60 static void __init meson_smp_prepare_cpus(const char *scu_compatible,
  61                                           const char *pmu_compatible,
  62                                           const char *sram_compatible)
  63 {
  64         static struct device_node *node;
  65 
  66         /* SMP SRAM */
  67         node = of_find_compatible_node(NULL, NULL, sram_compatible);
  68         if (!node) {
  69                 pr_err("Missing SRAM node\n");
  70                 return;
  71         }
  72 
  73         sram_base = of_iomap(node, 0);
  74         if (!sram_base) {
  75                 pr_err("Couldn't map SRAM registers\n");
  76                 return;
  77         }
  78 
  79         /* PMU */
  80         pmu = syscon_regmap_lookup_by_compatible(pmu_compatible);
  81         if (IS_ERR(pmu)) {
  82                 pr_err("Couldn't map PMU registers\n");
  83                 return;
  84         }
  85 
  86         /* SCU */
  87         node = of_find_compatible_node(NULL, NULL, scu_compatible);
  88         if (!node) {
  89                 pr_err("Missing SCU node\n");
  90                 return;
  91         }
  92 
  93         scu_base = of_iomap(node, 0);
  94         if (!scu_base) {
  95                 pr_err("Couldn't map SCU registers\n");
  96                 return;
  97         }
  98 
  99         scu_enable(scu_base);
 100 }
 101 
 102 static void __init meson8b_smp_prepare_cpus(unsigned int max_cpus)
 103 {
 104         meson_smp_prepare_cpus("arm,cortex-a5-scu", "amlogic,meson8b-pmu",
 105                                "amlogic,meson8b-smp-sram");
 106 }
 107 
 108 static void __init meson8_smp_prepare_cpus(unsigned int max_cpus)
 109 {
 110         meson_smp_prepare_cpus("arm,cortex-a9-scu", "amlogic,meson8-pmu",
 111                                "amlogic,meson8-smp-sram");
 112 }
 113 
 114 static void meson_smp_begin_secondary_boot(unsigned int cpu)
 115 {
 116         /*
 117          * Set the entry point before powering on the CPU through the SCU. This
 118          * is needed if the CPU is in "warm" state (= after rebooting the
 119          * system without power-cycling, or when taking the CPU offline and
 120          * then taking it online again.
 121          */
 122         writel(__pa_symbol(secondary_startup),
 123                sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
 124 
 125         /*
 126          * SCU Power on CPU (needs to be done before starting the CPU,
 127          * otherwise the secondary CPU will not start).
 128          */
 129         scu_cpu_power_enable(scu_base, cpu);
 130 }
 131 
 132 static int meson_smp_finalize_secondary_boot(unsigned int cpu)
 133 {
 134         unsigned long timeout;
 135 
 136         timeout = jiffies + (10 * HZ);
 137         while (readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu))) {
 138                 if (!time_before(jiffies, timeout)) {
 139                         pr_err("Timeout while waiting for CPU%d status\n",
 140                                cpu);
 141                         return -ETIMEDOUT;
 142                 }
 143         }
 144 
 145         writel(__pa_symbol(secondary_startup),
 146                sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
 147 
 148         meson_smp_set_cpu_ctrl(cpu, true);
 149 
 150         return 0;
 151 }
 152 
 153 static int meson8_smp_boot_secondary(unsigned int cpu,
 154                                      struct task_struct *idle)
 155 {
 156         struct reset_control *rstc;
 157         int ret;
 158 
 159         rstc = meson_smp_get_core_reset(cpu);
 160         if (IS_ERR(rstc)) {
 161                 pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
 162                 return PTR_ERR(rstc);
 163         }
 164 
 165         meson_smp_begin_secondary_boot(cpu);
 166 
 167         /* Reset enable */
 168         ret = reset_control_assert(rstc);
 169         if (ret) {
 170                 pr_err("Failed to assert CPU%d reset\n", cpu);
 171                 goto out;
 172         }
 173 
 174         /* CPU power ON */
 175         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
 176                                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
 177         if (ret < 0) {
 178                 pr_err("Couldn't wake up CPU%d\n", cpu);
 179                 goto out;
 180         }
 181 
 182         udelay(10);
 183 
 184         /* Isolation disable */
 185         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
 186                                  0);
 187         if (ret < 0) {
 188                 pr_err("Error when disabling isolation of CPU%d\n", cpu);
 189                 goto out;
 190         }
 191 
 192         /* Reset disable */
 193         ret = reset_control_deassert(rstc);
 194         if (ret) {
 195                 pr_err("Failed to de-assert CPU%d reset\n", cpu);
 196                 goto out;
 197         }
 198 
 199         ret = meson_smp_finalize_secondary_boot(cpu);
 200         if (ret)
 201                 goto out;
 202 
 203 out:
 204         reset_control_put(rstc);
 205 
 206         return 0;
 207 }
 208 
 209 static int meson8b_smp_boot_secondary(unsigned int cpu,
 210                                      struct task_struct *idle)
 211 {
 212         struct reset_control *rstc;
 213         int ret;
 214         u32 val;
 215 
 216         rstc = meson_smp_get_core_reset(cpu);
 217         if (IS_ERR(rstc)) {
 218                 pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
 219                 return PTR_ERR(rstc);
 220         }
 221 
 222         meson_smp_begin_secondary_boot(cpu);
 223 
 224         /* CPU power UP */
 225         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
 226                                  MESON_CPU_PWR_A9_CNTL0_M(cpu), 0);
 227         if (ret < 0) {
 228                 pr_err("Couldn't power up CPU%d\n", cpu);
 229                 goto out;
 230         }
 231 
 232         udelay(5);
 233 
 234         /* Reset enable */
 235         ret = reset_control_assert(rstc);
 236         if (ret) {
 237                 pr_err("Failed to assert CPU%d reset\n", cpu);
 238                 goto out;
 239         }
 240 
 241         /* Memory power UP */
 242         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
 243                                  MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0);
 244         if (ret < 0) {
 245                 pr_err("Couldn't power up the memory for CPU%d\n", cpu);
 246                 goto out;
 247         }
 248 
 249         /* Wake up CPU */
 250         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
 251                                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
 252         if (ret < 0) {
 253                 pr_err("Couldn't wake up CPU%d\n", cpu);
 254                 goto out;
 255         }
 256 
 257         udelay(10);
 258 
 259         ret = regmap_read_poll_timeout(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1, val,
 260                                        val & MESON_CPU_PWR_A9_CNTL1_ST(cpu),
 261                                        10, 10000);
 262         if (ret) {
 263                 pr_err("Timeout while polling PMU for CPU%d status\n", cpu);
 264                 goto out;
 265         }
 266 
 267         /* Isolation disable */
 268         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
 269                                  0);
 270         if (ret < 0) {
 271                 pr_err("Error when disabling isolation of CPU%d\n", cpu);
 272                 goto out;
 273         }
 274 
 275         /* Reset disable */
 276         ret = reset_control_deassert(rstc);
 277         if (ret) {
 278                 pr_err("Failed to de-assert CPU%d reset\n", cpu);
 279                 goto out;
 280         }
 281 
 282         ret = meson_smp_finalize_secondary_boot(cpu);
 283         if (ret)
 284                 goto out;
 285 
 286 out:
 287         reset_control_put(rstc);
 288 
 289         return 0;
 290 }
 291 
 292 #ifdef CONFIG_HOTPLUG_CPU
 293 static void meson8_smp_cpu_die(unsigned int cpu)
 294 {
 295         meson_smp_set_cpu_ctrl(cpu, false);
 296 
 297         v7_exit_coherency_flush(louis);
 298 
 299         scu_power_mode(scu_base, SCU_PM_POWEROFF);
 300 
 301         dsb();
 302         wfi();
 303 
 304         /* we should never get here */
 305         WARN_ON(1);
 306 }
 307 
 308 static int meson8_smp_cpu_kill(unsigned int cpu)
 309 {
 310         int ret, power_mode;
 311         unsigned long timeout;
 312 
 313         timeout = jiffies + (50 * HZ);
 314         do {
 315                 power_mode = scu_get_cpu_power_mode(scu_base, cpu);
 316 
 317                 if (power_mode == SCU_PM_POWEROFF)
 318                         break;
 319 
 320                 usleep_range(10000, 15000);
 321         } while (time_before(jiffies, timeout));
 322 
 323         if (power_mode != SCU_PM_POWEROFF) {
 324                 pr_err("Error while waiting for SCU power-off on CPU%d\n",
 325                        cpu);
 326                 return -ETIMEDOUT;
 327         }
 328 
 329         msleep(30);
 330 
 331         /* Isolation enable */
 332         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
 333                                  0x3);
 334         if (ret < 0) {
 335                 pr_err("Error when enabling isolation for CPU%d\n", cpu);
 336                 return ret;
 337         }
 338 
 339         udelay(10);
 340 
 341         /* CPU power OFF */
 342         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
 343                                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
 344         if (ret < 0) {
 345                 pr_err("Couldn't change sleep status of CPU%d\n", cpu);
 346                 return ret;
 347         }
 348 
 349         return 1;
 350 }
 351 
 352 static int meson8b_smp_cpu_kill(unsigned int cpu)
 353 {
 354         int ret, power_mode, count = 5000;
 355 
 356         do {
 357                 power_mode = scu_get_cpu_power_mode(scu_base, cpu);
 358 
 359                 if (power_mode == SCU_PM_POWEROFF)
 360                         break;
 361 
 362                 udelay(10);
 363         } while (++count);
 364 
 365         if (power_mode != SCU_PM_POWEROFF) {
 366                 pr_err("Error while waiting for SCU power-off on CPU%d\n",
 367                        cpu);
 368                 return -ETIMEDOUT;
 369         }
 370 
 371         udelay(10);
 372 
 373         /* CPU power DOWN */
 374         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
 375                                  MESON_CPU_PWR_A9_CNTL0_M(cpu), 0x3);
 376         if (ret < 0) {
 377                 pr_err("Couldn't power down CPU%d\n", cpu);
 378                 return ret;
 379         }
 380 
 381         /* Isolation enable */
 382         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
 383                                  0x3);
 384         if (ret < 0) {
 385                 pr_err("Error when enabling isolation for CPU%d\n", cpu);
 386                 return ret;
 387         }
 388 
 389         udelay(10);
 390 
 391         /* Sleep status */
 392         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
 393                                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
 394         if (ret < 0) {
 395                 pr_err("Couldn't change sleep status of CPU%d\n", cpu);
 396                 return ret;
 397         }
 398 
 399         /* Memory power DOWN */
 400         ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
 401                                  MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0xf);
 402         if (ret < 0) {
 403                 pr_err("Couldn't power down the memory of CPU%d\n", cpu);
 404                 return ret;
 405         }
 406 
 407         return 1;
 408 }
 409 #endif
 410 
 411 static struct smp_operations meson8_smp_ops __initdata = {
 412         .smp_prepare_cpus       = meson8_smp_prepare_cpus,
 413         .smp_boot_secondary     = meson8_smp_boot_secondary,
 414 #ifdef CONFIG_HOTPLUG_CPU
 415         .cpu_die                = meson8_smp_cpu_die,
 416         .cpu_kill               = meson8_smp_cpu_kill,
 417 #endif
 418 };
 419 
 420 static struct smp_operations meson8b_smp_ops __initdata = {
 421         .smp_prepare_cpus       = meson8b_smp_prepare_cpus,
 422         .smp_boot_secondary     = meson8b_smp_boot_secondary,
 423 #ifdef CONFIG_HOTPLUG_CPU
 424         .cpu_die                = meson8_smp_cpu_die,
 425         .cpu_kill               = meson8b_smp_cpu_kill,
 426 #endif
 427 };
 428 
 429 CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
 430 CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);

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