diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/netlogic | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/netlogic')
27 files changed, 4782 insertions, 0 deletions
diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig new file mode 100644 index 000000000..412351c5a --- /dev/null +++ b/arch/mips/netlogic/Kconfig | |||
@@ -0,0 +1,86 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | if NLM_XLP_BOARD || NLM_XLR_BOARD | ||
3 | |||
4 | if NLM_XLP_BOARD | ||
5 | config DT_XLP_EVP | ||
6 | bool "Built-in device tree for XLP EVP boards" | ||
7 | default y | ||
8 | select BUILTIN_DTB | ||
9 | help | ||
10 | Add an FDT blob for XLP EVP boards into the kernel. | ||
11 | This DTB will be used if the firmware does not pass in a DTB | ||
12 | pointer to the kernel. The corresponding DTS file is at | ||
13 | arch/mips/netlogic/dts/xlp_evp.dts | ||
14 | |||
15 | config DT_XLP_SVP | ||
16 | bool "Built-in device tree for XLP SVP boards" | ||
17 | default y | ||
18 | select BUILTIN_DTB | ||
19 | help | ||
20 | Add an FDT blob for XLP VP boards into the kernel. | ||
21 | This DTB will be used if the firmware does not pass in a DTB | ||
22 | pointer to the kernel. The corresponding DTS file is at | ||
23 | arch/mips/netlogic/dts/xlp_svp.dts | ||
24 | |||
25 | config DT_XLP_FVP | ||
26 | bool "Built-in device tree for XLP FVP boards" | ||
27 | default y | ||
28 | select BUILTIN_DTB | ||
29 | help | ||
30 | Add an FDT blob for XLP FVP board into the kernel. | ||
31 | This DTB will be used if the firmware does not pass in a DTB | ||
32 | pointer to the kernel. The corresponding DTS file is at | ||
33 | arch/mips/netlogic/dts/xlp_fvp.dts | ||
34 | |||
35 | config DT_XLP_GVP | ||
36 | bool "Built-in device tree for XLP GVP boards" | ||
37 | default y | ||
38 | select BUILTIN_DTB | ||
39 | help | ||
40 | Add an FDT blob for XLP GVP board into the kernel. | ||
41 | This DTB will be used if the firmware does not pass in a DTB | ||
42 | pointer to the kernel. The corresponding DTS file is at | ||
43 | arch/mips/netlogic/dts/xlp_gvp.dts | ||
44 | |||
45 | config DT_XLP_RVP | ||
46 | bool "Built-in device tree for XLP RVP boards" | ||
47 | default y | ||
48 | help | ||
49 | Add an FDT blob for XLP RVP board into the kernel. | ||
50 | This DTB will be used if the firmware does not pass in a DTB | ||
51 | pointer to the kernel. The corresponding DTS file is at | ||
52 | arch/mips/netlogic/dts/xlp_rvp.dts | ||
53 | |||
54 | config NLM_MULTINODE | ||
55 | bool "Support for multi-chip boards" | ||
56 | depends on NLM_XLP_BOARD | ||
57 | default n | ||
58 | help | ||
59 | Add support for boards with 2 or 4 XLPs connected over ICI. | ||
60 | |||
61 | if NLM_MULTINODE | ||
62 | choice | ||
63 | prompt "Number of XLPs on the board" | ||
64 | default NLM_MULTINODE_2 | ||
65 | help | ||
66 | In the multi-node case, specify the number of SoCs on the board. | ||
67 | |||
68 | config NLM_MULTINODE_2 | ||
69 | bool "Dual-XLP board" | ||
70 | help | ||
71 | Support boards with upto two XLPs connected over ICI. | ||
72 | |||
73 | config NLM_MULTINODE_4 | ||
74 | bool "Quad-XLP board" | ||
75 | help | ||
76 | Support boards with upto four XLPs connected over ICI. | ||
77 | |||
78 | endchoice | ||
79 | |||
80 | endif | ||
81 | endif | ||
82 | |||
83 | config NLM_COMMON | ||
84 | bool | ||
85 | |||
86 | endif | ||
diff --git a/arch/mips/netlogic/Makefile b/arch/mips/netlogic/Makefile new file mode 100644 index 000000000..c53561589 --- /dev/null +++ b/arch/mips/netlogic/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | obj-$(CONFIG_NLM_COMMON) += common/ | ||
3 | obj-$(CONFIG_CPU_XLR) += xlr/ | ||
4 | obj-$(CONFIG_CPU_XLP) += xlp/ | ||
diff --git a/arch/mips/netlogic/Platform b/arch/mips/netlogic/Platform new file mode 100644 index 000000000..4195a097f --- /dev/null +++ b/arch/mips/netlogic/Platform | |||
@@ -0,0 +1,16 @@ | |||
1 | # | ||
2 | # NETLOGIC includes | ||
3 | # | ||
4 | cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic | ||
5 | cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic | ||
6 | |||
7 | # | ||
8 | # use mips64 if xlr is not available | ||
9 | # | ||
10 | cflags-$(CONFIG_CPU_XLR) += $(call cc-option,-march=xlr,-march=mips64) | ||
11 | cflags-$(CONFIG_CPU_XLP) += $(call cc-option,-march=xlp,-march=mips64r2) | ||
12 | |||
13 | # | ||
14 | # NETLOGIC processor support | ||
15 | # | ||
16 | load-$(CONFIG_NLM_COMMON) += 0xffffffff80100000 | ||
diff --git a/arch/mips/netlogic/common/Makefile b/arch/mips/netlogic/common/Makefile new file mode 100644 index 000000000..89f6e3f39 --- /dev/null +++ b/arch/mips/netlogic/common/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | obj-y += irq.o time.o | ||
3 | obj-y += reset.o | ||
4 | obj-$(CONFIG_SMP) += smp.o smpboot.o | ||
5 | obj-$(CONFIG_EARLY_PRINTK) += earlycons.o | ||
diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c new file mode 100644 index 000000000..8f5bc1597 --- /dev/null +++ b/arch/mips/netlogic/common/earlycons.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/serial_reg.h> | ||
37 | |||
38 | #include <asm/mipsregs.h> | ||
39 | #include <asm/setup.h> | ||
40 | #include <asm/netlogic/haldefs.h> | ||
41 | #include <asm/netlogic/common.h> | ||
42 | |||
43 | #if defined(CONFIG_CPU_XLP) | ||
44 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
45 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
46 | #include <asm/netlogic/xlp-hal/uart.h> | ||
47 | #elif defined(CONFIG_CPU_XLR) | ||
48 | #include <asm/netlogic/xlr/iomap.h> | ||
49 | #endif | ||
50 | |||
51 | void prom_putchar(char c) | ||
52 | { | ||
53 | uint64_t uartbase; | ||
54 | |||
55 | #if defined(CONFIG_CPU_XLP) | ||
56 | uartbase = nlm_get_uart_regbase(0, 0); | ||
57 | #elif defined(CONFIG_CPU_XLR) | ||
58 | uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); | ||
59 | #endif | ||
60 | while ((nlm_read_reg(uartbase, UART_LSR) & UART_LSR_THRE) == 0) | ||
61 | ; | ||
62 | nlm_write_reg(uartbase, UART_TX, c); | ||
63 | } | ||
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c new file mode 100644 index 000000000..cf33dd8a4 --- /dev/null +++ b/arch/mips/netlogic/common/irq.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/linkage.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/irq.h> | ||
42 | |||
43 | #include <linux/irqdomain.h> | ||
44 | #include <linux/of_address.h> | ||
45 | #include <linux/of_irq.h> | ||
46 | |||
47 | #include <asm/errno.h> | ||
48 | #include <asm/signal.h> | ||
49 | #include <asm/ptrace.h> | ||
50 | #include <asm/mipsregs.h> | ||
51 | #include <asm/thread_info.h> | ||
52 | |||
53 | #include <asm/netlogic/mips-extns.h> | ||
54 | #include <asm/netlogic/interrupt.h> | ||
55 | #include <asm/netlogic/haldefs.h> | ||
56 | #include <asm/netlogic/common.h> | ||
57 | |||
58 | #if defined(CONFIG_CPU_XLP) | ||
59 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
60 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
61 | #include <asm/netlogic/xlp-hal/pic.h> | ||
62 | #elif defined(CONFIG_CPU_XLR) | ||
63 | #include <asm/netlogic/xlr/iomap.h> | ||
64 | #include <asm/netlogic/xlr/pic.h> | ||
65 | #include <asm/netlogic/xlr/fmn.h> | ||
66 | #else | ||
67 | #error "Unknown CPU" | ||
68 | #endif | ||
69 | |||
70 | #ifdef CONFIG_SMP | ||
71 | #define SMP_IRQ_MASK ((1ULL << IRQ_IPI_SMP_FUNCTION) | \ | ||
72 | (1ULL << IRQ_IPI_SMP_RESCHEDULE)) | ||
73 | #else | ||
74 | #define SMP_IRQ_MASK 0 | ||
75 | #endif | ||
76 | #define PERCPU_IRQ_MASK (SMP_IRQ_MASK | (1ull << IRQ_TIMER) | \ | ||
77 | (1ull << IRQ_FMN)) | ||
78 | |||
79 | struct nlm_pic_irq { | ||
80 | void (*extra_ack)(struct irq_data *); | ||
81 | struct nlm_soc_info *node; | ||
82 | int picirq; | ||
83 | int irt; | ||
84 | int flags; | ||
85 | }; | ||
86 | |||
87 | static void xlp_pic_enable(struct irq_data *d) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); | ||
91 | |||
92 | BUG_ON(!pd); | ||
93 | spin_lock_irqsave(&pd->node->piclock, flags); | ||
94 | nlm_pic_enable_irt(pd->node->picbase, pd->irt); | ||
95 | spin_unlock_irqrestore(&pd->node->piclock, flags); | ||
96 | } | ||
97 | |||
98 | static void xlp_pic_disable(struct irq_data *d) | ||
99 | { | ||
100 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); | ||
101 | unsigned long flags; | ||
102 | |||
103 | BUG_ON(!pd); | ||
104 | spin_lock_irqsave(&pd->node->piclock, flags); | ||
105 | nlm_pic_disable_irt(pd->node->picbase, pd->irt); | ||
106 | spin_unlock_irqrestore(&pd->node->piclock, flags); | ||
107 | } | ||
108 | |||
109 | static void xlp_pic_mask_ack(struct irq_data *d) | ||
110 | { | ||
111 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); | ||
112 | |||
113 | clear_c0_eimr(pd->picirq); | ||
114 | ack_c0_eirr(pd->picirq); | ||
115 | } | ||
116 | |||
117 | static void xlp_pic_unmask(struct irq_data *d) | ||
118 | { | ||
119 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); | ||
120 | |||
121 | BUG_ON(!pd); | ||
122 | |||
123 | if (pd->extra_ack) | ||
124 | pd->extra_ack(d); | ||
125 | |||
126 | /* re-enable the intr on this cpu */ | ||
127 | set_c0_eimr(pd->picirq); | ||
128 | |||
129 | /* Ack is a single write, no need to lock */ | ||
130 | nlm_pic_ack(pd->node->picbase, pd->irt); | ||
131 | } | ||
132 | |||
133 | static struct irq_chip xlp_pic = { | ||
134 | .name = "XLP-PIC", | ||
135 | .irq_enable = xlp_pic_enable, | ||
136 | .irq_disable = xlp_pic_disable, | ||
137 | .irq_mask_ack = xlp_pic_mask_ack, | ||
138 | .irq_unmask = xlp_pic_unmask, | ||
139 | }; | ||
140 | |||
141 | static void cpuintr_disable(struct irq_data *d) | ||
142 | { | ||
143 | clear_c0_eimr(d->irq); | ||
144 | } | ||
145 | |||
146 | static void cpuintr_enable(struct irq_data *d) | ||
147 | { | ||
148 | set_c0_eimr(d->irq); | ||
149 | } | ||
150 | |||
151 | static void cpuintr_ack(struct irq_data *d) | ||
152 | { | ||
153 | ack_c0_eirr(d->irq); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Chip definition for CPU originated interrupts(timer, msg) and | ||
158 | * IPIs | ||
159 | */ | ||
160 | struct irq_chip nlm_cpu_intr = { | ||
161 | .name = "XLP-CPU-INTR", | ||
162 | .irq_enable = cpuintr_enable, | ||
163 | .irq_disable = cpuintr_disable, | ||
164 | .irq_mask = cpuintr_disable, | ||
165 | .irq_ack = cpuintr_ack, | ||
166 | .irq_eoi = cpuintr_enable, | ||
167 | }; | ||
168 | |||
169 | static void __init nlm_init_percpu_irqs(void) | ||
170 | { | ||
171 | int i; | ||
172 | |||
173 | for (i = 0; i < PIC_IRT_FIRST_IRQ; i++) | ||
174 | irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq); | ||
175 | #ifdef CONFIG_SMP | ||
176 | irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, | ||
177 | nlm_smp_function_ipi_handler); | ||
178 | irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, | ||
179 | nlm_smp_resched_ipi_handler); | ||
180 | #endif | ||
181 | } | ||
182 | |||
183 | |||
184 | void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) | ||
185 | { | ||
186 | struct nlm_pic_irq *pic_data; | ||
187 | int xirq; | ||
188 | |||
189 | xirq = nlm_irq_to_xirq(node, irq); | ||
190 | pic_data = kzalloc(sizeof(*pic_data), GFP_KERNEL); | ||
191 | BUG_ON(pic_data == NULL); | ||
192 | pic_data->irt = irt; | ||
193 | pic_data->picirq = picirq; | ||
194 | pic_data->node = nlm_get_node(node); | ||
195 | irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); | ||
196 | irq_set_chip_data(xirq, pic_data); | ||
197 | } | ||
198 | |||
199 | void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) | ||
200 | { | ||
201 | struct nlm_pic_irq *pic_data; | ||
202 | int xirq; | ||
203 | |||
204 | xirq = nlm_irq_to_xirq(node, irq); | ||
205 | pic_data = irq_get_chip_data(xirq); | ||
206 | if (WARN_ON(!pic_data)) | ||
207 | return; | ||
208 | pic_data->extra_ack = xack; | ||
209 | } | ||
210 | |||
211 | static void nlm_init_node_irqs(int node) | ||
212 | { | ||
213 | struct nlm_soc_info *nodep; | ||
214 | int i, irt; | ||
215 | |||
216 | pr_info("Init IRQ for node %d\n", node); | ||
217 | nodep = nlm_get_node(node); | ||
218 | nodep->irqmask = PERCPU_IRQ_MASK; | ||
219 | for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) { | ||
220 | irt = nlm_irq_to_irt(i); | ||
221 | if (irt == -1) /* unused irq */ | ||
222 | continue; | ||
223 | nodep->irqmask |= 1ull << i; | ||
224 | if (irt == -2) /* not a direct PIC irq */ | ||
225 | continue; | ||
226 | |||
227 | nlm_pic_init_irt(nodep->picbase, irt, i, | ||
228 | node * nlm_threads_per_node(), 0); | ||
229 | nlm_setup_pic_irq(node, i, i, irt); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | void nlm_smp_irq_init(int hwtid) | ||
234 | { | ||
235 | int cpu, node; | ||
236 | |||
237 | cpu = hwtid % nlm_threads_per_node(); | ||
238 | node = hwtid / nlm_threads_per_node(); | ||
239 | |||
240 | if (cpu == 0 && node != 0) | ||
241 | nlm_init_node_irqs(node); | ||
242 | write_c0_eimr(nlm_get_node(node)->irqmask); | ||
243 | } | ||
244 | |||
245 | asmlinkage void plat_irq_dispatch(void) | ||
246 | { | ||
247 | uint64_t eirr; | ||
248 | int i, node; | ||
249 | |||
250 | node = nlm_nodeid(); | ||
251 | eirr = read_c0_eirr_and_eimr(); | ||
252 | if (eirr == 0) | ||
253 | return; | ||
254 | |||
255 | i = __ffs64(eirr); | ||
256 | /* per-CPU IRQs don't need translation */ | ||
257 | if (i < PIC_IRQ_BASE) { | ||
258 | do_IRQ(i); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | #if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP) | ||
263 | /* PCI interrupts need a second level dispatch for MSI bits */ | ||
264 | if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) { | ||
265 | nlm_dispatch_msi(node, i); | ||
266 | return; | ||
267 | } | ||
268 | if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) { | ||
269 | nlm_dispatch_msix(node, i); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | #endif | ||
274 | /* top level irq handling */ | ||
275 | do_IRQ(nlm_irq_to_xirq(node, i)); | ||
276 | } | ||
277 | |||
278 | #ifdef CONFIG_CPU_XLP | ||
279 | static const struct irq_domain_ops xlp_pic_irq_domain_ops = { | ||
280 | .xlate = irq_domain_xlate_onetwocell, | ||
281 | }; | ||
282 | |||
283 | static int __init xlp_of_pic_init(struct device_node *node, | ||
284 | struct device_node *parent) | ||
285 | { | ||
286 | const int n_picirqs = PIC_IRT_LAST_IRQ - PIC_IRQ_BASE + 1; | ||
287 | struct irq_domain *xlp_pic_domain; | ||
288 | struct resource res; | ||
289 | int socid, ret, bus; | ||
290 | |||
291 | /* we need a hack to get the PIC's SoC chip id */ | ||
292 | ret = of_address_to_resource(node, 0, &res); | ||
293 | if (ret < 0) { | ||
294 | pr_err("PIC %pOFn: reg property not found!\n", node); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | if (cpu_is_xlp9xx()) { | ||
299 | bus = (res.start >> 20) & 0xf; | ||
300 | for (socid = 0; socid < NLM_NR_NODES; socid++) { | ||
301 | if (!nlm_node_present(socid)) | ||
302 | continue; | ||
303 | if (nlm_get_node(socid)->socbus == bus) | ||
304 | break; | ||
305 | } | ||
306 | if (socid == NLM_NR_NODES) { | ||
307 | pr_err("PIC %pOFn: Node mapping for bus %d not found!\n", | ||
308 | node, bus); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | } else { | ||
312 | socid = (res.start >> 18) & 0x3; | ||
313 | if (!nlm_node_present(socid)) { | ||
314 | pr_err("PIC %pOFn: node %d does not exist!\n", | ||
315 | node, socid); | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | if (!nlm_node_present(socid)) { | ||
321 | pr_err("PIC %pOFn: node %d does not exist!\n", node, socid); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs, | ||
326 | nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE, | ||
327 | &xlp_pic_irq_domain_ops, NULL); | ||
328 | if (xlp_pic_domain == NULL) { | ||
329 | pr_err("PIC %pOFn: Creating legacy domain failed!\n", node); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static struct of_device_id __initdata xlp_pic_irq_ids[] = { | ||
337 | { .compatible = "netlogic,xlp-pic", .data = xlp_of_pic_init }, | ||
338 | {}, | ||
339 | }; | ||
340 | #endif | ||
341 | |||
342 | void __init arch_init_irq(void) | ||
343 | { | ||
344 | /* Initialize the irq descriptors */ | ||
345 | nlm_init_percpu_irqs(); | ||
346 | nlm_init_node_irqs(0); | ||
347 | write_c0_eimr(nlm_current_node()->irqmask); | ||
348 | #if defined(CONFIG_CPU_XLR) | ||
349 | nlm_setup_fmn_irq(); | ||
350 | #endif | ||
351 | #ifdef CONFIG_CPU_XLP | ||
352 | of_irq_init(xlp_pic_irq_ids); | ||
353 | #endif | ||
354 | } | ||
diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S new file mode 100644 index 000000000..c474981a6 --- /dev/null +++ b/arch/mips/netlogic/common/reset.S | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2013 Broadcom Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | |||
36 | #include <asm/asm.h> | ||
37 | #include <asm/asm-offsets.h> | ||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/cacheops.h> | ||
40 | #include <asm/regdef.h> | ||
41 | #include <asm/mipsregs.h> | ||
42 | #include <asm/stackframe.h> | ||
43 | #include <asm/asmmacro.h> | ||
44 | #include <asm/addrspace.h> | ||
45 | |||
46 | #include <asm/netlogic/common.h> | ||
47 | |||
48 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
49 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
50 | #include <asm/netlogic/xlp-hal/sys.h> | ||
51 | #include <asm/netlogic/xlp-hal/cpucontrol.h> | ||
52 | |||
53 | #define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ | ||
54 | XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ | ||
55 | SYS_CPU_NONCOHERENT_MODE * 4 | ||
56 | |||
57 | /* Enable XLP features and workarounds in the LSU */ | ||
58 | .macro xlp_config_lsu | ||
59 | li t0, LSU_DEFEATURE | ||
60 | mfcr t1, t0 | ||
61 | |||
62 | lui t2, 0x4080 /* Enable Unaligned Access, L2HPE */ | ||
63 | or t1, t1, t2 | ||
64 | mtcr t1, t0 | ||
65 | |||
66 | li t0, ICU_DEFEATURE | ||
67 | mfcr t1, t0 | ||
68 | ori t1, 0x1000 /* Enable Icache partitioning */ | ||
69 | mtcr t1, t0 | ||
70 | |||
71 | li t0, SCHED_DEFEATURE | ||
72 | lui t1, 0x0100 /* Disable BRU accepting ALU ops */ | ||
73 | mtcr t1, t0 | ||
74 | .endm | ||
75 | |||
76 | /* | ||
77 | * Allow access to physical mem >64G by enabling ELPA in PAGEGRAIN | ||
78 | * register. This is needed before going to C code since the SP can | ||
79 | * in this region. Called from all HW threads. | ||
80 | */ | ||
81 | .macro xlp_early_mmu_init | ||
82 | mfc0 t0, CP0_PAGEMASK, 1 | ||
83 | li t1, (1 << 29) /* ELPA bit */ | ||
84 | or t0, t1 | ||
85 | mtc0 t0, CP0_PAGEMASK, 1 | ||
86 | .endm | ||
87 | |||
88 | /* | ||
89 | * L1D cache has to be flushed before enabling threads in XLP. | ||
90 | * On XLP8xx/XLP3xx, we do a low level flush using processor control | ||
91 | * registers. On XLPII CPUs, usual cache instructions work. | ||
92 | */ | ||
93 | .macro xlp_flush_l1_dcache | ||
94 | mfc0 t0, CP0_PRID | ||
95 | andi t0, t0, PRID_IMP_MASK | ||
96 | slt t1, t0, 0x1200 | ||
97 | beqz t1, 15f | ||
98 | nop | ||
99 | |||
100 | /* XLP8xx low level cache flush */ | ||
101 | li t0, LSU_DEBUG_DATA0 | ||
102 | li t1, LSU_DEBUG_ADDR | ||
103 | li t2, 0 /* index */ | ||
104 | li t3, 0x1000 /* loop count */ | ||
105 | 11: | ||
106 | sll v0, t2, 5 | ||
107 | mtcr zero, t0 | ||
108 | ori v1, v0, 0x3 /* way0 | write_enable | write_active */ | ||
109 | mtcr v1, t1 | ||
110 | 12: | ||
111 | mfcr v1, t1 | ||
112 | andi v1, 0x1 /* wait for write_active == 0 */ | ||
113 | bnez v1, 12b | ||
114 | nop | ||
115 | mtcr zero, t0 | ||
116 | ori v1, v0, 0x7 /* way1 | write_enable | write_active */ | ||
117 | mtcr v1, t1 | ||
118 | 13: | ||
119 | mfcr v1, t1 | ||
120 | andi v1, 0x1 /* wait for write_active == 0 */ | ||
121 | bnez v1, 13b | ||
122 | nop | ||
123 | addi t2, 1 | ||
124 | bne t3, t2, 11b | ||
125 | nop | ||
126 | b 17f | ||
127 | nop | ||
128 | |||
129 | /* XLPII CPUs, Invalidate all 64k of L1 D-cache */ | ||
130 | 15: | ||
131 | li t0, 0x80000000 | ||
132 | li t1, 0x80010000 | ||
133 | 16: cache Index_Writeback_Inv_D, 0(t0) | ||
134 | addiu t0, t0, 32 | ||
135 | bne t0, t1, 16b | ||
136 | nop | ||
137 | 17: | ||
138 | .endm | ||
139 | |||
140 | /* | ||
141 | * nlm_reset_entry will be copied to the reset entry point for | ||
142 | * XLR and XLP. The XLP cores start here when they are woken up. This | ||
143 | * is also the NMI entry point. | ||
144 | * | ||
145 | * We use scratch reg 6/7 to save k0/k1 and check for NMI first. | ||
146 | * | ||
147 | * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS | ||
148 | * location, this will have the thread mask (used when core is woken up) | ||
149 | * and the current NMI handler in case we reached here for an NMI. | ||
150 | * | ||
151 | * When a core or thread is newly woken up, it marks itself ready and | ||
152 | * loops in a 'wait'. When the CPU really needs waking up, we send an NMI | ||
153 | * IPI to it, with the NMI handler set to prom_boot_secondary_cpus | ||
154 | */ | ||
155 | .set noreorder | ||
156 | .set noat | ||
157 | .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ | ||
158 | |||
159 | FEXPORT(nlm_reset_entry) | ||
160 | dmtc0 k0, $22, 6 | ||
161 | dmtc0 k1, $22, 7 | ||
162 | mfc0 k0, CP0_STATUS | ||
163 | li k1, 0x80000 | ||
164 | and k1, k0, k1 | ||
165 | beqz k1, 1f /* go to real reset entry */ | ||
166 | nop | ||
167 | li k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */ | ||
168 | ld k0, BOOT_NMI_HANDLER(k1) | ||
169 | jr k0 | ||
170 | nop | ||
171 | |||
172 | 1: /* Entry point on core wakeup */ | ||
173 | mfc0 t0, CP0_PRID /* processor ID */ | ||
174 | andi t0, PRID_IMP_MASK | ||
175 | li t1, 0x1500 /* XLP 9xx */ | ||
176 | beq t0, t1, 2f /* does not need to set coherent */ | ||
177 | nop | ||
178 | |||
179 | li t1, 0x1300 /* XLP 5xx */ | ||
180 | beq t0, t1, 2f /* does not need to set coherent */ | ||
181 | nop | ||
182 | |||
183 | /* set bit in SYS coherent register for the core */ | ||
184 | mfc0 t0, CP0_EBASE | ||
185 | mfc0 t1, CP0_EBASE | ||
186 | srl t1, 5 | ||
187 | andi t1, 0x3 /* t1 <- node */ | ||
188 | li t2, 0x40000 | ||
189 | mul t3, t2, t1 /* t3 = node * 0x40000 */ | ||
190 | srl t0, t0, 2 | ||
191 | and t0, t0, 0x7 /* t0 <- core */ | ||
192 | li t1, 0x1 | ||
193 | sll t0, t1, t0 | ||
194 | nor t0, t0, zero /* t0 <- ~(1 << core) */ | ||
195 | li t2, SYS_CPU_COHERENT_BASE | ||
196 | add t2, t2, t3 /* t2 <- SYS offset for node */ | ||
197 | lw t1, 0(t2) | ||
198 | and t1, t1, t0 | ||
199 | sw t1, 0(t2) | ||
200 | |||
201 | /* read back to ensure complete */ | ||
202 | lw t1, 0(t2) | ||
203 | sync | ||
204 | |||
205 | 2: | ||
206 | /* Configure LSU on Non-0 Cores. */ | ||
207 | xlp_config_lsu | ||
208 | /* FALL THROUGH */ | ||
209 | |||
210 | /* | ||
211 | * Wake up sibling threads from the initial thread in a core. | ||
212 | */ | ||
213 | EXPORT(nlm_boot_siblings) | ||
214 | /* core L1D flush before enable threads */ | ||
215 | xlp_flush_l1_dcache | ||
216 | /* save ra and sp, will be used later (only for boot cpu) */ | ||
217 | dmtc0 ra, $22, 6 | ||
218 | dmtc0 sp, $22, 7 | ||
219 | /* Enable hw threads by writing to MAP_THREADMODE of the core */ | ||
220 | li t0, CKSEG1ADDR(RESET_DATA_PHYS) | ||
221 | lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ | ||
222 | li t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE) | ||
223 | mfcr t2, t0 | ||
224 | or t2, t2, t1 | ||
225 | mtcr t2, t0 | ||
226 | |||
227 | /* | ||
228 | * The new hardware thread starts at the next instruction | ||
229 | * For all the cases other than core 0 thread 0, we will | ||
230 | * jump to the secondary wait function. | ||
231 | |||
232 | * NOTE: All GPR contents are lost after the mtcr above! | ||
233 | */ | ||
234 | mfc0 v0, CP0_EBASE | ||
235 | andi v0, 0x3ff /* v0 <- node/core */ | ||
236 | |||
237 | /* | ||
238 | * Errata: to avoid potential live lock, setup IFU_BRUB_RESERVE | ||
239 | * when running 4 threads per core | ||
240 | */ | ||
241 | andi v1, v0, 0x3 /* v1 <- thread id */ | ||
242 | bnez v1, 2f | ||
243 | nop | ||
244 | |||
245 | /* thread 0 of each core. */ | ||
246 | li t0, CKSEG1ADDR(RESET_DATA_PHYS) | ||
247 | lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ | ||
248 | subu t1, 0x3 /* 4-thread per core mode? */ | ||
249 | bnez t1, 2f | ||
250 | nop | ||
251 | |||
252 | li t0, IFU_BRUB_RESERVE | ||
253 | li t1, 0x55 | ||
254 | mtcr t1, t0 | ||
255 | _ehb | ||
256 | 2: | ||
257 | beqz v0, 4f /* boot cpu (cpuid == 0)? */ | ||
258 | nop | ||
259 | |||
260 | /* setup status reg */ | ||
261 | move t1, zero | ||
262 | #ifdef CONFIG_64BIT | ||
263 | ori t1, ST0_KX | ||
264 | #endif | ||
265 | mtc0 t1, CP0_STATUS | ||
266 | |||
267 | xlp_early_mmu_init | ||
268 | |||
269 | /* mark CPU ready */ | ||
270 | li t3, CKSEG1ADDR(RESET_DATA_PHYS) | ||
271 | ADDIU t1, t3, BOOT_CPU_READY | ||
272 | sll v1, v0, 2 | ||
273 | PTR_ADDU t1, v1 | ||
274 | li t2, 1 | ||
275 | sw t2, 0(t1) | ||
276 | /* Wait until NMI hits */ | ||
277 | 3: wait | ||
278 | b 3b | ||
279 | nop | ||
280 | |||
281 | /* | ||
282 | * For the boot CPU, we have to restore ra and sp and return, rest | ||
283 | * of the registers will be restored by the caller | ||
284 | */ | ||
285 | 4: | ||
286 | dmfc0 ra, $22, 6 | ||
287 | dmfc0 sp, $22, 7 | ||
288 | jr ra | ||
289 | nop | ||
290 | EXPORT(nlm_reset_entry_end) | ||
291 | |||
292 | LEAF(nlm_init_boot_cpu) | ||
293 | #ifdef CONFIG_CPU_XLP | ||
294 | xlp_config_lsu | ||
295 | xlp_early_mmu_init | ||
296 | #endif | ||
297 | jr ra | ||
298 | nop | ||
299 | END(nlm_init_boot_cpu) | ||
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c new file mode 100644 index 000000000..39a300bd6 --- /dev/null +++ b/arch/mips/netlogic/common/smp.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/sched/task_stack.h> | ||
39 | #include <linux/smp.h> | ||
40 | #include <linux/irq.h> | ||
41 | |||
42 | #include <asm/mmu_context.h> | ||
43 | |||
44 | #include <asm/netlogic/interrupt.h> | ||
45 | #include <asm/netlogic/mips-extns.h> | ||
46 | #include <asm/netlogic/haldefs.h> | ||
47 | #include <asm/netlogic/common.h> | ||
48 | |||
49 | #if defined(CONFIG_CPU_XLP) | ||
50 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
51 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
52 | #include <asm/netlogic/xlp-hal/pic.h> | ||
53 | #elif defined(CONFIG_CPU_XLR) | ||
54 | #include <asm/netlogic/xlr/iomap.h> | ||
55 | #include <asm/netlogic/xlr/pic.h> | ||
56 | #include <asm/netlogic/xlr/xlr.h> | ||
57 | #else | ||
58 | #error "Unknown CPU" | ||
59 | #endif | ||
60 | |||
61 | void nlm_send_ipi_single(int logical_cpu, unsigned int action) | ||
62 | { | ||
63 | unsigned int hwtid; | ||
64 | uint64_t picbase; | ||
65 | |||
66 | /* node id is part of hwtid, and needed for send_ipi */ | ||
67 | hwtid = cpu_logical_map(logical_cpu); | ||
68 | picbase = nlm_get_node(nlm_hwtid_to_node(hwtid))->picbase; | ||
69 | |||
70 | if (action & SMP_CALL_FUNCTION) | ||
71 | nlm_pic_send_ipi(picbase, hwtid, IRQ_IPI_SMP_FUNCTION, 0); | ||
72 | if (action & SMP_RESCHEDULE_YOURSELF) | ||
73 | nlm_pic_send_ipi(picbase, hwtid, IRQ_IPI_SMP_RESCHEDULE, 0); | ||
74 | } | ||
75 | |||
76 | void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) | ||
77 | { | ||
78 | int cpu; | ||
79 | |||
80 | for_each_cpu(cpu, mask) { | ||
81 | nlm_send_ipi_single(cpu, action); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | /* IRQ_IPI_SMP_FUNCTION Handler */ | ||
86 | void nlm_smp_function_ipi_handler(struct irq_desc *desc) | ||
87 | { | ||
88 | unsigned int irq = irq_desc_get_irq(desc); | ||
89 | clear_c0_eimr(irq); | ||
90 | ack_c0_eirr(irq); | ||
91 | generic_smp_call_function_interrupt(); | ||
92 | set_c0_eimr(irq); | ||
93 | } | ||
94 | |||
95 | /* IRQ_IPI_SMP_RESCHEDULE handler */ | ||
96 | void nlm_smp_resched_ipi_handler(struct irq_desc *desc) | ||
97 | { | ||
98 | unsigned int irq = irq_desc_get_irq(desc); | ||
99 | clear_c0_eimr(irq); | ||
100 | ack_c0_eirr(irq); | ||
101 | scheduler_ipi(); | ||
102 | set_c0_eimr(irq); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Called before going into mips code, early cpu init | ||
107 | */ | ||
108 | void nlm_early_init_secondary(int cpu) | ||
109 | { | ||
110 | change_c0_config(CONF_CM_CMASK, 0x3); | ||
111 | #ifdef CONFIG_CPU_XLP | ||
112 | xlp_mmu_init(); | ||
113 | #endif | ||
114 | write_c0_ebase(nlm_current_node()->ebase); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Code to run on secondary just after probing the CPU | ||
119 | */ | ||
120 | static void nlm_init_secondary(void) | ||
121 | { | ||
122 | int hwtid; | ||
123 | |||
124 | hwtid = hard_smp_processor_id(); | ||
125 | cpu_set_core(¤t_cpu_data, hwtid / NLM_THREADS_PER_CORE); | ||
126 | current_cpu_data.package = nlm_nodeid(); | ||
127 | nlm_percpu_init(hwtid); | ||
128 | nlm_smp_irq_init(hwtid); | ||
129 | } | ||
130 | |||
131 | void nlm_prepare_cpus(unsigned int max_cpus) | ||
132 | { | ||
133 | /* declare we are SMT capable */ | ||
134 | smp_num_siblings = nlm_threads_per_core; | ||
135 | } | ||
136 | |||
137 | void nlm_smp_finish(void) | ||
138 | { | ||
139 | local_irq_enable(); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Boot all other cpus in the system, initialize them, and bring them into | ||
144 | * the boot function | ||
145 | */ | ||
146 | unsigned long nlm_next_gp; | ||
147 | unsigned long nlm_next_sp; | ||
148 | static cpumask_t phys_cpu_present_mask; | ||
149 | |||
150 | int nlm_boot_secondary(int logical_cpu, struct task_struct *idle) | ||
151 | { | ||
152 | uint64_t picbase; | ||
153 | int hwtid; | ||
154 | |||
155 | hwtid = cpu_logical_map(logical_cpu); | ||
156 | picbase = nlm_get_node(nlm_hwtid_to_node(hwtid))->picbase; | ||
157 | |||
158 | nlm_next_sp = (unsigned long)__KSTK_TOS(idle); | ||
159 | nlm_next_gp = (unsigned long)task_thread_info(idle); | ||
160 | |||
161 | /* barrier for sp/gp store above */ | ||
162 | __sync(); | ||
163 | nlm_pic_send_ipi(picbase, hwtid, 1, 1); /* NMI */ | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | void __init nlm_smp_setup(void) | ||
169 | { | ||
170 | unsigned int boot_cpu; | ||
171 | int num_cpus, i, ncore, node; | ||
172 | volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); | ||
173 | |||
174 | boot_cpu = hard_smp_processor_id(); | ||
175 | cpumask_clear(&phys_cpu_present_mask); | ||
176 | |||
177 | cpumask_set_cpu(boot_cpu, &phys_cpu_present_mask); | ||
178 | __cpu_number_map[boot_cpu] = 0; | ||
179 | __cpu_logical_map[0] = boot_cpu; | ||
180 | set_cpu_possible(0, true); | ||
181 | |||
182 | num_cpus = 1; | ||
183 | for (i = 0; i < NR_CPUS; i++) { | ||
184 | /* | ||
185 | * cpu_ready array is not set for the boot_cpu, | ||
186 | * it is only set for ASPs (see smpboot.S) | ||
187 | */ | ||
188 | if (cpu_ready[i]) { | ||
189 | cpumask_set_cpu(i, &phys_cpu_present_mask); | ||
190 | __cpu_number_map[i] = num_cpus; | ||
191 | __cpu_logical_map[num_cpus] = i; | ||
192 | set_cpu_possible(num_cpus, true); | ||
193 | node = nlm_hwtid_to_node(i); | ||
194 | cpumask_set_cpu(num_cpus, &nlm_get_node(node)->cpumask); | ||
195 | ++num_cpus; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | pr_info("Physical CPU mask: %*pb\n", | ||
200 | cpumask_pr_args(&phys_cpu_present_mask)); | ||
201 | pr_info("Possible CPU mask: %*pb\n", | ||
202 | cpumask_pr_args(cpu_possible_mask)); | ||
203 | |||
204 | /* check with the cores we have woken up */ | ||
205 | for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) | ||
206 | ncore += hweight32(nlm_get_node(i)->coremask); | ||
207 | |||
208 | pr_info("Detected (%dc%dt) %d Slave CPU(s)\n", ncore, | ||
209 | nlm_threads_per_core, num_cpus); | ||
210 | |||
211 | /* switch NMI handler to boot CPUs */ | ||
212 | nlm_set_nmi_handler(nlm_boot_secondary_cpus); | ||
213 | } | ||
214 | |||
215 | static int nlm_parse_cpumask(cpumask_t *wakeup_mask) | ||
216 | { | ||
217 | uint32_t core0_thr_mask, core_thr_mask; | ||
218 | int threadmode, i, j; | ||
219 | |||
220 | core0_thr_mask = 0; | ||
221 | for (i = 0; i < NLM_THREADS_PER_CORE; i++) | ||
222 | if (cpumask_test_cpu(i, wakeup_mask)) | ||
223 | core0_thr_mask |= (1 << i); | ||
224 | switch (core0_thr_mask) { | ||
225 | case 1: | ||
226 | nlm_threads_per_core = 1; | ||
227 | threadmode = 0; | ||
228 | break; | ||
229 | case 3: | ||
230 | nlm_threads_per_core = 2; | ||
231 | threadmode = 2; | ||
232 | break; | ||
233 | case 0xf: | ||
234 | nlm_threads_per_core = 4; | ||
235 | threadmode = 3; | ||
236 | break; | ||
237 | default: | ||
238 | goto unsupp; | ||
239 | } | ||
240 | |||
241 | /* Verify other cores CPU masks */ | ||
242 | for (i = 0; i < NR_CPUS; i += NLM_THREADS_PER_CORE) { | ||
243 | core_thr_mask = 0; | ||
244 | for (j = 0; j < NLM_THREADS_PER_CORE; j++) | ||
245 | if (cpumask_test_cpu(i + j, wakeup_mask)) | ||
246 | core_thr_mask |= (1 << j); | ||
247 | if (core_thr_mask != 0 && core_thr_mask != core0_thr_mask) | ||
248 | goto unsupp; | ||
249 | } | ||
250 | return threadmode; | ||
251 | |||
252 | unsupp: | ||
253 | panic("Unsupported CPU mask %*pb", cpumask_pr_args(wakeup_mask)); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | int nlm_wakeup_secondary_cpus(void) | ||
258 | { | ||
259 | u32 *reset_data; | ||
260 | int threadmode; | ||
261 | |||
262 | /* verify the mask and setup core config variables */ | ||
263 | threadmode = nlm_parse_cpumask(&nlm_cpumask); | ||
264 | |||
265 | /* Setup CPU init parameters */ | ||
266 | reset_data = nlm_get_boot_data(BOOT_THREAD_MODE); | ||
267 | *reset_data = threadmode; | ||
268 | |||
269 | #ifdef CONFIG_CPU_XLP | ||
270 | xlp_wakeup_secondary_cpus(); | ||
271 | #else | ||
272 | xlr_wakeup_secondary_cpus(); | ||
273 | #endif | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | const struct plat_smp_ops nlm_smp_ops = { | ||
278 | .send_ipi_single = nlm_send_ipi_single, | ||
279 | .send_ipi_mask = nlm_send_ipi_mask, | ||
280 | .init_secondary = nlm_init_secondary, | ||
281 | .smp_finish = nlm_smp_finish, | ||
282 | .boot_secondary = nlm_boot_secondary, | ||
283 | .smp_setup = nlm_smp_setup, | ||
284 | .prepare_cpus = nlm_prepare_cpus, | ||
285 | }; | ||
diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S new file mode 100644 index 000000000..509c1a7e7 --- /dev/null +++ b/arch/mips/netlogic/common/smpboot.S | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | |||
36 | #include <asm/asm.h> | ||
37 | #include <asm/asm-offsets.h> | ||
38 | #include <asm/regdef.h> | ||
39 | #include <asm/mipsregs.h> | ||
40 | #include <asm/stackframe.h> | ||
41 | #include <asm/asmmacro.h> | ||
42 | #include <asm/addrspace.h> | ||
43 | |||
44 | #include <asm/netlogic/common.h> | ||
45 | |||
46 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
47 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
48 | #include <asm/netlogic/xlp-hal/sys.h> | ||
49 | #include <asm/netlogic/xlp-hal/cpucontrol.h> | ||
50 | |||
51 | .set noreorder | ||
52 | .set noat | ||
53 | .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ | ||
54 | |||
55 | /* Called by the boot cpu to wake up its sibling threads */ | ||
56 | NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) | ||
57 | /* CPU register contents lost when enabling threads, save them first */ | ||
58 | SAVE_ALL | ||
59 | sync | ||
60 | /* find the location to which nlm_boot_siblings was relocated */ | ||
61 | li t0, CKSEG1ADDR(RESET_VEC_PHYS) | ||
62 | PTR_LA t1, nlm_reset_entry | ||
63 | PTR_LA t2, nlm_boot_siblings | ||
64 | dsubu t2, t1 | ||
65 | daddu t2, t0 | ||
66 | /* call it */ | ||
67 | jalr t2 | ||
68 | nop | ||
69 | RESTORE_ALL | ||
70 | jr ra | ||
71 | nop | ||
72 | END(xlp_boot_core0_siblings) | ||
73 | |||
74 | NESTED(nlm_boot_secondary_cpus, 16, sp) | ||
75 | /* Initialize CP0 Status */ | ||
76 | move t1, zero | ||
77 | #ifdef CONFIG_64BIT | ||
78 | ori t1, ST0_KX | ||
79 | #endif | ||
80 | mtc0 t1, CP0_STATUS | ||
81 | PTR_LA t1, nlm_next_sp | ||
82 | PTR_L sp, 0(t1) | ||
83 | PTR_LA t1, nlm_next_gp | ||
84 | PTR_L gp, 0(t1) | ||
85 | |||
86 | /* a0 has the processor id */ | ||
87 | mfc0 a0, CP0_EBASE | ||
88 | andi a0, 0x3ff /* a0 <- node/core */ | ||
89 | PTR_LA t0, nlm_early_init_secondary | ||
90 | jalr t0 | ||
91 | nop | ||
92 | |||
93 | PTR_LA t0, smp_bootstrap | ||
94 | jr t0 | ||
95 | nop | ||
96 | END(nlm_boot_secondary_cpus) | ||
97 | |||
98 | /* | ||
99 | * In case of RMIboot bootloader which is used on XLR boards, the CPUs | ||
100 | * be already woken up and waiting in bootloader code. | ||
101 | * This will get them out of the bootloader code and into linux. Needed | ||
102 | * because the bootloader area will be taken and initialized by linux. | ||
103 | */ | ||
104 | NESTED(nlm_rmiboot_preboot, 16, sp) | ||
105 | mfc0 t0, $15, 1 /* read ebase */ | ||
106 | andi t0, 0x1f /* t0 has the processor_id() */ | ||
107 | andi t2, t0, 0x3 /* thread num */ | ||
108 | sll t0, 2 /* offset in cpu array */ | ||
109 | |||
110 | li t3, CKSEG1ADDR(RESET_DATA_PHYS) | ||
111 | ADDIU t1, t3, BOOT_CPU_READY | ||
112 | ADDU t1, t0 | ||
113 | li t3, 1 | ||
114 | sw t3, 0(t1) | ||
115 | |||
116 | bnez t2, 1f /* skip thread programming */ | ||
117 | nop /* for thread id != 0 */ | ||
118 | |||
119 | /* | ||
120 | * XLR MMU setup only for first thread in core | ||
121 | */ | ||
122 | li t0, 0x400 | ||
123 | mfcr t1, t0 | ||
124 | li t2, 6 /* XLR thread mode mask */ | ||
125 | nor t3, t2, zero | ||
126 | and t2, t1, t2 /* t2 - current thread mode */ | ||
127 | li v0, CKSEG1ADDR(RESET_DATA_PHYS) | ||
128 | lw v1, BOOT_THREAD_MODE(v0) /* v1 - new thread mode */ | ||
129 | sll v1, 1 | ||
130 | beq v1, t2, 1f /* same as request value */ | ||
131 | nop /* nothing to do */ | ||
132 | |||
133 | and t2, t1, t3 /* mask out old thread mode */ | ||
134 | or t1, t2, v1 /* put in new value */ | ||
135 | mtcr t1, t0 /* update core control */ | ||
136 | |||
137 | /* wait for NMI to hit */ | ||
138 | 1: wait | ||
139 | b 1b | ||
140 | nop | ||
141 | END(nlm_rmiboot_preboot) | ||
diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c new file mode 100644 index 000000000..cbbf0d482 --- /dev/null +++ b/arch/mips/netlogic/common/time.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include <asm/time.h> | ||
38 | #include <asm/cpu-features.h> | ||
39 | |||
40 | #include <asm/netlogic/interrupt.h> | ||
41 | #include <asm/netlogic/common.h> | ||
42 | #include <asm/netlogic/haldefs.h> | ||
43 | |||
44 | #if defined(CONFIG_CPU_XLP) | ||
45 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
46 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
47 | #include <asm/netlogic/xlp-hal/sys.h> | ||
48 | #include <asm/netlogic/xlp-hal/pic.h> | ||
49 | #elif defined(CONFIG_CPU_XLR) | ||
50 | #include <asm/netlogic/xlr/iomap.h> | ||
51 | #include <asm/netlogic/xlr/pic.h> | ||
52 | #include <asm/netlogic/xlr/xlr.h> | ||
53 | #else | ||
54 | #error "Unknown CPU" | ||
55 | #endif | ||
56 | |||
57 | unsigned int get_c0_compare_int(void) | ||
58 | { | ||
59 | return IRQ_TIMER; | ||
60 | } | ||
61 | |||
62 | static u64 nlm_get_pic_timer(struct clocksource *cs) | ||
63 | { | ||
64 | uint64_t picbase = nlm_get_node(0)->picbase; | ||
65 | |||
66 | return ~nlm_pic_read_timer(picbase, PIC_CLOCK_TIMER); | ||
67 | } | ||
68 | |||
69 | static u64 nlm_get_pic_timer32(struct clocksource *cs) | ||
70 | { | ||
71 | uint64_t picbase = nlm_get_node(0)->picbase; | ||
72 | |||
73 | return ~nlm_pic_read_timer32(picbase, PIC_CLOCK_TIMER); | ||
74 | } | ||
75 | |||
76 | static struct clocksource csrc_pic = { | ||
77 | .name = "PIC", | ||
78 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
79 | }; | ||
80 | |||
81 | static void nlm_init_pic_timer(void) | ||
82 | { | ||
83 | uint64_t picbase = nlm_get_node(0)->picbase; | ||
84 | u32 picfreq; | ||
85 | |||
86 | nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); | ||
87 | if (current_cpu_data.cputype == CPU_XLR) { | ||
88 | csrc_pic.mask = CLOCKSOURCE_MASK(32); | ||
89 | csrc_pic.read = nlm_get_pic_timer32; | ||
90 | } else { | ||
91 | csrc_pic.mask = CLOCKSOURCE_MASK(64); | ||
92 | csrc_pic.read = nlm_get_pic_timer; | ||
93 | } | ||
94 | csrc_pic.rating = 1000; | ||
95 | picfreq = pic_timer_freq(); | ||
96 | clocksource_register_hz(&csrc_pic, picfreq); | ||
97 | pr_info("PIC clock source added, frequency %d\n", picfreq); | ||
98 | } | ||
99 | |||
100 | void __init plat_time_init(void) | ||
101 | { | ||
102 | nlm_init_pic_timer(); | ||
103 | mips_hpt_frequency = nlm_get_cpu_frequency(); | ||
104 | if (current_cpu_type() == CPU_XLR) | ||
105 | preset_lpj = mips_hpt_frequency / (3 * HZ); | ||
106 | else | ||
107 | preset_lpj = mips_hpt_frequency / (2 * HZ); | ||
108 | pr_info("MIPS counter frequency [%ld]\n", | ||
109 | (unsigned long)mips_hpt_frequency); | ||
110 | } | ||
diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile new file mode 100644 index 000000000..d62465717 --- /dev/null +++ b/arch/mips/netlogic/xlp/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | obj-y += setup.o nlm_hal.o cop2-ex.o dt.o | ||
3 | obj-$(CONFIG_SMP) += wakeup.o | ||
4 | ifdef CONFIG_USB | ||
5 | obj-y += usb-init.o | ||
6 | obj-y += usb-init-xlp2.o | ||
7 | endif | ||
8 | ifdef CONFIG_SATA_AHCI | ||
9 | obj-y += ahci-init.o | ||
10 | obj-y += ahci-init-xlp2.o | ||
11 | endif | ||
diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c new file mode 100644 index 000000000..c11b9c7dc --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2014 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/irq.h> | ||
41 | #include <linux/bitops.h> | ||
42 | #include <linux/pci_ids.h> | ||
43 | #include <linux/nodemask.h> | ||
44 | |||
45 | #include <asm/cpu.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | |||
48 | #include <asm/netlogic/common.h> | ||
49 | #include <asm/netlogic/haldefs.h> | ||
50 | #include <asm/netlogic/mips-extns.h> | ||
51 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
52 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
53 | |||
54 | #define SATA_CTL 0x0 | ||
55 | #define SATA_STATUS 0x1 /* Status Reg */ | ||
56 | #define SATA_INT 0x2 /* Interrupt Reg */ | ||
57 | #define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ | ||
58 | #define SATA_BIU_TIMEOUT 0x4 | ||
59 | #define AXIWRSPERRLOG 0x5 | ||
60 | #define AXIRDSPERRLOG 0x6 | ||
61 | #define BiuTimeoutLow 0x7 | ||
62 | #define BiuTimeoutHi 0x8 | ||
63 | #define BiuSlvErLow 0x9 | ||
64 | #define BiuSlvErHi 0xa | ||
65 | #define IO_CONFIG_SWAP_DIS 0xb | ||
66 | #define CR_REG_TIMER 0xc | ||
67 | #define CORE_ID 0xd | ||
68 | #define AXI_SLAVE_OPT1 0xe | ||
69 | #define PHY_MEM_ACCESS 0xf | ||
70 | #define PHY0_CNTRL 0x10 | ||
71 | #define PHY0_STAT 0x11 | ||
72 | #define PHY0_RX_ALIGN 0x12 | ||
73 | #define PHY0_RX_EQ_LO 0x13 | ||
74 | #define PHY0_RX_EQ_HI 0x14 | ||
75 | #define PHY0_BIST_LOOP 0x15 | ||
76 | #define PHY1_CNTRL 0x16 | ||
77 | #define PHY1_STAT 0x17 | ||
78 | #define PHY1_RX_ALIGN 0x18 | ||
79 | #define PHY1_RX_EQ_LO 0x19 | ||
80 | #define PHY1_RX_EQ_HI 0x1a | ||
81 | #define PHY1_BIST_LOOP 0x1b | ||
82 | #define RdExBase 0x1c | ||
83 | #define RdExLimit 0x1d | ||
84 | #define CacheAllocBase 0x1e | ||
85 | #define CacheAllocLimit 0x1f | ||
86 | #define BiuSlaveCmdGstNum 0x20 | ||
87 | |||
88 | /*SATA_CTL Bits */ | ||
89 | #define SATA_RST_N BIT(0) /* Active low reset sata_core phy */ | ||
90 | #define SataCtlReserve0 BIT(1) | ||
91 | #define M_CSYSREQ BIT(2) /* AXI master low power, not used */ | ||
92 | #define S_CSYSREQ BIT(3) /* AXI slave low power, not used */ | ||
93 | #define P0_CP_DET BIT(8) /* Reserved, bring in from pad */ | ||
94 | #define P0_MP_SW BIT(9) /* Mech Switch */ | ||
95 | #define P0_DISABLE BIT(10) /* disable p0 */ | ||
96 | #define P0_ACT_LED_EN BIT(11) /* Active LED enable */ | ||
97 | #define P0_IRST_HARD_SYNTH BIT(12) /* PHY hard synth reset */ | ||
98 | #define P0_IRST_HARD_TXRX BIT(13) /* PHY lane hard reset */ | ||
99 | #define P0_IRST_POR BIT(14) /* PHY power on reset*/ | ||
100 | #define P0_IPDTXL BIT(15) /* PHY Tx lane dis/power down */ | ||
101 | #define P0_IPDRXL BIT(16) /* PHY Rx lane dis/power down */ | ||
102 | #define P0_IPDIPDMSYNTH BIT(17) /* PHY synthesizer dis/porwer down */ | ||
103 | #define P0_CP_POD_EN BIT(18) /* CP_POD enable */ | ||
104 | #define P0_AT_BYPASS BIT(19) /* P0 address translation by pass */ | ||
105 | #define P1_CP_DET BIT(20) /* Reserved,Cold Detect */ | ||
106 | #define P1_MP_SW BIT(21) /* Mech Switch */ | ||
107 | #define P1_DISABLE BIT(22) /* disable p1 */ | ||
108 | #define P1_ACT_LED_EN BIT(23) /* Active LED enable */ | ||
109 | #define P1_IRST_HARD_SYNTH BIT(24) /* PHY hard synth reset */ | ||
110 | #define P1_IRST_HARD_TXRX BIT(25) /* PHY lane hard reset */ | ||
111 | #define P1_IRST_POR BIT(26) /* PHY power on reset*/ | ||
112 | #define P1_IPDTXL BIT(27) /* PHY Tx lane dis/porwer down */ | ||
113 | #define P1_IPDRXL BIT(28) /* PHY Rx lane dis/porwer down */ | ||
114 | #define P1_IPDIPDMSYNTH BIT(29) /* PHY synthesizer dis/porwer down */ | ||
115 | #define P1_CP_POD_EN BIT(30) | ||
116 | #define P1_AT_BYPASS BIT(31) /* P1 address translation by pass */ | ||
117 | |||
118 | /* Status register */ | ||
119 | #define M_CACTIVE BIT(0) /* m_cactive, not used */ | ||
120 | #define S_CACTIVE BIT(1) /* s_cactive, not used */ | ||
121 | #define P0_PHY_READY BIT(8) /* phy is ready */ | ||
122 | #define P0_CP_POD BIT(9) /* Cold PowerOn */ | ||
123 | #define P0_SLUMBER BIT(10) /* power mode slumber */ | ||
124 | #define P0_PATIAL BIT(11) /* power mode patial */ | ||
125 | #define P0_PHY_SIG_DET BIT(12) /* phy dignal detect */ | ||
126 | #define P0_PHY_CALI BIT(13) /* phy calibration done */ | ||
127 | #define P1_PHY_READY BIT(16) /* phy is ready */ | ||
128 | #define P1_CP_POD BIT(17) /* Cold PowerOn */ | ||
129 | #define P1_SLUMBER BIT(18) /* power mode slumber */ | ||
130 | #define P1_PATIAL BIT(19) /* power mode patial */ | ||
131 | #define P1_PHY_SIG_DET BIT(20) /* phy dignal detect */ | ||
132 | #define P1_PHY_CALI BIT(21) /* phy calibration done */ | ||
133 | |||
134 | /* SATA CR_REG_TIMER bits */ | ||
135 | #define CR_TIME_SCALE (0x1000 << 0) | ||
136 | |||
137 | /* SATA PHY specific registers start and end address */ | ||
138 | #define RXCDRCALFOSC0 0x0065 | ||
139 | #define CALDUTY 0x006e | ||
140 | #define RXDPIF 0x8065 | ||
141 | #define PPMDRIFTMAX_HI 0x80A4 | ||
142 | |||
143 | #define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) | ||
144 | #define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) | ||
145 | #define nlm_get_sata_pcibase(node) \ | ||
146 | nlm_pcicfg_base(XLP9XX_IO_SATA_OFFSET(node)) | ||
147 | #define nlm_get_sata_regbase(node) \ | ||
148 | (nlm_get_sata_pcibase(node) + 0x100) | ||
149 | |||
150 | /* SATA PHY config for register block 1 0x0065 .. 0x006e */ | ||
151 | static const u8 sata_phy_config1[] = { | ||
152 | 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 | ||
153 | }; | ||
154 | |||
155 | /* SATA PHY config for register block 2 0x8065 .. 0x80A4 */ | ||
156 | static const u8 sata_phy_config2[] = { | ||
157 | 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, | ||
158 | 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, | ||
159 | 0xCF, 0xF7, 0xE1, 0xF5, 0xFD, 0xFD, 0xFF, 0xFF, | ||
160 | 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, 0xFD, 0xFD, | ||
161 | 0xF5, 0xF5, 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, | ||
162 | 0xFD, 0xFD, 0xF5, 0xF5, 0xFF, 0xFF, 0xFF, 0xF5, | ||
163 | 0x3F, 0x00, 0x32, 0x00, 0x03, 0x01, 0x05, 0x05, | ||
164 | 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, | ||
165 | }; | ||
166 | |||
167 | const int sata_phy_debug = 0; /* set to verify PHY writes */ | ||
168 | |||
169 | static void sata_clear_glue_reg(u64 regbase, u32 off, u32 bit) | ||
170 | { | ||
171 | u32 reg_val; | ||
172 | |||
173 | reg_val = nlm_read_sata_reg(regbase, off); | ||
174 | nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); | ||
175 | } | ||
176 | |||
177 | static void sata_set_glue_reg(u64 regbase, u32 off, u32 bit) | ||
178 | { | ||
179 | u32 reg_val; | ||
180 | |||
181 | reg_val = nlm_read_sata_reg(regbase, off); | ||
182 | nlm_write_sata_reg(regbase, off, (reg_val | bit)); | ||
183 | } | ||
184 | |||
185 | static void write_phy_reg(u64 regbase, u32 addr, u32 physel, u8 data) | ||
186 | { | ||
187 | nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, | ||
188 | (1u << 31) | (physel << 24) | (data << 16) | addr); | ||
189 | udelay(850); | ||
190 | } | ||
191 | |||
192 | static u8 read_phy_reg(u64 regbase, u32 addr, u32 physel) | ||
193 | { | ||
194 | u32 val; | ||
195 | |||
196 | nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, | ||
197 | (0 << 31) | (physel << 24) | (0 << 16) | addr); | ||
198 | udelay(850); | ||
199 | val = nlm_read_sata_reg(regbase, PHY_MEM_ACCESS); | ||
200 | return (val >> 16) & 0xff; | ||
201 | } | ||
202 | |||
203 | static void config_sata_phy(u64 regbase) | ||
204 | { | ||
205 | u32 port, i, reg; | ||
206 | u8 val; | ||
207 | |||
208 | for (port = 0; port < 2; port++) { | ||
209 | for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) | ||
210 | write_phy_reg(regbase, reg, port, sata_phy_config1[i]); | ||
211 | |||
212 | for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) | ||
213 | write_phy_reg(regbase, reg, port, sata_phy_config2[i]); | ||
214 | |||
215 | /* Fix for PHY link up failures at lower temperatures */ | ||
216 | write_phy_reg(regbase, 0x800F, port, 0x1f); | ||
217 | |||
218 | val = read_phy_reg(regbase, 0x0029, port); | ||
219 | write_phy_reg(regbase, 0x0029, port, val | (0x7 << 1)); | ||
220 | |||
221 | val = read_phy_reg(regbase, 0x0056, port); | ||
222 | write_phy_reg(regbase, 0x0056, port, val & ~(1 << 3)); | ||
223 | |||
224 | val = read_phy_reg(regbase, 0x0018, port); | ||
225 | write_phy_reg(regbase, 0x0018, port, val & ~(0x7 << 0)); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void check_phy_register(u64 regbase, u32 addr, u32 physel, u8 xdata) | ||
230 | { | ||
231 | u8 data; | ||
232 | |||
233 | data = read_phy_reg(regbase, addr, physel); | ||
234 | pr_info("PHY read addr = 0x%x physel = %d data = 0x%x %s\n", | ||
235 | addr, physel, data, data == xdata ? "TRUE" : "FALSE"); | ||
236 | } | ||
237 | |||
238 | static void verify_sata_phy_config(u64 regbase) | ||
239 | { | ||
240 | u32 port, i, reg; | ||
241 | |||
242 | for (port = 0; port < 2; port++) { | ||
243 | for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) | ||
244 | check_phy_register(regbase, reg, port, | ||
245 | sata_phy_config1[i]); | ||
246 | |||
247 | for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) | ||
248 | check_phy_register(regbase, reg, port, | ||
249 | sata_phy_config2[i]); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void nlm_sata_firmware_init(int node) | ||
254 | { | ||
255 | u32 reg_val; | ||
256 | u64 regbase; | ||
257 | int n; | ||
258 | |||
259 | pr_info("Initializing XLP9XX On-chip AHCI...\n"); | ||
260 | regbase = nlm_get_sata_regbase(node); | ||
261 | |||
262 | /* Reset port0 */ | ||
263 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_POR); | ||
264 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); | ||
265 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); | ||
266 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDTXL); | ||
267 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDRXL); | ||
268 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); | ||
269 | |||
270 | /* port1 */ | ||
271 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_POR); | ||
272 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); | ||
273 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); | ||
274 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDTXL); | ||
275 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDRXL); | ||
276 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); | ||
277 | udelay(300); | ||
278 | |||
279 | /* Set PHY */ | ||
280 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDTXL); | ||
281 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDRXL); | ||
282 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); | ||
283 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDTXL); | ||
284 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDRXL); | ||
285 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); | ||
286 | |||
287 | udelay(1000); | ||
288 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_POR); | ||
289 | udelay(1000); | ||
290 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_POR); | ||
291 | udelay(1000); | ||
292 | |||
293 | /* setup PHY */ | ||
294 | config_sata_phy(regbase); | ||
295 | if (sata_phy_debug) | ||
296 | verify_sata_phy_config(regbase); | ||
297 | |||
298 | udelay(1000); | ||
299 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); | ||
300 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); | ||
301 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); | ||
302 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); | ||
303 | udelay(300); | ||
304 | |||
305 | /* Override reset in serial PHY mode */ | ||
306 | sata_set_glue_reg(regbase, CR_REG_TIMER, CR_TIME_SCALE); | ||
307 | /* Set reset SATA */ | ||
308 | sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
309 | sata_set_glue_reg(regbase, SATA_CTL, M_CSYSREQ); | ||
310 | sata_set_glue_reg(regbase, SATA_CTL, S_CSYSREQ); | ||
311 | |||
312 | pr_debug("Waiting for PHYs to come up.\n"); | ||
313 | n = 10000; | ||
314 | do { | ||
315 | reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); | ||
316 | if ((reg_val & P1_PHY_READY) && (reg_val & P0_PHY_READY)) | ||
317 | break; | ||
318 | udelay(10); | ||
319 | } while (--n > 0); | ||
320 | |||
321 | if (reg_val & P0_PHY_READY) | ||
322 | pr_info("PHY0 is up.\n"); | ||
323 | else | ||
324 | pr_info("PHY0 is down.\n"); | ||
325 | if (reg_val & P1_PHY_READY) | ||
326 | pr_info("PHY1 is up.\n"); | ||
327 | else | ||
328 | pr_info("PHY1 is down.\n"); | ||
329 | |||
330 | pr_info("XLP AHCI Init Done.\n"); | ||
331 | } | ||
332 | |||
333 | static int __init nlm_ahci_init(void) | ||
334 | { | ||
335 | int node; | ||
336 | |||
337 | if (!cpu_is_xlp9xx()) | ||
338 | return 0; | ||
339 | for (node = 0; node < NLM_NR_NODES; node++) | ||
340 | if (nlm_node_present(node)) | ||
341 | nlm_sata_firmware_init(node); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static void nlm_sata_intr_ack(struct irq_data *data) | ||
346 | { | ||
347 | u64 regbase; | ||
348 | u32 val; | ||
349 | int node; | ||
350 | |||
351 | node = data->irq / NLM_IRQS_PER_NODE; | ||
352 | regbase = nlm_get_sata_regbase(node); | ||
353 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
354 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
355 | } | ||
356 | |||
357 | static void nlm_sata_fixup_bar(struct pci_dev *dev) | ||
358 | { | ||
359 | dev->resource[5] = dev->resource[0]; | ||
360 | memset(&dev->resource[0], 0, sizeof(dev->resource[0])); | ||
361 | } | ||
362 | |||
363 | static void nlm_sata_fixup_final(struct pci_dev *dev) | ||
364 | { | ||
365 | u32 val; | ||
366 | u64 regbase; | ||
367 | int node; | ||
368 | |||
369 | /* Find end bridge function to find node */ | ||
370 | node = xlp_socdev_to_node(dev); | ||
371 | regbase = nlm_get_sata_regbase(node); | ||
372 | |||
373 | /* clear pending interrupts and then enable them */ | ||
374 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
375 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
376 | |||
377 | /* Enable only the core interrupt */ | ||
378 | sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); | ||
379 | |||
380 | dev->irq = nlm_irq_to_xirq(node, PIC_SATA_IRQ); | ||
381 | nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); | ||
382 | } | ||
383 | |||
384 | arch_initcall(nlm_ahci_init); | ||
385 | |||
386 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, | ||
387 | nlm_sata_fixup_bar); | ||
388 | |||
389 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, | ||
390 | nlm_sata_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/ahci-init.c b/arch/mips/netlogic/xlp/ahci-init.c new file mode 100644 index 000000000..92be1a325 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2014 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/irq.h> | ||
41 | #include <linux/bitops.h> | ||
42 | |||
43 | #include <asm/cpu.h> | ||
44 | #include <asm/mipsregs.h> | ||
45 | |||
46 | #include <asm/netlogic/haldefs.h> | ||
47 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
48 | #include <asm/netlogic/common.h> | ||
49 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
50 | #include <asm/netlogic/mips-extns.h> | ||
51 | |||
52 | #define SATA_CTL 0x0 | ||
53 | #define SATA_STATUS 0x1 /* Status Reg */ | ||
54 | #define SATA_INT 0x2 /* Interrupt Reg */ | ||
55 | #define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ | ||
56 | #define SATA_CR_REG_TIMER 0x4 /* PHY Conrol Timer Reg */ | ||
57 | #define SATA_CORE_ID 0x5 /* Core ID Reg */ | ||
58 | #define SATA_AXI_SLAVE_OPT1 0x6 /* AXI Slave Options Reg */ | ||
59 | #define SATA_PHY_LOS_LEV 0x7 /* PHY LOS Level Reg */ | ||
60 | #define SATA_PHY_MULTI 0x8 /* PHY Multiplier Reg */ | ||
61 | #define SATA_PHY_CLK_SEL 0x9 /* Clock Select Reg */ | ||
62 | #define SATA_PHY_AMP1_GEN1 0xa /* PHY Transmit Amplitude Reg 1 */ | ||
63 | #define SATA_PHY_AMP1_GEN2 0xb /* PHY Transmit Amplitude Reg 2 */ | ||
64 | #define SATA_PHY_AMP1_GEN3 0xc /* PHY Transmit Amplitude Reg 3 */ | ||
65 | #define SATA_PHY_PRE1 0xd /* PHY Transmit Preemphasis Reg 1 */ | ||
66 | #define SATA_PHY_PRE2 0xe /* PHY Transmit Preemphasis Reg 2 */ | ||
67 | #define SATA_PHY_PRE3 0xf /* PHY Transmit Preemphasis Reg 3 */ | ||
68 | #define SATA_SPDMODE 0x10 /* Speed Mode Reg */ | ||
69 | #define SATA_REFCLK 0x11 /* Reference Clock Control Reg */ | ||
70 | #define SATA_BYTE_SWAP_DIS 0x12 /* byte swap disable */ | ||
71 | |||
72 | /*SATA_CTL Bits */ | ||
73 | #define SATA_RST_N BIT(0) | ||
74 | #define PHY0_RESET_N BIT(16) | ||
75 | #define PHY1_RESET_N BIT(17) | ||
76 | #define PHY2_RESET_N BIT(18) | ||
77 | #define PHY3_RESET_N BIT(19) | ||
78 | #define M_CSYSREQ BIT(2) | ||
79 | #define S_CSYSREQ BIT(3) | ||
80 | |||
81 | /*SATA_STATUS Bits */ | ||
82 | #define P0_PHY_READY BIT(4) | ||
83 | #define P1_PHY_READY BIT(5) | ||
84 | #define P2_PHY_READY BIT(6) | ||
85 | #define P3_PHY_READY BIT(7) | ||
86 | |||
87 | #define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) | ||
88 | #define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) | ||
89 | #define nlm_get_sata_pcibase(node) \ | ||
90 | nlm_pcicfg_base(XLP_IO_SATA_OFFSET(node)) | ||
91 | /* SATA device specific configuration registers are starts at 0x900 offset */ | ||
92 | #define nlm_get_sata_regbase(node) \ | ||
93 | (nlm_get_sata_pcibase(node) + 0x900) | ||
94 | |||
95 | static void sata_clear_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) | ||
96 | { | ||
97 | uint32_t reg_val; | ||
98 | |||
99 | reg_val = nlm_read_sata_reg(regbase, off); | ||
100 | nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); | ||
101 | } | ||
102 | |||
103 | static void sata_set_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) | ||
104 | { | ||
105 | uint32_t reg_val; | ||
106 | |||
107 | reg_val = nlm_read_sata_reg(regbase, off); | ||
108 | nlm_write_sata_reg(regbase, off, (reg_val | bit)); | ||
109 | } | ||
110 | |||
111 | static void nlm_sata_firmware_init(int node) | ||
112 | { | ||
113 | uint32_t reg_val; | ||
114 | uint64_t regbase; | ||
115 | int i; | ||
116 | |||
117 | pr_info("XLP AHCI Initialization started.\n"); | ||
118 | regbase = nlm_get_sata_regbase(node); | ||
119 | |||
120 | /* Reset SATA */ | ||
121 | sata_clear_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
122 | /* Reset PHY */ | ||
123 | sata_clear_glue_reg(regbase, SATA_CTL, | ||
124 | (PHY3_RESET_N | PHY2_RESET_N | ||
125 | | PHY1_RESET_N | PHY0_RESET_N)); | ||
126 | |||
127 | /* Set SATA */ | ||
128 | sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
129 | /* Set PHY */ | ||
130 | sata_set_glue_reg(regbase, SATA_CTL, | ||
131 | (PHY3_RESET_N | PHY2_RESET_N | ||
132 | | PHY1_RESET_N | PHY0_RESET_N)); | ||
133 | |||
134 | pr_debug("Waiting for PHYs to come up.\n"); | ||
135 | i = 0; | ||
136 | do { | ||
137 | reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); | ||
138 | i++; | ||
139 | } while (((reg_val & 0xF0) != 0xF0) && (i < 10000)); | ||
140 | |||
141 | for (i = 0; i < 4; i++) { | ||
142 | if (reg_val & (P0_PHY_READY << i)) | ||
143 | pr_info("PHY%d is up.\n", i); | ||
144 | else | ||
145 | pr_info("PHY%d is down.\n", i); | ||
146 | } | ||
147 | |||
148 | pr_info("XLP AHCI init done.\n"); | ||
149 | } | ||
150 | |||
151 | static int __init nlm_ahci_init(void) | ||
152 | { | ||
153 | int node = 0; | ||
154 | int chip = read_c0_prid() & PRID_IMP_MASK; | ||
155 | |||
156 | if (chip == PRID_IMP_NETLOGIC_XLP3XX) | ||
157 | nlm_sata_firmware_init(node); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void nlm_sata_intr_ack(struct irq_data *data) | ||
162 | { | ||
163 | uint32_t val = 0; | ||
164 | uint64_t regbase; | ||
165 | |||
166 | regbase = nlm_get_sata_regbase(nlm_nodeid()); | ||
167 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
168 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
169 | } | ||
170 | |||
171 | static void nlm_sata_fixup_bar(struct pci_dev *dev) | ||
172 | { | ||
173 | /* | ||
174 | * The AHCI resource is in BAR 0, move it to | ||
175 | * BAR 5, where it is expected | ||
176 | */ | ||
177 | dev->resource[5] = dev->resource[0]; | ||
178 | memset(&dev->resource[0], 0, sizeof(dev->resource[0])); | ||
179 | } | ||
180 | |||
181 | static void nlm_sata_fixup_final(struct pci_dev *dev) | ||
182 | { | ||
183 | uint32_t val; | ||
184 | uint64_t regbase; | ||
185 | int node = 0; /* XLP3XX does not support multi-node */ | ||
186 | |||
187 | regbase = nlm_get_sata_regbase(node); | ||
188 | |||
189 | /* clear pending interrupts and then enable them */ | ||
190 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
191 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
192 | |||
193 | /* Mask the core interrupt. If all the interrupts | ||
194 | * are enabled there are spurious interrupt flow | ||
195 | * happening, to avoid only enable core interrupt | ||
196 | * mask. | ||
197 | */ | ||
198 | sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); | ||
199 | |||
200 | dev->irq = PIC_SATA_IRQ; | ||
201 | nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); | ||
202 | } | ||
203 | |||
204 | arch_initcall(nlm_ahci_init); | ||
205 | |||
206 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, | ||
207 | nlm_sata_fixup_bar); | ||
208 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, | ||
209 | nlm_sata_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/cop2-ex.c b/arch/mips/netlogic/xlp/cop2-ex.c new file mode 100644 index 000000000..21e439b3d --- /dev/null +++ b/arch/mips/netlogic/xlp/cop2-ex.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2013 Broadcom Corporation. | ||
7 | * | ||
8 | * based on arch/mips/cavium-octeon/cpu.c | ||
9 | * Copyright (C) 2009 Wind River Systems, | ||
10 | * written by Ralf Baechle <ralf@linux-mips.org> | ||
11 | */ | ||
12 | #include <linux/capability.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irqflags.h> | ||
15 | #include <linux/notifier.h> | ||
16 | #include <linux/prefetch.h> | ||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/sched/task_stack.h> | ||
20 | |||
21 | #include <asm/cop2.h> | ||
22 | #include <asm/current.h> | ||
23 | #include <asm/mipsregs.h> | ||
24 | #include <asm/page.h> | ||
25 | |||
26 | #include <asm/netlogic/mips-extns.h> | ||
27 | |||
28 | /* | ||
29 | * 64 bit ops are done in inline assembly to support 32 bit | ||
30 | * compilation | ||
31 | */ | ||
32 | void nlm_cop2_save(struct nlm_cop2_state *r) | ||
33 | { | ||
34 | asm volatile( | ||
35 | ".set push\n" | ||
36 | ".set noat\n" | ||
37 | "dmfc2 $1, $0, 0\n" | ||
38 | "sd $1, 0(%1)\n" | ||
39 | "dmfc2 $1, $0, 1\n" | ||
40 | "sd $1, 8(%1)\n" | ||
41 | "dmfc2 $1, $0, 2\n" | ||
42 | "sd $1, 16(%1)\n" | ||
43 | "dmfc2 $1, $0, 3\n" | ||
44 | "sd $1, 24(%1)\n" | ||
45 | "dmfc2 $1, $1, 0\n" | ||
46 | "sd $1, 0(%2)\n" | ||
47 | "dmfc2 $1, $1, 1\n" | ||
48 | "sd $1, 8(%2)\n" | ||
49 | "dmfc2 $1, $1, 2\n" | ||
50 | "sd $1, 16(%2)\n" | ||
51 | "dmfc2 $1, $1, 3\n" | ||
52 | "sd $1, 24(%2)\n" | ||
53 | ".set pop\n" | ||
54 | : "=m"(*r) | ||
55 | : "r"(r->tx), "r"(r->rx)); | ||
56 | |||
57 | r->tx_msg_status = __read_32bit_c2_register($2, 0); | ||
58 | r->rx_msg_status = __read_32bit_c2_register($3, 0) & 0x0fffffff; | ||
59 | } | ||
60 | |||
61 | void nlm_cop2_restore(struct nlm_cop2_state *r) | ||
62 | { | ||
63 | u32 rstat; | ||
64 | |||
65 | asm volatile( | ||
66 | ".set push\n" | ||
67 | ".set noat\n" | ||
68 | "ld $1, 0(%1)\n" | ||
69 | "dmtc2 $1, $0, 0\n" | ||
70 | "ld $1, 8(%1)\n" | ||
71 | "dmtc2 $1, $0, 1\n" | ||
72 | "ld $1, 16(%1)\n" | ||
73 | "dmtc2 $1, $0, 2\n" | ||
74 | "ld $1, 24(%1)\n" | ||
75 | "dmtc2 $1, $0, 3\n" | ||
76 | "ld $1, 0(%2)\n" | ||
77 | "dmtc2 $1, $1, 0\n" | ||
78 | "ld $1, 8(%2)\n" | ||
79 | "dmtc2 $1, $1, 1\n" | ||
80 | "ld $1, 16(%2)\n" | ||
81 | "dmtc2 $1, $1, 2\n" | ||
82 | "ld $1, 24(%2)\n" | ||
83 | "dmtc2 $1, $1, 3\n" | ||
84 | ".set pop\n" | ||
85 | : : "m"(*r), "r"(r->tx), "r"(r->rx)); | ||
86 | |||
87 | __write_32bit_c2_register($2, 0, r->tx_msg_status); | ||
88 | rstat = __read_32bit_c2_register($3, 0) & 0xf0000000u; | ||
89 | __write_32bit_c2_register($3, 0, r->rx_msg_status | rstat); | ||
90 | } | ||
91 | |||
92 | static int nlm_cu2_call(struct notifier_block *nfb, unsigned long action, | ||
93 | void *data) | ||
94 | { | ||
95 | unsigned long flags; | ||
96 | unsigned int status; | ||
97 | |||
98 | switch (action) { | ||
99 | case CU2_EXCEPTION: | ||
100 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | ||
101 | break; | ||
102 | local_irq_save(flags); | ||
103 | KSTK_STATUS(current) |= ST0_CU2; | ||
104 | status = read_c0_status(); | ||
105 | write_c0_status(status | ST0_CU2); | ||
106 | nlm_cop2_restore(&(current->thread.cp2)); | ||
107 | write_c0_status(status & ~ST0_CU2); | ||
108 | local_irq_restore(flags); | ||
109 | pr_info("COP2 access enabled for pid %d (%s)\n", | ||
110 | current->pid, current->comm); | ||
111 | return NOTIFY_BAD; /* Don't call default notifier */ | ||
112 | } | ||
113 | |||
114 | return NOTIFY_OK; /* Let default notifier send signals */ | ||
115 | } | ||
116 | |||
117 | static int __init nlm_cu2_setup(void) | ||
118 | { | ||
119 | return cu2_notifier(nlm_cu2_call, 0); | ||
120 | } | ||
121 | early_initcall(nlm_cu2_setup); | ||
diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c new file mode 100644 index 000000000..c856f2a3e --- /dev/null +++ b/arch/mips/netlogic/xlp/dt.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2013 Broadcom Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/memblock.h> | ||
37 | |||
38 | #include <linux/of_fdt.h> | ||
39 | #include <linux/of_platform.h> | ||
40 | #include <linux/of_device.h> | ||
41 | |||
42 | #include <asm/prom.h> | ||
43 | |||
44 | extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], __dtb_xlp_fvp_begin[], | ||
45 | __dtb_xlp_gvp_begin[], __dtb_xlp_rvp_begin[]; | ||
46 | static void *xlp_fdt_blob; | ||
47 | |||
48 | void __init *xlp_dt_init(void *fdtp) | ||
49 | { | ||
50 | if (!fdtp) { | ||
51 | switch (current_cpu_data.processor_id & PRID_IMP_MASK) { | ||
52 | #ifdef CONFIG_DT_XLP_RVP | ||
53 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
54 | fdtp = __dtb_xlp_rvp_begin; | ||
55 | break; | ||
56 | #endif | ||
57 | #ifdef CONFIG_DT_XLP_GVP | ||
58 | case PRID_IMP_NETLOGIC_XLP9XX: | ||
59 | fdtp = __dtb_xlp_gvp_begin; | ||
60 | break; | ||
61 | #endif | ||
62 | #ifdef CONFIG_DT_XLP_FVP | ||
63 | case PRID_IMP_NETLOGIC_XLP2XX: | ||
64 | fdtp = __dtb_xlp_fvp_begin; | ||
65 | break; | ||
66 | #endif | ||
67 | #ifdef CONFIG_DT_XLP_SVP | ||
68 | case PRID_IMP_NETLOGIC_XLP3XX: | ||
69 | fdtp = __dtb_xlp_svp_begin; | ||
70 | break; | ||
71 | #endif | ||
72 | #ifdef CONFIG_DT_XLP_EVP | ||
73 | case PRID_IMP_NETLOGIC_XLP8XX: | ||
74 | fdtp = __dtb_xlp_evp_begin; | ||
75 | break; | ||
76 | #endif | ||
77 | default: | ||
78 | /* Pick a built-in if any, and hope for the best */ | ||
79 | fdtp = __dtb_start; | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | xlp_fdt_blob = fdtp; | ||
84 | return fdtp; | ||
85 | } | ||
86 | |||
87 | void __init xlp_early_init_devtree(void) | ||
88 | { | ||
89 | __dt_setup_arch(xlp_fdt_blob); | ||
90 | } | ||
91 | |||
92 | void __init device_tree_init(void) | ||
93 | { | ||
94 | unflatten_and_copy_device_tree(); | ||
95 | } | ||
diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c new file mode 100644 index 000000000..25ee69489 --- /dev/null +++ b/arch/mips/netlogic/xlp/nlm_hal.c | |||
@@ -0,0 +1,508 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/mm.h> | ||
38 | #include <linux/delay.h> | ||
39 | |||
40 | #include <asm/mipsregs.h> | ||
41 | #include <asm/time.h> | ||
42 | |||
43 | #include <asm/netlogic/common.h> | ||
44 | #include <asm/netlogic/haldefs.h> | ||
45 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
46 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
47 | #include <asm/netlogic/xlp-hal/bridge.h> | ||
48 | #include <asm/netlogic/xlp-hal/pic.h> | ||
49 | #include <asm/netlogic/xlp-hal/sys.h> | ||
50 | |||
51 | /* Main initialization */ | ||
52 | void nlm_node_init(int node) | ||
53 | { | ||
54 | struct nlm_soc_info *nodep; | ||
55 | |||
56 | nodep = nlm_get_node(node); | ||
57 | if (node == 0) | ||
58 | nodep->coremask = 1; /* node 0, boot cpu */ | ||
59 | nodep->sysbase = nlm_get_sys_regbase(node); | ||
60 | nodep->picbase = nlm_get_pic_regbase(node); | ||
61 | nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; | ||
62 | if (cpu_is_xlp9xx()) | ||
63 | nodep->socbus = xlp9xx_get_socbus(node); | ||
64 | else | ||
65 | nodep->socbus = 0; | ||
66 | spin_lock_init(&nodep->piclock); | ||
67 | } | ||
68 | |||
69 | static int xlp9xx_irq_to_irt(int irq) | ||
70 | { | ||
71 | switch (irq) { | ||
72 | case PIC_GPIO_IRQ: | ||
73 | return 12; | ||
74 | case PIC_I2C_0_IRQ: | ||
75 | return 125; | ||
76 | case PIC_I2C_1_IRQ: | ||
77 | return 126; | ||
78 | case PIC_I2C_2_IRQ: | ||
79 | return 127; | ||
80 | case PIC_I2C_3_IRQ: | ||
81 | return 128; | ||
82 | case PIC_9XX_XHCI_0_IRQ: | ||
83 | return 114; | ||
84 | case PIC_9XX_XHCI_1_IRQ: | ||
85 | return 115; | ||
86 | case PIC_9XX_XHCI_2_IRQ: | ||
87 | return 116; | ||
88 | case PIC_UART_0_IRQ: | ||
89 | return 133; | ||
90 | case PIC_UART_1_IRQ: | ||
91 | return 134; | ||
92 | case PIC_SATA_IRQ: | ||
93 | return 143; | ||
94 | case PIC_NAND_IRQ: | ||
95 | return 151; | ||
96 | case PIC_SPI_IRQ: | ||
97 | return 152; | ||
98 | case PIC_MMC_IRQ: | ||
99 | return 153; | ||
100 | case PIC_PCIE_LINK_LEGACY_IRQ(0): | ||
101 | case PIC_PCIE_LINK_LEGACY_IRQ(1): | ||
102 | case PIC_PCIE_LINK_LEGACY_IRQ(2): | ||
103 | case PIC_PCIE_LINK_LEGACY_IRQ(3): | ||
104 | return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; | ||
105 | } | ||
106 | return -1; | ||
107 | } | ||
108 | |||
109 | static int xlp_irq_to_irt(int irq) | ||
110 | { | ||
111 | uint64_t pcibase; | ||
112 | int devoff, irt; | ||
113 | |||
114 | devoff = 0; | ||
115 | switch (irq) { | ||
116 | case PIC_UART_0_IRQ: | ||
117 | devoff = XLP_IO_UART0_OFFSET(0); | ||
118 | break; | ||
119 | case PIC_UART_1_IRQ: | ||
120 | devoff = XLP_IO_UART1_OFFSET(0); | ||
121 | break; | ||
122 | case PIC_MMC_IRQ: | ||
123 | devoff = XLP_IO_MMC_OFFSET(0); | ||
124 | break; | ||
125 | case PIC_I2C_0_IRQ: /* I2C will be fixed up */ | ||
126 | case PIC_I2C_1_IRQ: | ||
127 | case PIC_I2C_2_IRQ: | ||
128 | case PIC_I2C_3_IRQ: | ||
129 | if (cpu_is_xlpii()) | ||
130 | devoff = XLP2XX_IO_I2C_OFFSET(0); | ||
131 | else | ||
132 | devoff = XLP_IO_I2C0_OFFSET(0); | ||
133 | break; | ||
134 | case PIC_SATA_IRQ: | ||
135 | devoff = XLP_IO_SATA_OFFSET(0); | ||
136 | break; | ||
137 | case PIC_GPIO_IRQ: | ||
138 | devoff = XLP_IO_GPIO_OFFSET(0); | ||
139 | break; | ||
140 | case PIC_NAND_IRQ: | ||
141 | devoff = XLP_IO_NAND_OFFSET(0); | ||
142 | break; | ||
143 | case PIC_SPI_IRQ: | ||
144 | devoff = XLP_IO_SPI_OFFSET(0); | ||
145 | break; | ||
146 | default: | ||
147 | if (cpu_is_xlpii()) { | ||
148 | switch (irq) { | ||
149 | /* XLP2XX has three XHCI USB controller */ | ||
150 | case PIC_2XX_XHCI_0_IRQ: | ||
151 | devoff = XLP2XX_IO_USB_XHCI0_OFFSET(0); | ||
152 | break; | ||
153 | case PIC_2XX_XHCI_1_IRQ: | ||
154 | devoff = XLP2XX_IO_USB_XHCI1_OFFSET(0); | ||
155 | break; | ||
156 | case PIC_2XX_XHCI_2_IRQ: | ||
157 | devoff = XLP2XX_IO_USB_XHCI2_OFFSET(0); | ||
158 | break; | ||
159 | } | ||
160 | } else { | ||
161 | switch (irq) { | ||
162 | case PIC_EHCI_0_IRQ: | ||
163 | devoff = XLP_IO_USB_EHCI0_OFFSET(0); | ||
164 | break; | ||
165 | case PIC_EHCI_1_IRQ: | ||
166 | devoff = XLP_IO_USB_EHCI1_OFFSET(0); | ||
167 | break; | ||
168 | case PIC_OHCI_0_IRQ: | ||
169 | devoff = XLP_IO_USB_OHCI0_OFFSET(0); | ||
170 | break; | ||
171 | case PIC_OHCI_1_IRQ: | ||
172 | devoff = XLP_IO_USB_OHCI1_OFFSET(0); | ||
173 | break; | ||
174 | case PIC_OHCI_2_IRQ: | ||
175 | devoff = XLP_IO_USB_OHCI2_OFFSET(0); | ||
176 | break; | ||
177 | case PIC_OHCI_3_IRQ: | ||
178 | devoff = XLP_IO_USB_OHCI3_OFFSET(0); | ||
179 | break; | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if (devoff != 0) { | ||
185 | uint32_t val; | ||
186 | |||
187 | pcibase = nlm_pcicfg_base(devoff); | ||
188 | val = nlm_read_reg(pcibase, XLP_PCI_IRTINFO_REG); | ||
189 | if (val == 0xffffffff) { | ||
190 | irt = -1; | ||
191 | } else { | ||
192 | irt = val & 0xffff; | ||
193 | /* HW weirdness, I2C IRT entry has to be fixed up */ | ||
194 | switch (irq) { | ||
195 | case PIC_I2C_1_IRQ: | ||
196 | irt = irt + 1; break; | ||
197 | case PIC_I2C_2_IRQ: | ||
198 | irt = irt + 2; break; | ||
199 | case PIC_I2C_3_IRQ: | ||
200 | irt = irt + 3; break; | ||
201 | } | ||
202 | } | ||
203 | } else if (irq >= PIC_PCIE_LINK_LEGACY_IRQ(0) && | ||
204 | irq <= PIC_PCIE_LINK_LEGACY_IRQ(3)) { | ||
205 | /* HW bug, PCI IRT entries are bad on early silicon, fix */ | ||
206 | irt = PIC_IRT_PCIE_LINK_INDEX(irq - | ||
207 | PIC_PCIE_LINK_LEGACY_IRQ_BASE); | ||
208 | } else { | ||
209 | irt = -1; | ||
210 | } | ||
211 | return irt; | ||
212 | } | ||
213 | |||
214 | int nlm_irq_to_irt(int irq) | ||
215 | { | ||
216 | /* return -2 for irqs without 1-1 mapping */ | ||
217 | if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && irq <= PIC_PCIE_LINK_MSI_IRQ(3)) | ||
218 | return -2; | ||
219 | if (irq >= PIC_PCIE_MSIX_IRQ(0) && irq <= PIC_PCIE_MSIX_IRQ(3)) | ||
220 | return -2; | ||
221 | |||
222 | if (cpu_is_xlp9xx()) | ||
223 | return xlp9xx_irq_to_irt(irq); | ||
224 | else | ||
225 | return xlp_irq_to_irt(irq); | ||
226 | } | ||
227 | |||
228 | static unsigned int nlm_xlp2_get_core_frequency(int node, int core) | ||
229 | { | ||
230 | unsigned int pll_post_div, ctrl_val0, ctrl_val1, denom; | ||
231 | uint64_t num, sysbase, clockbase; | ||
232 | |||
233 | if (cpu_is_xlp9xx()) { | ||
234 | clockbase = nlm_get_clock_regbase(node); | ||
235 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
236 | SYS_9XX_CPU_PLL_CTRL0(core)); | ||
237 | ctrl_val1 = nlm_read_sys_reg(clockbase, | ||
238 | SYS_9XX_CPU_PLL_CTRL1(core)); | ||
239 | } else { | ||
240 | sysbase = nlm_get_node(node)->sysbase; | ||
241 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
242 | SYS_CPU_PLL_CTRL0(core)); | ||
243 | ctrl_val1 = nlm_read_sys_reg(sysbase, | ||
244 | SYS_CPU_PLL_CTRL1(core)); | ||
245 | } | ||
246 | |||
247 | /* Find PLL post divider value */ | ||
248 | switch ((ctrl_val0 >> 24) & 0x7) { | ||
249 | case 1: | ||
250 | pll_post_div = 2; | ||
251 | break; | ||
252 | case 3: | ||
253 | pll_post_div = 4; | ||
254 | break; | ||
255 | case 7: | ||
256 | pll_post_div = 8; | ||
257 | break; | ||
258 | case 6: | ||
259 | pll_post_div = 16; | ||
260 | break; | ||
261 | case 0: | ||
262 | default: | ||
263 | pll_post_div = 1; | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | num = 1000000ULL * (400 * 3 + 100 * (ctrl_val1 & 0x3f)); | ||
268 | denom = 3 * pll_post_div; | ||
269 | do_div(num, denom); | ||
270 | |||
271 | return (unsigned int)num; | ||
272 | } | ||
273 | |||
274 | static unsigned int nlm_xlp_get_core_frequency(int node, int core) | ||
275 | { | ||
276 | unsigned int pll_divf, pll_divr, dfs_div, ext_div; | ||
277 | unsigned int rstval, dfsval, denom; | ||
278 | uint64_t num, sysbase; | ||
279 | |||
280 | sysbase = nlm_get_node(node)->sysbase; | ||
281 | rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); | ||
282 | dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); | ||
283 | pll_divf = ((rstval >> 10) & 0x7f) + 1; | ||
284 | pll_divr = ((rstval >> 8) & 0x3) + 1; | ||
285 | ext_div = ((rstval >> 30) & 0x3) + 1; | ||
286 | dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; | ||
287 | |||
288 | num = 800000000ULL * pll_divf; | ||
289 | denom = 3 * pll_divr * ext_div * dfs_div; | ||
290 | do_div(num, denom); | ||
291 | |||
292 | return (unsigned int)num; | ||
293 | } | ||
294 | |||
295 | unsigned int nlm_get_core_frequency(int node, int core) | ||
296 | { | ||
297 | if (cpu_is_xlpii()) | ||
298 | return nlm_xlp2_get_core_frequency(node, core); | ||
299 | else | ||
300 | return nlm_xlp_get_core_frequency(node, core); | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * Calculate PIC frequency from PLL registers. | ||
305 | * freq_out = (ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13) / | ||
306 | * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) | ||
307 | */ | ||
308 | static unsigned int nlm_xlp2_get_pic_frequency(int node) | ||
309 | { | ||
310 | u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div, cpu_xlp9xx; | ||
311 | u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div; | ||
312 | u64 sysbase, pll_out_freq_num, ref_clk_select, clockbase, ref_clk; | ||
313 | |||
314 | sysbase = nlm_get_node(node)->sysbase; | ||
315 | clockbase = nlm_get_clock_regbase(node); | ||
316 | cpu_xlp9xx = cpu_is_xlp9xx(); | ||
317 | |||
318 | /* Find ref_clk_base */ | ||
319 | if (cpu_xlp9xx) | ||
320 | ref_clk_select = (nlm_read_sys_reg(sysbase, | ||
321 | SYS_9XX_POWER_ON_RESET_CFG) >> 18) & 0x3; | ||
322 | else | ||
323 | ref_clk_select = (nlm_read_sys_reg(sysbase, | ||
324 | SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; | ||
325 | switch (ref_clk_select) { | ||
326 | case 0: | ||
327 | ref_clk = 200000000ULL; | ||
328 | ref_div = 3; | ||
329 | break; | ||
330 | case 1: | ||
331 | ref_clk = 100000000ULL; | ||
332 | ref_div = 1; | ||
333 | break; | ||
334 | case 2: | ||
335 | ref_clk = 125000000ULL; | ||
336 | ref_div = 1; | ||
337 | break; | ||
338 | case 3: | ||
339 | ref_clk = 400000000ULL; | ||
340 | ref_div = 3; | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | /* Find the clock source PLL device for PIC */ | ||
345 | if (cpu_xlp9xx) { | ||
346 | reg_select = nlm_read_sys_reg(clockbase, | ||
347 | SYS_9XX_CLK_DEV_SEL_REG) & 0x3; | ||
348 | switch (reg_select) { | ||
349 | case 0: | ||
350 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
351 | SYS_9XX_PLL_CTRL0); | ||
352 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
353 | SYS_9XX_PLL_CTRL2); | ||
354 | break; | ||
355 | case 1: | ||
356 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
357 | SYS_9XX_PLL_CTRL0_DEVX(0)); | ||
358 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
359 | SYS_9XX_PLL_CTRL2_DEVX(0)); | ||
360 | break; | ||
361 | case 2: | ||
362 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
363 | SYS_9XX_PLL_CTRL0_DEVX(1)); | ||
364 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
365 | SYS_9XX_PLL_CTRL2_DEVX(1)); | ||
366 | break; | ||
367 | case 3: | ||
368 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
369 | SYS_9XX_PLL_CTRL0_DEVX(2)); | ||
370 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
371 | SYS_9XX_PLL_CTRL2_DEVX(2)); | ||
372 | break; | ||
373 | } | ||
374 | } else { | ||
375 | reg_select = (nlm_read_sys_reg(sysbase, | ||
376 | SYS_CLK_DEV_SEL_REG) >> 22) & 0x3; | ||
377 | switch (reg_select) { | ||
378 | case 0: | ||
379 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
380 | SYS_PLL_CTRL0); | ||
381 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
382 | SYS_PLL_CTRL2); | ||
383 | break; | ||
384 | case 1: | ||
385 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
386 | SYS_PLL_CTRL0_DEVX(0)); | ||
387 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
388 | SYS_PLL_CTRL2_DEVX(0)); | ||
389 | break; | ||
390 | case 2: | ||
391 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
392 | SYS_PLL_CTRL0_DEVX(1)); | ||
393 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
394 | SYS_PLL_CTRL2_DEVX(1)); | ||
395 | break; | ||
396 | case 3: | ||
397 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
398 | SYS_PLL_CTRL0_DEVX(2)); | ||
399 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
400 | SYS_PLL_CTRL2_DEVX(2)); | ||
401 | break; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | vco_post_div = (ctrl_val0 >> 5) & 0x7; | ||
406 | pll_post_div = (ctrl_val0 >> 24) & 0x7; | ||
407 | mdiv = ctrl_val2 & 0xff; | ||
408 | fdiv = (ctrl_val2 >> 8) & 0x1fff; | ||
409 | |||
410 | /* Find PLL post divider value */ | ||
411 | switch (pll_post_div) { | ||
412 | case 1: | ||
413 | pll_post_div = 2; | ||
414 | break; | ||
415 | case 3: | ||
416 | pll_post_div = 4; | ||
417 | break; | ||
418 | case 7: | ||
419 | pll_post_div = 8; | ||
420 | break; | ||
421 | case 6: | ||
422 | pll_post_div = 16; | ||
423 | break; | ||
424 | case 0: | ||
425 | default: | ||
426 | pll_post_div = 1; | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | fdiv = fdiv/(1 << 13); | ||
431 | pll_out_freq_num = ((ref_clk >> 1) * (6 + mdiv)) + fdiv; | ||
432 | pll_out_freq_den = (1 << vco_post_div) * pll_post_div * ref_div; | ||
433 | |||
434 | if (pll_out_freq_den > 0) | ||
435 | do_div(pll_out_freq_num, pll_out_freq_den); | ||
436 | |||
437 | /* PIC post divider, which happens after PLL */ | ||
438 | if (cpu_xlp9xx) | ||
439 | pic_div = nlm_read_sys_reg(clockbase, | ||
440 | SYS_9XX_CLK_DEV_DIV_REG) & 0x3; | ||
441 | else | ||
442 | pic_div = (nlm_read_sys_reg(sysbase, | ||
443 | SYS_CLK_DEV_DIV_REG) >> 22) & 0x3; | ||
444 | do_div(pll_out_freq_num, 1 << pic_div); | ||
445 | |||
446 | return pll_out_freq_num; | ||
447 | } | ||
448 | |||
449 | unsigned int nlm_get_pic_frequency(int node) | ||
450 | { | ||
451 | if (cpu_is_xlpii()) | ||
452 | return nlm_xlp2_get_pic_frequency(node); | ||
453 | else | ||
454 | return 133333333; | ||
455 | } | ||
456 | |||
457 | unsigned int nlm_get_cpu_frequency(void) | ||
458 | { | ||
459 | return nlm_get_core_frequency(0, 0); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Fills upto 8 pairs of entries containing the DRAM map of a node | ||
464 | * if node < 0, get dram map for all nodes | ||
465 | */ | ||
466 | int nlm_get_dram_map(int node, uint64_t *dram_map, int nentries) | ||
467 | { | ||
468 | uint64_t bridgebase, base, lim; | ||
469 | uint32_t val; | ||
470 | unsigned int barreg, limreg, xlatreg; | ||
471 | int i, n, rv; | ||
472 | |||
473 | /* Look only at mapping on Node 0, we don't handle crazy configs */ | ||
474 | bridgebase = nlm_get_bridge_regbase(0); | ||
475 | rv = 0; | ||
476 | for (i = 0; i < 8; i++) { | ||
477 | if (rv + 1 >= nentries) | ||
478 | break; | ||
479 | if (cpu_is_xlp9xx()) { | ||
480 | barreg = BRIDGE_9XX_DRAM_BAR(i); | ||
481 | limreg = BRIDGE_9XX_DRAM_LIMIT(i); | ||
482 | xlatreg = BRIDGE_9XX_DRAM_NODE_TRANSLN(i); | ||
483 | } else { | ||
484 | barreg = BRIDGE_DRAM_BAR(i); | ||
485 | limreg = BRIDGE_DRAM_LIMIT(i); | ||
486 | xlatreg = BRIDGE_DRAM_NODE_TRANSLN(i); | ||
487 | } | ||
488 | if (node >= 0) { | ||
489 | /* node specified, get node mapping of BAR */ | ||
490 | val = nlm_read_bridge_reg(bridgebase, xlatreg); | ||
491 | n = (val >> 1) & 0x3; | ||
492 | if (n != node) | ||
493 | continue; | ||
494 | } | ||
495 | val = nlm_read_bridge_reg(bridgebase, barreg); | ||
496 | val = (val >> 12) & 0xfffff; | ||
497 | base = (uint64_t) val << 20; | ||
498 | val = nlm_read_bridge_reg(bridgebase, limreg); | ||
499 | val = (val >> 12) & 0xfffff; | ||
500 | if (val == 0) /* BAR not used */ | ||
501 | continue; | ||
502 | lim = ((uint64_t)val + 1) << 20; | ||
503 | dram_map[rv] = base; | ||
504 | dram_map[rv + 1] = lim; | ||
505 | rv += 2; | ||
506 | } | ||
507 | return rv; | ||
508 | } | ||
diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c new file mode 100644 index 000000000..9adc0c1b4 --- /dev/null +++ b/arch/mips/netlogic/xlp/setup.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/of_fdt.h> | ||
37 | #include <linux/memblock.h> | ||
38 | |||
39 | #include <asm/idle.h> | ||
40 | #include <asm/reboot.h> | ||
41 | #include <asm/time.h> | ||
42 | #include <asm/bootinfo.h> | ||
43 | |||
44 | #include <asm/netlogic/haldefs.h> | ||
45 | #include <asm/netlogic/common.h> | ||
46 | |||
47 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
48 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
49 | #include <asm/netlogic/xlp-hal/sys.h> | ||
50 | |||
51 | uint64_t nlm_io_base; | ||
52 | struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; | ||
53 | cpumask_t nlm_cpumask = CPU_MASK_CPU0; | ||
54 | unsigned int nlm_threads_per_core; | ||
55 | |||
56 | static void nlm_linux_exit(void) | ||
57 | { | ||
58 | uint64_t sysbase = nlm_get_node(0)->sysbase; | ||
59 | |||
60 | if (cpu_is_xlp9xx()) | ||
61 | nlm_write_sys_reg(sysbase, SYS_9XX_CHIP_RESET, 1); | ||
62 | else | ||
63 | nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); | ||
64 | for ( ; ; ) | ||
65 | cpu_wait(); | ||
66 | } | ||
67 | |||
68 | static void nlm_fixup_mem(void) | ||
69 | { | ||
70 | const int pref_backup = 512; | ||
71 | struct memblock_region *mem; | ||
72 | |||
73 | for_each_mem_region(mem) { | ||
74 | memblock_remove(mem->base + mem->size - pref_backup, | ||
75 | pref_backup); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void __init xlp_init_mem_from_bars(void) | ||
80 | { | ||
81 | uint64_t map[16]; | ||
82 | int i, n; | ||
83 | |||
84 | n = nlm_get_dram_map(-1, map, ARRAY_SIZE(map)); /* -1 : all nodes */ | ||
85 | for (i = 0; i < n; i += 2) { | ||
86 | /* exclude 0x1000_0000-0x2000_0000, u-boot device */ | ||
87 | if (map[i] <= 0x10000000 && map[i+1] > 0x10000000) | ||
88 | map[i+1] = 0x10000000; | ||
89 | if (map[i] > 0x10000000 && map[i] < 0x20000000) | ||
90 | map[i] = 0x20000000; | ||
91 | |||
92 | memblock_add(map[i], map[i+1] - map[i]); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void __init plat_mem_setup(void) | ||
97 | { | ||
98 | #ifdef CONFIG_SMP | ||
99 | nlm_wakeup_secondary_cpus(); | ||
100 | |||
101 | /* update TLB size after waking up threads */ | ||
102 | current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; | ||
103 | |||
104 | register_smp_ops(&nlm_smp_ops); | ||
105 | #endif | ||
106 | _machine_restart = (void (*)(char *))nlm_linux_exit; | ||
107 | _machine_halt = nlm_linux_exit; | ||
108 | pm_power_off = nlm_linux_exit; | ||
109 | |||
110 | /* memory and bootargs from DT */ | ||
111 | xlp_early_init_devtree(); | ||
112 | |||
113 | if (memblock_end_of_DRAM() == 0) { | ||
114 | pr_info("Using DRAM BARs for memory map.\n"); | ||
115 | xlp_init_mem_from_bars(); | ||
116 | } | ||
117 | /* Calculate and setup wired entries for mapped kernel */ | ||
118 | nlm_fixup_mem(); | ||
119 | } | ||
120 | |||
121 | const char *get_system_type(void) | ||
122 | { | ||
123 | switch (read_c0_prid() & PRID_IMP_MASK) { | ||
124 | case PRID_IMP_NETLOGIC_XLP9XX: | ||
125 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
126 | case PRID_IMP_NETLOGIC_XLP2XX: | ||
127 | return "Broadcom XLPII Series"; | ||
128 | default: | ||
129 | return "Netlogic XLP Series"; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | void __init prom_free_prom_memory(void) | ||
134 | { | ||
135 | /* Nothing yet */ | ||
136 | } | ||
137 | |||
138 | void xlp_mmu_init(void) | ||
139 | { | ||
140 | u32 conf4; | ||
141 | |||
142 | if (cpu_is_xlpii()) { | ||
143 | /* XLPII series has extended pagesize in config 4 */ | ||
144 | conf4 = read_c0_config4() & ~0x1f00u; | ||
145 | write_c0_config4(conf4 | ((PAGE_SHIFT - 10) / 2 << 8)); | ||
146 | } else { | ||
147 | /* enable extended TLB and Large Fixed TLB */ | ||
148 | write_c0_config6(read_c0_config6() | 0x24); | ||
149 | |||
150 | /* set page mask of extended Fixed TLB in config7 */ | ||
151 | write_c0_config7(PM_DEFAULT_MASK >> | ||
152 | (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2))); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void nlm_percpu_init(int hwcpuid) | ||
157 | { | ||
158 | } | ||
159 | |||
160 | void __init prom_init(void) | ||
161 | { | ||
162 | void *reset_vec; | ||
163 | |||
164 | nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); | ||
165 | nlm_init_boot_cpu(); | ||
166 | xlp_mmu_init(); | ||
167 | nlm_node_init(0); | ||
168 | xlp_dt_init((void *)(long)fw_arg0); | ||
169 | |||
170 | /* Update reset entry point with CPU init code */ | ||
171 | reset_vec = (void *)CKSEG1ADDR(RESET_VEC_PHYS); | ||
172 | memset(reset_vec, 0, RESET_VEC_SIZE); | ||
173 | memcpy(reset_vec, (void *)nlm_reset_entry, | ||
174 | (nlm_reset_entry_end - nlm_reset_entry)); | ||
175 | |||
176 | #ifdef CONFIG_SMP | ||
177 | cpumask_setall(&nlm_cpumask); | ||
178 | #endif | ||
179 | } | ||
diff --git a/arch/mips/netlogic/xlp/usb-init-xlp2.c b/arch/mips/netlogic/xlp/usb-init-xlp2.c new file mode 100644 index 000000000..2524939a5 --- /dev/null +++ b/arch/mips/netlogic/xlp/usb-init-xlp2.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2013 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/pci_ids.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <linux/irq.h> | ||
43 | |||
44 | #include <asm/netlogic/common.h> | ||
45 | #include <asm/netlogic/haldefs.h> | ||
46 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
47 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
48 | |||
49 | #define XLPII_USB3_CTL_0 0xc0 | ||
50 | #define XLPII_VAUXRST BIT(0) | ||
51 | #define XLPII_VCCRST BIT(1) | ||
52 | #define XLPII_NUM2PORT 9 | ||
53 | #define XLPII_NUM3PORT 13 | ||
54 | #define XLPII_RTUNEREQ BIT(20) | ||
55 | #define XLPII_MS_CSYSREQ BIT(21) | ||
56 | #define XLPII_XS_CSYSREQ BIT(22) | ||
57 | #define XLPII_RETENABLEN BIT(23) | ||
58 | #define XLPII_TX2RX BIT(24) | ||
59 | #define XLPII_XHCIREV BIT(25) | ||
60 | #define XLPII_ECCDIS BIT(26) | ||
61 | |||
62 | #define XLPII_USB3_INT_REG 0xc2 | ||
63 | #define XLPII_USB3_INT_MASK 0xc3 | ||
64 | |||
65 | #define XLPII_USB_PHY_TEST 0xc6 | ||
66 | #define XLPII_PRESET BIT(0) | ||
67 | #define XLPII_ATERESET BIT(1) | ||
68 | #define XLPII_LOOPEN BIT(2) | ||
69 | #define XLPII_TESTPDHSP BIT(3) | ||
70 | #define XLPII_TESTPDSSP BIT(4) | ||
71 | #define XLPII_TESTBURNIN BIT(5) | ||
72 | |||
73 | #define XLPII_USB_PHY_LOS_LV 0xc9 | ||
74 | #define XLPII_LOSLEV 0 | ||
75 | #define XLPII_LOSBIAS 5 | ||
76 | #define XLPII_SQRXTX 8 | ||
77 | #define XLPII_TXBOOST 11 | ||
78 | #define XLPII_RSLKSEL 16 | ||
79 | #define XLPII_FSEL 20 | ||
80 | |||
81 | #define XLPII_USB_RFCLK_REG 0xcc | ||
82 | #define XLPII_VVLD 30 | ||
83 | |||
84 | #define nlm_read_usb_reg(b, r) nlm_read_reg(b, r) | ||
85 | #define nlm_write_usb_reg(b, r, v) nlm_write_reg(b, r, v) | ||
86 | |||
87 | #define nlm_xlpii_get_usb_pcibase(node, inst) \ | ||
88 | nlm_pcicfg_base(cpu_is_xlp9xx() ? \ | ||
89 | XLP9XX_IO_USB_OFFSET(node, inst) : \ | ||
90 | XLP2XX_IO_USB_OFFSET(node, inst)) | ||
91 | #define nlm_xlpii_get_usb_regbase(node, inst) \ | ||
92 | (nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) | ||
93 | |||
94 | static void xlp2xx_usb_ack(struct irq_data *data) | ||
95 | { | ||
96 | u64 port_addr; | ||
97 | |||
98 | switch (data->irq) { | ||
99 | case PIC_2XX_XHCI_0_IRQ: | ||
100 | port_addr = nlm_xlpii_get_usb_regbase(0, 1); | ||
101 | break; | ||
102 | case PIC_2XX_XHCI_1_IRQ: | ||
103 | port_addr = nlm_xlpii_get_usb_regbase(0, 2); | ||
104 | break; | ||
105 | case PIC_2XX_XHCI_2_IRQ: | ||
106 | port_addr = nlm_xlpii_get_usb_regbase(0, 3); | ||
107 | break; | ||
108 | default: | ||
109 | pr_err("No matching USB irq!\n"); | ||
110 | return; | ||
111 | } | ||
112 | nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); | ||
113 | } | ||
114 | |||
115 | static void xlp9xx_usb_ack(struct irq_data *data) | ||
116 | { | ||
117 | u64 port_addr; | ||
118 | int node, irq; | ||
119 | |||
120 | /* Find the node and irq on the node */ | ||
121 | irq = data->irq % NLM_IRQS_PER_NODE; | ||
122 | node = data->irq / NLM_IRQS_PER_NODE; | ||
123 | |||
124 | switch (irq) { | ||
125 | case PIC_9XX_XHCI_0_IRQ: | ||
126 | port_addr = nlm_xlpii_get_usb_regbase(node, 1); | ||
127 | break; | ||
128 | case PIC_9XX_XHCI_1_IRQ: | ||
129 | port_addr = nlm_xlpii_get_usb_regbase(node, 2); | ||
130 | break; | ||
131 | case PIC_9XX_XHCI_2_IRQ: | ||
132 | port_addr = nlm_xlpii_get_usb_regbase(node, 3); | ||
133 | break; | ||
134 | default: | ||
135 | pr_err("No matching USB irq %d node %d!\n", irq, node); | ||
136 | return; | ||
137 | } | ||
138 | nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); | ||
139 | } | ||
140 | |||
141 | static void nlm_xlpii_usb_hw_reset(int node, int port) | ||
142 | { | ||
143 | u64 port_addr, xhci_base, pci_base; | ||
144 | void __iomem *corebase; | ||
145 | u32 val; | ||
146 | |||
147 | port_addr = nlm_xlpii_get_usb_regbase(node, port); | ||
148 | |||
149 | /* Set frequency */ | ||
150 | val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV); | ||
151 | val &= ~(0x3f << XLPII_FSEL); | ||
152 | val |= (0x27 << XLPII_FSEL); | ||
153 | nlm_write_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV, val); | ||
154 | |||
155 | val = nlm_read_usb_reg(port_addr, XLPII_USB_RFCLK_REG); | ||
156 | val |= (1 << XLPII_VVLD); | ||
157 | nlm_write_usb_reg(port_addr, XLPII_USB_RFCLK_REG, val); | ||
158 | |||
159 | /* PHY reset */ | ||
160 | val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_TEST); | ||
161 | val &= (XLPII_ATERESET | XLPII_LOOPEN | XLPII_TESTPDHSP | ||
162 | | XLPII_TESTPDSSP | XLPII_TESTBURNIN); | ||
163 | nlm_write_usb_reg(port_addr, XLPII_USB_PHY_TEST, val); | ||
164 | |||
165 | /* Setup control register */ | ||
166 | val = XLPII_VAUXRST | XLPII_VCCRST | (1 << XLPII_NUM2PORT) | ||
167 | | (1 << XLPII_NUM3PORT) | XLPII_MS_CSYSREQ | XLPII_XS_CSYSREQ | ||
168 | | XLPII_RETENABLEN | XLPII_XHCIREV; | ||
169 | nlm_write_usb_reg(port_addr, XLPII_USB3_CTL_0, val); | ||
170 | |||
171 | /* Enable interrupts */ | ||
172 | nlm_write_usb_reg(port_addr, XLPII_USB3_INT_MASK, 0x00000001); | ||
173 | |||
174 | /* Clear all interrupts */ | ||
175 | nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); | ||
176 | |||
177 | udelay(2000); | ||
178 | |||
179 | /* XHCI configuration at PCI mem */ | ||
180 | pci_base = nlm_xlpii_get_usb_pcibase(node, port); | ||
181 | xhci_base = nlm_read_usb_reg(pci_base, 0x4) & ~0xf; | ||
182 | corebase = ioremap(xhci_base, 0x10000); | ||
183 | if (!corebase) | ||
184 | return; | ||
185 | |||
186 | writel(0x240002, corebase + 0xc2c0); | ||
187 | /* GCTL 0xc110 */ | ||
188 | val = readl(corebase + 0xc110); | ||
189 | val &= ~(0x3 << 12); | ||
190 | val |= (1 << 12); | ||
191 | writel(val, corebase + 0xc110); | ||
192 | udelay(100); | ||
193 | |||
194 | /* PHYCFG 0xc200 */ | ||
195 | val = readl(corebase + 0xc200); | ||
196 | val &= ~(1 << 6); | ||
197 | writel(val, corebase + 0xc200); | ||
198 | udelay(100); | ||
199 | |||
200 | /* PIPECTL 0xc2c0 */ | ||
201 | val = readl(corebase + 0xc2c0); | ||
202 | val &= ~(1 << 17); | ||
203 | writel(val, corebase + 0xc2c0); | ||
204 | |||
205 | iounmap(corebase); | ||
206 | } | ||
207 | |||
208 | static int __init nlm_platform_xlpii_usb_init(void) | ||
209 | { | ||
210 | int node; | ||
211 | |||
212 | if (!cpu_is_xlpii()) | ||
213 | return 0; | ||
214 | |||
215 | if (!cpu_is_xlp9xx()) { | ||
216 | /* XLP 2XX single node */ | ||
217 | pr_info("Initializing 2XX USB Interface\n"); | ||
218 | nlm_xlpii_usb_hw_reset(0, 1); | ||
219 | nlm_xlpii_usb_hw_reset(0, 2); | ||
220 | nlm_xlpii_usb_hw_reset(0, 3); | ||
221 | nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlp2xx_usb_ack); | ||
222 | nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlp2xx_usb_ack); | ||
223 | nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlp2xx_usb_ack); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* XLP 9XX, multi-node */ | ||
228 | pr_info("Initializing 9XX/5XX USB Interface\n"); | ||
229 | for (node = 0; node < NLM_NR_NODES; node++) { | ||
230 | if (!nlm_node_present(node)) | ||
231 | continue; | ||
232 | nlm_xlpii_usb_hw_reset(node, 1); | ||
233 | nlm_xlpii_usb_hw_reset(node, 2); | ||
234 | nlm_xlpii_usb_hw_reset(node, 3); | ||
235 | nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_0_IRQ, xlp9xx_usb_ack); | ||
236 | nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_1_IRQ, xlp9xx_usb_ack); | ||
237 | nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_2_IRQ, xlp9xx_usb_ack); | ||
238 | } | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | arch_initcall(nlm_platform_xlpii_usb_init); | ||
243 | |||
244 | static u64 xlp_usb_dmamask = ~(u32)0; | ||
245 | |||
246 | /* Fixup the IRQ for USB devices which is exist on XLP9XX SOC PCIE bus */ | ||
247 | static void nlm_xlp9xx_usb_fixup_final(struct pci_dev *dev) | ||
248 | { | ||
249 | int node; | ||
250 | |||
251 | node = xlp_socdev_to_node(dev); | ||
252 | dev->dev.dma_mask = &xlp_usb_dmamask; | ||
253 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
254 | switch (dev->devfn) { | ||
255 | case 0x21: | ||
256 | dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_0_IRQ); | ||
257 | break; | ||
258 | case 0x22: | ||
259 | dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_1_IRQ); | ||
260 | break; | ||
261 | case 0x23: | ||
262 | dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_2_IRQ); | ||
263 | break; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* Fixup the IRQ for USB devices which is exist on XLP2XX SOC PCIE bus */ | ||
268 | static void nlm_xlp2xx_usb_fixup_final(struct pci_dev *dev) | ||
269 | { | ||
270 | dev->dev.dma_mask = &xlp_usb_dmamask; | ||
271 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
272 | switch (dev->devfn) { | ||
273 | case 0x21: | ||
274 | dev->irq = PIC_2XX_XHCI_0_IRQ; | ||
275 | break; | ||
276 | case 0x22: | ||
277 | dev->irq = PIC_2XX_XHCI_1_IRQ; | ||
278 | break; | ||
279 | case 0x23: | ||
280 | dev->irq = PIC_2XX_XHCI_2_IRQ; | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_XHCI, | ||
286 | nlm_xlp9xx_usb_fixup_final); | ||
287 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI, | ||
288 | nlm_xlp2xx_usb_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/usb-init.c b/arch/mips/netlogic/xlp/usb-init.c new file mode 100644 index 000000000..f8117985f --- /dev/null +++ b/arch/mips/netlogic/xlp/usb-init.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2012 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/platform_device.h> | ||
41 | |||
42 | #include <asm/netlogic/haldefs.h> | ||
43 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
44 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
45 | |||
46 | /* | ||
47 | * USB glue logic registers, used only during initialization | ||
48 | */ | ||
49 | #define USB_CTL_0 0x01 | ||
50 | #define USB_PHY_0 0x0A | ||
51 | #define USB_PHY_RESET 0x01 | ||
52 | #define USB_PHY_PORT_RESET_0 0x10 | ||
53 | #define USB_PHY_PORT_RESET_1 0x20 | ||
54 | #define USB_CONTROLLER_RESET 0x01 | ||
55 | #define USB_INT_STATUS 0x0E | ||
56 | #define USB_INT_EN 0x0F | ||
57 | #define USB_PHY_INTERRUPT_EN 0x01 | ||
58 | #define USB_OHCI_INTERRUPT_EN 0x02 | ||
59 | #define USB_OHCI_INTERRUPT1_EN 0x04 | ||
60 | #define USB_OHCI_INTERRUPT2_EN 0x08 | ||
61 | #define USB_CTRL_INTERRUPT_EN 0x10 | ||
62 | |||
63 | #define nlm_read_usb_reg(b, r) nlm_read_reg(b, r) | ||
64 | #define nlm_write_usb_reg(b, r, v) nlm_write_reg(b, r, v) | ||
65 | #define nlm_get_usb_pcibase(node, inst) \ | ||
66 | nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst)) | ||
67 | #define nlm_get_usb_regbase(node, inst) \ | ||
68 | (nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) | ||
69 | |||
70 | static void nlm_usb_intr_en(int node, int port) | ||
71 | { | ||
72 | uint32_t val; | ||
73 | uint64_t port_addr; | ||
74 | |||
75 | port_addr = nlm_get_usb_regbase(node, port); | ||
76 | val = nlm_read_usb_reg(port_addr, USB_INT_EN); | ||
77 | val = USB_CTRL_INTERRUPT_EN | USB_OHCI_INTERRUPT_EN | | ||
78 | USB_OHCI_INTERRUPT1_EN | USB_OHCI_INTERRUPT2_EN; | ||
79 | nlm_write_usb_reg(port_addr, USB_INT_EN, val); | ||
80 | } | ||
81 | |||
82 | static void nlm_usb_hw_reset(int node, int port) | ||
83 | { | ||
84 | uint64_t port_addr; | ||
85 | uint32_t val; | ||
86 | |||
87 | /* reset USB phy */ | ||
88 | port_addr = nlm_get_usb_regbase(node, port); | ||
89 | val = nlm_read_usb_reg(port_addr, USB_PHY_0); | ||
90 | val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1); | ||
91 | nlm_write_usb_reg(port_addr, USB_PHY_0, val); | ||
92 | |||
93 | mdelay(100); | ||
94 | val = nlm_read_usb_reg(port_addr, USB_CTL_0); | ||
95 | val &= ~(USB_CONTROLLER_RESET); | ||
96 | val |= 0x4; | ||
97 | nlm_write_usb_reg(port_addr, USB_CTL_0, val); | ||
98 | } | ||
99 | |||
100 | static int __init nlm_platform_usb_init(void) | ||
101 | { | ||
102 | if (cpu_is_xlpii()) | ||
103 | return 0; | ||
104 | |||
105 | pr_info("Initializing USB Interface\n"); | ||
106 | nlm_usb_hw_reset(0, 0); | ||
107 | nlm_usb_hw_reset(0, 3); | ||
108 | |||
109 | /* Enable PHY interrupts */ | ||
110 | nlm_usb_intr_en(0, 0); | ||
111 | nlm_usb_intr_en(0, 3); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | arch_initcall(nlm_platform_usb_init); | ||
117 | |||
118 | static u64 xlp_usb_dmamask = ~(u32)0; | ||
119 | |||
120 | /* Fixup the IRQ for USB devices which is exist on XLP SOC PCIE bus */ | ||
121 | static void nlm_usb_fixup_final(struct pci_dev *dev) | ||
122 | { | ||
123 | dev->dev.dma_mask = &xlp_usb_dmamask; | ||
124 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
125 | switch (dev->devfn) { | ||
126 | case 0x10: | ||
127 | dev->irq = PIC_EHCI_0_IRQ; | ||
128 | break; | ||
129 | case 0x11: | ||
130 | dev->irq = PIC_OHCI_0_IRQ; | ||
131 | break; | ||
132 | case 0x12: | ||
133 | dev->irq = PIC_OHCI_1_IRQ; | ||
134 | break; | ||
135 | case 0x13: | ||
136 | dev->irq = PIC_EHCI_1_IRQ; | ||
137 | break; | ||
138 | case 0x14: | ||
139 | dev->irq = PIC_OHCI_2_IRQ; | ||
140 | break; | ||
141 | case 0x15: | ||
142 | dev->irq = PIC_OHCI_3_IRQ; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_EHCI, | ||
147 | nlm_usb_fixup_final); | ||
148 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_OHCI, | ||
149 | nlm_usb_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c new file mode 100644 index 000000000..d61004dd7 --- /dev/null +++ b/arch/mips/netlogic/xlp/wakeup.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/threads.h> | ||
37 | |||
38 | #include <asm/asm.h> | ||
39 | #include <asm/asm-offsets.h> | ||
40 | #include <asm/mipsregs.h> | ||
41 | #include <asm/addrspace.h> | ||
42 | #include <asm/string.h> | ||
43 | |||
44 | #include <asm/netlogic/haldefs.h> | ||
45 | #include <asm/netlogic/common.h> | ||
46 | #include <asm/netlogic/mips-extns.h> | ||
47 | |||
48 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
49 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
50 | #include <asm/netlogic/xlp-hal/pic.h> | ||
51 | #include <asm/netlogic/xlp-hal/sys.h> | ||
52 | |||
53 | static int xlp_wakeup_core(uint64_t sysbase, int node, int core) | ||
54 | { | ||
55 | uint32_t coremask, value; | ||
56 | int count, resetreg; | ||
57 | |||
58 | coremask = (1 << core); | ||
59 | |||
60 | /* Enable CPU clock in case of 8xx/3xx */ | ||
61 | if (!cpu_is_xlpii()) { | ||
62 | value = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL); | ||
63 | value &= ~coremask; | ||
64 | nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value); | ||
65 | } | ||
66 | |||
67 | /* On 9XX, mark coherent first */ | ||
68 | if (cpu_is_xlp9xx()) { | ||
69 | value = nlm_read_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE); | ||
70 | value &= ~coremask; | ||
71 | nlm_write_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE, value); | ||
72 | } | ||
73 | |||
74 | /* Remove CPU Reset */ | ||
75 | resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET; | ||
76 | value = nlm_read_sys_reg(sysbase, resetreg); | ||
77 | value &= ~coremask; | ||
78 | nlm_write_sys_reg(sysbase, resetreg, value); | ||
79 | |||
80 | /* We are done on 9XX */ | ||
81 | if (cpu_is_xlp9xx()) | ||
82 | return 1; | ||
83 | |||
84 | /* Poll for CPU to mark itself coherent on other type of XLP */ | ||
85 | count = 100000; | ||
86 | do { | ||
87 | value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); | ||
88 | } while ((value & coremask) != 0 && --count > 0); | ||
89 | |||
90 | return count != 0; | ||
91 | } | ||
92 | |||
93 | static int wait_for_cpus(int cpu, int bootcpu) | ||
94 | { | ||
95 | volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); | ||
96 | int i, count, notready; | ||
97 | |||
98 | count = 0x800000; | ||
99 | do { | ||
100 | notready = nlm_threads_per_core; | ||
101 | for (i = 0; i < nlm_threads_per_core; i++) | ||
102 | if (cpu_ready[cpu + i] || (cpu + i) == bootcpu) | ||
103 | --notready; | ||
104 | } while (notready != 0 && --count > 0); | ||
105 | |||
106 | return count != 0; | ||
107 | } | ||
108 | |||
109 | static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) | ||
110 | { | ||
111 | struct nlm_soc_info *nodep; | ||
112 | uint64_t syspcibase, fusebase; | ||
113 | uint32_t syscoremask, mask, fusemask; | ||
114 | int core, n, cpu, ncores; | ||
115 | |||
116 | for (n = 0; n < NLM_NR_NODES; n++) { | ||
117 | if (n != 0) { | ||
118 | /* check if node exists and is online */ | ||
119 | if (cpu_is_xlp9xx()) { | ||
120 | int b = xlp9xx_get_socbus(n); | ||
121 | pr_info("Node %d SoC PCI bus %d.\n", n, b); | ||
122 | if (b == 0) | ||
123 | break; | ||
124 | } else { | ||
125 | syspcibase = nlm_get_sys_pcibase(n); | ||
126 | if (nlm_read_reg(syspcibase, 0) == 0xffffffff) | ||
127 | break; | ||
128 | } | ||
129 | nlm_node_init(n); | ||
130 | } | ||
131 | |||
132 | /* read cores in reset from SYS */ | ||
133 | nodep = nlm_get_node(n); | ||
134 | |||
135 | if (cpu_is_xlp9xx()) { | ||
136 | fusebase = nlm_get_fuse_regbase(n); | ||
137 | fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); | ||
138 | switch (read_c0_prid() & PRID_IMP_MASK) { | ||
139 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
140 | mask = 0xff; | ||
141 | break; | ||
142 | case PRID_IMP_NETLOGIC_XLP9XX: | ||
143 | default: | ||
144 | mask = 0xfffff; | ||
145 | break; | ||
146 | } | ||
147 | } else { | ||
148 | fusemask = nlm_read_sys_reg(nodep->sysbase, | ||
149 | SYS_EFUSE_DEVICE_CFG_STATUS0); | ||
150 | switch (read_c0_prid() & PRID_IMP_MASK) { | ||
151 | case PRID_IMP_NETLOGIC_XLP3XX: | ||
152 | mask = 0xf; | ||
153 | break; | ||
154 | case PRID_IMP_NETLOGIC_XLP2XX: | ||
155 | mask = 0x3; | ||
156 | break; | ||
157 | case PRID_IMP_NETLOGIC_XLP8XX: | ||
158 | default: | ||
159 | mask = 0xff; | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Fused out cores are set in the fusemask, and the remaining | ||
166 | * cores are renumbered to range 0 .. nactive-1 | ||
167 | */ | ||
168 | syscoremask = (1 << hweight32(~fusemask & mask)) - 1; | ||
169 | |||
170 | pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); | ||
171 | ncores = nlm_cores_per_node(); | ||
172 | for (core = 0; core < ncores; core++) { | ||
173 | /* we will be on node 0 core 0 */ | ||
174 | if (n == 0 && core == 0) | ||
175 | continue; | ||
176 | |||
177 | /* see if the core exists */ | ||
178 | if ((syscoremask & (1 << core)) == 0) | ||
179 | continue; | ||
180 | |||
181 | /* see if at least the first hw thread is enabled */ | ||
182 | cpu = (n * ncores + core) * NLM_THREADS_PER_CORE; | ||
183 | if (!cpumask_test_cpu(cpu, wakeup_mask)) | ||
184 | continue; | ||
185 | |||
186 | /* wake up the core */ | ||
187 | if (!xlp_wakeup_core(nodep->sysbase, n, core)) | ||
188 | continue; | ||
189 | |||
190 | /* core is up */ | ||
191 | nodep->coremask |= 1u << core; | ||
192 | |||
193 | /* spin until the hw threads sets their ready */ | ||
194 | if (!wait_for_cpus(cpu, 0)) | ||
195 | pr_err("Node %d : timeout core %d\n", n, core); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | void xlp_wakeup_secondary_cpus(void) | ||
201 | { | ||
202 | /* | ||
203 | * In case of u-boot, the secondaries are in reset | ||
204 | * first wakeup core 0 threads | ||
205 | */ | ||
206 | xlp_boot_core0_siblings(); | ||
207 | if (!wait_for_cpus(0, 0)) | ||
208 | pr_err("Node 0 : timeout core 0\n"); | ||
209 | |||
210 | /* now get other cores out of reset */ | ||
211 | xlp_enable_secondary_cores(&nlm_cpumask); | ||
212 | } | ||
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile new file mode 100644 index 000000000..7c83100e5 --- /dev/null +++ b/arch/mips/netlogic/xlr/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | obj-y += fmn.o fmn-config.o setup.o platform.o platform-flash.o | ||
3 | obj-$(CONFIG_SMP) += wakeup.o | ||
diff --git a/arch/mips/netlogic/xlr/fmn-config.c b/arch/mips/netlogic/xlr/fmn-config.c new file mode 100644 index 000000000..c7622c6e5 --- /dev/null +++ b/arch/mips/netlogic/xlr/fmn-config.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2012 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <asm/cpu-info.h> | ||
36 | #include <linux/irq.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | |||
39 | #include <asm/cpu.h> | ||
40 | #include <asm/mipsregs.h> | ||
41 | #include <asm/netlogic/xlr/fmn.h> | ||
42 | #include <asm/netlogic/xlr/xlr.h> | ||
43 | #include <asm/netlogic/common.h> | ||
44 | #include <asm/netlogic/haldefs.h> | ||
45 | |||
46 | struct xlr_board_fmn_config xlr_board_fmn_config; | ||
47 | |||
48 | static void __maybe_unused print_credit_config(struct xlr_fmn_info *fmn_info) | ||
49 | { | ||
50 | int bkt; | ||
51 | |||
52 | pr_info("Bucket size :\n"); | ||
53 | pr_info("Station\t: Size\n"); | ||
54 | for (bkt = 0; bkt < 16; bkt++) | ||
55 | pr_info(" %d %d %d %d %d %d %d %d\n", | ||
56 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 0], | ||
57 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 1], | ||
58 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 2], | ||
59 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 3], | ||
60 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 4], | ||
61 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 5], | ||
62 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 6], | ||
63 | xlr_board_fmn_config.bucket_size[(bkt * 8) + 7]); | ||
64 | pr_info("\n"); | ||
65 | |||
66 | pr_info("Credits distribution :\n"); | ||
67 | pr_info("Station\t: Size\n"); | ||
68 | for (bkt = 0; bkt < 16; bkt++) | ||
69 | pr_info(" %d %d %d %d %d %d %d %d\n", | ||
70 | fmn_info->credit_config[(bkt * 8) + 0], | ||
71 | fmn_info->credit_config[(bkt * 8) + 1], | ||
72 | fmn_info->credit_config[(bkt * 8) + 2], | ||
73 | fmn_info->credit_config[(bkt * 8) + 3], | ||
74 | fmn_info->credit_config[(bkt * 8) + 4], | ||
75 | fmn_info->credit_config[(bkt * 8) + 5], | ||
76 | fmn_info->credit_config[(bkt * 8) + 6], | ||
77 | fmn_info->credit_config[(bkt * 8) + 7]); | ||
78 | pr_info("\n"); | ||
79 | } | ||
80 | |||
81 | static void check_credit_distribution(void) | ||
82 | { | ||
83 | struct xlr_board_fmn_config *cfg = &xlr_board_fmn_config; | ||
84 | int bkt, n, total_credits, ncores; | ||
85 | |||
86 | ncores = hweight32(nlm_current_node()->coremask); | ||
87 | for (bkt = 0; bkt < 128; bkt++) { | ||
88 | total_credits = 0; | ||
89 | for (n = 0; n < ncores; n++) | ||
90 | total_credits += cfg->cpu[n].credit_config[bkt]; | ||
91 | total_credits += cfg->gmac[0].credit_config[bkt]; | ||
92 | total_credits += cfg->gmac[1].credit_config[bkt]; | ||
93 | total_credits += cfg->dma.credit_config[bkt]; | ||
94 | total_credits += cfg->cmp.credit_config[bkt]; | ||
95 | total_credits += cfg->sae.credit_config[bkt]; | ||
96 | total_credits += cfg->xgmac[0].credit_config[bkt]; | ||
97 | total_credits += cfg->xgmac[1].credit_config[bkt]; | ||
98 | if (total_credits > cfg->bucket_size[bkt]) | ||
99 | pr_err("ERROR: Bucket %d: credits (%d) > size (%d)\n", | ||
100 | bkt, total_credits, cfg->bucket_size[bkt]); | ||
101 | } | ||
102 | pr_info("Credit distribution complete.\n"); | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Configure bucket size and credits for a device. 'size' is the size of | ||
107 | * the buckets for the device. This size is distributed among all the CPUs | ||
108 | * so that all of them can send messages to the device. | ||
109 | * | ||
110 | * The device is also given 'cpu_credits' to send messages to the CPUs | ||
111 | * | ||
112 | * @dev_info: FMN information structure for each devices | ||
113 | * @start_stn_id: Starting station id of dev_info | ||
114 | * @end_stn_id: End station id of dev_info | ||
115 | * @num_buckets: Total number of buckets for den_info | ||
116 | * @cpu_credits: Allowed credits to cpu for each devices pointing by dev_info | ||
117 | * @size: Size of the each buckets in the device station | ||
118 | */ | ||
119 | static void setup_fmn_cc(struct xlr_fmn_info *dev_info, int start_stn_id, | ||
120 | int end_stn_id, int num_buckets, int cpu_credits, int size) | ||
121 | { | ||
122 | int i, j, num_core, n, credits_per_cpu; | ||
123 | struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu; | ||
124 | |||
125 | num_core = hweight32(nlm_current_node()->coremask); | ||
126 | dev_info->num_buckets = num_buckets; | ||
127 | dev_info->start_stn_id = start_stn_id; | ||
128 | dev_info->end_stn_id = end_stn_id; | ||
129 | |||
130 | n = num_core; | ||
131 | if (num_core == 3) | ||
132 | n = 4; | ||
133 | |||
134 | for (i = start_stn_id; i <= end_stn_id; i++) { | ||
135 | xlr_board_fmn_config.bucket_size[i] = size; | ||
136 | |||
137 | /* Dividing device credits equally to cpus */ | ||
138 | credits_per_cpu = size / n; | ||
139 | for (j = 0; j < num_core; j++) | ||
140 | cpu[j].credit_config[i] = credits_per_cpu; | ||
141 | |||
142 | /* credits left to distribute */ | ||
143 | credits_per_cpu = size - (credits_per_cpu * num_core); | ||
144 | |||
145 | /* distribute the remaining credits (if any), among cores */ | ||
146 | for (j = 0; (j < num_core) && (credits_per_cpu >= 4); j++) { | ||
147 | cpu[j].credit_config[i] += 4; | ||
148 | credits_per_cpu -= 4; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | /* Distributing cpu per bucket credits to devices */ | ||
153 | for (i = 0; i < num_core; i++) { | ||
154 | for (j = 0; j < FMN_CORE_NBUCKETS; j++) | ||
155 | dev_info->credit_config[(i * 8) + j] = cpu_credits; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Each core has 256 slots and 8 buckets, | ||
161 | * Configure the 8 buckets each with 32 slots | ||
162 | */ | ||
163 | static void setup_cpu_fmninfo(struct xlr_fmn_info *cpu, int num_core) | ||
164 | { | ||
165 | int i, j; | ||
166 | |||
167 | for (i = 0; i < num_core; i++) { | ||
168 | cpu[i].start_stn_id = (8 * i); | ||
169 | cpu[i].end_stn_id = (8 * i + 8); | ||
170 | |||
171 | for (j = cpu[i].start_stn_id; j < cpu[i].end_stn_id; j++) | ||
172 | xlr_board_fmn_config.bucket_size[j] = 32; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * Setup the FMN details for each devices according to the device available | ||
178 | * in each variant of XLR/XLS processor | ||
179 | */ | ||
180 | void xlr_board_info_setup(void) | ||
181 | { | ||
182 | struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu; | ||
183 | struct xlr_fmn_info *gmac = xlr_board_fmn_config.gmac; | ||
184 | struct xlr_fmn_info *xgmac = xlr_board_fmn_config.xgmac; | ||
185 | struct xlr_fmn_info *dma = &xlr_board_fmn_config.dma; | ||
186 | struct xlr_fmn_info *cmp = &xlr_board_fmn_config.cmp; | ||
187 | struct xlr_fmn_info *sae = &xlr_board_fmn_config.sae; | ||
188 | int processor_id, num_core; | ||
189 | |||
190 | num_core = hweight32(nlm_current_node()->coremask); | ||
191 | processor_id = read_c0_prid() & PRID_IMP_MASK; | ||
192 | |||
193 | setup_cpu_fmninfo(cpu, num_core); | ||
194 | switch (processor_id) { | ||
195 | case PRID_IMP_NETLOGIC_XLS104: | ||
196 | case PRID_IMP_NETLOGIC_XLS108: | ||
197 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
198 | FMN_STNID_GMAC0_TX3, 8, 16, 32); | ||
199 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
200 | FMN_STNID_DMA_3, 4, 8, 64); | ||
201 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
202 | FMN_STNID_SEC1, 2, 8, 128); | ||
203 | break; | ||
204 | |||
205 | case PRID_IMP_NETLOGIC_XLS204: | ||
206 | case PRID_IMP_NETLOGIC_XLS208: | ||
207 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
208 | FMN_STNID_GMAC0_TX3, 8, 16, 32); | ||
209 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
210 | FMN_STNID_DMA_3, 4, 8, 64); | ||
211 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
212 | FMN_STNID_SEC1, 2, 8, 128); | ||
213 | break; | ||
214 | |||
215 | case PRID_IMP_NETLOGIC_XLS404: | ||
216 | case PRID_IMP_NETLOGIC_XLS408: | ||
217 | case PRID_IMP_NETLOGIC_XLS404B: | ||
218 | case PRID_IMP_NETLOGIC_XLS408B: | ||
219 | case PRID_IMP_NETLOGIC_XLS416B: | ||
220 | case PRID_IMP_NETLOGIC_XLS608B: | ||
221 | case PRID_IMP_NETLOGIC_XLS616B: | ||
222 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
223 | FMN_STNID_GMAC0_TX3, 8, 8, 32); | ||
224 | setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0, | ||
225 | FMN_STNID_GMAC1_TX3, 8, 8, 32); | ||
226 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
227 | FMN_STNID_DMA_3, 4, 4, 64); | ||
228 | setup_fmn_cc(cmp, FMN_STNID_CMP_0, | ||
229 | FMN_STNID_CMP_3, 4, 4, 64); | ||
230 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
231 | FMN_STNID_SEC1, 2, 8, 128); | ||
232 | break; | ||
233 | |||
234 | case PRID_IMP_NETLOGIC_XLS412B: | ||
235 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
236 | FMN_STNID_GMAC0_TX3, 8, 8, 32); | ||
237 | setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0, | ||
238 | FMN_STNID_GMAC1_TX3, 8, 8, 32); | ||
239 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
240 | FMN_STNID_DMA_3, 4, 4, 64); | ||
241 | setup_fmn_cc(cmp, FMN_STNID_CMP_0, | ||
242 | FMN_STNID_CMP_3, 4, 4, 64); | ||
243 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
244 | FMN_STNID_SEC1, 2, 8, 128); | ||
245 | break; | ||
246 | |||
247 | case PRID_IMP_NETLOGIC_XLR308: | ||
248 | case PRID_IMP_NETLOGIC_XLR308C: | ||
249 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
250 | FMN_STNID_GMAC0_TX3, 8, 16, 32); | ||
251 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
252 | FMN_STNID_DMA_3, 4, 8, 64); | ||
253 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
254 | FMN_STNID_SEC1, 2, 4, 128); | ||
255 | break; | ||
256 | |||
257 | case PRID_IMP_NETLOGIC_XLR532: | ||
258 | case PRID_IMP_NETLOGIC_XLR532C: | ||
259 | case PRID_IMP_NETLOGIC_XLR516C: | ||
260 | case PRID_IMP_NETLOGIC_XLR508C: | ||
261 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
262 | FMN_STNID_GMAC0_TX3, 8, 16, 32); | ||
263 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
264 | FMN_STNID_DMA_3, 4, 8, 64); | ||
265 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
266 | FMN_STNID_SEC1, 2, 4, 128); | ||
267 | break; | ||
268 | |||
269 | case PRID_IMP_NETLOGIC_XLR732: | ||
270 | case PRID_IMP_NETLOGIC_XLR716: | ||
271 | setup_fmn_cc(&xgmac[0], FMN_STNID_XMAC0_00_TX, | ||
272 | FMN_STNID_XMAC0_15_TX, 8, 0, 32); | ||
273 | setup_fmn_cc(&xgmac[1], FMN_STNID_XMAC1_00_TX, | ||
274 | FMN_STNID_XMAC1_15_TX, 8, 0, 32); | ||
275 | setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, | ||
276 | FMN_STNID_GMAC0_TX3, 8, 24, 32); | ||
277 | setup_fmn_cc(dma, FMN_STNID_DMA_0, | ||
278 | FMN_STNID_DMA_3, 4, 4, 64); | ||
279 | setup_fmn_cc(sae, FMN_STNID_SEC0, | ||
280 | FMN_STNID_SEC1, 2, 4, 128); | ||
281 | break; | ||
282 | default: | ||
283 | pr_err("Unknown CPU with processor ID [%d]\n", processor_id); | ||
284 | pr_err("Error: Cannot initialize FMN credits.\n"); | ||
285 | } | ||
286 | |||
287 | check_credit_distribution(); | ||
288 | |||
289 | #if 0 /* debug */ | ||
290 | print_credit_config(&cpu[0]); | ||
291 | print_credit_config(&gmac[0]); | ||
292 | #endif | ||
293 | } | ||
diff --git a/arch/mips/netlogic/xlr/fmn.c b/arch/mips/netlogic/xlr/fmn.c new file mode 100644 index 000000000..f90303f31 --- /dev/null +++ b/arch/mips/netlogic/xlr/fmn.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2012 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/irqreturn.h> | ||
37 | #include <linux/irq.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | |||
40 | #include <asm/mipsregs.h> | ||
41 | #include <asm/netlogic/interrupt.h> | ||
42 | #include <asm/netlogic/xlr/fmn.h> | ||
43 | #include <asm/netlogic/common.h> | ||
44 | |||
45 | #define COP2_CC_INIT_CPU_DEST(dest, conf) \ | ||
46 | do { \ | ||
47 | nlm_write_c2_cc##dest(0, conf[(dest * 8) + 0]); \ | ||
48 | nlm_write_c2_cc##dest(1, conf[(dest * 8) + 1]); \ | ||
49 | nlm_write_c2_cc##dest(2, conf[(dest * 8) + 2]); \ | ||
50 | nlm_write_c2_cc##dest(3, conf[(dest * 8) + 3]); \ | ||
51 | nlm_write_c2_cc##dest(4, conf[(dest * 8) + 4]); \ | ||
52 | nlm_write_c2_cc##dest(5, conf[(dest * 8) + 5]); \ | ||
53 | nlm_write_c2_cc##dest(6, conf[(dest * 8) + 6]); \ | ||
54 | nlm_write_c2_cc##dest(7, conf[(dest * 8) + 7]); \ | ||
55 | } while (0) | ||
56 | |||
57 | struct fmn_message_handler { | ||
58 | void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *); | ||
59 | void *arg; | ||
60 | } msg_handlers[128]; | ||
61 | |||
62 | /* | ||
63 | * FMN interrupt handler. We configure the FMN so that any messages in | ||
64 | * any of the CPU buckets will trigger an interrupt on the CPU. | ||
65 | * The message can be from any device on the FMN (like NAE/SAE/DMA). | ||
66 | * The source station id is used to figure out which of the registered | ||
67 | * handlers have to be called. | ||
68 | */ | ||
69 | static irqreturn_t fmn_message_handler(int irq, void *data) | ||
70 | { | ||
71 | struct fmn_message_handler *hndlr; | ||
72 | int bucket, rv; | ||
73 | int size = 0, code = 0, src_stnid = 0; | ||
74 | struct nlm_fmn_msg msg; | ||
75 | uint32_t mflags, bkt_status; | ||
76 | |||
77 | mflags = nlm_cop2_enable_irqsave(); | ||
78 | /* Disable message ring interrupt */ | ||
79 | nlm_fmn_setup_intr(irq, 0); | ||
80 | while (1) { | ||
81 | /* 8 bkts per core, [24:31] each bit represents one bucket | ||
82 | * Bit is Zero if bucket is not empty */ | ||
83 | bkt_status = (nlm_read_c2_status0() >> 24) & 0xff; | ||
84 | if (bkt_status == 0xff) | ||
85 | break; | ||
86 | for (bucket = 0; bucket < 8; bucket++) { | ||
87 | /* Continue on empty bucket */ | ||
88 | if (bkt_status & (1 << bucket)) | ||
89 | continue; | ||
90 | rv = nlm_fmn_receive(bucket, &size, &code, &src_stnid, | ||
91 | &msg); | ||
92 | if (rv != 0) | ||
93 | continue; | ||
94 | |||
95 | hndlr = &msg_handlers[src_stnid]; | ||
96 | if (hndlr->action == NULL) | ||
97 | pr_warn("No msgring handler for stnid %d\n", | ||
98 | src_stnid); | ||
99 | else { | ||
100 | nlm_cop2_disable_irqrestore(mflags); | ||
101 | hndlr->action(bucket, src_stnid, size, code, | ||
102 | &msg, hndlr->arg); | ||
103 | mflags = nlm_cop2_enable_irqsave(); | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | /* Enable message ring intr, to any thread in core */ | ||
108 | nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1); | ||
109 | nlm_cop2_disable_irqrestore(mflags); | ||
110 | return IRQ_HANDLED; | ||
111 | } | ||
112 | |||
113 | void xlr_percpu_fmn_init(void) | ||
114 | { | ||
115 | struct xlr_fmn_info *cpu_fmn_info; | ||
116 | int *bucket_sizes; | ||
117 | uint32_t flags; | ||
118 | int id; | ||
119 | |||
120 | BUG_ON(nlm_thread_id() != 0); | ||
121 | id = nlm_core_id(); | ||
122 | |||
123 | bucket_sizes = xlr_board_fmn_config.bucket_size; | ||
124 | cpu_fmn_info = &xlr_board_fmn_config.cpu[id]; | ||
125 | flags = nlm_cop2_enable_irqsave(); | ||
126 | |||
127 | /* Setup bucket sizes for the core. */ | ||
128 | nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]); | ||
129 | nlm_write_c2_bucksize(1, bucket_sizes[id * 8 + 1]); | ||
130 | nlm_write_c2_bucksize(2, bucket_sizes[id * 8 + 2]); | ||
131 | nlm_write_c2_bucksize(3, bucket_sizes[id * 8 + 3]); | ||
132 | nlm_write_c2_bucksize(4, bucket_sizes[id * 8 + 4]); | ||
133 | nlm_write_c2_bucksize(5, bucket_sizes[id * 8 + 5]); | ||
134 | nlm_write_c2_bucksize(6, bucket_sizes[id * 8 + 6]); | ||
135 | nlm_write_c2_bucksize(7, bucket_sizes[id * 8 + 7]); | ||
136 | |||
137 | /* | ||
138 | * For sending FMN messages, we need credits on the destination | ||
139 | * bucket. Program the credits this core has on the 128 possible | ||
140 | * destination buckets. | ||
141 | * We cannot use a loop here, because the the first argument has | ||
142 | * to be a constant integer value. | ||
143 | */ | ||
144 | COP2_CC_INIT_CPU_DEST(0, cpu_fmn_info->credit_config); | ||
145 | COP2_CC_INIT_CPU_DEST(1, cpu_fmn_info->credit_config); | ||
146 | COP2_CC_INIT_CPU_DEST(2, cpu_fmn_info->credit_config); | ||
147 | COP2_CC_INIT_CPU_DEST(3, cpu_fmn_info->credit_config); | ||
148 | COP2_CC_INIT_CPU_DEST(4, cpu_fmn_info->credit_config); | ||
149 | COP2_CC_INIT_CPU_DEST(5, cpu_fmn_info->credit_config); | ||
150 | COP2_CC_INIT_CPU_DEST(6, cpu_fmn_info->credit_config); | ||
151 | COP2_CC_INIT_CPU_DEST(7, cpu_fmn_info->credit_config); | ||
152 | COP2_CC_INIT_CPU_DEST(8, cpu_fmn_info->credit_config); | ||
153 | COP2_CC_INIT_CPU_DEST(9, cpu_fmn_info->credit_config); | ||
154 | COP2_CC_INIT_CPU_DEST(10, cpu_fmn_info->credit_config); | ||
155 | COP2_CC_INIT_CPU_DEST(11, cpu_fmn_info->credit_config); | ||
156 | COP2_CC_INIT_CPU_DEST(12, cpu_fmn_info->credit_config); | ||
157 | COP2_CC_INIT_CPU_DEST(13, cpu_fmn_info->credit_config); | ||
158 | COP2_CC_INIT_CPU_DEST(14, cpu_fmn_info->credit_config); | ||
159 | COP2_CC_INIT_CPU_DEST(15, cpu_fmn_info->credit_config); | ||
160 | |||
161 | /* enable FMN interrupts on this CPU */ | ||
162 | nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1); | ||
163 | nlm_cop2_disable_irqrestore(flags); | ||
164 | } | ||
165 | |||
166 | |||
167 | /* | ||
168 | * Register a FMN message handler with respect to the source station id | ||
169 | * @stnid: source station id | ||
170 | * @action: Handler function pointer | ||
171 | */ | ||
172 | int nlm_register_fmn_handler(int start_stnid, int end_stnid, | ||
173 | void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *), | ||
174 | void *arg) | ||
175 | { | ||
176 | int sstnid; | ||
177 | |||
178 | for (sstnid = start_stnid; sstnid <= end_stnid; sstnid++) { | ||
179 | msg_handlers[sstnid].arg = arg; | ||
180 | smp_wmb(); | ||
181 | msg_handlers[sstnid].action = action; | ||
182 | } | ||
183 | pr_debug("Registered FMN msg handler for stnid %d-%d\n", | ||
184 | start_stnid, end_stnid); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | void nlm_setup_fmn_irq(void) | ||
189 | { | ||
190 | uint32_t flags; | ||
191 | |||
192 | /* request irq only once */ | ||
193 | if (request_irq(IRQ_FMN, fmn_message_handler, IRQF_PERCPU, "fmn", NULL)) | ||
194 | pr_err("Failed to request irq %d (fmn)\n", IRQ_FMN); | ||
195 | |||
196 | flags = nlm_cop2_enable_irqsave(); | ||
197 | nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1); | ||
198 | nlm_cop2_disable_irqrestore(flags); | ||
199 | } | ||
diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c new file mode 100644 index 000000000..cf9162284 --- /dev/null +++ b/arch/mips/netlogic/xlr/platform-flash.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * Copyright 2011, Netlogic Microsystems. | ||
3 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | */ | ||
9 | |||
10 | #include <linux/device.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/resource.h> | ||
18 | #include <linux/spi/flash.h> | ||
19 | |||
20 | #include <linux/mtd/mtd.h> | ||
21 | #include <linux/mtd/physmap.h> | ||
22 | #include <linux/mtd/platnand.h> | ||
23 | |||
24 | #include <asm/netlogic/haldefs.h> | ||
25 | #include <asm/netlogic/xlr/iomap.h> | ||
26 | #include <asm/netlogic/xlr/flash.h> | ||
27 | #include <asm/netlogic/xlr/bridge.h> | ||
28 | #include <asm/netlogic/xlr/gpio.h> | ||
29 | #include <asm/netlogic/xlr/xlr.h> | ||
30 | |||
31 | /* | ||
32 | * Default NOR partition layout | ||
33 | */ | ||
34 | static struct mtd_partition xlr_nor_parts[] = { | ||
35 | { | ||
36 | .name = "User FS", | ||
37 | .offset = 0x800000, | ||
38 | .size = MTDPART_SIZ_FULL, | ||
39 | } | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Default NAND partition layout | ||
44 | */ | ||
45 | static struct mtd_partition xlr_nand_parts[] = { | ||
46 | { | ||
47 | .name = "Root Filesystem", | ||
48 | .offset = 64 * 64 * 2048, | ||
49 | .size = 432 * 64 * 2048, | ||
50 | }, | ||
51 | { | ||
52 | .name = "Home Filesystem", | ||
53 | .offset = MTDPART_OFS_APPEND, | ||
54 | .size = MTDPART_SIZ_FULL, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | /* Use PHYSMAP flash for NOR */ | ||
59 | struct physmap_flash_data xlr_nor_data = { | ||
60 | .width = 2, | ||
61 | .parts = xlr_nor_parts, | ||
62 | .nr_parts = ARRAY_SIZE(xlr_nor_parts), | ||
63 | }; | ||
64 | |||
65 | static struct resource xlr_nor_res[] = { | ||
66 | { | ||
67 | .flags = IORESOURCE_MEM, | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static struct platform_device xlr_nor_dev = { | ||
72 | .name = "physmap-flash", | ||
73 | .dev = { | ||
74 | .platform_data = &xlr_nor_data, | ||
75 | }, | ||
76 | .num_resources = ARRAY_SIZE(xlr_nor_res), | ||
77 | .resource = xlr_nor_res, | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * Use "gen_nand" driver for NAND flash | ||
82 | * | ||
83 | * There seems to be no way to store a private pointer containing | ||
84 | * platform specific info in gen_nand drivier. We will use a global | ||
85 | * struct for now, since we currently have only one NAND chip per board. | ||
86 | */ | ||
87 | struct xlr_nand_flash_priv { | ||
88 | int cs; | ||
89 | uint64_t flash_mmio; | ||
90 | }; | ||
91 | |||
92 | static struct xlr_nand_flash_priv nand_priv; | ||
93 | |||
94 | static void xlr_nand_ctrl(struct nand_chip *chip, int cmd, | ||
95 | unsigned int ctrl) | ||
96 | { | ||
97 | if (ctrl & NAND_CLE) | ||
98 | nlm_write_reg(nand_priv.flash_mmio, | ||
99 | FLASH_NAND_CLE(nand_priv.cs), cmd); | ||
100 | else if (ctrl & NAND_ALE) | ||
101 | nlm_write_reg(nand_priv.flash_mmio, | ||
102 | FLASH_NAND_ALE(nand_priv.cs), cmd); | ||
103 | } | ||
104 | |||
105 | struct platform_nand_data xlr_nand_data = { | ||
106 | .chip = { | ||
107 | .nr_chips = 1, | ||
108 | .nr_partitions = ARRAY_SIZE(xlr_nand_parts), | ||
109 | .chip_delay = 50, | ||
110 | .partitions = xlr_nand_parts, | ||
111 | }, | ||
112 | .ctrl = { | ||
113 | .cmd_ctrl = xlr_nand_ctrl, | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static struct resource xlr_nand_res[] = { | ||
118 | { | ||
119 | .flags = IORESOURCE_MEM, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | static struct platform_device xlr_nand_dev = { | ||
124 | .name = "gen_nand", | ||
125 | .id = -1, | ||
126 | .num_resources = ARRAY_SIZE(xlr_nand_res), | ||
127 | .resource = xlr_nand_res, | ||
128 | .dev = { | ||
129 | .platform_data = &xlr_nand_data, | ||
130 | } | ||
131 | }; | ||
132 | |||
133 | /* | ||
134 | * XLR/XLS supports upto 8 devices on its FLASH interface. The value in | ||
135 | * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the | ||
136 | * flash devices. | ||
137 | * Under this, each flash device has an offset and size given by the | ||
138 | * CSBASE_ADDR and CSBASE_MASK registers for the device. | ||
139 | * | ||
140 | * The CSBASE_ registers are expected to be setup by the bootloader. | ||
141 | */ | ||
142 | static void setup_flash_resource(uint64_t flash_mmio, | ||
143 | uint64_t flash_map_base, int cs, struct resource *res) | ||
144 | { | ||
145 | u32 base, mask; | ||
146 | |||
147 | base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs)); | ||
148 | mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs)); | ||
149 | |||
150 | res->start = flash_map_base + ((unsigned long)base << 16); | ||
151 | res->end = res->start + (mask + 1) * 64 * 1024; | ||
152 | } | ||
153 | |||
154 | static int __init xlr_flash_init(void) | ||
155 | { | ||
156 | uint64_t gpio_mmio, flash_mmio, flash_map_base; | ||
157 | u32 gpio_resetcfg, flash_bar; | ||
158 | int cs, boot_nand, boot_nor; | ||
159 | |||
160 | /* Flash address bits 39:24 is in bridge flash BAR */ | ||
161 | flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR); | ||
162 | flash_map_base = (flash_bar & 0xffff0000) << 8; | ||
163 | |||
164 | gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); | ||
165 | flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET); | ||
166 | |||
167 | /* Get the chip reset config */ | ||
168 | gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG); | ||
169 | |||
170 | /* Check for boot flash type */ | ||
171 | boot_nor = boot_nand = 0; | ||
172 | if (nlm_chip_is_xls()) { | ||
173 | /* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */ | ||
174 | if (gpio_resetcfg & (1 << 16)) | ||
175 | boot_nand = 1; | ||
176 | |||
177 | /* check boot from PCMCIA, (GPIO reset reg bit 15 */ | ||
178 | if ((gpio_resetcfg & (1 << 15)) == 0) | ||
179 | boot_nor = 1; /* not set, booted from NOR */ | ||
180 | } else { /* XLR */ | ||
181 | /* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */ | ||
182 | if ((gpio_resetcfg & (1 << 16)) == 0) | ||
183 | boot_nor = 1; /* not set, booted from NOR */ | ||
184 | } | ||
185 | |||
186 | /* boot flash at chip select 0 */ | ||
187 | cs = 0; | ||
188 | |||
189 | if (boot_nand) { | ||
190 | nand_priv.cs = cs; | ||
191 | nand_priv.flash_mmio = flash_mmio; | ||
192 | setup_flash_resource(flash_mmio, flash_map_base, cs, | ||
193 | xlr_nand_res); | ||
194 | |||
195 | /* Initialize NAND flash at CS 0 */ | ||
196 | nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs), | ||
197 | FLASH_NAND_CSDEV_PARAM); | ||
198 | nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs), | ||
199 | FLASH_NAND_CSTIME_PARAMA); | ||
200 | nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs), | ||
201 | FLASH_NAND_CSTIME_PARAMB); | ||
202 | |||
203 | pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res); | ||
204 | return platform_device_register(&xlr_nand_dev); | ||
205 | } | ||
206 | |||
207 | if (boot_nor) { | ||
208 | setup_flash_resource(flash_mmio, flash_map_base, cs, | ||
209 | xlr_nor_res); | ||
210 | pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res); | ||
211 | return platform_device_register(&xlr_nor_dev); | ||
212 | } | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | arch_initcall(xlr_flash_init); | ||
diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c new file mode 100644 index 000000000..4785932af --- /dev/null +++ b/arch/mips/netlogic/xlr/platform.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * Copyright 2011, Netlogic Microsystems. | ||
3 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | */ | ||
9 | |||
10 | #include <linux/device.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/resource.h> | ||
15 | #include <linux/serial_8250.h> | ||
16 | #include <linux/serial_reg.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/usb/ehci_pdriver.h> | ||
19 | #include <linux/usb/ohci_pdriver.h> | ||
20 | |||
21 | #include <asm/netlogic/haldefs.h> | ||
22 | #include <asm/netlogic/xlr/iomap.h> | ||
23 | #include <asm/netlogic/xlr/pic.h> | ||
24 | #include <asm/netlogic/xlr/xlr.h> | ||
25 | |||
26 | static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) | ||
27 | { | ||
28 | uint64_t uartbase; | ||
29 | unsigned int value; | ||
30 | |||
31 | /* sign extend to 64 bits, if needed */ | ||
32 | uartbase = (uint64_t)(long)p->membase; | ||
33 | value = nlm_read_reg(uartbase, offset); | ||
34 | |||
35 | /* See XLR/XLS errata */ | ||
36 | if (offset == UART_MSR) | ||
37 | value ^= 0xF0; | ||
38 | else if (offset == UART_MCR) | ||
39 | value ^= 0x3; | ||
40 | |||
41 | return value; | ||
42 | } | ||
43 | |||
44 | static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) | ||
45 | { | ||
46 | uint64_t uartbase; | ||
47 | |||
48 | /* sign extend to 64 bits, if needed */ | ||
49 | uartbase = (uint64_t)(long)p->membase; | ||
50 | |||
51 | /* See XLR/XLS errata */ | ||
52 | if (offset == UART_MSR) | ||
53 | value ^= 0xF0; | ||
54 | else if (offset == UART_MCR) | ||
55 | value ^= 0x3; | ||
56 | |||
57 | nlm_write_reg(uartbase, offset, value); | ||
58 | } | ||
59 | |||
60 | #define PORT(_irq) \ | ||
61 | { \ | ||
62 | .irq = _irq, \ | ||
63 | .regshift = 2, \ | ||
64 | .iotype = UPIO_MEM32, \ | ||
65 | .flags = (UPF_SKIP_TEST | \ | ||
66 | UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ | ||
67 | .uartclk = PIC_CLK_HZ, \ | ||
68 | .type = PORT_16550A, \ | ||
69 | .serial_in = nlm_xlr_uart_in, \ | ||
70 | .serial_out = nlm_xlr_uart_out, \ | ||
71 | } | ||
72 | |||
73 | static struct plat_serial8250_port xlr_uart_data[] = { | ||
74 | PORT(PIC_UART_0_IRQ), | ||
75 | PORT(PIC_UART_1_IRQ), | ||
76 | {}, | ||
77 | }; | ||
78 | |||
79 | static struct platform_device uart_device = { | ||
80 | .name = "serial8250", | ||
81 | .id = PLAT8250_DEV_PLATFORM, | ||
82 | .dev = { | ||
83 | .platform_data = xlr_uart_data, | ||
84 | }, | ||
85 | }; | ||
86 | |||
87 | static int __init nlm_uart_init(void) | ||
88 | { | ||
89 | unsigned long uartbase; | ||
90 | |||
91 | uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); | ||
92 | xlr_uart_data[0].membase = (void __iomem *)uartbase; | ||
93 | xlr_uart_data[0].mapbase = CPHYSADDR(uartbase); | ||
94 | |||
95 | uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET); | ||
96 | xlr_uart_data[1].membase = (void __iomem *)uartbase; | ||
97 | xlr_uart_data[1].mapbase = CPHYSADDR(uartbase); | ||
98 | |||
99 | return platform_device_register(&uart_device); | ||
100 | } | ||
101 | |||
102 | arch_initcall(nlm_uart_init); | ||
103 | |||
104 | #ifdef CONFIG_USB | ||
105 | /* Platform USB devices, only on XLS chips */ | ||
106 | static u64 xls_usb_dmamask = ~(u32)0; | ||
107 | #define USB_PLATFORM_DEV(n, i, irq) \ | ||
108 | { \ | ||
109 | .name = n, \ | ||
110 | .id = i, \ | ||
111 | .num_resources = 2, \ | ||
112 | .dev = { \ | ||
113 | .dma_mask = &xls_usb_dmamask, \ | ||
114 | .coherent_dma_mask = 0xffffffff, \ | ||
115 | }, \ | ||
116 | .resource = (struct resource[]) { \ | ||
117 | { \ | ||
118 | .flags = IORESOURCE_MEM, \ | ||
119 | }, \ | ||
120 | { \ | ||
121 | .start = irq, \ | ||
122 | .end = irq, \ | ||
123 | .flags = IORESOURCE_IRQ, \ | ||
124 | }, \ | ||
125 | }, \ | ||
126 | } | ||
127 | |||
128 | static struct usb_ehci_pdata xls_usb_ehci_pdata = { | ||
129 | .caps_offset = 0, | ||
130 | }; | ||
131 | |||
132 | static struct usb_ohci_pdata xls_usb_ohci_pdata; | ||
133 | |||
134 | static struct platform_device xls_usb_ehci_device = | ||
135 | USB_PLATFORM_DEV("ehci-platform", 0, PIC_USB_IRQ); | ||
136 | static struct platform_device xls_usb_ohci_device_0 = | ||
137 | USB_PLATFORM_DEV("ohci-platform", 1, PIC_USB_IRQ); | ||
138 | static struct platform_device xls_usb_ohci_device_1 = | ||
139 | USB_PLATFORM_DEV("ohci-platform", 2, PIC_USB_IRQ); | ||
140 | |||
141 | static struct platform_device *xls_platform_devices[] = { | ||
142 | &xls_usb_ehci_device, | ||
143 | &xls_usb_ohci_device_0, | ||
144 | &xls_usb_ohci_device_1, | ||
145 | }; | ||
146 | |||
147 | int xls_platform_usb_init(void) | ||
148 | { | ||
149 | uint64_t usb_mmio, gpio_mmio; | ||
150 | unsigned long memres; | ||
151 | uint32_t val; | ||
152 | |||
153 | if (!nlm_chip_is_xls()) | ||
154 | return 0; | ||
155 | |||
156 | gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); | ||
157 | usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET); | ||
158 | |||
159 | /* Clear Rogue Phy INTs */ | ||
160 | nlm_write_reg(usb_mmio, 49, 0x10000000); | ||
161 | /* Enable all interrupts */ | ||
162 | nlm_write_reg(usb_mmio, 50, 0x1f000000); | ||
163 | |||
164 | /* Enable ports */ | ||
165 | nlm_write_reg(usb_mmio, 1, 0x07000500); | ||
166 | |||
167 | val = nlm_read_reg(gpio_mmio, 21); | ||
168 | if (((val >> 22) & 0x01) == 0) { | ||
169 | pr_info("Detected USB Device mode - Not supported!\n"); | ||
170 | nlm_write_reg(usb_mmio, 0, 0x01000000); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | pr_info("Detected USB Host mode - Adding XLS USB devices.\n"); | ||
175 | /* Clear reset, host mode */ | ||
176 | nlm_write_reg(usb_mmio, 0, 0x02000000); | ||
177 | |||
178 | /* Memory resource for various XLS usb ports */ | ||
179 | usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET); | ||
180 | memres = CPHYSADDR((unsigned long)usb_mmio); | ||
181 | xls_usb_ehci_device.resource[0].start = memres; | ||
182 | xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1; | ||
183 | xls_usb_ehci_device.dev.platform_data = &xls_usb_ehci_pdata; | ||
184 | |||
185 | memres += 0x400; | ||
186 | xls_usb_ohci_device_0.resource[0].start = memres; | ||
187 | xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1; | ||
188 | xls_usb_ohci_device_0.dev.platform_data = &xls_usb_ohci_pdata; | ||
189 | |||
190 | memres += 0x400; | ||
191 | xls_usb_ohci_device_1.resource[0].start = memres; | ||
192 | xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1; | ||
193 | xls_usb_ohci_device_1.dev.platform_data = &xls_usb_ohci_pdata; | ||
194 | |||
195 | return platform_add_devices(xls_platform_devices, | ||
196 | ARRAY_SIZE(xls_platform_devices)); | ||
197 | } | ||
198 | |||
199 | arch_initcall(xls_platform_usb_init); | ||
200 | #endif | ||
201 | |||
202 | #ifdef CONFIG_I2C | ||
203 | static struct i2c_board_info nlm_i2c_board_info1[] __initdata = { | ||
204 | /* All XLR boards have this RTC and Max6657 Temp Chip */ | ||
205 | [0] = { | ||
206 | .type = "ds1374", | ||
207 | .addr = 0x68 | ||
208 | }, | ||
209 | [1] = { | ||
210 | .type = "lm90", | ||
211 | .addr = 0x4c | ||
212 | }, | ||
213 | }; | ||
214 | |||
215 | static struct resource i2c_resources[] = { | ||
216 | [0] = { | ||
217 | .start = 0, /* filled at init */ | ||
218 | .end = 0, | ||
219 | .flags = IORESOURCE_MEM, | ||
220 | }, | ||
221 | }; | ||
222 | |||
223 | static struct platform_device nlm_xlr_i2c_1 = { | ||
224 | .name = "xlr-i2cbus", | ||
225 | .id = 1, | ||
226 | .num_resources = 1, | ||
227 | .resource = i2c_resources, | ||
228 | }; | ||
229 | |||
230 | static int __init nlm_i2c_init(void) | ||
231 | { | ||
232 | int err = 0; | ||
233 | unsigned int offset; | ||
234 | |||
235 | /* I2C bus 0 does not have any useful devices, configure only bus 1 */ | ||
236 | offset = NETLOGIC_IO_I2C_1_OFFSET; | ||
237 | nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset)); | ||
238 | nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff; | ||
239 | |||
240 | platform_device_register(&nlm_xlr_i2c_1); | ||
241 | |||
242 | err = i2c_register_board_info(1, nlm_i2c_board_info1, | ||
243 | ARRAY_SIZE(nlm_i2c_board_info1)); | ||
244 | if (err < 0) | ||
245 | pr_err("nlm-i2c: cannot register board I2C devices\n"); | ||
246 | return err; | ||
247 | } | ||
248 | |||
249 | arch_initcall(nlm_i2c_init); | ||
250 | #endif | ||
diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c new file mode 100644 index 000000000..627e88101 --- /dev/null +++ b/arch/mips/netlogic/xlr/setup.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/serial_8250.h> | ||
37 | #include <linux/memblock.h> | ||
38 | #include <linux/pm.h> | ||
39 | |||
40 | #include <asm/idle.h> | ||
41 | #include <asm/reboot.h> | ||
42 | #include <asm/time.h> | ||
43 | #include <asm/bootinfo.h> | ||
44 | |||
45 | #include <asm/netlogic/interrupt.h> | ||
46 | #include <asm/netlogic/psb-bootinfo.h> | ||
47 | #include <asm/netlogic/haldefs.h> | ||
48 | #include <asm/netlogic/common.h> | ||
49 | |||
50 | #include <asm/netlogic/xlr/xlr.h> | ||
51 | #include <asm/netlogic/xlr/iomap.h> | ||
52 | #include <asm/netlogic/xlr/pic.h> | ||
53 | #include <asm/netlogic/xlr/gpio.h> | ||
54 | #include <asm/netlogic/xlr/fmn.h> | ||
55 | |||
56 | uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE; | ||
57 | struct psb_info nlm_prom_info; | ||
58 | |||
59 | /* default to uniprocessor */ | ||
60 | unsigned int nlm_threads_per_core = 1; | ||
61 | struct nlm_soc_info nlm_nodes[NLM_NR_NODES]; | ||
62 | cpumask_t nlm_cpumask = CPU_MASK_CPU0; | ||
63 | |||
64 | static void nlm_linux_exit(void) | ||
65 | { | ||
66 | uint64_t gpiobase; | ||
67 | |||
68 | gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); | ||
69 | /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ | ||
70 | nlm_write_reg(gpiobase, GPIO_SWRESET_REG, 1); | ||
71 | for ( ; ; ) | ||
72 | cpu_wait(); | ||
73 | } | ||
74 | |||
75 | void __init plat_mem_setup(void) | ||
76 | { | ||
77 | _machine_restart = (void (*)(char *))nlm_linux_exit; | ||
78 | _machine_halt = nlm_linux_exit; | ||
79 | pm_power_off = nlm_linux_exit; | ||
80 | } | ||
81 | |||
82 | const char *get_system_type(void) | ||
83 | { | ||
84 | return "Netlogic XLR/XLS Series"; | ||
85 | } | ||
86 | |||
87 | unsigned int nlm_get_cpu_frequency(void) | ||
88 | { | ||
89 | return (unsigned int)nlm_prom_info.cpu_frequency; | ||
90 | } | ||
91 | |||
92 | void __init prom_free_prom_memory(void) | ||
93 | { | ||
94 | /* Nothing yet */ | ||
95 | } | ||
96 | |||
97 | void nlm_percpu_init(int hwcpuid) | ||
98 | { | ||
99 | if (hwcpuid % 4 == 0) | ||
100 | xlr_percpu_fmn_init(); | ||
101 | } | ||
102 | |||
103 | static void __init build_arcs_cmdline(int *argv) | ||
104 | { | ||
105 | int i, remain, len; | ||
106 | char *arg; | ||
107 | |||
108 | remain = sizeof(arcs_cmdline) - 1; | ||
109 | arcs_cmdline[0] = '\0'; | ||
110 | for (i = 0; argv[i] != 0; i++) { | ||
111 | arg = (char *)(long)argv[i]; | ||
112 | len = strlen(arg); | ||
113 | if (len + 1 > remain) | ||
114 | break; | ||
115 | strcat(arcs_cmdline, arg); | ||
116 | strcat(arcs_cmdline, " "); | ||
117 | remain -= len + 1; | ||
118 | } | ||
119 | |||
120 | /* Add the default options here */ | ||
121 | if ((strstr(arcs_cmdline, "console=")) == NULL) { | ||
122 | arg = "console=ttyS0,38400 "; | ||
123 | len = strlen(arg); | ||
124 | if (len > remain) | ||
125 | goto fail; | ||
126 | strcat(arcs_cmdline, arg); | ||
127 | remain -= len; | ||
128 | } | ||
129 | #ifdef CONFIG_BLK_DEV_INITRD | ||
130 | if ((strstr(arcs_cmdline, "rdinit=")) == NULL) { | ||
131 | arg = "rdinit=/sbin/init "; | ||
132 | len = strlen(arg); | ||
133 | if (len > remain) | ||
134 | goto fail; | ||
135 | strcat(arcs_cmdline, arg); | ||
136 | remain -= len; | ||
137 | } | ||
138 | #endif | ||
139 | return; | ||
140 | fail: | ||
141 | panic("Cannot add %s, command line too big!", arg); | ||
142 | } | ||
143 | |||
144 | static void prom_add_memory(void) | ||
145 | { | ||
146 | struct nlm_boot_mem_map *bootm; | ||
147 | u64 start, size; | ||
148 | u64 pref_backup = 512; /* avoid pref walking beyond end */ | ||
149 | int i; | ||
150 | |||
151 | bootm = (void *)(long)nlm_prom_info.psb_mem_map; | ||
152 | for (i = 0; i < bootm->nr_map; i++) { | ||
153 | if (bootm->map[i].type != NLM_BOOT_MEM_RAM) | ||
154 | continue; | ||
155 | start = bootm->map[i].addr; | ||
156 | size = bootm->map[i].size; | ||
157 | |||
158 | /* Work around for using bootloader mem */ | ||
159 | if (i == 0 && start == 0 && size == 0x0c000000) | ||
160 | size = 0x0ff00000; | ||
161 | |||
162 | memblock_add(start, size - pref_backup); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static void nlm_init_node(void) | ||
167 | { | ||
168 | struct nlm_soc_info *nodep; | ||
169 | |||
170 | nodep = nlm_current_node(); | ||
171 | nodep->picbase = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); | ||
172 | nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; | ||
173 | spin_lock_init(&nodep->piclock); | ||
174 | } | ||
175 | |||
176 | void __init prom_init(void) | ||
177 | { | ||
178 | int *argv, *envp; /* passed as 32 bit ptrs */ | ||
179 | struct psb_info *prom_infop; | ||
180 | void *reset_vec; | ||
181 | #ifdef CONFIG_SMP | ||
182 | int i; | ||
183 | #endif | ||
184 | |||
185 | /* truncate to 32 bit and sign extend all args */ | ||
186 | argv = (int *)(long)(int)fw_arg1; | ||
187 | envp = (int *)(long)(int)fw_arg2; | ||
188 | prom_infop = (struct psb_info *)(long)(int)fw_arg3; | ||
189 | |||
190 | nlm_prom_info = *prom_infop; | ||
191 | nlm_init_node(); | ||
192 | |||
193 | /* Update reset entry point with CPU init code */ | ||
194 | reset_vec = (void *)CKSEG1ADDR(RESET_VEC_PHYS); | ||
195 | memset(reset_vec, 0, RESET_VEC_SIZE); | ||
196 | memcpy(reset_vec, (void *)nlm_reset_entry, | ||
197 | (nlm_reset_entry_end - nlm_reset_entry)); | ||
198 | |||
199 | build_arcs_cmdline(argv); | ||
200 | prom_add_memory(); | ||
201 | |||
202 | #ifdef CONFIG_SMP | ||
203 | for (i = 0; i < 32; i++) | ||
204 | if (nlm_prom_info.online_cpu_map & (1 << i)) | ||
205 | cpumask_set_cpu(i, &nlm_cpumask); | ||
206 | nlm_wakeup_secondary_cpus(); | ||
207 | register_smp_ops(&nlm_smp_ops); | ||
208 | #endif | ||
209 | xlr_board_info_setup(); | ||
210 | xlr_percpu_fmn_init(); | ||
211 | } | ||
diff --git a/arch/mips/netlogic/xlr/wakeup.c b/arch/mips/netlogic/xlr/wakeup.c new file mode 100644 index 000000000..d61cba1e9 --- /dev/null +++ b/arch/mips/netlogic/xlr/wakeup.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/delay.h> | ||
36 | #include <linux/threads.h> | ||
37 | |||
38 | #include <asm/asm.h> | ||
39 | #include <asm/asm-offsets.h> | ||
40 | #include <asm/mipsregs.h> | ||
41 | #include <asm/addrspace.h> | ||
42 | #include <asm/string.h> | ||
43 | |||
44 | #include <asm/netlogic/haldefs.h> | ||
45 | #include <asm/netlogic/common.h> | ||
46 | #include <asm/netlogic/mips-extns.h> | ||
47 | |||
48 | #include <asm/netlogic/xlr/iomap.h> | ||
49 | #include <asm/netlogic/xlr/pic.h> | ||
50 | |||
51 | int xlr_wakeup_secondary_cpus(void) | ||
52 | { | ||
53 | struct nlm_soc_info *nodep; | ||
54 | unsigned int i, j, boot_cpu; | ||
55 | volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); | ||
56 | |||
57 | /* | ||
58 | * In case of RMI boot, hit with NMI to get the cores | ||
59 | * from bootloader to linux code. | ||
60 | */ | ||
61 | nodep = nlm_get_node(0); | ||
62 | boot_cpu = hard_smp_processor_id(); | ||
63 | nlm_set_nmi_handler(nlm_rmiboot_preboot); | ||
64 | for (i = 0; i < NR_CPUS; i++) { | ||
65 | if (i == boot_cpu || !cpumask_test_cpu(i, &nlm_cpumask)) | ||
66 | continue; | ||
67 | nlm_pic_send_ipi(nodep->picbase, i, 1, 1); /* send NMI */ | ||
68 | } | ||
69 | |||
70 | /* Fill up the coremask early */ | ||
71 | nodep->coremask = 1; | ||
72 | for (i = 1; i < nlm_cores_per_node(); i++) { | ||
73 | for (j = 1000000; j > 0; j--) { | ||
74 | if (cpu_ready[i * NLM_THREADS_PER_CORE]) | ||
75 | break; | ||
76 | udelay(10); | ||
77 | } | ||
78 | if (j != 0) | ||
79 | nodep->coremask |= (1u << i); | ||
80 | else | ||
81 | pr_err("Failed to wakeup core %d\n", i); | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||