blob: e6ad6e64440a1c20765669d2da4c4640e9e09513 [file] [log] [blame]
Vineet Gupta82fea5a2014-09-10 19:05:38 +05301/*
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
16static char smp_cpuinfo_buf[128];
17
18static 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 */
28void mcip_init_smp(unsigned int cpu)
29{
30 smp_ipi_irq_setup(cpu, IPI_IRQ);
31}
32
33static 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
42static 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
59volatile int wake_flag;
60
61static void mcip_wakeup_cpu(int cpu, unsigned long pc)
62{
63 BUG_ON(cpu == 0);
64 wake_flag = cpu;
65}
66
67void 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
76struct 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
83void 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}