]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/archkw.c
merge
[plan9front.git] / sys / src / 9 / kw / archkw.c
1 /*
2  * stuff specific to marvell's kirkwood architecture
3  * as seen in the sheevaplug
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11 #include "io.h"
12
13 #include "../port/netif.h"
14 #include "../port/etherif.h"
15 #include "../port/flashif.h"
16
17 #include "arm.h"
18
19 enum {
20         L2writeback = 1,
21         Debug = 0,
22 };
23
24 typedef struct GpioReg GpioReg;
25 struct GpioReg {
26         ulong   dataout;
27         ulong   dataoutena;
28         ulong   blinkena;
29         ulong   datainpol;
30         ulong   datain;
31         ulong   intrcause;
32         ulong   intrmask;
33         ulong   intrlevelmask;
34 };
35
36 typedef struct L2uncache L2uncache;
37 typedef struct L2win L2win;
38 struct L2uncache {
39         struct L2win {
40                 ulong   base;   /* phys addr */
41                 ulong   size;
42         } win[4];
43 };
44
45 enum {
46         /* L2win->base bits */
47         L2enable        = 1<<0,
48 };
49
50 typedef struct Dramctl Dramctl;
51 struct Dramctl {
52         ulong   ctl;
53         ulong   ddrctllo;
54         struct {
55                 ulong   lo;
56                 ulong   hi;
57         } time;
58         ulong   addrctl;
59         ulong   opagectl;
60         ulong   oper;
61         ulong   mode;
62         ulong   extmode;
63         ulong   ddrctlhi;
64         ulong   ddr2timelo;
65         ulong   operctl;
66         struct {
67                 ulong   lo;
68                 ulong   hi;
69         } mbusctl;
70         ulong   mbustimeout;
71         ulong   ddrtimehi;
72         ulong   sdinitctl;
73         ulong   extsdmode1;
74         ulong   extsdmode2;
75         struct {
76                 ulong   lo;
77                 ulong   hi;
78         } odtctl;
79         ulong   ddrodtctl;
80         ulong   rbuffsel;
81
82         ulong   accalib;
83         ulong   dqcalib;
84         ulong   dqscalib;
85 };
86
87 /* unused so far */
88 typedef struct SDramdReg SDramdReg;
89 struct SDramdReg {
90         struct {
91                 ulong   base;
92                 ulong   size;
93         } win[4];
94 };
95
96 typedef struct Addrmap Addrmap;
97 typedef struct Addrwin Addrwin;
98 struct Addrmap {
99         struct Addrwin {
100                 ulong   ctl;    /* see Winenable in io.h */
101                 ulong   base;
102                 ulong   remaplo;
103                 ulong   remaphi;
104         } win[8];
105         ulong   dirba;          /* device internal reg's base addr.: PHYSIO */
106 };
107
108 Soc soc = {
109         .cpu            = PHYSIO+0x20100,
110         .devid          = PHYSIO+0x10034,
111         .l2cache        = PHYSIO+0x20a00,       /* uncachable addrs for L2 */
112         .sdramc         = PHYSIO+0x01400,
113 //      .sdramd         = PHYSIO+0x01500,       /* unused */
114
115         .iocfg          = PHYSIO+0x100e0,
116         .addrmap        = PHYSIO+0x20000,
117         .intr           = PHYSIO+0x20200,
118         .nand           = PHYSIO+0x10418,
119         .cesa           = PHYSIO+0x30000,       /* crypto accelerator */
120         .ehci           = PHYSIO+0x50000,
121         .spi            = PHYSIO+0x10600,
122         .twsi           = PHYSIO+0x11000,
123
124         .analog         = PHYSIO+0x1007c,
125         .pci            = PHYSIO+0x40000,
126         .pcibase        = PHYSIO+0x41800,
127
128         .rtc            = PHYSIO+0x10300,
129         .clock          = PHYSIO+0x20300,
130 //      .clockctl       = PHYSIO+0x1004c,       /* unused */
131
132         .ether          = { PHYSIO+0x72000, PHYSIO+0x76000, },
133         .sata           = { PHYSIO+0x80000,     /* sata config reg here */
134                         PHYSIO+0x82000,         /* edma config reg here */
135                         PHYSIO+0x84000,         /* edma config reg here */
136                         },
137         .uart           = { PHYSIO+0x12000, PHYSIO+0x12100, },
138         .gpio           = { PHYSIO+0x10100, PHYSIO+0x10140, },
139 };
140
141 /*
142  * sheeva/openrd u-boot leaves us with this address map:
143  *
144  * 0 targ 4 attr 0xe8 size 256MB addr 0x9::  remap addr 0x9::   pci mem
145  * 1 targ 1 attr 0x2f size   8MB addr 0xf9:: remap addr 0xf9::  nand flash
146  * 2 targ 4 attr 0xe0 size  16MB addr 0xf::  remap addr 0xc::   pci i/o
147  * 3 targ 1 attr 0x1e size  16MB addr 0xf8:: remap addr 0x0     spi flash
148  * 4 targ 1 attr 0x1d size  16MB addr 0xff::                    boot rom
149  * 5 targ 1 attr 0x1e size 128MB addr 0xe8::    disabled        spi flash
150  * 6 targ 1 attr 0x1d size 128MB addr 0xf::     disabled        boot rom
151  * 7 targ 3 attr 0x1  size  64K  addr 0xfb::                    crypto sram
152  */
153 #define WINTARG(ctl)    (((ctl) >> 4) & 017)
154 #define WINATTR(ctl)    (((ctl) >> 8) & 0377)
155 #define WIN64KSIZE(ctl) (((ctl) >> 16) + 1)
156
157 static void
158 praddrwin(Addrwin *win, int i)
159 {
160         ulong ctl, targ, attr, size64k;
161
162         if (!Debug) {
163                 USED(win, i);
164                 return;
165         }
166         ctl = win->ctl;
167         targ = WINTARG(ctl);
168         attr = WINATTR(ctl);
169         size64k = WIN64KSIZE(ctl);
170         print("cpu addr map: %s window %d: targ %ld attr %#lux size %,ld addr %#lux",
171                 ctl & Winenable? "enabled": "disabled", i, targ, attr,
172                 size64k * 64*1024, win->base);
173         if (i < 4)
174                 print(" remap addr %#llux", (uvlong)win->remaphi<<32 |
175                         win->remaplo);
176         print("\n");
177 }
178
179 static void
180 fixaddrmap(void)
181 {
182         int i;
183         ulong ctl, targ, attr, size64k;
184         Addrmap *map;
185         Addrwin *win;
186
187         map = (Addrmap *)soc.addrmap;
188         for (i = 0; i < nelem(map->win); i++) {
189                 win = &map->win[i];
190                 ctl = win->ctl;
191                 targ = WINTARG(ctl);
192                 attr = WINATTR(ctl);
193                 size64k = WIN64KSIZE(ctl);
194
195                 USED(attr, size64k);
196                 if (targ == Targcesasram) {
197                         win->ctl |= Winenable;
198                         win->base = PHYSCESASRAM;
199                         coherence();
200                         praddrwin(win, i);
201                 }
202         }
203         if (map->dirba != PHYSIO)
204                 panic("dirba not %#ux", PHYSIO);
205 }
206
207 static void
208 praddrmap(void)
209 {
210         int i;
211         Addrmap *map;
212
213         map = (Addrmap *)soc.addrmap;
214         for (i = 0; i < nelem(map->win); i++)
215                 praddrwin(&map->win[i], i);
216 }
217
218 int
219 ispow2(uvlong ul)
220 {
221         /* see Hacker's Delight if this isn't obvious */
222         return (ul & (ul - 1)) == 0;
223 }
224
225 /*
226  * return exponent of smallest power of 2 â‰¥ n
227  */
228 int
229 log2(ulong n)
230 {
231         int i;
232
233         i = 31 - clz(n);
234         if (!ispow2(n) || n == 0)
235                 i++;
236         return i;
237 }
238
239 void
240 cacheinfo(int level, int kind, Memcache *cp)            /* l1 only */
241 {
242         uint len, assoc, size;
243         ulong setsways;
244
245         /* get cache types & sizes (read-only reg) */
246         setsways = cprdsc(0, CpID, CpIDidct, CpIDct);
247
248         cp->level = level;
249         cp->kind = kind;
250
251         if ((setsways & (1<<24)) == 0)
252                 kind = Unified;
253         if (kind != Icache)
254                 setsways >>= 12;
255
256         assoc = (setsways >> 3) & MASK(3);
257         cp->nways = 1 << assoc;
258         size = (setsways >> 6) & MASK(4);
259         cp->size  = 1 << (size + 9);
260         len = setsways & MASK(2);
261         cp->log2linelen = len + 3;
262         cp->linelen = 1 << cp->log2linelen;
263         cp->setsways = setsways;
264
265         cp->nsets = 1 << (size + 6 - assoc - len);
266         cp->setsh = cp->log2linelen;
267         cp->waysh = 32 - log2(cp->nways);
268 }
269
270 static char *
271 wbtype(uint type)
272 {
273         static char *types[] = {
274                 "write-through",
275                 "read data block",
276                 "reg 7 ops, no lock-down",
277         [06]    "reg 7 ops, format A",
278         [07]    "reg 7 ops, format B deprecated",
279         [016]   "reg 7 ops, format C",
280         [05]    "reg 7 ops, format D",
281         };
282
283         if (type >= nelem(types) || types[type] == nil)
284                 return "GOK";
285         return types[type];
286 }
287
288 static void
289 prcache(Memcache *mcp)
290 {
291         int type;
292         char id;
293
294         if (mcp->kind == Unified)
295                 id = 'U';
296         else if (mcp->kind == Icache)
297                 id = 'I';
298         else if (mcp->kind == Dcache)
299                 id = 'D';
300         else
301                 id = '?';
302         print("l%d %c: %d bytes, %d ways %d sets %d bytes/line",
303                 mcp->level, id, mcp->size, mcp->nways, mcp->nsets,
304                 mcp->linelen);
305         if (mcp->linelen != CACHELINESZ)
306                 print(" *should* be %d", CACHELINESZ);
307         type = (mcp->setsways >> 25) & MASK(4);
308         if (type == 0)
309                 print("; write-through only");
310         else
311                 print("; write-back type `%s' (%#o) possible",
312                         wbtype(type), type);
313         if (mcp->setsways & (1<<11))
314                 print("; page table mapping restrictions apply");
315         if (mcp->setsways & (1<<2))
316                 print("; M bit is set in cache type reg");
317         print("\n");
318 }
319
320 static void
321 prcachecfg(void)
322 {
323         Memcache mc;
324
325         cacheinfo(1, Dcache, &mc);
326         prcache(&mc);
327         cacheinfo(1, Icache, &mc);
328         prcache(&mc);
329 }
330
331 void
332 l2cacheon(void)
333 {
334         ulong cfg;
335         CpucsReg *cpu;
336         L2uncache *l2p;
337
338         cacheuwbinv();
339         l2cacheuwbinv();
340         l1cachesoff();                  /* turns off L2 as a side effect */
341
342         cpwrsc(CpDef, CpCLD, 0, 0, 0);  /* GL-CPU-100: set D cache lockdown reg. */
343
344         /* marvell guideline GL-CPU-130 */
345         cpu = (CpucsReg *)soc.cpu;
346         cfg = cpu->cpucfg | L2exists | L2ecc | Cfgiprefetch | Cfgdprefetch;
347
348         if (L2writeback)
349                 cfg &= ~L2writethru;    /* see PTE Cached & Buffered bits */
350         else
351                 cfg |= L2writethru;
352         cpu->l2cfg = cfg;
353         coherence();                    /* force l2 cache to pay attention */
354         cpu->l2tm1 = cpu->l2tm0 = 0x66666666; /* marvell guideline GL-CPU-120 */
355         coherence();
356
357         cpwrsc(CpL2, CpTESTCFG, CpTCl2waylck, CpTCl2waylock, 0);
358
359         cachedinv();
360         l2cacheuinv();
361
362         /* disable l2 caching of i/o registers */
363         l2p = (L2uncache *)soc.l2cache;
364         memset(l2p, 0, sizeof *l2p);
365         /*
366          * l2: don't cache upper half of address space.
367          * the L2 cache is PIPT, so the addresses are physical.
368          */
369         l2p->win[0].base = 0x80000000 | L2enable;       /* 64K multiple */
370         l2p->win[0].size = (32*1024-1) << 16;           /* 64K multiples */
371         coherence();
372
373         l2cachecfgon();
374         l1cacheson();                   /* turns L2 on as a side effect */
375         print("l2 cache: 256K or 512K: 4 ways, 32-byte lines, write-%s, sdram only\n",
376                 cpu->l2cfg & L2writethru? "through": "back");
377 }
378
379 /* called late in main */
380 void
381 archconfinit(void)
382 {
383         m->cpuhz = Frequency;
384         m->delayloop = m->cpuhz/2000;    /* initial estimate */
385         fixaddrmap();
386         if (Debug)
387                 praddrmap();
388         prcachecfg();
389
390         l2cacheon();
391 }
392
393 void
394 archkwlink(void)
395 {
396 }
397
398 /* LED/USB gpios */
399 enum {
400         /*
401          * the bit assignments are MPP pin numbers from the last page of the
402          * sheevaplug 6.0.1 schematic.
403          */
404         KWOEValHigh     = 1<<(49-32),   /* pin 49: LED pin */
405         KWOEValLow      = 1<<29,        /* pin 29: USB_PWEN, pin 28: usb_pwerr */
406         KWOELow         = ~0,
407         KWOEHigh        = ~0,
408 };
409
410 /* called early in main */
411 void
412 archreset(void)
413 {
414         ulong clocks;
415         CpucsReg *cpu;
416         Dramctl *dram;
417         GpioReg *gpio;
418
419         clockshutdown();                /* watchdog disabled */
420
421         /* configure gpios */
422         gpio = (GpioReg*)soc.gpio[0];
423         gpio->dataout = KWOEValLow;
424         coherence();
425         gpio->dataoutena = KWOELow;
426
427         gpio = (GpioReg*)soc.gpio[1];
428         gpio->dataout = KWOEValHigh;
429         coherence();
430         gpio->dataoutena = KWOEHigh;
431         coherence();
432
433         cpu = (CpucsReg *)soc.cpu;
434         cpu->mempm = 0;                 /* turn everything on */
435         coherence();
436
437         clocks = MASK(10);
438         clocks |= MASK(21) & ~MASK(14);
439         clocks &= ~(1<<18 | 1<<1);      /* reserved bits */
440         cpu->clockgate |= clocks;       /* enable all the clocks */
441         cpu->l2cfg |= L2exists;         /* when L2exists is 0, the l2 ignores us */
442         coherence();
443
444         dram = (Dramctl *)soc.sdramc;
445         dram->ddrctllo &= ~(1<<6);      /* marvell guideline GL-MEM-70 */
446
447         *(ulong *)soc.analog = 0x68;    /* marvell guideline GL-MISC-40 */
448         coherence();
449 }
450
451 void
452 archreboot(void)
453 {
454         CpucsReg *cpu;
455
456         iprint("reset!\n");
457         delay(10);
458
459         cpu = (CpucsReg *)soc.cpu;
460         cpu->rstout = RstoutSoft;
461         cpu->softreset = ResetSystem;
462         coherence();
463         cpu->cpucsr = Reset;
464         coherence();
465         delay(500);
466
467         splhi();
468         iprint("waiting...");
469         for(;;)
470                 idlehands();
471 }
472
473 void
474 archconsole(void)
475 {
476 //      uartconsole(0, "b115200");
477 //serialputs("uart0 console @ 115200\n", strlen("uart0 console @ 115200\n"));
478 }
479
480 void
481 archflashwp(Flash*, int)
482 {
483 }
484
485 int     flashat(Flash *f, uintptr pa);
486
487 /*
488  * for ../port/devflash.c:/^flashreset
489  * retrieve flash type, virtual base and length and return 0;
490  * return -1 on error (no flash)
491  */
492 int
493 archflashreset(int bank, Flash *f)
494 {
495         if(bank != 0)
496                 return -1;
497         f->type = "nand";
498         if (flashat(f, PHYSNAND1))
499                 f->addr = (void*)PHYSNAND1;
500         else if (flashat(f, PHYSNAND2))
501                 f->addr = (void*)PHYSNAND2;
502         else
503                 f->addr = nil;
504         f->size = 0;            /* done by probe */
505         f->width = 1;
506         f->interleave = 0;
507         return 0;
508 }