1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f137e463SAndrew Isaacson /*
3f137e463SAndrew Isaacson * Copyright (C) 2001,2002,2004 Broadcom Corporation
4f137e463SAndrew Isaacson */
5f137e463SAndrew Isaacson
6f137e463SAndrew Isaacson #include <linux/init.h>
7f137e463SAndrew Isaacson #include <linux/delay.h>
8f137e463SAndrew Isaacson #include <linux/smp.h>
9f137e463SAndrew Isaacson #include <linux/kernel_stat.h>
10184748ccSPeter Zijlstra #include <linux/sched.h>
1168db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
12f137e463SAndrew Isaacson
13f137e463SAndrew Isaacson #include <asm/mmu_context.h>
14f137e463SAndrew Isaacson #include <asm/io.h>
1587353d8aSRalf Baechle #include <asm/fw/cfe/cfe_api.h>
16f137e463SAndrew Isaacson #include <asm/sibyte/sb1250.h>
17f137e463SAndrew Isaacson #include <asm/sibyte/bcm1480_regs.h>
18f137e463SAndrew Isaacson #include <asm/sibyte/bcm1480_int.h>
19f137e463SAndrew Isaacson
20f137e463SAndrew Isaacson /*
21f137e463SAndrew Isaacson * These are routines for dealing with the bcm1480 smp capabilities
22f137e463SAndrew Isaacson * independent of board/firmware
23f137e463SAndrew Isaacson */
24f137e463SAndrew Isaacson
258fb303c7SRalf Baechle static void *mailbox_0_set_regs[] = {
26f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
27f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
28f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
29f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
30f137e463SAndrew Isaacson };
31f137e463SAndrew Isaacson
328fb303c7SRalf Baechle static void *mailbox_0_clear_regs[] = {
33f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
34f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
35f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
36f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
37f137e463SAndrew Isaacson };
38f137e463SAndrew Isaacson
398fb303c7SRalf Baechle static void *mailbox_0_regs[] = {
40f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
41f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
42f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
43f137e463SAndrew Isaacson IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
44f137e463SAndrew Isaacson };
45f137e463SAndrew Isaacson
46f137e463SAndrew Isaacson /*
47f137e463SAndrew Isaacson * SMP init and finish on secondary CPUs
48f137e463SAndrew Isaacson */
bcm1480_smp_init(void)49078a55fcSPaul Gortmaker void bcm1480_smp_init(void)
50f137e463SAndrew Isaacson {
51f137e463SAndrew Isaacson unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
52f137e463SAndrew Isaacson STATUSF_IP1 | STATUSF_IP0;
53f137e463SAndrew Isaacson
54f137e463SAndrew Isaacson /* Set interrupt mask, but don't enable */
55f137e463SAndrew Isaacson change_c0_status(ST0_IM, imask);
56f137e463SAndrew Isaacson }
57f137e463SAndrew Isaacson
58f137e463SAndrew Isaacson /*
59f137e463SAndrew Isaacson * These are routines for dealing with the sb1250 smp capabilities
60f137e463SAndrew Isaacson * independent of board/firmware
61f137e463SAndrew Isaacson */
62f137e463SAndrew Isaacson
63f137e463SAndrew Isaacson /*
64f137e463SAndrew Isaacson * Simple enough; everything is set up, so just poke the appropriate mailbox
65f137e463SAndrew Isaacson * register, and we should be set
66f137e463SAndrew Isaacson */
bcm1480_send_ipi_single(int cpu,unsigned int action)6787353d8aSRalf Baechle static void bcm1480_send_ipi_single(int cpu, unsigned int action)
68f137e463SAndrew Isaacson {
69f137e463SAndrew Isaacson __raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
70f137e463SAndrew Isaacson }
71f137e463SAndrew Isaacson
bcm1480_send_ipi_mask(const struct cpumask * mask,unsigned int action)7248a048feSRusty Russell static void bcm1480_send_ipi_mask(const struct cpumask *mask,
7348a048feSRusty Russell unsigned int action)
7487353d8aSRalf Baechle {
7587353d8aSRalf Baechle unsigned int i;
7687353d8aSRalf Baechle
7748a048feSRusty Russell for_each_cpu(i, mask)
7887353d8aSRalf Baechle bcm1480_send_ipi_single(i, action);
7987353d8aSRalf Baechle }
8087353d8aSRalf Baechle
8187353d8aSRalf Baechle /*
8287353d8aSRalf Baechle * Code to run on secondary just after probing the CPU
8387353d8aSRalf Baechle */
bcm1480_init_secondary(void)84078a55fcSPaul Gortmaker static void bcm1480_init_secondary(void)
8587353d8aSRalf Baechle {
8687353d8aSRalf Baechle extern void bcm1480_smp_init(void);
8787353d8aSRalf Baechle
8887353d8aSRalf Baechle bcm1480_smp_init();
8987353d8aSRalf Baechle }
9087353d8aSRalf Baechle
9187353d8aSRalf Baechle /*
9287353d8aSRalf Baechle * Do any tidying up before marking online and running the idle
9387353d8aSRalf Baechle * loop
9487353d8aSRalf Baechle */
bcm1480_smp_finish(void)95078a55fcSPaul Gortmaker static void bcm1480_smp_finish(void)
9687353d8aSRalf Baechle {
9787353d8aSRalf Baechle extern void sb1480_clockevent_init(void);
9887353d8aSRalf Baechle
9987353d8aSRalf Baechle sb1480_clockevent_init();
10087353d8aSRalf Baechle local_irq_enable();
10187353d8aSRalf Baechle }
10287353d8aSRalf Baechle
10387353d8aSRalf Baechle /*
10487353d8aSRalf Baechle * Setup the PC, SP, and GP of a secondary processor and start it
10587353d8aSRalf Baechle * running!
10687353d8aSRalf Baechle */
bcm1480_boot_secondary(int cpu,struct task_struct * idle)107d595d423SPaul Burton static int bcm1480_boot_secondary(int cpu, struct task_struct *idle)
10887353d8aSRalf Baechle {
10987353d8aSRalf Baechle int retval;
11087353d8aSRalf Baechle
11187353d8aSRalf Baechle retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
11287353d8aSRalf Baechle __KSTK_TOS(idle),
11387353d8aSRalf Baechle (unsigned long)task_thread_info(idle), 0);
11487353d8aSRalf Baechle if (retval != 0)
11587353d8aSRalf Baechle printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
116d595d423SPaul Burton return retval;
11787353d8aSRalf Baechle }
11887353d8aSRalf Baechle
11987353d8aSRalf Baechle /*
12087353d8aSRalf Baechle * Use CFE to find out how many CPUs are available, setting up
1215f054e31SRusty Russell * cpu_possible_mask and the logical/physical mappings.
12287353d8aSRalf Baechle * XXXKW will the boot CPU ever not be physical 0?
12387353d8aSRalf Baechle *
12487353d8aSRalf Baechle * Common setup before any secondaries are started
12587353d8aSRalf Baechle */
bcm1480_smp_setup(void)12687353d8aSRalf Baechle static void __init bcm1480_smp_setup(void)
12787353d8aSRalf Baechle {
12887353d8aSRalf Baechle int i, num;
12987353d8aSRalf Baechle
1300b5f9c00SRusty Russell init_cpu_possible(cpumask_of(0));
13187353d8aSRalf Baechle __cpu_number_map[0] = 0;
13287353d8aSRalf Baechle __cpu_logical_map[0] = 0;
13387353d8aSRalf Baechle
13487353d8aSRalf Baechle for (i = 1, num = 0; i < NR_CPUS; i++) {
13587353d8aSRalf Baechle if (cfe_cpu_stop(i) == 0) {
1360b5f9c00SRusty Russell set_cpu_possible(i, true);
13787353d8aSRalf Baechle __cpu_number_map[i] = ++num;
13887353d8aSRalf Baechle __cpu_logical_map[num] = i;
13987353d8aSRalf Baechle }
14087353d8aSRalf Baechle }
14187353d8aSRalf Baechle printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
14287353d8aSRalf Baechle }
14387353d8aSRalf Baechle
bcm1480_prepare_cpus(unsigned int max_cpus)14487353d8aSRalf Baechle static void __init bcm1480_prepare_cpus(unsigned int max_cpus)
14587353d8aSRalf Baechle {
14687353d8aSRalf Baechle }
14787353d8aSRalf Baechle
148ff2c8252SMatt Redfearn const struct plat_smp_ops bcm1480_smp_ops = {
14987353d8aSRalf Baechle .send_ipi_single = bcm1480_send_ipi_single,
15087353d8aSRalf Baechle .send_ipi_mask = bcm1480_send_ipi_mask,
15187353d8aSRalf Baechle .init_secondary = bcm1480_init_secondary,
15287353d8aSRalf Baechle .smp_finish = bcm1480_smp_finish,
15387353d8aSRalf Baechle .boot_secondary = bcm1480_boot_secondary,
15487353d8aSRalf Baechle .smp_setup = bcm1480_smp_setup,
15587353d8aSRalf Baechle .prepare_cpus = bcm1480_prepare_cpus,
15687353d8aSRalf Baechle };
15787353d8aSRalf Baechle
bcm1480_mailbox_interrupt(void)158937a8015SRalf Baechle void bcm1480_mailbox_interrupt(void)
159f137e463SAndrew Isaacson {
160f137e463SAndrew Isaacson int cpu = smp_processor_id();
161d2287f5eSMike Travis int irq = K_BCM1480_INT_MBOX_0_0;
162f137e463SAndrew Isaacson unsigned int action;
163f137e463SAndrew Isaacson
164310ff2c8SThomas Gleixner kstat_incr_irq_this_cpu(irq);
165f137e463SAndrew Isaacson /* Load the mailbox register to figure out what we're supposed to do */
166f137e463SAndrew Isaacson action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
167f137e463SAndrew Isaacson
168f137e463SAndrew Isaacson /* Clear the mailbox to clear the interrupt */
169f137e463SAndrew Isaacson __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
170f137e463SAndrew Isaacson
171184748ccSPeter Zijlstra if (action & SMP_RESCHEDULE_YOURSELF)
172184748ccSPeter Zijlstra scheduler_ipi();
173f137e463SAndrew Isaacson
1744ace6139SAlex Smith if (action & SMP_CALL_FUNCTION) {
1754ace6139SAlex Smith irq_enter();
1764ace6139SAlex Smith generic_smp_call_function_interrupt();
1774ace6139SAlex Smith irq_exit();
1784ace6139SAlex Smith }
179f137e463SAndrew Isaacson }
180