diff options
author | Ajay Kumar Gupta <ajay.gupta@ti.com> | 2009-04-03 19:16:17 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-16 00:44:41 -0400 |
commit | a483d7068f661213e9586d4d132fc0e0287118b4 (patch) | |
tree | ff575463eacee555e070a2d2a049f7ac37d9fb38 | |
parent | d1043a2697effee3054451a9293a376bfb013e4b (diff) |
musb: add high bandwidth ISO support
Tested on OMAP3 host side with Creative (Live! Cam Optia) USB camera
which uses high bandwidth isochronous IN endpoints. FIFO mode 4 is
updated to provide the needed 4K endpoint buffer without breaking
the g_nokia composite gadget configuration. (This is the only
gadget driver known to use enough endpoints to notice the change.)
Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r-- | drivers/usb/musb/musb_core.c | 19 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 3 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 47 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.h | 1 |
4 files changed, 48 insertions, 22 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b49859623f8d..554a414f65d1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -1084,14 +1084,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = { | |||
1084 | { .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, }, | 1084 | { .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, }, |
1085 | { .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, }, | 1085 | { .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, }, |
1086 | { .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, }, | 1086 | { .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, }, |
1087 | { .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, }, | 1087 | { .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 256, }, |
1088 | { .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, }, | 1088 | { .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 64, }, |
1089 | { .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, }, | 1089 | { .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 256, }, |
1090 | { .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, }, | 1090 | { .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 64, }, |
1091 | { .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, }, | 1091 | { .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 256, }, |
1092 | { .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, }, | 1092 | { .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 64, }, |
1093 | { .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, }, | 1093 | { .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, }, |
1094 | { .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, }, | ||
1095 | { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, | 1094 | { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, |
1096 | { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, | 1095 | { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, |
1097 | }; | 1096 | }; |
@@ -1351,11 +1350,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) | |||
1351 | } | 1350 | } |
1352 | if (reg & MUSB_CONFIGDATA_HBRXE) { | 1351 | if (reg & MUSB_CONFIGDATA_HBRXE) { |
1353 | strcat(aInfo, ", HB-ISO Rx"); | 1352 | strcat(aInfo, ", HB-ISO Rx"); |
1354 | strcat(aInfo, " (X)"); /* no driver support */ | 1353 | musb->hb_iso_rx = true; |
1355 | } | 1354 | } |
1356 | if (reg & MUSB_CONFIGDATA_HBTXE) { | 1355 | if (reg & MUSB_CONFIGDATA_HBTXE) { |
1357 | strcat(aInfo, ", HB-ISO Tx"); | 1356 | strcat(aInfo, ", HB-ISO Tx"); |
1358 | strcat(aInfo, " (X)"); /* no driver support */ | 1357 | musb->hb_iso_tx = true; |
1359 | } | 1358 | } |
1360 | if (reg & MUSB_CONFIGDATA_SOFTCONE) | 1359 | if (reg & MUSB_CONFIGDATA_SOFTCONE) |
1361 | strcat(aInfo, ", SoftConn"); | 1360 | strcat(aInfo, ", SoftConn"); |
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 78116fdb5781..f3772ca3b2cf 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -395,6 +395,9 @@ struct musb { | |||
395 | unsigned is_multipoint:1; | 395 | unsigned is_multipoint:1; |
396 | unsigned ignore_disconnect:1; /* during bus resets */ | 396 | unsigned ignore_disconnect:1; /* during bus resets */ |
397 | 397 | ||
398 | unsigned hb_iso_rx:1; /* high bandwidth iso rx? */ | ||
399 | unsigned hb_iso_tx:1; /* high bandwidth iso tx? */ | ||
400 | |||
398 | #ifdef C_MP_TX | 401 | #ifdef C_MP_TX |
399 | unsigned bulk_split:1; | 402 | unsigned bulk_split:1; |
400 | #define can_bulk_split(musb,type) \ | 403 | #define can_bulk_split(musb,type) \ |
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 0d1f15336a9c..94a2a350a414 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c | |||
@@ -605,7 +605,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) | |||
605 | musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg); | 605 | musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg); |
606 | musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg); | 606 | musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg); |
607 | /* NOTE: bulk combining rewrites high bits of maxpacket */ | 607 | /* NOTE: bulk combining rewrites high bits of maxpacket */ |
608 | musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket); | 608 | musb_writew(ep->regs, MUSB_RXMAXP, |
609 | qh->maxpacket | ((qh->hb_mult - 1) << 11)); | ||
609 | 610 | ||
610 | ep->rx_reinit = 0; | 611 | ep->rx_reinit = 0; |
611 | } | 612 | } |
@@ -627,9 +628,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma, | |||
627 | csr = musb_readw(epio, MUSB_TXCSR); | 628 | csr = musb_readw(epio, MUSB_TXCSR); |
628 | if (length > pkt_size) { | 629 | if (length > pkt_size) { |
629 | mode = 1; | 630 | mode = 1; |
630 | csr |= MUSB_TXCSR_AUTOSET | 631 | csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB; |
631 | | MUSB_TXCSR_DMAMODE | 632 | /* autoset shouldn't be set in high bandwidth */ |
632 | | MUSB_TXCSR_DMAENAB; | 633 | if (qh->hb_mult == 1) |
634 | csr |= MUSB_TXCSR_AUTOSET; | ||
633 | } else { | 635 | } else { |
634 | mode = 0; | 636 | mode = 0; |
635 | csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); | 637 | csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); |
@@ -1497,6 +1499,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1497 | /* packet error reported later */ | 1499 | /* packet error reported later */ |
1498 | iso_err = true; | 1500 | iso_err = true; |
1499 | } | 1501 | } |
1502 | } else if (rx_csr & MUSB_RXCSR_INCOMPRX) { | ||
1503 | DBG(3, "end %d high bandwidth incomplete ISO packet RX\n", | ||
1504 | epnum); | ||
1505 | status = -EPROTO; | ||
1500 | } | 1506 | } |
1501 | 1507 | ||
1502 | /* faults abort the transfer */ | 1508 | /* faults abort the transfer */ |
@@ -1704,7 +1710,11 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1704 | val &= ~MUSB_RXCSR_H_AUTOREQ; | 1710 | val &= ~MUSB_RXCSR_H_AUTOREQ; |
1705 | else | 1711 | else |
1706 | val |= MUSB_RXCSR_H_AUTOREQ; | 1712 | val |= MUSB_RXCSR_H_AUTOREQ; |
1707 | val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB; | 1713 | val |= MUSB_RXCSR_DMAENAB; |
1714 | |||
1715 | /* autoclear shouldn't be set in high bandwidth */ | ||
1716 | if (qh->hb_mult == 1) | ||
1717 | val |= MUSB_RXCSR_AUTOCLEAR; | ||
1708 | 1718 | ||
1709 | musb_writew(epio, MUSB_RXCSR, | 1719 | musb_writew(epio, MUSB_RXCSR, |
1710 | MUSB_RXCSR_H_WZC_BITS | val); | 1720 | MUSB_RXCSR_H_WZC_BITS | val); |
@@ -1790,9 +1800,10 @@ static int musb_schedule( | |||
1790 | continue; | 1800 | continue; |
1791 | 1801 | ||
1792 | if (is_in) | 1802 | if (is_in) |
1793 | diff = hw_ep->max_packet_sz_rx - qh->maxpacket; | 1803 | diff = hw_ep->max_packet_sz_rx; |
1794 | else | 1804 | else |
1795 | diff = hw_ep->max_packet_sz_tx - qh->maxpacket; | 1805 | diff = hw_ep->max_packet_sz_tx; |
1806 | diff -= (qh->maxpacket * qh->hb_mult); | ||
1796 | 1807 | ||
1797 | if (diff >= 0 && best_diff > diff) { | 1808 | if (diff >= 0 && best_diff > diff) { |
1798 | best_diff = diff; | 1809 | best_diff = diff; |
@@ -1895,15 +1906,27 @@ static int musb_urb_enqueue( | |||
1895 | qh->is_ready = 1; | 1906 | qh->is_ready = 1; |
1896 | 1907 | ||
1897 | qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize); | 1908 | qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize); |
1909 | qh->type = usb_endpoint_type(epd); | ||
1898 | 1910 | ||
1899 | /* no high bandwidth support yet */ | 1911 | /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier. |
1900 | if (qh->maxpacket & ~0x7ff) { | 1912 | * Some musb cores don't support high bandwidth ISO transfers; and |
1901 | ret = -EMSGSIZE; | 1913 | * we don't (yet!) support high bandwidth interrupt transfers. |
1902 | goto done; | 1914 | */ |
1915 | qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03); | ||
1916 | if (qh->hb_mult > 1) { | ||
1917 | int ok = (qh->type == USB_ENDPOINT_XFER_ISOC); | ||
1918 | |||
1919 | if (ok) | ||
1920 | ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx) | ||
1921 | || (usb_pipeout(urb->pipe) && musb->hb_iso_tx); | ||
1922 | if (!ok) { | ||
1923 | ret = -EMSGSIZE; | ||
1924 | goto done; | ||
1925 | } | ||
1926 | qh->maxpacket &= 0x7ff; | ||
1903 | } | 1927 | } |
1904 | 1928 | ||
1905 | qh->epnum = usb_endpoint_num(epd); | 1929 | qh->epnum = usb_endpoint_num(epd); |
1906 | qh->type = usb_endpoint_type(epd); | ||
1907 | 1930 | ||
1908 | /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */ | 1931 | /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */ |
1909 | qh->addr_reg = (u8) usb_pipedevice(urb->pipe); | 1932 | qh->addr_reg = (u8) usb_pipedevice(urb->pipe); |
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 0b7fbcd21963..14b00776638d 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h | |||
@@ -67,6 +67,7 @@ struct musb_qh { | |||
67 | u8 is_ready; /* safe to modify hw_ep */ | 67 | u8 is_ready; /* safe to modify hw_ep */ |
68 | u8 type; /* XFERTYPE_* */ | 68 | u8 type; /* XFERTYPE_* */ |
69 | u8 epnum; | 69 | u8 epnum; |
70 | u8 hb_mult; /* high bandwidth pkts per uf */ | ||
70 | u16 maxpacket; | 71 | u16 maxpacket; |
71 | u16 frame; /* for periodic schedule */ | 72 | u16 frame; /* for periodic schedule */ |
72 | unsigned iso_idx; /* in urb->iso_frame_desc[] */ | 73 | unsigned iso_idx; /* in urb->iso_frame_desc[] */ |