xref: /linux/arch/arc/kernel/mcip.c (revision 82fea5a1bbbe8c3b56d5f3efbf8880c7b25b1758)
1 /*
2  * ARC ARConnect (MultiCore IP) support (formerly known as MCIP)
3  *
4  * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/smp.h>
12 #include <linux/irq.h>
13 #include <linux/spinlock.h>
14 #include <asm/mcip.h>
15 
16 static char smp_cpuinfo_buf[128];
17 
18 static DEFINE_RAW_SPINLOCK(mcip_lock);
19 
20 
21 /*
22  * Any SMP specific init any CPU does when it comes up.
23  * Here we setup the CPU to enable Inter-Processor-Interrupts
24  * Called for each CPU
25  * -Master      : init_IRQ()
26  * -Other(s)    : start_kernel_secondary()
27  */
28 void mcip_init_smp(unsigned int cpu)
29 {
30 	smp_ipi_irq_setup(cpu, IPI_IRQ);
31 }
32 
33 static void mcip_ipi_send(int cpu)
34 {
35 	unsigned long flags;
36 
37 	raw_spin_lock_irqsave(&mcip_lock, flags);
38 	__mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
39 	raw_spin_unlock_irqrestore(&mcip_lock, flags);
40 }
41 
42 static void mcip_ipi_clear(int irq)
43 {
44 	unsigned int cpu;
45 	unsigned long flags;
46 
47 	raw_spin_lock_irqsave(&mcip_lock, flags);
48 
49 	/* Who sent the IPI */
50 	__mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0);
51 
52 	cpu = read_aux_reg(ARC_REG_MCIP_READBACK);	/* 1,2,4,8... */
53 
54 	__mcip_cmd(CMD_INTRPT_GENERATE_ACK, __ffs(cpu)); /* 0,1,2,3... */
55 
56 	raw_spin_unlock_irqrestore(&mcip_lock, flags);
57 }
58 
59 volatile int wake_flag;
60 
61 static void mcip_wakeup_cpu(int cpu, unsigned long pc)
62 {
63 	BUG_ON(cpu == 0);
64 	wake_flag = cpu;
65 }
66 
67 void arc_platform_smp_wait_to_boot(int cpu)
68 {
69 	while (wake_flag != cpu)
70 		;
71 
72 	wake_flag = 0;
73 	__asm__ __volatile__("j @first_lines_of_secondary	\n");
74 }
75 
76 struct plat_smp_ops plat_smp_ops = {
77 	.info		= smp_cpuinfo_buf,
78 	.cpu_kick	= mcip_wakeup_cpu,
79 	.ipi_send	= mcip_ipi_send,
80 	.ipi_clear	= mcip_ipi_clear,
81 };
82 
83 void mcip_init_early_smp(void)
84 {
85 #define IS_AVAIL1(var, str)    ((var) ? str : "")
86 
87 	struct mcip_bcr {
88 #ifdef CONFIG_CPU_BIG_ENDIAN
89 		unsigned int pad3:8,
90 			     idu:1, llm:1, num_cores:6,
91 			     iocoh:1,  grtc:1, dbg:1, pad2:1,
92 			     msg:1, sem:1, ipi:1, pad:1,
93 			     ver:8;
94 #else
95 		unsigned int ver:8,
96 			     pad:1, ipi:1, sem:1, msg:1,
97 			     pad2:1, dbg:1, grtc:1, iocoh:1,
98 			     num_cores:6, llm:1, idu:1,
99 			     pad3:8;
100 #endif
101 	} mp;
102 
103 	READ_BCR(ARC_REG_MCIP_BCR, mp);
104 
105 	sprintf(smp_cpuinfo_buf,
106 		"Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
107 		mp.ver, mp.num_cores,
108 		IS_AVAIL1(mp.ipi, "IPI "),
109 		IS_AVAIL1(mp.idu, "IDU "),
110 		IS_AVAIL1(mp.dbg, "DEBUG "),
111 		IS_AVAIL1(mp.grtc, "GRTC"));
112 
113 	if (mp.dbg) {
114 		__mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
115 		__mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
116 	}
117 }
118