Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (C) 2002 ARM Ltd.
0004  *  All Rights Reserved
0005  *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
0006  *  Copyright (c) 2014 The Linux Foundation. All rights reserved.
0007  */
0008 
0009 #include <linux/init.h>
0010 #include <linux/errno.h>
0011 #include <linux/delay.h>
0012 #include <linux/device.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/smp.h>
0016 #include <linux/io.h>
0017 #include <linux/qcom_scm.h>
0018 
0019 #include <asm/smp_plat.h>
0020 
0021 
0022 #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x35a0
0023 #define SCSS_CPU1CORE_RESET     0x2d80
0024 #define SCSS_DBG_STATUS_CORE_PWRDUP 0x2e64
0025 
0026 #define APCS_CPU_PWR_CTL    0x04
0027 #define PLL_CLAMP       BIT(8)
0028 #define CORE_PWRD_UP        BIT(7)
0029 #define COREPOR_RST     BIT(5)
0030 #define CORE_RST        BIT(4)
0031 #define L2DT_SLP        BIT(3)
0032 #define CORE_MEM_CLAMP      BIT(1)
0033 #define CLAMP           BIT(0)
0034 
0035 #define APC_PWR_GATE_CTL    0x14
0036 #define BHS_CNT_SHIFT       24
0037 #define LDO_PWR_DWN_SHIFT   16
0038 #define LDO_BYP_SHIFT       8
0039 #define BHS_SEG_SHIFT       1
0040 #define BHS_EN          BIT(0)
0041 
0042 #define APCS_SAW2_VCTL      0x14
0043 #define APCS_SAW2_2_VCTL    0x1c
0044 
0045 extern void secondary_startup_arm(void);
0046 
0047 #ifdef CONFIG_HOTPLUG_CPU
0048 static void qcom_cpu_die(unsigned int cpu)
0049 {
0050     wfi();
0051 }
0052 #endif
0053 
0054 static int scss_release_secondary(unsigned int cpu)
0055 {
0056     struct device_node *node;
0057     void __iomem *base;
0058 
0059     node = of_find_compatible_node(NULL, NULL, "qcom,gcc-msm8660");
0060     if (!node) {
0061         pr_err("%s: can't find node\n", __func__);
0062         return -ENXIO;
0063     }
0064 
0065     base = of_iomap(node, 0);
0066     of_node_put(node);
0067     if (!base)
0068         return -ENOMEM;
0069 
0070     writel_relaxed(0, base + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
0071     writel_relaxed(0, base + SCSS_CPU1CORE_RESET);
0072     writel_relaxed(3, base + SCSS_DBG_STATUS_CORE_PWRDUP);
0073     mb();
0074     iounmap(base);
0075 
0076     return 0;
0077 }
0078 
0079 static int cortex_a7_release_secondary(unsigned int cpu)
0080 {
0081     int ret = 0;
0082     void __iomem *reg;
0083     struct device_node *cpu_node, *acc_node;
0084     u32 reg_val;
0085 
0086     cpu_node = of_get_cpu_node(cpu, NULL);
0087     if (!cpu_node)
0088         return -ENODEV;
0089 
0090     acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
0091     if (!acc_node) {
0092         ret = -ENODEV;
0093         goto out_acc;
0094     }
0095 
0096     reg = of_iomap(acc_node, 0);
0097     if (!reg) {
0098         ret = -ENOMEM;
0099         goto out_acc_map;
0100     }
0101 
0102     /* Put the CPU into reset. */
0103     reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP;
0104     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0105 
0106     /* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */
0107     writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL);
0108     /* Wait for the BHS to settle */
0109     udelay(2);
0110 
0111     reg_val &= ~CORE_MEM_CLAMP;
0112     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0113     reg_val |= L2DT_SLP;
0114     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0115     udelay(2);
0116 
0117     reg_val = (reg_val | BIT(17)) & ~CLAMP;
0118     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0119     udelay(2);
0120 
0121     /* Release CPU out of reset and bring it to life. */
0122     reg_val &= ~(CORE_RST | COREPOR_RST);
0123     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0124     reg_val |= CORE_PWRD_UP;
0125     writel(reg_val, reg + APCS_CPU_PWR_CTL);
0126 
0127     iounmap(reg);
0128 out_acc_map:
0129     of_node_put(acc_node);
0130 out_acc:
0131     of_node_put(cpu_node);
0132     return ret;
0133 }
0134 
0135 static int kpssv1_release_secondary(unsigned int cpu)
0136 {
0137     int ret = 0;
0138     void __iomem *reg, *saw_reg;
0139     struct device_node *cpu_node, *acc_node, *saw_node;
0140     u32 val;
0141 
0142     cpu_node = of_get_cpu_node(cpu, NULL);
0143     if (!cpu_node)
0144         return -ENODEV;
0145 
0146     acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
0147     if (!acc_node) {
0148         ret = -ENODEV;
0149         goto out_acc;
0150     }
0151 
0152     saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
0153     if (!saw_node) {
0154         ret = -ENODEV;
0155         goto out_saw;
0156     }
0157 
0158     reg = of_iomap(acc_node, 0);
0159     if (!reg) {
0160         ret = -ENOMEM;
0161         goto out_acc_map;
0162     }
0163 
0164     saw_reg = of_iomap(saw_node, 0);
0165     if (!saw_reg) {
0166         ret = -ENOMEM;
0167         goto out_saw_map;
0168     }
0169 
0170     /* Turn on CPU rail */
0171     writel_relaxed(0xA4, saw_reg + APCS_SAW2_VCTL);
0172     mb();
0173     udelay(512);
0174 
0175     /* Krait bring-up sequence */
0176     val = PLL_CLAMP | L2DT_SLP | CLAMP;
0177     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0178     val &= ~L2DT_SLP;
0179     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0180     mb();
0181     ndelay(300);
0182 
0183     val |= COREPOR_RST;
0184     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0185     mb();
0186     udelay(2);
0187 
0188     val &= ~CLAMP;
0189     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0190     mb();
0191     udelay(2);
0192 
0193     val &= ~COREPOR_RST;
0194     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0195     mb();
0196     udelay(100);
0197 
0198     val |= CORE_PWRD_UP;
0199     writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
0200     mb();
0201 
0202     iounmap(saw_reg);
0203 out_saw_map:
0204     iounmap(reg);
0205 out_acc_map:
0206     of_node_put(saw_node);
0207 out_saw:
0208     of_node_put(acc_node);
0209 out_acc:
0210     of_node_put(cpu_node);
0211     return ret;
0212 }
0213 
0214 static int kpssv2_release_secondary(unsigned int cpu)
0215 {
0216     void __iomem *reg;
0217     struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
0218     void __iomem *l2_saw_base;
0219     unsigned reg_val;
0220     int ret;
0221 
0222     cpu_node = of_get_cpu_node(cpu, NULL);
0223     if (!cpu_node)
0224         return -ENODEV;
0225 
0226     acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
0227     if (!acc_node) {
0228         ret = -ENODEV;
0229         goto out_acc;
0230     }
0231 
0232     l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
0233     if (!l2_node) {
0234         ret = -ENODEV;
0235         goto out_l2;
0236     }
0237 
0238     saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
0239     if (!saw_node) {
0240         ret = -ENODEV;
0241         goto out_saw;
0242     }
0243 
0244     reg = of_iomap(acc_node, 0);
0245     if (!reg) {
0246         ret = -ENOMEM;
0247         goto out_map;
0248     }
0249 
0250     l2_saw_base = of_iomap(saw_node, 0);
0251     if (!l2_saw_base) {
0252         ret = -ENOMEM;
0253         goto out_saw_map;
0254     }
0255 
0256     /* Turn on the BHS, turn off LDO Bypass and power down LDO */
0257     reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
0258     writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
0259     mb();
0260     /* wait for the BHS to settle */
0261     udelay(1);
0262 
0263     /* Turn on BHS segments */
0264     reg_val |= 0x3f << BHS_SEG_SHIFT;
0265     writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
0266     mb();
0267      /* wait for the BHS to settle */
0268     udelay(1);
0269 
0270     /* Finally turn on the bypass so that BHS supplies power */
0271     reg_val |= 0x3f << LDO_BYP_SHIFT;
0272     writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
0273 
0274     /* enable max phases */
0275     writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
0276     mb();
0277     udelay(50);
0278 
0279     reg_val = COREPOR_RST | CLAMP;
0280     writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
0281     mb();
0282     udelay(2);
0283 
0284     reg_val &= ~CLAMP;
0285     writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
0286     mb();
0287     udelay(2);
0288 
0289     reg_val &= ~COREPOR_RST;
0290     writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
0291     mb();
0292 
0293     reg_val |= CORE_PWRD_UP;
0294     writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
0295     mb();
0296 
0297     ret = 0;
0298 
0299     iounmap(l2_saw_base);
0300 out_saw_map:
0301     iounmap(reg);
0302 out_map:
0303     of_node_put(saw_node);
0304 out_saw:
0305     of_node_put(l2_node);
0306 out_l2:
0307     of_node_put(acc_node);
0308 out_acc:
0309     of_node_put(cpu_node);
0310 
0311     return ret;
0312 }
0313 
0314 static DEFINE_PER_CPU(int, cold_boot_done);
0315 
0316 static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
0317 {
0318     int ret = 0;
0319 
0320     if (!per_cpu(cold_boot_done, cpu)) {
0321         ret = func(cpu);
0322         if (!ret)
0323             per_cpu(cold_boot_done, cpu) = true;
0324     }
0325 
0326     /*
0327      * Send the secondary CPU a soft interrupt, thereby causing
0328      * the boot monitor to read the system wide flags register,
0329      * and branch to the address found there.
0330      */
0331     arch_send_wakeup_ipi_mask(cpumask_of(cpu));
0332 
0333     return ret;
0334 }
0335 
0336 static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
0337 {
0338     return qcom_boot_secondary(cpu, scss_release_secondary);
0339 }
0340 
0341 static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle)
0342 {
0343     return qcom_boot_secondary(cpu, cortex_a7_release_secondary);
0344 }
0345 
0346 static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
0347 {
0348     return qcom_boot_secondary(cpu, kpssv1_release_secondary);
0349 }
0350 
0351 static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
0352 {
0353     return qcom_boot_secondary(cpu, kpssv2_release_secondary);
0354 }
0355 
0356 static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
0357 {
0358     int cpu;
0359 
0360     if (qcom_scm_set_cold_boot_addr(secondary_startup_arm)) {
0361         for_each_present_cpu(cpu) {
0362             if (cpu == smp_processor_id())
0363                 continue;
0364             set_cpu_present(cpu, false);
0365         }
0366         pr_warn("Failed to set CPU boot address, disabling SMP\n");
0367     }
0368 }
0369 
0370 static const struct smp_operations smp_msm8660_ops __initconst = {
0371     .smp_prepare_cpus   = qcom_smp_prepare_cpus,
0372     .smp_boot_secondary = msm8660_boot_secondary,
0373 #ifdef CONFIG_HOTPLUG_CPU
0374     .cpu_die        = qcom_cpu_die,
0375 #endif
0376 };
0377 CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
0378 
0379 static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
0380     .smp_prepare_cpus   = qcom_smp_prepare_cpus,
0381     .smp_boot_secondary = cortex_a7_boot_secondary,
0382 #ifdef CONFIG_HOTPLUG_CPU
0383     .cpu_die        = qcom_cpu_die,
0384 #endif
0385 };
0386 CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
0387 CPU_METHOD_OF_DECLARE(qcom_smp_msm8909, "qcom,msm8909-smp", &qcom_smp_cortex_a7_ops);
0388 CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
0389 
0390 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
0391     .smp_prepare_cpus   = qcom_smp_prepare_cpus,
0392     .smp_boot_secondary = kpssv1_boot_secondary,
0393 #ifdef CONFIG_HOTPLUG_CPU
0394     .cpu_die        = qcom_cpu_die,
0395 #endif
0396 };
0397 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
0398 
0399 static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
0400     .smp_prepare_cpus   = qcom_smp_prepare_cpus,
0401     .smp_boot_secondary = kpssv2_boot_secondary,
0402 #ifdef CONFIG_HOTPLUG_CPU
0403     .cpu_die        = qcom_cpu_die,
0404 #endif
0405 };
0406 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);