17bffa14cSBrendan Higgins // SPDX-License-Identifier: GPL-2.0
27bffa14cSBrendan Higgins // Copyright (c) 2018 Nuvoton Technology corporation.
37bffa14cSBrendan Higgins // Copyright 2018 Google, Inc.
47bffa14cSBrendan Higgins
57bffa14cSBrendan Higgins #define pr_fmt(fmt) "nuvoton,npcm7xx-smp: " fmt
67bffa14cSBrendan Higgins
77bffa14cSBrendan Higgins #include <linux/delay.h>
87bffa14cSBrendan Higgins #include <linux/smp.h>
97bffa14cSBrendan Higgins #include <linux/io.h>
107bffa14cSBrendan Higgins #include <linux/of.h>
117bffa14cSBrendan Higgins #include <linux/of_address.h>
127bffa14cSBrendan Higgins #include <asm/cacheflush.h>
137bffa14cSBrendan Higgins #include <asm/smp.h>
147bffa14cSBrendan Higgins #include <asm/smp_plat.h>
157bffa14cSBrendan Higgins #include <asm/smp_scu.h>
167bffa14cSBrendan Higgins
177bffa14cSBrendan Higgins #define NPCM7XX_SCRPAD_REG 0x13c
187bffa14cSBrendan Higgins
197bffa14cSBrendan Higgins extern void npcm7xx_secondary_startup(void);
207bffa14cSBrendan Higgins
npcm7xx_smp_boot_secondary(unsigned int cpu,struct task_struct * idle)217bffa14cSBrendan Higgins static int npcm7xx_smp_boot_secondary(unsigned int cpu,
227bffa14cSBrendan Higgins struct task_struct *idle)
237bffa14cSBrendan Higgins {
247bffa14cSBrendan Higgins struct device_node *gcr_np;
257bffa14cSBrendan Higgins void __iomem *gcr_base;
267bffa14cSBrendan Higgins int ret = 0;
277bffa14cSBrendan Higgins
287bffa14cSBrendan Higgins gcr_np = of_find_compatible_node(NULL, NULL, "nuvoton,npcm750-gcr");
297bffa14cSBrendan Higgins if (!gcr_np) {
307bffa14cSBrendan Higgins pr_err("no gcr device node\n");
317bffa14cSBrendan Higgins ret = -ENODEV;
327bffa14cSBrendan Higgins goto out;
337bffa14cSBrendan Higgins }
347bffa14cSBrendan Higgins gcr_base = of_iomap(gcr_np, 0);
357bffa14cSBrendan Higgins if (!gcr_base) {
367bffa14cSBrendan Higgins pr_err("could not iomap gcr");
377bffa14cSBrendan Higgins ret = -ENOMEM;
387bffa14cSBrendan Higgins goto out;
397bffa14cSBrendan Higgins }
407bffa14cSBrendan Higgins
417bffa14cSBrendan Higgins /* give boot ROM kernel start address. */
427bffa14cSBrendan Higgins iowrite32(__pa_symbol(npcm7xx_secondary_startup), gcr_base +
437bffa14cSBrendan Higgins NPCM7XX_SCRPAD_REG);
447bffa14cSBrendan Higgins /* make sure the previous write is seen by all observers. */
457bffa14cSBrendan Higgins dsb_sev();
467bffa14cSBrendan Higgins
477bffa14cSBrendan Higgins iounmap(gcr_base);
487bffa14cSBrendan Higgins out:
497bffa14cSBrendan Higgins return ret;
507bffa14cSBrendan Higgins }
517bffa14cSBrendan Higgins
npcm7xx_smp_prepare_cpus(unsigned int max_cpus)527bffa14cSBrendan Higgins static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
537bffa14cSBrendan Higgins {
547bffa14cSBrendan Higgins struct device_node *scu_np;
557bffa14cSBrendan Higgins void __iomem *scu_base;
567bffa14cSBrendan Higgins
577bffa14cSBrendan Higgins scu_np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
587bffa14cSBrendan Higgins if (!scu_np) {
597bffa14cSBrendan Higgins pr_err("no scu device node\n");
607bffa14cSBrendan Higgins return;
617bffa14cSBrendan Higgins }
627bffa14cSBrendan Higgins scu_base = of_iomap(scu_np, 0);
637bffa14cSBrendan Higgins if (!scu_base) {
647bffa14cSBrendan Higgins pr_err("could not iomap scu");
657bffa14cSBrendan Higgins return;
667bffa14cSBrendan Higgins }
677bffa14cSBrendan Higgins
687bffa14cSBrendan Higgins scu_enable(scu_base);
697bffa14cSBrendan Higgins
707bffa14cSBrendan Higgins iounmap(scu_base);
717bffa14cSBrendan Higgins }
727bffa14cSBrendan Higgins
737bffa14cSBrendan Higgins static struct smp_operations npcm7xx_smp_ops __initdata = {
747bffa14cSBrendan Higgins .smp_prepare_cpus = npcm7xx_smp_prepare_cpus,
757bffa14cSBrendan Higgins .smp_boot_secondary = npcm7xx_smp_boot_secondary,
767bffa14cSBrendan Higgins };
777bffa14cSBrendan Higgins
787bffa14cSBrendan Higgins CPU_METHOD_OF_DECLARE(npcm7xx_smp, "nuvoton,npcm750-smp", &npcm7xx_smp_ops);
79