0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
0083 writel(__pa_symbol(secondary_startup),
0084 cpucfg_membase + CPUCFG_PRIVATE0_REG);
0085
0086
0087 writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0088
0089
0090 reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0091 writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0092
0093
0094 reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0095 writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
0096
0097
0098 for (i = 0; i <= 8; i++)
0099 writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
0100 mdelay(10);
0101
0102
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
0108 writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0109
0110
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
0167 writel(__pa_symbol(secondary_startup),
0168 cpucfg_membase + CPUCFG_PRIVATE0_REG);
0169
0170
0171 writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
0172
0173
0174 reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0175 writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
0176
0177
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
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);