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