m8260.c 14 KB

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