Home | History | Annotate | Line # | Download | only in altboot
      1  1.42   thorpej /* $NetBSD: brdsetup.c,v 1.42 2023/12/20 15:29:07 thorpej Exp $ */
      2   1.1  nisimura 
      3   1.1  nisimura /*-
      4   1.1  nisimura  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5   1.1  nisimura  * All rights reserved.
      6   1.1  nisimura  *
      7   1.1  nisimura  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  nisimura  * by Tohru Nishimura.
      9   1.1  nisimura  *
     10   1.1  nisimura  * Redistribution and use in source and binary forms, with or without
     11   1.1  nisimura  * modification, are permitted provided that the following conditions
     12   1.1  nisimura  * are met:
     13   1.1  nisimura  * 1. Redistributions of source code must retain the above copyright
     14   1.1  nisimura  *    notice, this list of conditions and the following disclaimer.
     15   1.1  nisimura  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  nisimura  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  nisimura  *    documentation and/or other materials provided with the distribution.
     18   1.1  nisimura  *
     19   1.1  nisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  nisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  nisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  nisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  nisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  nisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  nisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  nisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  nisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  nisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  nisimura  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  nisimura  */
     31   1.1  nisimura 
     32   1.1  nisimura #include <sys/param.h>
     33   1.1  nisimura 
     34  1.10       phx #include <powerpc/psl.h>
     35   1.1  nisimura #include <powerpc/oea/spr.h>
     36   1.1  nisimura 
     37   1.1  nisimura #include <lib/libsa/stand.h>
     38   1.1  nisimura #include <lib/libsa/net.h>
     39   1.1  nisimura #include <lib/libkern/libkern.h>
     40   1.1  nisimura 
     41   1.1  nisimura #include <machine/bootinfo.h>
     42   1.1  nisimura 
     43   1.1  nisimura #include "globals.h"
     44   1.1  nisimura 
     45   1.1  nisimura #define BRD_DECL(xxx) \
     46   1.1  nisimura     void xxx ## setup(struct brdprop *); \
     47   1.1  nisimura     void xxx ## brdfix(struct brdprop *); \
     48   1.1  nisimura     void xxx ## pcifix(struct brdprop *); \
     49  1.31       phx     void xxx ## launch(struct brdprop *); \
     50   1.1  nisimura     void xxx ## reset(void)
     51   1.1  nisimura 
     52   1.1  nisimura BRD_DECL(mot);
     53   1.1  nisimura BRD_DECL(enc);
     54   1.1  nisimura BRD_DECL(kuro);
     55   1.1  nisimura BRD_DECL(syno);
     56   1.1  nisimura BRD_DECL(qnap);
     57   1.2  nisimura BRD_DECL(iomega);
     58   1.3  nisimura BRD_DECL(dlink);
     59   1.5  nisimura BRD_DECL(nhnas);
     60  1.28  nisimura BRD_DECL(kurot4);
     61   1.1  nisimura 
     62  1.26       phx static void brdfixup(void);
     63  1.26       phx static void setup(void);
     64  1.26       phx static void send_iomega(int, int, int, int, int, int);
     65  1.26       phx static inline uint32_t mfmsr(void);
     66  1.26       phx static inline void mtmsr(uint32_t);
     67  1.26       phx static inline uint32_t cputype(void);
     68  1.38       phx static inline uint64_t mftb(void);
     69  1.26       phx static void init_uart(unsigned, unsigned, uint8_t);
     70  1.26       phx static void send_sat(char *);
     71  1.26       phx static unsigned mpc107memsize(void);
     72  1.26       phx 
     73  1.26       phx /* UART registers */
     74  1.26       phx #define RBR		0
     75  1.26       phx #define THR		0
     76  1.26       phx #define DLB		0
     77  1.26       phx #define DMB		1
     78  1.26       phx #define IER		1
     79  1.26       phx #define FCR		2
     80  1.26       phx #define LCR		3
     81  1.26       phx #define  LCR_DLAB	0x80
     82  1.26       phx #define  LCR_PEVEN	0x18
     83  1.26       phx #define  LCR_PNONE	0x00
     84  1.26       phx #define  LCR_8BITS	0x03
     85  1.26       phx #define MCR		4
     86  1.26       phx #define  MCR_RTS	0x02
     87  1.26       phx #define  MCR_DTR	0x01
     88  1.26       phx #define LSR		5
     89  1.26       phx #define  LSR_THRE	0x20
     90  1.26       phx #define  LSR_DRDY	0x01
     91  1.26       phx #define DCR		0x11
     92  1.26       phx #define UART_READ(base, r)	in8(base + (r))
     93  1.26       phx #define UART_WRITE(base, r, v)	out8(base + (r), (v))
     94  1.26       phx 
     95  1.26       phx /* MPC106 and MPC824x PCI bridge memory configuration */
     96  1.26       phx #define MPC106_MEMSTARTADDR1	0x80
     97  1.26       phx #define MPC106_EXTMEMSTARTADDR1	0x88
     98  1.26       phx #define MPC106_MEMENDADDR1	0x90
     99  1.26       phx #define MPC106_EXTMEMENDADDR1	0x98
    100  1.26       phx #define MPC106_MEMEN		0xa0
    101  1.26       phx 
    102  1.26       phx /* Iomega StorCenter MC68HC908 microcontroller data packet */
    103  1.26       phx #define IOMEGA_POWER		0
    104  1.26       phx #define IOMEGA_LED		1
    105  1.26       phx #define IOMEGA_FLASH_RATE	2
    106  1.26       phx #define IOMEGA_FAN		3
    107  1.26       phx #define IOMEGA_HIGH_TEMP	4
    108  1.26       phx #define IOMEGA_LOW_TEMP		5
    109  1.26       phx #define IOMEGA_ID		6
    110  1.26       phx #define IOMEGA_CHECKSUM		7
    111  1.26       phx #define IOMEGA_PACKETSIZE	8
    112  1.26       phx 
    113  1.26       phx /* NH230/231 GPIO */
    114  1.36       phx #define NHGPIO_WRITE(x)		*((volatile uint8_t *)0x70000000) = (x)
    115  1.36       phx 
    116  1.36       phx /* Synology CPLD (2007 and newer models) */
    117  1.36       phx #define SYNOCPLD_READ(r)	*((volatile uint8_t *)0xff000000 + (r))
    118  1.36       phx #define SYNOCPLD_WRITE(r,x)	do { \
    119  1.36       phx     *((volatile uint8_t *)0xff000000 + (r)) = (x); \
    120  1.36       phx     delay(10); \
    121  1.36       phx     } while(0)
    122  1.26       phx 
    123   1.1  nisimura static struct brdprop brdlist[] = {
    124   1.1  nisimura     {
    125   1.1  nisimura 	"sandpoint",
    126   1.1  nisimura 	"Sandpoint X3",
    127   1.1  nisimura 	BRD_SANDPOINTX3,
    128   1.1  nisimura 	0,
    129   1.1  nisimura 	"com", 0x3f8, 115200,
    130  1.31       phx 	motsetup, motbrdfix, motpcifix, NULL, NULL },
    131   1.1  nisimura     {
    132   1.1  nisimura 	"encpp1",
    133   1.1  nisimura 	"EnCore PP1",
    134   1.1  nisimura 	BRD_ENCOREPP1,
    135   1.1  nisimura 	0,
    136   1.1  nisimura 	"com", 0x3f8, 115200,
    137  1.31       phx 	encsetup, encbrdfix, encpcifix, NULL, NULL },
    138   1.1  nisimura     {
    139   1.1  nisimura 	"kurobox",
    140   1.1  nisimura 	"KuroBox",
    141   1.1  nisimura 	BRD_KUROBOX,
    142  1.25       phx 	0,
    143   1.1  nisimura 	"eumb", 0x4600, 57600,
    144  1.31       phx 	kurosetup, kurobrdfix, NULL, NULL, kuroreset },
    145   1.1  nisimura     {
    146   1.1  nisimura 	"synology",
    147  1.31       phx 	"Synology CS/DS/RS",
    148   1.1  nisimura 	BRD_SYNOLOGY,
    149  1.25       phx 	0,
    150   1.1  nisimura 	"eumb", 0x4500, 115200,
    151  1.31       phx 	synosetup, synobrdfix, synopcifix, synolaunch, synoreset },
    152   1.1  nisimura     {
    153   1.1  nisimura 	"qnap",
    154  1.12       phx 	"QNAP TS",
    155  1.12       phx 	BRD_QNAPTS,
    156  1.14       phx 	33164691,	/* Linux source says 33000000, but the Synology  */
    157  1.14       phx 			/* clock value delivers a much better precision. */
    158   1.1  nisimura 	"eumb", 0x4500, 115200,
    159  1.31       phx 	NULL, qnapbrdfix, NULL, NULL, qnapreset },
    160   1.1  nisimura     {
    161   1.1  nisimura 	"iomega",
    162  1.12       phx 	"IOMEGA StorCenter G2",
    163   1.1  nisimura 	BRD_STORCENTER,
    164   1.1  nisimura 	0,
    165   1.1  nisimura 	"eumb", 0x4500, 115200,
    166  1.31       phx 	NULL, iomegabrdfix, NULL, NULL, iomegareset },
    167   1.1  nisimura     {
    168   1.3  nisimura 	"dlink",
    169   1.4  nisimura 	"D-Link DSM-G600",
    170   1.4  nisimura 	BRD_DLINKDSM,
    171  1.15       phx 	33000000,
    172   1.3  nisimura 	"eumb", 0x4500, 9600,
    173  1.31       phx 	NULL, dlinkbrdfix, NULL, NULL, NULL },
    174   1.5  nisimura     {
    175   1.5  nisimura 	"nhnas",
    176  1.27       phx 	"Netronix NH-230/231",
    177   1.5  nisimura 	BRD_NH230NAS,
    178  1.25       phx 	33000000,
    179   1.5  nisimura 	"eumb", 0x4500, 9600,
    180  1.31       phx 	NULL, nhnasbrdfix, NULL, NULL, nhnasreset },
    181   1.3  nisimura     {
    182  1.29  nisimura 	"kurot4",
    183  1.28  nisimura 	"KuroBox/T4",
    184  1.28  nisimura 	BRD_KUROBOXT4,
    185  1.30  nisimura 	32768000,
    186  1.28  nisimura 	"eumb", 0x4600, 57600,
    187  1.31       phx 	NULL, kurot4brdfix, NULL, NULL, NULL },
    188  1.28  nisimura     {
    189   1.1  nisimura 	"unknown",
    190   1.1  nisimura 	"Unknown board",
    191   1.1  nisimura 	BRD_UNKNOWN,
    192   1.1  nisimura 	0,
    193   1.1  nisimura 	"eumb", 0x4500, 115200,
    194  1.31       phx 	NULL, NULL, NULL, NULL, NULL }, /* must be the last */
    195   1.1  nisimura };
    196   1.1  nisimura 
    197   1.1  nisimura static struct brdprop *brdprop;
    198   1.1  nisimura static uint32_t ticks_per_sec, ns_per_tick;
    199   1.1  nisimura 
    200   1.1  nisimura const unsigned dcache_line_size = 32;		/* 32B linesize */
    201   1.1  nisimura const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */
    202   1.1  nisimura 
    203   1.1  nisimura unsigned uart1base;	/* console */
    204   1.1  nisimura unsigned uart2base;	/* optional satellite processor */
    205   1.1  nisimura 
    206   1.1  nisimura void brdsetup(void);	/* called by entry.S */
    207   1.1  nisimura 
    208   1.1  nisimura void
    209   1.1  nisimura brdsetup(void)
    210   1.1  nisimura {
    211   1.1  nisimura 	static uint8_t pci_to_memclk[] = {
    212   1.1  nisimura 		30, 30, 10, 10, 20, 10, 10, 10,
    213   1.1  nisimura 		10, 20, 20, 15, 20, 15, 20, 30,
    214   1.1  nisimura 		30, 40, 15, 40, 20, 25, 20, 40,
    215   1.1  nisimura 		25, 20, 10, 20, 15, 15, 20, 00
    216   1.1  nisimura 	};
    217   1.1  nisimura 	static uint8_t mem_to_cpuclk[] = {
    218   1.1  nisimura 		25, 30, 45, 20, 20, 00, 10, 30,
    219   1.1  nisimura 		30, 20, 45, 30, 25, 35, 30, 35,
    220   1.1  nisimura 		20, 25, 20, 30, 35, 40, 40, 20,
    221   1.1  nisimura 		30, 25, 40, 30, 30, 25, 35, 00
    222   1.1  nisimura 	};
    223   1.1  nisimura 	char *consname;
    224   1.1  nisimura 	int consport;
    225   1.1  nisimura 	uint32_t extclk;
    226  1.28  nisimura 	unsigned pchb, pcib, dev11, dev12, dev13, dev15, dev16, val;
    227   1.1  nisimura 	extern struct btinfo_memory bi_mem;
    228   1.1  nisimura 	extern struct btinfo_console bi_cons;
    229   1.1  nisimura 	extern struct btinfo_clock bi_clk;
    230   1.1  nisimura 	extern struct btinfo_prodfamily bi_fam;
    231   1.1  nisimura 
    232   1.1  nisimura 	/*
    233   1.1  nisimura 	 * CHRP specification "Map-B" BAT012 layout
    234   1.1  nisimura 	 *   BAT0 0000-0000 (256MB) SDRAM
    235   1.1  nisimura 	 *   BAT1 8000-0000 (256MB) PCI mem space
    236   1.1  nisimura 	 *   BAT2 fc00-0000 (64MB)  EUMB, PCI I/O space, misc devs, flash
    237   1.1  nisimura 	 *
    238   1.1  nisimura 	 * EUMBBAR is at fc00-0000.
    239   1.1  nisimura 	 */
    240   1.1  nisimura 	pchb = pcimaketag(0, 0, 0);
    241   1.1  nisimura 	pcicfgwrite(pchb, 0x78, 0xfc000000);
    242   1.1  nisimura 
    243   1.1  nisimura 	brdtype = BRD_UNKNOWN;
    244   1.1  nisimura 	extclk = EXT_CLK_FREQ;	/* usually 33MHz */
    245   1.1  nisimura 	busclock = 0;
    246   1.1  nisimura 
    247   1.5  nisimura 	dev11 = pcimaketag(0, 11, 0);
    248  1.28  nisimura 	dev12 = pcimaketag(0, 12, 0);
    249   1.5  nisimura 	dev13 = pcimaketag(0, 13, 0);
    250   1.5  nisimura 	dev15 = pcimaketag(0, 15, 0);
    251   1.5  nisimura 	dev16 = pcimaketag(0, 16, 0);
    252   1.5  nisimura 
    253   1.1  nisimura 	if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
    254   1.5  nisimura 		/* WinBond 553 southbridge at dev 11 */
    255   1.1  nisimura 		brdtype = BRD_SANDPOINTX3;
    256   1.1  nisimura 	}
    257   1.1  nisimura 	else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
    258   1.5  nisimura 		/* VIA 686B southbridge at dev 22 */
    259   1.1  nisimura 		brdtype = BRD_ENCOREPP1;
    260   1.1  nisimura 	}
    261   1.8       phx 	else if (PCI_CLASS(pcicfgread(dev11, PCI_CLASS_REG)) == PCI_CLASS_ETH) {
    262   1.5  nisimura 		/* ADMtek AN985 (tlp) or RealTek 8169S (re) at dev 11 */
    263  1.37  nisimura 		if (PCI_VENDOR(pcicfgread(dev11, PCI_ID_REG)) == 0x1317)
    264  1.28  nisimura 			brdtype = BRD_KUROBOX;
    265  1.37  nisimura 		else if (PCI_VENDOR(pcicfgread(dev11, PCI_ID_REG)) == 0x10ec) {
    266  1.37  nisimura 			if (PCI_PRODUCT(pcicfgread(dev12,PCI_ID_REG)) != 0x3512)
    267  1.37  nisimura 				brdtype = BRD_KUROBOX;
    268  1.37  nisimura 			else
    269  1.37  nisimura 				brdtype = BRD_KUROBOXT4;
    270  1.37  nisimura 		}
    271   1.1  nisimura 	}
    272  1.39       phx 	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x1148
    273  1.39       phx 	    || PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x11ab) {
    274   1.5  nisimura 		/* SKnet/Marvell (sk) at dev 15 */
    275   1.1  nisimura 		brdtype = BRD_SYNOLOGY;
    276   1.1  nisimura 	}
    277  1.16       phx 	else if (PCI_VENDOR(pcicfgread(dev13, PCI_ID_REG)) == 0x1106) {
    278  1.16       phx 		/* VIA 6410 (viaide) at dev 13 */
    279  1.16       phx 		brdtype = BRD_STORCENTER;
    280  1.16       phx 	}
    281   1.5  nisimura 	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1191) {
    282   1.5  nisimura 		/* ACARD ATP865 (acardide) at dev 16 */
    283   1.4  nisimura 		brdtype = BRD_DLINKDSM;
    284   1.3  nisimura 	}
    285   1.5  nisimura 	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1283
    286  1.12       phx 	    || PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1095) {
    287   1.5  nisimura 		/* ITE (iteide) or SiI (satalink) at dev 16 */
    288   1.5  nisimura 		brdtype = BRD_NH230NAS;
    289   1.5  nisimura 	}
    290  1.17       phx 	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x8086
    291  1.17       phx 	    || PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x10ec) {
    292  1.17       phx 		/* Intel (wm) or RealTek (re) at dev 15 */
    293  1.17       phx 		brdtype = BRD_QNAPTS;
    294  1.17       phx 	}
    295   1.1  nisimura 
    296   1.1  nisimura 	brdprop = brd_lookup(brdtype);
    297   1.1  nisimura 
    298   1.1  nisimura 	/* brd dependent adjustments */
    299   1.1  nisimura 	setup();
    300   1.1  nisimura 
    301   1.1  nisimura 	/* determine clock frequencies */
    302   1.1  nisimura 	if (brdprop->extclk != 0)
    303   1.1  nisimura 		extclk = brdprop->extclk;
    304   1.1  nisimura 	if (busclock == 0) {
    305   1.1  nisimura 		if (cputype() == MPC8245) {
    306   1.1  nisimura 			/* PLL_CFG from PCI host bridge register 0xe2 */
    307   1.1  nisimura 			val = pcicfgread(pchb, 0xe0);
    308   1.1  nisimura 			busclock = (extclk *
    309   1.1  nisimura 			    pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
    310   1.1  nisimura 			/* PLLRATIO from HID1 */
    311  1.10       phx 			asm volatile ("mfspr %0,1009" : "=r"(val));
    312   1.1  nisimura 			cpuclock = ((uint64_t)busclock *
    313   1.1  nisimura 			    mem_to_cpuclk[val >> 27] + 10) / 10;
    314   1.1  nisimura 		} else
    315   1.1  nisimura 			busclock = 100000000;	/* 100MHz bus clock default */
    316   1.1  nisimura 	}
    317   1.1  nisimura 	ticks_per_sec = busclock >> 2;
    318   1.1  nisimura 	ns_per_tick = 1000000000 / ticks_per_sec;
    319   1.1  nisimura 
    320   1.1  nisimura 	/* now prepare serial console */
    321   1.1  nisimura 	consname = brdprop->consname;
    322   1.1  nisimura 	consport = brdprop->consport;
    323   1.1  nisimura 	if (strcmp(consname, "eumb") == 0) {
    324   1.1  nisimura 		uart1base = 0xfc000000 + consport;	/* 0x4500, 0x4600 */
    325   1.1  nisimura 		UART_WRITE(uart1base, DCR, 0x01);	/* enable DUART mode */
    326   1.1  nisimura 		uart2base = uart1base ^ 0x0300;
    327   1.1  nisimura 	} else
    328   1.1  nisimura 		uart1base = 0xfe000000 + consport;	/* 0x3f8, 0x2f8 */
    329   1.1  nisimura 
    330   1.1  nisimura 	/* more brd adjustments */
    331   1.1  nisimura 	brdfixup();
    332   1.1  nisimura 
    333   1.1  nisimura 	bi_mem.memsize = mpc107memsize();
    334  1.34     joerg 	snprintf(bi_cons.devname, sizeof(bi_cons.devname), "%s", consname);
    335   1.1  nisimura 	bi_cons.addr = consport;
    336   1.1  nisimura 	bi_cons.speed = brdprop->consspeed;
    337   1.1  nisimura 	bi_clk.ticks_per_sec = ticks_per_sec;
    338  1.34     joerg 	snprintf(bi_fam.name, sizeof(bi_fam.name), "%s", brdprop->family);
    339   1.1  nisimura }
    340   1.1  nisimura 
    341   1.1  nisimura struct brdprop *
    342   1.1  nisimura brd_lookup(int brd)
    343   1.1  nisimura {
    344   1.1  nisimura 	u_int i;
    345   1.1  nisimura 
    346   1.1  nisimura 	for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
    347   1.1  nisimura 		if (brdlist[i].brdtype == brd)
    348   1.1  nisimura 			return &brdlist[i];
    349   1.1  nisimura 	}
    350   1.1  nisimura 	return &brdlist[i - 1];
    351   1.1  nisimura }
    352   1.1  nisimura 
    353   1.1  nisimura static void
    354   1.1  nisimura setup()
    355   1.1  nisimura {
    356   1.1  nisimura 
    357   1.1  nisimura 	if (brdprop->setup == NULL)
    358   1.1  nisimura 		return;
    359   1.1  nisimura 	(*brdprop->setup)(brdprop);
    360   1.1  nisimura }
    361   1.1  nisimura 
    362   1.1  nisimura static void
    363   1.1  nisimura brdfixup()
    364   1.1  nisimura {
    365   1.1  nisimura 
    366   1.1  nisimura 	if (brdprop->brdfix == NULL)
    367   1.1  nisimura 		return;
    368   1.1  nisimura 	(*brdprop->brdfix)(brdprop);
    369   1.1  nisimura }
    370   1.1  nisimura 
    371   1.1  nisimura void
    372   1.1  nisimura pcifixup()
    373   1.1  nisimura {
    374   1.1  nisimura 
    375   1.1  nisimura 	if (brdprop->pcifix == NULL)
    376   1.1  nisimura 		return;
    377   1.1  nisimura 	(*brdprop->pcifix)(brdprop);
    378   1.1  nisimura }
    379   1.1  nisimura 
    380   1.1  nisimura void
    381  1.31       phx launchfixup()
    382  1.31       phx {
    383  1.31       phx 
    384  1.31       phx 	if (brdprop->launch == NULL)
    385  1.31       phx 		return;
    386  1.31       phx 	(*brdprop->launch)(brdprop);
    387  1.31       phx }
    388  1.31       phx 
    389  1.31       phx void
    390   1.1  nisimura encsetup(struct brdprop *brd)
    391   1.1  nisimura {
    392   1.1  nisimura 
    393   1.1  nisimura #ifdef COSNAME
    394   1.1  nisimura 	brd->consname = CONSNAME;
    395   1.1  nisimura #endif
    396   1.1  nisimura #ifdef CONSPORT
    397   1.1  nisimura 	brd->consport = CONSPORT;
    398   1.1  nisimura #endif
    399   1.1  nisimura #ifdef CONSSPEED
    400   1.1  nisimura 	brd->consspeed = CONSSPEED;
    401   1.1  nisimura #endif
    402   1.1  nisimura }
    403   1.1  nisimura 
    404   1.1  nisimura void
    405   1.1  nisimura encbrdfix(struct brdprop *brd)
    406   1.1  nisimura {
    407   1.5  nisimura 	unsigned ac97, ide, pcib, pmgt, usb12, usb34, val;
    408   1.1  nisimura 
    409   1.1  nisimura /*
    410   1.1  nisimura  * VIA82C686B Southbridge
    411   1.1  nisimura  *	0.22.0	1106.0686	PCI-ISA bridge
    412   1.1  nisimura  *	0.22.1	1106.0571	IDE (viaide)
    413   1.1  nisimura  *	0.22.2	1106.3038	USB 0/1 (uhci)
    414   1.1  nisimura  *	0.22.3	1106.3038	USB 2/3 (uhci)
    415   1.1  nisimura  *	0.22.4	1106.3057	power management
    416   1.1  nisimura  *	0.22.5	1106.3058	AC97 (auvia)
    417   1.1  nisimura  */
    418   1.1  nisimura 	pcib  = pcimaketag(0, 22, 0);
    419   1.1  nisimura 	ide   = pcimaketag(0, 22, 1);
    420   1.1  nisimura 	usb12 = pcimaketag(0, 22, 2);
    421   1.5  nisimura 	usb34 = pcimaketag(0, 22, 3);
    422   1.1  nisimura 	pmgt  = pcimaketag(0, 22, 4);
    423   1.1  nisimura 	ac97  = pcimaketag(0, 22, 5);
    424   1.1  nisimura 
    425   1.1  nisimura #define	CFG(i,v) do { \
    426   1.1  nisimura    *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
    427   1.1  nisimura    *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
    428   1.1  nisimura    } while (0)
    429   1.1  nisimura 	val = pcicfgread(pcib, 0x84);
    430   1.1  nisimura 	val |= (02 << 8);
    431   1.1  nisimura 	pcicfgwrite(pcib, 0x84, val);
    432   1.1  nisimura 	CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
    433   1.1  nisimura 	val = pcicfgread(pcib, 0x84);
    434   1.1  nisimura 	val &= ~(02 << 8);
    435   1.1  nisimura 	pcicfgwrite(pcib, 0x84, val);
    436   1.1  nisimura 
    437   1.1  nisimura 	/* route pin C to i8259 IRQ 5, pin D to 11 */
    438   1.1  nisimura 	val = pcicfgread(pcib, 0x54);
    439   1.1  nisimura 	val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
    440   1.1  nisimura 	pcicfgwrite(pcib, 0x54, val);
    441   1.1  nisimura 
    442   1.1  nisimura 	/* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
    443   1.1  nisimura 	val = pcicfgread(pcib, 0x44);
    444   1.1  nisimura 	val = val | 0x20000000;
    445   1.1  nisimura 	pcicfgwrite(pcib, 0x44, val);
    446   1.1  nisimura 
    447   1.1  nisimura 	/* select level trigger for IRQ 5/11 at ELCR1/2 */
    448   1.1  nisimura 	*(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
    449   1.1  nisimura 	*(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */
    450   1.1  nisimura 
    451   1.1  nisimura 	/* USB and AC97 are hardwired with pin D and C */
    452   1.1  nisimura 	val = pcicfgread(usb12, 0x3c) &~ 0xff;
    453   1.1  nisimura 	val |= 11;
    454   1.1  nisimura 	pcicfgwrite(usb12, 0x3c, val);
    455   1.5  nisimura 	val = pcicfgread(usb34, 0x3c) &~ 0xff;
    456   1.1  nisimura 	val |= 11;
    457   1.5  nisimura 	pcicfgwrite(usb34, 0x3c, val);
    458   1.1  nisimura 	val = pcicfgread(ac97, 0x3c) &~ 0xff;
    459   1.1  nisimura 	val |= 5;
    460   1.1  nisimura 	pcicfgwrite(ac97, 0x3c, val);
    461  1.33  nisimura 
    462  1.33  nisimura 	(void) pcicfgread(ide, 0x08);
    463  1.33  nisimura 	(void) pcicfgread(pmgt, 0x08);
    464   1.1  nisimura }
    465   1.1  nisimura 
    466   1.1  nisimura void
    467   1.5  nisimura encpcifix(struct brdprop *brd)
    468   1.5  nisimura {
    469   1.5  nisimura 	unsigned ide, irq, net, pcib, steer, val;
    470   1.5  nisimura 
    471   1.5  nisimura #define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
    472   1.5  nisimura 	pcib = pcimaketag(0, 22, 0);
    473   1.5  nisimura 	ide  = pcimaketag(0, 22, 1);
    474   1.5  nisimura 	net  = pcimaketag(0, 25, 0);
    475   1.5  nisimura 
    476   1.5  nisimura 	/*
    477   1.5  nisimura 	 * //// VIA PIRQ ////
    478   1.5  nisimura 	 * 0x57/56/55/54 - Dx CB Ax xS
    479   1.5  nisimura 	 */
    480   1.5  nisimura 	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
    481   1.5  nisimura 	steer = val & 0xf;
    482   1.5  nisimura 	irq = (val >> 12) & 0xf;	/* 15:12 */
    483   1.5  nisimura 	if (irq) {
    484   1.5  nisimura 		printf("pin A -> irq %d, %s\n",
    485   1.5  nisimura 			irq, STEER(steer, 0x1));
    486   1.5  nisimura 	}
    487   1.5  nisimura 	irq = (val >> 16) & 0xf;	/* 19:16 */
    488   1.5  nisimura 	if (irq) {
    489   1.5  nisimura 		printf("pin B -> irq %d, %s\n",
    490   1.5  nisimura 			irq, STEER(steer, 0x2));
    491   1.5  nisimura 	}
    492   1.5  nisimura 	irq = (val >> 20) & 0xf;	/* 23:20 */
    493   1.5  nisimura 	if (irq) {
    494   1.5  nisimura 		printf("pin C -> irq %d, %s\n",
    495   1.5  nisimura 			irq, STEER(steer, 0x4));
    496   1.5  nisimura 	}
    497   1.5  nisimura 	irq = (val >> 28);		/* 31:28 */
    498   1.5  nisimura 	if (irq) {
    499   1.5  nisimura 		printf("pin D -> irq %d, %s\n",
    500   1.5  nisimura 			irq, STEER(steer, 0x8));
    501   1.5  nisimura 	}
    502   1.5  nisimura #if 0
    503   1.5  nisimura 	/*
    504   1.5  nisimura 	 * //// IDE fixup ////
    505   1.5  nisimura 	 * - "native mode" (ide 0x09)
    506   1.5  nisimura 	 */
    507  1.20       phx 
    508   1.5  nisimura 	/* ide: 0x09 - programming interface; 1000'SsPp */
    509   1.5  nisimura 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    510   1.5  nisimura 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    511   1.5  nisimura 
    512   1.5  nisimura 	/* ide: 0x10-20 - leave them PCI memory space assigned */
    513   1.5  nisimura #else
    514   1.5  nisimura 	/*
    515   1.5  nisimura 	 * //// IDE fixup ////
    516  1.40    andvar 	 * - "compatibility mode" (ide 0x09)
    517   1.5  nisimura 	 * - remove PCI pin assignment (ide 0x3d)
    518   1.5  nisimura 	 */
    519  1.20       phx 
    520   1.5  nisimura 	/* ide: 0x09 - programming interface; 1000'SsPp */
    521   1.5  nisimura 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    522   1.5  nisimura 	val |= (0x8a << 8);
    523   1.5  nisimura 	pcicfgwrite(ide, 0x08, val);
    524   1.5  nisimura 
    525   1.5  nisimura 	/* ide: 0x10-20 */
    526   1.5  nisimura 	/*
    527  1.20       phx 	 * experiment shows writing ide: 0x09 changes these
    528  1.20       phx 	 * register behaviour. The pcicfgwrite() above writes
    529  1.20       phx 	 * 0x8a at ide: 0x09 to make sure legacy IDE.  Then
    530  1.20       phx 	 * reading BAR0-3 is to return value 0s even though
    531  1.20       phx 	 * pcisetup() has written range assignments.  Value
    532  1.20       phx 	 * overwrite makes no effect. Having 0x8f for native
    533  1.20       phx 	 * PCIIDE doesn't change register values and brings no
    534  1.20       phx 	 * weirdness.
    535   1.5  nisimura 	 */
    536   1.5  nisimura 
    537  1.20       phx 	/* ide: 0x3d/3c - turn off PCI pin */
    538   1.5  nisimura 	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
    539   1.5  nisimura 	pcicfgwrite(ide, 0x3c, val);
    540   1.5  nisimura #endif
    541   1.5  nisimura 	/*
    542   1.5  nisimura 	 * //// USBx2, audio, and modem fixup ////
    543   1.5  nisimura 	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
    544   1.5  nisimura 	 * - disable AC97 audio and MC97 modem (pcib 0x85)
    545   1.5  nisimura 	 */
    546   1.5  nisimura 
    547   1.5  nisimura 	/* pcib: 0x48 - disable USB #0 at function 2 */
    548   1.5  nisimura 	val = pcicfgread(pcib, 0x48);
    549   1.5  nisimura 	pcicfgwrite(pcib, 0x48, val | 04);
    550   1.5  nisimura 
    551   1.5  nisimura 	/* pcib: 0x85 - disable USB #1 at function 3 */
    552   1.5  nisimura 	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
    553   1.5  nisimura 	val = pcicfgread(pcib, 0x84);
    554   1.5  nisimura 	pcicfgwrite(pcib, 0x84, val | 0x1c00);
    555   1.5  nisimura 
    556   1.5  nisimura 	/*
    557   1.5  nisimura 	 * //// fxp fixup ////
    558   1.5  nisimura 	 * - use PCI pin A line 25 (fxp 0x3d/3c)
    559   1.5  nisimura 	 */
    560   1.5  nisimura 	/* 0x3d/3c - PCI pin/line */
    561   1.5  nisimura 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    562   1.5  nisimura 	val |= (('A' - '@') << 8) | 25;
    563   1.5  nisimura 	pcicfgwrite(net, 0x3c, val);
    564   1.5  nisimura }
    565   1.5  nisimura 
    566   1.5  nisimura void
    567   1.1  nisimura motsetup(struct brdprop *brd)
    568   1.1  nisimura {
    569   1.1  nisimura 
    570   1.1  nisimura #ifdef COSNAME
    571   1.1  nisimura 	brd->consname = CONSNAME;
    572   1.1  nisimura #endif
    573   1.1  nisimura #ifdef CONSPORT
    574   1.1  nisimura 	brd->consport = CONSPORT;
    575   1.1  nisimura #endif
    576   1.1  nisimura #ifdef CONSSPEED
    577   1.1  nisimura 	brd->consspeed = CONSSPEED;
    578   1.1  nisimura #endif
    579   1.1  nisimura }
    580   1.1  nisimura 
    581   1.1  nisimura void
    582   1.1  nisimura motbrdfix(struct brdprop *brd)
    583   1.1  nisimura {
    584   1.1  nisimura 
    585   1.1  nisimura /*
    586   1.1  nisimura  * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
    587   1.1  nisimura  *
    588   1.1  nisimura  *	0.11.0	10ad.0565	PCI-ISA bridge
    589   1.1  nisimura  *	0.11.1	10ad.0105	IDE (slide)
    590   1.1  nisimura  */
    591   1.1  nisimura }
    592   1.1  nisimura 
    593   1.1  nisimura void
    594   1.1  nisimura motpcifix(struct brdprop *brd)
    595   1.1  nisimura {
    596   1.4  nisimura 	unsigned ide, net, pcib, steer, val;
    597   1.1  nisimura 	int line;
    598   1.1  nisimura 
    599   1.1  nisimura 	pcib = pcimaketag(0, 11, 0);
    600   1.1  nisimura 	ide  = pcimaketag(0, 11, 1);
    601   1.4  nisimura 	net  = pcimaketag(0, 15, 0);
    602   1.1  nisimura 
    603   1.1  nisimura 	/*
    604   1.1  nisimura 	 * //// WinBond PIRQ ////
    605   1.1  nisimura 	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
    606   1.1  nisimura 	 * 0x60 - PIRQ interrupt routing steer
    607   1.1  nisimura 	 */
    608   1.1  nisimura 	if (pcicfgread(pcib, 0x40) & 0x20) {
    609   1.1  nisimura 		steer = pcicfgread(pcib, 0x60);
    610   1.1  nisimura 		if ((steer & 0x80808080) == 0x80808080)
    611   1.1  nisimura 			printf("PIRQ[0-3] disabled\n");
    612   1.1  nisimura 		else {
    613   1.1  nisimura 			unsigned i, v = steer;
    614   1.1  nisimura 			for (i = 0; i < 4; i++, v >>= 8) {
    615   1.1  nisimura 				if ((v & 0x80) != 0 || (v & 0xf) == 0)
    616   1.1  nisimura 					continue;
    617   1.1  nisimura 				printf("PIRQ[%d]=%d\n", i, v & 0xf);
    618   1.1  nisimura 				}
    619   1.1  nisimura 			}
    620   1.1  nisimura 		}
    621   1.1  nisimura #if 1
    622   1.1  nisimura 	/*
    623   1.1  nisimura 	 * //// IDE fixup -- case A ////
    624   1.1  nisimura 	 * - "native PCI mode" (ide 0x09)
    625   1.1  nisimura 	 * - don't use ISA IRQ14/15 (pcib 0x43)
    626   1.1  nisimura 	 * - native IDE for both channels (ide 0x40)
    627   1.1  nisimura 	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
    628   1.1  nisimura 	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
    629   1.1  nisimura 	 */
    630   1.1  nisimura 	/* ide: 0x09 - programming interface; 1000'SsPp */
    631   1.1  nisimura 	val = pcicfgread(ide, 0x08);
    632   1.1  nisimura 	val &= 0xffff00ff;
    633   1.1  nisimura 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    634   1.1  nisimura 
    635   1.1  nisimura 	/* pcib: 0x43 - IDE interrupt routing */
    636   1.1  nisimura 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    637   1.1  nisimura 	pcicfgwrite(pcib, 0x40, val);
    638   1.1  nisimura 
    639   1.1  nisimura 	/* pcib: 0x45/44 - PCI interrupt routing */
    640   1.1  nisimura 	val = pcicfgread(pcib, 0x44) & 0xffff0000;
    641   1.1  nisimura 	pcicfgwrite(pcib, 0x44, val);
    642   1.1  nisimura 
    643   1.1  nisimura 	/* ide: 0x41/40 - IDE channel */
    644   1.1  nisimura 	val = pcicfgread(ide, 0x40) & 0xffff0000;
    645   1.1  nisimura 	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
    646   1.1  nisimura 	pcicfgwrite(ide, 0x40, val);
    647   1.1  nisimura 
    648   1.1  nisimura 	/* ide: 0x3d/3c - use PCI pin C/line 11 */
    649   1.1  nisimura 	val = pcicfgread(ide, 0x3c) & 0xffffff00;
    650   1.1  nisimura 	val |= 11; /* pin designation is hardwired to pin A */
    651   1.1  nisimura 	pcicfgwrite(ide, 0x3c, val);
    652   1.1  nisimura #else
    653   1.1  nisimura 	/*
    654   1.1  nisimura 	 * //// IDE fixup -- case B ////
    655  1.40    andvar 	 * - "compatibility mode" (ide 0x09)
    656   1.1  nisimura 	 * - IDE primary/secondary interrupt routing (pcib 0x43)
    657   1.1  nisimura 	 * - PCI interrupt routing (pcib 0x45/44)
    658   1.1  nisimura 	 * - no PCI pin/line assignment (ide 0x3d/3c)
    659   1.1  nisimura 	 */
    660   1.1  nisimura 	/* ide: 0x09 - programming interface; 1000'SsPp */
    661   1.1  nisimura 	val = pcicfgread(ide, 0x08);
    662   1.1  nisimura 	val &= 0xffff00ff;
    663   1.1  nisimura 	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
    664   1.1  nisimura 
    665   1.1  nisimura 	/* pcib: 0x43 - IDE interrupt routing */
    666   1.1  nisimura 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    667   1.1  nisimura 	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
    668   1.1  nisimura 
    669   1.1  nisimura 	/* ide: 0x45/44 - PCI interrupt routing */
    670   1.1  nisimura 	val = pcicfgread(ide, 0x44) & 0xffff0000;
    671   1.1  nisimura 	pcicfgwrite(ide, 0x44, val);
    672   1.1  nisimura 
    673   1.1  nisimura 	/* ide: 0x3d/3c - turn off PCI pin/line */
    674   1.1  nisimura 	val = pcicfgread(ide, 0x3c) & 0xffff0000;
    675   1.1  nisimura 	pcicfgwrite(ide, 0x3c, val);
    676   1.1  nisimura #endif
    677   1.1  nisimura 
    678   1.1  nisimura 	/*
    679   1.1  nisimura 	 * //// fxp fixup ////
    680   1.1  nisimura 	 * - use PCI pin A line 15 (fxp 0x3d/3c)
    681   1.1  nisimura 	 */
    682   1.4  nisimura 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    683   1.4  nisimura 	pcidecomposetag(net, NULL, &line, NULL);
    684   1.1  nisimura 	val |= (('A' - '@') << 8) | line;
    685   1.4  nisimura 	pcicfgwrite(net, 0x3c, val);
    686   1.1  nisimura }
    687   1.1  nisimura 
    688   1.1  nisimura void
    689   1.1  nisimura kurosetup(struct brdprop *brd)
    690   1.1  nisimura {
    691   1.1  nisimura 
    692   1.1  nisimura 	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
    693   1.1  nisimura 		brd->extclk = 32768000; /* decr 2457600Hz */
    694   1.1  nisimura 	else
    695   1.1  nisimura 		brd->extclk = 32521333; /* decr 2439100Hz */
    696   1.1  nisimura }
    697   1.1  nisimura 
    698   1.1  nisimura void
    699   1.1  nisimura kurobrdfix(struct brdprop *brd)
    700   1.1  nisimura {
    701   1.1  nisimura 
    702   1.1  nisimura 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
    703   1.1  nisimura 	/* Stop Watchdog */
    704   1.1  nisimura 	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
    705   1.1  nisimura }
    706   1.1  nisimura 
    707   1.1  nisimura void
    708  1.26       phx kuroreset()
    709  1.26       phx {
    710  1.26       phx 
    711  1.26       phx 	send_sat("CCGG");
    712  1.26       phx 	/*NOTREACHED*/
    713  1.26       phx }
    714  1.26       phx 
    715  1.26       phx void
    716  1.25       phx synosetup(struct brdprop *brd)
    717  1.25       phx {
    718  1.42   thorpej 	/*
    719  1.42   thorpej 	 * My DS107e works much better with the
    720  1.42   thorpej 	 * default EXT_CLK_FREQ (33333333).
    721  1.42   thorpej 	 *   --thorpej
    722  1.42   thorpej 	 */
    723  1.42   thorpej #if 0
    724  1.25       phx 	if (1) /* 200 and 266MHz models */
    725  1.25       phx 		brd->extclk = 33164691; /* from Synology/Linux source */
    726  1.25       phx 	else   /* 400MHz models XXX how to check? */
    727  1.25       phx 		brd->extclk = 33165343;
    728  1.42   thorpej #endif
    729  1.25       phx }
    730  1.25       phx 
    731  1.25       phx void
    732   1.1  nisimura synobrdfix(struct brdprop *brd)
    733   1.1  nisimura {
    734   1.1  nisimura 
    735   1.1  nisimura 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    736   1.1  nisimura 	/* beep, power LED on, status LED off */
    737   1.1  nisimura 	send_sat("247");
    738   1.1  nisimura }
    739   1.1  nisimura 
    740  1.36       phx #define SYNO_FAN_TIMEOUT	500	/* 500ms to turn the fan off */
    741  1.36       phx #define SYNO_DISK_DELAY		30	/* 30 seconds to power up 2nd disk */
    742  1.36       phx 
    743   1.1  nisimura void
    744  1.31       phx synopcifix(struct brdprop *brd)
    745  1.31       phx {
    746  1.36       phx 	static const char models207[4][7] = {
    747  1.36       phx 		"???", "DS107e", "DS107", "DS207"
    748  1.36       phx 	};
    749  1.36       phx 	static const char models209[2][7] = {
    750  1.36       phx 		"DS109j", "DS209j"
    751  1.36       phx 	};
    752  1.36       phx 	static const char models406[3][7] = {
    753  1.36       phx 		"CS406e", "CS406", "RS406"
    754  1.31       phx 	};
    755  1.36       phx 	static const char models407[4][7] = {
    756  1.36       phx 		"???", "CS407e", "CS407", "RS407"
    757  1.36       phx 	};
    758  1.36       phx 	extern struct btinfo_model bi_model;
    759  1.36       phx 	const char *model_name;
    760  1.36       phx 	unsigned cpld, version, flags;
    761  1.36       phx 	uint8_t v, status;
    762  1.36       phx 	int i;
    763  1.36       phx 
    764  1.36       phx 	/*
    765  1.36       phx 	 * Determine if a CPLD is present and whether is has 4-bit
    766  1.36       phx 	 * (models 107, 207, 209)  or 8-bit (models 406, 407) registers.
    767  1.36       phx 	 * The register set repeats every 16 bytes.
    768  1.36       phx 	 */
    769  1.36       phx 	cpld = 0;
    770  1.36       phx 	flags = 0;
    771  1.36       phx 	version = 0;
    772  1.36       phx 	model_name = NULL;
    773  1.36       phx 
    774  1.36       phx 	SYNOCPLD_WRITE(0, 0x00);	/* LEDs blinking yellow (default) */
    775  1.36       phx 	v = SYNOCPLD_READ(0);
    776  1.36       phx 
    777  1.36       phx 	if (v != 0x00) {
    778  1.36       phx 		v &= 0xf0;
    779  1.36       phx 		if (v != 0x00 || (SYNOCPLD_READ(16 + 0) & 0xf0) != v)
    780  1.36       phx 			goto cpld_done;
    781  1.36       phx 
    782  1.36       phx   cpld4bits:
    783  1.36       phx 		/* 4-bit registers assumed, make LEDs solid yellow */
    784  1.36       phx 		SYNOCPLD_WRITE(0, 0x50);
    785  1.36       phx 		v = SYNOCPLD_READ(0) & 0xf0;
    786  1.36       phx 		if (v != 0x50 || (SYNOCPLD_READ(32 + 0) & 0xf0) != v)
    787  1.36       phx 			goto cpld_done;
    788  1.36       phx 
    789  1.36       phx 		v = SYNOCPLD_READ(2) & 0xf0;
    790  1.36       phx 		if ((SYNOCPLD_READ(48 + 2) & 0xf0) != v)
    791  1.36       phx 			goto cpld_done;
    792  1.36       phx 		version = (v >> 4) & 7;
    793  1.36       phx 
    794  1.36       phx 		/*
    795  1.36       phx 		 * Try to determine whether it is a 207-style or 209-style
    796  1.36       phx 		 * CPLD register set, by turning the fan off and check if
    797  1.36       phx 		 * either bit 5 or bit 4 changes from 0 to 1 to indicate
    798  1.36       phx 		 * the fan is stopped.
    799  1.36       phx 		 */
    800  1.36       phx 		status = SYNOCPLD_READ(3) & 0xf0;
    801  1.36       phx 		SYNOCPLD_WRITE(3, 0x00);	/* fan off */
    802  1.36       phx 
    803  1.36       phx 		for (i = 0; i < SYNO_FAN_TIMEOUT * 100; i++) {
    804  1.36       phx 			delay(10);
    805  1.36       phx 			v = SYNOCPLD_READ(3) & 0xf0;
    806  1.36       phx 			if ((status & 0x20) == 0 && (v & 0x20) != 0) {
    807  1.36       phx 				/* set x07 model */
    808  1.36       phx 				v = SYNOCPLD_READ(1) >> 6;
    809  1.36       phx 				model_name = models207[v];
    810  1.36       phx 				cpld = BI_MODEL_CPLD207;
    811  1.36       phx 				/* XXXX DS107v2/v3 have no thermal sensor */
    812  1.36       phx 				flags |= BI_MODEL_THERMAL;
    813  1.36       phx 				break;
    814  1.36       phx 			}
    815  1.36       phx 			if ((status & 0x10) == 0 && (v & 0x10) != 0) {
    816  1.36       phx 				/* set x09 model */
    817  1.36       phx 				v = SYNOCPLD_READ(1) >> 7;
    818  1.36       phx 				model_name = models209[v];
    819  1.36       phx 				cpld = BI_MODEL_CPLD209;
    820  1.36       phx 				if (v == 1)	/* DS209j */
    821  1.36       phx 					flags |= BI_MODEL_THERMAL;
    822  1.36       phx 				break;
    823  1.36       phx 			}
    824  1.36       phx 			/* XXX What about DS108j? Does it have a CPLD? */
    825  1.36       phx 		}
    826  1.36       phx 
    827  1.36       phx 		/* turn the fan on again */
    828  1.36       phx 		SYNOCPLD_WRITE(3, status);
    829  1.36       phx 
    830  1.36       phx 		if (i >= SYNO_FAN_TIMEOUT * 100)
    831  1.36       phx 			goto cpld_done;		/* timeout: no valid CPLD */
    832  1.36       phx 	} else {
    833  1.36       phx 		if (SYNOCPLD_READ(16 + 0) != v)
    834  1.36       phx 			goto cpld4bits;
    835  1.36       phx 
    836  1.36       phx 		/* 8-bit registers assumed, make LEDs solid yellow */
    837  1.36       phx 		SYNOCPLD_WRITE(0, 0x55);
    838  1.36       phx 		v = SYNOCPLD_READ(0);
    839  1.36       phx 		if (v != 0x55)
    840  1.36       phx 			goto cpld4bits;		/* try 4 bits instead */
    841  1.36       phx 		if (SYNOCPLD_READ(32 + 0) != v)
    842  1.36       phx 			goto cpld_done;
    843  1.36       phx 
    844  1.36       phx 		v = SYNOCPLD_READ(2);
    845  1.36       phx 		if (SYNOCPLD_READ(48 + 2) != v)
    846  1.36       phx 			goto cpld_done;
    847  1.36       phx 		version = v & 3;
    848  1.36       phx 
    849  1.36       phx 		if ((v & 0x0c) != 0x0c) {
    850  1.36       phx 			/* set 406 model */
    851  1.36       phx 			model_name = models406[(v >> 2) & 3];
    852  1.36       phx 			cpld = BI_MODEL_CPLD406;
    853  1.36       phx 		} else {
    854  1.36       phx 			/* set 407 model */
    855  1.36       phx 			model_name = models407[v >> 6];
    856  1.36       phx 			cpld = BI_MODEL_CPLD407;
    857  1.36       phx 			flags |= BI_MODEL_THERMAL;
    858  1.36       phx 		}
    859  1.36       phx 	}
    860  1.31       phx 
    861  1.36       phx 	printf("CPLD V%s%u detected for model %s\n",
    862  1.36       phx 	    cpld < BI_MODEL_CPLD406 ? "" : "1.",
    863  1.36       phx 	    version, model_name);
    864  1.36       phx 
    865  1.36       phx 	if (cpld ==  BI_MODEL_CPLD406 || cpld ==  BI_MODEL_CPLD407) {
    866  1.31       phx 		/*
    867  1.31       phx 		 * CS/RS stations power-up their disks one after another.
    868  1.31       phx 		 * We have to watch over the current power state in a CPLD
    869  1.31       phx 		 * register, until all disks become available.
    870  1.31       phx 		 */
    871  1.31       phx 		do {
    872  1.31       phx 			delay(1000 * 1000);
    873  1.36       phx 			v = SYNOCPLD_READ(1);
    874  1.36       phx 			printf("Power state: %02x\r", v);
    875  1.36       phx 		} while (v != 0xff);
    876  1.31       phx 		putchar('\n');
    877  1.36       phx 	} else if (model_name != NULL && model_name[2] == '2') {
    878  1.36       phx 		/*
    879  1.36       phx 		 * DS207 and DS209 have a second SATA disk, which is started
    880  1.36       phx 		 * with several seconds delay, but no CPLD register to
    881  1.36       phx 		 * monitor the power state. So all we can do is to
    882  1.36       phx 		 * wait some more seconds during SATA-init.
    883  1.39       phx 		 * Also wait some seconds now, to make sure the first
    884  1.39       phx 		 * disk is ready after a cold start.
    885  1.36       phx 		 */
    886  1.36       phx 		sata_delay[1] = SYNO_DISK_DELAY;
    887  1.39       phx 		delay(10 * 1024 * 1024);
    888  1.31       phx 	}
    889  1.36       phx 
    890  1.36       phx   cpld_done:
    891  1.36       phx 	if (model_name != NULL) {
    892  1.36       phx 		snprintf(bi_model.name, sizeof(bi_model.name), "%s", model_name);
    893  1.36       phx 		bi_model.flags = cpld | version | flags;
    894  1.36       phx 	} else
    895  1.36       phx 		printf("No CPLD found. DS101/DS106.\n");
    896  1.31       phx }
    897  1.31       phx 
    898  1.31       phx void
    899  1.31       phx synolaunch(struct brdprop *brd)
    900  1.31       phx {
    901  1.36       phx 	extern struct btinfo_model bi_model;
    902  1.31       phx 	struct dkdev_ata *sata1, *sata2;
    903  1.36       phx 	unsigned cpld;
    904  1.36       phx 
    905  1.36       phx 	cpld = bi_model.flags & BI_MODEL_CPLD_MASK;
    906  1.31       phx 
    907  1.36       phx 	if (cpld ==  BI_MODEL_CPLD406 || cpld ==  BI_MODEL_CPLD407) {
    908  1.36       phx 		/* set drive LEDs for active disk drives on CS/RS models */
    909  1.31       phx 		sata1 = lata[0].drv;
    910  1.31       phx 		sata2 = lata[1].drv;
    911  1.36       phx 		SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
    912  1.31       phx 		    (sata1->presense[1] ? 0x20 : 0x30) |
    913  1.31       phx 		    (sata2->presense[0] ? 0x08 : 0x0c) |
    914  1.36       phx 		    (sata2->presense[1] ? 0x02 : 0x03));
    915  1.36       phx 	} else if (cpld ==  BI_MODEL_CPLD207 || cpld ==  BI_MODEL_CPLD209) {
    916  1.36       phx 		/* set drive LEDs for DS207 and DS209 models */
    917  1.36       phx 		sata1 = lata[0].drv;
    918  1.36       phx 		SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
    919  1.36       phx 		    (sata1->presense[1] ? 0x20 : 0x30));
    920  1.31       phx 	}
    921  1.31       phx }
    922  1.31       phx 
    923  1.31       phx void
    924   1.2  nisimura synoreset()
    925   1.2  nisimura {
    926   1.2  nisimura 
    927   1.2  nisimura 	send_sat("C");
    928  1.11       phx 	/*NOTREACHED*/
    929   1.2  nisimura }
    930   1.2  nisimura 
    931   1.2  nisimura void
    932   1.5  nisimura qnapbrdfix(struct brdprop *brd)
    933   1.1  nisimura {
    934   1.1  nisimura 
    935  1.12       phx 	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
    936  1.12       phx 	/* beep, status LED red */
    937  1.12       phx 	send_sat("PW");
    938  1.12       phx }
    939  1.12       phx 
    940  1.12       phx void
    941  1.12       phx qnapreset()
    942  1.12       phx {
    943  1.12       phx 
    944  1.12       phx 	send_sat("f");
    945  1.12       phx 	/*NOTREACHED*/
    946   1.1  nisimura }
    947   1.1  nisimura 
    948   1.1  nisimura void
    949   1.2  nisimura iomegabrdfix(struct brdprop *brd)
    950   1.2  nisimura {
    951   1.2  nisimura 
    952   1.2  nisimura 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    953  1.23       phx 	/* LED flashing blue, fan auto, turn on at 50C, turn off at 45C */
    954  1.23       phx 	send_iomega('b', 'd', 2, 'a', 50, 45);
    955  1.22       phx }
    956  1.22       phx 
    957  1.22       phx void
    958  1.22       phx iomegareset()
    959  1.22       phx {
    960  1.22       phx 
    961  1.23       phx 	send_iomega('g', 0, 0, 0, 0, 0);
    962  1.22       phx 	/*NOTREACHED*/
    963   1.1  nisimura }
    964   1.1  nisimura 
    965   1.1  nisimura void
    966   1.3  nisimura dlinkbrdfix(struct brdprop *brd)
    967   1.3  nisimura {
    968   1.3  nisimura 
    969   1.3  nisimura 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    970  1.13       phx 	send_sat("SYN\n");
    971  1.13       phx 	send_sat("ZWO\n");	/* power LED solid on */
    972   1.3  nisimura }
    973   1.3  nisimura 
    974   1.3  nisimura void
    975   1.5  nisimura nhnasbrdfix(struct brdprop *brd)
    976   1.3  nisimura {
    977   1.3  nisimura 
    978  1.26       phx 	/* status LED off, USB-LEDs on, low-speed fan */
    979  1.26       phx 	NHGPIO_WRITE(0x04);
    980  1.26       phx }
    981  1.26       phx 
    982  1.26       phx void
    983  1.26       phx nhnasreset()
    984  1.26       phx {
    985  1.26       phx 
    986  1.26       phx 	/* status LED on, assert system-reset to all devices */
    987  1.26       phx 	NHGPIO_WRITE(0x02);
    988  1.26       phx 	delay(100000);
    989  1.26       phx 	/*NOTREACHED*/
    990   1.3  nisimura }
    991   1.3  nisimura 
    992   1.3  nisimura void
    993  1.28  nisimura kurot4brdfix(struct brdprop *brd)
    994  1.28  nisimura {
    995  1.28  nisimura 
    996  1.28  nisimura 	init_uart(uart2base, 38400, LCR_8BITS | LCR_PEVEN);
    997  1.28  nisimura }
    998  1.28  nisimura 
    999  1.28  nisimura void
   1000   1.1  nisimura _rtt(void)
   1001   1.1  nisimura {
   1002  1.10       phx 	uint32_t msr;
   1003  1.10       phx 
   1004  1.10       phx 	netif_shutdown_all();
   1005   1.1  nisimura 
   1006   1.1  nisimura 	if (brdprop->reset != NULL)
   1007   1.1  nisimura 		(*brdprop->reset)();
   1008  1.10       phx 	else {
   1009  1.10       phx 		msr = mfmsr();
   1010  1.10       phx 		msr &= ~PSL_EE;
   1011  1.10       phx 		mtmsr(msr);
   1012  1.10       phx 		asm volatile ("sync; isync");
   1013  1.10       phx 		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
   1014  1.10       phx 		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
   1015  1.10       phx 		mtmsr(msr);
   1016  1.10       phx 		asm volatile ("sync; isync");
   1017   1.1  nisimura 		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
   1018  1.10       phx 	}
   1019  1.35     joerg 	__unreachable();
   1020   1.1  nisimura }
   1021   1.1  nisimura 
   1022   1.1  nisimura satime_t
   1023   1.1  nisimura getsecs(void)
   1024   1.1  nisimura {
   1025  1.38       phx 	uint64_t tb = mftb();
   1026   1.1  nisimura 
   1027   1.1  nisimura 	return (tb / ticks_per_sec);
   1028   1.1  nisimura }
   1029   1.1  nisimura 
   1030   1.1  nisimura /*
   1031   1.1  nisimura  * Wait for about n microseconds (at least!).
   1032   1.1  nisimura  */
   1033   1.1  nisimura void
   1034  1.38       phx delay(unsigned n)
   1035   1.1  nisimura {
   1036  1.38       phx 	uint64_t tb;
   1037  1.38       phx 	uint32_t scratch, tbh, tbl;
   1038   1.1  nisimura 
   1039   1.1  nisimura 	tb = mftb();
   1040  1.38       phx 	tb += ((uint64_t)n * 1000 + ns_per_tick - 1) / ns_per_tick;
   1041   1.1  nisimura 	tbh = tb >> 32;
   1042   1.1  nisimura 	tbl = tb;
   1043  1.41  riastrad 	asm volatile(
   1044  1.41  riastrad 	    "1:	mftbu %0;"
   1045  1.41  riastrad 	    "	cmpw %0,%1;"
   1046  1.41  riastrad 	    "	blt 1b;"
   1047  1.41  riastrad 	    "	bgt 2f;"
   1048  1.41  riastrad 	    "	mftb %0;"
   1049  1.41  riastrad 	    "	cmpw 0, %0,%2;"
   1050  1.41  riastrad 	    "	blt 1b;"
   1051  1.41  riastrad 	    "2:"
   1052  1.41  riastrad 	    : "=&r"(scratch)
   1053  1.41  riastrad 	    : "r"(tbh), "r"(tbl)
   1054  1.41  riastrad 	    : "cc");
   1055   1.1  nisimura }
   1056   1.1  nisimura 
   1057   1.1  nisimura void
   1058   1.1  nisimura _wb(uint32_t adr, uint32_t siz)
   1059   1.1  nisimura {
   1060   1.1  nisimura 	uint32_t bnd;
   1061   1.1  nisimura 
   1062  1.41  riastrad 	asm volatile("eieio" ::: "memory");
   1063   1.1  nisimura 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
   1064  1.41  riastrad 		asm volatile("dcbst 0,%0" :: "r"(adr) : "memory");
   1065  1.41  riastrad 	asm volatile("sync" ::: "memory");
   1066   1.1  nisimura }
   1067   1.1  nisimura 
   1068   1.1  nisimura void
   1069   1.1  nisimura _wbinv(uint32_t adr, uint32_t siz)
   1070   1.1  nisimura {
   1071   1.1  nisimura 	uint32_t bnd;
   1072   1.1  nisimura 
   1073  1.41  riastrad 	asm volatile("eieio" ::: "memory");
   1074   1.1  nisimura 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
   1075  1.41  riastrad 		asm volatile("dcbf 0,%0" :: "r"(adr) : "memory");
   1076  1.41  riastrad 	asm volatile("sync");
   1077   1.1  nisimura }
   1078   1.1  nisimura 
   1079   1.1  nisimura void
   1080   1.1  nisimura _inv(uint32_t adr, uint32_t siz)
   1081   1.1  nisimura {
   1082   1.1  nisimura 	uint32_t bnd, off;
   1083   1.1  nisimura 
   1084   1.1  nisimura 	off = adr & (dcache_line_size - 1);
   1085   1.1  nisimura 	adr -= off;
   1086   1.1  nisimura 	siz += off;
   1087  1.41  riastrad 	asm volatile("eieio" ::: "memory");
   1088   1.1  nisimura 	if (off != 0) {
   1089   1.1  nisimura 		/* wbinv() leading unaligned dcache line */
   1090  1.41  riastrad 		asm volatile("dcbf 0,%0" :: "r"(adr) : "memory");
   1091   1.1  nisimura 		if (siz < dcache_line_size)
   1092   1.1  nisimura 			goto done;
   1093   1.1  nisimura 		adr += dcache_line_size;
   1094   1.1  nisimura 		siz -= dcache_line_size;
   1095   1.1  nisimura 	}
   1096   1.1  nisimura 	bnd = adr + siz;
   1097   1.1  nisimura 	off = bnd & (dcache_line_size - 1);
   1098   1.1  nisimura 	if (off != 0) {
   1099   1.1  nisimura 		/* wbinv() trailing unaligned dcache line */
   1100  1.41  riastrad 		asm volatile("dcbf 0,%0" :: "r"(bnd) : "memory"); /* it's OK */
   1101   1.1  nisimura 		if (siz < dcache_line_size)
   1102   1.1  nisimura 			goto done;
   1103   1.1  nisimura 		siz -= off;
   1104   1.1  nisimura 	}
   1105   1.1  nisimura 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
   1106   1.1  nisimura 		/* inv() intermediate dcache lines if ever */
   1107  1.41  riastrad 		asm volatile("dcbi 0,%0" :: "r"(adr) : "memory");
   1108   1.1  nisimura 	}
   1109   1.1  nisimura   done:
   1110  1.41  riastrad 	asm volatile("sync" ::: "memory");
   1111   1.1  nisimura }
   1112   1.1  nisimura 
   1113   1.1  nisimura static inline uint32_t
   1114  1.10       phx mfmsr(void)
   1115  1.10       phx {
   1116  1.10       phx 	uint32_t msr;
   1117  1.10       phx 
   1118  1.10       phx 	asm volatile ("mfmsr %0" : "=r"(msr));
   1119  1.10       phx 	return msr;
   1120  1.10       phx }
   1121  1.10       phx 
   1122  1.10       phx static inline void
   1123  1.10       phx mtmsr(uint32_t msr)
   1124  1.10       phx {
   1125  1.10       phx 	asm volatile ("mtmsr %0" : : "r"(msr));
   1126  1.10       phx }
   1127  1.10       phx 
   1128  1.10       phx static inline uint32_t
   1129   1.1  nisimura cputype(void)
   1130   1.1  nisimura {
   1131   1.1  nisimura 	uint32_t pvr;
   1132   1.1  nisimura 
   1133  1.10       phx 	asm volatile ("mfpvr %0" : "=r"(pvr));
   1134   1.1  nisimura 	return pvr >> 16;
   1135   1.1  nisimura }
   1136   1.1  nisimura 
   1137  1.38       phx static inline uint64_t
   1138   1.1  nisimura mftb(void)
   1139   1.1  nisimura {
   1140  1.38       phx 	uint32_t scratch;
   1141  1.38       phx 	uint64_t tb;
   1142   1.1  nisimura 
   1143   1.1  nisimura 	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
   1144  1.41  riastrad 	    : "=r"(tb), "=r"(scratch) :: "cc");
   1145  1.10       phx 	return tb;
   1146   1.1  nisimura }
   1147   1.1  nisimura 
   1148   1.1  nisimura static void
   1149   1.1  nisimura init_uart(unsigned base, unsigned speed, uint8_t lcr)
   1150   1.1  nisimura {
   1151   1.1  nisimura 	unsigned div;
   1152   1.1  nisimura 
   1153   1.1  nisimura 	div = busclock / speed / 16;
   1154   1.1  nisimura 	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
   1155   1.1  nisimura 	UART_WRITE(base, FCR, 0x00);
   1156   1.1  nisimura 	UART_WRITE(base, DMB, div >> 8);	/* set speed */
   1157   1.1  nisimura 	UART_WRITE(base, DLB, div & 0xff);
   1158   1.1  nisimura 	UART_WRITE(base, LCR, lcr);
   1159   1.1  nisimura 	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
   1160   1.1  nisimura 	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
   1161   1.1  nisimura }
   1162   1.1  nisimura 
   1163   1.1  nisimura /* talk to satellite processor */
   1164   1.1  nisimura static void
   1165   1.1  nisimura send_sat(char *msg)
   1166   1.1  nisimura {
   1167   1.1  nisimura 	unsigned savedbase;
   1168   1.1  nisimura 
   1169   1.1  nisimura 	savedbase = uart1base;
   1170   1.1  nisimura 	uart1base = uart2base;
   1171   1.1  nisimura 	while (*msg)
   1172   1.1  nisimura 		putchar(*msg++);
   1173   1.1  nisimura 	uart1base = savedbase;
   1174   1.1  nisimura }
   1175   1.1  nisimura 
   1176  1.22       phx #ifdef DEBUG
   1177  1.22       phx static void
   1178  1.22       phx iomega_debug(const char *txt, uint8_t buf[])
   1179  1.22       phx {
   1180  1.22       phx 	int i;
   1181  1.22       phx 
   1182  1.22       phx 	printf("%s:", txt);
   1183  1.22       phx 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1184  1.22       phx 		printf(" %02x", buf[i]);
   1185  1.22       phx 	putchar('\n');
   1186  1.22       phx }
   1187  1.22       phx #endif /* DEBUG */
   1188  1.22       phx 
   1189  1.23       phx static void
   1190  1.22       phx send_iomega(int power, int led, int rate, int fan, int high, int low)
   1191  1.18       phx {
   1192  1.22       phx 	uint8_t buf[IOMEGA_PACKETSIZE];
   1193  1.18       phx 	unsigned i, savedbase;
   1194  1.18       phx 
   1195  1.22       phx 	savedbase = uart1base;
   1196  1.22       phx 	uart1base = uart2base;
   1197  1.22       phx 
   1198  1.22       phx 	/* first flush the receive buffer */
   1199  1.22       phx   again:
   1200  1.22       phx 	while (tstchar())
   1201  1.22       phx 		(void)getchar();
   1202  1.22       phx 	delay(20000);
   1203  1.22       phx 	if (tstchar())
   1204  1.22       phx 		goto again;
   1205  1.22       phx 	/*
   1206  1.22       phx 	 * Now synchronize the transmitter by sending 0x00
   1207  1.22       phx 	 * until we receive a status reply.
   1208  1.22       phx 	 */
   1209  1.22       phx 	do {
   1210  1.22       phx 		putchar(0);
   1211  1.23       phx 		delay(50000);
   1212  1.22       phx 	} while (!tstchar());
   1213  1.22       phx 
   1214  1.22       phx 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1215  1.22       phx 		buf[i] = getchar();
   1216  1.22       phx #ifdef DEBUG
   1217  1.22       phx 	uart1base = savedbase;
   1218  1.22       phx 	iomega_debug("68HC908 status", buf);
   1219  1.22       phx 	uart1base = uart2base;
   1220  1.22       phx #endif
   1221  1.22       phx 
   1222  1.22       phx 	/* send command */
   1223  1.23       phx 	buf[IOMEGA_POWER] = power;
   1224  1.23       phx 	buf[IOMEGA_LED] = led;
   1225  1.23       phx 	buf[IOMEGA_FLASH_RATE] = rate;
   1226  1.23       phx 	buf[IOMEGA_FAN] = fan;
   1227  1.23       phx 	buf[IOMEGA_HIGH_TEMP] = high;
   1228  1.23       phx 	buf[IOMEGA_LOW_TEMP] = low;
   1229  1.18       phx 	buf[IOMEGA_ID] = 7;	/* host id */
   1230  1.18       phx 	buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
   1231  1.18       phx 	    buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
   1232  1.18       phx 	    buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
   1233  1.18       phx 	    buf[IOMEGA_ID]) & 0x7f;
   1234  1.22       phx #ifdef DEBUG
   1235  1.22       phx 	uart1base = savedbase;
   1236  1.22       phx 	iomega_debug("G2 sending", buf);
   1237  1.18       phx 	uart1base = uart2base;
   1238  1.22       phx #endif
   1239  1.18       phx 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1240  1.18       phx 		putchar(buf[i]);
   1241  1.22       phx 
   1242  1.22       phx 	/* receive the reply */
   1243  1.18       phx 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1244  1.18       phx 		buf[i] = getchar();
   1245  1.23       phx #ifdef DEBUG
   1246  1.18       phx 	uart1base = savedbase;
   1247  1.22       phx 	iomega_debug("68HC908 reply", buf);
   1248  1.23       phx 	uart1base = uart2base;
   1249  1.22       phx #endif
   1250  1.23       phx 
   1251  1.23       phx 	if (buf[0] == '#')
   1252  1.23       phx 		goto again;  /* try again on error */
   1253  1.23       phx 	uart1base = savedbase;
   1254  1.18       phx }
   1255  1.18       phx 
   1256   1.1  nisimura void
   1257   1.1  nisimura putchar(int c)
   1258   1.1  nisimura {
   1259   1.1  nisimura 	unsigned timo, lsr;
   1260   1.1  nisimura 
   1261   1.1  nisimura 	if (c == '\n')
   1262   1.1  nisimura 		putchar('\r');
   1263   1.1  nisimura 
   1264   1.1  nisimura 	timo = 0x00100000;
   1265   1.1  nisimura 	do {
   1266   1.1  nisimura 		lsr = UART_READ(uart1base, LSR);
   1267   1.1  nisimura 	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
   1268   1.1  nisimura 	if (timo > 0)
   1269   1.1  nisimura 		UART_WRITE(uart1base, THR, c);
   1270   1.1  nisimura }
   1271   1.1  nisimura 
   1272  1.11       phx int
   1273  1.11       phx getchar(void)
   1274  1.11       phx {
   1275  1.11       phx 	unsigned lsr;
   1276  1.11       phx 
   1277  1.11       phx 	do {
   1278  1.11       phx 		lsr = UART_READ(uart1base, LSR);
   1279  1.11       phx 	} while ((lsr & LSR_DRDY) == 0);
   1280  1.11       phx 	return UART_READ(uart1base, RBR);
   1281  1.11       phx }
   1282  1.11       phx 
   1283  1.11       phx int
   1284  1.11       phx tstchar(void)
   1285  1.11       phx {
   1286  1.21       phx 
   1287  1.11       phx 	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
   1288  1.11       phx }
   1289  1.11       phx 
   1290  1.24       phx #define SAR_MASK 0x0ff00000
   1291  1.24       phx #define SAR_SHIFT    20
   1292  1.24       phx #define EAR_MASK 0x30000000
   1293  1.24       phx #define EAR_SHIFT    28
   1294  1.24       phx #define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
   1295  1.24       phx #define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
   1296  1.24       phx static void
   1297  1.24       phx set_mem_bounds(unsigned tag, unsigned bk_en, ...)
   1298  1.24       phx {
   1299  1.24       phx 	unsigned mbst, mbxst, mben, mbxen;
   1300  1.24       phx 	unsigned start, end;
   1301  1.24       phx 	va_list ap;
   1302  1.24       phx 	int i, sh;
   1303  1.24       phx 
   1304  1.24       phx 	va_start(ap, bk_en);
   1305  1.24       phx 	mbst = mbxst = mben = mbxen = 0;
   1306  1.24       phx 
   1307  1.24       phx 	for (i = 0; i < 4; i++) {
   1308  1.24       phx 		if ((bk_en & (1U << i)) != 0) {
   1309  1.24       phx 			start = va_arg(ap, unsigned);
   1310  1.24       phx 			end = va_arg(ap, unsigned);
   1311  1.24       phx 		} else {
   1312  1.24       phx 			start = 0x3ff00000;
   1313  1.24       phx 			end = 0x3fffffff;
   1314  1.24       phx 		}
   1315  1.24       phx 		sh = i << 3;
   1316  1.24       phx 		mbst |= AR(start, sh);
   1317  1.24       phx 		mbxst |= XR(start, sh);
   1318  1.24       phx 		mben |= AR(end, sh);
   1319  1.24       phx 		mbxen |= XR(end, sh);
   1320  1.24       phx 	}
   1321  1.24       phx 	va_end(ap);
   1322  1.24       phx 
   1323  1.24       phx 	pcicfgwrite(tag, MPC106_MEMSTARTADDR1, mbst);
   1324  1.24       phx 	pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, mbxst);
   1325  1.24       phx 	pcicfgwrite(tag, MPC106_MEMENDADDR1, mben);
   1326  1.24       phx 	pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	mbxen);
   1327  1.24       phx 	pcicfgwrite(tag, MPC106_MEMEN,
   1328  1.24       phx 	    (pcicfgread(tag, MPC106_MEMEN) & ~0xff) | (bk_en & 0xff));
   1329  1.24       phx }
   1330  1.24       phx 
   1331  1.24       phx static unsigned
   1332  1.24       phx mpc107memsize(void)
   1333   1.1  nisimura {
   1334   1.1  nisimura 	unsigned bankn, end, n, tag, val;
   1335   1.1  nisimura 
   1336   1.1  nisimura 	tag = pcimaketag(0, 0, 0);
   1337   1.1  nisimura 
   1338   1.1  nisimura 	if (brdtype == BRD_ENCOREPP1) {
   1339   1.1  nisimura 		/* the brd's PPCBOOT looks to have erroneous values */
   1340  1.24       phx 		set_mem_bounds(tag, 1, 0x00000000, (128 << 20) - 1);
   1341  1.24       phx 	} else if (brdtype == BRD_NH230NAS) {
   1342  1.24       phx 		/*
   1343  1.24       phx 		 * PPCBoot sets the end address to 0x7ffffff, although the
   1344  1.24       phx 		 * board has just 64MB (0x3ffffff).
   1345  1.24       phx 		 */
   1346  1.24       phx 		set_mem_bounds(tag, 1, 0x00000000, 0x03ffffff);
   1347   1.1  nisimura 	}
   1348   1.1  nisimura 
   1349   1.1  nisimura 	bankn = 0;
   1350   1.1  nisimura 	val = pcicfgread(tag, MPC106_MEMEN);
   1351   1.1  nisimura 	for (n = 0; n < 4; n++) {
   1352   1.1  nisimura 		if ((val & (1U << n)) == 0)
   1353   1.1  nisimura 			break;
   1354   1.1  nisimura 		bankn = n;
   1355   1.1  nisimura 	}
   1356  1.24       phx 	bankn <<= 3;
   1357   1.1  nisimura 
   1358   1.1  nisimura 	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
   1359   1.1  nisimura 	end =  ((val >> bankn) & 0x03) << 28;
   1360   1.1  nisimura 	val = pcicfgread(tag, MPC106_MEMENDADDR1);
   1361   1.1  nisimura 	end |= ((val >> bankn) & 0xff) << 20;
   1362   1.1  nisimura 	end |= 0xfffff;
   1363   1.1  nisimura 
   1364   1.1  nisimura 	return (end + 1); /* assume the end address matches total amount */
   1365   1.1  nisimura }
   1366   1.1  nisimura 
   1367   1.1  nisimura struct fis_dir_entry {
   1368   1.1  nisimura 	char		name[16];
   1369   1.1  nisimura 	uint32_t	startaddr;
   1370   1.1  nisimura 	uint32_t	loadaddr;
   1371   1.1  nisimura 	uint32_t	flashsize;
   1372   1.1  nisimura 	uint32_t	entryaddr;
   1373   1.1  nisimura 	uint32_t	filesize;
   1374   1.1  nisimura 	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
   1375   1.1  nisimura };
   1376   1.1  nisimura 
   1377   1.1  nisimura #define FIS_LOWER_LIMIT	0xfff00000
   1378   1.1  nisimura 
   1379   1.1  nisimura /*
   1380   1.1  nisimura  * Look for a Redboot-style Flash Image System FIS-directory and
   1381   1.1  nisimura  * return a pointer to the start address of the requested file.
   1382   1.1  nisimura  */
   1383   1.1  nisimura static void *
   1384   1.1  nisimura redboot_fis_lookup(const char *filename)
   1385   1.1  nisimura {
   1386   1.1  nisimura 	static const char FISdirname[16] = {
   1387   1.1  nisimura 	    'F', 'I', 'S', ' ',
   1388   1.1  nisimura 	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
   1389   1.1  nisimura 	};
   1390   1.1  nisimura 	struct fis_dir_entry *dir;
   1391   1.1  nisimura 
   1392   1.1  nisimura 	/*
   1393   1.1  nisimura 	 * The FIS directory is usually in the last sector of the flash.
   1394   1.1  nisimura 	 * But we do not know the sector size (erase size), so start
   1395   1.1  nisimura 	 * at 0xffffff00 and scan backwards in steps of the FIS directory
   1396   1.1  nisimura 	 * entry size (0x100).
   1397   1.1  nisimura 	 */
   1398   1.1  nisimura 	for (dir = (struct fis_dir_entry *)0xffffff00;
   1399   1.1  nisimura 	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
   1400   1.1  nisimura 		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
   1401   1.1  nisimura 			break;
   1402   1.1  nisimura 	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
   1403   1.1  nisimura 		printf("No FIS directory found!\n");
   1404   1.1  nisimura 		return NULL;
   1405   1.1  nisimura 	}
   1406   1.1  nisimura 
   1407   1.1  nisimura 	/* Now find filename by scanning the directory from beginning. */
   1408   1.1  nisimura 	dir = (struct fis_dir_entry *)dir->startaddr;
   1409   1.1  nisimura 	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
   1410   1.1  nisimura 		if (strcmp(dir->name, filename) == 0)
   1411   1.1  nisimura 			return (void *)dir->startaddr;	/* found */
   1412   1.1  nisimura 		dir++;
   1413   1.1  nisimura 	}
   1414   1.1  nisimura 	printf("\"%s\" not found in FIS directory!\n", filename);
   1415   1.1  nisimura 	return NULL;
   1416   1.1  nisimura }
   1417   1.1  nisimura 
   1418   1.6       phx static void
   1419   1.6       phx read_mac_string(uint8_t *mac, char *p)
   1420   1.6       phx {
   1421   1.6       phx 	int i;
   1422   1.6       phx 
   1423   1.6       phx 	for (i = 0; i < 6; i++, p += 3)
   1424   1.7       phx 		*mac++ = read_hex(p);
   1425   1.6       phx }
   1426   1.6       phx 
   1427   1.1  nisimura /*
   1428  1.32       phx  * Scan through the Flash memory and look for a string starting at 512 bytes
   1429  1.32       phx  * block boundaries, matching the format: xx:xx:xx:xx:xx:xx<NUL>, where "x"
   1430  1.32       phx  * are hexadecimal digits.
   1431  1.32       phx  * Read the first match as our MAC address.
   1432  1.32       phx  * The start address of the search, p, *must* be dividable by 512!
   1433  1.32       phx  * Return false when no suitable MAC string was found.
   1434  1.32       phx  */
   1435  1.32       phx static int
   1436  1.32       phx find_mac_string(uint8_t *mac, char *p)
   1437  1.32       phx {
   1438  1.32       phx 	int i;
   1439  1.32       phx 
   1440  1.32       phx 	for (;;) {
   1441  1.32       phx 		for (i = 0; i < 3 * 6; i += 3) {
   1442  1.32       phx 			if (!isxdigit((unsigned)p[i]) ||
   1443  1.32       phx 			    !isxdigit((unsigned)p[i + 1]))
   1444  1.32       phx 				break;
   1445  1.32       phx 			if ((i < 5 && p[i + 2] != ':') ||
   1446  1.32       phx 			    (i >= 5 && p[i + 2] != '\0'))
   1447  1.32       phx 				break;
   1448  1.32       phx 		}
   1449  1.32       phx 		if (i >= 6) {
   1450  1.32       phx 			/* found a valid MAC address */
   1451  1.32       phx 			read_mac_string(mac, p);
   1452  1.32       phx 			return 1;
   1453  1.32       phx 		}
   1454  1.32       phx 		if (p >= (char *)0xfffffe00)
   1455  1.32       phx 			break;
   1456  1.32       phx 		p += 0x200;
   1457  1.32       phx 	}
   1458  1.32       phx 	return 0;
   1459  1.32       phx }
   1460  1.32       phx 
   1461  1.32       phx 
   1462  1.32       phx /*
   1463   1.9       phx  * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
   1464   1.9       phx  * ethernet address and keep it in their Flash memory instead.
   1465   1.1  nisimura  */
   1466   1.1  nisimura void
   1467   1.1  nisimura read_mac_from_flash(uint8_t *mac)
   1468   1.1  nisimura {
   1469   1.1  nisimura 	uint8_t *p;
   1470   1.1  nisimura 
   1471   1.9       phx 	switch (brdtype) {
   1472   1.9       phx 	case BRD_SYNOLOGY:
   1473   1.1  nisimura 		p = redboot_fis_lookup("vendor");
   1474   1.9       phx 		if (p == NULL)
   1475   1.9       phx 			break;
   1476   1.9       phx 		memcpy(mac, p, 6);
   1477   1.9       phx 		return;
   1478   1.9       phx 	case BRD_DLINKDSM:
   1479   1.6       phx 		read_mac_string(mac, (char *)0xfff0ff80);
   1480   1.6       phx 		return;
   1481  1.32       phx 	case BRD_QNAPTS:
   1482  1.32       phx 		if (find_mac_string(mac, (char *)0xfff00000))
   1483  1.32       phx 			return;
   1484  1.32       phx 		break;
   1485   1.9       phx 	default:
   1486   1.1  nisimura 		printf("Warning: This board has no known method defined "
   1487   1.1  nisimura 		    "to determine its MAC address!\n");
   1488   1.9       phx 		break;
   1489   1.9       phx 	}
   1490   1.1  nisimura 
   1491   1.1  nisimura 	/* set to 00:00:00:00:00:00 in case of error */
   1492   1.1  nisimura 	memset(mac, 0, 6);
   1493   1.1  nisimura }
   1494  1.21       phx 
   1495  1.21       phx #ifdef DEBUG
   1496  1.21       phx void
   1497  1.21       phx sat_write(char *p, int len)
   1498  1.21       phx {
   1499  1.21       phx 	unsigned savedbase;
   1500  1.21       phx 
   1501  1.21       phx 	savedbase = uart1base;
   1502  1.21       phx 	uart1base = uart2base;
   1503  1.21       phx 	while (len--)
   1504  1.21       phx 		putchar(*p++);
   1505  1.21       phx 	uart1base = savedbase;
   1506  1.21       phx }
   1507  1.21       phx 
   1508  1.21       phx int
   1509  1.21       phx sat_getch(void)
   1510  1.21       phx {
   1511  1.21       phx 	unsigned lsr;
   1512  1.21       phx 
   1513  1.21       phx 	do {
   1514  1.21       phx 		lsr = UART_READ(uart2base, LSR);
   1515  1.21       phx 	} while ((lsr & LSR_DRDY) == 0);
   1516  1.21       phx 	return UART_READ(uart2base, RBR);
   1517  1.21       phx }
   1518  1.21       phx 
   1519  1.21       phx int
   1520  1.21       phx sat_tstch(void)
   1521  1.21       phx {
   1522  1.21       phx 
   1523  1.21       phx 	return (UART_READ(uart2base, LSR) & LSR_DRDY) != 0;
   1524  1.21       phx }
   1525  1.21       phx #endif /* DEBUG */
   1526