FreeBSD/Linux Kernel Cross Reference
sys/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 = 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;
445 kstrdup(&segbuf.name, name);
446 segbuf.pa = start;
447 segbuf.size = length;
448 if (addphysseg(&segbuf) == -1) {
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 }
Cache object: 0c1e9c54904f01710a48a6eded714329
|