Message ID | 20170127032546.14657-3-chris.packham@alliedtelesis.co.nz (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Chris, On ven., janv. 27 2017, Chris Packham <chris.packham@alliedtelesis.co.nz> wrote: > 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: Chris Packham <chris.packham@alliedtelesis.co.nz> > Acked-by: Rob Herring <robh@kernel.org> > --- > > Notes: > Changes in v2: > - Document new enable-method value > - Correct some references from 98DX4521 to 98DX3236 > Changes in v3: > - Simplify mv98dx3236_resume_init by using of_io_request_and_map() > Changes in v4: > - integrate changes into platsmp.c instead of new init call > - avoid duplicated code. > - fix error return > - Collect ack from Rob > Changes in v5: > - Remove useless casts (thanks to Stephen Boyd) > > Documentation/devicetree/bindings/arm/cpus.txt | 1 + > .../bindings/arm/marvell/98dx3236-resume-ctrl.txt | 16 ++++ > arch/arm/mach-mvebu/platsmp.c | 86 ++++++++++++++++++++++ > 3 files changed, 103 insertions(+) > create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt > > diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt > index a1bcfeed5f24..3c2fd72d0bf9 100644 > --- a/Documentation/devicetree/bindings/arm/cpus.txt > +++ b/Documentation/devicetree/bindings/arm/cpus.txt > @@ -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" > diff --git a/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt > new file mode 100644 > index 000000000000..26eb9d3aa630 > --- /dev/null > +++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt > @@ -0,0 +1,16 @@ > +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>; > +}; > diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c > index 46c742d3bd41..a5b464497e1a 100644 > --- a/arch/arm/mach-mvebu/platsmp.c > +++ b/arch/arm/mach-mvebu/platsmp.c > @@ -184,3 +184,89 @@ const struct smp_operations armada_xp_smp_ops __initconst = { > > CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp", > &armada_xp_smp_ops); > + > +struct resume_controller { > + u32 resume_control; > + u32 resume_boot_addr; > +}; > + > +static const struct resume_controller mv98dx3336_resume_controller = { > + .resume_control = 0x08, > + .resume_boot_addr = 0x04, > +}; > + > +static const struct of_device_id of_mv98dx3236_resume_table[] = { > + { > + .compatible = "marvell,98dx3336-resume-ctrl", > + .data = &mv98dx3336_resume_controller, > + }, > + { /* end of list */ }, > +}; Do you expect to have other SoC which use the same logical but with register at a different place? Else you can just remove the resume_controller struct and use the address (using define) directly in the mv98dx3236_resume_set_cpu_boot_addr function. > + > +static int mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr) > +{ > + const struct of_device_id *match; > + struct device_node *np; > + void __iomem *base; > + const struct resume_controller *rc; > + > + WARN_ON(hw_cpu != 1); > + > + np = of_find_matching_node_and_match(NULL, of_mv98dx3236_resume_table, > + &match); > + if (!np) > + return -ENODEV; > + > + base = of_io_request_and_map(np, 0, of_node_full_name(np)); > + rc = match->data; > + of_node_put(np); > + if (IS_ERR(base)) > + return PTR_ERR(base); > + > + writel(0, base + rc->resume_control); > + writel(virt_to_phys(boot_addr), base + rc->resume_boot_addr); > + you should use iounmap() on base here, to free it. Gregory > + 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); > -- > 2.11.0.24.ge6920cf >
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index a1bcfeed5f24..3c2fd72d0bf9 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -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" diff --git a/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt new file mode 100644 index 000000000000..26eb9d3aa630 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt @@ -0,0 +1,16 @@ +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>; +}; diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 46c742d3bd41..a5b464497e1a 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -184,3 +184,89 @@ const struct smp_operations armada_xp_smp_ops __initconst = { CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp", &armada_xp_smp_ops); + +struct resume_controller { + u32 resume_control; + u32 resume_boot_addr; +}; + +static const struct resume_controller mv98dx3336_resume_controller = { + .resume_control = 0x08, + .resume_boot_addr = 0x04, +}; + +static const struct of_device_id of_mv98dx3236_resume_table[] = { + { + .compatible = "marvell,98dx3336-resume-ctrl", + .data = &mv98dx3336_resume_controller, + }, + { /* end of list */ }, +}; + +static int mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr) +{ + const struct of_device_id *match; + struct device_node *np; + void __iomem *base; + const struct resume_controller *rc; + + WARN_ON(hw_cpu != 1); + + np = of_find_matching_node_and_match(NULL, of_mv98dx3236_resume_table, + &match); + if (!np) + return -ENODEV; + + base = of_io_request_and_map(np, 0, of_node_full_name(np)); + rc = match->data; + of_node_put(np); + if (IS_ERR(base)) + return PTR_ERR(base); + + writel(0, base + rc->resume_control); + writel(virt_to_phys(boot_addr), base + rc->resume_boot_addr); + + 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);