1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 8 typedef struct Chanuse Chanuse; 9 struct Chanuse { 10 Lock; 11 void* owner; 12 } ; 13 14 enum { 15 BDSIZE= 1024, /* IO memory reserved for buffer descriptors */ 16 CPMSIZE= 1024, /* IO memory reserved for other uses */ 17 18 /* channel IDs */ 19 SCC1ID= 0, 20 I2CID= 1, 21 IDMA1ID= 1, 22 SCC2ID= 4, 23 SPIID= 5, 24 IDMA2ID= 5, 25 TIMERID= 5, 26 SCC3ID= 8, 27 SMC1ID= 9, 28 DSP1ID= 9, 29 SCC4ID= 12, 30 SMC2ID= 13, 31 DSP2ID= 13, 32 NCPMID= 16, 33 34 NSCC = 4, 35 36 /* SCC.gsmr_l */ 37 ENR = 1<<5, /* enable receiver */ 38 ENT = 1<<4, /* enable transmitter */ 39 40 NSMC = 2, 41 42 /* SMC.smcmr */ 43 TEN = 1<<1, /* transmitter enable */ 44 REN = 1<<0, /* receiver enable */ 45 }; 46 47 static Map bdmapv[BDSIZE/sizeof(BD)]; 48 static RMap bdmap = {"buffer descriptors"}; 49 50 static Map cpmmapv[CPMSIZE/sizeof(ulong)]; 51 static RMap cpmmap = {"CPM memory"}; 52 53 static Lock cpmlock; 54 55 static struct { 56 Lock; 57 ulong avail; 58 } brgens; 59 60 static Chanuse cpmids[NCPMID]; 61 static CPMdev cpmdevinfo[] = { 62 [CPscc1] {SCC1ID, 0x1E, 0xA00, 0x3C00}, 63 [CPscc2] {SCC2ID, 0x1D, 0xA20, 0x3D00}, 64 [CPscc3] {SCC3ID, 0x1C, 0xA40, 0x3E00}, 65 [CPscc4] {SCC4ID, 0x1B, 0xA60, 0x3F00}, 66 [CPsmc1] {SMC1ID, 0x04, 0xA80, 0x3E80}, 67 [CPsmc2] {SMC2ID, 0x03, 0xA90, 0x3F80}, 68 [CPdsp1] {DSP1ID, 0x16, 0, 0x3EC0}, 69 [CPdsp2] {DSP2ID, 0x16, 0, 0x3FC0}, 70 [CPidma1] {IDMA1ID, 0x15, 0, 0x3CC0}, 71 [CPidma2] {IDMA2ID, 0x14, 0, 0x3DC0}, 72 [CPtimer] {TIMERID, 0x11, 0, 0x3DB0}, 73 [CPspi] {SPIID, 0x05, 0xAA0, 0x3D80}, /* parameters relocated below */ 74 [CPi2c] {I2CID, 0x10, 0x860, 0x3C80}, /* parameters relocated below */ 75 }; 76 77 static void i2cspireloc(void); 78 static void* relocateparam(ulong, int); 79 80 /* 81 * initialise the communications processor module 82 * and associated device registers 83 */ 84 void 85 cpminit(void) 86 { 87 IMM *io; 88 89 io = m->iomem; 90 io->sdcr = 1; 91 io->rccr = 0; 92 io->rmds = 0; 93 io->lccr = 0; /* disable LCD */ 94 io->vccr = 0; /* disable video */ 95 io->i2mod = 0; /* stop I2C */ 96 io->pcint = 0; /* disable all port C interrupts */ 97 io->pcso = 0; 98 io->pcdir =0; 99 io->pcpar = 0; 100 io->pcdat = 0; 101 io->papar = 0; 102 io->padir = 0; 103 io->paodr = 0; 104 io->padat = 0; 105 io->pbpar = 0; 106 io->pbdir = 0; 107 io->pbodr = 0; 108 io->pbdat = 0; 109 io->tgcr = 0x2222; /* reset timers, low-power stop */ 110 eieio(); 111 112 for(io->cpcr = 0x8001; io->cpcr & 1;) /* reset all CPM channels */ 113 eieio(); 114 115 mapinit(&bdmap, bdmapv, sizeof(bdmapv)); 116 mapfree(&bdmap, DPBASE, BDSIZE); 117 mapinit(&cpmmap, cpmmapv, sizeof(cpmmapv)); 118 mapfree(&cpmmap, DPBASE+BDSIZE, CPMSIZE); 119 120 if(m->cputype == 0x50 && (getimmr() & 0xFFFF) <= 0x2001) 121 brgens.avail = 0x3; 122 else 123 brgens.avail = 0xF; 124 i2cspireloc(); 125 } 126 127 /* 128 * return parameters defining a CPM device, given logical ID 129 */ 130 CPMdev* 131 cpmdev(int n) 132 { 133 CPMdev *d; 134 135 if(n < 0 || n >= nelem(cpmdevinfo)) 136 panic("cpmdev"); 137 d = &cpmdevinfo[n]; 138 if(d->param == nil && d->pbase != 0){ 139 if((n == CPi2c || n == CPspi)){ 140 d->param = relocateparam(d->pbase, 0xB0-0x80); /* relocate */ 141 if(d->param == nil) 142 return nil; 143 } else 144 d->param = (char*)m->iomem+d->pbase; 145 } 146 if(d->rbase != 0) 147 d->regs = (char*)m->iomem+d->rbase; 148 return d; 149 } 150 151 /* 152 * issue a request to a CPM device 153 */ 154 void 155 cpmop(CPMdev *cpd, int op, int param) 156 { 157 IMM *io; 158 159 ilock(&cpmlock); 160 io = m->iomem; 161 while(io->cpcr & 1) 162 eieio(); 163 io->cpcr = (op<<8)|(cpd->id<<4)|(param<<1)|1; 164 eieio(); 165 while(io->cpcr & 1) 166 eieio(); 167 iunlock(&cpmlock); 168 } 169 170 /* 171 * lock the shared IO memory and return a reference to it 172 */ 173 IMM* 174 ioplock(void) 175 { 176 ilock(&cpmlock); 177 return m->iomem; 178 } 179 180 /* 181 * release the lock on the shared IO memory 182 */ 183 void 184 iopunlock(void) 185 { 186 eieio(); 187 iunlock(&cpmlock); 188 } 189 190 /* 191 * connect SCCx clocks in NSMI mode (x=1 for USB) 192 */ 193 void 194 sccnmsi(int x, int rcs, int tcs) 195 { 196 IMM *io; 197 ulong v; 198 int sh; 199 200 sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */ 201 v = (((rcs&7)<<3) | (tcs&7)) << sh; 202 io = ioplock(); 203 io->sicr = (io->sicr & ~(0xFF<<sh)) | v; 204 iopunlock(); 205 } 206 207 /* 208 * connect SMCx clock in NSMI mode 209 */ 210 void 211 smcnmsi(int x, int cs) 212 { 213 IMM *io; 214 ulong v; 215 int sh; 216 217 if(x == 1) 218 sh = 0; 219 else 220 sh = 16; 221 v = cs << (12+sh); 222 io = ioplock(); 223 io->simode = (io->simode & ~(0xF000<<sh)) | v; /* SMCx to NMSI mode, set Tx/Rx clock */ 224 iopunlock(); 225 } 226 227 /* 228 * claim the use of a CPM ID (SCC, SMC) that might be used by two mutually exclusive devices, 229 * for the caller determined by the given parameter (which must be unique). 230 * returns non-zero if the resource is already in use. 231 */ 232 int 233 cpmidopen(int id, void *owner) 234 { 235 Chanuse *use; 236 237 use = &cpmids[id]; 238 ilock(use); 239 if(use->owner != nil && use->owner != owner){ 240 iunlock(use); 241 return -1; 242 } 243 use->owner = owner; 244 iunlock(use); 245 return 0; 246 } 247 248 /* 249 * release a previously claimed CPM ID 250 */ 251 void 252 cpmidclose(int id) 253 { 254 Chanuse *use; 255 256 use = &cpmids[id]; 257 ilock(use); 258 use->owner = nil; 259 iunlock(use); 260 } 261 262 /* 263 * if SCC d is currently enabled, shut it down 264 */ 265 void 266 sccxstop(CPMdev *d) 267 { 268 SCC *scc; 269 270 if(d == nil) 271 return; 272 scc = d->regs; 273 if(scc->gsmrl & (ENT|ENR)){ 274 if(scc->gsmrl & ENT) 275 cpmop(d, GracefulStopTx, 0); 276 if(scc->gsmrl & ENR) 277 cpmop(d, CloseRxBD, 0); 278 delay(1); 279 scc->gsmrl &= ~(ENT|ENR); /* disable current use */ 280 eieio(); 281 } 282 scc->sccm = 0; /* mask interrupts */ 283 } 284 285 /* 286 * if SMC d is currently enabled, shut it down 287 */ 288 void 289 smcxstop(CPMdev *d) 290 { 291 SMC *smc; 292 293 if(d == nil) 294 return; 295 smc = d->regs; 296 if(smc->smcmr & (TEN|REN)){ 297 if(smc->smcmr & TEN) 298 cpmop(d, StopTx, 0); 299 if(smc->smcmr & REN) 300 cpmop(d, CloseRxBD, 0); 301 delay(1); 302 smc->smcmr &= ~(TEN|REN); 303 eieio(); 304 } 305 smc->smcm = 0; /* mask interrupts */ 306 } 307 308 /* 309 * allocate a buffer descriptor 310 */ 311 BD * 312 bdalloc(int n) 313 { 314 ulong a; 315 316 a = rmapalloc(&bdmap, 0, n*sizeof(BD), sizeof(BD)); 317 if(a == 0) 318 panic("bdalloc"); 319 return KADDR(a); 320 } 321 322 /* 323 * free a buffer descriptor 324 */ 325 void 326 bdfree(BD *b, int n) 327 { 328 if(b){ 329 eieio(); 330 mapfree(&bdmap, PADDR(b), n*sizeof(BD)); 331 } 332 } 333 334 /* 335 * print a buffer descriptor and its data (when debugging) 336 */ 337 void 338 dumpbd(char *name, BD *b, int maxn) 339 { 340 uchar *d; 341 int i; 342 343 print("%s #%4.4lux: s=#%4.4ux l=%ud a=#%8.8lux", name, PADDR(b)&0xFFFF, b->status, b->length, b->addr); 344 if(maxn > b->length) 345 maxn = b->length; 346 if(b->addr != 0){ 347 d = KADDR(b->addr); 348 for(i=0; i<maxn; i++) 349 print(" %2.2ux", d[i]); 350 if(i < b->length) 351 print(" ..."); 352 } 353 print("\n"); 354 } 355 356 /* 357 * allocate memory from the shared IO memory space 358 */ 359 void * 360 cpmalloc(int n, int align) 361 { 362 ulong a; 363 364 a = rmapalloc(&cpmmap, 0, n, align); 365 if(a == 0) 366 panic("cpmalloc"); 367 return KADDR(a); 368 } 369 370 /* 371 * free previously allocated shared memory 372 */ 373 void 374 cpmfree(void *p, int n) 375 { 376 if(p != nil && n > 0){ 377 eieio(); 378 mapfree(&cpmmap, PADDR(p), n); 379 } 380 } 381 382 /* 383 * allocate a baud rate generator, returning its index 384 * (or -1 if none is available) 385 */ 386 int 387 brgalloc(void) 388 { 389 int n; 390 391 lock(&brgens); 392 for(n=0; brgens.avail!=0; n++) 393 if(brgens.avail & (1<<n)){ 394 brgens.avail &= ~(1<<n); 395 unlock(&brgens); 396 return n; 397 } 398 unlock(&brgens); 399 return -1; 400 } 401 402 /* 403 * free a previously allocated baud rate generator 404 */ 405 void 406 brgfree(int n) 407 { 408 if(n >= 0){ 409 if(n > 3 || brgens.avail & (1<<n)) 410 panic("brgfree"); 411 lock(&brgens); 412 brgens.avail |= 1 << n; 413 unlock(&brgens); 414 } 415 } 416 417 /* 418 * return a value suitable for loading into a baud rate 419 * generator to produce the given rate if the generator 420 * is prescaled by the given amount (typically 16). 421 * the value must be or'd with BaudEnable to start the generator. 422 */ 423 ulong 424 baudgen(int rate, int scale) 425 { 426 int d; 427 428 rate *= scale; 429 d = (2*m->cpuhz+rate)/(2*rate) - 1; 430 if(d < 0) 431 d = 0; 432 if(d >= (1<<12)) 433 return ((d+15)>>(4-1))|1; /* divider too big: enable prescale by 16 */ 434 return d<<1; 435 } 436 437 /* 438 * initialise receive and transmit buffer rings. 439 */ 440 int 441 ioringinit(Ring* r, int nrdre, int ntdre, int bufsize) 442 { 443 int i, x; 444 445 /* the ring entries must be aligned on sizeof(BD) boundaries */ 446 r->nrdre = nrdre; 447 if(r->rdr == nil) 448 r->rdr = bdalloc(nrdre); 449 /* the buffer size must align with cache lines since the cache doesn't snoop */ 450 bufsize = (bufsize+CACHELINESZ-1)&~(CACHELINESZ-1); 451 if(r->rrb == nil) 452 r->rrb = malloc(nrdre*bufsize); 453 if(r->rdr == nil || r->rrb == nil) 454 return -1; 455 dcflush(r->rrb, nrdre*bufsize); 456 x = PADDR(r->rrb); 457 for(i = 0; i < nrdre; i++){ 458 r->rdr[i].length = 0; 459 r->rdr[i].addr = x; 460 r->rdr[i].status = BDEmpty|BDInt; 461 x += bufsize; 462 } 463 r->rdr[i-1].status |= BDWrap; 464 r->rdrx = 0; 465 466 r->ntdre = ntdre; 467 if(r->tdr == nil) 468 r->tdr = bdalloc(ntdre); 469 if(r->txb == nil) 470 r->txb = malloc(ntdre*sizeof(Block*)); 471 if(r->tdr == nil || r->txb == nil) 472 return -1; 473 for(i = 0; i < ntdre; i++){ 474 r->txb[i] = nil; 475 r->tdr[i].addr = 0; 476 r->tdr[i].length = 0; 477 r->tdr[i].status = 0; 478 } 479 r->tdr[i-1].status |= BDWrap; 480 r->tdrh = 0; 481 r->tdri = 0; 482 r->ntq = 0; 483 return 0; 484 } 485 486 /* 487 * Allocate a new parameter block for I2C or SPI, 488 * and plant a pointer to it for the microcode, returning the kernel address. 489 * See Motorola errata and microcode package: 490 * the design botch is that the parameters for the SCC2 ethernet overlap the 491 * SPI/I2C parameter space; this compensates by relocating the latter. 492 * This routine may be used iff i2cspireloc is used (and it is, above). 493 */ 494 static void* 495 relocateparam(ulong olda, int nb) 496 { 497 void *p; 498 499 if(olda < (ulong)m->iomem) 500 olda += (ulong)m->iomem; 501 p = cpmalloc(nb, 32); /* ``RPBASE must be multiple of 32'' */ 502 if(p == nil) 503 return p; 504 *(ushort*)KADDR(olda+0x2C) = PADDR(p); /* set RPBASE */ 505 eieio(); 506 return p; 507 } 508 509 /* 510 * I2C/SPI microcode package from Motorola 511 * (to relocate I2C/SPI parameters), which was distributed 512 * on their web site in S-record format. 513 * 514 * May 1998 515 */ 516 517 /*S00600004844521B*/ 518 static ulong ubase1 = 0x2000; 519 static ulong ucode1[] = { 520 /* #02202000 */ 0x7FFFEFD9, 521 /* #02202004 */ 0x3FFD0000, 522 /* #02202008 */ 0x7FFB49F7, 523 /* #0220200C */ 0x7FF90000, 524 /* #02202010 */ 0x5FEFADF7, 525 /* #02202014 */ 0x5F89ADF7, 526 /* #02202018 */ 0x5FEFAFF7, 527 /* #0220201C */ 0x5F89AFF7, 528 /* #02202020 */ 0x3A9CFBC8, 529 /* #02202024 */ 0xE7C0EDF0, 530 /* #02202028 */ 0x77C1E1BB, 531 /* #0220202C */ 0xF4DC7F1D, 532 /* #02202030 */ 0xABAD932F, 533 /* #02202034 */ 0x4E08FDCF, 534 /* #02202038 */ 0x6E0FAFF8, 535 /* #0220203C */ 0x7CCF76CF, 536 /* #02202040 */ 0xFD1FF9CF, 537 /* #02202044 */ 0xABF88DC6, 538 /* #02202048 */ 0xAB5679F7, 539 /* #0220204C */ 0xB0937383, 540 /* #02202050 */ 0xDFCE79F7, 541 /* #02202054 */ 0xB091E6BB, 542 /* #02202058 */ 0xE5BBE74F, 543 /* #0220205C */ 0xB3FA6F0F, 544 /* #02202060 */ 0x6FFB76CE, 545 /* #02202064 */ 0xEE0DF9CF, 546 /* #02202068 */ 0x2BFBEFEF, 547 /* #0220206C */ 0xCFEEF9CF, 548 /* #02202070 */ 0x76CEAD24, 549 /* #02202074 */ 0x90B2DF9A, 550 /* #02202078 */ 0x7FDDD0BF, 551 /* #0220207C */ 0x4BF847FD, 552 /* #02202080 */ 0x7CCF76CE, 553 /* #02202084 */ 0xCFEF7E1F, 554 /* #02202088 */ 0x7F1D7DFD, 555 /* #0220208C */ 0xF0B6EF71, 556 /* #02202090 */ 0x7FC177C1, 557 /* #02202094 */ 0xFBC86079, 558 /* #02202098 */ 0xE722FBC8, 559 /* #0220209C */ 0x5FFFDFFF, 560 /* #022020A0 */ 0x5FB2FFFB, 561 /* #022020A4 */ 0xFBC8F3C8, 562 /* #022020A8 */ 0x94A67F01, 563 /* #022020AC */ 0x7F1D5F39, 564 /* #022020B0 */ 0xAFE85F5E, 565 /* #022020B4 */ 0xFFDFDF96, 566 /* #022020B8 */ 0xCB9FAF7D, 567 /* #022020BC */ 0x5FC1AFED, 568 /* #022020C0 */ 0x8C1C5FC1, 569 /* #022020C4 */ 0xAFDD5FC3, 570 /* #022020C8 */ 0xDF9A7EFD, 571 /* #022020CC */ 0xB0B25FB2, 572 /* #022020D0 */ 0xFFFEABAD, 573 /* #022020D4 */ 0x5FB2FFFE, 574 /* #022020D8 */ 0x5FCE600B, 575 /* #022020DC */ 0xE6BB600B, 576 /* #022020E0 */ 0x5FCEDFC6, 577 /* #022020E4 */ 0x27FBEFDF, 578 /* #022020E8 */ 0x5FC8CFDE, 579 /* #022020EC */ 0x3A9CE7C0, 580 /* #022020F0 */ 0xEDF0F3C8, 581 /* #022020F4 */ 0x7F0154CD, 582 /* #022020F8 */ 0x7F1D2D3D, 583 /* #022020FC */ 0x363A7570, 584 /* #02202100 */ 0x7E0AF1CE, 585 /* #02202104 */ 0x37EF2E68, 586 /* #02202108 */ 0x7FEE10EC, 587 /* #0220210C */ 0xADF8EFDE, 588 /* #02202110 */ 0xCFEAE52F, 589 /* #02202114 */ 0x7D0FE12B, 590 /* #02202118 */ 0xF1CE5F65, 591 /* #0220211C */ 0x7E0A4DF8, 592 /* #02202120 */ 0xCFEA5F72, 593 /* #02202124 */ 0x7D0BEFEE, 594 /* #02202128 */ 0xCFEA5F74, 595 /* #0220212C */ 0xE522EFDE, 596 /* #02202130 */ 0x5F74CFDA, 597 /* #02202134 */ 0x0B627385, 598 /* #02202138 */ 0xDF627E0A, 599 /* #0220213C */ 0x30D8145B, 600 /* #02202140 */ 0xBFFFF3C8, 601 /* #02202144 */ 0x5FFFDFFF, 602 /* #02202148 */ 0xA7F85F5E, 603 /* #0220214C */ 0xBFFE7F7D, 604 /* #02202150 */ 0x10D31450, 605 /* #02202154 */ 0x5F36BFFF, 606 /* #02202158 */ 0xAF785F5E, 607 /* #0220215C */ 0xBFFDA7F8, 608 /* #02202160 */ 0x5F36BFFE, 609 /* #02202164 */ 0x77FD30C0, 610 /* #02202168 */ 0x4E08FDCF, 611 /* #0220216C */ 0xE5FF6E0F, 612 /* #02202170 */ 0xAFF87E1F, 613 /* #02202174 */ 0x7E0FFD1F, 614 /* #02202178 */ 0xF1CF5F1B, 615 /* #0220217C */ 0xABF80D5E, 616 /* #02202180 */ 0x5F5EFFEF, 617 /* #02202184 */ 0x79F730A2, 618 /* #02202188 */ 0xAFDD5F34, 619 /* #0220218C */ 0x47F85F34, 620 /* #02202190 */ 0xAFED7FDD, 621 /* #02202194 */ 0x50B24978, 622 /* #02202198 */ 0x47FD7F1D, 623 /* #0220219C */ 0x7DFD70AD, 624 /* #022021A0 */ 0xEF717EC1, 625 /* #022021A4 */ 0x6BA47F01, 626 /* #022021A8 */ 0x2D267EFD, 627 /* #022021AC */ 0x30DE5F5E, 628 /* #022021B0 */ 0xFFFD5F5E, 629 /* #022021B4 */ 0xFFEF5F5E, 630 /* #022021B8 */ 0xFFDF0CA0, 631 /* #022021BC */ 0xAFED0A9E, 632 /* #022021C0 */ 0xAFDD0C3A, 633 /* #022021C4 */ 0x5F3AAFBD, 634 /* #022021C8 */ 0x7FBDB082, 635 /* #022021CC */ 0x5F8247F8, 636 }; 637 638 /*S00600004844521B*/ 639 static ulong ubase2 = 0x2F00; 640 static ulong ucode2[] = { 641 /* #02202F00 */ 0x3E303430, 642 /* #02202F04 */ 0x34343737, 643 /* #02202F08 */ 0xABF7BF9B, 644 /* #02202F0C */ 0x994B4FBD, 645 /* #02202F10 */ 0xBD599493, 646 /* #02202F14 */ 0x349FFF37, 647 /* #02202F18 */ 0xFB9B177D, 648 /* #02202F1C */ 0xD9936956, 649 /* #02202F20 */ 0xBBFDD697, 650 /* #02202F24 */ 0xBDD2FD11, 651 /* #02202F28 */ 0x31DB9BB3, 652 /* #02202F2C */ 0x63139637, 653 /* #02202F30 */ 0x93733693, 654 /* #02202F34 */ 0x193137F7, 655 /* #02202F38 */ 0x331737AF, 656 /* #02202F3C */ 0x7BB9B999, 657 /* #02202F40 */ 0xBB197957, 658 /* #02202F44 */ 0x7FDFD3D5, 659 /* #02202F48 */ 0x73B773F7, 660 /* #02202F4C */ 0x37933B99, 661 /* #02202F50 */ 0x1D115316, 662 /* #02202F54 */ 0x99315315, 663 /* #02202F58 */ 0x31694BF4, 664 /* #02202F5C */ 0xFBDBD359, 665 /* #02202F60 */ 0x31497353, 666 /* #02202F64 */ 0x76956D69, 667 /* #02202F68 */ 0x7B9D9693, 668 /* #02202F6C */ 0x13131979, 669 /* #02202F70 */ 0x79376935, 670 }; 671 672 /* 673 * compensate for chip design botch by installing 674 * microcode to relocate I2C and SPI parameters away 675 * from the ethernet parameters 676 */ 677 static void 678 i2cspireloc(void) 679 { 680 IMM *io; 681 static int done; 682 683 if(done) 684 return; 685 io = m->iomem; 686 io->rccr &= ~3; 687 memmove((uchar*)m->iomem+ubase1, ucode1, sizeof(ucode1)); 688 memmove((uchar*)m->iomem+ubase2, ucode2, sizeof(ucode2)); 689 io->rctr1 = 0x802a; /* relocate SPI */ 690 io->rctr2 = 0x8028; /* relocate SPI */ 691 io->rctr3 = 0x802e; /* relocate I2C */ 692 io->rctr4 = 0x802c; /* relocate I2C */ 693 io->rccr |= 1; 694 done = 1; 695 } 696