123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- /*
- * stuff specific to marvell's kirkwood architecture
- * as seen in the sheevaplug
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "io.h"
- #include "../port/netif.h"
- #include "etherif.h"
- #include "../port/flashif.h"
- #include "arm.h"
- enum {
- L2writeback = 1,
- Debug = 0,
- };
- typedef struct GpioReg GpioReg;
- struct GpioReg {
- ulong dataout;
- ulong dataoutena;
- ulong blinkena;
- ulong datainpol;
- ulong datain;
- ulong intrcause;
- ulong intrmask;
- ulong intrlevelmask;
- };
- typedef struct L2uncache L2uncache;
- typedef struct L2win L2win;
- struct L2uncache {
- struct L2win {
- ulong base; /* phys addr */
- ulong size;
- } win[4];
- };
- enum {
- /* L2win->base bits */
- L2enable = 1<<0,
- };
- typedef struct Dramctl Dramctl;
- struct Dramctl {
- ulong ctl;
- ulong ddrctllo;
- struct {
- ulong lo;
- ulong hi;
- } time;
- ulong addrctl;
- ulong opagectl;
- ulong oper;
- ulong mode;
- ulong extmode;
- ulong ddrctlhi;
- ulong ddr2timelo;
- ulong operctl;
- struct {
- ulong lo;
- ulong hi;
- } mbusctl;
- ulong mbustimeout;
- ulong ddrtimehi;
- ulong sdinitctl;
- ulong extsdmode1;
- ulong extsdmode2;
- struct {
- ulong lo;
- ulong hi;
- } odtctl;
- ulong ddrodtctl;
- ulong rbuffsel;
- ulong accalib;
- ulong dqcalib;
- ulong dqscalib;
- };
- /* unused so far */
- typedef struct SDramdReg SDramdReg;
- struct SDramdReg {
- struct {
- ulong base;
- ulong size;
- } win[4];
- };
- typedef struct Addrmap Addrmap;
- typedef struct Addrwin Addrwin;
- struct Addrmap {
- struct Addrwin {
- ulong ctl; /* see Winenable in io.h */
- ulong base; /* virtual address */
- ulong remaplo; /* physical address sent to target */
- ulong remaphi; /* " */
- } win[8];
- ulong dirba; /* device internal reg's base addr.: PHYSIO */
- };
- Soc soc = {
- .cpu = PHYSIO+0x20100,
- .devid = PHYSIO+0x10034,
- .l2cache = PHYSIO+0x20a00, /* uncachable addrs for L2 */
- .sdramc = PHYSIO+0x01400,
- // .sdramd = PHYSIO+0x01500, /* unused */
- .iocfg = PHYSIO+0x100e0,
- .addrmap = PHYSIO+0x20000, /* cpu address map */
- .intr = PHYSIO+0x20200,
- .nand = PHYSIO+0x10418,
- .cesa = PHYSIO+0x30000, /* crypto accelerator */
- .ehci = PHYSIO+0x50000,
- .spi = PHYSIO+0x10600,
- .twsi = PHYSIO+0x11000,
- .analog = PHYSIO+0x1007c,
- .pci = PHYSIO+0x40000,
- .pcibase = PHYSIO+0x41800,
- .rtc = PHYSIO+0x10300,
- .clock = PHYSIO+0x20300,
- // .clockctl = PHYSIO+0x1004c, /* unused */
- .ether = { PHYSIO+0x72000, PHYSIO+0x76000, },
- .sata = { PHYSIO+0x80000, /* sata config reg here */
- PHYSIO+0x82000, /* edma config reg here */
- PHYSIO+0x84000, /* edma config reg here */
- },
- .uart = { PHYSIO+0x12000, PHYSIO+0x12100, },
- .gpio = { PHYSIO+0x10100, PHYSIO+0x10140, },
- };
- /*
- * sheeva/openrd u-boot leaves us with this address map:
- *
- * 0 targ 4 attr 0xe8 size 256MB addr 0x9:: remap addr 0x9:: pci mem
- * 1 targ 1 attr 0x2f size 8MB addr 0xf9:: remap addr 0xf9:: nand flash
- * 2 targ 4 attr 0xe0 size 16MB addr 0xf:: remap addr 0xc:: pci i/o
- * 3 targ 1 attr 0x1e size 16MB addr 0xf8:: remap addr 0x0 spi flash
- * 4 targ 1 attr 0x1d size 16MB addr 0xff:: boot rom
- * 5 targ 1 attr 0x1e size 128MB addr 0xe8:: disabled spi flash
- * 6 targ 1 attr 0x1d size 128MB addr 0xf:: disabled boot rom
- * 7 targ 3 attr 0x1 size 64K addr 0xfb:: crypto sram
- *
- * dreamplug u-boot leaves us with this address map:
- *
- * 0 targ 4 attr 0xe8 size 256MB addr 0x9:: remap addr 0x9:: pci mem
- * 1 targ 4 attr 0xe0 size 64KB addr 0xc:: remap addr 0xc:: pci i/o
- * 2 targ 1 attr 0x2f size 128MB addr 0xd8:: remap addr 0xd8:: nand flash
- * 3 targ 1 attr 0x1e size 128MB addr 0xe8:: remap addr 0xe8:: spi flash
- * 4 targ 1 attr 0x1d size 128MB addr 0xf8:: boot rom
- * 5 targ 3 attr 0x1 size 64K addr 0xc801:: crypto sram
- * 6 targ 0 attr 0x0 size 64K addr 0xf:: disabled ram?
- * 7 targ 0 attr 0x0 size 64K addr 0xf8:: disabled ram?
- */
- #define WINTARG(ctl) (((ctl) >> 4) & 017)
- #define WINATTR(ctl) (((ctl) >> 8) & 0377)
- #define WIN64KSIZE(ctl) (((ctl) >> 16) + 1)
- static void
- praddrwin(Addrwin *win, int i)
- {
- ulong ctl, targ, attr, size64k;
- if (!Debug) {
- USED(win, i);
- return;
- }
- ctl = win->ctl;
- targ = WINTARG(ctl);
- attr = WINATTR(ctl);
- size64k = WIN64KSIZE(ctl);
- print("cpu addr map: %s window %d: targ %ld attr %#lux size %,ld addr %#lux",
- ctl & Winenable? "enabled": "disabled", i, targ, attr,
- size64k * 64*1024, win->base);
- if (i < 4)
- print(" remap addr %#llux", (uvlong)win->remaphi<<32 |
- win->remaplo);
- print("\n");
- }
- static void
- fixaddrmap(void)
- {
- int i;
- ulong ctl, targ, attr, size64k;
- Addrmap *map;
- Addrwin *win;
- map = (Addrmap *)soc.addrmap;
- for (i = 0; i < nelem(map->win); i++) {
- win = &map->win[i];
- ctl = win->ctl;
- targ = WINTARG(ctl);
- attr = WINATTR(ctl);
- size64k = WIN64KSIZE(ctl);
- USED(attr, size64k);
- if (targ == Targcesasram) {
- win->ctl |= Winenable;
- win->base = PHYSCESASRAM;
- coherence();
- praddrwin(win, i);
- }
- }
- if (map->dirba != PHYSIO)
- panic("dirba not %#ux", PHYSIO);
- }
- static void
- praddrmap(void)
- {
- int i;
- Addrmap *map;
- map = (Addrmap *)soc.addrmap;
- for (i = 0; i < nelem(map->win); i++)
- praddrwin(&map->win[i], i);
- }
- int
- ispow2(uvlong ul)
- {
- /* see Hacker's Delight if this isn't obvious */
- return (ul & (ul - 1)) == 0;
- }
- /*
- * return exponent of smallest power of 2 ≥ n
- */
- int
- log2(ulong n)
- {
- int i;
- i = 31 - clz(n);
- if (!ispow2(n) || n == 0)
- i++;
- return i;
- }
- void
- cacheinfo(int level, int kind, Memcache *cp) /* l1 only */
- {
- uint len, assoc, size;
- ulong setsways;
- /* get cache types & sizes (read-only reg) */
- setsways = cprdsc(0, CpID, CpIDidct, CpIDct);
- cp->level = level;
- cp->kind = kind;
- if ((setsways & (1<<24)) == 0)
- kind = Unified;
- if (kind != Icache)
- setsways >>= 12;
- assoc = (setsways >> 3) & MASK(3);
- cp->nways = 1 << assoc;
- size = (setsways >> 6) & MASK(4);
- cp->size = 1 << (size + 9);
- len = setsways & MASK(2);
- cp->log2linelen = len + 3;
- cp->linelen = 1 << cp->log2linelen;
- cp->setsways = setsways;
- cp->nsets = 1 << (size + 6 - assoc - len);
- cp->setsh = cp->log2linelen;
- cp->waysh = 32 - log2(cp->nways);
- }
- static char *
- wbtype(uint type)
- {
- static char *types[] = {
- "write-through",
- "read data block",
- "reg 7 ops, no lock-down",
- [06] "reg 7 ops, format A",
- [07] "reg 7 ops, format B deprecated",
- [016] "reg 7 ops, format C",
- [05] "reg 7 ops, format D",
- };
- if (type >= nelem(types) || types[type] == nil)
- return "GOK";
- return types[type];
- }
- static void
- prcache(Memcache *mcp)
- {
- int type;
- char id;
- if (mcp->kind == Unified)
- id = 'U';
- else if (mcp->kind == Icache)
- id = 'I';
- else if (mcp->kind == Dcache)
- id = 'D';
- else
- id = '?';
- print("l%d %c: %d bytes, %d ways %d sets %d bytes/line",
- mcp->level, id, mcp->size, mcp->nways, mcp->nsets,
- mcp->linelen);
- if (mcp->linelen != CACHELINESZ)
- print(" *should* be %d", CACHELINESZ);
- type = (mcp->setsways >> 25) & MASK(4);
- if (type == 0)
- print("; write-through only");
- else
- print("; write-back type `%s' (%#o) possible",
- wbtype(type), type);
- if (mcp->setsways & (1<<11))
- print("; page table mapping restrictions apply");
- if (mcp->setsways & (1<<2))
- print("; M bit is set in cache type reg");
- print("\n");
- }
- static void
- prcachecfg(void)
- {
- Memcache mc;
- cacheinfo(1, Dcache, &mc);
- prcache(&mc);
- cacheinfo(1, Icache, &mc);
- prcache(&mc);
- }
- void
- l2cacheon(void)
- {
- ulong cfg;
- CpucsReg *cpu;
- L2uncache *l2p;
- cacheuwbinv();
- l2cacheuwbinv();
- l1cachesoff(); /* turns off L2 as a side effect */
- cpwrsc(CpDef, CpCLD, 0, 0, 0); /* GL-CPU-100: set D cache lockdown reg. */
- /* marvell guideline GL-CPU-130 */
- cpu = (CpucsReg *)soc.cpu;
- cfg = cpu->cpucfg | L2exists | L2ecc | Cfgiprefetch | Cfgdprefetch;
- if (L2writeback)
- cfg &= ~L2writethru; /* see PTE Cached & Buffered bits */
- else
- cfg |= L2writethru;
- cpu->l2cfg = cfg;
- coherence(); /* force l2 cache to pay attention */
- cpu->l2tm1 = cpu->l2tm0 = 0x66666666; /* marvell guideline GL-CPU-120 */
- coherence();
- cpwrsc(CpL2, CpTESTCFG, CpTCl2waylck, CpTCl2waylock, 0);
- cachedinv();
- l2cacheuinv();
- /* disable l2 caching of i/o registers */
- l2p = (L2uncache *)soc.l2cache;
- memset(l2p, 0, sizeof *l2p);
- /*
- * l2: don't cache upper half of address space.
- * the L2 cache is PIPT, so the addresses are physical.
- */
- l2p->win[0].base = 0x80000000 | L2enable; /* 64K multiple */
- l2p->win[0].size = (32*1024-1) << 16; /* 64K multiples */
- coherence();
- l2cachecfgon();
- l1cacheson(); /* turns L2 on as a side effect */
- print("l2 cache: 256K or 512K: 4 ways, 32-byte lines, write-%s, sdram only\n",
- cpu->l2cfg & L2writethru? "through": "back");
- }
- /* called late in main */
- void
- archconfinit(void)
- {
- m->cpuhz = Frequency;
- m->delayloop = m->cpuhz/2000; /* initial estimate */
- fixaddrmap();
- if (Debug)
- praddrmap();
- prcachecfg();
- l2cacheon();
- }
- void
- archkwlink(void)
- {
- }
- int
- archether(unsigned ctlno, Ether *ether)
- {
- if(ctlno >= 2)
- return -1;
- ether->type = "88e1116";
- ether->port = ctlno;
- // ether->mbps = 1000;
- return 1;
- }
- /* LED/USB gpios */
- enum {
- /*
- * the bit assignments are MPP pin numbers from the last page of the
- * sheevaplug 6.0.1 schematic.
- */
- KWOEValHigh = 1<<(49-32), /* pin 49: LED pin */
- KWOEValLow = 1<<29, /* pin 29: USB_PWEN, pin 28: usb_pwerr */
- KWOELow = ~0,
- KWOEHigh = ~0,
- };
- /* called early in main */
- void
- archreset(void)
- {
- ulong clocks;
- CpucsReg *cpu;
- Dramctl *dram;
- GpioReg *gpio;
- clockshutdown(); /* watchdog disabled */
- /* configure gpios */
- gpio = (GpioReg*)soc.gpio[0];
- gpio->dataout = KWOEValLow;
- coherence();
- gpio->dataoutena = KWOELow;
- gpio = (GpioReg*)soc.gpio[1];
- gpio->dataout = KWOEValHigh;
- coherence();
- gpio->dataoutena = KWOEHigh;
- coherence();
- cpu = (CpucsReg *)soc.cpu;
- cpu->mempm = 0; /* turn everything on */
- coherence();
- clocks = MASK(10);
- clocks |= MASK(21) & ~MASK(14);
- clocks &= ~(1<<18 | 1<<1); /* reserved bits */
- cpu->clockgate |= clocks; /* enable all the clocks */
- cpu->l2cfg |= L2exists; /* when L2exists is 0, the l2 ignores us */
- coherence();
- dram = (Dramctl *)soc.sdramc;
- dram->ddrctllo &= ~(1<<6); /* marvell guideline GL-MEM-70 */
- *(ulong *)soc.analog = 0x68; /* marvell guideline GL-MISC-40 */
- coherence();
- }
- void
- archreboot(void)
- {
- CpucsReg *cpu;
- iprint("reset!\n");
- delay(10);
- cpu = (CpucsReg *)soc.cpu;
- cpu->rstout = RstoutSoft;
- cpu->softreset = ResetSystem;
- coherence();
- cpu->cpucsr = Reset;
- coherence();
- delay(500);
- splhi();
- iprint("waiting...");
- for(;;)
- idlehands();
- }
- void
- archconsole(void)
- {
- // uartconsole(0, "b115200");
- //serialputs("uart0 console @ 115200\n", strlen("uart0 console @ 115200\n"));
- }
- void
- archflashwp(Flash*, int)
- {
- }
- int flashat(Flash *f, uintptr pa);
- /*
- * 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 = "nand";
- if (flashat(f, PHYSNAND1))
- f->addr = (void*)PHYSNAND1;
- else if (flashat(f, PHYSNAND2))
- f->addr = (void*)PHYSNAND2;
- else
- f->addr = nil;
- f->size = 0; /* done by probe */
- f->width = 1;
- f->interleave = 0;
- return 0;
- }
|