]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/m8260.c
merge
[plan9front.git] / sys / src / 9 / ppc / m8260.c
1 /*
2  *      8260 specific stuff:
3  *              Interrupt handling
4  */
5 #include        "u.h"
6 #include        "../port/lib.h"
7 #include        "mem.h"
8 #include        "dat.h"
9 #include        "io.h"
10 #include        "fns.h"
11 #include        "m8260.h"
12
13 enum {
14         Pin4 = BIT(4),
15 };
16
17 static union {
18         struct {
19                 ulong   hi;
20                 ulong   lo;
21         };
22         uvlong          val;
23 } ticks;
24
25 struct {
26         ulong   hi;
27         ulong   lo;
28 } vec2mask[64]  = {
29 [0]     = {0,           0       },      /* Error, No interrupt */
30 [1]     = {0,           BIT(16) },      /* I2C */
31 [2]     = {0,           BIT(17) },      /* SPI */
32 [3]     = {0,           BIT(18) },      /* Risc Timers */
33 [4]     = {0,           BIT(19) },      /* SMC1 */
34 [5]     = {0,           BIT(20) },      /* SMC2 */
35 [6]     = {0,           BIT(21) },      /* IDMA1 */
36 [7]     = {0,           BIT(22) },      /* IDMA2 */
37 [8]     = {0,           BIT(23) },      /* IDMA3 */
38 [9]     = {0,           BIT(24) },      /* IDMA4 */
39 [10]    = {0,           BIT(25) },      /* SDMA */
40 [11]    = {0,           0       },      /* Reserved */
41 [12]    = {0,           BIT(27) },      /* Timer1 */
42 [13]    = {0,           BIT(28) },      /* Timer2 */
43 [14]    = {0,           BIT(29) },      /* Timer3 */
44 [15]    = {0,           BIT(30) },      /* Timer4 */
45
46 [16]    = {BIT(29),     0       },      /* TMCNT */
47 [17]    = {BIT(30),     0       },      /* PIT */
48 [18]    = {0,           0       },      /* Reserved */
49 [19]    = {BIT(17),     0       },      /* IRQ1 */
50 [20]    = {BIT(18),     0       },      /* IRQ2 */
51 [21]    = {BIT(19),     0       },      /* IRQ3 */
52 [22]    = {BIT(20),     0       },      /* IRQ4 */
53 [23]    = {BIT(21),     0       },      /* IRQ5 */
54 [24]    = {BIT(22),     0       },      /* IRQ6 */
55 [25]    = {BIT(23),     0       },      /* IRQ7 */
56 [26]    = {0,           0       },      /* Reserved */
57 [27]    = {0,           0       },      /* Reserved */
58 [28]    = {0,           0       },      /* Reserved */
59 [29]    = {0,           0       },      /* Reserved */
60 [30]    = {0,           0       },      /* Reserved */
61 [31]    = {0,           0       },      /* Reserved */
62
63 [32]    = {0,           BIT(0)  },      /* FCC1 */
64 [33]    = {0,           BIT(1)  },      /* FCC2 */
65 [34]    = {0,           BIT(2)  },      /* FCC3 */
66 [35]    = {0,           0       },      /* Reserved */
67 [36]    = {0,           BIT(4)  },      /* MCC1 */
68 [37]    = {0,           BIT(5)  },      /* MCC2 */
69 [38]    = {0,           0       },      /* Reserved */
70 [39]    = {0,           0       },      /* Reserved */
71 [40]    = {0,           BIT(8)  },      /* SCC1 */
72 [41]    = {0,           BIT(9)  },      /* SCC2 */
73 [42]    = {0,           BIT(10) },      /* SCC3 */
74 [43]    = {0,           BIT(11) },      /* SCC4 */
75 [44]    = {0,           0       },      /* Reserved */
76 [45]    = {0,           0       },      /* Reserved */
77 [46]    = {0,           0       },      /* Reserved */
78 [47]    = {0,           0       },      /* Reserved */
79
80 [48]    = {BIT(15),     0       },      /* PC15 */
81 [49]    = {BIT(14),     0       },      /* PC14 */
82 [50]    = {BIT(13),     0       },      /* PC13 */
83 [51]    = {BIT(12),     0       },      /* PC12 */
84 [52]    = {BIT(11),     0       },      /* PC11 */
85 [53]    = {BIT(10),     0       },      /* PC10 */
86 [54]    = {BIT(9),      0       },      /* PC9 */
87 [55]    = {BIT(8),      0       },      /* PC8 */
88 [56]    = {BIT(7),      0       },      /* PC7 */
89 [57]    = {BIT(6),      0       },      /* PC6 */
90 [58]    = {BIT(5),      0       },      /* PC5 */
91 [59]    = {BIT(4),      0       },      /* PC4 */
92 [60]    = {BIT(3),      0       },      /* PC3 */
93 [61]    = {BIT(2),      0       },      /* PC2 */
94 [62]    = {BIT(1),      0       },      /* PC1 */
95 [63]    = {BIT(0),      0       },      /* PC0 */
96 };
97
98 /* Blast memory layout:
99  *      CS0: FE000000 -> FFFFFFFF (Flash)
100  *      CS1: FC000000 -> FCFFFFFF (DSP hpi)
101  *      CS2: 00000000 -> 03FFFFFF (60x sdram)
102  *      CS3: 04000000 -> 04FFFFFF (FPGA)
103  *      CS4: 05000000 -> 06FFFFFF (local bus sdram)
104  *      CS5: 07000000 -> 0700FFFF (eeprom - not populated)
105  *      CS6: E0000000 -> E0FFFFFF (FPGA - 64bits)
106  *
107  * Main Board memory layout:
108  *      CS0: FE000000 -> FEFFFFFF (16 M FLASH)
109  *      CS1: FC000000 -> FCFFFFFF (16 M DSP1)
110  *      CS2: 00000000 -> 03FFFFFF (64 M SDRAM)
111  *      CS3: 04000000 -> 04FFFFFF (16M DSP2)
112  *      CS4: 05000000 -> 06FFFFFF (32 M Local SDRAM)
113  *      CS5: 07000000 -> 0700FFFF (eeprom - not populated)
114  *      CS6: unused
115  *      CS7: E0000000 -> E0FFFFFF (16 M FPGA)
116  */
117
118 IMM* iomem = (IMM*)IOMEM;
119
120 static Lock cpmlock;
121
122 void
123 machinit(void)
124 {
125         ulong scmr;
126         int pllmf;
127         extern char* plan9inistr;
128
129         memset(m, 0, sizeof(*m));
130         m->cputype = getpvr()>>16;      /* pvr = 0x00810101 for the 8260 */
131         m->imap = (Imap*)INTMEM;
132
133         m->loopconst = 1096;
134
135         /* Make sure Ethernet is disabled (boot code may have buffers allocated anywhere in memory) */
136         iomem->fcc[0].gfmr &= ~(BIT(27)|BIT(26));
137         iomem->fcc[1].gfmr &= ~(BIT(27)|BIT(26));
138         iomem->fcc[2].gfmr &= ~(BIT(27)|BIT(26));
139
140         /* Flashed CS configuration is wrong for DSP2.  It's set to 64 bits, should be 16 */
141         iomem->bank[3].br = 0x04001001; /* Set 16-bit port */
142
143         /*
144          * FPGA is capable of doing 64-bit transfers.  To use these, set br to 0xe0000001.
145          * Currently we use 32-bit transfers, because the 8260 does not easily do 64-bit operations.
146          */
147         iomem->bank[6].br = 0xe0001801;
148         iomem->bank[6].or = 0xff000830; /* Was 0xff000816 */
149
150 /*
151  * All systems with rev. A.1 (0K26N) silicon had serious problems when doing
152  * DMA transfers with data cache enabled (usually this shows when  using
153  * one of the FCC's with some traffic on the ethernet).  Allocating FCC buffer
154  * descriptors in main memory instead of DP ram solves this problem.
155  */
156
157         /* Guess at clocks based upon the PLL configuration from the
158          * power-on reset.
159          */
160         scmr = iomem->scmr;
161
162         /* The EST8260 is typically run using either 33 or 66 MHz
163          * external clock.  The configuration byte in the Flash will
164          * tell us which is configured.  The blast appears to be slightly
165          * overclocked at 72 MHz (if set to 66 MHz, the uart runs too fast)
166          */
167
168         m->clkin = CLKIN;
169
170         pllmf = scmr & 0xfff;
171
172         /* This is arithmetic from the 8260 manual, section 9.4.1. */
173
174         /* Collect the bits from the scmr.
175         */
176         m->vco_out = m->clkin * (pllmf + 1);
177         if (scmr & BIT(19))     /* plldf (division factor is 1 or 2) */
178                 m->vco_out >>= 1;
179
180         m->cpmhz = m->vco_out >> 1;     /* cpm hz is half of vco_out */
181         m->brghz = m->vco_out >> (2 * ((iomem->sccr & 0x3) + 1));
182         m->bushz = m->vco_out / (((scmr & 0x00f00000) >> 20) + 1);
183
184         /* Serial init sets BRG clock....I don't know how to compute
185          * core clock from core configuration, but I think I know the
186          * mapping....
187          */
188         switch(scmr >> (31-7)){
189         case 0x0a:
190                 m->cpuhz = m->clkin * 2;
191                 break;
192         case 0x0b:
193                 m->cpuhz = (m->clkin >> 1) * 5;
194                 break;
195         default:
196         case 0x0d:
197                 m->cpuhz = m->clkin * 3;
198                 break;
199         case 0x14:
200                 m->cpuhz = (m->clkin >> 1) * 7;
201                 break;
202         case 0x1c:
203                 m->cpuhz = m->clkin * 4;
204                 break;
205         }
206
207         m->cyclefreq = m->bushz / 4;
208
209 /*      Expect:
210         intfreq 133             m->cpuhz
211         busfreq 33              m->bushz
212         cpmfreq 99              m->cpmhz
213         brgfreq 49.5            m->brghz
214         vco             198
215 */
216
217         active.machs[0] = 1;
218         active.exiting = 0;
219
220         putmsr(getmsr() | MSR_ME);
221
222         /*
223          * turn on data cache before instruction cache;
224          * for some reason which I don't understand,
225          * you can't turn on both caches at once
226          */
227         icacheenb();
228         dcacheenb();
229
230         kfpinit();
231
232         /* Plan9.ini location in flash is FLASHMEM+PLAN9INI
233          * if PLAN9INI == ~0, it's not stored in flash or there is no flash
234          * if *cp == 0xff, flash memory is not initialized
235          */
236         if (PLAN9INI == ~0 || *(plan9inistr = (char*)(FLASHMEM+PLAN9INI)) == 0xff){
237                 /* No plan9.ini in flash */
238                 plan9inistr =
239                         "console=0\n"
240                         "ether0=type=fcc port=0 ea=00601d051dd8\n"
241                         "flash0=mem=0xfe000000\n"
242                         "fs=135.104.9.42\n"
243                         "auth=135.104.9.7\n"
244                         "authdom=cs.bell-labs.com\n"
245                         "sys=blast\n"
246                         "ntp=135.104.9.52\n";
247         }
248 }
249
250 void
251 fpgareset(void)
252 {
253         print("fpga reset\n");
254
255         ioplock();
256
257         iomem->port[1].pdat &= ~Pin4;   /* force reset signal to 0 */
258         delay(100);
259         iomem->port[1].pdat |= Pin4;            /* force reset signal back to one */
260
261         iopunlock();
262 }
263
264 void
265 hwintrinit(void)
266 {
267         iomem->sicr = 2 << 8;
268         /* Write ones into most bits of the interrupt pending registers to clear interrupts */
269         iomem->sipnr_h = ~7;
270         iomem->sipnr_h = ~1;
271         /* Clear the interrupt masks, thereby disabling all interrupts */
272         iomem->simr_h = 0;
273         iomem->simr_l = 0;
274
275         iomem->sypcr &= ~2;     /* cause a machine check interrupt on memory timeout */
276
277         /* Initialize fpga reset pin */
278         iomem->port[1].pdir |= Pin4;            /* 1 is an output */
279         iomem->port[1].ppar &= ~Pin4;
280         iomem->port[1].pdat |= Pin4;            /* force reset signal back to one */
281 }
282
283 int
284 vectorenable(Vctl *v)
285 {
286         ulong hi, lo;
287
288         if (v->irq & ~0x3f){
289                 print("m8260enable: interrupt vector %d out of range\n", v->irq);
290                 return -1;
291         }
292         hi = vec2mask[v->irq].hi;
293         lo = vec2mask[v->irq].lo;
294         if (hi == 0 && lo == 0){
295                 print("m8260enable: nonexistent vector %d\n", v->irq);
296                 return -1;
297         }
298         ioplock();
299         /* Clear the interrupt before enabling */
300         iomem->sipnr_h |= hi;
301         iomem->sipnr_l |= lo;
302         /* Enable */
303         iomem->simr_h |= hi;
304         iomem->simr_l |= lo;
305         iopunlock();
306         return v->irq;
307 }
308
309 void
310 vectordisable(Vctl *v)
311 {
312         ulong hi, lo;
313
314         if (v->irq & ~0x3f){
315                 print("m8260disable: interrupt vector %d out of range\n", v->irq);
316                 return;
317         }
318         hi = vec2mask[v->irq].hi;
319         lo = vec2mask[v->irq].lo;
320         if (hi == 0 && lo == 0){
321                 print("m8260disable: nonexistent vector %d\n", v->irq);
322                 return;
323         }
324         ioplock();
325         iomem->simr_h &= ~hi;
326         iomem->simr_l &= ~lo;
327         iopunlock();
328 }
329
330 int
331 intvec(void)
332 {
333         return iomem->sivec >> 26;
334 }
335
336 void
337 intend(int vno)
338 {
339         /* Clear interrupt */
340         ioplock();
341         iomem->sipnr_h |= vec2mask[vno].hi;
342         iomem->sipnr_l |= vec2mask[vno].lo;
343         iopunlock();
344 }
345
346 int
347 m8260eoi(int)
348 {
349         return 0;
350 }
351
352 int
353 m8260isr(int)
354 {
355         return 0;
356 }
357
358 void
359 flashprogpower(int)
360 {
361 }
362
363 enum {
364         TgcrCas                         = 0x80,
365         TgcrGm                  = 0x08,
366         TgcrStp                         = 0x2,  /* There are two of these, timer-2 bits are bits << 4 */
367         TgcrRst                         = 0x1,
368
369         TmrIclkCasc             = 0x00<<1,
370         TmrIclkIntclock = 0x01<<1,
371         TmrIclkIntclock16       = 0x02<<1,
372         TmrIclkTin              = 0x03<<1,
373         TmrCERising             = 0x1 << 6,
374         TmrCEFalling            = 0x2 << 6,
375         TmrCEAny                = 0x3 << 6,
376         TmrFrr                  = SBIT(12),
377         TmrOri                  = SBIT(11),
378
379         TerRef                  = SBIT(14),
380         TerCap                  = SBIT(15),
381 };
382
383 uvlong
384 fastticks(uvlong *hz)
385 {
386         ulong count;
387         static Lock fasttickslock;
388
389         if (hz)
390                 *hz = m->clkin>>1;
391         ilock(&fasttickslock);
392         count = iomem->tcnl1;
393         if (count < ticks.lo)
394                 ticks.hi += 1;
395         ticks.lo = count;
396         iunlock(&fasttickslock);
397         return ticks.val;
398 }
399
400 void
401 timerset(uvlong next)
402 {
403         long offset;
404         uvlong now;
405         static int cnt;
406
407         now = fastticks(nil);
408         offset = next - now;
409         if (offset < 2500)
410                 next = now + 2500;      /* 10000 instructions */
411         else if (offset > m->clkin / HZ){
412                 print("too far in the future: offset %llux, now %llux\n", next, now);
413                 next = now + m->clkin / HZ;
414         }
415         iomem->trrl1 = next;
416 }
417
418 void
419 m8260timerintr(Ureg *u, void*)
420 {
421         iomem->ter2 |= TerRef | TerCap;         /* Clear interrupt */
422         timerintr(u, 0);
423 }
424
425 void
426 timerinit(void)
427 {
428
429         iomem->tgcr1 = TgcrCas | TgcrGm;                /* cascade timers 1 & 2, normal gate mode */
430         iomem->tcnl1 = 0;
431         iomem->trrl1 = m->clkin / HZ;           /* first capture in 1/HZ seconds */
432         iomem->tmr1 = TmrIclkCasc;
433         iomem->tmr2 = TmrIclkIntclock | TmrOri;
434         intrenable(13, m8260timerintr, nil, "timer");   /* Timer 2 interrupt is on 13 */
435         iomem->tgcr1 |= TgcrRst << 4;
436 }
437
438 static void
439 addseg(char *name, ulong start, ulong length)
440 {
441         Physseg segbuf;
442
443         memset(&segbuf, 0, sizeof(segbuf));
444         segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
445         kstrdup(&segbuf.name, name);
446         segbuf.pa = start;
447         segbuf.size = length;
448         if (addphysseg(&segbuf) == nil) {
449                 print("addphysseg: %s\n", name);
450                 return;
451         }
452 }
453
454 void
455 sharedseginit(void)
456 {
457         int i, j;
458         ulong base, size;
459         char name[16], *a, *b, *s;
460         static char *segnames[] = {
461                 "fpga",
462                 "dsp",
463         };
464
465         for (j = 0; j < nelem(segnames); j++){
466                 for (i = 0; i < 8; i++){
467                         snprint(name, sizeof name, "%s%d", segnames[j], i);
468                         if ((a = getconf(name)) == nil)
469                                 continue;
470                         if ((b = strstr(a, "mem=")) == nil){
471                                 print("blastseginit: %s: no base\n", name);
472                                 continue;
473                         }
474                         b += 4;
475                         base = strtoul(b, nil, 0);
476                         if (base == 0){
477                                 print("blastseginit: %s: bad base: %s\n", name, b);
478                                 continue;
479                         }
480                         if ((s = strstr(a, "size=")) == nil){
481                                 print("blastseginit: %s: no size\n", name);
482                                 continue;
483                         }
484                         s += 5;
485                         size = strtoul(s, nil, 0);
486                         if (size == 0){
487                                 print("blastseginit: %s: bad size: %s\n", name, s);
488                                 continue;
489                         }
490                         addseg(name, base, size);
491                 }
492         }
493 }
494
495 void
496 cpmop(int op, int dev, int mcn)
497 {
498         ioplock();
499         eieio();
500         while(iomem->cpcr & 0x10000)
501                 eieio();
502         iomem->cpcr = dev<<(31-10) | mcn<<(31-25) | op | 0x10000;
503         eieio();
504         while(iomem->cpcr & 0x10000)
505                 eieio();
506         iopunlock();
507 }
508
509 /*
510  * connect SCCx clocks in NSMI mode (x=1 for USB)
511  */
512 void
513 sccnmsi(int x, int rcs, int tcs)
514 {
515         ulong v;
516         int sh;
517
518         sh = (x-1)*8;   /* each SCCx field in sicr is 8 bits */
519         v = (((rcs&7)<<3) | (tcs&7)) << sh;
520         iomem->sicr = (iomem->sicr & ~(0xFF<<sh)) | v;
521 }
522
523 /*
524  * lock the shared IO memory and return a reference to it
525  */
526 void
527 ioplock(void)
528 {
529         ilock(&cpmlock);
530 }
531
532 /*
533  * release the lock on the shared IO memory
534  */
535 void
536 iopunlock(void)
537 {
538         eieio();
539         iunlock(&cpmlock);
540 }
541
542 BD*
543 bdalloc(int n)
544 {
545         static BD *palloc = ((Imap*)INTMEM)->bd;
546         BD *p;
547         
548         p = palloc;
549         if (palloc > ((Imap*)INTMEM)->bd + nelem(((Imap*)INTMEM)->bd)){
550                 print("bdalloc: out of BDs\n");
551                 return nil;
552         }
553         palloc += n;
554         return p;
555 }
556
557 /*
558  * Initialise receive and transmit buffer rings.  Only used for FCC
559  * Ethernet now.
560  *
561  * Ioringinit will allocate the buffer descriptors in normal memory
562  * and NOT in Dual-Ported Ram, as prescribed by the MPC8260
563  * PowerQUICC II manual (Section 28.6).  When they are allocated
564  * in DPram and the Dcache is enabled, the processor will hang.
565  * This has been observed for the FCCs, it may or may not be true
566  * for SCCs or DMA.
567  * The SMC Uart buffer descriptors are not allocated here; (1) they
568  * can ONLY be in DPram and (2) they are not configured as a ring.
569  */
570 int
571 ioringinit(Ring* r, int nrdre, int ntdre, int bufsize)
572 {
573         int i, x;
574         static uchar *dpmallocaddr;
575         static uchar *dpmallocend;
576
577         if (dpmallocaddr == nil){
578                 dpmallocaddr = m->imap->dpram1;
579                 dpmallocend = dpmallocaddr + sizeof(m->imap->dpram1);
580         }
581         /* the ring entries must be aligned on sizeof(BD) boundaries */
582         r->nrdre = nrdre;
583         if(r->rdr == nil)
584                 r->rdr = xspanalloc(nrdre*sizeof(BD), 0, 8);
585         if(r->rdr == nil)
586                 return -1;
587         if(r->rrb == nil && bufsize){
588                 r->rrb = xspanalloc(nrdre*bufsize, 0, CACHELINESZ);
589                 if(r->rrb == nil)
590                         return -1;
591         }
592         x = bufsize ? PADDR(r->rrb) : 0;
593         for(i = 0; i < nrdre; i++){
594                 r->rdr[i].length = 0;
595                 r->rdr[i].addr = x;
596                 r->rdr[i].status = BDEmpty|BDInt;
597                 x += bufsize;
598         }
599         r->rdr[i-1].status |= BDWrap;
600         r->rdrx = 0;
601
602         r->ntdre = ntdre;
603         if(r->tdr == nil)
604                 r->tdr = xspanalloc(ntdre*sizeof(BD), 0, 8);
605         if(r->txb == nil)
606                 r->txb = xspanalloc(ntdre*sizeof(Block*), 0, CACHELINESZ);
607         if(r->tdr == nil || r->txb == nil)
608                 return -1;
609         for(i = 0; i < ntdre; i++){
610                 r->txb[i] = nil;
611                 r->tdr[i].addr = 0;
612                 r->tdr[i].length = 0;
613                 r->tdr[i].status = 0;
614         }
615         r->tdr[i-1].status |= BDWrap;
616         r->tdrh = 0;
617         r->tdri = 0;
618         r->ntq = 0;
619         return 0;
620 }
621
622 void
623 trapinit(void)
624 {
625         int i;
626
627         /*
628          * set all exceptions to trap
629          */
630         for(i = 0x0; i < 0x2000; i += 0x100)
631                 sethvec(i, trapvec);
632
633         setmvec(0x1000, imiss, tlbvec);
634         setmvec(0x1100, dmiss, tlbvec);
635         setmvec(0x1200, dmiss, tlbvec);
636
637 /*      Useful for avoiding assembler miss handling:
638         sethvec(0x1000, tlbvec);
639         sethvec(0x1100, tlbvec);
640         sethvec(0x1200, tlbvec);
641 /* */
642         dcflush(KADDR(0), 0x2000);
643         icflush(KADDR(0), 0x2000);
644
645         putmsr(getmsr() & ~MSR_IP);
646 }
647
648 void
649 reboot(void*, void*, ulong)
650 {
651         ulong *p;
652         int x;
653
654         p = (ulong*)0x90000000;
655         x = splhi();
656         iomem->sypcr |= 0xc0;
657         print("iomem->sypcr = 0x%lux\n", iomem->sypcr);
658         *p = 0;
659         print("still alive\n");
660         splx(x);
661 }