Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015 Carlo Caione <carlo@endlessm.com>
0004  * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
0005  */
0006 
0007 #include <linux/delay.h>
0008 #include <linux/init.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/regmap.h>
0013 #include <linux/reset.h>
0014 #include <linux/smp.h>
0015 #include <linux/mfd/syscon.h>
0016 
0017 #include <asm/cacheflush.h>
0018 #include <asm/cp15.h>
0019 #include <asm/smp_scu.h>
0020 #include <asm/smp_plat.h>
0021 
0022 #define MESON_SMP_SRAM_CPU_CTRL_REG     (0x00)
0023 #define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c) (0x04 + ((c - 1) << 2))
0024 
0025 #define MESON_CPU_AO_RTI_PWR_A9_CNTL0       (0x00)
0026 #define MESON_CPU_AO_RTI_PWR_A9_CNTL1       (0x04)
0027 #define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0     (0x14)
0028 
0029 #define MESON_CPU_PWR_A9_CNTL0_M(c)     (0x03 << ((c * 2) + 16))
0030 #define MESON_CPU_PWR_A9_CNTL1_M(c)     (0x03 << ((c + 1) << 1))
0031 #define MESON_CPU_PWR_A9_MEM_PD0_M(c)       (0x0f << (32 - (c * 4)))
0032 #define MESON_CPU_PWR_A9_CNTL1_ST(c)        (0x01 << (c + 16))
0033 
0034 static void __iomem *sram_base;
0035 static void __iomem *scu_base;
0036 static struct regmap *pmu;
0037 
0038 static struct reset_control *meson_smp_get_core_reset(int cpu)
0039 {
0040     struct device_node *np = of_get_cpu_node(cpu, 0);
0041 
0042     return of_reset_control_get_exclusive(np, NULL);
0043 }
0044 
0045 static void meson_smp_set_cpu_ctrl(int cpu, bool on_off)
0046 {
0047     u32 val = readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
0048 
0049     if (on_off)
0050         val |= BIT(cpu);
0051     else
0052         val &= ~BIT(cpu);
0053 
0054     /* keep bit 0 always enabled */
0055     val |= BIT(0);
0056 
0057     writel(val, sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
0058 }
0059 
0060 static void __init meson_smp_prepare_cpus(const char *scu_compatible,
0061                       const char *pmu_compatible,
0062                       const char *sram_compatible)
0063 {
0064     static struct device_node *node;
0065 
0066     /* SMP SRAM */
0067     node = of_find_compatible_node(NULL, NULL, sram_compatible);
0068     if (!node) {
0069         pr_err("Missing SRAM node\n");
0070         return;
0071     }
0072 
0073     sram_base = of_iomap(node, 0);
0074     of_node_put(node);
0075     if (!sram_base) {
0076         pr_err("Couldn't map SRAM registers\n");
0077         return;
0078     }
0079 
0080     /* PMU */
0081     pmu = syscon_regmap_lookup_by_compatible(pmu_compatible);
0082     if (IS_ERR(pmu)) {
0083         pr_err("Couldn't map PMU registers\n");
0084         return;
0085     }
0086 
0087     /* SCU */
0088     node = of_find_compatible_node(NULL, NULL, scu_compatible);
0089     if (!node) {
0090         pr_err("Missing SCU node\n");
0091         return;
0092     }
0093 
0094     scu_base = of_iomap(node, 0);
0095     of_node_put(node);
0096     if (!scu_base) {
0097         pr_err("Couldn't map SCU registers\n");
0098         return;
0099     }
0100 
0101     scu_enable(scu_base);
0102 }
0103 
0104 static void __init meson8b_smp_prepare_cpus(unsigned int max_cpus)
0105 {
0106     meson_smp_prepare_cpus("arm,cortex-a5-scu", "amlogic,meson8b-pmu",
0107                    "amlogic,meson8b-smp-sram");
0108 }
0109 
0110 static void __init meson8_smp_prepare_cpus(unsigned int max_cpus)
0111 {
0112     meson_smp_prepare_cpus("arm,cortex-a9-scu", "amlogic,meson8-pmu",
0113                    "amlogic,meson8-smp-sram");
0114 }
0115 
0116 static void meson_smp_begin_secondary_boot(unsigned int cpu)
0117 {
0118     /*
0119      * Set the entry point before powering on the CPU through the SCU. This
0120      * is needed if the CPU is in "warm" state (= after rebooting the
0121      * system without power-cycling, or when taking the CPU offline and
0122      * then taking it online again.
0123      */
0124     writel(__pa_symbol(secondary_startup),
0125            sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
0126 
0127     /*
0128      * SCU Power on CPU (needs to be done before starting the CPU,
0129      * otherwise the secondary CPU will not start).
0130      */
0131     scu_cpu_power_enable(scu_base, cpu);
0132 }
0133 
0134 static int meson_smp_finalize_secondary_boot(unsigned int cpu)
0135 {
0136     unsigned long timeout;
0137 
0138     timeout = jiffies + (10 * HZ);
0139     while (readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu))) {
0140         if (!time_before(jiffies, timeout)) {
0141             pr_err("Timeout while waiting for CPU%d status\n",
0142                    cpu);
0143             return -ETIMEDOUT;
0144         }
0145     }
0146 
0147     writel(__pa_symbol(secondary_startup),
0148            sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
0149 
0150     meson_smp_set_cpu_ctrl(cpu, true);
0151 
0152     return 0;
0153 }
0154 
0155 static int meson8_smp_boot_secondary(unsigned int cpu,
0156                      struct task_struct *idle)
0157 {
0158     struct reset_control *rstc;
0159     int ret;
0160 
0161     rstc = meson_smp_get_core_reset(cpu);
0162     if (IS_ERR(rstc)) {
0163         pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
0164         return PTR_ERR(rstc);
0165     }
0166 
0167     meson_smp_begin_secondary_boot(cpu);
0168 
0169     /* Reset enable */
0170     ret = reset_control_assert(rstc);
0171     if (ret) {
0172         pr_err("Failed to assert CPU%d reset\n", cpu);
0173         goto out;
0174     }
0175 
0176     /* CPU power ON */
0177     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
0178                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
0179     if (ret < 0) {
0180         pr_err("Couldn't wake up CPU%d\n", cpu);
0181         goto out;
0182     }
0183 
0184     udelay(10);
0185 
0186     /* Isolation disable */
0187     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
0188                  0);
0189     if (ret < 0) {
0190         pr_err("Error when disabling isolation of CPU%d\n", cpu);
0191         goto out;
0192     }
0193 
0194     /* Reset disable */
0195     ret = reset_control_deassert(rstc);
0196     if (ret) {
0197         pr_err("Failed to de-assert CPU%d reset\n", cpu);
0198         goto out;
0199     }
0200 
0201     ret = meson_smp_finalize_secondary_boot(cpu);
0202     if (ret)
0203         goto out;
0204 
0205 out:
0206     reset_control_put(rstc);
0207 
0208     return 0;
0209 }
0210 
0211 static int meson8b_smp_boot_secondary(unsigned int cpu,
0212                      struct task_struct *idle)
0213 {
0214     struct reset_control *rstc;
0215     int ret;
0216     u32 val;
0217 
0218     rstc = meson_smp_get_core_reset(cpu);
0219     if (IS_ERR(rstc)) {
0220         pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
0221         return PTR_ERR(rstc);
0222     }
0223 
0224     meson_smp_begin_secondary_boot(cpu);
0225 
0226     /* CPU power UP */
0227     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
0228                  MESON_CPU_PWR_A9_CNTL0_M(cpu), 0);
0229     if (ret < 0) {
0230         pr_err("Couldn't power up CPU%d\n", cpu);
0231         goto out;
0232     }
0233 
0234     udelay(5);
0235 
0236     /* Reset enable */
0237     ret = reset_control_assert(rstc);
0238     if (ret) {
0239         pr_err("Failed to assert CPU%d reset\n", cpu);
0240         goto out;
0241     }
0242 
0243     /* Memory power UP */
0244     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
0245                  MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0);
0246     if (ret < 0) {
0247         pr_err("Couldn't power up the memory for CPU%d\n", cpu);
0248         goto out;
0249     }
0250 
0251     /* Wake up CPU */
0252     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
0253                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
0254     if (ret < 0) {
0255         pr_err("Couldn't wake up CPU%d\n", cpu);
0256         goto out;
0257     }
0258 
0259     udelay(10);
0260 
0261     ret = regmap_read_poll_timeout(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1, val,
0262                        val & MESON_CPU_PWR_A9_CNTL1_ST(cpu),
0263                        10, 10000);
0264     if (ret) {
0265         pr_err("Timeout while polling PMU for CPU%d status\n", cpu);
0266         goto out;
0267     }
0268 
0269     /* Isolation disable */
0270     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
0271                  0);
0272     if (ret < 0) {
0273         pr_err("Error when disabling isolation of CPU%d\n", cpu);
0274         goto out;
0275     }
0276 
0277     /* Reset disable */
0278     ret = reset_control_deassert(rstc);
0279     if (ret) {
0280         pr_err("Failed to de-assert CPU%d reset\n", cpu);
0281         goto out;
0282     }
0283 
0284     ret = meson_smp_finalize_secondary_boot(cpu);
0285     if (ret)
0286         goto out;
0287 
0288 out:
0289     reset_control_put(rstc);
0290 
0291     return 0;
0292 }
0293 
0294 #ifdef CONFIG_HOTPLUG_CPU
0295 static void meson8_smp_cpu_die(unsigned int cpu)
0296 {
0297     meson_smp_set_cpu_ctrl(cpu, false);
0298 
0299     v7_exit_coherency_flush(louis);
0300 
0301     scu_power_mode(scu_base, SCU_PM_POWEROFF);
0302 
0303     dsb();
0304     wfi();
0305 
0306     /* we should never get here */
0307     WARN_ON(1);
0308 }
0309 
0310 static int meson8_smp_cpu_kill(unsigned int cpu)
0311 {
0312     int ret, power_mode;
0313     unsigned long timeout;
0314 
0315     timeout = jiffies + (50 * HZ);
0316     do {
0317         power_mode = scu_get_cpu_power_mode(scu_base, cpu);
0318 
0319         if (power_mode == SCU_PM_POWEROFF)
0320             break;
0321 
0322         usleep_range(10000, 15000);
0323     } while (time_before(jiffies, timeout));
0324 
0325     if (power_mode != SCU_PM_POWEROFF) {
0326         pr_err("Error while waiting for SCU power-off on CPU%d\n",
0327                cpu);
0328         return -ETIMEDOUT;
0329     }
0330 
0331     msleep(30);
0332 
0333     /* Isolation enable */
0334     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
0335                  0x3);
0336     if (ret < 0) {
0337         pr_err("Error when enabling isolation for CPU%d\n", cpu);
0338         return ret;
0339     }
0340 
0341     udelay(10);
0342 
0343     /* CPU power OFF */
0344     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
0345                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
0346     if (ret < 0) {
0347         pr_err("Couldn't change sleep status of CPU%d\n", cpu);
0348         return ret;
0349     }
0350 
0351     return 1;
0352 }
0353 
0354 static int meson8b_smp_cpu_kill(unsigned int cpu)
0355 {
0356     int ret, power_mode, count = 5000;
0357 
0358     do {
0359         power_mode = scu_get_cpu_power_mode(scu_base, cpu);
0360 
0361         if (power_mode == SCU_PM_POWEROFF)
0362             break;
0363 
0364         udelay(10);
0365     } while (++count);
0366 
0367     if (power_mode != SCU_PM_POWEROFF) {
0368         pr_err("Error while waiting for SCU power-off on CPU%d\n",
0369                cpu);
0370         return -ETIMEDOUT;
0371     }
0372 
0373     udelay(10);
0374 
0375     /* CPU power DOWN */
0376     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
0377                  MESON_CPU_PWR_A9_CNTL0_M(cpu), 0x3);
0378     if (ret < 0) {
0379         pr_err("Couldn't power down CPU%d\n", cpu);
0380         return ret;
0381     }
0382 
0383     /* Isolation enable */
0384     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
0385                  0x3);
0386     if (ret < 0) {
0387         pr_err("Error when enabling isolation for CPU%d\n", cpu);
0388         return ret;
0389     }
0390 
0391     udelay(10);
0392 
0393     /* Sleep status */
0394     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
0395                  MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
0396     if (ret < 0) {
0397         pr_err("Couldn't change sleep status of CPU%d\n", cpu);
0398         return ret;
0399     }
0400 
0401     /* Memory power DOWN */
0402     ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
0403                  MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0xf);
0404     if (ret < 0) {
0405         pr_err("Couldn't power down the memory of CPU%d\n", cpu);
0406         return ret;
0407     }
0408 
0409     return 1;
0410 }
0411 #endif
0412 
0413 static struct smp_operations meson8_smp_ops __initdata = {
0414     .smp_prepare_cpus   = meson8_smp_prepare_cpus,
0415     .smp_boot_secondary = meson8_smp_boot_secondary,
0416 #ifdef CONFIG_HOTPLUG_CPU
0417     .cpu_die        = meson8_smp_cpu_die,
0418     .cpu_kill       = meson8_smp_cpu_kill,
0419 #endif
0420 };
0421 
0422 static struct smp_operations meson8b_smp_ops __initdata = {
0423     .smp_prepare_cpus   = meson8b_smp_prepare_cpus,
0424     .smp_boot_secondary = meson8b_smp_boot_secondary,
0425 #ifdef CONFIG_HOTPLUG_CPU
0426     .cpu_die        = meson8_smp_cpu_die,
0427     .cpu_kill       = meson8b_smp_cpu_kill,
0428 #endif
0429 };
0430 
0431 CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
0432 CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);