]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/teg2/archtegra.c
kernel: do not pull in atom.s from libc for arm kernels
[plan9front.git] / sys / src / 9 / teg2 / archtegra.c
1 /*
2  * nvidia tegra 2 architecture-specific stuff
3  */
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 #include "arm.h"
13
14 #include "../port/netif.h"
15 #include "etherif.h"
16 #include "../port/flashif.h"
17 #include "../port/usb.h"
18 #include "../port/portusbehci.h"
19 #include "usbehci.h"
20
21 enum {
22         /* hardware limits imposed by register contents or layouts */
23         Maxcpus         = 4,
24         Maxflowcpus     = 2,
25
26         Debug   = 0,
27 };
28
29 typedef struct Clkrst Clkrst;
30 typedef struct Diag Diag;
31 typedef struct Flow Flow;
32 typedef struct Scu Scu;
33 typedef struct Power Power;
34
35 struct Clkrst {
36         ulong   rstsrc;
37         ulong   rstdevl;
38         ulong   rstdevh;
39         ulong   rstdevu;
40
41         ulong   clkoutl;
42         ulong   clkouth;
43         ulong   clkoutu;
44
45         uchar   _pad0[0x24-0x1c];
46         ulong   supcclkdiv;             /* super cclk divider */
47         ulong   _pad1;
48         ulong   supsclkdiv;             /* super sclk divider */
49
50         uchar   _pad4[0x4c-0x30];
51         ulong   clkcpu;
52
53         uchar   _pad1[0xe0-0x50];
54         ulong   pllxbase;               /* pllx controls CPU clock speed */
55         ulong   pllxmisc;
56         ulong   pllebase;               /* plle is dedicated to pcie */
57         ulong   pllemisc;
58
59         uchar   _pad2[0x340-0xf0];
60         ulong   cpuset;
61         ulong   cpuclr;
62 };
63
64 enum {
65         /* rstsrc bits */
66         Wdcpurst =      1<<0,
67         Wdcoprst =      1<<1,
68         Wdsysrst =      1<<2,
69         Wdsel =         1<<4,           /* tmr1 or tmr2? */
70         Wdena =         1<<5,
71
72         /* devl bits */
73         Sysreset =      1<<2,
74
75         /* clkcpu bits */
76         Cpu1stop =      1<<9,
77         Cpu0stop =      1<<8,
78
79         /* cpu* bits */
80         Cpu1dbgreset =  1<<13,
81         Cpu0dbgreset =  1<<12,
82         Cpu1wdreset =   1<<9,
83         Cpu0wdreset =   1<<8,
84         Cpu1dereset =   1<<5,
85         Cpu0dereset =   1<<4,
86         Cpu1reset =     1<<1,
87         Cpu0reset =     1<<0,
88 };
89
90 struct Power {
91         ulong   ctl;                    /* mainly for rtc clock signals */
92         ulong   secregdis;
93         ulong   swrst;
94
95         ulong   wakevmask;
96         ulong   waklvl;
97         ulong   waksts;
98         ulong   swwaksts;
99
100         ulong   dpdpadsovr;             /* deep power down pads override */
101         ulong   dpdsample;
102         ulong   dpden;
103
104         ulong   gatetimroff;
105         ulong   gatetimron;
106         ulong   toggle;
107         ulong   unclamp;
108         ulong   gatests;                /* ro */
109
110         ulong   goodtmr;
111         ulong   blinktmr;
112
113         ulong   noiopwr;
114         ulong   detect;
115         ulong   detlatch;
116
117         ulong   scratch[24];
118         ulong   secscratch[6];
119
120         ulong   cpupwrgoodtmr;
121         ulong   cpupwrofftmr;
122
123         ulong   pgmask[2];
124
125         ulong   autowaklvl;
126         ulong   autowaklvlmask;
127         ulong   wakdelay;
128
129         ulong   detval;
130         ulong   ddr;
131         ulong   usbdebdel;      /* usb de-bounce delay */
132         ulong   usbao;
133         ulong   cryptoop;
134         ulong   pllpwb0ovr;
135         ulong   scratch24[42-24+1];
136         ulong   boundoutmirr[3];
137         ulong   sys33ven;
138         ulong   boundoutmirracc;
139         ulong   gate;
140 };
141
142 enum {
143         /* toggle bits */
144         Start   = 1<<8,
145         /* partition ids */
146         Partpcie= 3,
147         Partl2  = 4,
148 };
149
150 struct Scu {
151         ulong   ctl;
152         ulong   cfg;                    /* ro */
153         ulong   cpupwrsts;
154         ulong   inval;
155
156         uchar   _pad0[0x40-0x10];
157         ulong   filtstart;
158         ulong   filtend;
159
160         uchar   _pad1[0x50-0x48];
161         ulong   accctl;                 /* initially 0 */
162         ulong   nsaccctl;
163 };
164
165 enum {
166         /* ctl bits */
167         Scuenable =     1<<0,
168         Filter =        1<<1,
169         Scuparity =     1<<2,
170         Specfill =      1<<3,           /* only for PL310 */
171         Allport0 =      1<<4,
172         Standby =       1<<5,
173         Icstandby =     1<<6,
174 };
175
176 struct Flow {
177         ulong   haltcpu0;
178         ulong   haltcop;
179         ulong   cpu0;
180         ulong   cop;
181         ulong   xrq;
182         ulong   haltcpu1;
183         ulong   cpu1;
184 };
185
186 enum {
187         /* haltcpu* bits */
188         Stop =  2<<29,
189
190         /* cpu* bits */
191         Event =                 1<<14,  /* w1c */
192         Waitwfebitsshift =      4,
193         Waitwfebitsmask =       MASK(2),
194         Eventenable =           1<<1,
195         Cpuenable =             1<<0,
196 };
197
198 struct Diag {
199         Cacheline c0;
200         Lock;
201         Ref     cnt;
202         Ref     sync;
203         Cacheline c1;
204 };
205
206 extern ulong testmem;
207
208 /*
209  * number of cpus available.  contrast with conf.nmach, which is number
210  * of running cpus.
211  */
212 int navailcpus;
213 Isolated l1ptstable;
214
215 Soc soc = {
216         .clkrst = 0x60006000,           /* clock & reset signals */
217         .power  = 0x7000e400,
218         .exceptvec = PHYSEVP,           /* undocumented magic */
219         .sema   = 0x60001000,
220         .l2cache= PHYSL2BAG,            /* pl310 bag on the side */
221         .flow   = 0x60007000,
222
223         /* 4 non-gic controllers */
224 //      .intr   = { 0x60004000, 0x60004100, 0x60004200, 0x60004300, },
225
226         /* private memory region */
227         .scu    = 0x50040000,
228         /* we got this address from the `cortex-a series programmer's guide'. */
229         .intr   = 0x50040100,           /* per-cpu interface */
230         .glbtmr = 0x50040200,
231         .loctmr = 0x50040600,
232         .intrdist=0x50041000,
233
234         .uart   = { 0x70006000, 0x70006040,
235                     0x70006200, 0x70006300, 0x70006400, },
236
237         .rtc    = 0x7000e000,
238         .tmr    = { 0x60005000, 0x60005008, 0x60005050, 0x60005058, },
239         .µs    = 0x60005010,
240
241         .pci    = 0x80000000,
242         .ether  = 0xa0024000,
243
244         .nand   = 0x70008000,
245         .nor    = 0x70009000,           /* also VIRTNOR */
246
247         .ehci   = P2VAHB(0xc5000000),   /* 1st of 3 */
248         .ide    = P2VAHB(0xc3000000),
249
250         .gpio   = { 0x6000d000, 0x6000d080, 0x6000d100, 0x6000d180,
251                             0x6000d200, 0x6000d280, 0x6000d300, },
252         .spi    = { 0x7000d400, 0x7000d600, 0x7000d800, 0x7000da00, },
253         .twsi   = 0x7000c000,
254         .mmc    = { P2VAHB(0xc8000000), P2VAHB(0xc8000200),
255                     P2VAHB(0xc8000400), P2VAHB(0xc8000600), },
256 };
257
258 static volatile Diag diag;
259 static int missed;
260
261 void
262 dumpcpuclks(void)               /* run CPU at full speed */
263 {
264         Clkrst *clk = (Clkrst *)soc.clkrst;
265
266         iprint("pllx base %#lux misc %#lux\n", clk->pllxbase, clk->pllxmisc);
267         iprint("plle base %#lux misc %#lux\n", clk->pllebase, clk->pllemisc);
268         iprint("super cclk divider %#lux\n", clk->supcclkdiv);
269         iprint("super sclk divider %#lux\n", clk->supsclkdiv);
270 }
271
272 static char *
273 devidstr(ulong)
274 {
275         return "ARM Cortex-A9";
276 }
277
278 void
279 archtegralink(void)
280 {
281 }
282
283 /* convert AddrDevid register to a string in buf and return buf */
284 char *
285 cputype2name(char *buf, int size)
286 {
287         ulong r;
288
289         r = cpidget();                  /* main id register */
290         assert((r >> 24) == 'A');
291         seprint(buf, buf + size, "Cortex-A9 r%ldp%ld",
292                 (r >> 20) & MASK(4), r & MASK(4));
293         return buf;
294 }
295
296 static void
297 errata(void)
298 {
299         ulong reg, r, p;
300
301         /* apply cortex-a9 errata workarounds */
302         r = cpidget();                  /* main id register */
303         assert((r >> 24) == 'A');
304         p = r & MASK(4);                /* minor revision */
305         r >>= 20;
306         r &= MASK(4);                   /* major revision */
307
308         /* this is an undocumented `diagnostic register' that linux knows */
309         reg = cprdsc(0, CpDTLB, 0, 1);
310         if (r < 2 || r == 2 && p <= 2)
311                 reg |= 1<<4;                    /* 742230 */
312         if (r == 2 && p <= 2)
313                 reg |= 1<<6 | 1<<12 | 1<<22;    /* 743622, 2×742231 */
314         if (r < 3)
315                 reg |= 1<<11;                   /* 751472 */
316         cpwrsc(0, CpDTLB, 0, 1, reg);
317 }
318
319 void
320 archconfinit(void)
321 {
322         char *p;
323         ulong hz;
324
325         assert(m != nil);
326         m->cpuhz = 1000 * Mhz;                  /* trimslice speed */
327         p = getconf("*cpumhz");
328         if (p) {
329                 hz = atoi(p) * Mhz;
330                 if (hz >= 100*Mhz && hz <= 3600UL*Mhz)
331                         m->cpuhz = hz;
332         }
333         m->delayloop = m->cpuhz/2000;           /* initial estimate */
334         errata();
335 }
336
337 int
338 archether(unsigned ctlrno, Ether *ether)
339 {
340         switch(ctlrno) {
341         case 0:
342                 ether->type = "rtl8169";                /* pci-e ether */
343                 ether->ctlrno = ctlrno;
344                 ether->irq = Pcieirq;                   /* non-msi pci-e intr */
345                 ether->nopt = 0;
346                 ether->mbps = 1000;
347                 return 1;
348         }
349         return -1;
350 }
351
352 void
353 dumpscustate(void)
354 {
355         Scu *scu = (Scu *)soc.scu;
356
357         print("cpu%d scu: accctl %#lux\n", m->machno, scu->accctl);
358         print("cpu%d scu: smp cpu bit map %#lo for %ld cpus; ", m->machno,
359                 (scu->cfg >> 4) & MASK(4), (scu->cfg & MASK(2)) + 1);
360         print("cpus' power %#lux\n", scu->cpupwrsts);
361 }
362
363 void
364 scuon(void)
365 {
366         Scu *scu = (Scu *)soc.scu;
367
368         if (scu->ctl & Scuenable)
369                 return;
370         scu->inval = MASK(16);
371         coherence();
372         scu->ctl = Scuparity | Scuenable | Specfill;
373         coherence();
374 }
375
376 int
377 getncpus(void)
378 {
379         int n;
380         char *p;
381         Scu *scu;
382
383         if (navailcpus == 0) {
384                 scu = (Scu *)soc.scu;
385                 navailcpus = (scu->cfg & MASK(2)) + 1;
386                 if (navailcpus > MAXMACH)
387                         navailcpus = MAXMACH;
388
389                 p = getconf("*ncpu");
390                 if (p && *p) {
391                         n = atoi(p);
392                         if (n > 0 && n < navailcpus)
393                                 navailcpus = n;
394                 }
395         }
396         return navailcpus;
397 }
398
399 void
400 cpuidprint(void)
401 {
402         char name[64];
403
404         cputype2name(name, sizeof name);
405         delay(50);                              /* let uart catch up */
406         iprint("cpu%d: %lldMHz ARM %s %s-endian\n",
407                 m->machno, m->cpuhz / Mhz, name,
408                 getpsr() & PsrBigend? "big": "little");
409 }
410
411 static void
412 clockson(void)
413 {
414         Clkrst *clk = (Clkrst *)soc.clkrst;
415
416         /* enable all by clearing resets */
417         clk->rstdevl = clk->rstdevh = clk->rstdevu = 0;
418         coherence();
419         clk->clkoutl = clk->clkouth = clk->clkoutu = ~0; /* enable all clocks */
420         coherence();
421
422         clk->rstsrc = Wdcpurst | Wdcoprst | Wdsysrst | Wdena;
423         coherence();
424 }
425
426 /* we could be shutting down ourself (if cpu == m->machno), so take care. */
427 void
428 stopcpu(uint cpu)
429 {
430         Flow *flow = (Flow *)soc.flow;
431         Clkrst *clk = (Clkrst *)soc.clkrst;
432
433         if (cpu == 0) {
434                 iprint("stopcpu: may not stop cpu0\n");
435                 return;
436         }
437
438         machoff(cpu);
439         lock(&active);
440         active.stopped |= 1 << cpu;
441         unlock(&active);
442         l1cache->wb();
443
444         /* shut down arm7 avp coproc so it can't cause mischief. */
445         /* could try watchdog without stopping avp. */
446         flow->haltcop = Stop;
447         coherence();
448         flow->cop = 0;                                  /* no Cpuenable */
449         coherence();
450         delay(10);
451
452         assert(cpu < Maxflowcpus);
453         *(cpu == 0? &flow->haltcpu0: &flow->haltcpu1) = Stop;
454         coherence();
455         *(cpu == 0? &flow->cpu0: &flow->cpu1) = 0;      /* no Cpuenable */
456         coherence();
457         delay(10);
458
459         /* cold reset */
460         assert(cpu < Maxcpus);
461         clk->cpuset = (Cpu0reset | Cpu0dbgreset | Cpu0dereset) << cpu;
462         coherence();
463         delay(1);
464
465         l1cache->wb();
466 }
467
468 static void
469 synccpus(Ref *cntp, int n)
470 {
471         incref(cntp);
472         while (cntp->ref < n)
473                 ;
474         /* all cpus should now be here */
475 }
476
477 static void
478 pass1(int pass, volatile Diag *dp)
479 {
480         int i;
481
482         if(m->machno == 0)
483                 iprint(" %d", pass);
484         for (i = 1000*1000; --i > 0; ) {
485                 incref(&dp->cnt);
486                 incref(&dp->cnt);
487         }
488
489         synccpus(&dp->sync, navailcpus);
490         /* all cpus are now here */
491
492         ilock(dp);
493         if(dp->cnt.ref != 0)
494                 panic("cpu%d: diag: failed w count %ld", m->machno, dp->cnt.ref);
495         iunlock(dp);
496
497         synccpus(&dp->sync, 2 * navailcpus);
498         /* all cpus are now here */
499         decref(&dp->sync);
500         decref(&dp->sync);
501 }
502
503 /*
504  * try to confirm coherence of l1 caches.
505  * assume that all available cpus will be started.
506  */
507 void
508 l1diag(void)
509 {
510         int pass;
511         volatile Diag *dp;
512
513         if (!Debug)
514                 return;
515
516         l1cache->wb();
517
518         /*
519          * synchronise and print
520          */
521         dp = &diag;
522         ilock(dp);
523         if (m->machno == 0)
524                 iprint("l1: waiting for %d cpus... ", navailcpus);
525         iunlock(dp);
526
527         synccpus(&dp->sync, navailcpus);
528
529         ilock(dp);
530         if (m->machno == 0)
531                 iprint("cache coherency pass");
532         iunlock(dp);
533
534         synccpus(&dp->sync, 2 * navailcpus);
535         decref(&dp->sync);
536         decref(&dp->sync);
537
538         /*
539          * cpus contend
540          */
541         for (pass = 0; pass < 3; pass++)
542                 pass1(pass, dp);
543
544         /*
545          * synchronise and check sanity
546          */
547         synccpus(&dp->sync, navailcpus);
548
549         if(dp->sync.ref < navailcpus || dp->sync.ref >= 2 * navailcpus)
550                 panic("cpu%d: diag: failed w dp->sync %ld", m->machno,
551                         dp->sync.ref);
552         if(dp->cnt.ref != 0)
553                 panic("cpu%d: diag: failed w dp->cnt %ld", m->machno,
554                         dp->cnt.ref);
555
556         ilock(dp);
557         iprint(" cpu%d ok", m->machno);
558         iunlock(dp);
559
560         synccpus(&dp->sync, 2 * navailcpus);
561         decref(&dp->sync);
562         decref(&dp->sync);
563         l1cache->wb();
564
565         /*
566          * all done, print
567          */
568         ilock(dp);
569         if (m->machno == 0)
570                 iprint("\n");
571         iunlock(dp);
572 }
573
574 static void
575 unfreeze(uint cpu)
576 {
577         Clkrst *clk = (Clkrst *)soc.clkrst;
578         Flow *flow = (Flow *)soc.flow;
579
580         assert(cpu < Maxcpus);
581
582         clk->clkcpu &= ~(Cpu0stop << cpu);
583         coherence();
584         /* out of reset */
585         clk->cpuclr = (Cpu0reset | Cpu0wdreset | Cpu0dbgreset | Cpu0dereset) <<
586                 cpu;
587         coherence();
588
589         assert(cpu < Maxflowcpus);
590         *(cpu == 0? &flow->cpu0: &flow->cpu1) = 0;
591         coherence();
592         *(cpu == 0? &flow->haltcpu0: &flow->haltcpu1) = 0; /* normal operat'n */
593         coherence();
594 }
595
596 /*
597  * this is all a bit magic.  the soc.exceptvec register is effectively
598  * undocumented.  we had to look at linux and experiment, alas.  this is the
599  * sort of thing that should be standardised as part of the cortex mpcore spec.
600  * even intel document their equivalent procedure.
601  */
602 int
603 startcpu(uint cpu)
604 {
605         int i, r;
606         ulong oldvec, rstaddr;
607         ulong *evp = (ulong *)soc.exceptvec;    /* magic */
608
609         r = 0;
610         if (getncpus() < 2 || cpu == m->machno ||
611             cpu >= MAXMACH || cpu >= navailcpus)
612                 return -1;
613
614         oldvec = *evp;
615         l1cache->wb();                  /* start next cpu w same view of ram */
616         *evp = rstaddr = PADDR(_vrst);  /* will start cpu executing at _vrst */
617         coherence();
618         l1cache->wb();
619         unfreeze(cpu);
620
621         for (i = 2000; i > 0 && *evp == rstaddr; i--)
622                 delay(1);
623         if (i <= 0 || *evp != cpu) {
624                 iprint("cpu%d: didn't start!\n", cpu);
625                 stopcpu(cpu);           /* make sure it's stopped */
626                 r = -1;
627         }
628         *evp = oldvec;
629         return r;
630 }
631
632 static void
633 cksecure(void)
634 {
635         ulong db;
636         extern ulong getdebug(void);
637
638         if (getscr() & 1)
639                 panic("cpu%d: running non-secure", m->machno);
640         db = getdebug();
641         if (db)
642                 iprint("cpu%d: debug enable reg %#lux\n", m->machno, db);
643 }
644
645 ulong
646 smpon(void)
647 {
648         ulong aux;
649
650         /* cortex-a9 model-specific configuration */
651         aux = getauxctl();
652         putauxctl(aux | CpACsmp | CpACmaintbcast);
653         return aux;
654 }
655
656 void
657 cortexa9cachecfg(void)
658 {
659         /* cortex-a9 model-specific configuration */
660         putauxctl(getauxctl() | CpACparity | CpAClwr0line | CpACl2pref);
661 }
662
663 /*
664  * called on a cpu other than 0 from cpureset in l.s,
665  * from _vrst in lexception.s.
666  * mmu and l1 (and system-wide l2) caches and coherency (smpon) are on,
667  * but interrupts are disabled.
668  * our mmu is using an exact copy of cpu0's l1 page table
669  * as it was after userinit ran.
670  */
671 void
672 cpustart(void)
673 {
674         int ms;
675         ulong *evp;
676         Power *pwr;
677
678         up = nil;
679         if (active.machs & (1<<m->machno)) {
680                 serialputc('?');
681                 serialputc('r');
682                 panic("cpu%d: resetting after start", m->machno);
683         }
684         assert(m->machno != 0);
685
686         errata();
687         cortexa9cachecfg();
688         memdiag(&testmem);
689
690         machinit();                     /* bumps nmach, adds bit to machs */
691         machoff(m->machno);             /* not ready to go yet */
692
693         /* clock signals and scu are system-wide and already on */
694         clockshutdown();                /* kill any watch-dog timer */
695
696         trapinit();
697         clockinit();                    /* sets loop delay */
698         timersinit();
699         cpuidprint();
700
701         /*
702          * notify cpu0 that we're up so it can proceed to l1diag.
703          */
704         evp = (ulong *)soc.exceptvec;   /* magic */
705         *evp = m->machno;
706         coherence();
707
708         l1diag();               /* contend with other cpus to verify sanity */
709
710         /*
711          * pwr->noiopwr == 0
712          * pwr->detect == 0x1ff (default, all disabled)
713          */
714         pwr = (Power *)soc.power;
715         assert(pwr->gatests == MASK(7)); /* everything has power */
716
717         /*
718          * 8169 has to initialise before we get past this, thus cpu0
719          * has to schedule processes first.
720          */
721         if (Debug)
722                 iprint("cpu%d: waiting for 8169\n", m->machno);
723         for (ms = 0; !l1ptstable.word && ms < 5000; ms += 10) {
724                 delay(10);
725                 cachedinvse(&l1ptstable.word, sizeof l1ptstable.word);
726         }
727         if (!l1ptstable.word)
728                 iprint("cpu%d: 8169 unreasonably slow; proceeding\n", m->machno);
729         /* now safe to copy cpu0's l1 pt in mmuinit */
730
731         mmuinit();                      /* update our l1 pt from cpu0's */
732         fpon();
733         machon(m->machno);              /* now ready to go and be scheduled */
734
735         if (Debug)
736                 iprint("cpu%d: scheding\n", m->machno);
737         schedinit();
738         panic("cpu%d: schedinit returned", m->machno);
739 }
740
741 /* mainly used to break out of wfi */
742 void
743 sgintr(Ureg *ureg, void *)
744 {
745         iprint("cpu%d: got sgi\n", m->machno);
746         /* try to prod cpu1 into life when it gets stuck */
747         if (m->machno != 0)
748                 clockprod(ureg);
749 }
750
751 void
752 archreset(void)
753 {
754         static int beenhere;
755
756         if (beenhere)
757                 return;
758         beenhere = 1;
759
760         /* conservative temporary values until archconfinit runs */
761         m->cpuhz = 1000 * Mhz;                  /* trimslice speed */
762         m->delayloop = m->cpuhz/2000;           /* initial estimate */
763
764         prcachecfg();
765
766         clockson();
767         /* all partitions were powered up by u-boot, so needn't do anything */
768         archconfinit();
769 //      resetusb();
770         fpon();
771
772         if (irqtooearly)
773                 panic("archreset: too early for irqenable");
774         irqenable(Cpu0irq, sgintr, nil, "cpu0");
775         irqenable(Cpu1irq, sgintr, nil, "cpu1");
776         /* ... */
777 }
778
779 void
780 archreboot(void)
781 {
782         Clkrst *clk = (Clkrst *)soc.clkrst;
783
784         assert(m->machno == 0);
785         iprint("archreboot: reset!\n");
786         delay(20);
787
788         clk->rstdevl |= Sysreset;
789         coherence();
790         delay(500);
791
792         /* shouldn't get here */
793         splhi();
794         iprint("awaiting reset");
795         for(;;) {
796                 delay(1000);
797                 print(".");
798         }
799 }
800
801 void
802 kbdinit(void)
803 {
804 }
805
806 static void
807 missing(ulong addr, char *name)
808 {
809         static int firstmiss = 1;
810
811         if (addr == 0) {
812                 iprint("address zero for %s\n", name);
813                 return;
814         }
815         if (probeaddr(addr) >= 0)
816                 return;
817         missed++;
818         if (firstmiss) {
819                 iprint("missing:");
820                 firstmiss = 0;
821         } else
822                 iprint(",\n\t");
823         iprint(" %s at %#lux", name, addr);
824 }
825
826 /* verify that all the necessary device registers are accessible */
827 void
828 chkmissing(void)
829 {
830         delay(10);
831         missing(KZERO, "dram");
832         missing(soc.intr, "intr ctlr");
833         missing(soc.intrdist, "intr distrib");
834         missing(soc.tmr[0], "tegra timer1");
835         missing(soc.uart[0], "console uart");
836         missing(soc.pci, "pcie");
837         missing(soc.ether, "ether8169");
838         missing(soc.µs, "µs counter");
839         if (missed)
840                 iprint("\n");
841         delay(10);
842 }
843
844 void
845 archflashwp(Flash*, int)
846 {
847 }
848
849 /*
850  * for ../port/devflash.c:/^flashreset
851  * retrieve flash type, virtual base and length and return 0;
852  * return -1 on error (no flash)
853  */
854 int
855 archflashreset(int bank, Flash *f)
856 {
857         if(bank != 0)
858                 return -1;
859 panic("archflashreset: rewrite for nor & nand flash on ts");
860         /*
861          * this is set up for the igepv2 board.
862          */
863         f->type = "onenand";
864         f->addr = (void*)VIRTNOR;               /* mapped here by archreset */
865         f->size = 0;                            /* done by probe */
866         f->width = 1;
867         f->interleave = 0;
868         return 0;
869 }