18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Author: Xianghua Xiao <x.xiao@freescale.com> 48c2ecf20Sopenharmony_ci * Zhang Wei <wei.zhang@freescale.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2006 Freescale Semiconductor Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/stddef.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/code-patching.h> 168c2ecf20Sopenharmony_ci#include <asm/page.h> 178c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h> 188c2ecf20Sopenharmony_ci#include <asm/mpic.h> 198c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 208c2ecf20Sopenharmony_ci#include <asm/inst.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "mpc86xx.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciextern void __secondary_start_mpc86xx(void); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MCM_PORT_CONFIG_OFFSET 0x10 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Offset from CCSRBAR */ 318c2ecf20Sopenharmony_ci#define MPC86xx_MCM_OFFSET (0x1000) 328c2ecf20Sopenharmony_ci#define MPC86xx_MCM_SIZE (0x1000) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void __init 358c2ecf20Sopenharmony_cismp_86xx_release_core(int nr) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci __be32 __iomem *mcm_vaddr; 388c2ecf20Sopenharmony_ci unsigned long pcr; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (nr < 0 || nr >= NR_CPUS) 418c2ecf20Sopenharmony_ci return; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * Startup Core #nr. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET, 478c2ecf20Sopenharmony_ci MPC86xx_MCM_SIZE); 488c2ecf20Sopenharmony_ci pcr = in_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2)); 498c2ecf20Sopenharmony_ci pcr |= 1 << (nr + 24); 508c2ecf20Sopenharmony_ci out_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2), pcr); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci iounmap(mcm_vaddr); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int __init 578c2ecf20Sopenharmony_cismp_86xx_kick_cpu(int nr) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci unsigned int save_vector; 608c2ecf20Sopenharmony_ci unsigned long target, flags; 618c2ecf20Sopenharmony_ci int n = 0; 628c2ecf20Sopenharmony_ci unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (nr < 0 || nr >= NR_CPUS) 658c2ecf20Sopenharmony_ci return -ENOENT; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci local_irq_save(flags); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* Save reset vector */ 728c2ecf20Sopenharmony_ci save_vector = *vector; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Setup fake reset vector to call __secondary_start_mpc86xx. */ 758c2ecf20Sopenharmony_ci target = (unsigned long) __secondary_start_mpc86xx; 768c2ecf20Sopenharmony_ci patch_branch((struct ppc_inst *)vector, target, BRANCH_SET_LINK); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Kick that CPU */ 798c2ecf20Sopenharmony_ci smp_86xx_release_core(nr); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Wait a bit for the CPU to take the exception. */ 828c2ecf20Sopenharmony_ci while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000)) 838c2ecf20Sopenharmony_ci mdelay(1); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Restore the exception vector */ 868c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)vector, ppc_inst(save_vector)); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci local_irq_restore(flags); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci pr_debug("wait CPU #%d for %d msecs.\n", nr, n); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void __init 978c2ecf20Sopenharmony_cismp_86xx_setup_cpu(int cpu_nr) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci mpic_setup_this_cpu(); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct smp_ops_t smp_86xx_ops = { 1048c2ecf20Sopenharmony_ci .cause_nmi_ipi = NULL, 1058c2ecf20Sopenharmony_ci .message_pass = smp_mpic_message_pass, 1068c2ecf20Sopenharmony_ci .probe = smp_mpic_probe, 1078c2ecf20Sopenharmony_ci .kick_cpu = smp_86xx_kick_cpu, 1088c2ecf20Sopenharmony_ci .setup_cpu = smp_86xx_setup_cpu, 1098c2ecf20Sopenharmony_ci .take_timebase = smp_generic_take_timebase, 1108c2ecf20Sopenharmony_ci .give_timebase = smp_generic_give_timebase, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_civoid __init 1158c2ecf20Sopenharmony_cimpc86xx_smp_init(void) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci smp_ops = &smp_86xx_ops; 1188c2ecf20Sopenharmony_ci} 119