1 // SPDX-License-Identifier: GPL-2.0
3 * SMP support for J2 processor
5 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
9 #include <linux/interrupt.h>
11 #include <linux/of_address.h>
12 #include <linux/of_irq.h>
13 #include <asm/cmpxchg.h>
15 DEFINE_PER_CPU(unsigned, j2_ipi_messages
);
17 extern u32
*sh2_cpuid_addr
;
18 static u32
*j2_ipi_trigger
;
19 static int j2_ipi_irq
;
21 static irqreturn_t
j2_ipi_interrupt_handler(int irq
, void *arg
)
23 unsigned cpu
= hard_smp_processor_id();
24 volatile unsigned *pmsg
= &per_cpu(j2_ipi_messages
, cpu
);
28 while (cmpxchg(pmsg
, messages
, 0) != messages
);
30 if (!messages
) return IRQ_NONE
;
32 for (i
=0; i
<SMP_MSG_NR
; i
++)
33 if (messages
& (1U<<i
))
39 static void j2_smp_setup(void)
43 static void j2_prepare_cpus(unsigned int max_cpus
)
45 struct device_node
*np
;
48 np
= of_find_compatible_node(NULL
, NULL
, "jcore,ipi-controller");
52 j2_ipi_irq
= irq_of_parse_and_map(np
, 0);
53 j2_ipi_trigger
= of_iomap(np
, 0);
54 if (!j2_ipi_irq
|| !j2_ipi_trigger
)
57 np
= of_find_compatible_node(NULL
, NULL
, "jcore,cpuid-mmio");
61 sh2_cpuid_addr
= of_iomap(np
, 0);
65 if (request_irq(j2_ipi_irq
, j2_ipi_interrupt_handler
, IRQF_PERCPU
,
66 "ipi", (void *)j2_ipi_interrupt_handler
) != 0)
71 /* Disable any cpus past max_cpus, or all secondaries if we didn't
72 * get the necessary resources to support SMP. */
73 for (i
=max
; i
<NR_CPUS
; i
++) {
74 set_cpu_possible(i
, false);
75 set_cpu_present(i
, false);
79 static void j2_start_cpu(unsigned int cpu
, unsigned long entry_point
)
81 struct device_node
*np
;
83 void __iomem
*release
, *initpc
;
87 np
= of_get_cpu_node(cpu
, NULL
);
90 if (of_property_read_u32_array(np
, "cpu-release-addr", regs
, 2)) return;
91 release
= ioremap_nocache(regs
[0], sizeof(u32
));
92 initpc
= ioremap_nocache(regs
[1], sizeof(u32
));
94 __raw_writel(entry_point
, initpc
);
95 __raw_writel(1, release
);
100 pr_info("J2 SMP: requested start of cpu %u\n", cpu
);
103 static unsigned int j2_smp_processor_id(void)
105 return __raw_readl(sh2_cpuid_addr
);
108 static void j2_send_ipi(unsigned int cpu
, unsigned int message
)
110 volatile unsigned *pmsg
;
114 /* There is only one IPI interrupt shared by all messages, so
115 * we keep a separate interrupt flag per message type in sw. */
116 pmsg
= &per_cpu(j2_ipi_messages
, cpu
);
118 while (cmpxchg(pmsg
, old
, old
|(1U<<message
)) != old
);
120 /* Generate the actual interrupt by writing to CCRn bit 28. */
121 val
= __raw_readl(j2_ipi_trigger
+ cpu
);
122 __raw_writel(val
| (1U<<28), j2_ipi_trigger
+ cpu
);
125 static struct plat_smp_ops j2_smp_ops
= {
126 .smp_setup
= j2_smp_setup
,
127 .prepare_cpus
= j2_prepare_cpus
,
128 .start_cpu
= j2_start_cpu
,
129 .smp_processor_id
= j2_smp_processor_id
,
130 .send_ipi
= j2_send_ipi
,
131 .cpu_die
= native_cpu_die
,
132 .cpu_disable
= native_cpu_disable
,
133 .play_dead
= native_play_dead
,
136 CPU_METHOD_OF_DECLARE(j2_cpu_method
, "jcore,spin-table", &j2_smp_ops
);