#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include #include #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;viomem->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<iomem->pddir |= 0x20<iomem->pddat ^= 0x020<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<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) { }