Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73e601ea authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'sunxi-core-for-4.2' of...

Merge tag 'sunxi-core-for-4.2' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into next/soc

Merge "Allwinner core additions for 4.2" from Maxime Ripard:

This pull request contains only the changes needed to support the SMP on
the Allwinner A23.

* tag 'sunxi-core-for-4.2' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux:
  ARM: sun8i: Add SMP support for the Allwinner A23
parents 3d00d04f 7917d141
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ nodes to be present and contain the properties described below.
			# On ARM 32-bit systems this property is optional and
			  can be one of:
			    "allwinner,sun6i-a31"
			    "allwinner,sun8i-a23"
			    "arm,psci"
			    "brcm,brahma-b15"
			    "marvell,armada-375-smp"
+69 −0
Original line number Diff line number Diff line
@@ -121,3 +121,72 @@ static struct smp_operations sun6i_smp_ops __initdata = {
	.smp_boot_secondary	= sun6i_smp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);

static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
{
	struct device_node *node;

	node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
	if (!node) {
		pr_err("Missing A23 PRCM node in the device tree\n");
		return;
	}

	prcm_membase = of_iomap(node, 0);
	if (!prcm_membase) {
		pr_err("Couldn't map A23 PRCM registers\n");
		return;
	}

	node = of_find_compatible_node(NULL, NULL,
				       "allwinner,sun8i-a23-cpuconfig");
	if (!node) {
		pr_err("Missing A23 CPU config node in the device tree\n");
		return;
	}

	cpucfg_membase = of_iomap(node, 0);
	if (!cpucfg_membase)
		pr_err("Couldn't map A23 CPU config registers\n");

}

static int sun8i_smp_boot_secondary(unsigned int cpu,
				    struct task_struct *idle)
{
	u32 reg;

	if (!(prcm_membase && cpucfg_membase))
		return -EFAULT;

	spin_lock(&cpu_lock);

	/* Set CPU boot address */
	writel(virt_to_phys(secondary_startup),
	       cpucfg_membase + CPUCFG_PRIVATE0_REG);

	/* Assert the CPU core in reset */
	writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));

	/* Assert the L1 cache in reset */
	reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);

	/* Clear CPU power-off gating */
	reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
	writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
	mdelay(1);

	/* Deassert the CPU core reset */
	writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));

	spin_unlock(&cpu_lock);

	return 0;
}

struct smp_operations sun8i_smp_ops __initdata = {
	.smp_prepare_cpus	= sun8i_smp_prepare_cpus,
	.smp_boot_secondary	= sun8i_smp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);