1 /* $NetBSD: brdsetup.c,v 1.7 2009/06/12 00:24:33 nisimura Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
40 const unsigned dcache_line_size
= 32; /* 32B linesize */
41 const unsigned dcache_range_size
= 4 * 1024; /* 16KB / 4-way */
44 void setup_82C686B(void);
45 void setup_83C553F(void);
47 static inline u_quad_t
mftb(void);
60 #define UART_READ(r) *(volatile char *)(uartbase + (r))
61 #define UART_WRITE(r, v) *(volatile char *)(uartbase + (r)) = (v)
66 unsigned pchb
, pcib
, div
;
68 /* BAT to arrange address space */
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
;
79 else if (pcifinddev(0x1106, 0x0686, &pcib
) == 0) {
80 brdtype
= BRD_ENCOREPP1
;
83 else if ((pcicfgread(pcimaketag(0, 11, 0), PCI_CLASS_REG
) >> 16) ==
85 /* tlp (ADMtek AN985) or re (RealTek 8169S) at dev 11 */
86 brdtype
= BRD_KUROBOX
;
90 if (pcifinddev(0x10ec, 0x8169, &pcib
) == 0) /* KURO-BOX/HG */
91 ticks_per_sec
= 133000000 / 4;
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 */
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 */
136 lsr
= UART_READ(LSR
);
137 } while (timo
-- > 0 && (lsr
& LSR_THRE
) == 0);
145 run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
149 static inline u_quad_t
155 asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
156 : "=r"(tb
), "=r"(scratch
));
163 u_quad_t tb
= mftb();
165 return (tb
/ TICKS_PER_SEC
);
169 * Wait for about n microseconds (at least!).
175 u_long tbh
, tbl
, scratch
;
178 tb
+= (n
* 1000 + NS_PER_TICK
- 1) / NS_PER_TICK
;
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
));
185 _wb(uint32_t adr
, uint32_t siz
)
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");
196 _wbinv(uint32_t adr
, uint32_t siz
)
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");
207 _inv(uint32_t adr
, uint32_t siz
)
211 off
= adr
& (dcache_line_size
- 1);
214 asm volatile ("eieio");
216 /* wbinv() leading unaligned dcache line */
217 asm volatile ("dcbf 0,%0" :: "r"(adr
));
218 if (siz
< dcache_line_size
)
220 adr
+= dcache_line_size
;
221 siz
-= dcache_line_size
;
224 off
= bnd
& (dcache_line_size
- 1);
226 /* wbinv() trailing unaligned dcache line */
227 asm volatile ("dcbf 0,%0" :: "r"(bnd
)); /* it's OK */
228 if (siz
< dcache_line_size
)
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
));
237 asm volatile ("sync");
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 */
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
267 #define EAR_MASK 0x30000000
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);
283 val
= pcicfgread(tag
, MPC106_MEMEN
);
284 for (n
= 0; n
< 4; n
++) {
285 if ((val
& (1U << n
)) == 0)
291 val
= pcicfgread(tag
, MPC106_EXTMEMENDADDR1
);
292 end
= ((val
>> bankn
) & 0x03) << 28;
293 val
= pcicfgread(tag
, MPC106_MEMENDADDR1
);
294 end
|= ((val
>> bankn
) & 0xff) << 20;
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)
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); \
325 val
= pcicfgread(pcib
, 0x84);
327 pcicfgwrite(pcib
, 0x84, val
);
328 CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
329 val
= pcicfgread(pcib
, 0x84);
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;
350 pcicfgwrite(usb12
, 0x3c, val
);
351 val
= pcicfgread(usb34
, 0x3c) &~ 0xff;
353 pcicfgwrite(usb34
, 0x3c, val
);
354 val
= pcicfgread(ac97
, 0x3c) &~ 0xff;
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)
369 unsigned pcib
, ide
, val
;
371 pcib
= pcimaketag(0, 11, 0);
372 ide
= pcimaketag(0, 11, 1);
379 unsigned pcib
, ide
, nic
, val
, steer
, irq
;
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");
398 unsigned i
, v
= steer
;
399 for (i
= 0; i
< 4; i
++, v
>>= 8) {
400 if ((v
& 0x80) != 0 || (v
& 0xf) == 0)
402 printf("PIRQ[%d]=%d\n", i
, v
& 0xf);
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);
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
);
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);
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
);
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
);
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);
482 * 0x57/56/55/54 - Dx CB Ax xS
484 val
= pcicfgread(pcib
, 0x54); /* Dx CB Ax xs */
486 irq
= (val
>> 12) & 0xf; /* 15:12 */
488 printf("pin A -> irq %d, %s\n",
489 irq
, STEER(steer
, 0x1));
491 irq
= (val
>> 16) & 0xf; /* 19:16 */
493 printf("pin B -> irq %d, %s\n",
494 irq
, STEER(steer
, 0x2));
496 irq
= (val
>> 20) & 0xf; /* 23:20 */
498 printf("pin C -> irq %d, %s\n",
499 irq
, STEER(steer
, 0x4));
501 irq
= (val
>> 28); /* 31:28 */
503 printf("pin D -> irq %d, %s\n",
504 irq
, STEER(steer
, 0x8));
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;
521 pcicfgwrite(ide
, 0x40, val
);
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;
532 pcicfgwrite(ide
, 0x08, val
);
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
546 /* ide: 0x40 - use primary only */
547 val
= pcicfgread(ide
, 0x40) &~ 03;
549 pcicfgwrite(ide
, 0x40, val
);
551 /* ide: 0x3d/3c - turn off PCI pin */
552 val
= pcicfgread(ide
, 0x3c) & 0xffff00ff;
553 pcicfgwrite(ide
, 0x3c, val
);
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
);