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

Commit db889778 authored by Chris Packham's avatar Chris Packham Committed by Gregory CLEMENT
Browse files

arm: mvebu: support for SMP on 98DX3336 SoC



Compared to the armada-xp the 98DX3336 uses different registers to set
the boot address for the secondary CPU so a new enable-method is needed.
This will only work if the machine definition doesn't define an overall
smp_ops because there is not currently a way of overriding this from the
device tree if it is set in the machine definition.

Signed-off-by: default avatarChris Packham <chris.packham@alliedtelesis.co.nz>
Acked-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
parent f2591b99
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ nodes to be present and contain the properties described below.
			    "marvell,armada-380-smp"
			    "marvell,armada-390-smp"
			    "marvell,armada-xp-smp"
			    "marvell,98dx3236-smp"
			    "mediatek,mt6589-smp"
			    "mediatek,mt81xx-tz-smp"
			    "qcom,gcc-msm8660"
+16 −0
Original line number Diff line number Diff line
Resume Control
--------------
Available on Marvell SOCs: 98DX3336 and 98DX4251

Required properties:

- compatible: must be "marvell,98dx3336-resume-ctrl"

- reg: Should contain resume control registers location and length

Example:

resume@20980 {
	compatible = "marvell,98dx3336-resume-ctrl";
	reg = <0x20980 0x10>;
};
+75 −0
Original line number Diff line number Diff line
@@ -184,3 +184,78 @@ const struct smp_operations armada_xp_smp_ops __initconst = {

CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp",
		      &armada_xp_smp_ops);

#define MV98DX3236_CPU_RESUME_CTRL_REG 0x08
#define MV98DX3236_CPU_RESUME_ADDR_REG 0x04

static const struct of_device_id of_mv98dx3236_resume_table[] = {
	{
		.compatible = "marvell,98dx3336-resume-ctrl",
	},
	{ /* end of list */ },
};

static int mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
{
	struct device_node *np;
	void __iomem *base;
	WARN_ON(hw_cpu != 1);

	np = of_find_matching_node(NULL, of_mv98dx3236_resume_table);
	if (!np)
		return -ENODEV;

	base = of_io_request_and_map(np, 0, of_node_full_name(np));
	of_node_put(np);
	if (IS_ERR(base))
		return PTR_ERR(base);

	writel(0, base + MV98DX3236_CPU_RESUME_CTRL_REG);
	writel(virt_to_phys(boot_addr), base + MV98DX3236_CPU_RESUME_ADDR_REG);

	iounmap(base);

	return 0;
}

static int mv98dx3236_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	int ret, hw_cpu;

	hw_cpu = cpu_logical_map(cpu);
	set_secondary_cpu_clock(hw_cpu);
	mv98dx3236_resume_set_cpu_boot_addr(hw_cpu,
					    armada_xp_secondary_startup);

	/*
	 * This is needed to wake up CPUs in the offline state after
	 * using CPU hotplug.
	 */
	arch_send_wakeup_ipi_mask(cpumask_of(cpu));

	/*
	 * This is needed to take secondary CPUs out of reset on the
	 * initial boot.
	 */
	ret = mvebu_cpu_reset_deassert(hw_cpu);
	if (ret) {
		pr_warn("unable to boot CPU: %d\n", ret);
		return ret;
	}

	return 0;
}

static const struct smp_operations mv98dx3236_smp_ops __initconst = {
	.smp_init_cpus		= armada_xp_smp_init_cpus,
	.smp_prepare_cpus	= armada_xp_smp_prepare_cpus,
	.smp_boot_secondary	= mv98dx3236_boot_secondary,
	.smp_secondary_init     = armada_xp_secondary_init,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= armada_xp_cpu_die,
	.cpu_kill               = armada_xp_cpu_kill,
#endif
};

CPU_METHOD_OF_DECLARE(mv98dx3236_smp, "marvell,98dx3236-smp",
		      &mv98dx3236_smp_ops);