#include <sys/param.h>
#include <powerpc/psl.h>
#include <powerpc/oea/spr.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#include <lib/libkern/libkern.h>
#include <machine/bootinfo.h>
#include "globals.h"
#define BRD_DECL(xxx) \
void xxx ## setup(struct brdprop *); \
void xxx ## brdfix(struct brdprop *); \
void xxx ## pcifix(struct brdprop *); \
void xxx ## launch(struct brdprop *); \
void xxx ## reset(void)
BRD_DECL(mot);
BRD_DECL(enc);
BRD_DECL(kuro);
BRD_DECL(syno);
BRD_DECL(qnap);
BRD_DECL(iomega);
BRD_DECL(dlink);
BRD_DECL(nhnas);
BRD_DECL(kurot4);
static void brdfixup(void);
static void setup(void);
static void send_iomega(int, int, int, int, int, int);
static inline uint32_t mfmsr(void);
static inline void mtmsr(uint32_t);
static inline uint32_t cputype(void);
static inline uint64_t mftb(void);
static void init_uart(unsigned, unsigned, uint8_t);
static void send_sat(char *);
static unsigned mpc107memsize(void);
#define RBR 0
#define THR 0
#define DLB 0
#define DMB 1
#define IER 1
#define FCR 2
#define LCR 3
#define LCR_DLAB 0x80
#define LCR_PEVEN 0x18
#define LCR_PNONE 0x00
#define LCR_8BITS 0x03
#define MCR 4
#define MCR_RTS 0x02
#define MCR_DTR 0x01
#define LSR 5
#define LSR_THRE 0x20
#define LSR_DRDY 0x01
#define DCR 0x11
#define UART_READ(base, r) in8(base + (r))
#define UART_WRITE(base, r, v) out8(base + (r), (v))
#define MPC106_MEMSTARTADDR1 0x80
#define MPC106_EXTMEMSTARTADDR1 0x88
#define MPC106_MEMENDADDR1 0x90
#define MPC106_EXTMEMENDADDR1 0x98
#define MPC106_MEMEN 0xa0
#define IOMEGA_POWER 0
#define IOMEGA_LED 1
#define IOMEGA_FLASH_RATE 2
#define IOMEGA_FAN 3
#define IOMEGA_HIGH_TEMP 4
#define IOMEGA_LOW_TEMP 5
#define IOMEGA_ID 6
#define IOMEGA_CHECKSUM 7
#define IOMEGA_PACKETSIZE 8
#define NHGPIO_WRITE(x) *((volatile uint8_t *)0x70000000) = (x)
#define SYNOCPLD_READ(r) *((volatile uint8_t *)0xff000000 + (r))
#define SYNOCPLD_WRITE(r,x) do { \
*((volatile uint8_t *)0xff000000 + (r)) = (x); \
delay(10); \
} while(0)
static struct brdprop brdlist[] = {
{
"sandpoint",
"Sandpoint X3",
BRD_SANDPOINTX3,
0,
"com", 0x3f8, 115200,
motsetup, motbrdfix, motpcifix, NULL, NULL },
{
"encpp1",
"EnCore PP1",
BRD_ENCOREPP1,
0,
"com", 0x3f8, 115200,
encsetup, encbrdfix, encpcifix, NULL, NULL },
{
"kurobox",
"KuroBox",
BRD_KUROBOX,
0,
"eumb", 0x4600, 57600,
kurosetup, kurobrdfix, NULL, NULL, kuroreset },
{
"synology",
"Synology CS/DS/RS",
BRD_SYNOLOGY,
0,
"eumb", 0x4500, 115200,
synosetup, synobrdfix, synopcifix, synolaunch, synoreset },
{
"qnap",
"QNAP TS",
BRD_QNAPTS,
33164691,
"eumb", 0x4500, 115200,
NULL, qnapbrdfix, NULL, NULL, qnapreset },
{
"iomega",
"IOMEGA StorCenter G2",
BRD_STORCENTER,
0,
"eumb", 0x4500, 115200,
NULL, iomegabrdfix, NULL, NULL, iomegareset },
{
"dlink",
"D-Link DSM-G600",
BRD_DLINKDSM,
33000000,
"eumb", 0x4500, 9600,
NULL, dlinkbrdfix, NULL, NULL, NULL },
{
"nhnas",
"Netronix NH-230/231",
BRD_NH230NAS,
33000000,
"eumb", 0x4500, 9600,
NULL, nhnasbrdfix, NULL, NULL, nhnasreset },
{
"kurot4",
"KuroBox/T4",
BRD_KUROBOXT4,
32768000,
"eumb", 0x4600, 57600,
NULL, kurot4brdfix, NULL, NULL, NULL },
{
"unknown",
"Unknown board",
BRD_UNKNOWN,
0,
"eumb", 0x4500, 115200,
NULL, NULL, NULL, NULL, NULL },
};
static struct brdprop *brdprop;
static uint32_t ticks_per_sec, ns_per_tick;
const unsigned dcache_line_size = 32;
const unsigned dcache_range_size = 4 * 1024;
unsigned uart1base;
unsigned uart2base;
void brdsetup(void);
void
brdsetup(void)
{
static uint8_t pci_to_memclk[] = {
30, 30, 10, 10, 20, 10, 10, 10,
10, 20, 20, 15, 20, 15, 20, 30,
30, 40, 15, 40, 20, 25, 20, 40,
25, 20, 10, 20, 15, 15, 20, 00
};
static uint8_t mem_to_cpuclk[] = {
25, 30, 45, 20, 20, 00, 10, 30,
30, 20, 45, 30, 25, 35, 30, 35,
20, 25, 20, 30, 35, 40, 40, 20,
30, 25, 40, 30, 30, 25, 35, 00
};
char *consname;
int consport;
uint32_t extclk;
unsigned pchb, pcib, dev11, dev12, dev13, dev15, dev16, val;
extern struct btinfo_memory bi_mem;
extern struct btinfo_console bi_cons;
extern struct btinfo_clock bi_clk;
extern struct btinfo_prodfamily bi_fam;
pchb = pcimaketag(0, 0, 0);
pcicfgwrite(pchb, 0x78, 0xfc000000);
brdtype = BRD_UNKNOWN;
extclk = EXT_CLK_FREQ;
busclock = 0;
dev11 = pcimaketag(0, 11, 0);
dev12 = pcimaketag(0, 12, 0);
dev13 = pcimaketag(0, 13, 0);
dev15 = pcimaketag(0, 15, 0);
dev16 = pcimaketag(0, 16, 0);
if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
brdtype = BRD_SANDPOINTX3;
}
else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
brdtype = BRD_ENCOREPP1;
}
else if (PCI_CLASS(pcicfgread(dev11, PCI_CLASS_REG)) == PCI_CLASS_ETH) {
if (PCI_VENDOR(pcicfgread(dev11, PCI_ID_REG)) == 0x1317)
brdtype = BRD_KUROBOX;
else if (PCI_VENDOR(pcicfgread(dev11, PCI_ID_REG)) == 0x10ec) {
if (PCI_PRODUCT(pcicfgread(dev12,PCI_ID_REG)) != 0x3512)
brdtype = BRD_KUROBOX;
else
brdtype = BRD_KUROBOXT4;
}
}
else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x1148
|| PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x11ab) {
brdtype = BRD_SYNOLOGY;
}
else if (PCI_VENDOR(pcicfgread(dev13, PCI_ID_REG)) == 0x1106) {
brdtype = BRD_STORCENTER;
}
else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1191) {
brdtype = BRD_DLINKDSM;
}
else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1283
|| PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1095) {
brdtype = BRD_NH230NAS;
}
else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x8086
|| PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x10ec) {
brdtype = BRD_QNAPTS;
}
brdprop = brd_lookup(brdtype);
setup();
if (brdprop->extclk != 0)
extclk = brdprop->extclk;
if (busclock == 0) {
if (cputype() == MPC8245) {
val = pcicfgread(pchb, 0xe0);
busclock = (extclk *
pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
asm volatile ("mfspr %0,1009" : "=r"(val));
cpuclock = ((uint64_t)busclock *
mem_to_cpuclk[val >> 27] + 10) / 10;
} else
busclock = 100000000;
}
ticks_per_sec = busclock >> 2;
ns_per_tick = 1000000000 / ticks_per_sec;
consname = brdprop->consname;
consport = brdprop->consport;
if (strcmp(consname, "eumb") == 0) {
uart1base = 0xfc000000 + consport;
UART_WRITE(uart1base, DCR, 0x01);
uart2base = uart1base ^ 0x0300;
} else
uart1base = 0xfe000000 + consport;
brdfixup();
bi_mem.memsize = mpc107memsize();
snprintf(bi_cons.devname, sizeof(bi_cons.devname), "%s", consname);
bi_cons.addr = consport;
bi_cons.speed = brdprop->consspeed;
bi_clk.ticks_per_sec = ticks_per_sec;
snprintf(bi_fam.name, sizeof(bi_fam.name), "%s", brdprop->family);
}
struct brdprop *
brd_lookup(int brd)
{
u_int i;
for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
if (brdlist[i].brdtype == brd)
return &brdlist[i];
}
return &brdlist[i - 1];
}
static void
setup()
{
if (brdprop->setup == NULL)
return;
(*brdprop->setup)(brdprop);
}
static void
brdfixup()
{
if (brdprop->brdfix == NULL)
return;
(*brdprop->brdfix)(brdprop);
}
void
pcifixup()
{
if (brdprop->pcifix == NULL)
return;
(*brdprop->pcifix)(brdprop);
}
void
launchfixup()
{
if (brdprop->launch == NULL)
return;
(*brdprop->launch)(brdprop);
}
void
encsetup(struct brdprop *brd)
{
#ifdef COSNAME
brd->consname = CONSNAME;
#endif
#ifdef CONSPORT
brd->consport = CONSPORT;
#endif
#ifdef CONSSPEED
brd->consspeed = CONSSPEED;
#endif
}
void
encbrdfix(struct brdprop *brd)
{
unsigned ac97, ide, pcib, pmgt, usb12, usb34, val;
pcib = pcimaketag(0, 22, 0);
ide = pcimaketag(0, 22, 1);
usb12 = pcimaketag(0, 22, 2);
usb34 = pcimaketag(0, 22, 3);
pmgt = pcimaketag(0, 22, 4);
ac97 = pcimaketag(0, 22, 5);
#define CFG(i,v) do { \
*(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
*(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
} while (0)
val = pcicfgread(pcib, 0x84);
val |= (02 << 8);
pcicfgwrite(pcib, 0x84, val);
CFG(0xe2, 0x0f);
val = pcicfgread(pcib, 0x84);
val &= ~(02 << 8);
pcicfgwrite(pcib, 0x84, val);
val = pcicfgread(pcib, 0x54);
val = (val & 0xff) | 0xb0500000;
pcicfgwrite(pcib, 0x54, val);
val = pcicfgread(pcib, 0x44);
val = val | 0x20000000;
pcicfgwrite(pcib, 0x44, val);
*(volatile uint8_t *)0xfe0004d0 = 0x20;
*(volatile uint8_t *)0xfe0004d1 = 0x08;
val = pcicfgread(usb12, 0x3c) &~ 0xff;
val |= 11;
pcicfgwrite(usb12, 0x3c, val);
val = pcicfgread(usb34, 0x3c) &~ 0xff;
val |= 11;
pcicfgwrite(usb34, 0x3c, val);
val = pcicfgread(ac97, 0x3c) &~ 0xff;
val |= 5;
pcicfgwrite(ac97, 0x3c, val);
(void) pcicfgread(ide, 0x08);
(void) pcicfgread(pmgt, 0x08);
}
void
encpcifix(struct brdprop *brd)
{
unsigned ide, irq, net, pcib, steer, val;
#define STEER(v, b) (((v) & (b)) ? "edge" : "level")
pcib = pcimaketag(0, 22, 0);
ide = pcimaketag(0, 22, 1);
net = pcimaketag(0, 25, 0);
val = pcicfgread(pcib, 0x54);
steer = val & 0xf;
irq = (val >> 12) & 0xf;
if (irq) {
printf("pin A -> irq %d, %s\n",
irq, STEER(steer, 0x1));
}
irq = (val >> 16) & 0xf;
if (irq) {
printf("pin B -> irq %d, %s\n",
irq, STEER(steer, 0x2));
}
irq = (val >> 20) & 0xf;
if (irq) {
printf("pin C -> irq %d, %s\n",
irq, STEER(steer, 0x4));
}
irq = (val >> 28);
if (irq) {
printf("pin D -> irq %d, %s\n",
irq, STEER(steer, 0x8));
}
#if 0
val = pcicfgread(ide, 0x08) & 0xffff00ff;
pcicfgwrite(ide, 0x08, val | (0x8f << 8));
#else
val = pcicfgread(ide, 0x08) & 0xffff00ff;
val |= (0x8a << 8);
pcicfgwrite(ide, 0x08, val);
val = pcicfgread(ide, 0x3c) & 0xffff00ff;
pcicfgwrite(ide, 0x3c, val);
#endif
val = pcicfgread(pcib, 0x48);
pcicfgwrite(pcib, 0x48, val | 04);
val = pcicfgread(pcib, 0x84);
pcicfgwrite(pcib, 0x84, val | 0x1c00);
val = pcicfgread(net, 0x3c) & 0xffff0000;
val |= (('A' - '@') << 8) | 25;
pcicfgwrite(net, 0x3c, val);
}
void
motsetup(struct brdprop *brd)
{
#ifdef COSNAME
brd->consname = CONSNAME;
#endif
#ifdef CONSPORT
brd->consport = CONSPORT;
#endif
#ifdef CONSSPEED
brd->consspeed = CONSSPEED;
#endif
}
void
motbrdfix(struct brdprop *brd)
{
}
void
motpcifix(struct brdprop *brd)
{
unsigned ide, net, pcib, steer, val;
int line;
pcib = pcimaketag(0, 11, 0);
ide = pcimaketag(0, 11, 1);
net = pcimaketag(0, 15, 0);
if (pcicfgread(pcib, 0x40) & 0x20) {
steer = pcicfgread(pcib, 0x60);
if ((steer & 0x80808080) == 0x80808080)
printf("PIRQ[0-3] disabled\n");
else {
unsigned i, v = steer;
for (i = 0; i < 4; i++, v >>= 8) {
if ((v & 0x80) != 0 || (v & 0xf) == 0)
continue;
printf("PIRQ[%d]=%d\n", i, v & 0xf);
}
}
}
#if 1
val = pcicfgread(ide, 0x08);
val &= 0xffff00ff;
pcicfgwrite(ide, 0x08, val | (0x8f << 8));
val = pcicfgread(pcib, 0x40) & 0x00ffffff;
pcicfgwrite(pcib, 0x40, val);
val = pcicfgread(pcib, 0x44) & 0xffff0000;
pcicfgwrite(pcib, 0x44, val);
val = pcicfgread(ide, 0x40) & 0xffff0000;
val |= (1 << 11) | 0x33;
pcicfgwrite(ide, 0x40, val);
val = pcicfgread(ide, 0x3c) & 0xffffff00;
val |= 11;
pcicfgwrite(ide, 0x3c, val);
#else
val = pcicfgread(ide, 0x08);
val &= 0xffff00ff;
pcicfgwrite(ide, 0x08, val | (0x8a << 8));
val = pcicfgread(pcib, 0x40) & 0x00ffffff;
pcicfgwrite(pcib, 0x40, val | (0xee << 24));
val = pcicfgread(ide, 0x44) & 0xffff0000;
pcicfgwrite(ide, 0x44, val);
val = pcicfgread(ide, 0x3c) & 0xffff0000;
pcicfgwrite(ide, 0x3c, val);
#endif
val = pcicfgread(net, 0x3c) & 0xffff0000;
pcidecomposetag(net, NULL, &line, NULL);
val |= (('A' - '@') << 8) | line;
pcicfgwrite(net, 0x3c, val);
}
void
kurosetup(struct brdprop *brd)
{
if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
brd->extclk = 32768000;
else
brd->extclk = 32521333;
}
void
kurobrdfix(struct brdprop *brd)
{
init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
}
void
kuroreset()
{
send_sat("CCGG");
}
void
synosetup(struct brdprop *brd)
{
#if 0
if (1)
brd->extclk = 33164691;
else
brd->extclk = 33165343;
#endif
}
void
synobrdfix(struct brdprop *brd)
{
init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
send_sat("247");
}
#define SYNO_FAN_TIMEOUT 500
#define SYNO_DISK_DELAY 30
void
synopcifix(struct brdprop *brd)
{
static const char models207[4][7] = {
"???", "DS107e", "DS107", "DS207"
};
static const char models209[2][7] = {
"DS109j", "DS209j"
};
static const char models406[3][7] = {
"CS406e", "CS406", "RS406"
};
static const char models407[4][7] = {
"???", "CS407e", "CS407", "RS407"
};
extern struct btinfo_model bi_model;
const char *model_name;
unsigned cpld, version, flags;
uint8_t v, status;
int i;
cpld = 0;
flags = 0;
version = 0;
model_name = NULL;
SYNOCPLD_WRITE(0, 0x00);
v = SYNOCPLD_READ(0);
if (v != 0x00) {
v &= 0xf0;
if (v != 0x00 || (SYNOCPLD_READ(16 + 0) & 0xf0) != v)
goto cpld_done;
cpld4bits:
SYNOCPLD_WRITE(0, 0x50);
v = SYNOCPLD_READ(0) & 0xf0;
if (v != 0x50 || (SYNOCPLD_READ(32 + 0) & 0xf0) != v)
goto cpld_done;
v = SYNOCPLD_READ(2) & 0xf0;
if ((SYNOCPLD_READ(48 + 2) & 0xf0) != v)
goto cpld_done;
version = (v >> 4) & 7;
status = SYNOCPLD_READ(3) & 0xf0;
SYNOCPLD_WRITE(3, 0x00);
for (i = 0; i < SYNO_FAN_TIMEOUT * 100; i++) {
delay(10);
v = SYNOCPLD_READ(3) & 0xf0;
if ((status & 0x20) == 0 && (v & 0x20) != 0) {
v = SYNOCPLD_READ(1) >> 6;
model_name = models207[v];
cpld = BI_MODEL_CPLD207;
flags |= BI_MODEL_THERMAL;
break;
}
if ((status & 0x10) == 0 && (v & 0x10) != 0) {
v = SYNOCPLD_READ(1) >> 7;
model_name = models209[v];
cpld = BI_MODEL_CPLD209;
if (v == 1)
flags |= BI_MODEL_THERMAL;
break;
}
}
SYNOCPLD_WRITE(3, status);
if (i >= SYNO_FAN_TIMEOUT * 100)
goto cpld_done;
} else {
if (SYNOCPLD_READ(16 + 0) != v)
goto cpld4bits;
SYNOCPLD_WRITE(0, 0x55);
v = SYNOCPLD_READ(0);
if (v != 0x55)
goto cpld4bits;
if (SYNOCPLD_READ(32 + 0) != v)
goto cpld_done;
v = SYNOCPLD_READ(2);
if (SYNOCPLD_READ(48 + 2) != v)
goto cpld_done;
version = v & 3;
if ((v & 0x0c) != 0x0c) {
model_name = models406[(v >> 2) & 3];
cpld = BI_MODEL_CPLD406;
} else {
model_name = models407[v >> 6];
cpld = BI_MODEL_CPLD407;
flags |= BI_MODEL_THERMAL;
}
}
printf("CPLD V%s%u detected for model %s\n",
cpld < BI_MODEL_CPLD406 ? "" : "1.",
version, model_name);
if (cpld == BI_MODEL_CPLD406 || cpld == BI_MODEL_CPLD407) {
do {
delay(1000 * 1000);
v = SYNOCPLD_READ(1);
printf("Power state: %02x\r", v);
} while (v != 0xff);
putchar('\n');
} else if (model_name != NULL && model_name[2] == '2') {
sata_delay[1] = SYNO_DISK_DELAY;
delay(10 * 1024 * 1024);
}
cpld_done:
if (model_name != NULL) {
snprintf(bi_model.name, sizeof(bi_model.name), "%s", model_name);
bi_model.flags = cpld | version | flags;
} else
printf("No CPLD found. DS101/DS106.\n");
}
void
synolaunch(struct brdprop *brd)
{
extern struct btinfo_model bi_model;
struct dkdev_ata *sata1, *sata2;
unsigned cpld;
cpld = bi_model.flags & BI_MODEL_CPLD_MASK;
if (cpld == BI_MODEL_CPLD406 || cpld == BI_MODEL_CPLD407) {
sata1 = lata[0].drv;
sata2 = lata[1].drv;
SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
(sata1->presense[1] ? 0x20 : 0x30) |
(sata2->presense[0] ? 0x08 : 0x0c) |
(sata2->presense[1] ? 0x02 : 0x03));
} else if (cpld == BI_MODEL_CPLD207 || cpld == BI_MODEL_CPLD209) {
sata1 = lata[0].drv;
SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
(sata1->presense[1] ? 0x20 : 0x30));
}
}
void
synoreset()
{
send_sat("C");
}
void
qnapbrdfix(struct brdprop *brd)
{
init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
send_sat("PW");
}
void
qnapreset()
{
send_sat("f");
}
void
iomegabrdfix(struct brdprop *brd)
{
init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
send_iomega('b', 'd', 2, 'a', 50, 45);
}
void
iomegareset()
{
send_iomega('g', 0, 0, 0, 0, 0);
}
void
dlinkbrdfix(struct brdprop *brd)
{
init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
send_sat("SYN\n");
send_sat("ZWO\n");
}
void
nhnasbrdfix(struct brdprop *brd)
{
NHGPIO_WRITE(0x04);
}
void
nhnasreset()
{
NHGPIO_WRITE(0x02);
delay(100000);
}
void
kurot4brdfix(struct brdprop *brd)
{
init_uart(uart2base, 38400, LCR_8BITS | LCR_PEVEN);
}
void
_rtt(void)
{
uint32_t msr;
netif_shutdown_all();
if (brdprop->reset != NULL)
(*brdprop->reset)();
else {
msr = mfmsr();
msr &= ~PSL_EE;
mtmsr(msr);
asm volatile ("sync; isync");
asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
msr &= ~(PSL_ME | PSL_DR | PSL_IR);
mtmsr(msr);
asm volatile ("sync; isync");
run(0, 0, 0, 0, (void *)0xFFF00100);
}
__unreachable();
}
satime_t
getsecs(void)
{
uint64_t tb = mftb();
return (tb / ticks_per_sec);
}
void
delay(unsigned n)
{
uint64_t tb;
uint32_t scratch, tbh, tbl;
tb = mftb();
tb += ((uint64_t)n * 1000 + ns_per_tick - 1) / ns_per_tick;
tbh = tb >> 32;
tbl = tb;
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)
: "cc");
}
void
_wb(uint32_t adr, uint32_t siz)
{
uint32_t bnd;
asm volatile("eieio" ::: "memory");
for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
asm volatile("dcbst 0,%0" :: "r"(adr) : "memory");
asm volatile("sync" ::: "memory");
}
void
_wbinv(uint32_t adr, uint32_t siz)
{
uint32_t bnd;
asm volatile("eieio" ::: "memory");
for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
asm volatile("dcbf 0,%0" :: "r"(adr) : "memory");
asm volatile("sync");
}
void
_inv(uint32_t adr, uint32_t siz)
{
uint32_t bnd, off;
off = adr & (dcache_line_size - 1);
adr -= off;
siz += off;
asm volatile("eieio" ::: "memory");
if (off != 0) {
asm volatile("dcbf 0,%0" :: "r"(adr) : "memory");
if (siz < dcache_line_size)
goto done;
adr += dcache_line_size;
siz -= dcache_line_size;
}
bnd = adr + siz;
off = bnd & (dcache_line_size - 1);
if (off != 0) {
asm volatile("dcbf 0,%0" :: "r"(bnd) : "memory");
if (siz < dcache_line_size)
goto done;
siz -= off;
}
for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
asm volatile("dcbi 0,%0" :: "r"(adr) : "memory");
}
done:
asm volatile("sync" ::: "memory");
}
static inline uint32_t
mfmsr(void)
{
uint32_t msr;
asm volatile ("mfmsr %0" : "=r"(msr));
return msr;
}
static inline void
mtmsr(uint32_t msr)
{
asm volatile ("mtmsr %0" : : "r"(msr));
}
static inline uint32_t
cputype(void)
{
uint32_t pvr;
asm volatile ("mfpvr %0" : "=r"(pvr));
return pvr >> 16;
}
static inline uint64_t
mftb(void)
{
uint32_t scratch;
uint64_t tb;
asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
: "=r"(tb), "=r"(scratch) :: "cc");
return tb;
}
static void
init_uart(unsigned base, unsigned speed, uint8_t lcr)
{
unsigned div;
div = busclock / speed / 16;
UART_WRITE(base, LCR, 0x80);
UART_WRITE(base, FCR, 0x00);
UART_WRITE(base, DMB, div >> 8);
UART_WRITE(base, DLB, div & 0xff);
UART_WRITE(base, LCR, lcr);
UART_WRITE(base, FCR, 0x07);
UART_WRITE(base, IER, 0x00);
}
static void
send_sat(char *msg)
{
unsigned savedbase;
savedbase = uart1base;
uart1base = uart2base;
while (*msg)
putchar(*msg++);
uart1base = savedbase;
}
#ifdef DEBUG
static void
iomega_debug(const char *txt, uint8_t buf[])
{
int i;
printf("%s:", txt);
for (i = 0; i < IOMEGA_PACKETSIZE; i++)
printf(" %02x", buf[i]);
putchar('\n');
}
#endif
static void
send_iomega(int power, int led, int rate, int fan, int high, int low)
{
uint8_t buf[IOMEGA_PACKETSIZE];
unsigned i, savedbase;
savedbase = uart1base;
uart1base = uart2base;
again:
while (tstchar())
(void)getchar();
delay(20000);
if (tstchar())
goto again;
do {
putchar(0);
delay(50000);
} while (!tstchar());
for (i = 0; i < IOMEGA_PACKETSIZE; i++)
buf[i] = getchar();
#ifdef DEBUG
uart1base = savedbase;
iomega_debug("68HC908 status", buf);
uart1base = uart2base;
#endif
buf[IOMEGA_POWER] = power;
buf[IOMEGA_LED] = led;
buf[IOMEGA_FLASH_RATE] = rate;
buf[IOMEGA_FAN] = fan;
buf[IOMEGA_HIGH_TEMP] = high;
buf[IOMEGA_LOW_TEMP] = low;
buf[IOMEGA_ID] = 7;
buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
buf[IOMEGA_ID]) & 0x7f;
#ifdef DEBUG
uart1base = savedbase;
iomega_debug("G2 sending", buf);
uart1base = uart2base;
#endif
for (i = 0; i < IOMEGA_PACKETSIZE; i++)
putchar(buf[i]);
for (i = 0; i < IOMEGA_PACKETSIZE; i++)
buf[i] = getchar();
#ifdef DEBUG
uart1base = savedbase;
iomega_debug("68HC908 reply", buf);
uart1base = uart2base;
#endif
if (buf[0] == '#')
goto again;
uart1base = savedbase;
}
void
putchar(int c)
{
unsigned timo, lsr;
if (c == '\n')
putchar('\r');
timo = 0x00100000;
do {
lsr = UART_READ(uart1base, LSR);
} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
if (timo > 0)
UART_WRITE(uart1base, THR, c);
}
int
getchar(void)
{
unsigned lsr;
do {
lsr = UART_READ(uart1base, LSR);
} while ((lsr & LSR_DRDY) == 0);
return UART_READ(uart1base, RBR);
}
int
tstchar(void)
{
return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
}
#define SAR_MASK 0x0ff00000
#define SAR_SHIFT 20
#define EAR_MASK 0x30000000
#define EAR_SHIFT 28
#define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
#define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
static void
set_mem_bounds(unsigned tag, unsigned bk_en, ...)
{
unsigned mbst, mbxst, mben, mbxen;
unsigned start, end;
va_list ap;
int i, sh;
va_start(ap, bk_en);
mbst = mbxst = mben = mbxen = 0;
for (i = 0; i < 4; i++) {
if ((bk_en & (1U << i)) != 0) {
start = va_arg(ap, unsigned);
end = va_arg(ap, unsigned);
} else {
start = 0x3ff00000;
end = 0x3fffffff;
}
sh = i << 3;
mbst |= AR(start, sh);
mbxst |= XR(start, sh);
mben |= AR(end, sh);
mbxen |= XR(end, sh);
}
va_end(ap);
pcicfgwrite(tag, MPC106_MEMSTARTADDR1, mbst);
pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, mbxst);
pcicfgwrite(tag, MPC106_MEMENDADDR1, mben);
pcicfgwrite(tag, MPC106_EXTMEMENDADDR1, mbxen);
pcicfgwrite(tag, MPC106_MEMEN,
(pcicfgread(tag, MPC106_MEMEN) & ~0xff) | (bk_en & 0xff));
}
static unsigned
mpc107memsize(void)
{
unsigned bankn, end, n, tag, val;
tag = pcimaketag(0, 0, 0);
if (brdtype == BRD_ENCOREPP1) {
set_mem_bounds(tag, 1, 0x00000000, (128 << 20) - 1);
} else if (brdtype == BRD_NH230NAS) {
set_mem_bounds(tag, 1, 0x00000000, 0x03ffffff);
}
bankn = 0;
val = pcicfgread(tag, MPC106_MEMEN);
for (n = 0; n < 4; n++) {
if ((val & (1U << n)) == 0)
break;
bankn = n;
}
bankn <<= 3;
val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
end = ((val >> bankn) & 0x03) << 28;
val = pcicfgread(tag, MPC106_MEMENDADDR1);
end |= ((val >> bankn) & 0xff) << 20;
end |= 0xfffff;
return (end + 1);
}
struct fis_dir_entry {
char name[16];
uint32_t startaddr;
uint32_t loadaddr;
uint32_t flashsize;
uint32_t entryaddr;
uint32_t filesize;
char pad[256 - (16 + 5 * sizeof(uint32_t))];
};
#define FIS_LOWER_LIMIT 0xfff00000
static void *
redboot_fis_lookup(const char *filename)
{
static const char FISdirname[16] = {
'F', 'I', 'S', ' ',
'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
};
struct fis_dir_entry *dir;
for (dir = (struct fis_dir_entry *)0xffffff00;
(uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
break;
if ((uint32_t)dir < FIS_LOWER_LIMIT) {
printf("No FIS directory found!\n");
return NULL;
}
dir = (struct fis_dir_entry *)dir->startaddr;
while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
if (strcmp(dir->name, filename) == 0)
return (void *)dir->startaddr;
dir++;
}
printf("\"%s\" not found in FIS directory!\n", filename);
return NULL;
}
static void
read_mac_string(uint8_t *mac, char *p)
{
int i;
for (i = 0; i < 6; i++, p += 3)
*mac++ = read_hex(p);
}
static int
find_mac_string(uint8_t *mac, char *p)
{
int i;
for (;;) {
for (i = 0; i < 3 * 6; i += 3) {
if (!isxdigit((unsigned)p[i]) ||
!isxdigit((unsigned)p[i + 1]))
break;
if ((i < 5 && p[i + 2] != ':') ||
(i >= 5 && p[i + 2] != '\0'))
break;
}
if (i >= 6) {
read_mac_string(mac, p);
return 1;
}
if (p >= (char *)0xfffffe00)
break;
p += 0x200;
}
return 0;
}
void
read_mac_from_flash(uint8_t *mac)
{
uint8_t *p;
switch (brdtype) {
case BRD_SYNOLOGY:
p = redboot_fis_lookup("vendor");
if (p == NULL)
break;
memcpy(mac, p, 6);
return;
case BRD_DLINKDSM:
read_mac_string(mac, (char *)0xfff0ff80);
return;
case BRD_QNAPTS:
if (find_mac_string(mac, (char *)0xfff00000))
return;
break;
default:
printf("Warning: This board has no known method defined "
"to determine its MAC address!\n");
break;
}
memset(mac, 0, 6);
}
#ifdef DEBUG
void
sat_write(char *p, int len)
{
unsigned savedbase;
savedbase = uart1base;
uart1base = uart2base;
while (len--)
putchar(*p++);
uart1base = savedbase;
}
int
sat_getch(void)
{
unsigned lsr;
do {
lsr = UART_READ(uart2base, LSR);
} while ((lsr & LSR_DRDY) == 0);
return UART_READ(uart2base, RBR);
}
int
sat_tstch(void)
{
return (UART_READ(uart2base, LSR) & LSR_DRDY) != 0;
}
#endif