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

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

DEFINITIONS

This source file includes following definitions.
  1. qcom_cpu_die
  2. scss_release_secondary
  3. kpssv1_release_secondary
  4. kpssv2_release_secondary
  5. qcom_boot_secondary
  6. msm8660_boot_secondary
  7. kpssv1_boot_secondary
  8. kpssv2_boot_secondary
  9. qcom_smp_prepare_cpus

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  Copyright (C) 2002 ARM Ltd.
   4  *  All Rights Reserved
   5  *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
   6  *  Copyright (c) 2014 The Linux Foundation. All rights reserved.
   7  */
   8 
   9 #include <linux/init.h>
  10 #include <linux/errno.h>
  11 #include <linux/delay.h>
  12 #include <linux/device.h>
  13 #include <linux/of.h>
  14 #include <linux/of_address.h>
  15 #include <linux/smp.h>
  16 #include <linux/io.h>
  17 #include <linux/qcom_scm.h>
  18 
  19 #include <asm/smp_plat.h>
  20 
  21 
  22 #define VDD_SC1_ARRAY_CLAMP_GFS_CTL     0x35a0
  23 #define SCSS_CPU1CORE_RESET             0x2d80
  24 #define SCSS_DBG_STATUS_CORE_PWRDUP     0x2e64
  25 
  26 #define APCS_CPU_PWR_CTL        0x04
  27 #define PLL_CLAMP               BIT(8)
  28 #define CORE_PWRD_UP            BIT(7)
  29 #define COREPOR_RST             BIT(5)
  30 #define CORE_RST                BIT(4)
  31 #define L2DT_SLP                BIT(3)
  32 #define CLAMP                   BIT(0)
  33 
  34 #define APC_PWR_GATE_CTL        0x14
  35 #define BHS_CNT_SHIFT           24
  36 #define LDO_PWR_DWN_SHIFT       16
  37 #define LDO_BYP_SHIFT           8
  38 #define BHS_SEG_SHIFT           1
  39 #define BHS_EN                  BIT(0)
  40 
  41 #define APCS_SAW2_VCTL          0x14
  42 #define APCS_SAW2_2_VCTL        0x1c
  43 
  44 extern void secondary_startup_arm(void);
  45 
  46 #ifdef CONFIG_HOTPLUG_CPU
  47 static void qcom_cpu_die(unsigned int cpu)
  48 {
  49         wfi();
  50 }
  51 #endif
  52 
  53 static int scss_release_secondary(unsigned int cpu)
  54 {
  55         struct device_node *node;
  56         void __iomem *base;
  57 
  58         node = of_find_compatible_node(NULL, NULL, "qcom,gcc-msm8660");
  59         if (!node) {
  60                 pr_err("%s: can't find node\n", __func__);
  61                 return -ENXIO;
  62         }
  63 
  64         base = of_iomap(node, 0);
  65         of_node_put(node);
  66         if (!base)
  67                 return -ENOMEM;
  68 
  69         writel_relaxed(0, base + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
  70         writel_relaxed(0, base + SCSS_CPU1CORE_RESET);
  71         writel_relaxed(3, base + SCSS_DBG_STATUS_CORE_PWRDUP);
  72         mb();
  73         iounmap(base);
  74 
  75         return 0;
  76 }
  77 
  78 static int kpssv1_release_secondary(unsigned int cpu)
  79 {
  80         int ret = 0;
  81         void __iomem *reg, *saw_reg;
  82         struct device_node *cpu_node, *acc_node, *saw_node;
  83         u32 val;
  84 
  85         cpu_node = of_get_cpu_node(cpu, NULL);
  86         if (!cpu_node)
  87                 return -ENODEV;
  88 
  89         acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
  90         if (!acc_node) {
  91                 ret = -ENODEV;
  92                 goto out_acc;
  93         }
  94 
  95         saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
  96         if (!saw_node) {
  97                 ret = -ENODEV;
  98                 goto out_saw;
  99         }
 100 
 101         reg = of_iomap(acc_node, 0);
 102         if (!reg) {
 103                 ret = -ENOMEM;
 104                 goto out_acc_map;
 105         }
 106 
 107         saw_reg = of_iomap(saw_node, 0);
 108         if (!saw_reg) {
 109                 ret = -ENOMEM;
 110                 goto out_saw_map;
 111         }
 112 
 113         /* Turn on CPU rail */
 114         writel_relaxed(0xA4, saw_reg + APCS_SAW2_VCTL);
 115         mb();
 116         udelay(512);
 117 
 118         /* Krait bring-up sequence */
 119         val = PLL_CLAMP | L2DT_SLP | CLAMP;
 120         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 121         val &= ~L2DT_SLP;
 122         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 123         mb();
 124         ndelay(300);
 125 
 126         val |= COREPOR_RST;
 127         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 128         mb();
 129         udelay(2);
 130 
 131         val &= ~CLAMP;
 132         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 133         mb();
 134         udelay(2);
 135 
 136         val &= ~COREPOR_RST;
 137         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 138         mb();
 139         udelay(100);
 140 
 141         val |= CORE_PWRD_UP;
 142         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
 143         mb();
 144 
 145         iounmap(saw_reg);
 146 out_saw_map:
 147         iounmap(reg);
 148 out_acc_map:
 149         of_node_put(saw_node);
 150 out_saw:
 151         of_node_put(acc_node);
 152 out_acc:
 153         of_node_put(cpu_node);
 154         return ret;
 155 }
 156 
 157 static int kpssv2_release_secondary(unsigned int cpu)
 158 {
 159         void __iomem *reg;
 160         struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
 161         void __iomem *l2_saw_base;
 162         unsigned reg_val;
 163         int ret;
 164 
 165         cpu_node = of_get_cpu_node(cpu, NULL);
 166         if (!cpu_node)
 167                 return -ENODEV;
 168 
 169         acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
 170         if (!acc_node) {
 171                 ret = -ENODEV;
 172                 goto out_acc;
 173         }
 174 
 175         l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
 176         if (!l2_node) {
 177                 ret = -ENODEV;
 178                 goto out_l2;
 179         }
 180 
 181         saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
 182         if (!saw_node) {
 183                 ret = -ENODEV;
 184                 goto out_saw;
 185         }
 186 
 187         reg = of_iomap(acc_node, 0);
 188         if (!reg) {
 189                 ret = -ENOMEM;
 190                 goto out_map;
 191         }
 192 
 193         l2_saw_base = of_iomap(saw_node, 0);
 194         if (!l2_saw_base) {
 195                 ret = -ENOMEM;
 196                 goto out_saw_map;
 197         }
 198 
 199         /* Turn on the BHS, turn off LDO Bypass and power down LDO */
 200         reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
 201         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
 202         mb();
 203         /* wait for the BHS to settle */
 204         udelay(1);
 205 
 206         /* Turn on BHS segments */
 207         reg_val |= 0x3f << BHS_SEG_SHIFT;
 208         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
 209         mb();
 210          /* wait for the BHS to settle */
 211         udelay(1);
 212 
 213         /* Finally turn on the bypass so that BHS supplies power */
 214         reg_val |= 0x3f << LDO_BYP_SHIFT;
 215         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
 216 
 217         /* enable max phases */
 218         writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
 219         mb();
 220         udelay(50);
 221 
 222         reg_val = COREPOR_RST | CLAMP;
 223         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
 224         mb();
 225         udelay(2);
 226 
 227         reg_val &= ~CLAMP;
 228         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
 229         mb();
 230         udelay(2);
 231 
 232         reg_val &= ~COREPOR_RST;
 233         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
 234         mb();
 235 
 236         reg_val |= CORE_PWRD_UP;
 237         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
 238         mb();
 239 
 240         ret = 0;
 241 
 242         iounmap(l2_saw_base);
 243 out_saw_map:
 244         iounmap(reg);
 245 out_map:
 246         of_node_put(saw_node);
 247 out_saw:
 248         of_node_put(l2_node);
 249 out_l2:
 250         of_node_put(acc_node);
 251 out_acc:
 252         of_node_put(cpu_node);
 253 
 254         return ret;
 255 }
 256 
 257 static DEFINE_PER_CPU(int, cold_boot_done);
 258 
 259 static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
 260 {
 261         int ret = 0;
 262 
 263         if (!per_cpu(cold_boot_done, cpu)) {
 264                 ret = func(cpu);
 265                 if (!ret)
 266                         per_cpu(cold_boot_done, cpu) = true;
 267         }
 268 
 269         /*
 270          * Send the secondary CPU a soft interrupt, thereby causing
 271          * the boot monitor to read the system wide flags register,
 272          * and branch to the address found there.
 273          */
 274         arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 275 
 276         return ret;
 277 }
 278 
 279 static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
 280 {
 281         return qcom_boot_secondary(cpu, scss_release_secondary);
 282 }
 283 
 284 static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
 285 {
 286         return qcom_boot_secondary(cpu, kpssv1_release_secondary);
 287 }
 288 
 289 static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
 290 {
 291         return qcom_boot_secondary(cpu, kpssv2_release_secondary);
 292 }
 293 
 294 static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
 295 {
 296         int cpu;
 297 
 298         if (qcom_scm_set_cold_boot_addr(secondary_startup_arm,
 299                                         cpu_present_mask)) {
 300                 for_each_present_cpu(cpu) {
 301                         if (cpu == smp_processor_id())
 302                                 continue;
 303                         set_cpu_present(cpu, false);
 304                 }
 305                 pr_warn("Failed to set CPU boot address, disabling SMP\n");
 306         }
 307 }
 308 
 309 static const struct smp_operations smp_msm8660_ops __initconst = {
 310         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
 311         .smp_boot_secondary     = msm8660_boot_secondary,
 312 #ifdef CONFIG_HOTPLUG_CPU
 313         .cpu_die                = qcom_cpu_die,
 314 #endif
 315 };
 316 CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
 317 
 318 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
 319         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
 320         .smp_boot_secondary     = kpssv1_boot_secondary,
 321 #ifdef CONFIG_HOTPLUG_CPU
 322         .cpu_die                = qcom_cpu_die,
 323 #endif
 324 };
 325 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
 326 
 327 static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
 328         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
 329         .smp_boot_secondary     = kpssv2_boot_secondary,
 330 #ifdef CONFIG_HOTPLUG_CPU
 331         .cpu_die                = qcom_cpu_die,
 332 #endif
 333 };
 334 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);

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