Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SMP support for Allwinner SoCs
0004  *
0005  * Copyright (C) 2013 Maxime Ripard
0006  *
0007  * Maxime Ripard <maxime.ripard@free-electrons.com>
0008  *
0009  * Based on code
0010  *  Copyright (C) 2012-2013 Allwinner Ltd.
0011  *
0012  */
0013 
0014 #include <linux/delay.h>
0015 #include <linux/init.h>
0016 #include <linux/io.h>
0017 #include <linux/memory.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/smp.h>
0021 
0022 #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu)    ((cpu) * 0x40 + 0x64)
0023 #define CPUCFG_CPU_RST_CTRL_REG(cpu)        (((cpu) + 1) * 0x40)
0024 #define CPUCFG_CPU_CTRL_REG(cpu)        (((cpu) + 1) * 0x40 + 0x04)
0025 #define CPUCFG_CPU_STATUS_REG(cpu)      (((cpu) + 1) * 0x40 + 0x08)
0026 #define CPUCFG_GEN_CTRL_REG         0x184
0027 #define CPUCFG_PRIVATE0_REG         0x1a4
0028 #define CPUCFG_PRIVATE1_REG         0x1a8
0029 #define CPUCFG_DBG_CTL0_REG         0x1e0
0030 #define CPUCFG_DBG_CTL1_REG         0x1e4
0031 
0032 #define PRCM_CPU_PWROFF_REG         0x100
0033 #define PRCM_CPU_PWR_CLAMP_REG(cpu)     (((cpu) * 4) + 0x140)
0034 
0035 static void __iomem *cpucfg_membase;
0036 static void __iomem *prcm_membase;
0037 
0038 static DEFINE_SPINLOCK(cpu_lock);
0039 
0040 static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
0041 {
0042     struct device_node *node;
0043 
0044     node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
0045     if (!node) {
0046         pr_err("Missing A31 PRCM node in the device tree\n");
0047         return;
0048     }
0049 
0050     prcm_membase = of_iomap(node, 0);
0051     of_node_put(node);
0052     if (!prcm_membase) {
0053         pr_err("Couldn't map A31 PRCM registers\n");
0054         return;
0055     }
0056 
0057     node = of_find_compatible_node(NULL, NULL,
0058                        "allwinner,sun6i-a31-cpuconfig");
0059     if (!node) {
0060         pr_err("Missing A31 CPU config node in the device tree\n");
0061         return;
0062     }
0063 
0064     cpucfg_membase = of_iomap(node, 0);
0065     of_node_put(node);
0066     if (!cpucfg_membase)
0067         pr_err("Couldn't map A31 CPU config registers\n");
0068 
0069 }
0070 
0071 static int sun6i_smp_boot_secondary(unsigned int cpu,
0072                     struct task_struct *idle)
0073 {
0074     u32 reg;
0075     int i;
0076 
0077     if (!(prcm_membase && cpucfg_membase))
0078         return -EFAULT;
0079 
0080     spin_lock(&cpu_lock);
0081 
0082     /* Set CPU boot address */
0083     writel(__pa_symbol(secondary_startup),
0084            cpucfg_membase + CPUCFG_PRIVATE0_REG);
0085 
0086     /* Assert the CPU core in reset */
0087     writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0088 
0089     /* Assert the L1 cache in reset */
0090     reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0091     writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0092 
0093     /* Disable external debug access */
0094     reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0095     writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0096 
0097     /* Power up the CPU */
0098     for (i = 0; i <= 8; i++)
0099         writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
0100     mdelay(10);
0101 
0102     /* Clear CPU power-off gating */
0103     reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
0104     writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
0105     mdelay(1);
0106 
0107     /* Deassert the CPU core reset */
0108     writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0109 
0110     /* Enable back the external debug accesses */
0111     reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0112     writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0113 
0114     spin_unlock(&cpu_lock);
0115 
0116     return 0;
0117 }
0118 
0119 static const struct smp_operations sun6i_smp_ops __initconst = {
0120     .smp_prepare_cpus   = sun6i_smp_prepare_cpus,
0121     .smp_boot_secondary = sun6i_smp_boot_secondary,
0122 };
0123 CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
0124 
0125 static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
0126 {
0127     struct device_node *node;
0128 
0129     node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
0130     if (!node) {
0131         pr_err("Missing A23 PRCM node in the device tree\n");
0132         return;
0133     }
0134 
0135     prcm_membase = of_iomap(node, 0);
0136     of_node_put(node);
0137     if (!prcm_membase) {
0138         pr_err("Couldn't map A23 PRCM registers\n");
0139         return;
0140     }
0141 
0142     node = of_find_compatible_node(NULL, NULL,
0143                        "allwinner,sun8i-a23-cpuconfig");
0144     if (!node) {
0145         pr_err("Missing A23 CPU config node in the device tree\n");
0146         return;
0147     }
0148 
0149     cpucfg_membase = of_iomap(node, 0);
0150     of_node_put(node);
0151     if (!cpucfg_membase)
0152         pr_err("Couldn't map A23 CPU config registers\n");
0153 
0154 }
0155 
0156 static int sun8i_smp_boot_secondary(unsigned int cpu,
0157                     struct task_struct *idle)
0158 {
0159     u32 reg;
0160 
0161     if (!(prcm_membase && cpucfg_membase))
0162         return -EFAULT;
0163 
0164     spin_lock(&cpu_lock);
0165 
0166     /* Set CPU boot address */
0167     writel(__pa_symbol(secondary_startup),
0168            cpucfg_membase + CPUCFG_PRIVATE0_REG);
0169 
0170     /* Assert the CPU core in reset */
0171     writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0172 
0173     /* Assert the L1 cache in reset */
0174     reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0175     writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0176 
0177     /* Clear CPU power-off gating */
0178     reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
0179     writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
0180     mdelay(1);
0181 
0182     /* Deassert the CPU core reset */
0183     writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0184 
0185     spin_unlock(&cpu_lock);
0186 
0187     return 0;
0188 }
0189 
0190 static const struct smp_operations sun8i_smp_ops __initconst = {
0191     .smp_prepare_cpus   = sun8i_smp_prepare_cpus,
0192     .smp_boot_secondary = sun8i_smp_boot_secondary,
0193 };
0194 CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);