ofwoea_machdep.c revision 1.1.2.1 1 /* $NetBSD: ofwoea_machdep.c,v 1.1.2.1 2007/06/06 17:38:35 garbled Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.1.2.1 2007/06/06 17:38:35 garbled Exp $");
41
42
43 #include "opt_compat_netbsd.h"
44 #include "opt_ddb.h"
45 #include "opt_kgdb.h"
46 #include "opt_ipkdb.h"
47
48 #include <sys/param.h>
49 #include <sys/buf.h>
50 #include <sys/boot_flag.h>
51 #include <sys/extent.h>
52 #include <sys/kernel.h>
53
54 #include <uvm/uvm_extern.h>
55
56 #include <dev/ofw/openfirm.h>
57 #include <machine/pmap.h>
58 #include <machine/powerpc.h>
59 #include <machine/trap.h>
60 #include <powerpc/bus.h>
61 #include <powerpc/oea/bat.h>
62 #include <powerpc/ofw_bus.h>
63 #include <powerpc/ofw_cons.h>
64 #include <powerpc/spr.h>
65 #include <arch/powerpc/pic/picvar.h>
66
67 #ifdef DDB
68 #include <machine/db_machdep.h>
69 #include <ddb/db_extern.h>
70 #endif
71
72 #ifdef KGDB
73 #include <sys/kgdb.h>
74 #endif
75
76 #ifdef IPKDB
77 #include <ipkdb/ipkdb.h>
78 #endif
79
80
81 typedef struct _rangemap {
82 u_int32_t addr;
83 u_int32_t size;
84 int type;
85 } rangemap_t;
86
87 struct ofw_translations {
88 vaddr_t va;
89 int len;
90 #if defined (PMAC_G5)
91 register64_t pa;
92 #else
93 register_t pa;
94 #endif
95 int mode;
96 }__attribute__((packed));
97
98 #define RANGE_TYPE_PCI 1
99 #define RANGE_TYPE_ISA 2
100 #define RANGE_TYPE_MACIO 3
101 #define RANGE_TYPE_FIRSTPCI 4
102 #define RANGE_IO 1
103 #define RANGE_MEM 2
104
105 struct pmap ofw_pmap;
106 struct ofw_translations ofmap[32];
107 char bootpath[256];
108 #if NKSYMS || defined(DDB) || defined(LKM)
109 void *startsym, *endsym;
110 #endif
111 #ifdef TIMEBASE_FREQ
112 u_int timebase_freq = TIMEBASE_FREQ;
113 #else
114 u_int timebase_freq = 0;
115 #endif
116
117 extern int ofmsr;
118 extern int chosen;
119 extern uint32_t ticks_per_sec;
120 extern uint32_t ns_per_tick;
121 extern uint32_t ticks_per_intr;
122
123 static int save_ofmap(struct ofw_translations *, int);
124 static void restore_ofmap(struct ofw_translations *, int);
125 static void set_timebase(void);
126
127 void
128 ofwoea_initppc(u_int startkernel, u_int endkernel, char *args)
129 {
130 int ofmaplen;
131 #if defined (PPC_OEA64_BRIDGE)
132 register_t scratch;
133 #endif
134
135 #if defined (PPC_OEA)
136 /* initialze bats */
137 ofwoea_batinit();
138 #elif defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
139 #endif /* PPC_OEA */
140
141 #if NKSYMS || defined(DDB) || defined(LKM)
142 /* get info of kernel symbol table from bootloader */
143 memcpy(&startsym, args + strlen(args) + 1, sizeof(startsym));
144 memcpy(&endsym, args + strlen(args) + 1 + sizeof(startsym),
145 sizeof(endsym));
146 if (startsym == NULL || endsym == NULL)
147 startsym = endsym = NULL;
148 #endif
149
150 ofwoea_bus_space_init();
151
152 ofwoea_consinit();
153
154 oea_init(pic_ext_intr);
155
156 ofmaplen = save_ofmap(NULL, 0);
157 if (ofmaplen > 0)
158 save_ofmap(ofmap, ofmaplen);
159
160 ofmsr &= ~PSL_IP;
161
162 /* Parse the args string */
163 if (args) {
164 strcpy(bootpath, args);
165 args = bootpath;
166 while (*++args && *args != ' ');
167 if (*args) {
168 *args++ = 0;
169 while (*args)
170 BOOT_FLAG(*args++, boothowto);
171 }
172 }
173
174 uvm_setpagesize();
175 pmap_bootstrap(startkernel, endkernel);
176
177 #if defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
178 #if defined (PMAC_G5)
179 /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
180 pmap_setup_segment0_map(0, 0xff800000, 0x3fc00000, 0x400000, 0x0);
181 #elif defined (MAMBO)
182 /* Mapin 1st 256MB segment 1:1, also map in mem needed to access OFW*/
183 pmap_setup_segment0_map(0, 0xf4000000, 0xf4000000, 0x1000, 0x0);
184 #endif /* PMAC_G5 */
185
186 /* Now enable translation (and machine checks/recoverable interrupts) */
187 __asm __volatile ("sync; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
188 : "=r"(scratch)
189 : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
190 #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE */
191
192 restore_ofmap(ofmap, ofmaplen);
193
194 /* CPU clock stuff */
195 set_timebase();
196 }
197
198 void
199 set_timebase(void)
200 {
201 int qhandle, phandle, msr, scratch;
202 char type[32];
203
204 if (timebase_freq != 0) {
205 ticks_per_sec = timebase_freq;
206 goto found;
207 }
208
209 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
210 if (OF_getprop(qhandle, "device_type", type, sizeof type) > 0
211 && strcmp(type, "cpu") == 0
212 && OF_getprop(qhandle, "timebase-frequency",
213 &ticks_per_sec, sizeof ticks_per_sec) > 0) {
214 goto found;
215 }
216 if ((phandle = OF_child(qhandle)))
217 continue;
218 while (qhandle) {
219 if ((phandle = OF_peer(qhandle)))
220 break;
221 qhandle = OF_parent(qhandle);
222 }
223 }
224 panic("no cpu node");
225
226 found:
227 __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
228 : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE));
229 ns_per_tick = 1000000000 / ticks_per_sec;
230 ticks_per_intr = ticks_per_sec / hz;
231 cpu_timebase = ticks_per_sec;
232 curcpu()->ci_lasttb = mftbl();
233 mtspr(SPR_DEC, ticks_per_intr);
234 mtmsr(msr);
235 }
236
237 static int
238 save_ofmap(struct ofw_translations *map, int maxlen)
239 {
240 int mmui, mmu, len;
241
242 OF_getprop(chosen, "mmu", &mmui, sizeof mmui);
243 mmu = OF_instance_to_package(mmui);
244
245 if (map) {
246 memset(map, 0, maxlen); /* to be safe */
247 len = OF_getprop(mmu, "translations", map, maxlen);
248 } else
249 len = OF_getproplen(mmu, "translations");
250
251 if (len < 0)
252 len = 0;
253 return len;
254 }
255
256 void
257 restore_ofmap(struct ofw_translations *map, int len)
258 {
259 int n = len / sizeof(struct ofw_translations);
260 int i;
261
262 pmap_pinit(&ofw_pmap);
263
264 #if defined(PPC_OEA64_BRIDGE)
265 ofw_pmap.pm_sr[0x0] = KERNELN_SEGMENT(0);
266 #endif
267 ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT;
268
269 #ifdef KERNEL2_SR
270 ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT;
271 #endif
272
273 for (i = 0; i < n; i++) {
274 #if defined (PMAC_G5)
275 register64_t pa = map[i].pa;
276 #else
277 register_t pa = map[i].pa;
278 #endif
279 vaddr_t va = map[i].va;
280 size_t length = map[i].len;
281
282 if (va < 0xf0000000) /* XXX */
283 continue;
284
285 while (length > 0) {
286 pmap_enter(&ofw_pmap, va, (paddr_t)pa, VM_PROT_ALL,
287 VM_PROT_ALL|PMAP_WIRED);
288 pa += PAGE_SIZE;
289 va += PAGE_SIZE;
290 length -= PAGE_SIZE;
291 }
292 }
293 pmap_update(&ofw_pmap);
294 }
295
296
297
298 /*
299 * Scan the device tree for ranges, and batmap them.
300 */
301
302 static u_int16_t
303 ranges_bitmap(int node, u_int16_t bitmap)
304 {
305 int child, mlen, len, acells, scells, reclen, i, addr, j;
306 u_int32_t map[160];
307
308 for (child = OF_child(node); child; child = OF_peer(child)) {
309 mlen = OF_getprop(child, "ranges", map, sizeof(map));
310 if (mlen == -1)
311 goto noranges;
312 len = OF_getprop(child, "#address-cells", &acells,
313 sizeof(acells));
314 if (len == -1)
315 goto noranges;
316 len = OF_getprop(child, "#size-cells", &scells,
317 sizeof(scells));
318 if (len == -1)
319 goto noranges;
320
321 reclen = acells+1+scells;
322
323 for (i=0; i < reclen/(mlen/4); i++) {
324 addr = map[reclen*i + acells + 1];
325 len = map[reclen*i + reclen - 1];
326 for (j=0; j < len/0x10000000; j++)
327 bitmap |= 1 << ((addr+j*0x10000000) >>28);
328 bitmap |= 1 << (addr >> 28);
329 }
330
331 noranges:
332 bitmap |= ranges_bitmap(child, bitmap);
333 continue;
334 }
335 return bitmap;
336 }
337
338 void
339 ofwoea_batinit(void)
340 {
341 u_int16_t bitmap;
342 int node, i;
343
344 node = OF_finddevice("/");
345 bitmap = ranges_bitmap(node, 0);
346
347 oea_batinit(0);
348
349 for (i=1; i < 0xf; i++)
350 if (bitmap & (1 << i))
351 oea_iobat_add(0x10000000 * i, BAT_BL_256M);
352 }
353
354
355 /* we define these partially, as we will fill the rest in later */
356 struct powerpc_bus_space ofwoea_io_space_tag = {
357 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
358 .pbs_base = 0x00000000,
359 };
360
361 struct powerpc_bus_space genppc_isa_io_space_tag = {
362 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
363 .pbs_base = 0x00000000,
364 };
365
366 struct powerpc_bus_space ofwoea_mem_space_tag = {
367 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
368 .pbs_base = 0x00000000,
369 };
370
371 struct powerpc_bus_space genppc_isa_mem_space_tag = {
372 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
373 .pbs_base = 0x00000000,
374 };
375
376 static char ex_storage[2][EXTENT_FIXED_STORAGE_SIZE(8)]
377 __attribute__((aligned(8)));
378
379
380 static void
381 find_ranges(int base, rangemap_t *regions, int *cur, int type)
382 {
383 int node, i, len, reclen, foundfirst;
384 u_int32_t acells, scells, map[160];
385 char tmp[32];
386
387 foundfirst = 0;
388
389 for (node = OF_child(base); node; node = OF_peer(node)) {
390 if (OF_getprop(node, "device_type", tmp, sizeof(tmp)) == -1)
391 goto nxt;
392 if ((type == RANGE_TYPE_PCI || type == RANGE_TYPE_FIRSTPCI) &&
393 strcmp("pci", tmp) != 0)
394 goto nxt;
395 if (type == RANGE_TYPE_ISA && strcmp("isa", tmp) != 0)
396 goto nxt;
397 foundfirst++;
398 len = OF_getprop(node, "ranges", map, sizeof(map));
399 if (len == -1)
400 goto nxt;
401 if (OF_getprop(node, "#address-cells", &acells,
402 sizeof(acells)) != sizeof(acells))
403 acells = 1;
404 if (OF_getprop(node, "#size-cells", &scells,
405 sizeof(scells)) != sizeof(scells))
406 scells = 1;
407 if (type == RANGE_TYPE_ISA)
408 reclen = 6;
409 else
410 reclen = acells + scells + 1;
411 printf("found a map reclen=%d cur=%d\n", reclen, *cur);
412 switch (type) {
413 case RANGE_TYPE_PCI:
414 case RANGE_TYPE_FIRSTPCI:
415 for (i=0; i < len/(4*reclen); i++) {
416 regions[*cur].type = map[i*reclen] >> 24;
417 regions[*cur].addr = map[i*reclen + acells];
418 regions[*cur].size =
419 map[i*reclen + acells + scells];
420 (*cur)++;
421 }
422 break;
423 case RANGE_TYPE_ISA:
424 for (i=0; i < len/(4*reclen); i++) {
425 if (map[i*reclen] == 1)
426 regions[*cur].type = RANGE_IO;
427 else
428 regions[*cur].type = RANGE_MEM;
429 regions[*cur].size =
430 map[i*reclen + acells + scells];
431 (*cur)++;
432 }
433 break;
434 }
435 nxt:
436 if (type != RANGE_TYPE_FIRSTPCI)
437 find_ranges(node, regions, cur, type);
438 else if (foundfirst)
439 return;
440 continue;
441 }
442 }
443
444 static int
445 find_lowest_range(rangemap_t *ranges, int nrof, int type)
446 {
447 int i, low = 0;
448 u_int32_t addr = 0xffffffff;
449
450 for (i=0; i < nrof; i++) {
451 if (ranges[i].type == type && ranges[i].addr != 0 &&
452 ranges[i].addr < addr) {
453 low = i;
454 addr = ranges[i].addr;
455 }
456 }
457 if (addr == 0xffffffff)
458 return -1;
459 return low;
460 }
461
462 static int
463 ofwoea_map_space(int rangetype, int iomem)
464 {
465 int node, i, cur, range, nrofholes, error;
466 u_int32_t addr;
467 rangemap_t region, holes[32], list[32];
468
469 memset(list, 0, sizeof(list));
470 cur = 0;
471 node = OF_finddevice("/");
472 if (rangetype == RANGE_TYPE_ISA) {
473 u_int32_t size = 0;
474 rangemap_t regions[32];
475
476 find_ranges(node, list, &cur, RANGE_TYPE_FIRSTPCI);
477 range = 0;
478 find_ranges(node, regions, &range, RANGE_TYPE_ISA);
479 if (range == 0 || cur == 0)
480 return -1; /* no isa stuff found */
481 for (i=0; i < range; i++)
482 if (regions[i].type == iomem)
483 size = regions[i].size;
484 if (iomem == RANGE_IO) {
485 /* the first io range is the one */
486 for (i=0; i < cur; i++)
487 if (list[i].type == RANGE_IO && size) {
488 genppc_isa_io_space_tag.pbs_offset =
489 list[i].addr;
490 genppc_isa_io_space_tag.pbs_limit =
491 size;
492 error = bus_space_init(
493 &genppc_isa_io_space_tag,
494 "isa-ioport", NULL, 0);
495 return error;
496 }
497 } else {
498 for (i=0; i < cur; i++)
499 if (list[i].type == RANGE_MEM &&
500 list[i].size == size) {
501 genppc_isa_mem_space_tag.pbs_offset =
502 list[i].addr;
503 genppc_isa_mem_space_tag.pbs_limit =
504 size;
505 error = bus_space_init(
506 &genppc_isa_mem_space_tag,
507 "isa-iomem", NULL, 0);
508 return error;
509 }
510 }
511 return -1; /* NO ISA FOUND */
512 }
513 find_ranges(node, list, &cur, rangetype);
514
515 printf("cur == %d\n", cur);
516 /* now list should contain a list of memory regions */
517 for (i=0; i < cur; i++)
518 printf("addr=0x%x size=0x%x type=%d\n", list[i].addr,
519 list[i].size, list[i].type);
520
521 addr=0;
522 range = find_lowest_range(list, cur, iomem);
523 i = 0;
524 nrofholes = 0;
525 printf("range==%d\n", range);
526 while (range != -1) {
527 printf("i==%d\n", i);
528 if (i == 0) {
529 memcpy(®ion, &list[range], sizeof(rangemap_t));
530 list[range].addr = 0;
531 i++;
532 range = find_lowest_range(list, cur, iomem);
533 continue;
534 }
535 if (region.addr + region.size < list[range].addr) {
536 /* allocate a hole */
537 holes[nrofholes].addr = region.size + region.addr;
538 holes[nrofholes].size = list[range].addr -
539 holes[nrofholes].addr - 1;
540 nrofholes++;
541 }
542 region.size += list[range].size + list[range].addr -
543 region.addr + region.size;
544 list[range].addr = 0;
545 range = find_lowest_range(list, cur, iomem);
546 }
547 printf("RANGE iomem=%d FOUND\n", iomem);
548 printf("addr=0x%x size=0x%x type=%d\n", region.addr,
549 region.size, region.type);
550 printf("HOLES FOUND\n");
551 for (i=0; i < nrofholes; i++)
552 printf("addr=0x%x size=0x%x type=%d\n", holes[i].addr,
553 holes[i].size, holes[i].type);
554 /* AT THIS POINT WE MAP IT */
555
556 if (rangetype == RANGE_TYPE_PCI && iomem == RANGE_IO) {
557 ofwoea_io_space_tag.pbs_offset = region.addr;
558 ofwoea_io_space_tag.pbs_limit = region.size;
559 error = bus_space_init(&ofwoea_io_space_tag, "ioport",
560 ex_storage[0], sizeof(ex_storage[0]));
561 if (error)
562 panic("ofwoea_bus_space_init: can't init io tag");
563 for (i=0; i < nrofholes; i++) {
564 error =
565 extent_alloc_region(ofwoea_io_space_tag.pbs_extent,
566 holes[i].addr, holes[i].size, EX_NOWAIT);
567 if (error)
568 panic("ofwoea_bus_space_init: can't block out"
569 " reserved IO space 0x%x-0x%x: error=%d",
570 holes[i].addr, holes[i].addr+holes[i].size,
571 error);
572 }
573 return error;
574 }
575 if (rangetype == RANGE_TYPE_PCI && iomem == RANGE_MEM) {
576 ofwoea_mem_space_tag.pbs_offset = region.addr;
577 ofwoea_mem_space_tag.pbs_limit = region.size;
578 error = bus_space_init(&ofwoea_mem_space_tag, "iomem",
579 ex_storage[1], sizeof(ex_storage[1]));
580 if (error)
581 panic("ofwoea_bus_space_init: can't init mem tag");
582 for (i=0; i < nrofholes; i++) {
583 error =
584 extent_alloc_region(ofwoea_io_space_tag.pbs_extent,
585 holes[i].addr, holes[i].size, EX_NOWAIT);
586 if (error)
587 panic("ofwoea_bus_space_init: can't block out"
588 "reserved MEM space 0x%x-0x%x: error=%d",
589 holes[i].addr, holes[i].addr+holes[i].size,
590 error);
591 }
592 return error;
593 }
594 return -1;
595 }
596
597 void
598 ofwoea_bus_space_init(void)
599 {
600 int error;
601
602 error = ofwoea_map_space(RANGE_TYPE_PCI, RANGE_IO);
603 if (error)
604 panic("Could not map PCI IO");
605 error = ofwoea_map_space(RANGE_TYPE_PCI, RANGE_MEM);
606 if (error)
607 panic("Could not map PCI MEM");
608 error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_IO);
609 if (error > 0)
610 panic("Could not map ISA IO");
611 error = ofwoea_map_space(RANGE_TYPE_ISA, RANGE_MEM);
612 if (error > 0)
613 panic("Could not map ISA MEM");
614 }
615