usbdwc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. /*
  2. * USB host driver for BCM2835
  3. * Synopsis DesignWare Core USB 2.0 OTG controller
  4. *
  5. * Copyright © 2012 Richard Miller <r.miller@acm.org>
  6. *
  7. * This is work in progress:
  8. * - no isochronous pipes
  9. * - no bandwidth budgeting
  10. * - frame scheduling is crude
  11. * - error handling is overly optimistic
  12. * It should be just about adequate for a Plan 9 terminal with
  13. * keyboard, mouse, ethernet adapter, and an external flash drive.
  14. */
  15. #include "u.h"
  16. #include "../port/lib.h"
  17. #include "mem.h"
  18. #include "dat.h"
  19. #include "fns.h"
  20. #include "io.h"
  21. #include "../port/error.h"
  22. #include "../port/usb.h"
  23. #include "dwcotg.h"
  24. enum
  25. {
  26. USBREGS = VIRTIO + 0x980000,
  27. Enabledelay = 50,
  28. Resetdelay = 10,
  29. ResetdelayHS = 50,
  30. Read = 0,
  31. Write = 1,
  32. };
  33. typedef struct Ctlr Ctlr;
  34. typedef struct Epio Epio;
  35. struct Ctlr {
  36. Dwcregs *regs; /* controller registers */
  37. int nchan; /* number of host channels */
  38. ulong chanbusy; /* bitmap of in-use channels */
  39. QLock chanlock; /* serialise access to chanbusy */
  40. QLock split; /* serialise split transactions */
  41. int splitretry; /* count retries of Nyet */
  42. int sofchan; /* bitmap of channels waiting for sof */
  43. int wakechan; /* bitmap of channels to wakeup after fiq */
  44. int debugchan; /* bitmap of channels for interrupt debug */
  45. Rendez *chanintr; /* sleep till interrupt on channel N */
  46. };
  47. struct Epio {
  48. QLock;
  49. Block *cb;
  50. ulong lastpoll;
  51. };
  52. static Ctlr dwc;
  53. static int debug;
  54. static char Ebadlen[] = "bad usb request length";
  55. static void clog(Ep *ep, Hostchan *hc);
  56. static void logdump(Ep *ep);
  57. static Hostchan*
  58. chanalloc(Ep *ep)
  59. {
  60. Ctlr *ctlr;
  61. int bitmap, i;
  62. ctlr = ep->hp->aux;
  63. qlock(&ctlr->chanlock);
  64. bitmap = ctlr->chanbusy;
  65. for(i = 0; i < ctlr->nchan; i++)
  66. if((bitmap & (1<<i)) == 0){
  67. ctlr->chanbusy = bitmap | 1<<i;
  68. qunlock(&ctlr->chanlock);
  69. return &ctlr->regs->hchan[i];
  70. }
  71. qunlock(&ctlr->chanlock);
  72. panic("miller is a lazy git");
  73. return nil;
  74. }
  75. static void
  76. chanrelease(Ep *ep, Hostchan *chan)
  77. {
  78. Ctlr *ctlr;
  79. int i;
  80. ctlr = ep->hp->aux;
  81. i = chan - ctlr->regs->hchan;
  82. qlock(&ctlr->chanlock);
  83. ctlr->chanbusy &= ~(1<<i);
  84. qunlock(&ctlr->chanlock);
  85. }
  86. static void
  87. chansetup(Hostchan *hc, Ep *ep)
  88. {
  89. int hcc;
  90. Ctlr *ctlr = ep->hp->aux;
  91. if(ep->debug)
  92. ctlr->debugchan |= 1 << (hc - ctlr->regs->hchan);
  93. else
  94. ctlr->debugchan &= ~(1 << (hc - ctlr->regs->hchan));
  95. switch(ep->dev->state){
  96. case Dconfig:
  97. case Dreset:
  98. hcc = 0;
  99. break;
  100. default:
  101. hcc = ep->dev->nb<<ODevaddr;
  102. break;
  103. }
  104. hcc |= ep->maxpkt | 1<<OMulticnt | ep->nb<<OEpnum;
  105. switch(ep->ttype){
  106. case Tctl:
  107. hcc |= Epctl;
  108. break;
  109. case Tiso:
  110. hcc |= Episo;
  111. break;
  112. case Tbulk:
  113. hcc |= Epbulk;
  114. break;
  115. case Tintr:
  116. hcc |= Epintr;
  117. break;
  118. }
  119. switch(ep->dev->speed){
  120. case Lowspeed:
  121. hcc |= Lspddev;
  122. /* fall through */
  123. case Fullspeed:
  124. if(ep->dev->hub > 1){
  125. hc->hcsplt = Spltena | POS_ALL | ep->dev->hub<<OHubaddr |
  126. ep->dev->port;
  127. break;
  128. }
  129. /* fall through */
  130. default:
  131. hc->hcsplt = 0;
  132. break;
  133. }
  134. hc->hcchar = hcc;
  135. hc->hcint = ~0;
  136. }
  137. static int
  138. sofdone(void *a)
  139. {
  140. Dwcregs *r;
  141. r = a;
  142. return r->gintsts & Sofintr;
  143. }
  144. static void
  145. sofwait(Ctlr *ctlr, int n)
  146. {
  147. Dwcregs *r;
  148. int x;
  149. r = ctlr->regs;
  150. do{
  151. r->gintsts = Sofintr;
  152. x = splfhi();
  153. ctlr->sofchan |= 1<<n;
  154. r->gintmsk |= Sofintr;
  155. sleep(&ctlr->chanintr[n], sofdone, r);
  156. splx(x);
  157. }while((r->hfnum & 7) == 6);
  158. }
  159. static int
  160. chandone(void *a)
  161. {
  162. Hostchan *hc;
  163. hc = a;
  164. if(hc->hcint == (Chhltd|Ack))
  165. return 0;
  166. return (hc->hcint & hc->hcintmsk) != 0;
  167. }
  168. static int
  169. chanwait(Ep *ep, Ctlr *ctlr, Hostchan *hc, int mask)
  170. {
  171. int intr, n, x, ointr;
  172. ulong start, now;
  173. Dwcregs *r;
  174. r = ctlr->regs;
  175. n = hc - r->hchan;
  176. for(;;){
  177. restart:
  178. x = splfhi();
  179. r->haintmsk |= 1<<n;
  180. hc->hcintmsk = mask;
  181. sleep(&ctlr->chanintr[n], chandone, hc);
  182. hc->hcintmsk = 0;
  183. splx(x);
  184. intr = hc->hcint;
  185. if(intr & Chhltd)
  186. return intr;
  187. start = fastticks(0);
  188. ointr = intr;
  189. now = start;
  190. do{
  191. intr = hc->hcint;
  192. if(intr & Chhltd){
  193. if((ointr != Ack && ointr != (Ack|Xfercomp)) ||
  194. intr != (Ack|Chhltd|Xfercomp) ||
  195. (now - start) > 60)
  196. dprint("await %x after %ld %x -> %x\n",
  197. mask, now - start, ointr, intr);
  198. return intr;
  199. }
  200. if((intr & mask) == 0){
  201. dprint("ep%d.%d await %x intr %x -> %x\n",
  202. ep->dev->nb, ep->nb, mask, ointr, intr);
  203. goto restart;
  204. }
  205. now = fastticks(0);
  206. }while(now - start < 100);
  207. dprint("ep%d.%d halting channel %8.8ux hcchar %8.8ux "
  208. "grxstsr %8.8ux gnptxsts %8.8ux hptxsts %8.8ux\n",
  209. ep->dev->nb, ep->nb, intr, hc->hcchar, r->grxstsr,
  210. r->gnptxsts, r->hptxsts);
  211. mask = Chhltd;
  212. hc->hcchar |= Chdis;
  213. start = m->ticks;
  214. while(hc->hcchar & Chen){
  215. if(m->ticks - start >= 100){
  216. print("ep%d.%d channel won't halt hcchar %8.8ux\n",
  217. ep->dev->nb, ep->nb, hc->hcchar);
  218. break;
  219. }
  220. }
  221. logdump(ep);
  222. }
  223. }
  224. static int
  225. chanintr(Ctlr *ctlr, int n)
  226. {
  227. Hostchan *hc;
  228. int i;
  229. hc = &ctlr->regs->hchan[n];
  230. if(ctlr->debugchan & (1<<n))
  231. clog(nil, hc);
  232. if((hc->hcsplt & Spltena) == 0)
  233. return 0;
  234. i = hc->hcint;
  235. if(i == (Chhltd|Ack)){
  236. hc->hcsplt |= Compsplt;
  237. ctlr->splitretry = 0;
  238. }else if(i == (Chhltd|Nyet)){
  239. if(++ctlr->splitretry >= 3)
  240. return 0;
  241. }else
  242. return 0;
  243. if(hc->hcchar & Chen){
  244. iprint("hcchar %8.8ux hcint %8.8ux", hc->hcchar, hc->hcint);
  245. hc->hcchar |= Chen | Chdis;
  246. while(hc->hcchar&Chen)
  247. ;
  248. iprint(" %8.8ux\n", hc->hcint);
  249. }
  250. hc->hcint = i;
  251. if(ctlr->regs->hfnum & 1)
  252. hc->hcchar &= ~Oddfrm;
  253. else
  254. hc->hcchar |= Oddfrm;
  255. hc->hcchar = (hc->hcchar &~ Chdis) | Chen;
  256. return 1;
  257. }
  258. static Reg chanlog[32][5];
  259. static int nchanlog;
  260. static void
  261. logstart(Ep *ep)
  262. {
  263. if(ep->debug)
  264. nchanlog = 0;
  265. }
  266. static void
  267. clog(Ep *ep, Hostchan *hc)
  268. {
  269. Reg *p;
  270. if(ep != nil && !ep->debug)
  271. return;
  272. if(nchanlog == 32)
  273. nchanlog--;
  274. p = chanlog[nchanlog];
  275. p[0] = dwc.regs->hfnum;
  276. p[1] = hc->hcchar;
  277. p[2] = hc->hcint;
  278. p[3] = hc->hctsiz;
  279. p[4] = hc->hcdma;
  280. nchanlog++;
  281. }
  282. static void
  283. logdump(Ep *ep)
  284. {
  285. Reg *p;
  286. int i;
  287. if(!ep->debug)
  288. return;
  289. p = chanlog[0];
  290. for(i = 0; i < nchanlog; i++){
  291. print("%5.5d.%5.5d %8.8ux %8.8ux %8.8ux %8.8ux\n",
  292. p[0]&0xFFFF, p[0]>>16, p[1], p[2], p[3], p[4]);
  293. p += 5;
  294. }
  295. nchanlog = 0;
  296. }
  297. static int
  298. chanio(Ep *ep, Hostchan *hc, int dir, int pid, void *a, int len)
  299. {
  300. Ctlr *ctlr;
  301. int nleft, n, nt, i, maxpkt, npkt;
  302. uint hcdma, hctsiz;
  303. ctlr = ep->hp->aux;
  304. maxpkt = ep->maxpkt;
  305. npkt = HOWMANY(len, ep->maxpkt);
  306. if(npkt == 0)
  307. npkt = 1;
  308. hc->hcchar = (hc->hcchar & ~Epdir) | dir;
  309. if(dir == Epin)
  310. n = ROUND(len, ep->maxpkt);
  311. else
  312. n = len;
  313. hc->hctsiz = n | npkt<<OPktcnt | pid;
  314. hc->hcdma = PADDR(a);
  315. nleft = len;
  316. logstart(ep);
  317. for(;;){
  318. hcdma = hc->hcdma;
  319. hctsiz = hc->hctsiz;
  320. hc->hctsiz = hctsiz & ~Dopng;
  321. if(hc->hcchar&Chen){
  322. dprint("ep%d.%d before chanio hcchar=%8.8ux\n",
  323. ep->dev->nb, ep->nb, hc->hcchar);
  324. hc->hcchar |= Chen | Chdis;
  325. while(hc->hcchar&Chen)
  326. ;
  327. hc->hcint = Chhltd;
  328. }
  329. if((i = hc->hcint) != 0){
  330. dprint("ep%d.%d before chanio hcint=%8.8ux\n",
  331. ep->dev->nb, ep->nb, i);
  332. hc->hcint = i;
  333. }
  334. if(hc->hcsplt & Spltena){
  335. qlock(&ctlr->split);
  336. sofwait(ctlr, hc - ctlr->regs->hchan);
  337. if((dwc.regs->hfnum & 1) == 0)
  338. hc->hcchar &= ~Oddfrm;
  339. else
  340. hc->hcchar |= Oddfrm;
  341. }
  342. hc->hcchar = (hc->hcchar &~ Chdis) | Chen;
  343. clog(ep, hc);
  344. if(ep->ttype == Tbulk && dir == Epin)
  345. i = chanwait(ep, ctlr, hc, /* Ack| */ Chhltd);
  346. else if(ep->ttype == Tintr && (hc->hcsplt & Spltena))
  347. i = chanwait(ep, ctlr, hc, Chhltd);
  348. else
  349. i = chanwait(ep, ctlr, hc, Chhltd|Nak);
  350. clog(ep, hc);
  351. hc->hcint = i;
  352. if(hc->hcsplt & Spltena){
  353. hc->hcsplt &= ~Compsplt;
  354. qunlock(&ctlr->split);
  355. }
  356. if((i & Xfercomp) == 0 && i != (Chhltd|Ack) && i != Chhltd){
  357. if(i & Stall)
  358. error(Estalled);
  359. if(i & (Nyet|Frmovrun))
  360. continue;
  361. if(i & Nak){
  362. if(ep->ttype == Tintr)
  363. tsleep(&up->sleep, return0, 0, ep->pollival);
  364. else
  365. tsleep(&up->sleep, return0, 0, 1);
  366. continue;
  367. }
  368. logdump(ep);
  369. print("usbotg: ep%d.%d error intr %8.8ux\n",
  370. ep->dev->nb, ep->nb, i);
  371. if(i & ~(Chhltd|Ack))
  372. error(Eio);
  373. if(hc->hcdma != hcdma)
  374. print("usbotg: weird hcdma %x->%x intr %x->%x\n",
  375. hcdma, hc->hcdma, i, hc->hcint);
  376. }
  377. n = hc->hcdma - hcdma;
  378. if(n == 0){
  379. if((hc->hctsiz & Pktcnt) != (hctsiz & Pktcnt))
  380. break;
  381. else
  382. continue;
  383. }
  384. if(dir == Epin && ep->ttype == Tbulk && n == nleft){
  385. nt = (hctsiz & Xfersize) - (hc->hctsiz & Xfersize);
  386. if(nt != n){
  387. if(n == ROUND(nt, 4))
  388. n = nt;
  389. else
  390. print("usbotg: intr %8.8ux "
  391. "dma %8.8ux-%8.8ux "
  392. "hctsiz %8.8ux-%8.ux\n",
  393. i, hcdma, hc->hcdma, hctsiz,
  394. hc->hctsiz);
  395. }
  396. }
  397. if(n > nleft){
  398. if(n != ROUND(nleft, 4))
  399. dprint("too much: wanted %d got %d\n",
  400. len, len - nleft + n);
  401. n = nleft;
  402. }
  403. nleft -= n;
  404. if(nleft == 0 || (n % maxpkt) != 0)
  405. break;
  406. if((i & Xfercomp) && ep->ttype != Tctl)
  407. break;
  408. if(dir == Epout)
  409. dprint("too little: nleft %d hcdma %x->%x hctsiz %x->%x intr %x\n",
  410. nleft, hcdma, hc->hcdma, hctsiz, hc->hctsiz, i);
  411. }
  412. logdump(ep);
  413. return len - nleft;
  414. }
  415. static long
  416. multitrans(Ep *ep, Hostchan *hc, int rw, void *a, long n)
  417. {
  418. long sofar, m;
  419. sofar = 0;
  420. do{
  421. m = n - sofar;
  422. if(m > ep->maxpkt)
  423. m = ep->maxpkt;
  424. m = chanio(ep, hc, rw == Read? Epin : Epout, ep->toggle[rw],
  425. (char*)a + sofar, m);
  426. ep->toggle[rw] = hc->hctsiz & Pid;
  427. sofar += m;
  428. }while(sofar < n && m == ep->maxpkt);
  429. return sofar;
  430. }
  431. static long
  432. eptrans(Ep *ep, int rw, void *a, long n)
  433. {
  434. Hostchan *hc;
  435. if(ep->clrhalt){
  436. ep->clrhalt = 0;
  437. if(ep->mode != OREAD)
  438. ep->toggle[Write] = DATA0;
  439. if(ep->mode != OWRITE)
  440. ep->toggle[Read] = DATA0;
  441. }
  442. hc = chanalloc(ep);
  443. if(waserror()){
  444. ep->toggle[rw] = hc->hctsiz & Pid;
  445. chanrelease(ep, hc);
  446. if(strcmp(up->errstr, Estalled) == 0)
  447. return 0;
  448. nexterror();
  449. }
  450. chansetup(hc, ep);
  451. if(rw == Read && ep->ttype == Tbulk)
  452. n = multitrans(ep, hc, rw, a, n);
  453. else{
  454. n = chanio(ep, hc, rw == Read? Epin : Epout, ep->toggle[rw],
  455. a, n);
  456. ep->toggle[rw] = hc->hctsiz & Pid;
  457. }
  458. chanrelease(ep, hc);
  459. poperror();
  460. return n;
  461. }
  462. static long
  463. ctltrans(Ep *ep, uchar *req, long n)
  464. {
  465. Hostchan *hc;
  466. Epio *epio;
  467. Block *b;
  468. uchar *data;
  469. int datalen;
  470. epio = ep->aux;
  471. if(epio->cb != nil){
  472. freeb(epio->cb);
  473. epio->cb = nil;
  474. }
  475. if(n < Rsetuplen)
  476. error(Ebadlen);
  477. if(req[Rtype] & Rd2h){
  478. datalen = GET2(req+Rcount);
  479. if(datalen <= 0 || datalen > Maxctllen)
  480. error(Ebadlen);
  481. /* XXX cache madness */
  482. epio->cb = b = allocb(ROUND(datalen, ep->maxpkt) + CACHELINESZ);
  483. b->wp = (uchar*)ROUND((uintptr)b->wp, CACHELINESZ);
  484. memset(b->wp, 0x55, b->lim - b->wp);
  485. cachedwbinvse(b->wp, b->lim - b->wp);
  486. data = b->wp;
  487. }else{
  488. b = nil;
  489. datalen = n - Rsetuplen;
  490. data = req + Rsetuplen;
  491. }
  492. hc = chanalloc(ep);
  493. if(waserror()){
  494. chanrelease(ep, hc);
  495. if(strcmp(up->errstr, Estalled) == 0)
  496. return 0;
  497. nexterror();
  498. }
  499. chansetup(hc, ep);
  500. chanio(ep, hc, Epout, SETUP, req, Rsetuplen);
  501. if(req[Rtype] & Rd2h){
  502. if(ep->dev->hub <= 1){
  503. ep->toggle[Read] = DATA1;
  504. b->wp += multitrans(ep, hc, Read, data, datalen);
  505. }else
  506. b->wp += chanio(ep, hc, Epin, DATA1, data, datalen);
  507. chanio(ep, hc, Epout, DATA1, nil, 0);
  508. n = Rsetuplen;
  509. }else{
  510. if(datalen > 0)
  511. chanio(ep, hc, Epout, DATA1, data, datalen);
  512. chanio(ep, hc, Epin, DATA1, nil, 0);
  513. n = Rsetuplen + datalen;
  514. }
  515. chanrelease(ep, hc);
  516. poperror();
  517. return n;
  518. }
  519. static long
  520. ctldata(Ep *ep, void *a, long n)
  521. {
  522. Epio *epio;
  523. Block *b;
  524. epio = ep->aux;
  525. b = epio->cb;
  526. if(b == nil)
  527. return 0;
  528. if(n > BLEN(b))
  529. n = BLEN(b);
  530. memmove(a, b->rp, n);
  531. b->rp += n;
  532. if(BLEN(b) == 0){
  533. freeb(b);
  534. epio->cb = nil;
  535. }
  536. return n;
  537. }
  538. static void
  539. greset(Dwcregs *r, int bits)
  540. {
  541. r->grstctl |= bits;
  542. while(r->grstctl & bits)
  543. ;
  544. microdelay(10);
  545. }
  546. static void
  547. init(Hci *hp)
  548. {
  549. Ctlr *ctlr;
  550. Dwcregs *r;
  551. uint n, rx, tx, ptx;
  552. ctlr = hp->aux;
  553. r = ctlr->regs;
  554. ctlr->nchan = 1 + ((r->ghwcfg2 & Num_host_chan) >> ONum_host_chan);
  555. ctlr->chanintr = malloc(ctlr->nchan * sizeof(Rendez));
  556. r->gahbcfg = 0;
  557. setpower(PowerUsb, 1);
  558. while((r->grstctl&Ahbidle) == 0)
  559. ;
  560. greset(r, Csftrst);
  561. r->gusbcfg |= Force_host_mode;
  562. tsleep(&up->sleep, return0, 0, 25);
  563. r->gahbcfg |= Dmaenable;
  564. n = (r->ghwcfg3 & Dfifo_depth) >> ODfifo_depth;
  565. rx = 0x306;
  566. tx = 0x100;
  567. ptx = 0x200;
  568. r->grxfsiz = rx;
  569. r->gnptxfsiz = rx | tx<<ODepth;
  570. tsleep(&up->sleep, return0, 0, 1);
  571. r->hptxfsiz = (rx + tx) | ptx << ODepth;
  572. greset(r, Rxfflsh);
  573. r->grstctl = TXF_ALL;
  574. greset(r, Txfflsh);
  575. dprint("usbotg: FIFO depth %d sizes rx/nptx/ptx %8.8ux %8.8ux %8.8ux\n",
  576. n, r->grxfsiz, r->gnptxfsiz, r->hptxfsiz);
  577. r->hport0 = Prtpwr|Prtconndet|Prtenchng|Prtovrcurrchng;
  578. r->gintsts = ~0;
  579. r->gintmsk = Hcintr;
  580. r->gahbcfg |= Glblintrmsk;
  581. }
  582. static void
  583. dump(Hci*)
  584. {
  585. }
  586. static void
  587. fiqintr(Ureg*, void *a)
  588. {
  589. Hci *hp;
  590. Ctlr *ctlr;
  591. Dwcregs *r;
  592. uint intr, haint, wakechan;
  593. int i;
  594. hp = a;
  595. ctlr = hp->aux;
  596. r = ctlr->regs;
  597. wakechan = 0;
  598. intr = r->gintsts;
  599. if(intr & Hcintr){
  600. haint = r->haint & r->haintmsk;
  601. for(i = 0; haint; i++){
  602. if(haint & 1){
  603. if(chanintr(ctlr, i) == 0){
  604. r->haintmsk &= ~(1<<i);
  605. wakechan |= 1<<i;
  606. }
  607. }
  608. haint >>= 1;
  609. }
  610. }
  611. if(intr & Sofintr){
  612. r->gintsts = Sofintr;
  613. if((r->hfnum&7) != 6){
  614. r->gintmsk &= ~Sofintr;
  615. wakechan |= ctlr->sofchan;
  616. ctlr->sofchan = 0;
  617. }
  618. }
  619. if(wakechan){
  620. ctlr->wakechan |= wakechan;
  621. armtimerset(1);
  622. }
  623. }
  624. static void
  625. irqintr(Ureg*, void *a)
  626. {
  627. Ctlr *ctlr;
  628. uint wakechan;
  629. int i, x;
  630. ctlr = a;
  631. x = splfhi();
  632. armtimerset(0);
  633. wakechan = ctlr->wakechan;
  634. ctlr->wakechan = 0;
  635. splx(x);
  636. for(i = 0; wakechan; i++){
  637. if(wakechan & 1)
  638. wakeup(&ctlr->chanintr[i]);
  639. wakechan >>= 1;
  640. }
  641. }
  642. static void
  643. epopen(Ep *ep)
  644. {
  645. ddprint("usbotg: epopen ep%d.%d ttype %d\n",
  646. ep->dev->nb, ep->nb, ep->ttype);
  647. switch(ep->ttype){
  648. case Tnone:
  649. error(Enotconf);
  650. case Tintr:
  651. assert(ep->pollival > 0);
  652. /* fall through */
  653. case Tbulk:
  654. if(ep->toggle[Read] == 0)
  655. ep->toggle[Read] = DATA0;
  656. if(ep->toggle[Write] == 0)
  657. ep->toggle[Write] = DATA0;
  658. break;
  659. }
  660. ep->aux = malloc(sizeof(Epio));
  661. if(ep->aux == nil)
  662. error(Enomem);
  663. }
  664. static void
  665. epclose(Ep *ep)
  666. {
  667. ddprint("usbotg: epclose ep%d.%d ttype %d\n",
  668. ep->dev->nb, ep->nb, ep->ttype);
  669. switch(ep->ttype){
  670. case Tctl:
  671. freeb(((Epio*)ep->aux)->cb);
  672. /* fall through */
  673. default:
  674. free(ep->aux);
  675. break;
  676. }
  677. }
  678. static long
  679. epread(Ep *ep, void *a, long n)
  680. {
  681. Epio *epio;
  682. Block *b;
  683. uchar *p;
  684. ulong elapsed;
  685. long nr;
  686. ddprint("epread ep%d.%d %ld\n", ep->dev->nb, ep->nb, n);
  687. epio = ep->aux;
  688. b = nil;
  689. qlock(epio);
  690. if(waserror()){
  691. qunlock(epio);
  692. if(b)
  693. freeb(b);
  694. nexterror();
  695. }
  696. switch(ep->ttype){
  697. default:
  698. error(Egreg);
  699. case Tctl:
  700. nr = ctldata(ep, a, n);
  701. qunlock(epio);
  702. poperror();
  703. return nr;
  704. case Tintr:
  705. elapsed = TK2MS(m->ticks) - epio->lastpoll;
  706. if(elapsed < ep->pollival)
  707. tsleep(&up->sleep, return0, 0, ep->pollival - elapsed);
  708. /* fall through */
  709. case Tbulk:
  710. /* XXX cache madness */
  711. b = allocb(ROUND(n, ep->maxpkt) + CACHELINESZ);
  712. p = (uchar*)ROUND((uintptr)b->base, CACHELINESZ);
  713. cachedwbinvse(p, n);
  714. nr = eptrans(ep, Read, p, n);
  715. epio->lastpoll = TK2MS(m->ticks);
  716. memmove(a, p, nr);
  717. qunlock(epio);
  718. freeb(b);
  719. poperror();
  720. return nr;
  721. }
  722. }
  723. static long
  724. epwrite(Ep *ep, void *a, long n)
  725. {
  726. Epio *epio;
  727. Block *b;
  728. uchar *p;
  729. ulong elapsed;
  730. ddprint("epwrite ep%d.%d %ld\n", ep->dev->nb, ep->nb, n);
  731. epio = ep->aux;
  732. b = nil;
  733. qlock(epio);
  734. if(waserror()){
  735. qunlock(epio);
  736. if(b)
  737. freeb(b);
  738. nexterror();
  739. }
  740. switch(ep->ttype){
  741. default:
  742. error(Egreg);
  743. case Tintr:
  744. elapsed = TK2MS(m->ticks) - epio->lastpoll;
  745. if(elapsed < ep->pollival)
  746. tsleep(&up->sleep, return0, 0, ep->pollival - elapsed);
  747. /* fall through */
  748. case Tctl:
  749. case Tbulk:
  750. /* XXX cache madness */
  751. b = allocb(n + CACHELINESZ);
  752. p = (uchar*)ROUND((uintptr)b->base, CACHELINESZ);
  753. memmove(p, a, n);
  754. cachedwbse(p, n);
  755. if(ep->ttype == Tctl)
  756. n = ctltrans(ep, p, n);
  757. else{
  758. n = eptrans(ep, Write, p, n);
  759. epio->lastpoll = TK2MS(m->ticks);
  760. }
  761. qunlock(epio);
  762. freeb(b);
  763. poperror();
  764. return n;
  765. }
  766. }
  767. static char*
  768. seprintep(char *s, char*, Ep*)
  769. {
  770. return s;
  771. }
  772. static int
  773. portenable(Hci *hp, int port, int on)
  774. {
  775. Ctlr *ctlr;
  776. Dwcregs *r;
  777. assert(port == 1);
  778. ctlr = hp->aux;
  779. r = ctlr->regs;
  780. dprint("usbotg enable=%d; sts %#x\n", on, r->hport0);
  781. if(!on)
  782. r->hport0 = Prtpwr | Prtena;
  783. tsleep(&up->sleep, return0, 0, Enabledelay);
  784. dprint("usbotg enable=%d; sts %#x\n", on, r->hport0);
  785. return 0;
  786. }
  787. static int
  788. portreset(Hci *hp, int port, int on)
  789. {
  790. Ctlr *ctlr;
  791. Dwcregs *r;
  792. int b, s;
  793. assert(port == 1);
  794. ctlr = hp->aux;
  795. r = ctlr->regs;
  796. dprint("usbotg reset=%d; sts %#x\n", on, r->hport0);
  797. if(!on)
  798. return 0;
  799. r->hport0 = Prtpwr | Prtrst;
  800. tsleep(&up->sleep, return0, 0, ResetdelayHS);
  801. r->hport0 = Prtpwr;
  802. tsleep(&up->sleep, return0, 0, Enabledelay);
  803. s = r->hport0;
  804. b = s & (Prtconndet|Prtenchng|Prtovrcurrchng);
  805. if(b != 0)
  806. r->hport0 = Prtpwr | b;
  807. dprint("usbotg reset=%d; sts %#x\n", on, s);
  808. if((s & Prtena) == 0)
  809. print("usbotg: host port not enabled after reset");
  810. return 0;
  811. }
  812. static int
  813. portstatus(Hci *hp, int port)
  814. {
  815. Ctlr *ctlr;
  816. Dwcregs *r;
  817. int b, s;
  818. assert(port == 1);
  819. ctlr = hp->aux;
  820. r = ctlr->regs;
  821. s = r->hport0;
  822. b = s & (Prtconndet|Prtenchng|Prtovrcurrchng);
  823. if(b != 0)
  824. r->hport0 = Prtpwr | b;
  825. b = 0;
  826. if(s & Prtconnsts)
  827. b |= HPpresent;
  828. if(s & Prtconndet)
  829. b |= HPstatuschg;
  830. if(s & Prtena)
  831. b |= HPenable;
  832. if(s & Prtenchng)
  833. b |= HPchange;
  834. if(s & Prtovrcurract)
  835. b |= HPovercurrent;
  836. if(s & Prtsusp)
  837. b |= HPsuspend;
  838. if(s & Prtrst)
  839. b |= HPreset;
  840. if(s & Prtpwr)
  841. b |= HPpower;
  842. switch(s & Prtspd){
  843. case HIGHSPEED:
  844. b |= HPhigh;
  845. break;
  846. case LOWSPEED:
  847. b |= HPslow;
  848. break;
  849. }
  850. return b;
  851. }
  852. static void
  853. shutdown(Hci*)
  854. {
  855. }
  856. static void
  857. setdebug(Hci*, int d)
  858. {
  859. debug = d;
  860. }
  861. static int
  862. reset(Hci *hp)
  863. {
  864. Ctlr *ctlr;
  865. uint id;
  866. ctlr = &dwc;
  867. if(ctlr->regs != nil)
  868. return -1;
  869. ctlr->regs = (Dwcregs*)USBREGS;
  870. id = ctlr->regs->gsnpsid;
  871. if((id>>16) != ('O'<<8 | 'T'))
  872. return -1;
  873. dprint("usbotg: rev %d.%3.3x\n", (id>>12)&0xF, id&0xFFF);
  874. intrenable(IRQtimerArm, irqintr, ctlr, 0, "dwc");
  875. hp->aux = ctlr;
  876. hp->port = 0;
  877. hp->irq = IRQusb;
  878. hp->tbdf = 0;
  879. hp->nports = 1;
  880. hp->highspeed = 1;
  881. hp->init = init;
  882. hp->dump = dump;
  883. hp->interrupt = fiqintr;
  884. hp->epopen = epopen;
  885. hp->epclose = epclose;
  886. hp->epread = epread;
  887. hp->epwrite = epwrite;
  888. hp->seprintep = seprintep;
  889. hp->portenable = portenable;
  890. hp->portreset = portreset;
  891. hp->portstatus = portstatus;
  892. hp->shutdown = shutdown;
  893. hp->debug = setdebug;
  894. hp->type = "dwcotg";
  895. return 0;
  896. }
  897. void
  898. usbdwclink(void)
  899. {
  900. addhcitype("dwcotg", reset);
  901. }