162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2018 Nuvoton Technology corporation. 362306a36Sopenharmony_ci// Copyright 2018 Google, Inc. 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#define pr_fmt(fmt) "nuvoton,npcm7xx-smp: " fmt 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/smp.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/of_address.h> 1262306a36Sopenharmony_ci#include <asm/cacheflush.h> 1362306a36Sopenharmony_ci#include <asm/smp.h> 1462306a36Sopenharmony_ci#include <asm/smp_plat.h> 1562306a36Sopenharmony_ci#include <asm/smp_scu.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define NPCM7XX_SCRPAD_REG 0x13c 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciextern void npcm7xx_secondary_startup(void); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int npcm7xx_smp_boot_secondary(unsigned int cpu, 2262306a36Sopenharmony_ci struct task_struct *idle) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct device_node *gcr_np; 2562306a36Sopenharmony_ci void __iomem *gcr_base; 2662306a36Sopenharmony_ci int ret = 0; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci gcr_np = of_find_compatible_node(NULL, NULL, "nuvoton,npcm750-gcr"); 2962306a36Sopenharmony_ci if (!gcr_np) { 3062306a36Sopenharmony_ci pr_err("no gcr device node\n"); 3162306a36Sopenharmony_ci ret = -ENODEV; 3262306a36Sopenharmony_ci goto out; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci gcr_base = of_iomap(gcr_np, 0); 3562306a36Sopenharmony_ci if (!gcr_base) { 3662306a36Sopenharmony_ci pr_err("could not iomap gcr"); 3762306a36Sopenharmony_ci ret = -ENOMEM; 3862306a36Sopenharmony_ci goto out; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* give boot ROM kernel start address. */ 4262306a36Sopenharmony_ci iowrite32(__pa_symbol(npcm7xx_secondary_startup), gcr_base + 4362306a36Sopenharmony_ci NPCM7XX_SCRPAD_REG); 4462306a36Sopenharmony_ci /* make sure the previous write is seen by all observers. */ 4562306a36Sopenharmony_ci dsb_sev(); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci iounmap(gcr_base); 4862306a36Sopenharmony_ciout: 4962306a36Sopenharmony_ci return ret; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct device_node *scu_np; 5562306a36Sopenharmony_ci void __iomem *scu_base; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci scu_np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 5862306a36Sopenharmony_ci if (!scu_np) { 5962306a36Sopenharmony_ci pr_err("no scu device node\n"); 6062306a36Sopenharmony_ci return; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci scu_base = of_iomap(scu_np, 0); 6362306a36Sopenharmony_ci if (!scu_base) { 6462306a36Sopenharmony_ci pr_err("could not iomap scu"); 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci scu_enable(scu_base); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci iounmap(scu_base); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic struct smp_operations npcm7xx_smp_ops __initdata = { 7462306a36Sopenharmony_ci .smp_prepare_cpus = npcm7xx_smp_prepare_cpus, 7562306a36Sopenharmony_ci .smp_boot_secondary = npcm7xx_smp_boot_secondary, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciCPU_METHOD_OF_DECLARE(npcm7xx_smp, "nuvoton,npcm750-smp", &npcm7xx_smp_ops); 79