2 * SMP support for J2 processor
4 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
11 #include <linux/smp.h>
12 #include <linux/interrupt.h>
14 #include <linux/of_address.h>
15 #include <linux/of_irq.h>
16 #include <asm/cmpxchg.h>
18 DEFINE_PER_CPU(unsigned, j2_ipi_messages
);
20 extern u32
*sh2_cpuid_addr
;
21 static u32
*j2_ipi_trigger
;
22 static int j2_ipi_irq
;
24 static irqreturn_t
j2_ipi_interrupt_handler(int irq
, void *arg
)
26 unsigned cpu
= hard_smp_processor_id();
27 volatile unsigned *pmsg
= &per_cpu(j2_ipi_messages
, cpu
);
31 while (cmpxchg(pmsg
, messages
, 0) != messages
);
33 if (!messages
) return IRQ_NONE
;
35 for (i
=0; i
<SMP_MSG_NR
; i
++)
36 if (messages
& (1U<<i
))
42 static void j2_smp_setup(void)
46 static void j2_prepare_cpus(unsigned int max_cpus
)
48 struct device_node
*np
;
51 np
= of_find_compatible_node(NULL
, NULL
, "jcore,ipi-controller");
55 j2_ipi_irq
= irq_of_parse_and_map(np
, 0);
56 j2_ipi_trigger
= of_iomap(np
, 0);
57 if (!j2_ipi_irq
|| !j2_ipi_trigger
)
60 np
= of_find_compatible_node(NULL
, NULL
, "jcore,cpuid-mmio");
64 sh2_cpuid_addr
= of_iomap(np
, 0);
68 if (request_irq(j2_ipi_irq
, j2_ipi_interrupt_handler
, IRQF_PERCPU
,
69 "ipi", (void *)j2_ipi_interrupt_handler
) != 0)
74 /* Disable any cpus past max_cpus, or all secondaries if we didn't
75 * get the necessary resources to support SMP. */
76 for (i
=max
; i
<NR_CPUS
; i
++) {
77 set_cpu_possible(i
, false);
78 set_cpu_present(i
, false);
82 static void j2_start_cpu(unsigned int cpu
, unsigned long entry_point
)
84 struct device_node
*np
;
86 void __iomem
*release
, *initpc
;
90 np
= of_get_cpu_node(cpu
, NULL
);
93 if (of_property_read_u32_array(np
, "cpu-release-addr", regs
, 2)) return;
94 release
= ioremap_nocache(regs
[0], sizeof(u32
));
95 initpc
= ioremap_nocache(regs
[1], sizeof(u32
));
97 __raw_writel(entry_point
, initpc
);
98 __raw_writel(1, release
);
103 pr_info("J2 SMP: requested start of cpu %u\n", cpu
);
106 static unsigned int j2_smp_processor_id(void)
108 return __raw_readl(sh2_cpuid_addr
);
111 static void j2_send_ipi(unsigned int cpu
, unsigned int message
)
113 volatile unsigned *pmsg
;
117 /* There is only one IPI interrupt shared by all messages, so
118 * we keep a separate interrupt flag per message type in sw. */
119 pmsg
= &per_cpu(j2_ipi_messages
, cpu
);
121 while (cmpxchg(pmsg
, old
, old
|(1U<<message
)) != old
);
123 /* Generate the actual interrupt by writing to CCRn bit 28. */
124 val
= __raw_readl(j2_ipi_trigger
+ cpu
);
125 __raw_writel(val
| (1U<<28), j2_ipi_trigger
+ cpu
);
128 static struct plat_smp_ops j2_smp_ops
= {
129 .smp_setup
= j2_smp_setup
,
130 .prepare_cpus
= j2_prepare_cpus
,
131 .start_cpu
= j2_start_cpu
,
132 .smp_processor_id
= j2_smp_processor_id
,
133 .send_ipi
= j2_send_ipi
,
134 .cpu_die
= native_cpu_die
,
135 .cpu_disable
= native_cpu_disable
,
136 .play_dead
= native_play_dead
,
139 CPU_METHOD_OF_DECLARE(j2_cpu_method
, "jcore,spin-table", &j2_smp_ops
);