Home | History | Annotate | Line # | Download | only in altboot
brdsetup.c revision 1.24
      1 /* $NetBSD: brdsetup.c,v 1.24 2012/01/07 19:57:49 phx Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Tohru Nishimura.
      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  *
     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.
     30  */
     31 
     32 #include <sys/param.h>
     33 
     34 #include <powerpc/psl.h>
     35 #include <powerpc/oea/spr.h>
     36 
     37 #include <lib/libsa/stand.h>
     38 #include <lib/libsa/net.h>
     39 #include <lib/libkern/libkern.h>
     40 
     41 #include <machine/bootinfo.h>
     42 
     43 #include "globals.h"
     44 
     45 #define BRD_DECL(xxx) \
     46     void xxx ## setup(struct brdprop *); \
     47     void xxx ## brdfix(struct brdprop *); \
     48     void xxx ## pcifix(struct brdprop *); \
     49     void xxx ## reset(void)
     50 
     51 BRD_DECL(mot);
     52 BRD_DECL(enc);
     53 BRD_DECL(kuro);
     54 BRD_DECL(syno);
     55 BRD_DECL(qnap);
     56 BRD_DECL(iomega);
     57 BRD_DECL(dlink);
     58 BRD_DECL(nhnas);
     59 
     60 static struct brdprop brdlist[] = {
     61     {
     62 	"sandpoint",
     63 	"Sandpoint X3",
     64 	BRD_SANDPOINTX3,
     65 	0,
     66 	"com", 0x3f8, 115200,
     67 	motsetup, motbrdfix, motpcifix, NULL },
     68     {
     69 	"encpp1",
     70 	"EnCore PP1",
     71 	BRD_ENCOREPP1,
     72 	0,
     73 	"com", 0x3f8, 115200,
     74 	encsetup, encbrdfix, encpcifix, NULL },
     75     {
     76 	"kurobox",
     77 	"KuroBox",
     78 	BRD_KUROBOX,
     79 	32768000,
     80 	"eumb", 0x4600, 57600,
     81 	kurosetup, kurobrdfix, NULL, NULL },
     82     {
     83 	"synology",
     84 	"Synology DS",
     85 	BRD_SYNOLOGY,
     86 	33164691,	/* from Synology/Linux source            */
     87 			/* XXX should be 33165343 for the CS-406 */
     88 	"eumb", 0x4500, 115200,
     89 	NULL, synobrdfix, NULL, synoreset },
     90     {
     91 	"qnap",
     92 	"QNAP TS",
     93 	BRD_QNAPTS,
     94 	33164691,	/* Linux source says 33000000, but the Synology  */
     95 			/* clock value delivers a much better precision. */
     96 	"eumb", 0x4500, 115200,
     97 	NULL, qnapbrdfix, NULL, qnapreset },
     98     {
     99 	"iomega",
    100 	"IOMEGA StorCenter G2",
    101 	BRD_STORCENTER,
    102 	0,
    103 	"eumb", 0x4500, 115200,
    104 	NULL, iomegabrdfix, NULL, iomegareset },
    105     {
    106 	"dlink",
    107 	"D-Link DSM-G600",
    108 	BRD_DLINKDSM,
    109 	33000000,
    110 	"eumb", 0x4500, 9600,
    111 	NULL, dlinkbrdfix, NULL, NULL },
    112     {
    113 	"nhnas",
    114 	"Netronics NH230/231",
    115 	BRD_NH230NAS,
    116 	0,
    117 	"eumb", 0x4500, 9600,
    118 	NULL, nhnasbrdfix, NULL, NULL },
    119     {
    120 	"unknown",
    121 	"Unknown board",
    122 	BRD_UNKNOWN,
    123 	0,
    124 	"eumb", 0x4500, 115200,
    125 	NULL, NULL, NULL, NULL }, /* must be the last */
    126 };
    127 
    128 /* MPC106 and MPC824x PCI bridge memory configuration */
    129 #define MPC106_MEMSTARTADDR1	0x80
    130 #define MPC106_EXTMEMSTARTADDR1	0x88
    131 #define MPC106_MEMENDADDR1	0x90
    132 #define MPC106_EXTMEMENDADDR1	0x98
    133 #define MPC106_MEMEN		0xa0
    134 
    135 /* Iomega StorCenter MC68HC908 microcontroller data packet */
    136 #define IOMEGA_POWER		0
    137 #define IOMEGA_LED		1
    138 #define IOMEGA_FLASH_RATE	2
    139 #define IOMEGA_FAN		3
    140 #define IOMEGA_HIGH_TEMP	4
    141 #define IOMEGA_LOW_TEMP		5
    142 #define IOMEGA_ID		6
    143 #define IOMEGA_CHECKSUM		7
    144 #define IOMEGA_PACKETSIZE	8
    145 
    146 static struct brdprop *brdprop;
    147 static uint32_t ticks_per_sec, ns_per_tick;
    148 
    149 static void brdfixup(void);
    150 static void setup(void);
    151 static void send_iomega(int, int, int, int, int, int);
    152 static inline uint32_t mfmsr(void);
    153 static inline void mtmsr(uint32_t);
    154 static inline uint32_t cputype(void);
    155 static inline u_quad_t mftb(void);
    156 static void init_uart(unsigned, unsigned, uint8_t);
    157 static void send_sat(char *);
    158 static unsigned mpc107memsize(void);
    159 
    160 const unsigned dcache_line_size = 32;		/* 32B linesize */
    161 const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */
    162 
    163 unsigned uart1base;	/* console */
    164 unsigned uart2base;	/* optional satellite processor */
    165 #define RBR		0
    166 #define THR		0
    167 #define DLB		0
    168 #define DMB		1
    169 #define IER		1
    170 #define FCR		2
    171 #define LCR		3
    172 #define  LCR_DLAB	0x80
    173 #define  LCR_PEVEN	0x18
    174 #define  LCR_PNONE	0x00
    175 #define  LCR_8BITS	0x03
    176 #define MCR		4
    177 #define  MCR_RTS	0x02
    178 #define  MCR_DTR	0x01
    179 #define LSR		5
    180 #define  LSR_THRE	0x20
    181 #define  LSR_DRDY	0x01
    182 #define DCR		0x11
    183 #define UART_READ(base, r)	in8(base + (r))
    184 #define UART_WRITE(base, r, v)	out8(base + (r), (v))
    185 
    186 void brdsetup(void);	/* called by entry.S */
    187 
    188 void
    189 brdsetup(void)
    190 {
    191 	static uint8_t pci_to_memclk[] = {
    192 		30, 30, 10, 10, 20, 10, 10, 10,
    193 		10, 20, 20, 15, 20, 15, 20, 30,
    194 		30, 40, 15, 40, 20, 25, 20, 40,
    195 		25, 20, 10, 20, 15, 15, 20, 00
    196 	};
    197 	static uint8_t mem_to_cpuclk[] = {
    198 		25, 30, 45, 20, 20, 00, 10, 30,
    199 		30, 20, 45, 30, 25, 35, 30, 35,
    200 		20, 25, 20, 30, 35, 40, 40, 20,
    201 		30, 25, 40, 30, 30, 25, 35, 00
    202 	};
    203 	char *consname;
    204 	int consport;
    205 	uint32_t extclk;
    206 	unsigned pchb, pcib, dev11, dev13, dev15, dev16, val;
    207 	extern struct btinfo_memory bi_mem;
    208 	extern struct btinfo_console bi_cons;
    209 	extern struct btinfo_clock bi_clk;
    210 	extern struct btinfo_prodfamily bi_fam;
    211 
    212 	/*
    213 	 * CHRP specification "Map-B" BAT012 layout
    214 	 *   BAT0 0000-0000 (256MB) SDRAM
    215 	 *   BAT1 8000-0000 (256MB) PCI mem space
    216 	 *   BAT2 fc00-0000 (64MB)  EUMB, PCI I/O space, misc devs, flash
    217 	 *
    218 	 * EUMBBAR is at fc00-0000.
    219 	 */
    220 	pchb = pcimaketag(0, 0, 0);
    221 	pcicfgwrite(pchb, 0x78, 0xfc000000);
    222 
    223 	brdtype = BRD_UNKNOWN;
    224 	extclk = EXT_CLK_FREQ;	/* usually 33MHz */
    225 	busclock = 0;
    226 
    227 	dev11 = pcimaketag(0, 11, 0);
    228 	dev13 = pcimaketag(0, 13, 0);
    229 	dev15 = pcimaketag(0, 15, 0);
    230 	dev16 = pcimaketag(0, 16, 0);
    231 
    232 	if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
    233 		/* WinBond 553 southbridge at dev 11 */
    234 		brdtype = BRD_SANDPOINTX3;
    235 	}
    236 	else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
    237 		/* VIA 686B southbridge at dev 22 */
    238 		brdtype = BRD_ENCOREPP1;
    239 	}
    240 	else if (PCI_CLASS(pcicfgread(dev11, PCI_CLASS_REG)) == PCI_CLASS_ETH) {
    241 		/* ADMtek AN985 (tlp) or RealTek 8169S (re) at dev 11 */
    242 		brdtype = BRD_KUROBOX;
    243 	}
    244 	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x11ab) {
    245 		/* SKnet/Marvell (sk) at dev 15 */
    246 		brdtype = BRD_SYNOLOGY;
    247 	}
    248 	else if (PCI_VENDOR(pcicfgread(dev13, PCI_ID_REG)) == 0x1106) {
    249 		/* VIA 6410 (viaide) at dev 13 */
    250 		brdtype = BRD_STORCENTER;
    251 	}
    252 	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1191) {
    253 		/* ACARD ATP865 (acardide) at dev 16 */
    254 		brdtype = BRD_DLINKDSM;
    255 	}
    256 	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1283
    257 	    || PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1095) {
    258 		/* ITE (iteide) or SiI (satalink) at dev 16 */
    259 		brdtype = BRD_NH230NAS;
    260 	}
    261 	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x8086
    262 	    || PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x10ec) {
    263 		/* Intel (wm) or RealTek (re) at dev 15 */
    264 		brdtype = BRD_QNAPTS;
    265 	}
    266 
    267 	brdprop = brd_lookup(brdtype);
    268 
    269 	/* brd dependent adjustments */
    270 	setup();
    271 
    272 	/* determine clock frequencies */
    273 	if (brdprop->extclk != 0)
    274 		extclk = brdprop->extclk;
    275 	if (busclock == 0) {
    276 		if (cputype() == MPC8245) {
    277 			/* PLL_CFG from PCI host bridge register 0xe2 */
    278 			val = pcicfgread(pchb, 0xe0);
    279 			busclock = (extclk *
    280 			    pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
    281 			/* PLLRATIO from HID1 */
    282 			asm volatile ("mfspr %0,1009" : "=r"(val));
    283 			cpuclock = ((uint64_t)busclock *
    284 			    mem_to_cpuclk[val >> 27] + 10) / 10;
    285 		} else
    286 			busclock = 100000000;	/* 100MHz bus clock default */
    287 	}
    288 	ticks_per_sec = busclock >> 2;
    289 	ns_per_tick = 1000000000 / ticks_per_sec;
    290 
    291 	/* now prepare serial console */
    292 	consname = brdprop->consname;
    293 	consport = brdprop->consport;
    294 	if (strcmp(consname, "eumb") == 0) {
    295 		uart1base = 0xfc000000 + consport;	/* 0x4500, 0x4600 */
    296 		UART_WRITE(uart1base, DCR, 0x01);	/* enable DUART mode */
    297 		uart2base = uart1base ^ 0x0300;
    298 	} else
    299 		uart1base = 0xfe000000 + consport;	/* 0x3f8, 0x2f8 */
    300 
    301 	/* more brd adjustments */
    302 	brdfixup();
    303 
    304 	bi_mem.memsize = mpc107memsize();
    305 	snprintf(bi_cons.devname, sizeof(bi_cons.devname), consname);
    306 	bi_cons.addr = consport;
    307 	bi_cons.speed = brdprop->consspeed;
    308 	bi_clk.ticks_per_sec = ticks_per_sec;
    309 	snprintf(bi_fam.name, sizeof(bi_fam.name), brdprop->family);
    310 }
    311 
    312 struct brdprop *
    313 brd_lookup(int brd)
    314 {
    315 	u_int i;
    316 
    317 	for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
    318 		if (brdlist[i].brdtype == brd)
    319 			return &brdlist[i];
    320 	}
    321 	return &brdlist[i - 1];
    322 }
    323 
    324 static void
    325 setup()
    326 {
    327 
    328 	if (brdprop->setup == NULL)
    329 		return;
    330 	(*brdprop->setup)(brdprop);
    331 }
    332 
    333 static void
    334 brdfixup()
    335 {
    336 
    337 	if (brdprop->brdfix == NULL)
    338 		return;
    339 	(*brdprop->brdfix)(brdprop);
    340 }
    341 
    342 void
    343 pcifixup()
    344 {
    345 
    346 	if (brdprop->pcifix == NULL)
    347 		return;
    348 	(*brdprop->pcifix)(brdprop);
    349 }
    350 
    351 void
    352 encsetup(struct brdprop *brd)
    353 {
    354 
    355 #ifdef COSNAME
    356 	brd->consname = CONSNAME;
    357 #endif
    358 #ifdef CONSPORT
    359 	brd->consport = CONSPORT;
    360 #endif
    361 #ifdef CONSSPEED
    362 	brd->consspeed = CONSSPEED;
    363 #endif
    364 }
    365 
    366 void
    367 encbrdfix(struct brdprop *brd)
    368 {
    369 	unsigned ac97, ide, pcib, pmgt, usb12, usb34, val;
    370 
    371 /*
    372  * VIA82C686B Southbridge
    373  *	0.22.0	1106.0686	PCI-ISA bridge
    374  *	0.22.1	1106.0571	IDE (viaide)
    375  *	0.22.2	1106.3038	USB 0/1 (uhci)
    376  *	0.22.3	1106.3038	USB 2/3 (uhci)
    377  *	0.22.4	1106.3057	power management
    378  *	0.22.5	1106.3058	AC97 (auvia)
    379  */
    380 	pcib  = pcimaketag(0, 22, 0);
    381 	ide   = pcimaketag(0, 22, 1);
    382 	usb12 = pcimaketag(0, 22, 2);
    383 	usb34 = pcimaketag(0, 22, 3);
    384 	pmgt  = pcimaketag(0, 22, 4);
    385 	ac97  = pcimaketag(0, 22, 5);
    386 
    387 #define	CFG(i,v) do { \
    388    *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
    389    *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
    390    } while (0)
    391 	val = pcicfgread(pcib, 0x84);
    392 	val |= (02 << 8);
    393 	pcicfgwrite(pcib, 0x84, val);
    394 	CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
    395 	val = pcicfgread(pcib, 0x84);
    396 	val &= ~(02 << 8);
    397 	pcicfgwrite(pcib, 0x84, val);
    398 
    399 	/* route pin C to i8259 IRQ 5, pin D to 11 */
    400 	val = pcicfgread(pcib, 0x54);
    401 	val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
    402 	pcicfgwrite(pcib, 0x54, val);
    403 
    404 	/* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
    405 	val = pcicfgread(pcib, 0x44);
    406 	val = val | 0x20000000;
    407 	pcicfgwrite(pcib, 0x44, val);
    408 
    409 	/* select level trigger for IRQ 5/11 at ELCR1/2 */
    410 	*(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
    411 	*(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */
    412 
    413 	/* USB and AC97 are hardwired with pin D and C */
    414 	val = pcicfgread(usb12, 0x3c) &~ 0xff;
    415 	val |= 11;
    416 	pcicfgwrite(usb12, 0x3c, val);
    417 	val = pcicfgread(usb34, 0x3c) &~ 0xff;
    418 	val |= 11;
    419 	pcicfgwrite(usb34, 0x3c, val);
    420 	val = pcicfgread(ac97, 0x3c) &~ 0xff;
    421 	val |= 5;
    422 	pcicfgwrite(ac97, 0x3c, val);
    423 }
    424 
    425 void
    426 encpcifix(struct brdprop *brd)
    427 {
    428 	unsigned ide, irq, net, pcib, steer, val;
    429 
    430 #define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
    431 	pcib = pcimaketag(0, 22, 0);
    432 	ide  = pcimaketag(0, 22, 1);
    433 	net  = pcimaketag(0, 25, 0);
    434 
    435 	/*
    436 	 * //// VIA PIRQ ////
    437 	 * 0x57/56/55/54 - Dx CB Ax xS
    438 	 */
    439 	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
    440 	steer = val & 0xf;
    441 	irq = (val >> 12) & 0xf;	/* 15:12 */
    442 	if (irq) {
    443 		printf("pin A -> irq %d, %s\n",
    444 			irq, STEER(steer, 0x1));
    445 	}
    446 	irq = (val >> 16) & 0xf;	/* 19:16 */
    447 	if (irq) {
    448 		printf("pin B -> irq %d, %s\n",
    449 			irq, STEER(steer, 0x2));
    450 	}
    451 	irq = (val >> 20) & 0xf;	/* 23:20 */
    452 	if (irq) {
    453 		printf("pin C -> irq %d, %s\n",
    454 			irq, STEER(steer, 0x4));
    455 	}
    456 	irq = (val >> 28);		/* 31:28 */
    457 	if (irq) {
    458 		printf("pin D -> irq %d, %s\n",
    459 			irq, STEER(steer, 0x8));
    460 	}
    461 #if 0
    462 	/*
    463 	 * //// IDE fixup ////
    464 	 * - "native mode" (ide 0x09)
    465 	 */
    466 
    467 	/* ide: 0x09 - programming interface; 1000'SsPp */
    468 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    469 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    470 
    471 	/* ide: 0x10-20 - leave them PCI memory space assigned */
    472 #else
    473 	/*
    474 	 * //// IDE fixup ////
    475 	 * - "compatiblity mode" (ide 0x09)
    476 	 * - remove PCI pin assignment (ide 0x3d)
    477 	 */
    478 
    479 	/* ide: 0x09 - programming interface; 1000'SsPp */
    480 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    481 	val |= (0x8a << 8);
    482 	pcicfgwrite(ide, 0x08, val);
    483 
    484 	/* ide: 0x10-20 */
    485 	/*
    486 	 * experiment shows writing ide: 0x09 changes these
    487 	 * register behaviour. The pcicfgwrite() above writes
    488 	 * 0x8a at ide: 0x09 to make sure legacy IDE.  Then
    489 	 * reading BAR0-3 is to return value 0s even though
    490 	 * pcisetup() has written range assignments.  Value
    491 	 * overwrite makes no effect. Having 0x8f for native
    492 	 * PCIIDE doesn't change register values and brings no
    493 	 * weirdness.
    494 	 */
    495 
    496 	/* ide: 0x3d/3c - turn off PCI pin */
    497 	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
    498 	pcicfgwrite(ide, 0x3c, val);
    499 #endif
    500 	/*
    501 	 * //// USBx2, audio, and modem fixup ////
    502 	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
    503 	 * - disable AC97 audio and MC97 modem (pcib 0x85)
    504 	 */
    505 
    506 	/* pcib: 0x48 - disable USB #0 at function 2 */
    507 	val = pcicfgread(pcib, 0x48);
    508 	pcicfgwrite(pcib, 0x48, val | 04);
    509 
    510 	/* pcib: 0x85 - disable USB #1 at function 3 */
    511 	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
    512 	val = pcicfgread(pcib, 0x84);
    513 	pcicfgwrite(pcib, 0x84, val | 0x1c00);
    514 
    515 	/*
    516 	 * //// fxp fixup ////
    517 	 * - use PCI pin A line 25 (fxp 0x3d/3c)
    518 	 */
    519 	/* 0x3d/3c - PCI pin/line */
    520 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    521 	val |= (('A' - '@') << 8) | 25;
    522 	pcicfgwrite(net, 0x3c, val);
    523 }
    524 
    525 void
    526 motsetup(struct brdprop *brd)
    527 {
    528 
    529 #ifdef COSNAME
    530 	brd->consname = CONSNAME;
    531 #endif
    532 #ifdef CONSPORT
    533 	brd->consport = CONSPORT;
    534 #endif
    535 #ifdef CONSSPEED
    536 	brd->consspeed = CONSSPEED;
    537 #endif
    538 }
    539 
    540 void
    541 motbrdfix(struct brdprop *brd)
    542 {
    543 
    544 /*
    545  * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
    546  *
    547  *	0.11.0	10ad.0565	PCI-ISA bridge
    548  *	0.11.1	10ad.0105	IDE (slide)
    549  */
    550 }
    551 
    552 void
    553 motpcifix(struct brdprop *brd)
    554 {
    555 	unsigned ide, net, pcib, steer, val;
    556 	int line;
    557 
    558 	pcib = pcimaketag(0, 11, 0);
    559 	ide  = pcimaketag(0, 11, 1);
    560 	net  = pcimaketag(0, 15, 0);
    561 
    562 	/*
    563 	 * //// WinBond PIRQ ////
    564 	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
    565 	 * 0x60 - PIRQ interrupt routing steer
    566 	 */
    567 	if (pcicfgread(pcib, 0x40) & 0x20) {
    568 		steer = pcicfgread(pcib, 0x60);
    569 		if ((steer & 0x80808080) == 0x80808080)
    570 			printf("PIRQ[0-3] disabled\n");
    571 		else {
    572 			unsigned i, v = steer;
    573 			for (i = 0; i < 4; i++, v >>= 8) {
    574 				if ((v & 0x80) != 0 || (v & 0xf) == 0)
    575 					continue;
    576 				printf("PIRQ[%d]=%d\n", i, v & 0xf);
    577 				}
    578 			}
    579 		}
    580 #if 1
    581 	/*
    582 	 * //// IDE fixup -- case A ////
    583 	 * - "native PCI mode" (ide 0x09)
    584 	 * - don't use ISA IRQ14/15 (pcib 0x43)
    585 	 * - native IDE for both channels (ide 0x40)
    586 	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
    587 	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
    588 	 */
    589 	/* ide: 0x09 - programming interface; 1000'SsPp */
    590 	val = pcicfgread(ide, 0x08);
    591 	val &= 0xffff00ff;
    592 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    593 
    594 	/* pcib: 0x43 - IDE interrupt routing */
    595 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    596 	pcicfgwrite(pcib, 0x40, val);
    597 
    598 	/* pcib: 0x45/44 - PCI interrupt routing */
    599 	val = pcicfgread(pcib, 0x44) & 0xffff0000;
    600 	pcicfgwrite(pcib, 0x44, val);
    601 
    602 	/* ide: 0x41/40 - IDE channel */
    603 	val = pcicfgread(ide, 0x40) & 0xffff0000;
    604 	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
    605 	pcicfgwrite(ide, 0x40, val);
    606 
    607 	/* ide: 0x3d/3c - use PCI pin C/line 11 */
    608 	val = pcicfgread(ide, 0x3c) & 0xffffff00;
    609 	val |= 11; /* pin designation is hardwired to pin A */
    610 	pcicfgwrite(ide, 0x3c, val);
    611 #else
    612 	/*
    613 	 * //// IDE fixup -- case B ////
    614 	 * - "compatiblity mode" (ide 0x09)
    615 	 * - IDE primary/secondary interrupt routing (pcib 0x43)
    616 	 * - PCI interrupt routing (pcib 0x45/44)
    617 	 * - no PCI pin/line assignment (ide 0x3d/3c)
    618 	 */
    619 	/* ide: 0x09 - programming interface; 1000'SsPp */
    620 	val = pcicfgread(ide, 0x08);
    621 	val &= 0xffff00ff;
    622 	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
    623 
    624 	/* pcib: 0x43 - IDE interrupt routing */
    625 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    626 	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
    627 
    628 	/* ide: 0x45/44 - PCI interrupt routing */
    629 	val = pcicfgread(ide, 0x44) & 0xffff0000;
    630 	pcicfgwrite(ide, 0x44, val);
    631 
    632 	/* ide: 0x3d/3c - turn off PCI pin/line */
    633 	val = pcicfgread(ide, 0x3c) & 0xffff0000;
    634 	pcicfgwrite(ide, 0x3c, val);
    635 #endif
    636 
    637 	/*
    638 	 * //// fxp fixup ////
    639 	 * - use PCI pin A line 15 (fxp 0x3d/3c)
    640 	 */
    641 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    642 	pcidecomposetag(net, NULL, &line, NULL);
    643 	val |= (('A' - '@') << 8) | line;
    644 	pcicfgwrite(net, 0x3c, val);
    645 }
    646 
    647 void
    648 kurosetup(struct brdprop *brd)
    649 {
    650 
    651 	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
    652 		brd->extclk = 32768000; /* decr 2457600Hz */
    653 	else
    654 		brd->extclk = 32521333; /* decr 2439100Hz */
    655 }
    656 
    657 void
    658 kurobrdfix(struct brdprop *brd)
    659 {
    660 
    661 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
    662 	/* Stop Watchdog */
    663 	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
    664 }
    665 
    666 void
    667 synobrdfix(struct brdprop *brd)
    668 {
    669 
    670 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    671 	/* beep, power LED on, status LED off */
    672 	send_sat("247");
    673 }
    674 
    675 void
    676 synoreset()
    677 {
    678 
    679 	send_sat("C");
    680 	/*NOTREACHED*/
    681 }
    682 
    683 void
    684 qnapbrdfix(struct brdprop *brd)
    685 {
    686 
    687 	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
    688 	/* beep, status LED red */
    689 	send_sat("PW");
    690 }
    691 
    692 void
    693 qnapreset()
    694 {
    695 
    696 	send_sat("f");
    697 	/*NOTREACHED*/
    698 }
    699 
    700 void
    701 iomegabrdfix(struct brdprop *brd)
    702 {
    703 
    704 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    705 	/* LED flashing blue, fan auto, turn on at 50C, turn off at 45C */
    706 	send_iomega('b', 'd', 2, 'a', 50, 45);
    707 }
    708 
    709 void
    710 iomegareset()
    711 {
    712 
    713 	send_iomega('g', 0, 0, 0, 0, 0);
    714 	/*NOTREACHED*/
    715 }
    716 
    717 void
    718 dlinkbrdfix(struct brdprop *brd)
    719 {
    720 
    721 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    722 	send_sat("SYN\n");
    723 	send_sat("ZWO\n");	/* power LED solid on */
    724 }
    725 
    726 void
    727 nhnasbrdfix(struct brdprop *brd)
    728 {
    729 
    730 	/* illuminate LEDs */
    731 }
    732 
    733 void
    734 _rtt(void)
    735 {
    736 	uint32_t msr;
    737 
    738 	netif_shutdown_all();
    739 
    740 	if (brdprop->reset != NULL)
    741 		(*brdprop->reset)();
    742 	else {
    743 		msr = mfmsr();
    744 		msr &= ~PSL_EE;
    745 		mtmsr(msr);
    746 		asm volatile ("sync; isync");
    747 		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
    748 		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
    749 		mtmsr(msr);
    750 		asm volatile ("sync; isync");
    751 		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
    752 	}
    753 	/*NOTREACHED*/
    754 }
    755 
    756 satime_t
    757 getsecs(void)
    758 {
    759 	u_quad_t tb = mftb();
    760 
    761 	return (tb / ticks_per_sec);
    762 }
    763 
    764 /*
    765  * Wait for about n microseconds (at least!).
    766  */
    767 void
    768 delay(u_int n)
    769 {
    770 	u_quad_t tb;
    771 	u_long scratch, tbh, tbl;
    772 
    773 	tb = mftb();
    774 	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
    775 	tbh = tb >> 32;
    776 	tbl = tb;
    777 	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));
    778 }
    779 
    780 void
    781 _wb(uint32_t adr, uint32_t siz)
    782 {
    783 	uint32_t bnd;
    784 
    785 	asm volatile("eieio");
    786 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    787 		asm volatile ("dcbst 0,%0" :: "r"(adr));
    788 	asm volatile ("sync");
    789 }
    790 
    791 void
    792 _wbinv(uint32_t adr, uint32_t siz)
    793 {
    794 	uint32_t bnd;
    795 
    796 	asm volatile("eieio");
    797 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    798 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    799 	asm volatile ("sync");
    800 }
    801 
    802 void
    803 _inv(uint32_t adr, uint32_t siz)
    804 {
    805 	uint32_t bnd, off;
    806 
    807 	off = adr & (dcache_line_size - 1);
    808 	adr -= off;
    809 	siz += off;
    810 	asm volatile ("eieio");
    811 	if (off != 0) {
    812 		/* wbinv() leading unaligned dcache line */
    813 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    814 		if (siz < dcache_line_size)
    815 			goto done;
    816 		adr += dcache_line_size;
    817 		siz -= dcache_line_size;
    818 	}
    819 	bnd = adr + siz;
    820 	off = bnd & (dcache_line_size - 1);
    821 	if (off != 0) {
    822 		/* wbinv() trailing unaligned dcache line */
    823 		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
    824 		if (siz < dcache_line_size)
    825 			goto done;
    826 		siz -= off;
    827 	}
    828 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
    829 		/* inv() intermediate dcache lines if ever */
    830 		asm volatile ("dcbi 0,%0" :: "r"(adr));
    831 	}
    832   done:
    833 	asm volatile ("sync");
    834 }
    835 
    836 static inline uint32_t
    837 mfmsr(void)
    838 {
    839 	uint32_t msr;
    840 
    841 	asm volatile ("mfmsr %0" : "=r"(msr));
    842 	return msr;
    843 }
    844 
    845 static inline void
    846 mtmsr(uint32_t msr)
    847 {
    848 	asm volatile ("mtmsr %0" : : "r"(msr));
    849 }
    850 
    851 static inline uint32_t
    852 cputype(void)
    853 {
    854 	uint32_t pvr;
    855 
    856 	asm volatile ("mfpvr %0" : "=r"(pvr));
    857 	return pvr >> 16;
    858 }
    859 
    860 static inline u_quad_t
    861 mftb(void)
    862 {
    863 	u_long scratch;
    864 	u_quad_t tb;
    865 
    866 	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
    867 	    : "=r"(tb), "=r"(scratch));
    868 	return tb;
    869 }
    870 
    871 static void
    872 init_uart(unsigned base, unsigned speed, uint8_t lcr)
    873 {
    874 	unsigned div;
    875 
    876 	div = busclock / speed / 16;
    877 	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
    878 	UART_WRITE(base, FCR, 0x00);
    879 	UART_WRITE(base, DMB, div >> 8);	/* set speed */
    880 	UART_WRITE(base, DLB, div & 0xff);
    881 	UART_WRITE(base, LCR, lcr);
    882 	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
    883 	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
    884 }
    885 
    886 /* talk to satellite processor */
    887 static void
    888 send_sat(char *msg)
    889 {
    890 	unsigned savedbase;
    891 
    892 	savedbase = uart1base;
    893 	uart1base = uart2base;
    894 	while (*msg)
    895 		putchar(*msg++);
    896 	uart1base = savedbase;
    897 }
    898 
    899 #ifdef DEBUG
    900 static void
    901 iomega_debug(const char *txt, uint8_t buf[])
    902 {
    903 	int i;
    904 
    905 	printf("%s:", txt);
    906 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    907 		printf(" %02x", buf[i]);
    908 	putchar('\n');
    909 }
    910 #endif /* DEBUG */
    911 
    912 static void
    913 send_iomega(int power, int led, int rate, int fan, int high, int low)
    914 {
    915 	uint8_t buf[IOMEGA_PACKETSIZE];
    916 	unsigned i, savedbase;
    917 
    918 	savedbase = uart1base;
    919 	uart1base = uart2base;
    920 
    921 	/* first flush the receive buffer */
    922   again:
    923 	while (tstchar())
    924 		(void)getchar();
    925 	delay(20000);
    926 	if (tstchar())
    927 		goto again;
    928 	/*
    929 	 * Now synchronize the transmitter by sending 0x00
    930 	 * until we receive a status reply.
    931 	 */
    932 	do {
    933 		putchar(0);
    934 		delay(50000);
    935 	} while (!tstchar());
    936 
    937 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    938 		buf[i] = getchar();
    939 #ifdef DEBUG
    940 	uart1base = savedbase;
    941 	iomega_debug("68HC908 status", buf);
    942 	uart1base = uart2base;
    943 #endif
    944 
    945 	/* send command */
    946 	buf[IOMEGA_POWER] = power;
    947 	buf[IOMEGA_LED] = led;
    948 	buf[IOMEGA_FLASH_RATE] = rate;
    949 	buf[IOMEGA_FAN] = fan;
    950 	buf[IOMEGA_HIGH_TEMP] = high;
    951 	buf[IOMEGA_LOW_TEMP] = low;
    952 	buf[IOMEGA_ID] = 7;	/* host id */
    953 	buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
    954 	    buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
    955 	    buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
    956 	    buf[IOMEGA_ID]) & 0x7f;
    957 #ifdef DEBUG
    958 	uart1base = savedbase;
    959 	iomega_debug("G2 sending", buf);
    960 	uart1base = uart2base;
    961 #endif
    962 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    963 		putchar(buf[i]);
    964 
    965 	/* receive the reply */
    966 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    967 		buf[i] = getchar();
    968 #ifdef DEBUG
    969 	uart1base = savedbase;
    970 	iomega_debug("68HC908 reply", buf);
    971 	uart1base = uart2base;
    972 #endif
    973 
    974 	if (buf[0] == '#')
    975 		goto again;  /* try again on error */
    976 	uart1base = savedbase;
    977 }
    978 
    979 void
    980 putchar(int c)
    981 {
    982 	unsigned timo, lsr;
    983 
    984 	if (c == '\n')
    985 		putchar('\r');
    986 
    987 	timo = 0x00100000;
    988 	do {
    989 		lsr = UART_READ(uart1base, LSR);
    990 	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
    991 	if (timo > 0)
    992 		UART_WRITE(uart1base, THR, c);
    993 }
    994 
    995 int
    996 getchar(void)
    997 {
    998 	unsigned lsr;
    999 
   1000 	do {
   1001 		lsr = UART_READ(uart1base, LSR);
   1002 	} while ((lsr & LSR_DRDY) == 0);
   1003 	return UART_READ(uart1base, RBR);
   1004 }
   1005 
   1006 int
   1007 tstchar(void)
   1008 {
   1009 
   1010 	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
   1011 }
   1012 
   1013 #define SAR_MASK 0x0ff00000
   1014 #define SAR_SHIFT    20
   1015 #define EAR_MASK 0x30000000
   1016 #define EAR_SHIFT    28
   1017 #define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
   1018 #define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
   1019 static void
   1020 set_mem_bounds(unsigned tag, unsigned bk_en, ...)
   1021 {
   1022 	unsigned mbst, mbxst, mben, mbxen;
   1023 	unsigned start, end;
   1024 	va_list ap;
   1025 	int i, sh;
   1026 
   1027 	va_start(ap, bk_en);
   1028 	mbst = mbxst = mben = mbxen = 0;
   1029 
   1030 	for (i = 0; i < 4; i++) {
   1031 		if ((bk_en & (1U << i)) != 0) {
   1032 			start = va_arg(ap, unsigned);
   1033 			end = va_arg(ap, unsigned);
   1034 		} else {
   1035 			start = 0x3ff00000;
   1036 			end = 0x3fffffff;
   1037 		}
   1038 		sh = i << 3;
   1039 		mbst |= AR(start, sh);
   1040 		mbxst |= XR(start, sh);
   1041 		mben |= AR(end, sh);
   1042 		mbxen |= XR(end, sh);
   1043 	}
   1044 	va_end(ap);
   1045 
   1046 	pcicfgwrite(tag, MPC106_MEMSTARTADDR1, mbst);
   1047 	pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, mbxst);
   1048 	pcicfgwrite(tag, MPC106_MEMENDADDR1, mben);
   1049 	pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	mbxen);
   1050 	pcicfgwrite(tag, MPC106_MEMEN,
   1051 	    (pcicfgread(tag, MPC106_MEMEN) & ~0xff) | (bk_en & 0xff));
   1052 }
   1053 
   1054 static unsigned
   1055 mpc107memsize(void)
   1056 {
   1057 	unsigned bankn, end, n, tag, val;
   1058 
   1059 	tag = pcimaketag(0, 0, 0);
   1060 
   1061 	if (brdtype == BRD_ENCOREPP1) {
   1062 		/* the brd's PPCBOOT looks to have erroneous values */
   1063 		set_mem_bounds(tag, 1, 0x00000000, (128 << 20) - 1);
   1064 	} else if (brdtype == BRD_NH230NAS) {
   1065 		/*
   1066 		 * PPCBoot sets the end address to 0x7ffffff, although the
   1067 		 * board has just 64MB (0x3ffffff).
   1068 		 */
   1069 		set_mem_bounds(tag, 1, 0x00000000, 0x03ffffff);
   1070 	}
   1071 
   1072 	bankn = 0;
   1073 	val = pcicfgread(tag, MPC106_MEMEN);
   1074 	for (n = 0; n < 4; n++) {
   1075 		if ((val & (1U << n)) == 0)
   1076 			break;
   1077 		bankn = n;
   1078 	}
   1079 	bankn <<= 3;
   1080 
   1081 	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
   1082 	end =  ((val >> bankn) & 0x03) << 28;
   1083 	val = pcicfgread(tag, MPC106_MEMENDADDR1);
   1084 	end |= ((val >> bankn) & 0xff) << 20;
   1085 	end |= 0xfffff;
   1086 
   1087 	return (end + 1); /* assume the end address matches total amount */
   1088 }
   1089 
   1090 struct fis_dir_entry {
   1091 	char		name[16];
   1092 	uint32_t	startaddr;
   1093 	uint32_t	loadaddr;
   1094 	uint32_t	flashsize;
   1095 	uint32_t	entryaddr;
   1096 	uint32_t	filesize;
   1097 	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
   1098 };
   1099 
   1100 #define FIS_LOWER_LIMIT	0xfff00000
   1101 
   1102 /*
   1103  * Look for a Redboot-style Flash Image System FIS-directory and
   1104  * return a pointer to the start address of the requested file.
   1105  */
   1106 static void *
   1107 redboot_fis_lookup(const char *filename)
   1108 {
   1109 	static const char FISdirname[16] = {
   1110 	    'F', 'I', 'S', ' ',
   1111 	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
   1112 	};
   1113 	struct fis_dir_entry *dir;
   1114 
   1115 	/*
   1116 	 * The FIS directory is usually in the last sector of the flash.
   1117 	 * But we do not know the sector size (erase size), so start
   1118 	 * at 0xffffff00 and scan backwards in steps of the FIS directory
   1119 	 * entry size (0x100).
   1120 	 */
   1121 	for (dir = (struct fis_dir_entry *)0xffffff00;
   1122 	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
   1123 		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
   1124 			break;
   1125 	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
   1126 		printf("No FIS directory found!\n");
   1127 		return NULL;
   1128 	}
   1129 
   1130 	/* Now find filename by scanning the directory from beginning. */
   1131 	dir = (struct fis_dir_entry *)dir->startaddr;
   1132 	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
   1133 		if (strcmp(dir->name, filename) == 0)
   1134 			return (void *)dir->startaddr;	/* found */
   1135 		dir++;
   1136 	}
   1137 	printf("\"%s\" not found in FIS directory!\n", filename);
   1138 	return NULL;
   1139 }
   1140 
   1141 static void
   1142 read_mac_string(uint8_t *mac, char *p)
   1143 {
   1144 	int i;
   1145 
   1146 	for (i = 0; i < 6; i++, p += 3)
   1147 		*mac++ = read_hex(p);
   1148 }
   1149 
   1150 /*
   1151  * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
   1152  * ethernet address and keep it in their Flash memory instead.
   1153  */
   1154 void
   1155 read_mac_from_flash(uint8_t *mac)
   1156 {
   1157 	uint8_t *p;
   1158 
   1159 	switch (brdtype) {
   1160 	case BRD_SYNOLOGY:
   1161 		p = redboot_fis_lookup("vendor");
   1162 		if (p == NULL)
   1163 			break;
   1164 		memcpy(mac, p, 6);
   1165 		return;
   1166 	case BRD_DLINKDSM:
   1167 		read_mac_string(mac, (char *)0xfff0ff80);
   1168 		return;
   1169 	default:
   1170 		printf("Warning: This board has no known method defined "
   1171 		    "to determine its MAC address!\n");
   1172 		break;
   1173 	}
   1174 
   1175 	/* set to 00:00:00:00:00:00 in case of error */
   1176 	memset(mac, 0, 6);
   1177 }
   1178 
   1179 #ifdef DEBUG
   1180 void
   1181 sat_write(char *p, int len)
   1182 {
   1183 	unsigned savedbase;
   1184 
   1185 	savedbase = uart1base;
   1186 	uart1base = uart2base;
   1187 	while (len--)
   1188 		putchar(*p++);
   1189 	uart1base = savedbase;
   1190 }
   1191 
   1192 int
   1193 sat_getch(void)
   1194 {
   1195 	unsigned lsr;
   1196 
   1197 	do {
   1198 		lsr = UART_READ(uart2base, LSR);
   1199 	} while ((lsr & LSR_DRDY) == 0);
   1200 	return UART_READ(uart2base, RBR);
   1201 }
   1202 
   1203 int
   1204 sat_tstch(void)
   1205 {
   1206 
   1207 	return (UART_READ(uart2base, LSR) & LSR_DRDY) != 0;
   1208 }
   1209 #endif /* DEBUG */
   1210