162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Author: Xianghua Xiao <x.xiao@freescale.com> 462306a36Sopenharmony_ci * Zhang Wei <wei.zhang@freescale.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2006 Freescale Semiconductor Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/stddef.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/pgtable.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/code-patching.h> 1662306a36Sopenharmony_ci#include <asm/page.h> 1762306a36Sopenharmony_ci#include <asm/pci-bridge.h> 1862306a36Sopenharmony_ci#include <asm/mpic.h> 1962306a36Sopenharmony_ci#include <asm/cacheflush.h> 2062306a36Sopenharmony_ci#include <asm/inst.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "mpc86xx.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciextern void __secondary_start_mpc86xx(void); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MCM_PORT_CONFIG_OFFSET 0x10 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Offset from CCSRBAR */ 3162306a36Sopenharmony_ci#define MPC86xx_MCM_OFFSET (0x1000) 3262306a36Sopenharmony_ci#define MPC86xx_MCM_SIZE (0x1000) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void __init 3562306a36Sopenharmony_cismp_86xx_release_core(int nr) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci __be32 __iomem *mcm_vaddr; 3862306a36Sopenharmony_ci unsigned long pcr; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (nr < 0 || nr >= NR_CPUS) 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * Startup Core #nr. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET, 4762306a36Sopenharmony_ci MPC86xx_MCM_SIZE); 4862306a36Sopenharmony_ci pcr = in_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2)); 4962306a36Sopenharmony_ci pcr |= 1 << (nr + 24); 5062306a36Sopenharmony_ci out_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2), pcr); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci iounmap(mcm_vaddr); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int __init 5762306a36Sopenharmony_cismp_86xx_kick_cpu(int nr) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci unsigned int save_vector; 6062306a36Sopenharmony_ci unsigned long target, flags; 6162306a36Sopenharmony_ci int n = 0; 6262306a36Sopenharmony_ci unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (nr < 0 || nr >= NR_CPUS) 6562306a36Sopenharmony_ci return -ENOENT; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci local_irq_save(flags); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Save reset vector */ 7262306a36Sopenharmony_ci save_vector = *vector; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Setup fake reset vector to call __secondary_start_mpc86xx. */ 7562306a36Sopenharmony_ci target = (unsigned long) __secondary_start_mpc86xx; 7662306a36Sopenharmony_ci patch_branch(vector, target, BRANCH_SET_LINK); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Kick that CPU */ 7962306a36Sopenharmony_ci smp_86xx_release_core(nr); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Wait a bit for the CPU to take the exception. */ 8262306a36Sopenharmony_ci while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000)) 8362306a36Sopenharmony_ci mdelay(1); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Restore the exception vector */ 8662306a36Sopenharmony_ci patch_instruction(vector, ppc_inst(save_vector)); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci local_irq_restore(flags); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci pr_debug("wait CPU #%d for %d msecs.\n", nr, n); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void __init 9762306a36Sopenharmony_cismp_86xx_setup_cpu(int cpu_nr) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci mpic_setup_this_cpu(); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct smp_ops_t smp_86xx_ops = { 10462306a36Sopenharmony_ci .cause_nmi_ipi = NULL, 10562306a36Sopenharmony_ci .message_pass = smp_mpic_message_pass, 10662306a36Sopenharmony_ci .probe = smp_mpic_probe, 10762306a36Sopenharmony_ci .kick_cpu = smp_86xx_kick_cpu, 10862306a36Sopenharmony_ci .setup_cpu = smp_86xx_setup_cpu, 10962306a36Sopenharmony_ci .take_timebase = smp_generic_take_timebase, 11062306a36Sopenharmony_ci .give_timebase = smp_generic_give_timebase, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_civoid __init 11562306a36Sopenharmony_cimpc86xx_smp_init(void) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci smp_ops = &smp_86xx_ops; 11862306a36Sopenharmony_ci} 119