1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 /* 4 * SMP support functions for Microwatt 5 * Copyright 2025 Paul Mackerras <paulus@ozlabs.org> 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/smp.h> 10 #include <linux/io.h> 11 #include <asm/early_ioremap.h> 12 #include <asm/ppc-opcode.h> 13 #include <asm/reg.h> 14 #include <asm/smp.h> 15 #include <asm/xics.h> 16 17 #include "microwatt.h" 18 19 static void __init microwatt_smp_probe(void) 20 { 21 xics_smp_probe(); 22 } 23 24 static void microwatt_smp_setup_cpu(int cpu) 25 { 26 if (cpu != 0) 27 xics_setup_cpu(); 28 } 29 30 static struct smp_ops_t microwatt_smp_ops = { 31 .probe = microwatt_smp_probe, 32 .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */ 33 .kick_cpu = smp_generic_kick_cpu, 34 .setup_cpu = microwatt_smp_setup_cpu, 35 }; 36 37 /* XXX get from device tree */ 38 #define SYSCON_BASE 0xc0000000 39 #define SYSCON_LENGTH 0x100 40 41 #define SYSCON_CPU_CTRL 0x58 42 43 void __init microwatt_init_smp(void) 44 { 45 volatile unsigned char __iomem *syscon; 46 int ncpus; 47 int timeout; 48 49 syscon = early_ioremap(SYSCON_BASE, SYSCON_LENGTH); 50 if (syscon == NULL) { 51 pr_err("Failed to map SYSCON\n"); 52 return; 53 } 54 ncpus = (readl(syscon + SYSCON_CPU_CTRL) >> 8) & 0xff; 55 if (ncpus < 2) 56 goto out; 57 58 smp_ops = µwatt_smp_ops; 59 60 /* 61 * Write two instructions at location 0: 62 * mfspr r3, PIR 63 * b __secondary_hold 64 */ 65 *(unsigned int *)KERNELBASE = PPC_RAW_MFSPR(3, SPRN_PIR); 66 *(unsigned int *)(KERNELBASE+4) = PPC_RAW_BRANCH(&__secondary_hold - (char *)(KERNELBASE+4)); 67 68 /* enable the other CPUs, they start at location 0 */ 69 writel((1ul << ncpus) - 1, syscon + SYSCON_CPU_CTRL); 70 71 timeout = 10000; 72 while (!__secondary_hold_acknowledge) { 73 if (--timeout == 0) 74 break; 75 barrier(); 76 } 77 78 out: 79 early_iounmap((void *)syscon, SYSCON_LENGTH); 80 } 81