Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / sandpoint / stand / netboot / brdsetup.c
blobeb38429acf46b28d20e3a7db2d35d57c43a24d96
1 /* $NetBSD: brdsetup.c,v 1.7 2009/06/12 00:24:33 nisimura Exp $ */
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
34 #include <lib/libsa/stand.h>
35 #include <lib/libsa/net.h>
36 #include <lib/libkern/libkern.h>
38 #include "globals.h"
40 const unsigned dcache_line_size = 32; /* 32B linesize */
41 const unsigned dcache_range_size = 4 * 1024; /* 16KB / 4-way */
43 void brdsetup(void);
44 void setup_82C686B(void);
45 void setup_83C553F(void);
47 static inline u_quad_t mftb(void);
49 unsigned uartbase;
50 #define THR 0
51 #define DLB 0
52 #define DMB 1
53 #define IER 1
54 #define FCR 2
55 #define LCR 3
56 #define MCR 4
57 #define LSR 5
58 #define DCR 11
59 #define LSR_THRE 0x20
60 #define UART_READ(r) *(volatile char *)(uartbase + (r))
61 #define UART_WRITE(r, v) *(volatile char *)(uartbase + (r)) = (v)
63 void
64 brdsetup(void)
66 unsigned pchb, pcib, div;
68 /* BAT to arrange address space */
70 /* EUMBBAR */
71 pchb = pcimaketag(0, 0, 0);
72 pcicfgwrite(pchb, 0x78, 0xfc000000);
74 brdtype = BRD_UNKNOWN;
75 if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
76 brdtype = BRD_SANDPOINTX3;
77 setup_83C553F();
79 else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
80 brdtype = BRD_ENCOREPP1;
81 setup_82C686B();
83 else if ((pcicfgread(pcimaketag(0, 11, 0), PCI_CLASS_REG) >> 16) ==
84 PCI_CLASS_ETH) {
85 /* tlp (ADMtek AN985) or re (RealTek 8169S) at dev 11 */
86 brdtype = BRD_KUROBOX;
87 consname = "eumb";
88 consport = 0x4600;
89 consspeed = 57600;
90 if (pcifinddev(0x10ec, 0x8169, &pcib) == 0) /* KURO-BOX/HG */
91 ticks_per_sec = 133000000 / 4;
93 /* Stop Watchdog */
94 uartbase = 0xfc000000 + 0x4500;
95 div = (ticks_per_sec * 4) / 9600 / 16;
96 UART_WRITE(DCR, 0x01); /* 2 independent UART */
97 UART_WRITE(LCR, 0x80); /* turn on DLAB bit */
98 UART_WRITE(FCR, 0x00);
99 UART_WRITE(DMB, div >> 8);
100 UART_WRITE(DLB, div & 0xff);
101 UART_WRITE(LCR, 0x03 | 0x18); /* 8 E 1 */
102 UART_WRITE(MCR, 0x03); /* RTS DTR */
103 UART_WRITE(FCR, 0x07); /* FIFO_EN | RXSR | TXSR */
104 UART_WRITE(IER, 0x00); /* make sure INT disabled */
105 printf("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
108 /* now prepare serial console */
109 if (strcmp(consname, "eumb") != 0)
110 uartbase = 0xfe000000 + consport; /* 0x3f8, 0x2f8 */
111 else {
112 uartbase = 0xfc000000 + consport; /* 0x4500, 0x4600 */
113 div = (ticks_per_sec * 4) / consspeed / 16;
114 UART_WRITE(DCR, 0x01); /* 2 independent UART */
115 UART_WRITE(LCR, 0x80); /* turn on DLAB bit */
116 UART_WRITE(FCR, 0x00);
117 UART_WRITE(DMB, div >> 8);
118 UART_WRITE(DLB, div & 0xff); /* 0x36 when 115200bps@100MHz */
119 UART_WRITE(LCR, 0x03); /* 8 N 1 */
120 UART_WRITE(MCR, 0x03); /* RTS DTR */
121 UART_WRITE(FCR, 0x07); /* FIFO_EN | RXSR | TXSR */
122 UART_WRITE(IER, 0x00); /* make sure INT disabled */
126 void
127 putchar(int c)
129 unsigned timo, lsr;
131 if (c == '\n')
132 putchar('\r');
134 timo = 0x00100000;
135 do {
136 lsr = UART_READ(LSR);
137 } while (timo-- > 0 && (lsr & LSR_THRE) == 0);
138 if (timo > 0)
139 UART_WRITE(THR, c);
142 void
143 _rtt(void)
145 run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
146 /* NOTREACHED */
149 static inline u_quad_t
150 mftb(void)
152 u_long scratch;
153 u_quad_t tb;
155 asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
156 : "=r"(tb), "=r"(scratch));
157 return (tb);
160 satime_t
161 getsecs(void)
163 u_quad_t tb = mftb();
165 return (tb / TICKS_PER_SEC);
169 * Wait for about n microseconds (at least!).
171 void
172 delay(u_int n)
174 u_quad_t tb;
175 u_long tbh, tbl, scratch;
177 tb = mftb();
178 tb += (n * 1000 + NS_PER_TICK - 1) / NS_PER_TICK;
179 tbh = tb >> 32;
180 tbl = tb;
181 asm volatile ("1: mftbu %0; cmpw %0,%1; blt 1b; bgt 2f; mftb %0; cmpw 0, %0,%2; blt 1b; 2:" : "=&r"(scratch) : "r"(tbh), "r"(tbl));
184 void
185 _wb(uint32_t adr, uint32_t siz)
187 uint32_t bnd;
189 asm volatile("eieio");
190 for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
191 asm volatile ("dcbst 0,%0" :: "r"(adr));
192 asm volatile ("sync");
195 void
196 _wbinv(uint32_t adr, uint32_t siz)
198 uint32_t bnd;
200 asm volatile("eieio");
201 for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
202 asm volatile ("dcbf 0,%0" :: "r"(adr));
203 asm volatile ("sync");
206 void
207 _inv(uint32_t adr, uint32_t siz)
209 uint32_t off, bnd;
211 off = adr & (dcache_line_size - 1);
212 adr -= off;
213 siz += off;
214 asm volatile ("eieio");
215 if (off != 0) {
216 /* wbinv() leading unaligned dcache line */
217 asm volatile ("dcbf 0,%0" :: "r"(adr));
218 if (siz < dcache_line_size)
219 goto done;
220 adr += dcache_line_size;
221 siz -= dcache_line_size;
223 bnd = adr + siz;
224 off = bnd & (dcache_line_size - 1);
225 if (off != 0) {
226 /* wbinv() trailing unaligned dcache line */
227 asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
228 if (siz < dcache_line_size)
229 goto done;
230 siz -= off;
232 for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
233 /* inv() intermediate dcache lines if ever */
234 asm volatile ("dcbi 0,%0" :: "r"(adr));
236 done:
237 asm volatile ("sync");
240 unsigned
241 mpc107memsize()
243 unsigned tag, val, n, bankn, end;
245 tag = pcimaketag(0, 0, 0);
247 if (brdtype == BRD_ENCOREPP1) {
248 /* the brd's PPCBOOT looks to have erroneous values */
249 unsigned tbl[] = {
250 #define MPC106_MEMSTARTADDR1 0x80
251 #define MPC106_EXTMEMSTARTADDR1 0x88
252 #define MPC106_MEMENDADDR1 0x90
253 #define MPC106_EXTMEMENDADDR1 0x98
254 #define MPC106_MEMEN 0xa0
255 #define BK0_S 0x00000000
256 #define BK0_E (128 << 20) - 1
257 #define BK1_S 0x3ff00000
258 #define BK1_E 0x3fffffff
259 #define BK2_S 0x3ff00000
260 #define BK2_E 0x3fffffff
261 #define BK3_S 0x3ff00000
262 #define BK3_E 0x3fffffff
263 #define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
264 #define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
265 #define SAR_MASK 0x0ff00000
266 #define SAR_SHIFT 20
267 #define EAR_MASK 0x30000000
268 #define EAR_SHIFT 28
269 AR(BK0_S, 0) | AR(BK1_S, 8) | AR(BK2_S, 16) | AR(BK3_S, 24),
270 XR(BK0_S, 0) | XR(BK1_S, 8) | XR(BK2_S, 16) | XR(BK3_S, 24),
271 AR(BK0_E, 0) | AR(BK1_E, 8) | AR(BK2_E, 16) | AR(BK3_E, 24),
272 XR(BK0_E, 0) | XR(BK1_E, 8) | XR(BK2_E, 16) | XR(BK3_E, 24),
274 tag = pcimaketag(0, 0, 0);
275 pcicfgwrite(tag, MPC106_MEMSTARTADDR1, tbl[0]);
276 pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, tbl[1]);
277 pcicfgwrite(tag, MPC106_MEMENDADDR1, tbl[2]);
278 pcicfgwrite(tag, MPC106_EXTMEMENDADDR1, tbl[3]);
279 pcicfgwrite(tag, MPC106_MEMEN, 1);
282 bankn = 0;
283 val = pcicfgread(tag, MPC106_MEMEN);
284 for (n = 0; n < 4; n++) {
285 if ((val & (1U << n)) == 0)
286 break;
287 bankn = n;
289 bankn = bankn * 8;
291 val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
292 end = ((val >> bankn) & 0x03) << 28;
293 val = pcicfgread(tag, MPC106_MEMENDADDR1);
294 end |= ((val >> bankn) & 0xff) << 20;
295 end |= 0xfffff;
297 return (end + 1); /* size of bankN SDRAM */
301 * VIA82C686B Southbridge
302 * 0.22.0 1106.0686 PCI-ISA bridge
303 * 0.22.1 1106.0571 IDE (viaide)
304 * 0.22.2 1106.3038 USB 0/1 (uhci)
305 * 0.22.3 1106.3038 USB 2/3 (uhci)
306 * 0.22.4 1106.3057 power management
307 * 0.22.5 1106.3058 AC97 (auvia)
309 void
310 setup_82C686B()
312 unsigned pcib, ide, usb12, usb34, ac97, pmgt, val;
314 pcib = pcimaketag(0, 22, 0);
315 ide = pcimaketag(0, 22, 1);
316 usb12 = pcimaketag(0, 22, 2);
317 usb34 = pcimaketag(0, 22, 3);
318 pmgt = pcimaketag(0, 22, 4);
319 ac97 = pcimaketag(0, 22, 5);
321 #define CFG(i,v) do { \
322 *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
323 *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
324 } while (0)
325 val = pcicfgread(pcib, 0x84);
326 val |= (02 << 8);
327 pcicfgwrite(pcib, 0x84, val);
328 CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
329 val = pcicfgread(pcib, 0x84);
330 val &= ~(02 << 8);
331 pcicfgwrite(pcib, 0x84, val);
333 /* route pin C to i8259 IRQ 5, pin D to 11 */
334 val = pcicfgread(pcib, 0x54);
335 val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
336 pcicfgwrite(pcib, 0x54, val);
338 /* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
339 val = pcicfgread(pcib, 0x44);
340 val = val | 0x20000000;
341 pcicfgwrite(pcib, 0x44, val);
343 /* select level trigger for IRQ 5/11 at ELCR1/2 */
344 *(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
345 *(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */
347 /* USB and AC97 are hardwired with pin D and C */
348 val = pcicfgread(usb12, 0x3c) &~ 0xff;
349 val |= 11;
350 pcicfgwrite(usb12, 0x3c, val);
351 val = pcicfgread(usb34, 0x3c) &~ 0xff;
352 val |= 11;
353 pcicfgwrite(usb34, 0x3c, val);
354 val = pcicfgread(ac97, 0x3c) &~ 0xff;
355 val |= 5;
356 pcicfgwrite(ac97, 0x3c, val);
360 * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
362 * 0.11.0 10ad.0565 PCI-ISA bridge
363 * 0.11.1 10ad.0105 IDE (slide)
365 void
366 setup_83C553F()
368 #if 0
369 unsigned pcib, ide, val;
371 pcib = pcimaketag(0, 11, 0);
372 ide = pcimaketag(0, 11, 1);
373 #endif
376 void
377 pcifixup(void)
379 unsigned pcib, ide, nic, val, steer, irq;
380 int line;
382 switch (brdtype) {
383 case BRD_SANDPOINTX3:
384 pcib = pcimaketag(0, 11, 0);
385 ide = pcimaketag(0, 11, 1);
386 nic = pcimaketag(0, 15, 0);
389 * //// WinBond PIRQ ////
390 * 0x40 - bit 5 (0x20) indicates PIRQ presense
391 * 0x60 - PIRQ interrupt routing steer
393 if (pcicfgread(pcib, 0x40) & 0x20) {
394 steer = pcicfgread(pcib, 0x60);
395 if ((steer & 0x80808080) == 0x80808080)
396 printf("PIRQ[0-3] disabled\n");
397 else {
398 unsigned i, v = steer;
399 for (i = 0; i < 4; i++, v >>= 8) {
400 if ((v & 0x80) != 0 || (v & 0xf) == 0)
401 continue;
402 printf("PIRQ[%d]=%d\n", i, v & 0xf);
406 #if 1
408 * //// IDE fixup -- case A ////
409 * - "native PCI mode" (ide 0x09)
410 * - don't use ISA IRQ14/15 (pcib 0x43)
411 * - native IDE for both channels (ide 0x40)
412 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
413 * - sign as PCI pin C line 11 (ide 0x3d/3c)
415 /* ide: 0x09 - programming interface; 1000'SsPp */
416 val = pcicfgread(ide, 0x08);
417 val &= 0xffff00ff;
418 pcicfgwrite(ide, 0x08, val | (0x8f << 8));
420 /* pcib: 0x43 - IDE interrupt routing */
421 val = pcicfgread(pcib, 0x40) & 0x00ffffff;
422 pcicfgwrite(pcib, 0x40, val);
424 /* pcib: 0x45/44 - PCI interrupt routing */
425 val = pcicfgread(pcib, 0x44) & 0xffff0000;
426 pcicfgwrite(pcib, 0x44, val);
428 /* ide: 0x41/40 - IDE channel */
429 val = pcicfgread(ide, 0x40) & 0xffff0000;
430 val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
431 pcicfgwrite(ide, 0x40, val);
433 /* ide: 0x3d/3c - use PCI pin C/line 11 */
434 val = pcicfgread(ide, 0x3c) & 0xffffff00;
435 val |= 11; /* pin designation is hardwired to pin A */
436 pcicfgwrite(ide, 0x3c, val);
437 #else
439 * //// IDE fixup -- case B ////
440 * - "compatiblity mode" (ide 0x09)
441 * - IDE primary/secondary interrupt routing (pcib 0x43)
442 * - PCI interrupt routing (pcib 0x45/44)
443 * - no PCI pin/line assignment (ide 0x3d/3c)
445 /* ide: 0x09 - programming interface; 1000'SsPp */
446 val = pcicfgread(ide, 0x08);
447 val &= 0xffff00ff;
448 pcicfgwrite(ide, 0x08, val | (0x8a << 8));
450 /* pcib: 0x43 - IDE interrupt routing */
451 val = pcicfgread(pcib, 0x40) & 0x00ffffff;
452 pcicfgwrite(pcib, 0x40, val | (0xee << 24));
454 /* ide: 0x45/44 - PCI interrupt routing */
455 val = pcicfgread(ide, 0x44) & 0xffff0000;
456 pcicfgwrite(ide, 0x44, val);
458 /* ide: 0x3d/3c - turn off PCI pin/line */
459 val = pcicfgread(ide, 0x3c) & 0xffff0000;
460 pcicfgwrite(ide, 0x3c, val);
461 #endif
464 * //// fxp fixup ////
465 * - use PCI pin A line 15 (fxp 0x3d/3c)
467 val = pcicfgread(nic, 0x3c) & 0xffff0000;
468 pcidecomposetag(nic, NULL, &line, NULL);
469 val |= (('A' - '@') << 8) | line;
470 pcicfgwrite(nic, 0x3c, val);
471 break;
473 case BRD_ENCOREPP1:
474 #define STEER(v, b) (((v) & (b)) ? "edge" : "level")
476 pcib = pcimaketag(0, 22, 0);
477 ide = pcimaketag(0, 22, 1);
478 nic = pcimaketag(0, 25, 0);
481 * //// VIA PIRQ ////
482 * 0x57/56/55/54 - Dx CB Ax xS
484 val = pcicfgread(pcib, 0x54); /* Dx CB Ax xs */
485 steer = val & 0xf;
486 irq = (val >> 12) & 0xf; /* 15:12 */
487 if (irq) {
488 printf("pin A -> irq %d, %s\n",
489 irq, STEER(steer, 0x1));
491 irq = (val >> 16) & 0xf; /* 19:16 */
492 if (irq) {
493 printf("pin B -> irq %d, %s\n",
494 irq, STEER(steer, 0x2));
496 irq = (val >> 20) & 0xf; /* 23:20 */
497 if (irq) {
498 printf("pin C -> irq %d, %s\n",
499 irq, STEER(steer, 0x4));
501 irq = (val >> 28); /* 31:28 */
502 if (irq) {
503 printf("pin D -> irq %d, %s\n",
504 irq, STEER(steer, 0x8));
506 #if 0
508 * //// IDE fixup ////
509 * - "native mode" (ide 0x09)
510 * - use primary only (ide 0x40)
512 /* ide: 0x09 - programming interface; 1000'SsPp */
513 val = pcicfgread(ide, 0x08) & 0xffff00ff;
514 pcicfgwrite(ide, 0x08, val | (0x8f << 8));
516 /* ide: 0x10-20 - leave them PCI memory space assigned */
518 /* ide: 0x40 - use primary only */
519 val = pcicfgread(ide, 0x40) &~ 03;
520 val |= 02;
521 pcicfgwrite(ide, 0x40, val);
522 #else
524 * //// IDE fixup ////
525 * - "compatiblity mode" (ide 0x09)
526 * - use primary only (ide 0x40)
527 * - remove PCI pin assignment (ide 0x3d)
529 /* ide: 0x09 - programming interface; 1000'SsPp */
530 val = pcicfgread(ide, 0x08) & 0xffff00ff;
531 val |= (0x8a << 8);
532 pcicfgwrite(ide, 0x08, val);
534 /* ide: 0x10-20 */
536 experiment shows writing ide: 0x09 changes these
537 register behaviour. The pcicfgwrite() above writes
538 0x8a at ide: 0x09 to make sure legacy IDE. Then
539 reading BAR0-3 is to return value 0s even though
540 pcisetup() has written range assignments. Value
541 overwrite makes no effect. Having 0x8f for native
542 PCIIDE doesn't change register values and brings no
543 weirdness.
546 /* ide: 0x40 - use primary only */
547 val = pcicfgread(ide, 0x40) &~ 03;
548 val |= 02;
549 pcicfgwrite(ide, 0x40, val);
551 /* ide: 0x3d/3c - turn off PCI pin */
552 val = pcicfgread(ide, 0x3c) & 0xffff00ff;
553 pcicfgwrite(ide, 0x3c, val);
554 #endif
556 * //// USBx2, audio, and modem fixup ////
557 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
558 * - disable AC97 audio and MC97 modem (pcib 0x85)
561 /* pcib: 0x48 - disable USB #0 at function 2 */
562 val = pcicfgread(pcib, 0x48);
563 pcicfgwrite(pcib, 0x48, val | 04);
565 /* pcib: 0x85 - disable USB #1 at function 3 */
566 /* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
567 val = pcicfgread(pcib, 0x84);
568 pcicfgwrite(pcib, 0x84, val | 0x1c00);
571 * //// fxp fixup ////
572 * - use PCI pin A line 25 (fxp 0x3d/3c)
574 /* 0x3d/3c - PCI pin/line */
575 val = pcicfgread(nic, 0x3c) & 0xffff0000;
576 val |= (('A' - '@') << 8) | 25;
577 pcicfgwrite(nic, 0x3c, val);
578 break;