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

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

DEFINITIONS

This source file includes following definitions.
  1. sun6i_smp_prepare_cpus
  2. sun6i_smp_boot_secondary
  3. sun8i_smp_prepare_cpus
  4. sun8i_smp_boot_secondary

   1 /*
   2  * SMP support for Allwinner SoCs
   3  *
   4  * Copyright (C) 2013 Maxime Ripard
   5  *
   6  * Maxime Ripard <maxime.ripard@free-electrons.com>
   7  *
   8  * Based on code
   9  *  Copyright (C) 2012-2013 Allwinner Ltd.
  10  *
  11  * This file is licensed under the terms of the GNU General Public
  12  * License version 2.  This program is licensed "as is" without any
  13  * warranty of any kind, whether express or implied.
  14  */
  15 
  16 #include <linux/delay.h>
  17 #include <linux/init.h>
  18 #include <linux/io.h>
  19 #include <linux/memory.h>
  20 #include <linux/of.h>
  21 #include <linux/of_address.h>
  22 #include <linux/smp.h>
  23 
  24 #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu)    ((cpu) * 0x40 + 0x64)
  25 #define CPUCFG_CPU_RST_CTRL_REG(cpu)            (((cpu) + 1) * 0x40)
  26 #define CPUCFG_CPU_CTRL_REG(cpu)                (((cpu) + 1) * 0x40 + 0x04)
  27 #define CPUCFG_CPU_STATUS_REG(cpu)              (((cpu) + 1) * 0x40 + 0x08)
  28 #define CPUCFG_GEN_CTRL_REG                     0x184
  29 #define CPUCFG_PRIVATE0_REG                     0x1a4
  30 #define CPUCFG_PRIVATE1_REG                     0x1a8
  31 #define CPUCFG_DBG_CTL0_REG                     0x1e0
  32 #define CPUCFG_DBG_CTL1_REG                     0x1e4
  33 
  34 #define PRCM_CPU_PWROFF_REG                     0x100
  35 #define PRCM_CPU_PWR_CLAMP_REG(cpu)             (((cpu) * 4) + 0x140)
  36 
  37 static void __iomem *cpucfg_membase;
  38 static void __iomem *prcm_membase;
  39 
  40 static DEFINE_SPINLOCK(cpu_lock);
  41 
  42 static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
  43 {
  44         struct device_node *node;
  45 
  46         node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
  47         if (!node) {
  48                 pr_err("Missing A31 PRCM node in the device tree\n");
  49                 return;
  50         }
  51 
  52         prcm_membase = of_iomap(node, 0);
  53         of_node_put(node);
  54         if (!prcm_membase) {
  55                 pr_err("Couldn't map A31 PRCM registers\n");
  56                 return;
  57         }
  58 
  59         node = of_find_compatible_node(NULL, NULL,
  60                                        "allwinner,sun6i-a31-cpuconfig");
  61         if (!node) {
  62                 pr_err("Missing A31 CPU config node in the device tree\n");
  63                 return;
  64         }
  65 
  66         cpucfg_membase = of_iomap(node, 0);
  67         of_node_put(node);
  68         if (!cpucfg_membase)
  69                 pr_err("Couldn't map A31 CPU config registers\n");
  70 
  71 }
  72 
  73 static int sun6i_smp_boot_secondary(unsigned int cpu,
  74                                     struct task_struct *idle)
  75 {
  76         u32 reg;
  77         int i;
  78 
  79         if (!(prcm_membase && cpucfg_membase))
  80                 return -EFAULT;
  81 
  82         spin_lock(&cpu_lock);
  83 
  84         /* Set CPU boot address */
  85         writel(__pa_symbol(secondary_startup),
  86                cpucfg_membase + CPUCFG_PRIVATE0_REG);
  87 
  88         /* Assert the CPU core in reset */
  89         writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  90 
  91         /* Assert the L1 cache in reset */
  92         reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  93         writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  94 
  95         /* Disable external debug access */
  96         reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  97         writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  98 
  99         /* Power up the CPU */
 100         for (i = 0; i <= 8; i++)
 101                 writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
 102         mdelay(10);
 103 
 104         /* Clear CPU power-off gating */
 105         reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
 106         writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
 107         mdelay(1);
 108 
 109         /* Deassert the CPU core reset */
 110         writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 111 
 112         /* Enable back the external debug accesses */
 113         reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 114         writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 115 
 116         spin_unlock(&cpu_lock);
 117 
 118         return 0;
 119 }
 120 
 121 static const struct smp_operations sun6i_smp_ops __initconst = {
 122         .smp_prepare_cpus       = sun6i_smp_prepare_cpus,
 123         .smp_boot_secondary     = sun6i_smp_boot_secondary,
 124 };
 125 CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
 126 
 127 static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
 128 {
 129         struct device_node *node;
 130 
 131         node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
 132         if (!node) {
 133                 pr_err("Missing A23 PRCM node in the device tree\n");
 134                 return;
 135         }
 136 
 137         prcm_membase = of_iomap(node, 0);
 138         of_node_put(node);
 139         if (!prcm_membase) {
 140                 pr_err("Couldn't map A23 PRCM registers\n");
 141                 return;
 142         }
 143 
 144         node = of_find_compatible_node(NULL, NULL,
 145                                        "allwinner,sun8i-a23-cpuconfig");
 146         if (!node) {
 147                 pr_err("Missing A23 CPU config node in the device tree\n");
 148                 return;
 149         }
 150 
 151         cpucfg_membase = of_iomap(node, 0);
 152         of_node_put(node);
 153         if (!cpucfg_membase)
 154                 pr_err("Couldn't map A23 CPU config registers\n");
 155 
 156 }
 157 
 158 static int sun8i_smp_boot_secondary(unsigned int cpu,
 159                                     struct task_struct *idle)
 160 {
 161         u32 reg;
 162 
 163         if (!(prcm_membase && cpucfg_membase))
 164                 return -EFAULT;
 165 
 166         spin_lock(&cpu_lock);
 167 
 168         /* Set CPU boot address */
 169         writel(__pa_symbol(secondary_startup),
 170                cpucfg_membase + CPUCFG_PRIVATE0_REG);
 171 
 172         /* Assert the CPU core in reset */
 173         writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 174 
 175         /* Assert the L1 cache in reset */
 176         reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 177         writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 178 
 179         /* Clear CPU power-off gating */
 180         reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
 181         writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
 182         mdelay(1);
 183 
 184         /* Deassert the CPU core reset */
 185         writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 186 
 187         spin_unlock(&cpu_lock);
 188 
 189         return 0;
 190 }
 191 
 192 static const struct smp_operations sun8i_smp_ops __initconst = {
 193         .smp_prepare_cpus       = sun8i_smp_prepare_cpus,
 194         .smp_boot_secondary     = sun8i_smp_boot_secondary,
 195 };
 196 CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);

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