xref: /netbsd-src/sys/arch/evbmips/loongson/loongson2_machdep.c (revision ccb3b2f2320831ae6c9f7541e10c1cd964759f83)
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