aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/sibyte
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/sibyte')
-rw-r--r--arch/mips/sibyte/Kconfig167
-rw-r--r--arch/mips/sibyte/Makefile29
-rw-r--r--arch/mips/sibyte/Platform40
-rw-r--r--arch/mips/sibyte/bcm1480/Makefile4
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c348
-rw-r--r--arch/mips/sibyte/bcm1480/setup.c128
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c179
-rw-r--r--arch/mips/sibyte/bcm1480/time.c14
-rw-r--r--arch/mips/sibyte/common/Makefile6
-rw-r--r--arch/mips/sibyte/common/bus_watcher.c228
-rw-r--r--arch/mips/sibyte/common/cfe.c330
-rw-r--r--arch/mips/sibyte/common/cfe_console.c81
-rw-r--r--arch/mips/sibyte/common/dma.c14
-rw-r--r--arch/mips/sibyte/common/sb_tbprof.c595
-rw-r--r--arch/mips/sibyte/sb1250/Makefile4
-rw-r--r--arch/mips/sibyte/sb1250/irq.c324
-rw-r--r--arch/mips/sibyte/sb1250/setup.c234
-rw-r--r--arch/mips/sibyte/sb1250/smp.c168
-rw-r--r--arch/mips/sibyte/sb1250/time.c14
-rw-r--r--arch/mips/sibyte/swarm/Makefile5
-rw-r--r--arch/mips/sibyte/swarm/platform.c140
-rw-r--r--arch/mips/sibyte/swarm/rtc_m41t81.c228
-rw-r--r--arch/mips/sibyte/swarm/rtc_xicor1241.c206
-rw-r--r--arch/mips/sibyte/swarm/setup.c171
-rw-r--r--arch/mips/sibyte/swarm/swarm-i2c.c31
25 files changed, 3688 insertions, 0 deletions
diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig
new file mode 100644
index 000000000..470d46183
--- /dev/null
+++ b/arch/mips/sibyte/Kconfig
@@ -0,0 +1,167 @@
1# SPDX-License-Identifier: GPL-2.0
2config SIBYTE_SB1250
3 bool
4 select CEVT_SB1250
5 select CSRC_SB1250
6 select HAVE_PCI
7 select IRQ_MIPS_CPU
8 select SIBYTE_ENABLE_LDT_IF_PCI
9 select SIBYTE_HAS_ZBUS_PROFILING
10 select SIBYTE_SB1xxx_SOC
11 select SYS_SUPPORTS_SMP
12
13config SIBYTE_BCM1120
14 bool
15 select CEVT_SB1250
16 select CSRC_SB1250
17 select IRQ_MIPS_CPU
18 select SIBYTE_BCM112X
19 select SIBYTE_HAS_ZBUS_PROFILING
20 select SIBYTE_SB1xxx_SOC
21
22config SIBYTE_BCM1125
23 bool
24 select CEVT_SB1250
25 select CSRC_SB1250
26 select HAVE_PCI
27 select IRQ_MIPS_CPU
28 select SIBYTE_BCM112X
29 select SIBYTE_HAS_ZBUS_PROFILING
30 select SIBYTE_SB1xxx_SOC
31
32config SIBYTE_BCM1125H
33 bool
34 select CEVT_SB1250
35 select CSRC_SB1250
36 select HAVE_PCI
37 select IRQ_MIPS_CPU
38 select SIBYTE_BCM112X
39 select SIBYTE_ENABLE_LDT_IF_PCI
40 select SIBYTE_HAS_ZBUS_PROFILING
41 select SIBYTE_SB1xxx_SOC
42
43config SIBYTE_BCM112X
44 bool
45 select CEVT_SB1250
46 select CSRC_SB1250
47 select IRQ_MIPS_CPU
48 select SIBYTE_SB1xxx_SOC
49 select SIBYTE_HAS_ZBUS_PROFILING
50
51config SIBYTE_BCM1x80
52 bool
53 select CEVT_BCM1480
54 select CSRC_BCM1480
55 select HAVE_PCI
56 select IRQ_MIPS_CPU
57 select SIBYTE_HAS_ZBUS_PROFILING
58 select SIBYTE_SB1xxx_SOC
59 select SYS_SUPPORTS_SMP
60
61config SIBYTE_BCM1x55
62 bool
63 select CEVT_BCM1480
64 select CSRC_BCM1480
65 select HAVE_PCI
66 select IRQ_MIPS_CPU
67 select SIBYTE_SB1xxx_SOC
68 select SIBYTE_HAS_ZBUS_PROFILING
69 select SYS_SUPPORTS_SMP
70
71config SIBYTE_SB1xxx_SOC
72 bool
73 select IRQ_MIPS_CPU
74 select SWAP_IO_SPACE
75 select SYS_SUPPORTS_32BIT_KERNEL
76 select SYS_SUPPORTS_64BIT_KERNEL
77 select FW_CFE
78 select SYS_HAS_EARLY_PRINTK
79
80choice
81 prompt "SiByte SOC Stepping"
82 depends on SIBYTE_SB1xxx_SOC
83
84config CPU_SB1_PASS_2_1250
85 bool "1250 An"
86 depends on SIBYTE_SB1250
87 select CPU_SB1_PASS_2
88 help
89 Also called BCM1250 Pass 2
90
91config CPU_SB1_PASS_2_2
92 bool "1250 Bn"
93 depends on SIBYTE_SB1250
94 select CPU_HAS_PREFETCH
95 help
96 Also called BCM1250 Pass 2.2
97
98config CPU_SB1_PASS_4
99 bool "1250 Cn"
100 depends on SIBYTE_SB1250
101 select CPU_HAS_PREFETCH
102 help
103 Also called BCM1250 Pass 3
104
105config CPU_SB1_PASS_2_112x
106 bool "112x Hybrid"
107 depends on SIBYTE_BCM112X
108 select CPU_SB1_PASS_2
109
110config CPU_SB1_PASS_3
111 bool "112x An"
112 depends on SIBYTE_BCM112X
113 select CPU_HAS_PREFETCH
114
115endchoice
116
117config CPU_SB1_PASS_2
118 bool
119
120config SIBYTE_HAS_LDT
121 bool
122
123config SIBYTE_ENABLE_LDT_IF_PCI
124 bool
125 select SIBYTE_HAS_LDT if PCI
126
127config SB1_CEX_ALWAYS_FATAL
128 bool "All cache exceptions considered fatal (no recovery attempted)"
129 depends on SIBYTE_SB1xxx_SOC
130
131config SB1_CERR_STALL
132 bool "Stall (rather than panic) on fatal cache error"
133 depends on SIBYTE_SB1xxx_SOC
134
135config SIBYTE_CFE_CONSOLE
136 bool "Use firmware console"
137 depends on SIBYTE_SB1xxx_SOC
138 help
139 Use the CFE API's console write routines during boot. Other console
140 options (VT console, sb1250 duart console, etc.) should not be
141 configured.
142
143config SIBYTE_BUS_WATCHER
144 bool "Support for Bus Watcher statistics"
145 depends on SIBYTE_SB1xxx_SOC && \
146 (SIBYTE_BCM112X || SIBYTE_SB1250 || \
147 SIBYTE_BCM1x55 || SIBYTE_BCM1x80)
148 help
149 Handle and keep statistics on the bus error interrupts (COR_ECC,
150 BAD_ECC, IO_BUS).
151
152config SIBYTE_BW_TRACE
153 bool "Capture bus trace before bus error"
154 depends on SIBYTE_BUS_WATCHER
155 help
156 Run a continuous bus trace, dumping the raw data as soon as
157 a ZBbus error is detected. Cannot work if ZBbus profiling
158 is turned on, and also will interfere with JTAG-based trace
159 buffer activity. Raw buffer data is dumped to console, and
160 must be processed off-line.
161
162config SIBYTE_TBPROF
163 tristate "Support for ZBbus profiling"
164 depends on SIBYTE_HAS_ZBUS_PROFILING
165
166config SIBYTE_HAS_ZBUS_PROFILING
167 bool
diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile
new file mode 100644
index 000000000..d015c4d79
--- /dev/null
+++ b/arch/mips/sibyte/Makefile
@@ -0,0 +1,29 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Sibyte SB1250 / BCM1480 family of SOCs
4#
5obj-$(CONFIG_SIBYTE_BCM112X) += sb1250/
6obj-$(CONFIG_SIBYTE_BCM112X) += common/
7obj-$(CONFIG_SIBYTE_SB1250) += sb1250/
8obj-$(CONFIG_SIBYTE_SB1250) += common/
9obj-$(CONFIG_SIBYTE_BCM1x55) += bcm1480/
10obj-$(CONFIG_SIBYTE_BCM1x55) += common/
11obj-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/
12obj-$(CONFIG_SIBYTE_BCM1x80) += common/
13
14#
15# Sibyte BCM91120x (Carmel) board
16# Sibyte BCM91120C (CRhine) board
17# Sibyte BCM91125C (CRhone) board
18# Sibyte BCM91125E (Rhone) board
19# Sibyte SWARM board
20# Sibyte BCM91x80 (BigSur) board
21#
22obj-$(CONFIG_SIBYTE_CARMEL) += swarm/
23obj-$(CONFIG_SIBYTE_CRHINE) += swarm/
24obj-$(CONFIG_SIBYTE_CRHONE) += swarm/
25obj-$(CONFIG_SIBYTE_RHONE) += swarm/
26obj-$(CONFIG_SIBYTE_SENTOSA) += swarm/
27obj-$(CONFIG_SIBYTE_SWARM) += swarm/
28obj-$(CONFIG_SIBYTE_BIGSUR) += swarm/
29obj-$(CONFIG_SIBYTE_LITTLESUR) += swarm/
diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform
new file mode 100644
index 000000000..65b2225b7
--- /dev/null
+++ b/arch/mips/sibyte/Platform
@@ -0,0 +1,40 @@
1#
2# These are all rather similar so we consider them a single platform
3#
4
5#
6# Sibyte SB1250 / BCM1480 family of SOCs
7#
8cflags-$(CONFIG_SIBYTE_BCM112X) += \
9 -I$(srctree)/arch/mips/include/asm/mach-sibyte \
10 -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
11
12cflags-$(CONFIG_SIBYTE_SB1250) += \
13 -I$(srctree)/arch/mips/include/asm/mach-sibyte \
14 -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
15
16cflags-$(CONFIG_SIBYTE_BCM1x55) += \
17 -I$(srctree)/arch/mips/include/asm/mach-sibyte \
18 -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
19
20cflags-$(CONFIG_SIBYTE_BCM1x80) += \
21 -I$(srctree)/arch/mips/include/asm/mach-sibyte \
22 -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
23
24#
25# Sibyte BCM91120x (Carmel) board
26# Sibyte BCM91120C (CRhine) board
27# Sibyte BCM91125C (CRhone) board
28# Sibyte BCM91125E (Rhone) board
29# Sibyte BCM91250A (SWARM) board
30# Sibyte BCM91250C2 (LittleSur) board
31# Sibyte BCM91x80 (BigSur) board
32#
33load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
34load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000
35load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000
36load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000
37load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
38load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
39load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
40load-$(CONFIG_SIBYTE_LITTLESUR) := 0xffffffff80100000
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile
new file mode 100644
index 000000000..cf1327d3f
--- /dev/null
+++ b/arch/mips/sibyte/bcm1480/Makefile
@@ -0,0 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0-only
2obj-y := setup.o irq.o time.o
3
4obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
new file mode 100644
index 000000000..7929bee91
--- /dev/null
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -0,0 +1,348 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
4 */
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/linkage.h>
8#include <linux/interrupt.h>
9#include <linux/smp.h>
10#include <linux/spinlock.h>
11#include <linux/mm.h>
12#include <linux/kernel_stat.h>
13
14#include <asm/errno.h>
15#include <asm/irq_regs.h>
16#include <asm/signal.h>
17#include <asm/io.h>
18
19#include <asm/sibyte/bcm1480_regs.h>
20#include <asm/sibyte/bcm1480_int.h>
21#include <asm/sibyte/bcm1480_scd.h>
22
23#include <asm/sibyte/sb1250_uart.h>
24#include <asm/sibyte/sb1250.h>
25
26/*
27 * These are the routines that handle all the low level interrupt stuff.
28 * Actions handled here are: initialization of the interrupt map, requesting of
29 * interrupt lines by handlers, dispatching if interrupts to handlers, probing
30 * for interrupt lines
31 */
32
33#ifdef CONFIG_PCI
34extern unsigned long ht_eoi_space;
35#endif
36
37/* Store the CPU id (not the logical number) */
38int bcm1480_irq_owner[BCM1480_NR_IRQS];
39
40static DEFINE_RAW_SPINLOCK(bcm1480_imr_lock);
41
42void bcm1480_mask_irq(int cpu, int irq)
43{
44 unsigned long flags, hl_spacing;
45 u64 cur_ints;
46
47 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
48 hl_spacing = 0;
49 if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
50 hl_spacing = BCM1480_IMR_HL_SPACING;
51 irq -= BCM1480_NR_IRQS_HALF;
52 }
53 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
54 cur_ints |= (((u64) 1) << irq);
55 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
56 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
57}
58
59void bcm1480_unmask_irq(int cpu, int irq)
60{
61 unsigned long flags, hl_spacing;
62 u64 cur_ints;
63
64 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
65 hl_spacing = 0;
66 if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
67 hl_spacing = BCM1480_IMR_HL_SPACING;
68 irq -= BCM1480_NR_IRQS_HALF;
69 }
70 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
71 cur_ints &= ~(((u64) 1) << irq);
72 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
73 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
74}
75
76#ifdef CONFIG_SMP
77static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
78 bool force)
79{
80 unsigned int irq_dirty, irq = d->irq;
81 int i = 0, old_cpu, cpu, int_on, k;
82 u64 cur_ints;
83 unsigned long flags;
84
85 i = cpumask_first_and(mask, cpu_online_mask);
86
87 /* Convert logical CPU to physical CPU */
88 cpu = cpu_logical_map(i);
89
90 /* Protect against other affinity changers and IMR manipulation */
91 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
92
93 /* Swizzle each CPU's IMR (but leave the IP selection alone) */
94 old_cpu = bcm1480_irq_owner[irq];
95 irq_dirty = irq;
96 if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
97 irq_dirty -= BCM1480_NR_IRQS_HALF;
98 }
99
100 for (k=0; k<2; k++) { /* Loop through high and low interrupt mask register */
101 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
102 int_on = !(cur_ints & (((u64) 1) << irq_dirty));
103 if (int_on) {
104 /* If it was on, mask it */
105 cur_ints |= (((u64) 1) << irq_dirty);
106 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
107 }
108 bcm1480_irq_owner[irq] = cpu;
109 if (int_on) {
110 /* unmask for the new CPU */
111 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
112 cur_ints &= ~(((u64) 1) << irq_dirty);
113 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
114 }
115 }
116 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
117
118 return 0;
119}
120#endif
121
122
123/*****************************************************************************/
124
125static void disable_bcm1480_irq(struct irq_data *d)
126{
127 unsigned int irq = d->irq;
128
129 bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
130}
131
132static void enable_bcm1480_irq(struct irq_data *d)
133{
134 unsigned int irq = d->irq;
135
136 bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
137}
138
139
140static void ack_bcm1480_irq(struct irq_data *d)
141{
142 unsigned int irq_dirty, irq = d->irq;
143 u64 pending;
144 int k;
145
146 /*
147 * If the interrupt was an HT interrupt, now is the time to
148 * clear it. NOTE: we assume the HT bridge was set up to
149 * deliver the interrupts to all CPUs (which makes affinity
150 * changing easier for us)
151 */
152 irq_dirty = irq;
153 if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
154 irq_dirty -= BCM1480_NR_IRQS_HALF;
155 }
156 for (k=0; k<2; k++) { /* Loop through high and low LDT interrupts */
157 pending = __raw_readq(IOADDR(A_BCM1480_IMR_REGISTER(bcm1480_irq_owner[irq],
158 R_BCM1480_IMR_LDT_INTERRUPT_H + (k*BCM1480_IMR_HL_SPACING))));
159 pending &= ((u64)1 << (irq_dirty));
160 if (pending) {
161#ifdef CONFIG_SMP
162 int i;
163 for (i=0; i<NR_CPUS; i++) {
164 /*
165 * Clear for all CPUs so an affinity switch
166 * doesn't find an old status
167 */
168 __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(cpu_logical_map(i),
169 R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
170 }
171#else
172 __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
173#endif
174
175 /*
176 * Generate EOI. For Pass 1 parts, EOI is a nop. For
177 * Pass 2, the LDT world may be edge-triggered, but
178 * this EOI shouldn't hurt. If they are
179 * level-sensitive, the EOI is required.
180 */
181#ifdef CONFIG_PCI
182 if (ht_eoi_space)
183 *(uint32_t *)(ht_eoi_space+(irq<<16)+(7<<2)) = 0;
184#endif
185 }
186 }
187 bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
188}
189
190static struct irq_chip bcm1480_irq_type = {
191 .name = "BCM1480-IMR",
192 .irq_mask_ack = ack_bcm1480_irq,
193 .irq_mask = disable_bcm1480_irq,
194 .irq_unmask = enable_bcm1480_irq,
195#ifdef CONFIG_SMP
196 .irq_set_affinity = bcm1480_set_affinity
197#endif
198};
199
200void __init init_bcm1480_irqs(void)
201{
202 int i;
203
204 for (i = 0; i < BCM1480_NR_IRQS; i++) {
205 irq_set_chip_and_handler(i, &bcm1480_irq_type,
206 handle_level_irq);
207 bcm1480_irq_owner[i] = 0;
208 }
209}
210
211/*
212 * init_IRQ is called early in the boot sequence from init/main.c. It
213 * is responsible for setting up the interrupt mapper and installing the
214 * handler that will be responsible for dispatching interrupts to the
215 * "right" place.
216 */
217/*
218 * For now, map all interrupts to IP[2]. We could save
219 * some cycles by parceling out system interrupts to different
220 * IP lines, but keep it simple for bringup. We'll also direct
221 * all interrupts to a single CPU; we should probably route
222 * PCI and LDT to one cpu and everything else to the other
223 * to balance the load a bit.
224 *
225 * On the second cpu, everything is set to IP5, which is
226 * ignored, EXCEPT the mailbox interrupt. That one is
227 * set to IP[2] so it is handled. This is needed so we
228 * can do cross-cpu function calls, as required by SMP
229 */
230
231#define IMR_IP2_VAL K_BCM1480_INT_MAP_I0
232#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1
233#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2
234#define IMR_IP5_VAL K_BCM1480_INT_MAP_I3
235#define IMR_IP6_VAL K_BCM1480_INT_MAP_I4
236
237void __init arch_init_irq(void)
238{
239 unsigned int i, cpu;
240 u64 tmp;
241 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
242 STATUSF_IP1 | STATUSF_IP0;
243
244 /* Default everything to IP2 */
245 /* Start with _high registers which has no bit 0 interrupt source */
246 for (i = 1; i < BCM1480_NR_IRQS_HALF; i++) { /* was I0 */
247 for (cpu = 0; cpu < 4; cpu++) {
248 __raw_writeq(IMR_IP2_VAL,
249 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
250 R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (i << 3)));
251 }
252 }
253
254 /* Now do _low registers */
255 for (i = 0; i < BCM1480_NR_IRQS_HALF; i++) {
256 for (cpu = 0; cpu < 4; cpu++) {
257 __raw_writeq(IMR_IP2_VAL,
258 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
259 R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + (i << 3)));
260 }
261 }
262
263 init_bcm1480_irqs();
264
265 /*
266 * Map the high 16 bits of mailbox_0 registers to IP[3], for
267 * inter-cpu messages
268 */
269 /* Was I1 */
270 for (cpu = 0; cpu < 4; cpu++) {
271 __raw_writeq(IMR_IP3_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) +
272 (K_BCM1480_INT_MBOX_0_0 << 3)));
273 }
274
275
276 /* Clear the mailboxes. The firmware may leave them dirty */
277 for (cpu = 0; cpu < 4; cpu++) {
278 __raw_writeq(0xffffffffffffffffULL,
279 IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_0_CLR_CPU)));
280 __raw_writeq(0xffffffffffffffffULL,
281 IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_1_CLR_CPU)));
282 }
283
284
285 /* Mask everything except the high 16 bit of mailbox_0 registers for all cpus */
286 tmp = ~((u64) 0) ^ ( (((u64) 1) << K_BCM1480_INT_MBOX_0_0));
287 for (cpu = 0; cpu < 4; cpu++) {
288 __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_H)));
289 }
290 tmp = ~((u64) 0);
291 for (cpu = 0; cpu < 4; cpu++) {
292 __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L)));
293 }
294
295 /*
296 * Note that the timer interrupts are also mapped, but this is
297 * done in bcm1480_time_init(). Also, the profiling driver
298 * does its own management of IP7.
299 */
300
301 /* Enable necessary IPs, disable the rest */
302 change_c0_status(ST0_IM, imask);
303}
304
305extern void bcm1480_mailbox_interrupt(void);
306
307static inline void dispatch_ip2(void)
308{
309 unsigned long long mask_h, mask_l;
310 unsigned int cpu = smp_processor_id();
311 unsigned long base;
312
313 /*
314 * Default...we've hit an IP[2] interrupt, which means we've got to
315 * check the 1480 interrupt registers to figure out what to do. Need
316 * to detect which CPU we're on, now that smp_affinity is supported.
317 */
318 base = A_BCM1480_IMR_MAPPER(cpu);
319 mask_h = __raw_readq(
320 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
321 mask_l = __raw_readq(
322 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
323
324 if (mask_h) {
325 if (mask_h ^ 1)
326 do_IRQ(fls64(mask_h) - 1);
327 else if (mask_l)
328 do_IRQ(63 + fls64(mask_l));
329 }
330}
331
332asmlinkage void plat_irq_dispatch(void)
333{
334 unsigned int cpu = smp_processor_id();
335 unsigned int pending;
336
337 pending = read_c0_cause() & read_c0_status();
338
339 if (pending & CAUSEF_IP4)
340 do_IRQ(K_BCM1480_INT_TIMER_0 + cpu);
341#ifdef CONFIG_SMP
342 else if (pending & CAUSEF_IP3)
343 bcm1480_mailbox_interrupt();
344#endif
345
346 else if (pending & CAUSEF_IP2)
347 dispatch_ip2();
348}
diff --git a/arch/mips/sibyte/bcm1480/setup.c b/arch/mips/sibyte/bcm1480/setup.c
new file mode 100644
index 000000000..6f34b871b
--- /dev/null
+++ b/arch/mips/sibyte/bcm1480/setup.c
@@ -0,0 +1,128 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
4 */
5#include <linux/init.h>
6#include <linux/kernel.h>
7#include <linux/export.h>
8#include <linux/reboot.h>
9#include <linux/string.h>
10
11#include <asm/bootinfo.h>
12#include <asm/cpu.h>
13#include <asm/mipsregs.h>
14#include <asm/io.h>
15#include <asm/sibyte/sb1250.h>
16
17#include <asm/sibyte/bcm1480_regs.h>
18#include <asm/sibyte/bcm1480_scd.h>
19#include <asm/sibyte/sb1250_scd.h>
20
21unsigned int sb1_pass;
22unsigned int soc_pass;
23unsigned int soc_type;
24EXPORT_SYMBOL(soc_type);
25unsigned int periph_rev;
26EXPORT_SYMBOL_GPL(periph_rev);
27unsigned int zbbus_mhz;
28EXPORT_SYMBOL(zbbus_mhz);
29
30static unsigned int part_type;
31
32static char *soc_str;
33static char *pass_str;
34
35static int __init setup_bcm1x80_bcm1x55(void)
36{
37 int ret = 0;
38
39 switch (soc_pass) {
40 case K_SYS_REVISION_BCM1480_S0:
41 periph_rev = 1;
42 pass_str = "S0 (pass1)";
43 break;
44 case K_SYS_REVISION_BCM1480_A1:
45 periph_rev = 1;
46 pass_str = "A1 (pass1)";
47 break;
48 case K_SYS_REVISION_BCM1480_A2:
49 periph_rev = 1;
50 pass_str = "A2 (pass1)";
51 break;
52 case K_SYS_REVISION_BCM1480_A3:
53 periph_rev = 1;
54 pass_str = "A3 (pass1)";
55 break;
56 case K_SYS_REVISION_BCM1480_B0:
57 periph_rev = 1;
58 pass_str = "B0 (pass2)";
59 break;
60 default:
61 printk("Unknown %s rev %x\n", soc_str, soc_pass);
62 periph_rev = 1;
63 pass_str = "Unknown Revision";
64 break;
65 }
66
67 return ret;
68}
69
70/* Setup code likely to be common to all SiByte platforms */
71
72static int __init sys_rev_decode(void)
73{
74 int ret = 0;
75
76 switch (soc_type) {
77 case K_SYS_SOC_TYPE_BCM1x80:
78 if (part_type == K_SYS_PART_BCM1480)
79 soc_str = "BCM1480";
80 else if (part_type == K_SYS_PART_BCM1280)
81 soc_str = "BCM1280";
82 else
83 soc_str = "BCM1x80";
84 ret = setup_bcm1x80_bcm1x55();
85 break;
86
87 case K_SYS_SOC_TYPE_BCM1x55:
88 if (part_type == K_SYS_PART_BCM1455)
89 soc_str = "BCM1455";
90 else if (part_type == K_SYS_PART_BCM1255)
91 soc_str = "BCM1255";
92 else
93 soc_str = "BCM1x55";
94 ret = setup_bcm1x80_bcm1x55();
95 break;
96
97 default:
98 printk("Unknown part type %x\n", part_type);
99 ret = 1;
100 break;
101 }
102
103 return ret;
104}
105
106void __init bcm1480_setup(void)
107{
108 uint64_t sys_rev;
109 int plldiv;
110
111 sb1_pass = read_c0_prid() & PRID_REV_MASK;
112 sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
113 soc_type = SYS_SOC_TYPE(sys_rev);
114 part_type = G_SYS_PART(sys_rev);
115 soc_pass = G_SYS_REVISION(sys_rev);
116
117 if (sys_rev_decode()) {
118 printk("Restart after failure to identify SiByte chip\n");
119 machine_restart(NULL);
120 }
121
122 plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
123 zbbus_mhz = ((plldiv >> 1) * 50) + ((plldiv & 1) * 25);
124
125 printk("Broadcom SiByte %s %s @ %d MHz (SB-1A rev %d)\n",
126 soc_str, pass_str, zbbus_mhz * 2, sb1_pass);
127 printk("Board type: %s\n", get_system_type());
128}
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
new file mode 100644
index 000000000..5861e5025
--- /dev/null
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -0,0 +1,179 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2001,2002,2004 Broadcom Corporation
4 */
5
6#include <linux/init.h>
7#include <linux/delay.h>
8#include <linux/smp.h>
9#include <linux/kernel_stat.h>
10#include <linux/sched.h>
11#include <linux/sched/task_stack.h>
12
13#include <asm/mmu_context.h>
14#include <asm/io.h>
15#include <asm/fw/cfe/cfe_api.h>
16#include <asm/sibyte/sb1250.h>
17#include <asm/sibyte/bcm1480_regs.h>
18#include <asm/sibyte/bcm1480_int.h>
19
20/*
21 * These are routines for dealing with the bcm1480 smp capabilities
22 * independent of board/firmware
23 */
24
25static void *mailbox_0_set_regs[] = {
26 IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
27 IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
28 IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
29 IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
30};
31
32static void *mailbox_0_clear_regs[] = {
33 IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
34 IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
35 IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
36 IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
37};
38
39static void *mailbox_0_regs[] = {
40 IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
41 IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
42 IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
43 IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
44};
45
46/*
47 * SMP init and finish on secondary CPUs
48 */
49void bcm1480_smp_init(void)
50{
51 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
52 STATUSF_IP1 | STATUSF_IP0;
53
54 /* Set interrupt mask, but don't enable */
55 change_c0_status(ST0_IM, imask);
56}
57
58/*
59 * These are routines for dealing with the sb1250 smp capabilities
60 * independent of board/firmware
61 */
62
63/*
64 * Simple enough; everything is set up, so just poke the appropriate mailbox
65 * register, and we should be set
66 */
67static void bcm1480_send_ipi_single(int cpu, unsigned int action)
68{
69 __raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
70}
71
72static void bcm1480_send_ipi_mask(const struct cpumask *mask,
73 unsigned int action)
74{
75 unsigned int i;
76
77 for_each_cpu(i, mask)
78 bcm1480_send_ipi_single(i, action);
79}
80
81/*
82 * Code to run on secondary just after probing the CPU
83 */
84static void bcm1480_init_secondary(void)
85{
86 extern void bcm1480_smp_init(void);
87
88 bcm1480_smp_init();
89}
90
91/*
92 * Do any tidying up before marking online and running the idle
93 * loop
94 */
95static void bcm1480_smp_finish(void)
96{
97 extern void sb1480_clockevent_init(void);
98
99 sb1480_clockevent_init();
100 local_irq_enable();
101}
102
103/*
104 * Setup the PC, SP, and GP of a secondary processor and start it
105 * running!
106 */
107static int bcm1480_boot_secondary(int cpu, struct task_struct *idle)
108{
109 int retval;
110
111 retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
112 __KSTK_TOS(idle),
113 (unsigned long)task_thread_info(idle), 0);
114 if (retval != 0)
115 printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
116 return retval;
117}
118
119/*
120 * Use CFE to find out how many CPUs are available, setting up
121 * cpu_possible_mask and the logical/physical mappings.
122 * XXXKW will the boot CPU ever not be physical 0?
123 *
124 * Common setup before any secondaries are started
125 */
126static void __init bcm1480_smp_setup(void)
127{
128 int i, num;
129
130 init_cpu_possible(cpumask_of(0));
131 __cpu_number_map[0] = 0;
132 __cpu_logical_map[0] = 0;
133
134 for (i = 1, num = 0; i < NR_CPUS; i++) {
135 if (cfe_cpu_stop(i) == 0) {
136 set_cpu_possible(i, true);
137 __cpu_number_map[i] = ++num;
138 __cpu_logical_map[num] = i;
139 }
140 }
141 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
142}
143
144static void __init bcm1480_prepare_cpus(unsigned int max_cpus)
145{
146}
147
148const struct plat_smp_ops bcm1480_smp_ops = {
149 .send_ipi_single = bcm1480_send_ipi_single,
150 .send_ipi_mask = bcm1480_send_ipi_mask,
151 .init_secondary = bcm1480_init_secondary,
152 .smp_finish = bcm1480_smp_finish,
153 .boot_secondary = bcm1480_boot_secondary,
154 .smp_setup = bcm1480_smp_setup,
155 .prepare_cpus = bcm1480_prepare_cpus,
156};
157
158void bcm1480_mailbox_interrupt(void)
159{
160 int cpu = smp_processor_id();
161 int irq = K_BCM1480_INT_MBOX_0_0;
162 unsigned int action;
163
164 kstat_incr_irq_this_cpu(irq);
165 /* Load the mailbox register to figure out what we're supposed to do */
166 action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
167
168 /* Clear the mailbox to clear the interrupt */
169 __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
170
171 if (action & SMP_RESCHEDULE_YOURSELF)
172 scheduler_ipi();
173
174 if (action & SMP_CALL_FUNCTION) {
175 irq_enter();
176 generic_smp_call_function_interrupt();
177 irq_exit();
178 }
179}
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
new file mode 100644
index 000000000..e6450d79f
--- /dev/null
+++ b/arch/mips/sibyte/bcm1480/time.c
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000,2001,2004 Broadcom Corporation
4 */
5#include <linux/init.h>
6
7extern void sb1480_clockevent_init(void);
8extern void sb1480_clocksource_init(void);
9
10void __init plat_time_init(void)
11{
12 sb1480_clocksource_init();
13 sb1480_clockevent_init();
14}
diff --git a/arch/mips/sibyte/common/Makefile b/arch/mips/sibyte/common/Makefile
new file mode 100644
index 000000000..57f670aa1
--- /dev/null
+++ b/arch/mips/sibyte/common/Makefile
@@ -0,0 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0-only
2obj-y := cfe.o
3obj-$(CONFIG_SWIOTLB) += dma.o
4obj-$(CONFIG_SIBYTE_BUS_WATCHER) += bus_watcher.o
5obj-$(CONFIG_SIBYTE_CFE_CONSOLE) += cfe_console.o
6obj-$(CONFIG_SIBYTE_TBPROF) += sb_tbprof.o
diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c
new file mode 100644
index 000000000..d43291473
--- /dev/null
+++ b/arch/mips/sibyte/common/bus_watcher.c
@@ -0,0 +1,228 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2002,2003 Broadcom Corporation
4 */
5
6/*
7 * The Bus Watcher monitors internal bus transactions and maintains
8 * counts of transactions with error status, logging details and
9 * causing one of several interrupts. This driver provides a handler
10 * for those interrupts which aggregates the counts (to avoid
11 * saturating the 8-bit counters) and provides a presence in
12 * /proc/bus_watcher if PROC_FS is on.
13 */
14
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/sched.h>
19#include <linux/proc_fs.h>
20#include <linux/seq_file.h>
21#include <asm/io.h>
22
23#include <asm/sibyte/sb1250.h>
24#include <asm/sibyte/sb1250_regs.h>
25#include <asm/sibyte/sb1250_int.h>
26#include <asm/sibyte/sb1250_scd.h>
27#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
28#include <asm/sibyte/bcm1480_regs.h>
29#endif
30
31
32struct bw_stats_struct {
33 uint64_t status;
34 uint32_t l2_err;
35 uint32_t memio_err;
36 int status_printed;
37 unsigned long l2_cor_d;
38 unsigned long l2_bad_d;
39 unsigned long l2_cor_t;
40 unsigned long l2_bad_t;
41 unsigned long mem_cor_d;
42 unsigned long mem_bad_d;
43 unsigned long bus_error;
44} bw_stats;
45
46
47static void print_summary(uint32_t status, uint32_t l2_err,
48 uint32_t memio_err)
49{
50 printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
51 printk("\nLast recorded signature:\n");
52 printk("Request %02x from %d, answered by %d with Dcode %d\n",
53 (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
54 (int)(G_SCD_BERR_TID(status) >> 6),
55 (int)G_SCD_BERR_RID(status),
56 (int)G_SCD_BERR_DCODE(status));
57}
58
59/*
60 * check_bus_watcher is exported for use in situations where we want
61 * to see the most recent status of the bus watcher, which might have
62 * already been destructively read out of the registers.
63 *
64 * notes: this is currently used by the cache error handler
65 * should provide locking against the interrupt handler
66 */
67void check_bus_watcher(void)
68{
69 u32 status, l2_err, memio_err;
70
71#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
72 /* Use non-destructive register */
73 status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
74#elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
75 /* Use non-destructive register */
76 /* Same as 1250 except BUS_ERR_STATUS_DEBUG is in a different place. */
77 status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG));
78#else
79#error bus watcher being built for unknown Sibyte SOC!
80#endif
81 if (!(status & 0x7fffffff)) {
82 printk("Using last values reaped by bus watcher driver\n");
83 status = bw_stats.status;
84 l2_err = bw_stats.l2_err;
85 memio_err = bw_stats.memio_err;
86 } else {
87 l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
88 memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
89 }
90 if (status & ~(1UL << 31))
91 print_summary(status, l2_err, memio_err);
92 else
93 printk("Bus watcher indicates no error\n");
94}
95
96#ifdef CONFIG_PROC_FS
97
98/* For simplicity, I want to assume a single read is required each
99 time */
100static int bw_proc_show(struct seq_file *m, void *v)
101{
102 struct bw_stats_struct *stats = m->private;
103
104 seq_puts(m, "SiByte Bus Watcher statistics\n");
105 seq_puts(m, "-----------------------------\n");
106 seq_printf(m, "L2-d-cor %8ld\nL2-d-bad %8ld\n",
107 stats->l2_cor_d, stats->l2_bad_d);
108 seq_printf(m, "L2-t-cor %8ld\nL2-t-bad %8ld\n",
109 stats->l2_cor_t, stats->l2_bad_t);
110 seq_printf(m, "MC-d-cor %8ld\nMC-d-bad %8ld\n",
111 stats->mem_cor_d, stats->mem_bad_d);
112 seq_printf(m, "IO-err %8ld\n", stats->bus_error);
113 seq_puts(m, "\nLast recorded signature:\n");
114 seq_printf(m, "Request %02x from %d, answered by %d with Dcode %d\n",
115 (unsigned int)(G_SCD_BERR_TID(stats->status) & 0x3f),
116 (int)(G_SCD_BERR_TID(stats->status) >> 6),
117 (int)G_SCD_BERR_RID(stats->status),
118 (int)G_SCD_BERR_DCODE(stats->status));
119 /* XXXKW indicate multiple errors between printings, or stats
120 collection (or both)? */
121 if (stats->status & M_SCD_BERR_MULTERRS)
122 seq_puts(m, "Multiple errors observed since last check.\n");
123 if (stats->status_printed) {
124 seq_puts(m, "(no change since last printing)\n");
125 } else {
126 stats->status_printed = 1;
127 }
128
129 return 0;
130}
131
132static void create_proc_decoder(struct bw_stats_struct *stats)
133{
134 struct proc_dir_entry *ent;
135
136 ent = proc_create_single_data("bus_watcher", S_IWUSR | S_IRUGO, NULL,
137 bw_proc_show, stats);
138 if (!ent) {
139 printk(KERN_INFO "Unable to initialize bus_watcher /proc entry\n");
140 return;
141 }
142}
143
144#endif /* CONFIG_PROC_FS */
145
146/*
147 * sibyte_bw_int - handle bus watcher interrupts and accumulate counts
148 *
149 * notes: possible re-entry due to multiple sources
150 * should check/indicate saturation
151 */
152static irqreturn_t sibyte_bw_int(int irq, void *data)
153{
154 struct bw_stats_struct *stats = data;
155 unsigned long cntr;
156#ifdef CONFIG_SIBYTE_BW_TRACE
157 int i;
158#endif
159
160#ifdef CONFIG_SIBYTE_BW_TRACE
161 csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
162 csr_out32(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG));
163
164 for (i=0; i<256*6; i++)
165 printk("%016llx\n",
166 (long long)__raw_readq(IOADDR(A_SCD_TRACE_READ)));
167
168 csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
169 csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
170#endif
171
172 /* Destructive read, clears register and interrupt */
173 stats->status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
174 stats->status_printed = 0;
175
176 stats->l2_err = cntr = csr_in32(IOADDR(A_BUS_L2_ERRORS));
177 stats->l2_cor_d += G_SCD_L2ECC_CORR_D(cntr);
178 stats->l2_bad_d += G_SCD_L2ECC_BAD_D(cntr);
179 stats->l2_cor_t += G_SCD_L2ECC_CORR_T(cntr);
180 stats->l2_bad_t += G_SCD_L2ECC_BAD_T(cntr);
181 csr_out32(0, IOADDR(A_BUS_L2_ERRORS));
182
183 stats->memio_err = cntr = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
184 stats->mem_cor_d += G_SCD_MEM_ECC_CORR(cntr);
185 stats->mem_bad_d += G_SCD_MEM_ECC_BAD(cntr);
186 stats->bus_error += G_SCD_MEM_BUSERR(cntr);
187 csr_out32(0, IOADDR(A_BUS_MEM_IO_ERRORS));
188
189 return IRQ_HANDLED;
190}
191
192int __init sibyte_bus_watcher(void)
193{
194 memset(&bw_stats, 0, sizeof(struct bw_stats_struct));
195 bw_stats.status_printed = 1;
196
197 if (request_irq(K_INT_BAD_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
198 printk("Failed to register bus watcher BAD_ECC irq\n");
199 return -1;
200 }
201 if (request_irq(K_INT_COR_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
202 free_irq(K_INT_BAD_ECC, &bw_stats);
203 printk("Failed to register bus watcher COR_ECC irq\n");
204 return -1;
205 }
206 if (request_irq(K_INT_IO_BUS, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
207 free_irq(K_INT_BAD_ECC, &bw_stats);
208 free_irq(K_INT_COR_ECC, &bw_stats);
209 printk("Failed to register bus watcher IO_BUS irq\n");
210 return -1;
211 }
212
213#ifdef CONFIG_PROC_FS
214 create_proc_decoder(&bw_stats);
215#endif
216
217#ifdef CONFIG_SIBYTE_BW_TRACE
218 csr_out32((M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
219 K_SCD_TRSEQ_TRIGGER_ALL),
220 IOADDR(A_SCD_TRACE_SEQUENCE_0));
221 csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
222 csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
223#endif
224
225 return 0;
226}
227
228device_initcall(sibyte_bus_watcher);
diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c
new file mode 100644
index 000000000..89f7fca45
--- /dev/null
+++ b/arch/mips/sibyte/common/cfe.c
@@ -0,0 +1,330 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
4 */
5
6#include <linux/init.h>
7#include <linux/kernel.h>
8#include <linux/linkage.h>
9#include <linux/mm.h>
10#include <linux/blkdev.h>
11#include <linux/memblock.h>
12#include <linux/pm.h>
13#include <linux/smp.h>
14
15#include <asm/bootinfo.h>
16#include <asm/reboot.h>
17#include <asm/setup.h>
18#include <asm/sibyte/board.h>
19#include <asm/smp-ops.h>
20
21#include <asm/fw/cfe/cfe_api.h>
22#include <asm/fw/cfe/cfe_error.h>
23
24/* Max ram addressable in 32-bit segments */
25#ifdef CONFIG_64BIT
26#define MAX_RAM_SIZE (~0ULL)
27#else
28#ifdef CONFIG_HIGHMEM
29#ifdef CONFIG_PHYS_ADDR_T_64BIT
30#define MAX_RAM_SIZE (~0ULL)
31#else
32#define MAX_RAM_SIZE (0xffffffffULL)
33#endif
34#else
35#define MAX_RAM_SIZE (0x1fffffffULL)
36#endif
37#endif
38
39#define SIBYTE_MAX_MEM_REGIONS 8
40phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
41phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
42unsigned int board_mem_region_count;
43
44int cfe_cons_handle;
45
46#ifdef CONFIG_BLK_DEV_INITRD
47extern unsigned long initrd_start, initrd_end;
48#endif
49
50static void __noreturn cfe_linux_exit(void *arg)
51{
52 int warm = *(int *)arg;
53
54 if (smp_processor_id()) {
55 static int reboot_smp;
56
57 /* Don't repeat the process from another CPU */
58 if (!reboot_smp) {
59 /* Get CPU 0 to do the cfe_exit */
60 reboot_smp = 1;
61 smp_call_function(cfe_linux_exit, arg, 0);
62 }
63 } else {
64 printk("Passing control back to CFE...\n");
65 cfe_exit(warm, 0);
66 printk("cfe_exit returned??\n");
67 }
68 while (1);
69}
70
71static void __noreturn cfe_linux_restart(char *command)
72{
73 static const int zero;
74
75 cfe_linux_exit((void *)&zero);
76}
77
78static void __noreturn cfe_linux_halt(void)
79{
80 static const int one = 1;
81
82 cfe_linux_exit((void *)&one);
83}
84
85static __init void prom_meminit(void)
86{
87 u64 addr, size, type; /* regardless of PHYS_ADDR_T_64BIT */
88 int mem_flags = 0;
89 unsigned int idx;
90 int rd_flag;
91#ifdef CONFIG_BLK_DEV_INITRD
92 unsigned long initrd_pstart;
93 unsigned long initrd_pend;
94
95 initrd_pstart = CPHYSADDR(initrd_start);
96 initrd_pend = CPHYSADDR(initrd_end);
97 if (initrd_start &&
98 ((initrd_pstart > MAX_RAM_SIZE)
99 || (initrd_pend > MAX_RAM_SIZE))) {
100 panic("initrd out of addressable memory");
101 }
102
103#endif /* INITRD */
104
105 for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE;
106 idx++) {
107 rd_flag = 0;
108 if (type == CFE_MI_AVAILABLE) {
109 /*
110 * See if this block contains (any portion of) the
111 * ramdisk
112 */
113#ifdef CONFIG_BLK_DEV_INITRD
114 if (initrd_start) {
115 if ((initrd_pstart > addr) &&
116 (initrd_pstart < (addr + size))) {
117 memblock_add(addr,
118 initrd_pstart - addr);
119 rd_flag = 1;
120 }
121 if ((initrd_pend > addr) &&
122 (initrd_pend < (addr + size))) {
123 memblock_add(initrd_pend,
124 (addr + size) - initrd_pend);
125 rd_flag = 1;
126 }
127 }
128#endif
129 if (!rd_flag) {
130 if (addr > MAX_RAM_SIZE)
131 continue;
132 if (addr+size > MAX_RAM_SIZE)
133 size = MAX_RAM_SIZE - (addr+size) + 1;
134 /*
135 * memcpy/__copy_user prefetch, which
136 * will cause a bus error for
137 * KSEG/KUSEG addrs not backed by RAM.
138 * Hence, reserve some padding for the
139 * prefetch distance.
140 */
141 if (size > 512)
142 size -= 512;
143 memblock_add(addr, size);
144 }
145 board_mem_region_addrs[board_mem_region_count] = addr;
146 board_mem_region_sizes[board_mem_region_count] = size;
147 board_mem_region_count++;
148 if (board_mem_region_count ==
149 SIBYTE_MAX_MEM_REGIONS) {
150 /*
151 * Too many regions. Need to configure more
152 */
153 while(1);
154 }
155 }
156 }
157#ifdef CONFIG_BLK_DEV_INITRD
158 if (initrd_start) {
159 memblock_add(initrd_pstart, initrd_pend - initrd_pstart);
160 memblock_reserve(initrd_pstart, initrd_pend - initrd_pstart);
161 }
162#endif
163}
164
165#ifdef CONFIG_BLK_DEV_INITRD
166static int __init initrd_setup(char *str)
167{
168 char rdarg[64];
169 int idx;
170 char *tmp, *endptr;
171 unsigned long initrd_size;
172
173 /* Make a copy of the initrd argument so we can smash it up here */
174 for (idx = 0; idx < sizeof(rdarg)-1; idx++) {
175 if (!str[idx] || (str[idx] == ' ')) break;
176 rdarg[idx] = str[idx];
177 }
178
179 rdarg[idx] = 0;
180 str = rdarg;
181
182 /*
183 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
184 * e.g. initrd=3abfd@80010000. This is set up by the loader.
185 */
186 for (tmp = str; *tmp != '@'; tmp++) {
187 if (!*tmp) {
188 goto fail;
189 }
190 }
191 *tmp = 0;
192 tmp++;
193 if (!*tmp) {
194 goto fail;
195 }
196 initrd_size = simple_strtoul(str, &endptr, 16);
197 if (*endptr) {
198 *(tmp-1) = '@';
199 goto fail;
200 }
201 *(tmp-1) = '@';
202 initrd_start = simple_strtoul(tmp, &endptr, 16);
203 if (*endptr) {
204 goto fail;
205 }
206 initrd_end = initrd_start + initrd_size;
207 printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
208 return 1;
209 fail:
210 printk("Bad initrd argument. Disabling initrd\n");
211 initrd_start = 0;
212 initrd_end = 0;
213 return 1;
214}
215
216#endif
217
218extern const struct plat_smp_ops sb_smp_ops;
219extern const struct plat_smp_ops bcm1480_smp_ops;
220
221/*
222 * prom_init is called just after the cpu type is determined, from setup_arch()
223 */
224void __init prom_init(void)
225{
226 uint64_t cfe_ept, cfe_handle;
227 unsigned int cfe_eptseal;
228 int argc = fw_arg0;
229 char **envp = (char **) fw_arg2;
230 int *prom_vec = (int *) fw_arg3;
231
232 _machine_restart = cfe_linux_restart;
233 _machine_halt = cfe_linux_halt;
234 pm_power_off = cfe_linux_halt;
235
236 /*
237 * Check if a loader was used; if NOT, the 4 arguments are
238 * what CFE gives us (handle, 0, EPT and EPTSEAL)
239 */
240 if (argc < 0) {
241 cfe_handle = (uint64_t)(long)argc;
242 cfe_ept = (long)envp;
243 cfe_eptseal = (uint32_t)(unsigned long)prom_vec;
244 } else {
245 if ((int32_t)(long)prom_vec < 0) {
246 /*
247 * Old loader; all it gives us is the handle,
248 * so use the "known" entrypoint and assume
249 * the seal.
250 */
251 cfe_handle = (uint64_t)(long)prom_vec;
252 cfe_ept = (uint64_t)((int32_t)0x9fc00500);
253 cfe_eptseal = CFE_EPTSEAL;
254 } else {
255 /*
256 * Newer loaders bundle the handle/ept/eptseal
257 * Note: prom_vec is in the loader's useg
258 * which is still alive in the TLB.
259 */
260 cfe_handle = (uint64_t)((int32_t *)prom_vec)[0];
261 cfe_ept = (uint64_t)((int32_t *)prom_vec)[2];
262 cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3];
263 }
264 }
265 if (cfe_eptseal != CFE_EPTSEAL) {
266 /* too early for panic to do any good */
267 printk("CFE's entrypoint seal doesn't match. Spinning.");
268 while (1) ;
269 }
270 cfe_init(cfe_handle, cfe_ept);
271 /*
272 * Get the handle for (at least) prom_putchar, possibly for
273 * boot console
274 */
275 cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
276 if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, COMMAND_LINE_SIZE) < 0) {
277 if (argc >= 0) {
278 /* The loader should have set the command line */
279 /* too early for panic to do any good */
280 printk("LINUX_CMDLINE not defined in cfe.");
281 while (1) ;
282 }
283 }
284
285#ifdef CONFIG_BLK_DEV_INITRD
286 {
287 char *ptr;
288 /* Need to find out early whether we've got an initrd. So scan
289 the list looking now */
290 for (ptr = arcs_cmdline; *ptr; ptr++) {
291 while (*ptr == ' ') {
292 ptr++;
293 }
294 if (!strncmp(ptr, "initrd=", 7)) {
295 initrd_setup(ptr+7);
296 break;
297 } else {
298 while (*ptr && (*ptr != ' ')) {
299 ptr++;
300 }
301 }
302 }
303 }
304#endif /* CONFIG_BLK_DEV_INITRD */
305
306 /* Not sure this is needed, but it's the safe way. */
307 arcs_cmdline[COMMAND_LINE_SIZE-1] = 0;
308
309 prom_meminit();
310
311#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
312 register_smp_ops(&sb_smp_ops);
313#endif
314#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
315 register_smp_ops(&bcm1480_smp_ops);
316#endif
317}
318
319void __init prom_free_prom_memory(void)
320{
321 /* Not sure what I'm supposed to do here. Nothing, I think */
322}
323
324void prom_putchar(char c)
325{
326 int ret;
327
328 while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0)
329 ;
330}
diff --git a/arch/mips/sibyte/common/cfe_console.c b/arch/mips/sibyte/common/cfe_console.c
new file mode 100644
index 000000000..8af7b41f7
--- /dev/null
+++ b/arch/mips/sibyte/common/cfe_console.c
@@ -0,0 +1,81 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/init.h>
3#include <linux/errno.h>
4#include <linux/console.h>
5
6#include <asm/sibyte/board.h>
7
8#include <asm/fw/cfe/cfe_api.h>
9#include <asm/fw/cfe/cfe_error.h>
10
11extern int cfe_cons_handle;
12
13static void cfe_console_write(struct console *cons, const char *str,
14 unsigned int count)
15{
16 int i, last, written;
17
18 for (i=0, last=0; i<count; i++) {
19 if (!str[i])
20 /* XXXKW can/should this ever happen? */
21 return;
22 if (str[i] == '\n') {
23 do {
24 written = cfe_write(cfe_cons_handle, &str[last], i-last);
25 if (written < 0)
26 ;
27 last += written;
28 } while (last < i);
29 while (cfe_write(cfe_cons_handle, "\r", 1) <= 0)
30 ;
31 }
32 }
33 if (last != count) {
34 do {
35 written = cfe_write(cfe_cons_handle, &str[last], count-last);
36 if (written < 0)
37 ;
38 last += written;
39 } while (last < count);
40 }
41
42}
43
44static int cfe_console_setup(struct console *cons, char *str)
45{
46 char consdev[32];
47 /* XXXKW think about interaction with 'console=' cmdline arg */
48 /* If none of the console options are configured, the build will break. */
49 if (cfe_getenv("BOOT_CONSOLE", consdev, 32) >= 0) {
50#ifdef CONFIG_SERIAL_SB1250_DUART
51 if (!strcmp(consdev, "uart0")) {
52 setleds("u0cn");
53 } else if (!strcmp(consdev, "uart1")) {
54 setleds("u1cn");
55 } else
56#endif
57#ifdef CONFIG_VGA_CONSOLE
58 if (!strcmp(consdev, "pcconsole0")) {
59 setleds("pccn");
60 } else
61#endif
62 return -ENODEV;
63 }
64 return 0;
65}
66
67static struct console sb1250_cfe_cons = {
68 .name = "cfe",
69 .write = cfe_console_write,
70 .setup = cfe_console_setup,
71 .flags = CON_PRINTBUFFER,
72 .index = -1,
73};
74
75static int __init sb1250_cfe_console_init(void)
76{
77 register_console(&sb1250_cfe_cons);
78 return 0;
79}
80
81console_initcall(sb1250_cfe_console_init);
diff --git a/arch/mips/sibyte/common/dma.c b/arch/mips/sibyte/common/dma.c
new file mode 100644
index 000000000..eb47a94f3
--- /dev/null
+++ b/arch/mips/sibyte/common/dma.c
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * DMA support for Broadcom SiByte platforms.
4 *
5 * Copyright (c) 2018 Maciej W. Rozycki
6 */
7
8#include <linux/swiotlb.h>
9#include <asm/bootinfo.h>
10
11void __init plat_swiotlb_setup(void)
12{
13 swiotlb_init(1);
14}
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
new file mode 100644
index 000000000..f80d7a710
--- /dev/null
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -0,0 +1,595 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 *
4 * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
5 * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
6 * Copyright (C) 2007 MIPS Technologies, Inc.
7 * written by Ralf Baechle <ralf@linux-mips.org>
8 */
9
10#undef DEBUG
11
12#include <linux/device.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/sched.h>
19#include <linux/vmalloc.h>
20#include <linux/fs.h>
21#include <linux/errno.h>
22#include <linux/wait.h>
23#include <asm/io.h>
24#include <asm/sibyte/sb1250.h>
25
26#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
27#include <asm/sibyte/bcm1480_regs.h>
28#include <asm/sibyte/bcm1480_scd.h>
29#include <asm/sibyte/bcm1480_int.h>
30#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
31#include <asm/sibyte/sb1250_regs.h>
32#include <asm/sibyte/sb1250_scd.h>
33#include <asm/sibyte/sb1250_int.h>
34#else
35#error invalid SiByte UART configuration
36#endif
37
38#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
39#undef K_INT_TRACE_FREEZE
40#define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE
41#undef K_INT_PERF_CNT
42#define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT
43#endif
44
45#include <linux/uaccess.h>
46
47#define SBPROF_TB_MAJOR 240
48
49typedef u64 tb_sample_t[6*256];
50
51enum open_status {
52 SB_CLOSED,
53 SB_OPENING,
54 SB_OPEN
55};
56
57struct sbprof_tb {
58 wait_queue_head_t tb_sync;
59 wait_queue_head_t tb_read;
60 struct mutex lock;
61 enum open_status open;
62 tb_sample_t *sbprof_tbbuf;
63 int next_tb_sample;
64
65 volatile int tb_enable;
66 volatile int tb_armed;
67
68};
69
70static struct sbprof_tb sbp;
71
72#define MAX_SAMPLE_BYTES (24*1024*1024)
73#define MAX_TBSAMPLE_BYTES (12*1024*1024)
74
75#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
76#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
77#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
78
79/* ioctls */
80#define SBPROF_ZBSTART _IOW('s', 0, int)
81#define SBPROF_ZBSTOP _IOW('s', 1, int)
82#define SBPROF_ZBWAITFULL _IOW('s', 2, int)
83
84/*
85 * Routines for using 40-bit SCD cycle counter
86 *
87 * Client responsible for either handling interrupts or making sure
88 * the cycles counter never saturates, e.g., by doing
89 * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
90 */
91
92/*
93 * Configures SCD counter 0 to count ZCLKs starting from val;
94 * Configures SCD counters1,2,3 to count nothing.
95 * Must not be called while gathering ZBbus profiles.
96 */
97
98#define zclk_timer_init(val) \
99 __asm__ __volatile__ (".set push;" \
100 ".set mips64;" \
101 "la $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
102 "sd %0, 0x10($8);" /* write val to counter0 */ \
103 "sd %1, 0($8);" /* config counter0 for zclks*/ \
104 ".set pop" \
105 : /* no outputs */ \
106 /* enable, counter0 */ \
107 : /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
108 : /* modifies */ "$8" )
109
110
111/* Reads SCD counter 0 and puts result in value
112 unsigned long long val; */
113#define zclk_get(val) \
114 __asm__ __volatile__ (".set push;" \
115 ".set mips64;" \
116 "la $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
117 "ld %0, 0x10($8);" /* write val to counter0 */ \
118 ".set pop" \
119 : /* outputs */ "=r"(val) \
120 : /* inputs */ \
121 : /* modifies */ "$8" )
122
123#define DEVNAME "sb_tbprof"
124
125#define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES)
126
127/*
128 * Support for ZBbus sampling using the trace buffer
129 *
130 * We use the SCD performance counter interrupt, caused by a Zclk counter
131 * overflow, to trigger the start of tracing.
132 *
133 * We set the trace buffer to sample everything and freeze on
134 * overflow.
135 *
136 * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
137 *
138 */
139
140static u64 tb_period;
141
142static void arm_tb(void)
143{
144 u64 scdperfcnt;
145 u64 next = (1ULL << 40) - tb_period;
146 u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
147
148 /*
149 * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
150 * trigger start of trace. XXX vary sampling period
151 */
152 __raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
153 scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
154
155 /*
156 * Unfortunately, in Pass 2 we must clear all counters to knock down
157 * a previous interrupt request. This means that bus profiling
158 * requires ALL of the SCD perf counters.
159 */
160#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
161 __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
162 /* keep counters 0,2,3,4,5,6,7 as is */
163 V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */
164 IOADDR(A_BCM1480_SCD_PERF_CNT_CFG0));
165 __raw_writeq(
166 M_SPC_CFG_ENABLE | /* enable counting */
167 M_SPC_CFG_CLEAR | /* clear all counters */
168 V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */
169 IOADDR(A_BCM1480_SCD_PERF_CNT_CFG1));
170#else
171 __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
172 /* keep counters 0,2,3 as is */
173 M_SPC_CFG_ENABLE | /* enable counting */
174 M_SPC_CFG_CLEAR | /* clear all counters */
175 V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */
176 IOADDR(A_SCD_PERF_CNT_CFG));
177#endif
178 __raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
179 /* Reset the trace buffer */
180 __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
181#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
182 /* XXXKW may want to expose control to the data-collector */
183 tb_options |= M_SCD_TRACE_CFG_FORCECNT;
184#endif
185 __raw_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG));
186 sbp.tb_armed = 1;
187}
188
189static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
190{
191 int i;
192
193 pr_debug(DEVNAME ": tb_intr\n");
194
195 if (sbp.next_tb_sample < MAX_TB_SAMPLES) {
196 /* XXX should use XKPHYS to make writes bypass L2 */
197 u64 *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
198 /* Read out trace */
199 __raw_writeq(M_SCD_TRACE_CFG_START_READ,
200 IOADDR(A_SCD_TRACE_CFG));
201 __asm__ __volatile__ ("sync" : : : "memory");
202 /* Loop runs backwards because bundles are read out in reverse order */
203 for (i = 256 * 6; i > 0; i -= 6) {
204 /* Subscripts decrease to put bundle in the order */
205 /* t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */
206 p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
207 /* read t2 hi */
208 p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
209 /* read t2 lo */
210 p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
211 /* read t1 hi */
212 p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
213 /* read t1 lo */
214 p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
215 /* read t0 hi */
216 p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
217 /* read t0 lo */
218 }
219 if (!sbp.tb_enable) {
220 pr_debug(DEVNAME ": tb_intr shutdown\n");
221 __raw_writeq(M_SCD_TRACE_CFG_RESET,
222 IOADDR(A_SCD_TRACE_CFG));
223 sbp.tb_armed = 0;
224 wake_up_interruptible(&sbp.tb_sync);
225 } else {
226 /* knock down current interrupt and get another one later */
227 arm_tb();
228 }
229 } else {
230 /* No more trace buffer samples */
231 pr_debug(DEVNAME ": tb_intr full\n");
232 __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
233 sbp.tb_armed = 0;
234 if (!sbp.tb_enable)
235 wake_up_interruptible(&sbp.tb_sync);
236 wake_up_interruptible(&sbp.tb_read);
237 }
238 return IRQ_HANDLED;
239}
240
241static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
242{
243 printk(DEVNAME ": unexpected pc_intr");
244 return IRQ_NONE;
245}
246
247/*
248 * Requires: Already called zclk_timer_init with a value that won't
249 * saturate 40 bits. No subsequent use of SCD performance counters
250 * or trace buffer.
251 */
252
253static int sbprof_zbprof_start(struct file *filp)
254{
255 u64 scdperfcnt;
256 int err;
257
258 if (xchg(&sbp.tb_enable, 1))
259 return -EBUSY;
260
261 pr_debug(DEVNAME ": starting\n");
262
263 sbp.next_tb_sample = 0;
264 filp->f_pos = 0;
265
266 err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0,
267 DEVNAME " trace freeze", &sbp);
268 if (err)
269 return -EBUSY;
270
271 /* Make sure there isn't a perf-cnt interrupt waiting */
272 scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
273 /* Disable and clear counters, override SRC_1 */
274 __raw_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) |
275 M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
276 IOADDR(A_SCD_PERF_CNT_CFG));
277
278 /*
279 * We grab this interrupt to prevent others from trying to use
280 * it, even though we don't want to service the interrupts
281 * (they only feed into the trace-on-interrupt mechanism)
282 */
283 if (request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0, DEVNAME " scd perfcnt", &sbp)) {
284 free_irq(K_INT_TRACE_FREEZE, &sbp);
285 return -EBUSY;
286 }
287
288 /*
289 * I need the core to mask these, but the interrupt mapper to
290 * pass them through. I am exploiting my knowledge that
291 * cp0_status masks out IP[5]. krw
292 */
293#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
294 __raw_writeq(K_BCM1480_INT_MAP_I3,
295 IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) +
296 ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3)));
297#else
298 __raw_writeq(K_INT_MAP_I3,
299 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
300 (K_INT_PERF_CNT << 3)));
301#endif
302
303 /* Initialize address traps */
304 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0));
305 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_1));
306 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_2));
307 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_3));
308
309 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0));
310 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1));
311 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2));
312 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3));
313
314 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0));
315 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1));
316 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2));
317 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
318
319 /* Initialize Trace Event 0-7 */
320 /* when interrupt */
321 __raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
322 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
323 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
324 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3));
325 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4));
326 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5));
327 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6));
328 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
329
330 /* Initialize Trace Sequence 0-7 */
331 /* Start on event 0 (interrupt) */
332 __raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
333 IOADDR(A_SCD_TRACE_SEQUENCE_0));
334 /* dsamp when d used | asamp when a used */
335 __raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
336 K_SCD_TRSEQ_TRIGGER_ALL,
337 IOADDR(A_SCD_TRACE_SEQUENCE_1));
338 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2));
339 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3));
340 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4));
341 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5));
342 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6));
343 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7));
344
345 /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */
346#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
347 __raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f),
348 IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L)));
349#else
350 __raw_writeq(1ULL << K_INT_PERF_CNT,
351 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)));
352#endif
353 arm_tb();
354
355 pr_debug(DEVNAME ": done starting\n");
356
357 return 0;
358}
359
360static int sbprof_zbprof_stop(void)
361{
362 int err = 0;
363
364 pr_debug(DEVNAME ": stopping\n");
365
366 if (sbp.tb_enable) {
367 /*
368 * XXXKW there is a window here where the intr handler may run,
369 * see the disable, and do the wake_up before this sleep
370 * happens.
371 */
372 pr_debug(DEVNAME ": wait for disarm\n");
373 err = wait_event_interruptible(sbp.tb_sync, !sbp.tb_armed);
374 pr_debug(DEVNAME ": disarm complete, stat %d\n", err);
375
376 if (err)
377 return err;
378
379 sbp.tb_enable = 0;
380 free_irq(K_INT_TRACE_FREEZE, &sbp);
381 free_irq(K_INT_PERF_CNT, &sbp);
382 }
383
384 pr_debug(DEVNAME ": done stopping\n");
385
386 return err;
387}
388
389static int sbprof_tb_open(struct inode *inode, struct file *filp)
390{
391 int minor;
392
393 minor = iminor(inode);
394 if (minor != 0)
395 return -ENODEV;
396
397 if (xchg(&sbp.open, SB_OPENING) != SB_CLOSED)
398 return -EBUSY;
399
400 memset(&sbp, 0, sizeof(struct sbprof_tb));
401 sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES);
402 if (!sbp.sbprof_tbbuf) {
403 sbp.open = SB_CLOSED;
404 wmb();
405 return -ENOMEM;
406 }
407
408 init_waitqueue_head(&sbp.tb_sync);
409 init_waitqueue_head(&sbp.tb_read);
410 mutex_init(&sbp.lock);
411
412 sbp.open = SB_OPEN;
413 wmb();
414
415 return 0;
416}
417
418static int sbprof_tb_release(struct inode *inode, struct file *filp)
419{
420 int minor;
421
422 minor = iminor(inode);
423 if (minor != 0 || sbp.open != SB_CLOSED)
424 return -ENODEV;
425
426 mutex_lock(&sbp.lock);
427
428 if (sbp.tb_armed || sbp.tb_enable)
429 sbprof_zbprof_stop();
430
431 vfree(sbp.sbprof_tbbuf);
432 sbp.open = SB_CLOSED;
433 wmb();
434
435 mutex_unlock(&sbp.lock);
436
437 return 0;
438}
439
440static ssize_t sbprof_tb_read(struct file *filp, char *buf,
441 size_t size, loff_t *offp)
442{
443 int cur_sample, sample_off, cur_count, sample_left;
444 char *src;
445 int count = 0;
446 char *dest = buf;
447 long cur_off = *offp;
448
449 if (!access_ok(buf, size))
450 return -EFAULT;
451
452 mutex_lock(&sbp.lock);
453
454 count = 0;
455 cur_sample = cur_off / TB_SAMPLE_SIZE;
456 sample_off = cur_off % TB_SAMPLE_SIZE;
457 sample_left = TB_SAMPLE_SIZE - sample_off;
458
459 while (size && (cur_sample < sbp.next_tb_sample)) {
460 int err;
461
462 cur_count = size < sample_left ? size : sample_left;
463 src = (char *)(((long)sbp.sbprof_tbbuf[cur_sample])+sample_off);
464 err = __copy_to_user(dest, src, cur_count);
465 if (err) {
466 *offp = cur_off + cur_count - err;
467 mutex_unlock(&sbp.lock);
468 return err;
469 }
470 pr_debug(DEVNAME ": read from sample %d, %d bytes\n",
471 cur_sample, cur_count);
472 size -= cur_count;
473 sample_left -= cur_count;
474 if (!sample_left) {
475 cur_sample++;
476 sample_off = 0;
477 sample_left = TB_SAMPLE_SIZE;
478 } else {
479 sample_off += cur_count;
480 }
481 cur_off += cur_count;
482 dest += cur_count;
483 count += cur_count;
484 }
485 *offp = cur_off;
486 mutex_unlock(&sbp.lock);
487
488 return count;
489}
490
491static long sbprof_tb_ioctl(struct file *filp,
492 unsigned int command,
493 unsigned long arg)
494{
495 int err = 0;
496
497 switch (command) {
498 case SBPROF_ZBSTART:
499 mutex_lock(&sbp.lock);
500 err = sbprof_zbprof_start(filp);
501 mutex_unlock(&sbp.lock);
502 break;
503
504 case SBPROF_ZBSTOP:
505 mutex_lock(&sbp.lock);
506 err = sbprof_zbprof_stop();
507 mutex_unlock(&sbp.lock);
508 break;
509
510 case SBPROF_ZBWAITFULL: {
511 err = wait_event_interruptible(sbp.tb_read, TB_FULL);
512 if (err)
513 break;
514
515 err = put_user(TB_FULL, (int *) arg);
516 break;
517 }
518
519 default:
520 err = -EINVAL;
521 break;
522 }
523
524 return err;
525}
526
527static const struct file_operations sbprof_tb_fops = {
528 .owner = THIS_MODULE,
529 .open = sbprof_tb_open,
530 .release = sbprof_tb_release,
531 .read = sbprof_tb_read,
532 .unlocked_ioctl = sbprof_tb_ioctl,
533 .compat_ioctl = sbprof_tb_ioctl,
534 .mmap = NULL,
535 .llseek = default_llseek,
536};
537
538static struct class *tb_class;
539static struct device *tb_dev;
540
541static int __init sbprof_tb_init(void)
542{
543 struct device *dev;
544 struct class *tbc;
545 int err;
546
547 if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
548 printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
549 SBPROF_TB_MAJOR);
550 return -EIO;
551 }
552
553 tbc = class_create(THIS_MODULE, "sb_tracebuffer");
554 if (IS_ERR(tbc)) {
555 err = PTR_ERR(tbc);
556 goto out_chrdev;
557 }
558
559 tb_class = tbc;
560
561 dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), NULL, "tb");
562 if (IS_ERR(dev)) {
563 err = PTR_ERR(dev);
564 goto out_class;
565 }
566 tb_dev = dev;
567
568 sbp.open = SB_CLOSED;
569 wmb();
570 tb_period = zbbus_mhz * 10000LL;
571 pr_info(DEVNAME ": initialized - tb_period = %lld\n",
572 (long long) tb_period);
573 return 0;
574
575out_class:
576 class_destroy(tb_class);
577out_chrdev:
578 unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
579
580 return err;
581}
582
583static void __exit sbprof_tb_cleanup(void)
584{
585 device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0));
586 unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
587 class_destroy(tb_class);
588}
589
590module_init(sbprof_tb_init);
591module_exit(sbprof_tb_cleanup);
592
593MODULE_ALIAS_CHARDEV_MAJOR(SBPROF_TB_MAJOR);
594MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
595MODULE_LICENSE("GPL");
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
new file mode 100644
index 000000000..cf1327d3f
--- /dev/null
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -0,0 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0-only
2obj-y := setup.o irq.o time.o
3
4obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
new file mode 100644
index 000000000..86f49c48f
--- /dev/null
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -0,0 +1,324 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
4 */
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/linkage.h>
8#include <linux/interrupt.h>
9#include <linux/spinlock.h>
10#include <linux/smp.h>
11#include <linux/mm.h>
12#include <linux/kernel_stat.h>
13
14#include <asm/errno.h>
15#include <asm/signal.h>
16#include <asm/time.h>
17#include <asm/io.h>
18
19#include <asm/sibyte/sb1250_regs.h>
20#include <asm/sibyte/sb1250_int.h>
21#include <asm/sibyte/sb1250_uart.h>
22#include <asm/sibyte/sb1250_scd.h>
23#include <asm/sibyte/sb1250.h>
24
25/*
26 * These are the routines that handle all the low level interrupt stuff.
27 * Actions handled here are: initialization of the interrupt map, requesting of
28 * interrupt lines by handlers, dispatching if interrupts to handlers, probing
29 * for interrupt lines
30 */
31
32#ifdef CONFIG_SIBYTE_HAS_LDT
33extern unsigned long ldt_eoi_space;
34#endif
35
36/* Store the CPU id (not the logical number) */
37int sb1250_irq_owner[SB1250_NR_IRQS];
38
39static DEFINE_RAW_SPINLOCK(sb1250_imr_lock);
40
41void sb1250_mask_irq(int cpu, int irq)
42{
43 unsigned long flags;
44 u64 cur_ints;
45
46 raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
47 cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
48 R_IMR_INTERRUPT_MASK));
49 cur_ints |= (((u64) 1) << irq);
50 ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
51 R_IMR_INTERRUPT_MASK));
52 raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
53}
54
55void sb1250_unmask_irq(int cpu, int irq)
56{
57 unsigned long flags;
58 u64 cur_ints;
59
60 raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
61 cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
62 R_IMR_INTERRUPT_MASK));
63 cur_ints &= ~(((u64) 1) << irq);
64 ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
65 R_IMR_INTERRUPT_MASK));
66 raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
67}
68
69#ifdef CONFIG_SMP
70static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
71 bool force)
72{
73 int i = 0, old_cpu, cpu, int_on;
74 unsigned int irq = d->irq;
75 u64 cur_ints;
76 unsigned long flags;
77
78 i = cpumask_first_and(mask, cpu_online_mask);
79
80 /* Convert logical CPU to physical CPU */
81 cpu = cpu_logical_map(i);
82
83 /* Protect against other affinity changers and IMR manipulation */
84 raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
85
86 /* Swizzle each CPU's IMR (but leave the IP selection alone) */
87 old_cpu = sb1250_irq_owner[irq];
88 cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(old_cpu) +
89 R_IMR_INTERRUPT_MASK));
90 int_on = !(cur_ints & (((u64) 1) << irq));
91 if (int_on) {
92 /* If it was on, mask it */
93 cur_ints |= (((u64) 1) << irq);
94 ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(old_cpu) +
95 R_IMR_INTERRUPT_MASK));
96 }
97 sb1250_irq_owner[irq] = cpu;
98 if (int_on) {
99 /* unmask for the new CPU */
100 cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
101 R_IMR_INTERRUPT_MASK));
102 cur_ints &= ~(((u64) 1) << irq);
103 ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
104 R_IMR_INTERRUPT_MASK));
105 }
106 raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
107
108 return 0;
109}
110#endif
111
112static void disable_sb1250_irq(struct irq_data *d)
113{
114 unsigned int irq = d->irq;
115
116 sb1250_mask_irq(sb1250_irq_owner[irq], irq);
117}
118
119static void enable_sb1250_irq(struct irq_data *d)
120{
121 unsigned int irq = d->irq;
122
123 sb1250_unmask_irq(sb1250_irq_owner[irq], irq);
124}
125
126
127static void ack_sb1250_irq(struct irq_data *d)
128{
129 unsigned int irq = d->irq;
130#ifdef CONFIG_SIBYTE_HAS_LDT
131 u64 pending;
132
133 /*
134 * If the interrupt was an HT interrupt, now is the time to
135 * clear it. NOTE: we assume the HT bridge was set up to
136 * deliver the interrupts to all CPUs (which makes affinity
137 * changing easier for us)
138 */
139 pending = __raw_readq(IOADDR(A_IMR_REGISTER(sb1250_irq_owner[irq],
140 R_IMR_LDT_INTERRUPT)));
141 pending &= ((u64)1 << (irq));
142 if (pending) {
143 int i;
144 for (i=0; i<NR_CPUS; i++) {
145 int cpu;
146#ifdef CONFIG_SMP
147 cpu = cpu_logical_map(i);
148#else
149 cpu = i;
150#endif
151 /*
152 * Clear for all CPUs so an affinity switch
153 * doesn't find an old status
154 */
155 __raw_writeq(pending,
156 IOADDR(A_IMR_REGISTER(cpu,
157 R_IMR_LDT_INTERRUPT_CLR)));
158 }
159
160 /*
161 * Generate EOI. For Pass 1 parts, EOI is a nop. For
162 * Pass 2, the LDT world may be edge-triggered, but
163 * this EOI shouldn't hurt. If they are
164 * level-sensitive, the EOI is required.
165 */
166 *(uint32_t *)(ldt_eoi_space+(irq<<16)+(7<<2)) = 0;
167 }
168#endif
169 sb1250_mask_irq(sb1250_irq_owner[irq], irq);
170}
171
172static struct irq_chip sb1250_irq_type = {
173 .name = "SB1250-IMR",
174 .irq_mask_ack = ack_sb1250_irq,
175 .irq_unmask = enable_sb1250_irq,
176 .irq_mask = disable_sb1250_irq,
177#ifdef CONFIG_SMP
178 .irq_set_affinity = sb1250_set_affinity
179#endif
180};
181
182void __init init_sb1250_irqs(void)
183{
184 int i;
185
186 for (i = 0; i < SB1250_NR_IRQS; i++) {
187 irq_set_chip_and_handler(i, &sb1250_irq_type,
188 handle_level_irq);
189 sb1250_irq_owner[i] = 0;
190 }
191}
192
193
194/*
195 * arch_init_irq is called early in the boot sequence from init/main.c via
196 * init_IRQ. It is responsible for setting up the interrupt mapper and
197 * installing the handler that will be responsible for dispatching interrupts
198 * to the "right" place.
199 */
200/*
201 * For now, map all interrupts to IP[2]. We could save
202 * some cycles by parceling out system interrupts to different
203 * IP lines, but keep it simple for bringup. We'll also direct
204 * all interrupts to a single CPU; we should probably route
205 * PCI and LDT to one cpu and everything else to the other
206 * to balance the load a bit.
207 *
208 * On the second cpu, everything is set to IP5, which is
209 * ignored, EXCEPT the mailbox interrupt. That one is
210 * set to IP[2] so it is handled. This is needed so we
211 * can do cross-cpu function calls, as required by SMP
212 */
213
214#define IMR_IP2_VAL K_INT_MAP_I0
215#define IMR_IP3_VAL K_INT_MAP_I1
216#define IMR_IP4_VAL K_INT_MAP_I2
217#define IMR_IP5_VAL K_INT_MAP_I3
218#define IMR_IP6_VAL K_INT_MAP_I4
219
220void __init arch_init_irq(void)
221{
222
223 unsigned int i;
224 u64 tmp;
225 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
226 STATUSF_IP1 | STATUSF_IP0;
227
228 /* Default everything to IP2 */
229 for (i = 0; i < SB1250_NR_IRQS; i++) { /* was I0 */
230 __raw_writeq(IMR_IP2_VAL,
231 IOADDR(A_IMR_REGISTER(0,
232 R_IMR_INTERRUPT_MAP_BASE) +
233 (i << 3)));
234 __raw_writeq(IMR_IP2_VAL,
235 IOADDR(A_IMR_REGISTER(1,
236 R_IMR_INTERRUPT_MAP_BASE) +
237 (i << 3)));
238 }
239
240 init_sb1250_irqs();
241
242 /*
243 * Map the high 16 bits of the mailbox registers to IP[3], for
244 * inter-cpu messages
245 */
246 /* Was I1 */
247 __raw_writeq(IMR_IP3_VAL,
248 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
249 (K_INT_MBOX_0 << 3)));
250 __raw_writeq(IMR_IP3_VAL,
251 IOADDR(A_IMR_REGISTER(1, R_IMR_INTERRUPT_MAP_BASE) +
252 (K_INT_MBOX_0 << 3)));
253
254 /* Clear the mailboxes. The firmware may leave them dirty */
255 __raw_writeq(0xffffffffffffffffULL,
256 IOADDR(A_IMR_REGISTER(0, R_IMR_MAILBOX_CLR_CPU)));
257 __raw_writeq(0xffffffffffffffffULL,
258 IOADDR(A_IMR_REGISTER(1, R_IMR_MAILBOX_CLR_CPU)));
259
260 /* Mask everything except the mailbox registers for both cpus */
261 tmp = ~((u64) 0) ^ (((u64) 1) << K_INT_MBOX_0);
262 __raw_writeq(tmp, IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK)));
263 __raw_writeq(tmp, IOADDR(A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK)));
264
265 /*
266 * Note that the timer interrupts are also mapped, but this is
267 * done in sb1250_time_init(). Also, the profiling driver
268 * does its own management of IP7.
269 */
270
271 /* Enable necessary IPs, disable the rest */
272 change_c0_status(ST0_IM, imask);
273}
274
275extern void sb1250_mailbox_interrupt(void);
276
277static inline void dispatch_ip2(void)
278{
279 unsigned int cpu = smp_processor_id();
280 unsigned long long mask;
281
282 /*
283 * Default...we've hit an IP[2] interrupt, which means we've got to
284 * check the 1250 interrupt registers to figure out what to do. Need
285 * to detect which CPU we're on, now that smp_affinity is supported.
286 */
287 mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
288 R_IMR_INTERRUPT_STATUS_BASE)));
289 if (mask)
290 do_IRQ(fls64(mask) - 1);
291}
292
293asmlinkage void plat_irq_dispatch(void)
294{
295 unsigned int cpu = smp_processor_id();
296 unsigned int pending;
297
298 /*
299 * What a pain. We have to be really careful saving the upper 32 bits
300 * of any * register across function calls if we don't want them
301 * trashed--since were running in -o32, the calling routing never saves
302 * the full 64 bits of a register across a function call. Being the
303 * interrupt handler, we're guaranteed that interrupts are disabled
304 * during this code so we don't have to worry about random interrupts
305 * blasting the high 32 bits.
306 */
307
308 pending = read_c0_cause() & read_c0_status() & ST0_IM;
309
310 if (pending & CAUSEF_IP7) /* CPU performance counter interrupt */
311 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
312 else if (pending & CAUSEF_IP4)
313 do_IRQ(K_INT_TIMER_0 + cpu); /* sb1250_timer_interrupt() */
314
315#ifdef CONFIG_SMP
316 else if (pending & CAUSEF_IP3)
317 sb1250_mailbox_interrupt();
318#endif
319
320 else if (pending & CAUSEF_IP2)
321 dispatch_ip2();
322 else
323 spurious_interrupt();
324}
diff --git a/arch/mips/sibyte/sb1250/setup.c b/arch/mips/sibyte/sb1250/setup.c
new file mode 100644
index 000000000..644b19038
--- /dev/null
+++ b/arch/mips/sibyte/sb1250/setup.c
@@ -0,0 +1,234 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
4 */
5#include <linux/export.h>
6#include <linux/init.h>
7#include <linux/kernel.h>
8#include <linux/reboot.h>
9#include <linux/string.h>
10
11#include <asm/bootinfo.h>
12#include <asm/cpu.h>
13#include <asm/mipsregs.h>
14#include <asm/io.h>
15#include <asm/sibyte/sb1250.h>
16#include <asm/sibyte/sb1250_regs.h>
17#include <asm/sibyte/sb1250_scd.h>
18
19unsigned int sb1_pass;
20unsigned int soc_pass;
21unsigned int soc_type;
22EXPORT_SYMBOL(soc_type);
23unsigned int periph_rev;
24EXPORT_SYMBOL_GPL(periph_rev);
25unsigned int zbbus_mhz;
26EXPORT_SYMBOL(zbbus_mhz);
27
28static char *soc_str;
29static char *pass_str;
30static unsigned int war_pass; /* XXXKW don't overload PASS defines? */
31
32static int __init setup_bcm1250(void)
33{
34 int ret = 0;
35
36 switch (soc_pass) {
37 case K_SYS_REVISION_BCM1250_PASS1:
38 periph_rev = 1;
39 pass_str = "Pass 1";
40 break;
41 case K_SYS_REVISION_BCM1250_A10:
42 periph_rev = 2;
43 pass_str = "A8/A10";
44 /* XXXKW different war_pass? */
45 war_pass = K_SYS_REVISION_BCM1250_PASS2;
46 break;
47 case K_SYS_REVISION_BCM1250_PASS2_2:
48 periph_rev = 2;
49 pass_str = "B1";
50 break;
51 case K_SYS_REVISION_BCM1250_B2:
52 periph_rev = 2;
53 pass_str = "B2";
54 war_pass = K_SYS_REVISION_BCM1250_PASS2_2;
55 break;
56 case K_SYS_REVISION_BCM1250_PASS3:
57 periph_rev = 3;
58 pass_str = "C0";
59 break;
60 case K_SYS_REVISION_BCM1250_C1:
61 periph_rev = 3;
62 pass_str = "C1";
63 break;
64 default:
65 if (soc_pass < K_SYS_REVISION_BCM1250_PASS2_2) {
66 periph_rev = 2;
67 pass_str = "A0-A6";
68 war_pass = K_SYS_REVISION_BCM1250_PASS2;
69 } else {
70 printk("Unknown BCM1250 rev %x\n", soc_pass);
71 ret = 1;
72 }
73 break;
74 }
75
76 return ret;
77}
78
79int sb1250_m3_workaround_needed(void)
80{
81 switch (soc_type) {
82 case K_SYS_SOC_TYPE_BCM1250:
83 case K_SYS_SOC_TYPE_BCM1250_ALT:
84 case K_SYS_SOC_TYPE_BCM1250_ALT2:
85 case K_SYS_SOC_TYPE_BCM1125:
86 case K_SYS_SOC_TYPE_BCM1125H:
87 return soc_pass < K_SYS_REVISION_BCM1250_C0;
88
89 default:
90 return 0;
91 }
92}
93
94static int __init setup_bcm112x(void)
95{
96 int ret = 0;
97
98 switch (soc_pass) {
99 case 0:
100 /* Early build didn't have revid set */
101 periph_rev = 3;
102 pass_str = "A1";
103 war_pass = K_SYS_REVISION_BCM112x_A1;
104 break;
105 case K_SYS_REVISION_BCM112x_A1:
106 periph_rev = 3;
107 pass_str = "A1";
108 break;
109 case K_SYS_REVISION_BCM112x_A2:
110 periph_rev = 3;
111 pass_str = "A2";
112 break;
113 case K_SYS_REVISION_BCM112x_A3:
114 periph_rev = 3;
115 pass_str = "A3";
116 break;
117 case K_SYS_REVISION_BCM112x_A4:
118 periph_rev = 3;
119 pass_str = "A4";
120 break;
121 case K_SYS_REVISION_BCM112x_B0:
122 periph_rev = 3;
123 pass_str = "B0";
124 break;
125 default:
126 printk("Unknown %s rev %x\n", soc_str, soc_pass);
127 ret = 1;
128 }
129
130 return ret;
131}
132
133/* Setup code likely to be common to all SiByte platforms */
134
135static int __init sys_rev_decode(void)
136{
137 int ret = 0;
138
139 war_pass = soc_pass;
140 switch (soc_type) {
141 case K_SYS_SOC_TYPE_BCM1250:
142 case K_SYS_SOC_TYPE_BCM1250_ALT:
143 case K_SYS_SOC_TYPE_BCM1250_ALT2:
144 soc_str = "BCM1250";
145 ret = setup_bcm1250();
146 break;
147 case K_SYS_SOC_TYPE_BCM1120:
148 soc_str = "BCM1120";
149 ret = setup_bcm112x();
150 break;
151 case K_SYS_SOC_TYPE_BCM1125:
152 soc_str = "BCM1125";
153 ret = setup_bcm112x();
154 break;
155 case K_SYS_SOC_TYPE_BCM1125H:
156 soc_str = "BCM1125H";
157 ret = setup_bcm112x();
158 break;
159 default:
160 printk("Unknown SOC type %x\n", soc_type);
161 ret = 1;
162 break;
163 }
164
165 return ret;
166}
167
168void __init sb1250_setup(void)
169{
170 uint64_t sys_rev;
171 int plldiv;
172 int bad_config = 0;
173
174 sb1_pass = read_c0_prid() & PRID_REV_MASK;
175 sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
176 soc_type = SYS_SOC_TYPE(sys_rev);
177 soc_pass = G_SYS_REVISION(sys_rev);
178
179 if (sys_rev_decode()) {
180 printk("Restart after failure to identify SiByte chip\n");
181 machine_restart(NULL);
182 }
183
184 plldiv = G_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
185 zbbus_mhz = ((plldiv >> 1) * 50) + ((plldiv & 1) * 25);
186
187 printk("Broadcom SiByte %s %s @ %d MHz (SB1 rev %d)\n",
188 soc_str, pass_str, zbbus_mhz * 2, sb1_pass);
189 printk("Board type: %s\n", get_system_type());
190
191 switch (war_pass) {
192 case K_SYS_REVISION_BCM1250_PASS1:
193 printk("@@@@ This is a BCM1250 A0-A2 (Pass 1) board, "
194 "and the kernel doesn't have the proper "
195 "workarounds compiled in. @@@@\n");
196 bad_config = 1;
197 break;
198 case K_SYS_REVISION_BCM1250_PASS2:
199 /* Pass 2 - easiest as default for now - so many numbers */
200#if !defined(CONFIG_SB1_PASS_2_WORKAROUNDS) || \
201 !defined(CONFIG_SB1_PASS_2_1_WORKAROUNDS)
202 printk("@@@@ This is a BCM1250 A3-A10 board, and the "
203 "kernel doesn't have the proper workarounds "
204 "compiled in. @@@@\n");
205 bad_config = 1;
206#endif
207#ifdef CONFIG_CPU_HAS_PREFETCH
208 printk("@@@@ Prefetches may be enabled in this kernel, "
209 "but are buggy on this board. @@@@\n");
210 bad_config = 1;
211#endif
212 break;
213 case K_SYS_REVISION_BCM1250_PASS2_2:
214#ifndef CONFIG_SB1_PASS_2_WORKAROUNDS
215 printk("@@@@ This is a BCM1250 B1/B2. board, and the "
216 "kernel doesn't have the proper workarounds "
217 "compiled in. @@@@\n");
218 bad_config = 1;
219#endif
220#if defined(CONFIG_SB1_PASS_2_1_WORKAROUNDS) || \
221 !defined(CONFIG_CPU_HAS_PREFETCH)
222 printk("@@@@ This is a BCM1250 B1/B2, but the kernel is "
223 "conservatively configured for an 'A' stepping. "
224 "@@@@\n");
225#endif
226 break;
227 default:
228 break;
229 }
230 if (bad_config) {
231 printk("Invalid configuration for this chip.\n");
232 machine_restart(NULL);
233 }
234}
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
new file mode 100644
index 000000000..7a794234e
--- /dev/null
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
4 */
5
6#include <linux/init.h>
7#include <linux/delay.h>
8#include <linux/interrupt.h>
9#include <linux/smp.h>
10#include <linux/kernel_stat.h>
11#include <linux/sched/task_stack.h>
12
13#include <asm/mmu_context.h>
14#include <asm/io.h>
15#include <asm/fw/cfe/cfe_api.h>
16#include <asm/sibyte/sb1250.h>
17#include <asm/sibyte/sb1250_regs.h>
18#include <asm/sibyte/sb1250_int.h>
19
20static void *mailbox_set_regs[] = {
21 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU),
22 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU)
23};
24
25static void *mailbox_clear_regs[] = {
26 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU),
27 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU)
28};
29
30static void *mailbox_regs[] = {
31 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU),
32 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU)
33};
34
35/*
36 * SMP init and finish on secondary CPUs
37 */
38void sb1250_smp_init(void)
39{
40 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
41 STATUSF_IP1 | STATUSF_IP0;
42
43 /* Set interrupt mask, but don't enable */
44 change_c0_status(ST0_IM, imask);
45}
46
47/*
48 * These are routines for dealing with the sb1250 smp capabilities
49 * independent of board/firmware
50 */
51
52/*
53 * Simple enough; everything is set up, so just poke the appropriate mailbox
54 * register, and we should be set
55 */
56static void sb1250_send_ipi_single(int cpu, unsigned int action)
57{
58 __raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
59}
60
61static inline void sb1250_send_ipi_mask(const struct cpumask *mask,
62 unsigned int action)
63{
64 unsigned int i;
65
66 for_each_cpu(i, mask)
67 sb1250_send_ipi_single(i, action);
68}
69
70/*
71 * Code to run on secondary just after probing the CPU
72 */
73static void sb1250_init_secondary(void)
74{
75 extern void sb1250_smp_init(void);
76
77 sb1250_smp_init();
78}
79
80/*
81 * Do any tidying up before marking online and running the idle
82 * loop
83 */
84static void sb1250_smp_finish(void)
85{
86 extern void sb1250_clockevent_init(void);
87
88 sb1250_clockevent_init();
89 local_irq_enable();
90}
91
92/*
93 * Setup the PC, SP, and GP of a secondary processor and start it
94 * running!
95 */
96static int sb1250_boot_secondary(int cpu, struct task_struct *idle)
97{
98 int retval;
99
100 retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
101 __KSTK_TOS(idle),
102 (unsigned long)task_thread_info(idle), 0);
103 if (retval != 0)
104 printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
105 return retval;
106}
107
108/*
109 * Use CFE to find out how many CPUs are available, setting up
110 * cpu_possible_mask and the logical/physical mappings.
111 * XXXKW will the boot CPU ever not be physical 0?
112 *
113 * Common setup before any secondaries are started
114 */
115static void __init sb1250_smp_setup(void)
116{
117 int i, num;
118
119 init_cpu_possible(cpumask_of(0));
120 __cpu_number_map[0] = 0;
121 __cpu_logical_map[0] = 0;
122
123 for (i = 1, num = 0; i < NR_CPUS; i++) {
124 if (cfe_cpu_stop(i) == 0) {
125 set_cpu_possible(i, true);
126 __cpu_number_map[i] = ++num;
127 __cpu_logical_map[num] = i;
128 }
129 }
130 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
131}
132
133static void __init sb1250_prepare_cpus(unsigned int max_cpus)
134{
135}
136
137const struct plat_smp_ops sb_smp_ops = {
138 .send_ipi_single = sb1250_send_ipi_single,
139 .send_ipi_mask = sb1250_send_ipi_mask,
140 .init_secondary = sb1250_init_secondary,
141 .smp_finish = sb1250_smp_finish,
142 .boot_secondary = sb1250_boot_secondary,
143 .smp_setup = sb1250_smp_setup,
144 .prepare_cpus = sb1250_prepare_cpus,
145};
146
147void sb1250_mailbox_interrupt(void)
148{
149 int cpu = smp_processor_id();
150 int irq = K_INT_MBOX_0;
151 unsigned int action;
152
153 kstat_incr_irq_this_cpu(irq);
154 /* Load the mailbox register to figure out what we're supposed to do */
155 action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
156
157 /* Clear the mailbox to clear the interrupt */
158 ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]);
159
160 if (action & SMP_RESCHEDULE_YOURSELF)
161 scheduler_ipi();
162
163 if (action & SMP_CALL_FUNCTION) {
164 irq_enter();
165 generic_smp_call_function_interrupt();
166 irq_exit();
167 }
168}
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
new file mode 100644
index 000000000..8b63000a4
--- /dev/null
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -0,0 +1,14 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001 Broadcom Corporation
4 */
5#include <linux/init.h>
6
7extern void sb1250_clocksource_init(void);
8extern void sb1250_clockevent_init(void);
9
10void __init plat_time_init(void)
11{
12 sb1250_clocksource_init();
13 sb1250_clockevent_init();
14}
diff --git a/arch/mips/sibyte/swarm/Makefile b/arch/mips/sibyte/swarm/Makefile
new file mode 100644
index 000000000..96b41a28f
--- /dev/null
+++ b/arch/mips/sibyte/swarm/Makefile
@@ -0,0 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0-only
2obj-y := platform.o setup.o rtc_xicor1241.o \
3 rtc_m41t81.o
4
5obj-$(CONFIG_I2C_BOARDINFO) += swarm-i2c.o
diff --git a/arch/mips/sibyte/swarm/platform.c b/arch/mips/sibyte/swarm/platform.c
new file mode 100644
index 000000000..484969db7
--- /dev/null
+++ b/arch/mips/sibyte/swarm/platform.c
@@ -0,0 +1,140 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/err.h>
3#include <linux/kernel.h>
4#include <linux/init.h>
5#include <linux/io.h>
6#include <linux/platform_device.h>
7#include <linux/ata_platform.h>
8
9#include <asm/sibyte/board.h>
10#include <asm/sibyte/sb1250_genbus.h>
11#include <asm/sibyte/sb1250_regs.h>
12
13#if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR)
14
15#define DRV_NAME "pata-swarm"
16
17#define SWARM_IDE_SHIFT 5
18#define SWARM_IDE_BASE 0x1f0
19#define SWARM_IDE_CTRL 0x3f6
20
21static struct resource swarm_pata_resource[] = {
22 {
23 .name = "Swarm GenBus IDE",
24 .flags = IORESOURCE_MEM,
25 }, {
26 .name = "Swarm GenBus IDE",
27 .flags = IORESOURCE_MEM,
28 }, {
29 .name = "Swarm GenBus IDE",
30 .flags = IORESOURCE_IRQ,
31 .start = K_INT_GB_IDE,
32 .end = K_INT_GB_IDE,
33 },
34};
35
36static struct pata_platform_info pata_platform_data = {
37 .ioport_shift = SWARM_IDE_SHIFT,
38};
39
40static struct platform_device swarm_pata_device = {
41 .name = "pata_platform",
42 .id = -1,
43 .resource = swarm_pata_resource,
44 .num_resources = ARRAY_SIZE(swarm_pata_resource),
45 .dev = {
46 .platform_data = &pata_platform_data,
47 .coherent_dma_mask = ~0, /* grumble */
48 },
49};
50
51static int __init swarm_pata_init(void)
52{
53 u8 __iomem *base;
54 phys_addr_t offset, size;
55 struct resource *r;
56
57 if (!SIBYTE_HAVE_IDE)
58 return -ENODEV;
59
60 base = ioremap(A_IO_EXT_BASE, 0x800);
61 offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
62 size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
63 iounmap(base);
64
65 offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE;
66 size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE;
67 if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) {
68 pr_info(DRV_NAME ": PATA interface at GenBus disabled\n");
69
70 return -EBUSY;
71 }
72
73 pr_info(DRV_NAME ": PATA interface at GenBus slot %i\n", IDE_CS);
74
75 r = swarm_pata_resource;
76 r[0].start = offset + (SWARM_IDE_BASE << SWARM_IDE_SHIFT);
77 r[0].end = offset + ((SWARM_IDE_BASE + 8) << SWARM_IDE_SHIFT) - 1;
78 r[1].start = offset + (SWARM_IDE_CTRL << SWARM_IDE_SHIFT);
79 r[1].end = offset + ((SWARM_IDE_CTRL + 1) << SWARM_IDE_SHIFT) - 1;
80
81 return platform_device_register(&swarm_pata_device);
82}
83
84device_initcall(swarm_pata_init);
85
86#endif /* defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR) */
87
88#define sb1250_dev_struct(num) \
89 static struct resource sb1250_res##num = { \
90 .name = "SB1250 MAC " __stringify(num), \
91 .flags = IORESOURCE_MEM, \
92 .start = A_MAC_CHANNEL_BASE(num), \
93 .end = A_MAC_CHANNEL_BASE(num + 1) -1, \
94 };\
95 static struct platform_device sb1250_dev##num = { \
96 .name = "sb1250-mac", \
97 .id = num, \
98 .resource = &sb1250_res##num, \
99 .num_resources = 1, \
100 }
101
102sb1250_dev_struct(0);
103sb1250_dev_struct(1);
104sb1250_dev_struct(2);
105sb1250_dev_struct(3);
106
107static struct platform_device *sb1250_devs[] __initdata = {
108 &sb1250_dev0,
109 &sb1250_dev1,
110 &sb1250_dev2,
111 &sb1250_dev3,
112};
113
114static int __init sb1250_device_init(void)
115{
116 int ret;
117
118 /* Set the number of available units based on the SOC type. */
119 switch (soc_type) {
120 case K_SYS_SOC_TYPE_BCM1250:
121 case K_SYS_SOC_TYPE_BCM1250_ALT:
122 ret = platform_add_devices(sb1250_devs, 3);
123 break;
124 case K_SYS_SOC_TYPE_BCM1120:
125 case K_SYS_SOC_TYPE_BCM1125:
126 case K_SYS_SOC_TYPE_BCM1125H:
127 case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
128 ret = platform_add_devices(sb1250_devs, 2);
129 break;
130 case K_SYS_SOC_TYPE_BCM1x55:
131 case K_SYS_SOC_TYPE_BCM1x80:
132 ret = platform_add_devices(sb1250_devs, 4);
133 break;
134 default:
135 ret = -ENODEV;
136 break;
137 }
138 return ret;
139}
140device_initcall(sb1250_device_init);
diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c
new file mode 100644
index 000000000..afe1e3460
--- /dev/null
+++ b/arch/mips/sibyte/swarm/rtc_m41t81.c
@@ -0,0 +1,228 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001 Broadcom Corporation
4 *
5 * Copyright (C) 2002 MontaVista Software Inc.
6 * Author: jsun@mvista.com or jsun@junsun.net
7 */
8#include <linux/bcd.h>
9#include <linux/types.h>
10#include <linux/time.h>
11
12#include <asm/time.h>
13#include <asm/addrspace.h>
14#include <asm/io.h>
15
16#include <asm/sibyte/sb1250.h>
17#include <asm/sibyte/sb1250_regs.h>
18#include <asm/sibyte/sb1250_smbus.h>
19
20
21/* M41T81 definitions */
22
23/*
24 * Register bits
25 */
26
27#define M41T81REG_SC_ST 0x80 /* stop bit */
28#define M41T81REG_HR_CB 0x40 /* century bit */
29#define M41T81REG_HR_CEB 0x80 /* century enable bit */
30#define M41T81REG_CTL_S 0x20 /* sign bit */
31#define M41T81REG_CTL_FT 0x40 /* frequency test bit */
32#define M41T81REG_CTL_OUT 0x80 /* output level */
33#define M41T81REG_WD_RB0 0x01 /* watchdog resolution bit 0 */
34#define M41T81REG_WD_RB1 0x02 /* watchdog resolution bit 1 */
35#define M41T81REG_WD_BMB0 0x04 /* watchdog multiplier bit 0 */
36#define M41T81REG_WD_BMB1 0x08 /* watchdog multiplier bit 1 */
37#define M41T81REG_WD_BMB2 0x10 /* watchdog multiplier bit 2 */
38#define M41T81REG_WD_BMB3 0x20 /* watchdog multiplier bit 3 */
39#define M41T81REG_WD_BMB4 0x40 /* watchdog multiplier bit 4 */
40#define M41T81REG_AMO_ABE 0x20 /* alarm in "battery back-up mode" enable bit */
41#define M41T81REG_AMO_SQWE 0x40 /* square wave enable */
42#define M41T81REG_AMO_AFE 0x80 /* alarm flag enable flag */
43#define M41T81REG_ADT_RPT5 0x40 /* alarm repeat mode bit 5 */
44#define M41T81REG_ADT_RPT4 0x80 /* alarm repeat mode bit 4 */
45#define M41T81REG_AHR_RPT3 0x80 /* alarm repeat mode bit 3 */
46#define M41T81REG_AHR_HT 0x40 /* halt update bit */
47#define M41T81REG_AMN_RPT2 0x80 /* alarm repeat mode bit 2 */
48#define M41T81REG_ASC_RPT1 0x80 /* alarm repeat mode bit 1 */
49#define M41T81REG_FLG_AF 0x40 /* alarm flag (read only) */
50#define M41T81REG_FLG_WDF 0x80 /* watchdog flag (read only) */
51#define M41T81REG_SQW_RS0 0x10 /* sqw frequency bit 0 */
52#define M41T81REG_SQW_RS1 0x20 /* sqw frequency bit 1 */
53#define M41T81REG_SQW_RS2 0x40 /* sqw frequency bit 2 */
54#define M41T81REG_SQW_RS3 0x80 /* sqw frequency bit 3 */
55
56
57/*
58 * Register numbers
59 */
60
61#define M41T81REG_TSC 0x00 /* tenths/hundredths of second */
62#define M41T81REG_SC 0x01 /* seconds */
63#define M41T81REG_MN 0x02 /* minute */
64#define M41T81REG_HR 0x03 /* hour/century */
65#define M41T81REG_DY 0x04 /* day of week */
66#define M41T81REG_DT 0x05 /* date of month */
67#define M41T81REG_MO 0x06 /* month */
68#define M41T81REG_YR 0x07 /* year */
69#define M41T81REG_CTL 0x08 /* control */
70#define M41T81REG_WD 0x09 /* watchdog */
71#define M41T81REG_AMO 0x0A /* alarm: month */
72#define M41T81REG_ADT 0x0B /* alarm: date */
73#define M41T81REG_AHR 0x0C /* alarm: hour */
74#define M41T81REG_AMN 0x0D /* alarm: minute */
75#define M41T81REG_ASC 0x0E /* alarm: second */
76#define M41T81REG_FLG 0x0F /* flags */
77#define M41T81REG_SQW 0x13 /* square wave register */
78
79#define M41T81_CCR_ADDRESS 0x68
80
81#define SMB_CSR(reg) IOADDR(A_SMB_REGISTER(1, reg))
82
83static int m41t81_read(uint8_t addr)
84{
85 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
86 ;
87
88 __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
89 __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR1BYTE,
90 SMB_CSR(R_SMB_START));
91
92 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
93 ;
94
95 __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
96 SMB_CSR(R_SMB_START));
97
98 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
99 ;
100
101 if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
102 /* Clear error bit by writing a 1 */
103 __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
104 return -1;
105 }
106
107 return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff;
108}
109
110static int m41t81_write(uint8_t addr, int b)
111{
112 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
113 ;
114
115 __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
116 __raw_writeq(b & 0xff, SMB_CSR(R_SMB_DATA));
117 __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
118 SMB_CSR(R_SMB_START));
119
120 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
121 ;
122
123 if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
124 /* Clear error bit by writing a 1 */
125 __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
126 return -1;
127 }
128
129 /* read the same byte again to make sure it is written */
130 __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
131 SMB_CSR(R_SMB_START));
132
133 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
134 ;
135
136 return 0;
137}
138
139int m41t81_set_time(time64_t t)
140{
141 struct rtc_time tm;
142 unsigned long flags;
143
144 /* Note we don't care about the century */
145 rtc_time64_to_tm(t, &tm);
146
147 /*
148 * Note the write order matters as it ensures the correctness.
149 * When we write sec, 10th sec is clear. It is reasonable to
150 * believe we should finish writing min within a second.
151 */
152
153 spin_lock_irqsave(&rtc_lock, flags);
154 tm.tm_sec = bin2bcd(tm.tm_sec);
155 m41t81_write(M41T81REG_SC, tm.tm_sec);
156
157 tm.tm_min = bin2bcd(tm.tm_min);
158 m41t81_write(M41T81REG_MN, tm.tm_min);
159
160 tm.tm_hour = bin2bcd(tm.tm_hour);
161 tm.tm_hour = (tm.tm_hour & 0x3f) | (m41t81_read(M41T81REG_HR) & 0xc0);
162 m41t81_write(M41T81REG_HR, tm.tm_hour);
163
164 /* tm_wday starts from 0 to 6 */
165 if (tm.tm_wday == 0) tm.tm_wday = 7;
166 tm.tm_wday = bin2bcd(tm.tm_wday);
167 m41t81_write(M41T81REG_DY, tm.tm_wday);
168
169 tm.tm_mday = bin2bcd(tm.tm_mday);
170 m41t81_write(M41T81REG_DT, tm.tm_mday);
171
172 /* tm_mon starts from 0, *ick* */
173 tm.tm_mon ++;
174 tm.tm_mon = bin2bcd(tm.tm_mon);
175 m41t81_write(M41T81REG_MO, tm.tm_mon);
176
177 /* we don't do century, everything is beyond 2000 */
178 tm.tm_year %= 100;
179 tm.tm_year = bin2bcd(tm.tm_year);
180 m41t81_write(M41T81REG_YR, tm.tm_year);
181 spin_unlock_irqrestore(&rtc_lock, flags);
182
183 return 0;
184}
185
186time64_t m41t81_get_time(void)
187{
188 unsigned int year, mon, day, hour, min, sec;
189 unsigned long flags;
190
191 /*
192 * min is valid if two reads of sec are the same.
193 */
194 for (;;) {
195 spin_lock_irqsave(&rtc_lock, flags);
196 sec = m41t81_read(M41T81REG_SC);
197 min = m41t81_read(M41T81REG_MN);
198 if (sec == m41t81_read(M41T81REG_SC)) break;
199 spin_unlock_irqrestore(&rtc_lock, flags);
200 }
201 hour = m41t81_read(M41T81REG_HR) & 0x3f;
202 day = m41t81_read(M41T81REG_DT);
203 mon = m41t81_read(M41T81REG_MO);
204 year = m41t81_read(M41T81REG_YR);
205 spin_unlock_irqrestore(&rtc_lock, flags);
206
207 sec = bcd2bin(sec);
208 min = bcd2bin(min);
209 hour = bcd2bin(hour);
210 day = bcd2bin(day);
211 mon = bcd2bin(mon);
212 year = bcd2bin(year);
213
214 year += 2000;
215
216 return mktime64(year, mon, day, hour, min, sec);
217}
218
219int m41t81_probe(void)
220{
221 unsigned int tmp;
222
223 /* enable chip if it is not enabled yet */
224 tmp = m41t81_read(M41T81REG_SC);
225 m41t81_write(M41T81REG_SC, tmp & 0x7f);
226
227 return m41t81_read(M41T81REG_SC) != -1;
228}
diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c
new file mode 100644
index 000000000..e2164200c
--- /dev/null
+++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c
@@ -0,0 +1,206 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001 Broadcom Corporation
4 *
5 * Copyright (C) 2002 MontaVista Software Inc.
6 * Author: jsun@mvista.com or jsun@junsun.net
7 */
8#include <linux/bcd.h>
9#include <linux/types.h>
10#include <linux/time.h>
11
12#include <asm/time.h>
13#include <asm/addrspace.h>
14#include <asm/io.h>
15
16#include <asm/sibyte/sb1250.h>
17#include <asm/sibyte/sb1250_regs.h>
18#include <asm/sibyte/sb1250_smbus.h>
19
20
21/* Xicor 1241 definitions */
22
23/*
24 * Register bits
25 */
26
27#define X1241REG_SR_BAT 0x80 /* currently on battery power */
28#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */
29#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */
30#define X1241REG_SR_RTCF 0x01 /* clock failed */
31#define X1241REG_BL_BP2 0x80 /* block protect 2 */
32#define X1241REG_BL_BP1 0x40 /* block protect 1 */
33#define X1241REG_BL_BP0 0x20 /* block protect 0 */
34#define X1241REG_BL_WD1 0x10
35#define X1241REG_BL_WD0 0x08
36#define X1241REG_HR_MIL 0x80 /* military time format */
37
38/*
39 * Register numbers
40 */
41
42#define X1241REG_BL 0x10 /* block protect bits */
43#define X1241REG_INT 0x11 /* */
44#define X1241REG_SC 0x30 /* Seconds */
45#define X1241REG_MN 0x31 /* Minutes */
46#define X1241REG_HR 0x32 /* Hours */
47#define X1241REG_DT 0x33 /* Day of month */
48#define X1241REG_MO 0x34 /* Month */
49#define X1241REG_YR 0x35 /* Year */
50#define X1241REG_DW 0x36 /* Day of Week */
51#define X1241REG_Y2K 0x37 /* Year 2K */
52#define X1241REG_SR 0x3F /* Status register */
53
54#define X1241_CCR_ADDRESS 0x6F
55
56#define SMB_CSR(reg) IOADDR(A_SMB_REGISTER(1, reg))
57
58static int xicor_read(uint8_t addr)
59{
60 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
61 ;
62
63 __raw_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD));
64 __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_DATA));
65 __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
66 SMB_CSR(R_SMB_START));
67
68 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
69 ;
70
71 __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
72 SMB_CSR(R_SMB_START));
73
74 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
75 ;
76
77 if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
78 /* Clear error bit by writing a 1 */
79 __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
80 return -1;
81 }
82
83 return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff;
84}
85
86static int xicor_write(uint8_t addr, int b)
87{
88 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
89 ;
90
91 __raw_writeq(addr, SMB_CSR(R_SMB_CMD));
92 __raw_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA));
93 __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE,
94 SMB_CSR(R_SMB_START));
95
96 while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
97 ;
98
99 if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
100 /* Clear error bit by writing a 1 */
101 __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
102 return -1;
103 } else {
104 return 0;
105 }
106}
107
108int xicor_set_time(time64_t t)
109{
110 struct rtc_time tm;
111 int tmp;
112 unsigned long flags;
113
114 rtc_time64_to_tm(t, &tm);
115 tm.tm_year += 1900;
116
117 spin_lock_irqsave(&rtc_lock, flags);
118 /* unlock writes to the CCR */
119 xicor_write(X1241REG_SR, X1241REG_SR_WEL);
120 xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
121
122 /* trivial ones */
123 tm.tm_sec = bin2bcd(tm.tm_sec);
124 xicor_write(X1241REG_SC, tm.tm_sec);
125
126 tm.tm_min = bin2bcd(tm.tm_min);
127 xicor_write(X1241REG_MN, tm.tm_min);
128
129 tm.tm_mday = bin2bcd(tm.tm_mday);
130 xicor_write(X1241REG_DT, tm.tm_mday);
131
132 /* tm_mon starts from 0, *ick* */
133 tm.tm_mon ++;
134 tm.tm_mon = bin2bcd(tm.tm_mon);
135 xicor_write(X1241REG_MO, tm.tm_mon);
136
137 /* year is split */
138 tmp = tm.tm_year / 100;
139 tm.tm_year %= 100;
140 xicor_write(X1241REG_YR, tm.tm_year);
141 xicor_write(X1241REG_Y2K, tmp);
142
143 /* hour is the most tricky one */
144 tmp = xicor_read(X1241REG_HR);
145 if (tmp & X1241REG_HR_MIL) {
146 /* 24 hour format */
147 tm.tm_hour = bin2bcd(tm.tm_hour);
148 tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f);
149 } else {
150 /* 12 hour format, with 0x2 for pm */
151 tmp = tmp & ~0x3f;
152 if (tm.tm_hour >= 12) {
153 tmp |= 0x20;
154 tm.tm_hour -= 12;
155 }
156 tm.tm_hour = bin2bcd(tm.tm_hour);
157 tmp |= tm.tm_hour;
158 }
159 xicor_write(X1241REG_HR, tmp);
160
161 xicor_write(X1241REG_SR, 0);
162 spin_unlock_irqrestore(&rtc_lock, flags);
163
164 return 0;
165}
166
167time64_t xicor_get_time(void)
168{
169 unsigned int year, mon, day, hour, min, sec, y2k;
170 unsigned long flags;
171
172 spin_lock_irqsave(&rtc_lock, flags);
173 sec = xicor_read(X1241REG_SC);
174 min = xicor_read(X1241REG_MN);
175 hour = xicor_read(X1241REG_HR);
176
177 if (hour & X1241REG_HR_MIL) {
178 hour &= 0x3f;
179 } else {
180 if (hour & 0x20)
181 hour = (hour & 0xf) + 0x12;
182 }
183
184 day = xicor_read(X1241REG_DT);
185 mon = xicor_read(X1241REG_MO);
186 year = xicor_read(X1241REG_YR);
187 y2k = xicor_read(X1241REG_Y2K);
188 spin_unlock_irqrestore(&rtc_lock, flags);
189
190 sec = bcd2bin(sec);
191 min = bcd2bin(min);
192 hour = bcd2bin(hour);
193 day = bcd2bin(day);
194 mon = bcd2bin(mon);
195 year = bcd2bin(year);
196 y2k = bcd2bin(y2k);
197
198 year += (y2k * 100);
199
200 return mktime64(year, mon, day, hour, min, sec);
201}
202
203int xicor_probe(void)
204{
205 return xicor_read(X1241REG_SC) != -1;
206}
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c
new file mode 100644
index 000000000..538a2791b
--- /dev/null
+++ b/arch/mips/sibyte/swarm/setup.c
@@ -0,0 +1,171 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Broadcom Corporation
4 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
5 */
6
7/*
8 * Setup code for the SWARM board
9 */
10
11#include <linux/spinlock.h>
12#include <linux/mm.h>
13#include <linux/memblock.h>
14#include <linux/blkdev.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/screen_info.h>
18#include <linux/initrd.h>
19
20#include <asm/irq.h>
21#include <asm/io.h>
22#include <asm/bootinfo.h>
23#include <asm/mipsregs.h>
24#include <asm/reboot.h>
25#include <asm/time.h>
26#include <asm/traps.h>
27#include <asm/sibyte/sb1250.h>
28#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
29#include <asm/sibyte/bcm1480_regs.h>
30#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
31#include <asm/sibyte/sb1250_regs.h>
32#else
33#error invalid SiByte board configuration
34#endif
35#include <asm/sibyte/sb1250_genbus.h>
36#include <asm/sibyte/board.h>
37
38#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
39extern void bcm1480_setup(void);
40#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
41extern void sb1250_setup(void);
42#else
43#error invalid SiByte board configuration
44#endif
45
46extern int xicor_probe(void);
47extern int xicor_set_time(time64_t);
48extern time64_t xicor_get_time(void);
49
50extern int m41t81_probe(void);
51extern int m41t81_set_time(time64_t);
52extern time64_t m41t81_get_time(void);
53
54const char *get_system_type(void)
55{
56 return "SiByte " SIBYTE_BOARD_NAME;
57}
58
59int swarm_be_handler(struct pt_regs *regs, int is_fixup)
60{
61 if (!is_fixup && (regs->cp0_cause & 4)) {
62 /* Data bus error - print PA */
63 printk("DBE physical address: %010Lx\n",
64 __read_64bit_c0_register($26, 1));
65 }
66 return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
67}
68
69enum swarm_rtc_type {
70 RTC_NONE,
71 RTC_XICOR,
72 RTC_M41T81,
73};
74
75enum swarm_rtc_type swarm_rtc_type;
76
77void read_persistent_clock64(struct timespec64 *ts)
78{
79 time64_t sec;
80
81 switch (swarm_rtc_type) {
82 case RTC_XICOR:
83 sec = xicor_get_time();
84 break;
85
86 case RTC_M41T81:
87 sec = m41t81_get_time();
88 break;
89
90 case RTC_NONE:
91 default:
92 sec = mktime64(2000, 1, 1, 0, 0, 0);
93 break;
94 }
95 ts->tv_sec = sec;
96 ts->tv_nsec = 0;
97}
98
99int update_persistent_clock64(struct timespec64 now)
100{
101 time64_t sec = now.tv_sec;
102
103 switch (swarm_rtc_type) {
104 case RTC_XICOR:
105 return xicor_set_time(sec);
106
107 case RTC_M41T81:
108 return m41t81_set_time(sec);
109
110 case RTC_NONE:
111 default:
112 return -1;
113 }
114}
115
116void __init plat_mem_setup(void)
117{
118#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
119 bcm1480_setup();
120#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
121 sb1250_setup();
122#else
123#error invalid SiByte board configuration
124#endif
125
126 board_be_handler = swarm_be_handler;
127
128 if (xicor_probe())
129 swarm_rtc_type = RTC_XICOR;
130 if (m41t81_probe())
131 swarm_rtc_type = RTC_M41T81;
132
133#ifdef CONFIG_VT
134 screen_info = (struct screen_info) {
135 .orig_video_page = 52,
136 .orig_video_mode = 3,
137 .orig_video_cols = 80,
138 .flags = 12,
139 .orig_video_ega_bx = 3,
140 .orig_video_lines = 25,
141 .orig_video_isVGA = 0x22,
142 .orig_video_points = 16,
143 };
144 /* XXXKW for CFE, get lines/cols from environment */
145#endif
146}
147
148#ifdef LEDS_PHYS
149
150#ifdef CONFIG_SIBYTE_CARMEL
151/* XXXKW need to detect Monterey/LittleSur/etc */
152#undef LEDS_PHYS
153#define LEDS_PHYS MLEDS_PHYS
154#endif
155
156void setleds(char *str)
157{
158 void *reg;
159 int i;
160
161 for (i = 0; i < 4; i++) {
162 reg = IOADDR(LEDS_PHYS) + 0x20 + ((3 - i) << 3);
163
164 if (!str[i])
165 writeb(' ', reg);
166 else
167 writeb(str[i], reg);
168 }
169}
170
171#endif /* LEDS_PHYS */
diff --git a/arch/mips/sibyte/swarm/swarm-i2c.c b/arch/mips/sibyte/swarm/swarm-i2c.c
new file mode 100644
index 000000000..1ed2dc96d
--- /dev/null
+++ b/arch/mips/sibyte/swarm/swarm-i2c.c
@@ -0,0 +1,31 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Broadcom BCM91250A (SWARM), etc. I2C platform setup.
4 *
5 * Copyright (c) 2008 Maciej W. Rozycki
6 */
7
8#include <linux/i2c.h>
9#include <linux/init.h>
10#include <linux/kernel.h>
11
12
13static struct i2c_board_info swarm_i2c_info1[] __initdata = {
14 {
15 I2C_BOARD_INFO("m41t81", 0x68),
16 },
17};
18
19static int __init swarm_i2c_init(void)
20{
21 int err;
22
23 err = i2c_register_board_info(1, swarm_i2c_info1,
24 ARRAY_SIZE(swarm_i2c_info1));
25 if (err < 0)
26 printk(KERN_ERR
27 "swarm-i2c: cannot register board I2C devices\n");
28 return err;
29}
30
31arch_initcall(swarm_i2c_init);