Date: | 2011-04-19 03:15:16 (12 years 11 months ago) |
---|---|
Author: | Lars C. |
Commit: | ef7f1fc4516f6bd90c75ec41123e4f79000003d1 |
Message: | udc |
Files: |
drivers/usb/gadget/jz4740_udc.c (19 diffs) |
Change Details
drivers/usb/gadget/jz4740_udc.c | ||
---|---|---|
58 | 58 | #define JZ_REG_UDC_INMAXP 0x10 /* EP1-2 IN Max Pkt Size 16-bit */ |
59 | 59 | #define JZ_REG_UDC_INCSR 0x12 /* EP1-2 IN CSR LSB 8/16bit */ |
60 | 60 | #define JZ_REG_UDC_INCSRH 0x13 /* EP1-2 IN CSR MSB 8-bit */ |
61 | ||
61 | 62 | #define JZ_REG_UDC_OUTMAXP 0x14 /* EP1 OUT Max Pkt Size 16-bit */ |
62 | 63 | #define JZ_REG_UDC_OUTCSR 0x16 /* EP1 OUT CSR LSB 8/16bit */ |
63 | 64 | #define JZ_REG_UDC_OUTCSRH 0x17 /* EP1 OUT CSR MSB 8-bit */ |
... | ... | |
116 | 117 | #define USB_INCSR_UNDERRUN 0x04 |
117 | 118 | #define USB_INCSR_FFNOTEMPT 0x02 |
118 | 119 | #define USB_INCSR_INPKTRDY 0x01 |
120 | ||
119 | 121 | #define USB_OUTCSRH_AUTOCLR 0x80 |
120 | 122 | #define USB_OUTCSRH_ISO 0x40 |
121 | 123 | #define USB_OUTCSRH_DMAREQENAB 0x20 |
... | ... | |
153 | 155 | # define DEBUG_SETUP(fmt,args...) do {} while(0) |
154 | 156 | #endif |
155 | 157 | |
156 | static unsigned int use_dma = 0; /* 1: use DMA, 0: use PIO */ | |
157 | ||
158 | module_param(use_dma, int, 0); | |
159 | MODULE_PARM_DESC(use_dma, "DMA mode enable flag"); | |
160 | ||
161 | 158 | static struct jz4740_udc jz4740_udc_controller; |
162 | 159 | |
163 | 160 | /* |
... | ... | |
252 | 249 | DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); |
253 | 250 | |
254 | 251 | buf = req->req.buf + req->req.actual; |
255 | prefetch(buf); | |
256 | 252 | |
257 | 253 | length = req->req.length - req->req.actual; |
258 | 254 | if (length > count) |
... | ... | |
261 | 257 | |
262 | 258 | DEBUG("Write %d (count %d), fifo %x\n", length, count, ep->fifo); |
263 | 259 | |
264 | nlong = length >> 2; | |
265 | nbyte = length & 0x3; | |
266 | while (nlong--) { | |
267 | writel(*((uint32_t *)buf), fifo); | |
268 | buf += 4; | |
269 | } | |
270 | while (nbyte--) | |
271 | writeb(*buf++, fifo); | |
260 | memcpy_toio(fifo, buf, length); | |
272 | 261 | |
273 | 262 | return length; |
274 | 263 | } |
... | ... | |
282 | 271 | DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); |
283 | 272 | |
284 | 273 | buf = req->req.buf + req->req.actual; |
285 | prefetchw(buf); | |
286 | 274 | |
287 | 275 | length = req->req.length - req->req.actual; |
288 | 276 | if (length > count) |
289 | 277 | length = count; |
290 | 278 | req->req.actual += length; |
291 | 279 | |
292 | DEBUG("Read %d, fifo %x\n", length, ep->fifo); | |
293 | nlong = length >> 2; | |
294 | nbyte = length & 0x3; | |
295 | while (nlong--) { | |
296 | *((uint32_t *)buf) = readl(fifo); | |
297 | buf += 4; | |
298 | } | |
299 | while (nbyte--) | |
300 | *buf++ = readb(fifo); | |
280 | memcpy_fromio(buf, fifo, length); | |
301 | 281 | |
302 | 282 | return length; |
303 | 283 | } |
... | ... | |
378 | 358 | for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { |
379 | 359 | struct jz4740_ep *ep = &dev->ep[i]; |
380 | 360 | |
381 | jz_udc_set_index(dev, ep_index(ep)); | |
361 | jz_udc_select_ep(ep); | |
382 | 362 | flush(ep); |
383 | 363 | } |
384 | 364 | |
... | ... | |
486 | 466 | |
487 | 467 | ep->stopped = 1; |
488 | 468 | |
489 | jz_udc_set_index(dev, ep_index(ep)); | |
469 | jz_udc_select_ep(ep); | |
490 | 470 | nuke(ep, -ESHUTDOWN); |
491 | 471 | } |
492 | 472 | |
... | ... | |
536 | 516 | |
537 | 517 | /*-------------------------------------------------------------------------*/ |
538 | 518 | |
539 | /* | |
540 | * Starting DMA using mode 1 | |
541 | */ | |
542 | static void kick_dma(struct jz4740_ep *ep, struct jz4740_request *req) | |
543 | { | |
544 | struct jz4740_udc *dev = ep->dev; | |
545 | uint32_t count = req->req.length; | |
546 | uint32_t physaddr = virt_to_phys((void *)req->req.buf); | |
547 | ||
548 | DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); | |
549 | ||
550 | jz_udc_select_ep(ep); | |
551 | ||
552 | if (ep_is_in(ep)) { /* Bulk-IN transfer using DMA channel 1 */ | |
553 | ep->reg_addr = JZ_REG_UDC_ADDR1; | |
554 | ||
555 | dma_cache_wback_inv((unsigned long)req->req.buf, count); | |
556 | ||
557 | pio_irq_enable(ep); | |
558 | ||
559 | usb_writeb(dev, JZ_REG_UDC_INCSRH, | |
560 | USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); | |
561 | ||
562 | usb_writel(dev, JZ_REG_UDC_ADDR1, physaddr); | |
563 | usb_writel(dev, JZ_REG_UDC_COUNT1, count); | |
564 | usb_writel(dev, JZ_REG_UDC_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | | |
565 | USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); | |
566 | } | |
567 | else { /* Bulk-OUT transfer using DMA channel 2 */ | |
568 | ep->reg_addr = JZ_REG_UDC_ADDR2; | |
569 | ||
570 | dma_cache_wback_inv((unsigned long)req->req.buf, count); | |
571 | ||
572 | pio_irq_enable(ep); | |
573 | ||
574 | usb_setb(dev, JZ_REG_UDC_OUTCSRH, | |
575 | USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); | |
576 | ||
577 | usb_writel(dev, JZ_REG_UDC_ADDR2, physaddr); | |
578 | usb_writel(dev, JZ_REG_UDC_COUNT2, count); | |
579 | usb_writel(dev, JZ_REG_UDC_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | | |
580 | USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); | |
581 | } | |
582 | } | |
583 | ||
584 | /*-------------------------------------------------------------------------*/ | |
585 | ||
586 | 519 | /** Write request to FIFO (max write == maxp size) |
587 | 520 | * Return: 0 = still running, 1 = completed, negative = errno |
588 | 521 | * NOTE: INDEX register must be set for EP |
... | ... | |
596 | 529 | DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); |
597 | 530 | max = le16_to_cpu(ep->desc->wMaxPacketSize); |
598 | 531 | |
599 | if (use_dma) { | |
600 | uint32_t dma_count; | |
601 | ||
602 | /* DMA interrupt generated due to the last packet loaded into the FIFO */ | |
603 | ||
604 | dma_count = usb_readl(dev, ep->reg_addr) - physaddr; | |
605 | req->req.actual += dma_count; | |
606 | ||
607 | if (dma_count % max) { | |
608 | /* If the last packet is less than MAXP, set INPKTRDY manually */ | |
609 | usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); | |
610 | } | |
611 | ||
612 | done(ep, req, 0); | |
613 | if (list_empty(&ep->queue)) { | |
614 | pio_irq_disable(ep); | |
615 | return 1; | |
616 | } | |
617 | else { | |
618 | /* advance the request queue */ | |
619 | req = list_entry(ep->queue.next, struct jz4740_request, queue); | |
620 | kick_dma(ep, req); | |
621 | return 0; | |
622 | } | |
623 | } | |
624 | ||
625 | /* | |
626 | * PIO mode handling starts here ... | |
627 | */ | |
628 | ||
629 | 532 | csr = usb_readb(dev, ep->csr); |
630 | 533 | |
631 | 534 | if (!(csr & USB_INCSR_FFNOTEMPT)) { |
... | ... | |
678 | 581 | uint32_t csr; |
679 | 582 | unsigned count, is_short; |
680 | 583 | |
681 | #if 0 | |
682 | uint32_t physaddr = virt_to_phys((void *)req->req.buf); | |
683 | ||
684 | if (use_dma) { | |
685 | uint32_t dma_count; | |
686 | ||
687 | /* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */ | |
688 | ||
689 | dma_count = usb_readl(dev, ep->reg_addr) - physaddr; | |
690 | req->req.actual += dma_count; | |
691 | ||
692 | /* Disable interrupt and DMA */ | |
693 | pio_irq_disable(ep); | |
694 | usb_writel(dev, JZ_REG_UDC_CNTL2, 0); | |
695 | ||
696 | /* Read all bytes from this packet */ | |
697 | count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); | |
698 | count = read_packet(ep, req, count); | |
699 | ||
700 | if (count) { | |
701 | /* If the last packet is greater than zero, clear OUTPKTRDY manually */ | |
702 | usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY); | |
703 | } | |
704 | done(ep, req, 0); | |
705 | ||
706 | if (!list_empty(&ep->queue)) { | |
707 | /* advance the request queue */ | |
708 | req = list_entry(ep->queue.next, struct jz4740_request, queue); | |
709 | kick_dma(ep, req); | |
710 | } | |
711 | ||
712 | return 1; | |
713 | } | |
714 | #endif | |
715 | /* | |
716 | * PIO mode handling starts here ... | |
717 | */ | |
718 | ||
719 | 584 | /* make sure there's a packet in the FIFO. */ |
720 | 585 | csr = usb_readb(dev, ep->csr); |
721 | 586 | if (!(csr & USB_OUTCSR_OUTPKTRDY)) { |
... | ... | |
786 | 651 | ep->stopped = stopped; |
787 | 652 | } |
788 | 653 | |
654 | static inline unsigned int jz4740_udc_ep_irq_enable_reg(struct jz4740_ep *ep) | |
655 | { | |
656 | if (ep_is_in(ep)) | |
657 | return JZ_REG_UDC_INTRINE; | |
658 | else | |
659 | return JZ_REG_UDC_INTROUTE; | |
660 | } | |
661 | ||
789 | 662 | /** Enable EP interrupt */ |
790 | 663 | static void pio_irq_enable(struct jz4740_ep *ep) |
791 | 664 | { |
792 | uint8_t index = ep_index(ep); | |
793 | struct jz4740_udc *dev = ep->dev; | |
794 | 665 | DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); |
795 | 666 | |
796 | if (ep_is_in(ep)) { | |
797 | switch (index) { | |
798 | case 1: | |
799 | case 2: | |
800 | usb_setw(dev, JZ_REG_UDC_INTRINE, BIT(index)); | |
801 | break; | |
802 | default: | |
803 | DEBUG("Unknown endpoint: %d\n", index); | |
804 | break; | |
805 | } | |
806 | } | |
807 | else { | |
808 | switch (index) { | |
809 | case 1: | |
810 | usb_setw(dev, JZ_REG_UDC_INTROUTE, BIT(index)); | |
811 | break; | |
812 | default: | |
813 | DEBUG("Unknown endpoint: %d\n", index); | |
814 | break; | |
815 | } | |
816 | } | |
667 | usb_setw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); | |
817 | 668 | } |
818 | 669 | |
819 | 670 | /** Disable EP interrupt */ |
820 | 671 | static void pio_irq_disable(struct jz4740_ep *ep) |
821 | 672 | { |
822 | uint8_t index = ep_index(ep); | |
823 | ||
824 | 673 | DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); |
825 | 674 | |
826 | if (ep_is_in(ep)) { | |
827 | switch (ep_index(ep)) { | |
828 | case 1: | |
829 | case 2: | |
830 | usb_clearw(ep->dev, JZ_REG_UDC_INTRINE, BIT(index)); | |
831 | break; | |
832 | default: | |
833 | DEBUG("Unknown endpoint: %d\n", index); | |
834 | break; | |
835 | } | |
836 | } | |
837 | else { | |
838 | switch (ep_index(ep)) { | |
839 | case 1: | |
840 | usb_clearw(ep->dev, JZ_REG_UDC_INTROUTE, BIT(index)); | |
841 | break; | |
842 | default: | |
843 | DEBUG("Unknown endpoint: %d\n", index); | |
844 | break; | |
845 | } | |
846 | } | |
675 | usb_clearw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); | |
847 | 676 | } |
848 | 677 | |
849 | 678 | /* |
... | ... | |
899 | 728 | struct jz4740_request *req; |
900 | 729 | DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); |
901 | 730 | |
902 | jz_udc_set_index(dev, ep_index(ep)); | |
731 | jz_udc_select_ep(ep); | |
903 | 732 | |
904 | 733 | csr = usb_readb(dev, ep->csr); |
905 | 734 | DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); |
... | ... | |
935 | 764 | if (ep->desc) { |
936 | 765 | uint32_t csr; |
937 | 766 | |
938 | if (use_dma) { | |
939 | /* DMA starts here ... */ | |
940 | if (!list_empty(&ep->queue)) { | |
941 | req = list_first_entry(&ep->queue, struct jz4740_request, queue); | |
942 | read_fifo(ep, req); | |
943 | } | |
944 | return; | |
945 | } | |
946 | ||
947 | /* | |
948 | * PIO mode starts here ... | |
949 | */ | |
950 | ||
951 | 767 | while ((csr = usb_readb(dev, ep->csr)) & |
952 | 768 | (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { |
953 | 769 | DEBUG("%s: %x\n", __FUNCTION__, csr); |
... | ... | |
1194 | 1010 | { |
1195 | 1011 | struct jz4740_request *req; |
1196 | 1012 | |
1197 | DEBUG("%s, %p\n", __FUNCTION__, ep); | |
1198 | ||
1199 | 1013 | req = container_of(_req, struct jz4740_request, req); |
1200 | 1014 | WARN_ON(!list_empty(&req->queue)); |
1015 | ||
1201 | 1016 | kfree(req); |
1202 | 1017 | } |
1203 | 1018 | |
... | ... | |
1255 | 1070 | list_add_tail(&req->queue, &ep->queue); |
1256 | 1071 | jz4740_ep0_kick(dev, ep); |
1257 | 1072 | req = 0; |
1258 | } else if (use_dma) { | |
1259 | /* DMA */ | |
1260 | kick_dma(ep, req); | |
1261 | 1073 | } |
1262 | /* PIO */ | |
1263 | 1074 | else if (ep_is_in(ep)) { |
1264 | 1075 | /* EP1 & EP2 */ |
1265 | 1076 | jz_udc_select_ep(ep); |
... | ... | |
1651 | 1462 | return -EOPNOTSUPP; |
1652 | 1463 | } |
1653 | 1464 | |
1654 | jz_udc_set_index(dev, ep_index(qep)); | |
1465 | jz_udc_select_ep(ep); | |
1655 | 1466 | |
1656 | 1467 | /* Return status on next IN token */ |
1657 | 1468 | switch (qep->type) { |
... | ... | |
2028 | 1839 | struct jz4740_ep *ep; |
2029 | 1840 | ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL1) >> 4) & 0xf; |
2030 | 1841 | ep = &jz4740_udc->ep[ep_num + 1]; |
2031 | jz_udc_set_index(jz4740_udc, ep_num); | |
1842 | jz_udc_select_ep(ep); | |
2032 | 1843 | usb_setb(jz4740_udc, ep->csr, USB_INCSR_INPKTRDY); |
2033 | 1844 | /* jz4740_in_epn(jz4740_udc, ep_num, intr_in);*/ |
2034 | 1845 | } |
... | ... | |
2338 | 2149 | return 0; |
2339 | 2150 | } |
2340 | 2151 | |
2341 | static const struct dev_pm_ops jz4740_udc_pm_ops = { | |
2342 | .suspend = jz4740_udc_suspend, | |
2343 | .resume = jz4740_udc_resume, | |
2344 | }; | |
2345 | ||
2152 | static SIMPLE_DEV_PM_OPS(jz4740_udc_pm_ops, jz4740_udc_suspend, jz4740_udc_resume); | |
2346 | 2153 | #define JZ4740_UDC_PM_OPS (&jz4740_udc_pm_ops) |
2347 | 2154 | |
2348 | 2155 | #else |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9