18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2018 Nuvoton Technology corporation. 38c2ecf20Sopenharmony_ci// Copyright 2018 Google, Inc. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "nuvoton,npcm7xx-smp: " fmt 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/smp.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 168c2ecf20Sopenharmony_ci#include <asm/smp.h> 178c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 188c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define NPCM7XX_SCRPAD_REG 0x13c 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciextern void npcm7xx_secondary_startup(void); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int npcm7xx_smp_boot_secondary(unsigned int cpu, 258c2ecf20Sopenharmony_ci struct task_struct *idle) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct device_node *gcr_np; 288c2ecf20Sopenharmony_ci void __iomem *gcr_base; 298c2ecf20Sopenharmony_ci int ret = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci gcr_np = of_find_compatible_node(NULL, NULL, "nuvoton,npcm750-gcr"); 328c2ecf20Sopenharmony_ci if (!gcr_np) { 338c2ecf20Sopenharmony_ci pr_err("no gcr device node\n"); 348c2ecf20Sopenharmony_ci ret = -ENODEV; 358c2ecf20Sopenharmony_ci goto out; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci gcr_base = of_iomap(gcr_np, 0); 388c2ecf20Sopenharmony_ci if (!gcr_base) { 398c2ecf20Sopenharmony_ci pr_err("could not iomap gcr"); 408c2ecf20Sopenharmony_ci ret = -ENOMEM; 418c2ecf20Sopenharmony_ci goto out; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* give boot ROM kernel start address. */ 458c2ecf20Sopenharmony_ci iowrite32(__pa_symbol(npcm7xx_secondary_startup), gcr_base + 468c2ecf20Sopenharmony_ci NPCM7XX_SCRPAD_REG); 478c2ecf20Sopenharmony_ci /* make sure the previous write is seen by all observers. */ 488c2ecf20Sopenharmony_ci dsb_sev(); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci iounmap(gcr_base); 518c2ecf20Sopenharmony_ciout: 528c2ecf20Sopenharmony_ci return ret; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct device_node *scu_np; 588c2ecf20Sopenharmony_ci void __iomem *scu_base; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci scu_np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 618c2ecf20Sopenharmony_ci if (!scu_np) { 628c2ecf20Sopenharmony_ci pr_err("no scu device node\n"); 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci scu_base = of_iomap(scu_np, 0); 668c2ecf20Sopenharmony_ci if (!scu_base) { 678c2ecf20Sopenharmony_ci pr_err("could not iomap scu"); 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci scu_enable(scu_base); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci iounmap(scu_base); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct smp_operations npcm7xx_smp_ops __initdata = { 778c2ecf20Sopenharmony_ci .smp_prepare_cpus = npcm7xx_smp_prepare_cpus, 788c2ecf20Sopenharmony_ci .smp_boot_secondary = npcm7xx_smp_boot_secondary, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(npcm7xx_smp, "nuvoton,npcm750-smp", &npcm7xx_smp_ops); 82