#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" #include <draw.h>#include <memdraw.h>#include "screen.h" #include "../port/netif.h"#include "etherif.h"#include "../port/flashif.h" #include "archipe.h" /* * board-specific support for the Bright Star Engineering ipEngine-1 */ enum { /* sccr */ COM3= IBIT(1)|IBIT(2), /* clock output disabled */ TBS = IBIT(6), /* =0, time base is OSCCLK/{4,16}; =1, time base is GCLK2/16 */ RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */ RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */ CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */ PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */ /* plprcr */ CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */ Showports = 0, /* used to find lightly-documented bits set by bootstrap (eg, PDN) */}; static ulong ports[4*4]; /* * called early in main.c, after machinit: * using board and architecture specific registers, initialise * 8xx registers that need it and complete initialisation of the Mach structure. */voidarchinit(void){ IMM *io; int mf; io = m->iomem; /* run by reset code: no need to lock */ m->clockgen = 4000000; /* crystal frequency */ m->oscclk = m->clockgen/MHz; io->plprcrk = KEEP_ALIVE_KEY; io->plprcr &= ~CSRC; /* general system clock is DFNH */ mf = (io->plprcr >> 20)+1; /* use timing set by bootstrap */ io->plprcrk = ~KEEP_ALIVE_KEY; io->sccrk = KEEP_ALIVE_KEY; io->sccr |= CRQEN | PRQEN | RTDIV | COM3; /* devfpga.c resets COM3 if needed */ io->sccrk = ~KEEP_ALIVE_KEY; m->cpuhz = m->clockgen*mf; m->speed = m->cpuhz/MHz; if((io->memc[CLOCKCS].base & 1) == 0){ /* prom hasn't mapped it */ io->memc[CLOCKCS].option = 0xFFFF0F24; io->memc[CLOCKCS].base = 0xFF020001; } if(Showports){ ports[0] = io->padat; ports[1] = io->padir; ports[2] = io->papar; ports[3] = io->paodr; ports[4] = io->pbdat; ports[5] = io->pbdir; ports[6] = io->pbpar; ports[7] = io->pbodr; ports[8] = io->pcdat; ports[9] = io->pcdir; ports[10] = io->pcpar; ports[11] = io->pcso; ports[12] = io->pddat; ports[13] = io->pddir; ports[14] = io->pdpar; ports[15] = 0; }} static ulongbanksize(int x, ulong *pa){ IMM *io; io = m->iomem; if((io->memc[x].base & 1) == 0) return 0; /* bank not valid */ *pa = io->memc[x].base & ~0x7FFF; return -(io->memc[x].option&~0x7FFF);} /* * initialise the kernel's memory configuration: * there are two banks (base0, npage0) and (base1, npage1). * initialise any other values in conf that are board-specific. */voidarchconfinit(void){ ulong pa, nbytes, ktop; conf.nscc = 2; conf.sccuarts = 0; /* no SCC uarts */ conf.smcuarts = (1<<0)|(1<<1); /* SMC1 (console) and SMC2 */ nbytes = banksize(DRAMCS, &pa); if(nbytes == 0){ /* force default */ nbytes = 16*1024*1024; pa = 0; } conf.npage0 = nbytes/BY2PG; conf.base0 = pa; conf.npage1 = 0; /* the following assumes the kernel text and/or data is in bank 0 */ ktop = PGROUND((ulong)end); ktop = PADDR(ktop) - conf.base0; conf.npage0 -= ktop/BY2PG; conf.base0 += ktop;} voidcpuidprint(void){ ulong v; print("PVR: "); switch(m->cputype){ case 0x01: print("MPC601"); break; case 0x03: print("MPC603"); break; case 0x04: print("MPC604"); break; case 0x06: print("MPC603e"); break; case 0x07: print("MPC603e-v7"); break; case 0x50: print("MPC8xx"); break; default: print("PowerPC version #%x", m->cputype); break; } print(", revision #%lux\n", getpvr()&0xffff); print("IMMR: "); v = getimmr() & 0xFFFF; switch(v>>8){ case 0x00: print("MPC860/821"); break; case 0x20: print("MPC823"); break; case 0x21: print("MPC823A"); break; default: print("Type #%lux", v>>8); break; } print(", mask #%lux\n", v&0xFF); print("%lud MHz system\n", m->cpuhz/MHz); print("\n"); if(Showports){ print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr); print("pipr=%8.8lux\n", m->iomem->pipr); print("ports:\n"); for(v=0;v<nelem(ports);v++) print("%2ld %8.8lux\n", v, ports[v]); /* dump the memory configuration while we're at it */ for(v=0; v<nelem(m->iomem->memc); v++) if(m->iomem->memc[v].base & 1) print("%ld %8.8lux %8.8lux\n", v, m->iomem->memc[v].base, m->iomem->memc[v].option); }} /* * fetch parameters from flash, as stored by BSE bootstrap, * compensating for a bug in its fset that produces silly entries. */ static intenvnameok(char *s){ if(*s == '*') s++; if(*s >= '0' && *s <= '9' || *s == 0) return 0; for(; *s; s++) if(*s >= '0' && *s <= '9' || *s >= 'a' && *s <= 'z' || *s >= 'A' && *s <= 'Z' || *s == '.' || *s == '_' || *s == '#'){ /* ok */ }else return 0; return 1;} intarchconfval(char **names, char **vals, int limit){ uchar *b, *e; char *s; int n, v, l, o; static char bootargs[512]; /* we assume we can access this space before mmuinit() */ b = KADDR(PHYSFLASH+0x4000); if(*b & 1){ b += 0x2000; /* try alternative location */ if(*b & 1) return 0; } v = (b[2]<<8)|b[3]; b += 4; if(v >= 0x2000-4) return 0; n = 0; o = 0; e = b+v; for(; b < e; b += v){ v = *b; if(v == 0xFF || n >= limit) break; s = (char*)b+1; if(v >= 0x80){ v = ((v&0x7F)<<8) | b[1]; s++; } if(envnameok(s)){ names[n] = s; s += strlen(s)+1; l = strlen(s)+1; if(o+l > sizeof(bootargs)) break; vals[n] = bootargs+o; memmove(vals[n], s, l); o += l; n++; } } return n;} voidtoggleled(int b){ int s; s = splhi(); m->iomem->pdpar &= ~(0x20<<b); m->iomem->pddir |= 0x20<<b; m->iomem->pddat ^= 0x020<<b; splx(s);} /* * provide value for #r/switch (devrtc.c) */intarchoptionsw(void){ return 0;} /* * invoked by clock.c:/^clockintr */static voidtwinkle(void){ if(m->ticks%MS2TK(1000) == 0 && m->iomem) toggleled(0);} void (*archclocktick)(void) = twinkle; /* * invoked by ../port/taslock.c:/^ilock: * reset watchdog timer here, if there is one and it is enabled */voidclockcheck(void){} /* * for ../port/devflash.c:/^flashreset * retrieve flash type, virtual base and length and return 0; * return -1 on error (no flash) */intarchflashreset(int bank, Flash *f){ if(bank != 0) return -1; f->type = "Intel28F320B3B"; f->addr = KADDR(PHYSFLASH); f->size = 4*1024*1024; f->width = 2; return 0;} voidarchflashwp(Flash*, int){} /* * set ether parameters: the contents should be derived from EEPROM or NVRAM */intarchether(int ctlno, Ether *ether){ if(isaconfig("ether", ctlno, ether) == 0 && ctlno > 0) return -1; if(ctlno == 0){ ether->type = "SCC"; ether->port = 2; } memmove(ether->ea, KADDR(PHYSFLASH+0x3FFA), Eaddrlen); return 1;} /* * enable the clocks for the given SCC ether and reveal them to the caller. * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback). */intarchetherenable(int cpmid, int *rcs, int *tcs, int mbps, int fd){ IMM *io; if(cpmid != CPscc2) return -1; USED(mbps); io = ioplock(); io->pcpar &= ~EnetLoopback; io->pcso &= ~EnetLoopback; io->pcdir |= EnetLoopback; io->pcdat &= ~EnetLoopback; if(0){ /* TO CHECK: causes ether errors if used */ io->pbpar &= ~EnetFullDuplex; io->pbdir |= EnetFullDuplex; if(fd) io->pbdat |= EnetFullDuplex; else io->pbdat &= ~EnetFullDuplex; } io->pbpar &= ~EnableEnet; io->pbdir |= EnableEnet; io->pbdat |= EnableEnet; io->papar |= SIBIT(7)|SIBIT(6); /* enable CLK1 and CLK2 */ io->padir &= ~(SIBIT(7)|SIBIT(6)); iopunlock(); *rcs = CLK2; *tcs = CLK1; return 0;} /* * do anything extra required to enable the UART on the given CPM port */static ulong uartsactive; voidarchenableuart(int id, int irda){ IMM *io; USED(id); /* both uarts seem to be controlled by the same bit */ USED(irda); /* no IrDA on ipEngine */ io = ioplock(); if(uartsactive == 0){ io->pbpar &= ~EnableRS232; io->pbdir |= EnableRS232; io->pbdat |= EnableRS232; } uartsactive |= 1<<id; iopunlock();} /* * do anything extra required to disable the UART on the given CPM port */voidarchdisableuart(int id){ IMM *io; io = ioplock(); uartsactive &= ~(1<<id); if(uartsactive == 0) io->pbdat &= ~EnableRS232; iopunlock();} /* * enable the external USB transceiver * speed is 12MHz if highspeed is non-zero; 1.5MHz if zero * master is non-zero if the node is acting as USB Host and should provide power */voidarchenableusb(int highspeed, int master){ IMM *io; USED(master); io = ioplock(); io->pcpar &= ~USBFullSpeed; io->pcso &= ~USBFullSpeed; if(highspeed) io->pcdat |= USBFullSpeed; else io->pcdat &= ~USBFullSpeed; io->pcdir |= USBFullSpeed; iopunlock();} /* * shut down the USB transceiver */voidarchdisableusb(void){ /* nothing to be done on ipEngine, apparently */} /* * set the external infrared transceiver to the given speed */voidarchsetirxcvr(int highspeed){ USED(highspeed);} /* * force hardware reset/reboot */voidarchreboot(void){ IMM *io; io = m->iomem; io->plprcrk = KEEP_ALIVE_KEY; io->plprcr |= 1<<7; /* checkstop reset enable */ io->plprcrk = ~KEEP_ALIVE_KEY; eieio(); io->sdcr = 1; eieio(); io->lccr = 0; /* switch LCD off */ eieio(); firmware(0);} /* * enable/disable the LCD panel's backlight */voidarchbacklight(int on){ USED(on);} /* * set parameters to describe the screen */intarchlcdmode(Mode *m){ /* sample parameters in case a panel is attached to the external pins */ m->x = 640; m->y = 480; m->d = 3; m->lcd.freq = 25000000; m->lcd.ac = 0; m->lcd.vpw = 1; m->lcd.wbf = 33; m->lcd.wbl = 228; m->lcd.flags = IsColour | IsTFT | OELow | VsyncLow | ClockLow; return -1; /* there isn't a screen */} /* * there isn't a keyboard port */voidarchkbdinit(void){}
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#include "../port/netif.h"
#include "etherif.h"
#include "../port/flashif.h"
#include "archipe.h"
/*
* board-specific support for the Bright Star Engineering ipEngine-1
*/
enum {
/* sccr */
COM3= IBIT(1)|IBIT(2), /* clock output disabled */
TBS = IBIT(6), /* =0, time base is OSCCLK/{4,16}; =1, time base is GCLK2/16 */
RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */
RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */
CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */
PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */
/* plprcr */
CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */
Showports = 0, /* used to find lightly-documented bits set by bootstrap (eg, PDN) */
};
static ulong ports[4*4];
/*
* called early in main.c, after machinit:
* using board and architecture specific registers, initialise
* 8xx registers that need it and complete initialisation of the Mach structure.
*/
void
archinit(void)
{
IMM *io;
int mf;
io = m->iomem; /* run by reset code: no need to lock */
m->clockgen = 4000000; /* crystal frequency */
m->oscclk = m->clockgen/MHz;
io->plprcrk = KEEP_ALIVE_KEY;
io->plprcr &= ~CSRC; /* general system clock is DFNH */
mf = (io->plprcr >> 20)+1; /* use timing set by bootstrap */
io->plprcrk = ~KEEP_ALIVE_KEY;
io->sccrk = KEEP_ALIVE_KEY;
io->sccr |= CRQEN | PRQEN | RTDIV | COM3; /* devfpga.c resets COM3 if needed */
io->sccrk = ~KEEP_ALIVE_KEY;
m->cpuhz = m->clockgen*mf;
m->speed = m->cpuhz/MHz;
if((io->memc[CLOCKCS].base & 1) == 0){ /* prom hasn't mapped it */
io->memc[CLOCKCS].option = 0xFFFF0F24;
io->memc[CLOCKCS].base = 0xFF020001;
}
if(Showports){
ports[0] = io->padat;
ports[1] = io->padir;
ports[2] = io->papar;
ports[3] = io->paodr;
ports[4] = io->pbdat;
ports[5] = io->pbdir;
ports[6] = io->pbpar;
ports[7] = io->pbodr;
ports[8] = io->pcdat;
ports[9] = io->pcdir;
ports[10] = io->pcpar;
ports[11] = io->pcso;
ports[12] = io->pddat;
ports[13] = io->pddir;
ports[14] = io->pdpar;
ports[15] = 0;
}
}
static ulong
banksize(int x, ulong *pa)
{
IMM *io;
io = m->iomem;
if((io->memc[x].base & 1) == 0)
return 0; /* bank not valid */
*pa = io->memc[x].base & ~0x7FFF;
return -(io->memc[x].option&~0x7FFF);
}
/*
* initialise the kernel's memory configuration:
* there are two banks (base0, npage0) and (base1, npage1).
* initialise any other values in conf that are board-specific.
*/
void
archconfinit(void)
{
ulong pa, nbytes, ktop;
conf.nscc = 2;
conf.sccuarts = 0; /* no SCC uarts */
conf.smcuarts = (1<<0)|(1<<1); /* SMC1 (console) and SMC2 */
nbytes = banksize(DRAMCS, &pa);
if(nbytes == 0){ /* force default */
nbytes = 16*1024*1024;
pa = 0;
}
conf.npage0 = nbytes/BY2PG;
conf.base0 = pa;
conf.npage1 = 0;
/* the following assumes the kernel text and/or data is in bank 0 */
ktop = PGROUND((ulong)end);
ktop = PADDR(ktop) - conf.base0;
conf.npage0 -= ktop/BY2PG;
conf.base0 += ktop;
}
void
cpuidprint(void)
{
ulong v;
print("PVR: ");
switch(m->cputype){
case 0x01: print("MPC601"); break;
case 0x03: print("MPC603"); break;
case 0x04: print("MPC604"); break;
case 0x06: print("MPC603e"); break;
case 0x07: print("MPC603e-v7"); break;
case 0x50: print("MPC8xx"); break;
default: print("PowerPC version #%x", m->cputype); break;
}
print(", revision #%lux\n", getpvr()&0xffff);
print("IMMR: ");
v = getimmr() & 0xFFFF;
switch(v>>8){
case 0x00: print("MPC860/821"); break;
case 0x20: print("MPC823"); break;
case 0x21: print("MPC823A"); break;
default: print("Type #%lux", v>>8); break;
}
print(", mask #%lux\n", v&0xFF);
print("%lud MHz system\n", m->cpuhz/MHz);
print("\n");
if(Showports){
print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr);
print("pipr=%8.8lux\n", m->iomem->pipr);
print("ports:\n");
for(v=0;v<nelem(ports);v++)
print("%2ld %8.8lux\n", v, ports[v]);
/* dump the memory configuration while we're at it */
for(v=0; v<nelem(m->iomem->memc); v++)
if(m->iomem->memc[v].base & 1)
print("%ld %8.8lux %8.8lux\n", v, m->iomem->memc[v].base, m->iomem->memc[v].option);
}
}
/*
* fetch parameters from flash, as stored by BSE bootstrap,
* compensating for a bug in its fset that produces silly entries.
*/
static int
envnameok(char *s)
{
if(*s == '*')
s++;
if(*s >= '0' && *s <= '9' || *s == 0)
return 0;
for(; *s; s++)
if(*s >= '0' && *s <= '9' ||
*s >= 'a' && *s <= 'z' ||
*s >= 'A' && *s <= 'Z' ||
*s == '.' || *s == '_' || *s == '#'){
/* ok */
}else
return 0;
return 1;
}
int
archconfval(char **names, char **vals, int limit)
{
uchar *b, *e;
char *s;
int n, v, l, o;
static char bootargs[512];
/* we assume we can access this space before mmuinit() */
b = KADDR(PHYSFLASH+0x4000);
if(*b & 1){
b += 0x2000; /* try alternative location */
if(*b & 1)
return 0;
}
v = (b[2]<<8)|b[3];
b += 4;
if(v >= 0x2000-4)
return 0;
n = 0;
o = 0;
e = b+v;
for(; b < e; b += v){
v = *b;
if(v == 0xFF || n >= limit)
break;
s = (char*)b+1;
if(v >= 0x80){
v = ((v&0x7F)<<8) | b[1];
s++;
}
if(envnameok(s)){
names[n] = s;
s += strlen(s)+1;
l = strlen(s)+1;
if(o+l > sizeof(bootargs))
break;
vals[n] = bootargs+o;
memmove(vals[n], s, l);
o += l;
n++;
}
}
return n;
}
void
toggleled(int b)
{
int s;
s = splhi();
m->iomem->pdpar &= ~(0x20<<b);
m->iomem->pddir |= 0x20<<b;
m->iomem->pddat ^= 0x020<<b;
splx(s);
}
/*
* provide value for #r/switch (devrtc.c)
*/
int
archoptionsw(void)
{
return 0;
}
/*
* invoked by clock.c:/^clockintr
*/
static void
twinkle(void)
{
if(m->ticks%MS2TK(1000) == 0 && m->iomem)
toggleled(0);
}
void (*archclocktick)(void) = twinkle;
/*
* invoked by ../port/taslock.c:/^ilock:
* reset watchdog timer here, if there is one and it is enabled
*/
void
clockcheck(void)
{
}
/*
* for ../port/devflash.c:/^flashreset
* retrieve flash type, virtual base and length and return 0;
* return -1 on error (no flash)
*/
int
archflashreset(int bank, Flash *f)
{
if(bank != 0)
return -1;
f->type = "Intel28F320B3B";
f->addr = KADDR(PHYSFLASH);
f->size = 4*1024*1024;
f->width = 2;
return 0;
}
void
archflashwp(Flash*, int)
{
}
/*
* set ether parameters: the contents should be derived from EEPROM or NVRAM
*/
int
archether(int ctlno, Ether *ether)
{
if(isaconfig("ether", ctlno, ether) == 0 && ctlno > 0)
return -1;
if(ctlno == 0){
ether->type = "SCC";
ether->port = 2;
}
memmove(ether->ea, KADDR(PHYSFLASH+0x3FFA), Eaddrlen);
return 1;
}
/*
* enable the clocks for the given SCC ether and reveal them to the caller.
* do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback).
*/
int
archetherenable(int cpmid, int *rcs, int *tcs, int mbps, int fd)
{
IMM *io;
if(cpmid != CPscc2)
return -1;
USED(mbps);
io = ioplock();
io->pcpar &= ~EnetLoopback;
io->pcso &= ~EnetLoopback;
io->pcdir |= EnetLoopback;
io->pcdat &= ~EnetLoopback;
if(0){ /* TO CHECK: causes ether errors if used */
io->pbpar &= ~EnetFullDuplex;
io->pbdir |= EnetFullDuplex;
if(fd)
io->pbdat |= EnetFullDuplex;
else
io->pbdat &= ~EnetFullDuplex;
}
io->pbpar &= ~EnableEnet;
io->pbdir |= EnableEnet;
io->pbdat |= EnableEnet;
io->papar |= SIBIT(7)|SIBIT(6); /* enable CLK1 and CLK2 */
io->padir &= ~(SIBIT(7)|SIBIT(6));
iopunlock();
*rcs = CLK2;
*tcs = CLK1;
return 0;
}
/*
* do anything extra required to enable the UART on the given CPM port
*/
static ulong uartsactive;
void
archenableuart(int id, int irda)
{
IMM *io;
USED(id); /* both uarts seem to be controlled by the same bit */
USED(irda); /* no IrDA on ipEngine */
io = ioplock();
if(uartsactive == 0){
io->pbpar &= ~EnableRS232;
io->pbdir |= EnableRS232;
io->pbdat |= EnableRS232;
}
uartsactive |= 1<<id;
iopunlock();
}
/*
* do anything extra required to disable the UART on the given CPM port
*/
void
archdisableuart(int id)
{
IMM *io;
io = ioplock();
uartsactive &= ~(1<<id);
if(uartsactive == 0)
io->pbdat &= ~EnableRS232;
iopunlock();
}
/*
* enable the external USB transceiver
* speed is 12MHz if highspeed is non-zero; 1.5MHz if zero
* master is non-zero if the node is acting as USB Host and should provide power
*/
void
archenableusb(int highspeed, int master)
{
IMM *io;
USED(master);
io = ioplock();
io->pcpar &= ~USBFullSpeed;
io->pcso &= ~USBFullSpeed;
if(highspeed)
io->pcdat |= USBFullSpeed;
else
io->pcdat &= ~USBFullSpeed;
io->pcdir |= USBFullSpeed;
iopunlock();
}
/*
* shut down the USB transceiver
*/
void
archdisableusb(void)
{
/* nothing to be done on ipEngine, apparently */
}
/*
* set the external infrared transceiver to the given speed
*/
void
archsetirxcvr(int highspeed)
{
USED(highspeed);
}
/*
* force hardware reset/reboot
*/
void
archreboot(void)
{
IMM *io;
io = m->iomem;
io->plprcrk = KEEP_ALIVE_KEY;
io->plprcr |= 1<<7; /* checkstop reset enable */
io->plprcrk = ~KEEP_ALIVE_KEY;
eieio();
io->sdcr = 1;
eieio();
io->lccr = 0; /* switch LCD off */
eieio();
firmware(0);
}
/*
* enable/disable the LCD panel's backlight
*/
void
archbacklight(int on)
{
USED(on);
}
/*
* set parameters to describe the screen
*/
int
archlcdmode(Mode *m)
{
/* sample parameters in case a panel is attached to the external pins */
m->x = 640;
m->y = 480;
m->d = 3;
m->lcd.freq = 25000000;
m->lcd.ac = 0;
m->lcd.vpw = 1;
m->lcd.wbf = 33;
m->lcd.wbl = 228;
m->lcd.flags = IsColour | IsTFT | OELow | VsyncLow | ClockLow;
return -1; /* there isn't a screen */
}
/*
* there isn't a keyboard port
*/
void
archkbdinit(void)
{
}