1 /* $OpenBSD: loongson2_machdep.c,v 1.11 2011/03/31 20:37:44 miod Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2010 Miodrag Vallat.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/proc.h>
23 #include <sys/sysctl.h>
24 #include <sys/kcore.h>
25
26 #include <uvm/uvm_extern.h>
27
28 #include <evbmips/loongson/autoconf.h>
29 #include <evbmips/loongson/loongson_intr.h>
30 #include <machine/kcore.h>
31 #include <machine/cpu.h>
32 #include <mips/pmon/pmon.h>
33
34 #include <mips/bonito/bonitoreg.h>
35 #include <mips/bonito/bonitovar.h>
36
37 boolean_t is_memory_range(paddr_t, psize_t, psize_t);
38 static void loongson2f_setup_window(uint, uint, uint64_t, uint64_t, uint64_t, uint);
39
40 /*
41 * Canonical crossbow assignments on Loongson 2F based designs.
42 * Might need to move to a per-design header file in the future.
43 */
44
45 #define MASTER_CPU 0
46 #define MASTER_PCI 1
47
48 #define WINDOW_CPU_LOW 0
49 #define WINDOW_CPU_PCILO 1
50 #define WINDOW_CPU_PCIHI 2
51 #define WINDOW_CPU_DDR 3
52
53 #define WINDOW_PCI_DDR 0
54
55 #define DDR_PHYSICAL_BASE 0x0000000000000000UL /* memory starts at 0 */
56 #define DDR_PHYSICAL_SIZE 0x0000000080000000UL /* up to 2GB */
57 #define DDR_WINDOW_BASE 0x0000000080000000UL /* mapped at 2GB */
58
59 #define PCI_RESOURCE_BASE 0x0000000000000000UL
60 #define PCI_RESOURCE_SIZE 0x0000000080000000UL
61
62 #define PCI_DDR_BASE 0x0000000080000000UL /* PCI->DDR at 2GB */
63
64 /* bonito interrupt mappings */
65 const struct bonito_irqmap loongson2e_irqmap[BONITO_NDIRECT] = {
66 { "mbox0", BONITO_INTR_MBOX + 0, IRQ_F_INT0 },
67 { "mbox1", BONITO_INTR_MBOX + 1, IRQ_F_INT0 },
68 { "mbox2", BONITO_INTR_MBOX + 2, IRQ_F_INT0 },
69 { "mbox3", BONITO_INTR_MBOX + 3, IRQ_F_INT0 },
70 { "dmardy", BONITO_INTR_MBOX + 4, IRQ_F_INT0 },
71 { "dmaempty", BONITO_INTR_MBOX + 5, IRQ_F_INT0 },
72 { "copyrdy", BONITO_INTR_MBOX + 6, IRQ_F_INT0 },
73 { "copyempty", BONITO_INTR_MBOX + 7, IRQ_F_INT0 },
74 { "coperr", BONITO_INTR_MBOX + 8, IRQ_F_INT1 },
75 { "pciirq", BONITO_INTR_MBOX + 9, IRQ_F_INT0 },
76 { "mastererr", BONITO_INTR_MBOX + 10, IRQ_F_INT1 },
77 { "systemerr", BONITO_INTR_MBOX + 11, IRQ_F_INT1 },
78 { "dramerr", BONITO_INTR_MBOX + 12, IRQ_F_INT1 },
79 { "retryerr", BONITO_INTR_MBOX + 13, IRQ_F_INT1 },
80 { NULL, BONITO_INTR_MBOX + 14, 0 },
81 { NULL, BONITO_INTR_MBOX + 15, 0 },
82 { "gpio0", BONITO_INTR_GPIO + 0, IRQ_F_INT0 },
83 { "gpio1", BONITO_INTR_GPIO + 1, IRQ_F_INT0 },
84 { "gpio2", BONITO_INTR_GPIO + 2, IRQ_F_INT0 },
85 { "gpio3", BONITO_INTR_GPIO + 3, IRQ_F_INT0 },
86 { "gpio4", BONITO_INTR_GPIO + 4, IRQ_F_INT0 },
87 { "gpio5", BONITO_INTR_GPIO + 5, IRQ_F_INT0 },
88 { "gpio6", BONITO_INTR_GPIO + 6, IRQ_F_INT0 },
89 { "gpio7", BONITO_INTR_GPIO + 7, IRQ_F_INT0 },
90 { "gpio8", BONITO_INTR_GPIO + 8, IRQ_F_INT0 },
91 { "gpin0", BONITO_INTR_GPIN + 0, IRQ_F_INT0 },
92 { "gpin1", BONITO_INTR_GPIN + 1, IRQ_F_INT0 },
93 { "gpin2", BONITO_INTR_GPIN + 2, IRQ_F_INT0 },
94 { "gpin3", BONITO_INTR_GPIN + 3, IRQ_F_INT0 },
95 { "gpin4", BONITO_INTR_GPIN + 4, IRQ_F_INT0 },
96 { "gpin5", BONITO_INTR_GPIN + 5, IRQ_F_INT0 },
97 { NULL, BONITO_INTR_GPIN + 6, 0 },
98 };
99
100 const struct bonito_irqmap loongson2f_irqmap[BONITO_NDIRECT] = {
101 { "gpio0", LOONGSON_INTR_GPIO0, IRQ_F_INT0 },
102 { "gpio1", LOONGSON_INTR_GPIO1, IRQ_F_INT0 },
103 { "gpio2", LOONGSON_INTR_GPIO2, IRQ_F_INT0 },
104 { "gpio3", LOONGSON_INTR_GPIO3, IRQ_F_INT0 },
105
106 { "pci inta", LOONGSON_INTR_PCIA, IRQ_F_INT0 },
107 { "pci intb", LOONGSON_INTR_PCIB, IRQ_F_INT0 },
108 { "pci intc", LOONGSON_INTR_PCIC, IRQ_F_INT0 },
109 { "pci intd", LOONGSON_INTR_PCID, IRQ_F_INT0 },
110
111 { "pci perr", LOONGSON_INTR_PCI_PARERR, IRQ_F_EDGE|IRQ_F_INT1 },
112 { "pci serr", LOONGSON_INTR_PCI_SYSERR, IRQ_F_EDGE|IRQ_F_INT1 },
113
114 { "denali", LOONGSON_INTR_DRAM_PARERR, IRQ_F_INT1 },
115
116 { "mips int0", LOONGSON_INTR_INT0, IRQ_F_INT0 },
117 { "mips int1", LOONGSON_INTR_INT1, IRQ_F_INT1 },
118 { "mips int2", LOONGSON_INTR_INT2, IRQ_F_INT2 },
119 { "mips int3", LOONGSON_INTR_INT3, IRQ_F_INT3 },
120 };
121
122 /*
123 * Setup memory mappings for Loongson 2E processors.
124 */
125
126 void
loongson2e_setup(paddr_t memlo,paddr_t memhi,vaddr_t vkernstart,vaddr_t vkernend,bus_dma_tag_t t)127 loongson2e_setup(paddr_t memlo, paddr_t memhi,
128 vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
129 {
130 if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) {
131 pmon_printf("WARNING! %d MB of memory will not be used",
132 memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20));
133 memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20;
134 }
135
136 physmem = btoc(memlo + memhi);
137
138 /* do NOT stomp on exception area */
139 /* mips_page_physload() will skip the kernel */
140 mem_clusters[0].start = DDR_PHYSICAL_BASE;
141 mem_clusters[0].size = memlo;
142 mem_cluster_cnt = 1;
143
144 if (memhi != 0) {
145 mem_clusters[1].start = BONITO_PCIHI_BASE;
146 mem_clusters[1].size = memhi;
147 mem_cluster_cnt = 2;
148 }
149
150 t->_wbase = PCI_DDR_BASE;
151 t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
152 t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
153 }
154
155 /*
156 * Setup memory mappings for Loongson 2F processors.
157 */
158
159 void
loongson2f_setup(paddr_t memlo,paddr_t memhi,vaddr_t vkernstart,vaddr_t vkernend,bus_dma_tag_t t)160 loongson2f_setup(paddr_t memlo, paddr_t memhi,
161 vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
162 {
163 /*
164 * Because we'll only set up a 2GB window for the PCI bus to
165 * access local memory, we'll limit ourselves to 2GB of usable
166 * memory as well.
167 *
168 * Note that this is a bad justification for this; it should be
169 * possible to setup a 1GB PCI space / 3GB memory access window,
170 * and use bounce buffers if physmem > 3GB; but at the moment
171 * there is no need to solve this problem until Loongson 2F-based
172 * hardware with more than 2GB of memory is commonly encountered.
173 *
174 * Also note that, despite the crossbar window registers being
175 * 64-bit wide, the upper 32-bit always read back as zeroes, so
176 * it is dubious whether it is possible to use more than a 4GB
177 * address space... and thus more than 2GB of physical memory.
178 */
179
180 physmem = btoc(memlo + memhi);
181 if (physmem > btoc(DDR_PHYSICAL_SIZE)) {
182 pmon_printf("WARNING! %d MB of memory will not be used",
183 (physmem >> 20) - (DDR_PHYSICAL_SIZE >> 20));
184 memhi = DDR_PHYSICAL_SIZE - btoc(256 << 20);
185 }
186
187 physmem = btoc(memlo + memhi);
188
189 /*
190 * PMON configures the system with only the low 256MB of memory
191 * accessible.
192 *
193 * We need to reprogram the address windows in order to be able to
194 * access the whole memory, both by the local processor and by the
195 * PCI bus.
196 *
197 * To make our life easier, we'll setup the memory as a contiguous
198 * range starting at 2GB, and take into account the fact that the
199 * first 256MB are also aliased at address zero (which is where the
200 * kernel is loaded, really).
201 */
202
203 if (memhi != 0 ) {
204 /* do NOT stomp on exception area */
205 /* also make sure to skip the kernel */
206 const paddr_t kernend = MIPS_KSEG0_TO_PHYS(round_page(vkernend));
207 mem_clusters[0].start = DDR_WINDOW_BASE + kernend;
208 mem_clusters[0].size = (memlo + memhi - kernend);
209 t->_wbase = PCI_DDR_BASE;
210 t->_bounce_alloc_lo = DDR_WINDOW_BASE;
211 t->_bounce_alloc_hi = DDR_WINDOW_BASE + DDR_PHYSICAL_SIZE;
212 mem_cluster_cnt = 1;
213 } else {
214 /* do NOT stomp on exception area */
215 /* mips_page_physload() will skip the kernel */
216 mem_clusters[0].start = DDR_PHYSICAL_BASE + PAGE_SIZE;
217 mem_clusters[0].size = (memlo + memhi - PAGE_SIZE - PAGE_SIZE);
218 t->_wbase = PCI_DDR_BASE;
219 t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
220 t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
221 mem_cluster_cnt = 1;
222 }
223
224 /*
225 * Allow access to memory beyond 256MB, by programming the
226 * Loongson 2F address window registers.
227 * This also makes sure PCI->DDR accesses can use a contiguous
228 * area regardless of the actual memory size.
229 */
230
231 /*
232 * Master #0 (cpu) window #0 allows access to the low 256MB
233 * of memory at address zero onwards.
234 * This window is inherited from PMON; we set it up just in case.
235 */
236 loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_LOW, DDR_PHYSICAL_BASE,
237 ~(0x0fffffffUL), DDR_PHYSICAL_BASE, MASTER_CPU);
238
239 /*
240 * Master #0 (cpu) window #1 allows access to the ``low'' PCI
241 * space (from 0x10000000 to 0x1fffffff).
242 * This window is inherited from PMON; we set it up just in case.
243 */
244 loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCILO, BONITO_PCILO_BASE,
245 ~(0x0fffffffUL), BONITO_PCILO_BASE, MASTER_PCI);
246
247 /*
248 * Master #1 (PCI) window #0 allows access to the memory space
249 * by PCI devices at addresses 0x80000000 onwards.
250 * This window is inherited from PMON, but its mask might be too
251 * restrictive (256MB) so we make sure it matches our needs.
252 */
253 loongson2f_setup_window(MASTER_PCI, WINDOW_PCI_DDR, PCI_DDR_BASE,
254 ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
255
256 /*
257 * Master #0 (CPU) window #2 allows access to a subset of the ``high''
258 * PCI space (from 0x40000000 to 0x7fffffff only).
259 */
260 loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCIHI, LS2F_PCIHI_BASE,
261 ~((uint64_t)LS2F_PCIHI_SIZE - 1), LS2F_PCIHI_BASE, MASTER_PCI);
262
263 /*
264 * Master #0 (CPU) window #3 allows access to the whole memory space
265 * at addresses 0x80000000 onwards.
266 */
267 loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_DDR, DDR_WINDOW_BASE,
268 ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
269
270 }
271
272 /*
273 * Setup a window in the Loongson2F crossbar.
274 */
275
276 static void
loongson2f_setup_window(uint master,uint window,uint64_t base,uint64_t mask,uint64_t mmap,uint slave)277 loongson2f_setup_window(uint master, uint window, uint64_t base, uint64_t mask,
278 uint64_t mmap, uint slave)
279 {
280 volatile uint64_t *awrreg;
281
282 awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
283 LOONGSON_AWR_BASE(master, window));
284 *awrreg = base;
285 (void)*awrreg;
286
287 awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
288 LOONGSON_AWR_SIZE(master, window));
289 *awrreg = mask;
290 (void)*awrreg;
291
292 awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
293 LOONGSON_AWR_MMAP(master, window));
294 *awrreg = mmap | slave;
295 (void)*awrreg;
296 }
297
298 /*
299 * Return whether a given physical address points to managed memory.
300 * (used by /dev/mem)
301 */
302
303 boolean_t
is_memory_range(paddr_t pa,psize_t len,psize_t limit)304 is_memory_range(paddr_t pa, psize_t len, psize_t limit)
305 {
306 uint64_t fp, lp;
307 int i;
308
309 fp = atop(pa);
310 lp = atop(round_page(pa + len));
311
312 if (limit != 0 && lp > atop(limit))
313 return FALSE;
314
315 /*
316 * Allow access to the low 256MB aliased region on 2F systems,
317 * if we are accessing memory at 2GB onwards.
318 */
319 if (pa < 0x10000000 && loongson_ver >= 0x2f) {
320 fp += btoc(mem_clusters[0].start);
321 lp += btoc(mem_clusters[0].start);
322 }
323
324 for (i = 0; i < VM_PHYSSEG_MAX; i++)
325 if (fp >= btoc(mem_clusters[i].start) &&
326 lp <= btoc(mem_clusters[i].start + mem_clusters[i].size))
327 return TRUE;
328
329 return FALSE;
330 }
331