linux/arch/arm/mach-sunxi/platsmp.c
<<
>>
Prefs
   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
  37static void __iomem *cpucfg_membase;
  38static void __iomem *prcm_membase;
  39
  40static DEFINE_SPINLOCK(cpu_lock);
  41
  42static 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        if (!prcm_membase) {
  54                pr_err("Couldn't map A31 PRCM registers\n");
  55                return;
  56        }
  57
  58        node = of_find_compatible_node(NULL, NULL,
  59                                       "allwinner,sun6i-a31-cpuconfig");
  60        if (!node) {
  61                pr_err("Missing A31 CPU config node in the device tree\n");
  62                return;
  63        }
  64
  65        cpucfg_membase = of_iomap(node, 0);
  66        if (!cpucfg_membase)
  67                pr_err("Couldn't map A31 CPU config registers\n");
  68
  69}
  70
  71static int sun6i_smp_boot_secondary(unsigned int cpu,
  72                                    struct task_struct *idle)
  73{
  74        u32 reg;
  75        int i;
  76
  77        if (!(prcm_membase && cpucfg_membase))
  78                return -EFAULT;
  79
  80        spin_lock(&cpu_lock);
  81
  82        /* Set CPU boot address */
  83        writel(__pa_symbol(secondary_startup),
  84               cpucfg_membase + CPUCFG_PRIVATE0_REG);
  85
  86        /* Assert the CPU core in reset */
  87        writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
  88
  89        /* Assert the L1 cache in reset */
  90        reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  91        writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
  92
  93        /* Disable external debug access */
  94        reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  95        writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
  96
  97        /* Power up the CPU */
  98        for (i = 0; i <= 8; i++)
  99                writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
 100        mdelay(10);
 101
 102        /* Clear CPU power-off gating */
 103        reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
 104        writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
 105        mdelay(1);
 106
 107        /* Deassert the CPU core reset */
 108        writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 109
 110        /* Enable back the external debug accesses */
 111        reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 112        writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 113
 114        spin_unlock(&cpu_lock);
 115
 116        return 0;
 117}
 118
 119static const struct smp_operations sun6i_smp_ops __initconst = {
 120        .smp_prepare_cpus       = sun6i_smp_prepare_cpus,
 121        .smp_boot_secondary     = sun6i_smp_boot_secondary,
 122};
 123CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
 124
 125static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
 126{
 127        struct device_node *node;
 128
 129        node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
 130        if (!node) {
 131                pr_err("Missing A23 PRCM node in the device tree\n");
 132                return;
 133        }
 134
 135        prcm_membase = of_iomap(node, 0);
 136        if (!prcm_membase) {
 137                pr_err("Couldn't map A23 PRCM registers\n");
 138                return;
 139        }
 140
 141        node = of_find_compatible_node(NULL, NULL,
 142                                       "allwinner,sun8i-a23-cpuconfig");
 143        if (!node) {
 144                pr_err("Missing A23 CPU config node in the device tree\n");
 145                return;
 146        }
 147
 148        cpucfg_membase = of_iomap(node, 0);
 149        if (!cpucfg_membase)
 150                pr_err("Couldn't map A23 CPU config registers\n");
 151
 152}
 153
 154static int sun8i_smp_boot_secondary(unsigned int cpu,
 155                                    struct task_struct *idle)
 156{
 157        u32 reg;
 158
 159        if (!(prcm_membase && cpucfg_membase))
 160                return -EFAULT;
 161
 162        spin_lock(&cpu_lock);
 163
 164        /* Set CPU boot address */
 165        writel(__pa_symbol(secondary_startup),
 166               cpucfg_membase + CPUCFG_PRIVATE0_REG);
 167
 168        /* Assert the CPU core in reset */
 169        writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 170
 171        /* Assert the L1 cache in reset */
 172        reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 173        writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 174
 175        /* Clear CPU power-off gating */
 176        reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
 177        writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
 178        mdelay(1);
 179
 180        /* Deassert the CPU core reset */
 181        writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 182
 183        spin_unlock(&cpu_lock);
 184
 185        return 0;
 186}
 187
 188static const struct smp_operations sun8i_smp_ops __initconst = {
 189        .smp_prepare_cpus       = sun8i_smp_prepare_cpus,
 190        .smp_boot_secondary     = sun8i_smp_boot_secondary,
 191};
 192CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);
 193