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