Commit 14f651a8 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: omap_udc updates

This is a collection of updates to the OMAP UDC driver.

  - OMAP-1510 support, including DMA (the DMA controller isn't quite
    the same as on newer chips) but not double buffering.

  - Some PIO work:

      * fix some races that showed up on OMAP-1510

      * tracking down annoying PIO-OUT lossage and making double buffering
        start to behave (needed as fallback if all DMA channels are in use).

  - DMA-IN works on both 1510 and 16xx

Plus minor cleanups.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 14bfb615
...@@ -59,15 +59,14 @@ ...@@ -59,15 +59,14 @@
#undef USB_TRACE #undef USB_TRACE
/* OUT-dma seems to be behaving */ /* bulk DMA seems to be behaving for both IN and OUT */
#define USE_DMA #define USE_DMA
/* ISO too */ /* ISO too */
#define USE_ISO #define USE_ISO
#define DRIVER_DESC "OMAP UDC driver" #define DRIVER_DESC "OMAP UDC driver"
#define DRIVER_VERSION "24 August 2004" #define DRIVER_VERSION "4 October 2004"
#define DMA_ADDR_INVALID (~(dma_addr_t)0) #define DMA_ADDR_INVALID (~(dma_addr_t)0)
...@@ -104,7 +103,6 @@ static unsigned fifo_mode = 0; ...@@ -104,7 +103,6 @@ static unsigned fifo_mode = 0;
module_param (fifo_mode, uint, 0); module_param (fifo_mode, uint, 0);
MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)"); MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
#ifdef USE_DMA #ifdef USE_DMA
static unsigned use_dma = 1; static unsigned use_dma = 1;
...@@ -224,18 +222,17 @@ static int omap_ep_enable(struct usb_ep *_ep, ...@@ -224,18 +222,17 @@ static int omap_ep_enable(struct usb_ep *_ep,
list_add(&ep->iso, &udc->iso); list_add(&ep->iso, &udc->iso);
/* maybe assign a DMA channel to this endpoint */ /* maybe assign a DMA channel to this endpoint */
if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK)
&& !(ep->bEndpointAddress & USB_DIR_IN)) /* FIXME ISO can dma, but prefers first channel */
/* FIXME ISO can dma, but prefers first channel.
* IN can dma, but lacks debugging.
*/
dma_channel_claim(ep, 0); dma_channel_claim(ep, 0);
/* PIO OUT may RX packets */ /* PIO OUT may RX packets */
if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
&& !ep->has_dma && !ep->has_dma
&& !(ep->bEndpointAddress & USB_DIR_IN)) && !(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
VDBG("%s enabled\n", _ep->name); VDBG("%s enabled\n", _ep->name);
...@@ -262,6 +259,7 @@ static int omap_ep_disable(struct usb_ep *_ep) ...@@ -262,6 +259,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
ep->has_dma = 0; ep->has_dma = 0;
UDC_CTRL_REG = UDC_SET_HALT; UDC_CTRL_REG = UDC_SET_HALT;
list_del_init(&ep->iso); list_del_init(&ep->iso);
del_timer(&ep->timer);
spin_unlock_irqrestore(&ep->udc->lock, flags); spin_unlock_irqrestore(&ep->udc->lock, flags);
...@@ -498,17 +496,22 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) ...@@ -498,17 +496,22 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
u16 ep_stat = UDC_STAT_FLG_REG; u16 ep_stat = UDC_STAT_FLG_REG;
is_last = 0; is_last = 0;
if (ep_stat & FIFO_UNREADABLE) if (ep_stat & FIFO_EMPTY) {
if (!ep->double_buf)
break;
ep->fnf = 1;
}
if (ep_stat & UDC_EP_HALTED)
break; break;
if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL)) if (ep_stat & FIFO_FULL)
avail = ep->ep.maxpacket; avail = ep->ep.maxpacket;
else else {
avail = UDC_RXFSTAT_REG; avail = UDC_RXFSTAT_REG;
ep->fnf = ep->double_buf;
}
count = read_packet(buf, req, avail); count = read_packet(buf, req, avail);
// FIXME double buffered PIO OUT wasn't behaving...
/* partial packet reads may not be errors */ /* partial packet reads may not be errors */
if (count < ep->ep.maxpacket) { if (count < ep->ep.maxpacket) {
is_last = 1; is_last = 1;
...@@ -526,26 +529,56 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) ...@@ -526,26 +529,56 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
if (!ep->bEndpointAddress) if (!ep->bEndpointAddress)
break; break;
if (!ep->double_buf) { if (is_last)
UDC_CTRL_REG = UDC_SET_FIFO_EN;
if (!is_last)
break;
}
if (is_last) {
done(ep, req, 0); done(ep, req, 0);
if (list_empty(&ep->queue) || !ep->double_buf)
break; break;
req = container_of(ep->queue.next,
struct omap_req, queue);
is_last = 0;
}
} }
return is_last; return is_last;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
/* IN-DMA needs this on fault/cancel paths, so 15xx misreports
* the last transfer's bytecount by more than a FIFO's worth.
*/
if (cpu_is_omap15xx())
return 0;
end = omap_readw(OMAP_DMA_CSAC(ep->lch));
if (end == ep->dma_counter)
return 0;
end |= start & (0xffff << 16);
if (end < start)
end += 0x10000;
return end - start;
}
#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
? OMAP_DMA_CSAC(x) /* really: CPC */ \
: OMAP_DMA_CDAC(x))
static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
end = omap_readw(DMA_DEST_LAST(ep->lch));
if (end == ep->dma_counter)
return 0;
end |= start & (0xffff << 16);
if (cpu_is_omap15xx())
end++;
if (end < start)
end += 0x10000;
return end - start;
}
/* Each USB transfer request using DMA maps to one or more DMA transfers. /* Each USB transfer request using DMA maps to one or more DMA transfers.
* When DMA completion isn't request completion, the UDC continues with * When DMA completion isn't request completion, the UDC continues with
* the next DMA transfer for that USB transfer. * the next DMA transfer for that USB transfer.
...@@ -555,26 +588,29 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) ...@@ -555,26 +588,29 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
{ {
u16 txdma_ctrl; u16 txdma_ctrl;
unsigned length = req->req.length - req->req.actual; unsigned length = req->req.length - req->req.actual;
const int sync_mode = cpu_is_omap15xx()
? OMAP_DMA_SYNC_FRAME
: OMAP_DMA_SYNC_ELEMENT;
/* measure length in either bytes or packets */ /* measure length in either bytes or packets */
if (length <= (UDC_TXN_TSC + 1)) { if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length; txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
length, 1, OMAP_DMA_SYNC_ELEMENT); length, 1, sync_mode);
} else { } else {
length = max(length / ep->maxpacket, length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1); (unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length; txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
ep->ep.maxpacket, length, ep->ep.maxpacket, length, sync_mode);
OMAP_DMA_SYNC_ELEMENT);
length *= ep->maxpacket; length *= ep->maxpacket;
} }
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
omap_start_dma(ep->lch); omap_start_dma(ep->lch);
ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
req->dma_bytes = length; req->dma_bytes = length;
...@@ -592,14 +628,9 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) ...@@ -592,14 +628,9 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
&& req->dma_bytes != 0 && req->dma_bytes != 0
&& (req->req.actual % ep->maxpacket) == 0) && (req->req.actual % ep->maxpacket) == 0)
return; return;
} else { } else
u32 last; req->req.actual += dma_src_len(ep, req->req.dma
+ req->req.actual);
// FIXME this surely isn't #bytes transferred
last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16)
| omap_readw(OMAP_DMA_CSSA_L(ep->lch));
req->req.actual = last - req->req.dma;
}
/* tx completion */ /* tx completion */
omap_stop_dma(ep->lch); omap_stop_dma(ep->lch);
...@@ -624,6 +655,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) ...@@ -624,6 +655,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
OMAP_DMA_SYNC_ELEMENT); OMAP_DMA_SYNC_ELEMENT);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
...@@ -638,11 +670,9 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) ...@@ -638,11 +670,9 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
{ {
u16 count; u16 count;
/* FIXME must be a better way to see how much dma if (status == 0)
* happened, even when it never got going... ep->dma_counter = (u16) (req->req.dma + req->req.actual);
*/ count = dma_dest_len(ep, req->req.dma + req->req.actual);
count = omap_readw(OMAP_DMA_CDAC(ep->lch));
count -= 0xffff & (req->req.dma + req->req.actual);
count += req->req.actual; count += req->req.actual;
if (count <= req->req.length) if (count <= req->req.length)
req->req.actual = count; req->req.actual = count;
...@@ -705,7 +735,9 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src) ...@@ -705,7 +735,9 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
if (irq_src & UDC_RXN_CNT) { if (irq_src & UDC_RXN_CNT) {
ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
DBG("%s, RX_CNT irq?\n", ep->ep.name); ep->irqs++;
/* omap15xx does this unasked... */
VDBG("%s, RX_CNT irq?\n", ep->ep.name);
UDC_IRQ_SRC_REG = UDC_RXN_CNT; UDC_IRQ_SRC_REG = UDC_RXN_CNT;
} }
} }
...@@ -778,6 +810,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ...@@ -778,6 +810,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
/* channel type P: hw synch (fifo) */ /* channel type P: hw synch (fifo) */
if (!cpu_is_omap15xx())
omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch)); omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
} }
...@@ -803,6 +836,10 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ...@@ -803,6 +836,10 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
use_ep(ep, UDC_EP_SEL); use_ep(ep, UDC_EP_SEL);
(is_in ? write_fifo : read_fifo)(ep, req); (is_in ? write_fifo : read_fifo)(ep, req);
deselect_ep(); deselect_ep();
if (!is_in) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
/* IN: 6 wait states before it'll tx */ /* IN: 6 wait states before it'll tx */
} }
} }
...@@ -833,24 +870,21 @@ static void dma_channel_release(struct omap_ep *ep) ...@@ -833,24 +870,21 @@ static void dma_channel_release(struct omap_ep *ep)
UDC_TXDMA_CFG_REG &= ~mask; UDC_TXDMA_CFG_REG &= ~mask;
if (req) { if (req) {
if (active)
udelay(50);
finish_in_dma(ep, req, -ECONNRESET); finish_in_dma(ep, req, -ECONNRESET);
if (UDC_TXDMA_CFG_REG & mask)
WARN("%s, SPIN abort TX dma\n", ep->ep.name);
}
/* host may empty the fifo (or not...) */ /* clear FIFO; hosts probably won't empty it */
use_ep(ep, UDC_EP_SEL);
UDC_CTRL_REG = UDC_CLR_EP;
deselect_ep();
}
while (UDC_TXDMA_CFG_REG & mask) while (UDC_TXDMA_CFG_REG & mask)
udelay(10); udelay(10);
} else { } else {
UDC_RXDMA_CFG_REG &= ~mask; UDC_RXDMA_CFG_REG &= ~mask;
/* dma empties the fifo */ /* dma empties the fifo */
while (active && (UDC_RXDMA_CFG_REG & mask)) while (UDC_RXDMA_CFG_REG & mask)
udelay(10); udelay(10);
omap_stop_dma(ep->lch);
if (req) if (req)
finish_out_dma(ep, req, -ECONNRESET); finish_out_dma(ep, req, -ECONNRESET);
} }
...@@ -997,6 +1031,10 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) ...@@ -997,6 +1031,10 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
req = 0; req = 0;
deselect_ep(); deselect_ep();
if (!is_in) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
/* IN: 6 wait states before it'll tx */ /* IN: 6 wait states before it'll tx */
} }
} }
...@@ -1034,7 +1072,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ...@@ -1034,7 +1072,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) { if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) {
int channel = ep->dma_channel; int channel = ep->dma_channel;
/* releasing the dma completion cancels the request, /* releasing the channel cancels the request,
* reclaiming the channel restarts the queue * reclaiming the channel restarts the queue
*/ */
dma_channel_release(ep); dma_channel_release(ep);
...@@ -1104,8 +1142,10 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) ...@@ -1104,8 +1142,10 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
use_ep(ep, 0); use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP; UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0; ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
} }
} }
done: done:
...@@ -1218,7 +1258,7 @@ static void pullup_disable(struct omap_udc *udc) ...@@ -1218,7 +1258,7 @@ static void pullup_disable(struct omap_udc *udc)
/* /*
* Called by whatever detects VBUS sessions: external transceiver * Called by whatever detects VBUS sessions: external transceiver
* driver, or maybe GPIO0 VBUS IRQ. * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
*/ */
static int omap_vbus_session(struct usb_gadget *gadget, int is_active) static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
{ {
...@@ -1229,6 +1269,13 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active) ...@@ -1229,6 +1269,13 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
spin_lock_irqsave(&udc->lock, flags); spin_lock_irqsave(&udc->lock, flags);
VDBG("VBUS %s\n", is_active ? "on" : "off"); VDBG("VBUS %s\n", is_active ? "on" : "off");
udc->vbus_active = (is_active != 0); udc->vbus_active = (is_active != 0);
if (cpu_is_omap15xx()) {
/* "software" detect, ignored if !VBUS_MODE_1510 */
if (is_active)
FUNC_MUX_CTRL_0_REG |= VBUS_CTRL_1510;
else
FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
}
if (can_pullup(udc)) if (can_pullup(udc))
pullup_enable(udc); pullup_enable(udc);
else else
...@@ -1342,8 +1389,15 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) ...@@ -1342,8 +1389,15 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* Clear any pending requests and then scrub any rx/tx state /* Clear any pending requests and then scrub any rx/tx state
* before starting to handle the SETUP request. * before starting to handle the SETUP request.
*/ */
if (irq_src & UDC_SETUP) if (irq_src & UDC_SETUP) {
u16 ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX);
nuke(ep0, 0); nuke(ep0, 0);
if (ack) {
UDC_IRQ_SRC_REG = ack;
irq_src = UDC_SETUP;
}
}
/* IN/OUT packets mean we're in the DATA or STATUS stage. /* IN/OUT packets mean we're in the DATA or STATUS stage.
* This driver uses only uses protocol stalls (ep0 never halts), * This driver uses only uses protocol stalls (ep0 never halts),
...@@ -1508,8 +1562,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) ...@@ -1508,8 +1562,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
use_ep(ep, 0); use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP; UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0; ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
} }
VDBG("%s halt cleared by host\n", ep->name); VDBG("%s halt cleared by host\n", ep->name);
goto ep0out_status_stage; goto ep0out_status_stage;
...@@ -1743,6 +1799,39 @@ omap_udc_irq(int irq, void *_udc, struct pt_regs *r) ...@@ -1743,6 +1799,39 @@ omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
return status; return status;
} }
/* workaround for seemingly-lost IRQs for RX ACKs... */
#define PIO_OUT_TIMEOUT (jiffies + HZ/3)
#define HALF_FULL(f) (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))
static void pio_out_timer(unsigned long _ep)
{
struct omap_ep *ep = (void *) _ep;
unsigned long flags;
u16 stat_flg;
spin_lock_irqsave(&ep->udc->lock, flags);
if (!list_empty(&ep->queue) && ep->ackwait) {
use_ep(ep, 0);
stat_flg = UDC_STAT_FLG_REG;
if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
|| (ep->double_buf && HALF_FULL(stat_flg)))) {
struct omap_req *req;
VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
req = container_of(ep->queue.next,
struct omap_req, queue);
UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
(void) read_fifo(ep, req);
UDC_EP_NUM_REG = ep->bEndpointAddress;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
}
mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
spin_unlock_irqrestore(&ep->udc->lock, flags);
}
static irqreturn_t static irqreturn_t
omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
{ {
...@@ -1766,38 +1855,56 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) ...@@ -1766,38 +1855,56 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
ep = &udc->ep[epnum]; ep = &udc->ep[epnum];
ep->irqs++; ep->irqs++;
if (!list_empty(&ep->queue)) {
UDC_EP_NUM_REG = epnum | UDC_EP_SEL; UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
ep->fnf = 0;
if ((UDC_STAT_FLG_REG & UDC_ACK)) { if ((UDC_STAT_FLG_REG & UDC_ACK)) {
ep->ackwait--;
if (!list_empty(&ep->queue)) {
int stat; int stat;
req = container_of(ep->queue.next, req = container_of(ep->queue.next,
struct omap_req, queue); struct omap_req, queue);
stat = read_fifo(ep, req); stat = read_fifo(ep, req);
// FIXME double buffered PIO OUT should work if (!ep->double_buf)
ep->fnf = 1;
}
} }
/* min 6 clock delay before clearing EP_SEL ... */
epn_stat = UDC_EPN_STAT_REG;
epn_stat = UDC_EPN_STAT_REG;
UDC_EP_NUM_REG = epnum; UDC_EP_NUM_REG = epnum;
/* enabling fifo _after_ clearing ACK, contrary to docs,
* reduces lossage; timer still needed though (sigh).
*/
if (ep->fnf) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
} }
mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
} }
/* then IN transfers */ /* then IN transfers */
if (irq_src & UDC_EPN_TX) { else if (irq_src & UDC_EPN_TX) {
epnum = epn_stat & 0x0f; epnum = epn_stat & 0x0f;
UDC_IRQ_SRC_REG = UDC_EPN_TX; UDC_IRQ_SRC_REG = UDC_EPN_TX;
status = IRQ_HANDLED; status = IRQ_HANDLED;
ep = &udc->ep[16 + epnum]; ep = &udc->ep[16 + epnum];
ep->irqs++; ep->irqs++;
ep->ackwait = 0;
if (!list_empty(&ep->queue)) {
UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL; UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
if ((UDC_STAT_FLG_REG & UDC_ACK)) { if ((UDC_STAT_FLG_REG & UDC_ACK)) {
ep->ackwait = 0;
if (!list_empty(&ep->queue)) {
req = container_of(ep->queue.next, req = container_of(ep->queue.next,
struct omap_req, queue); struct omap_req, queue);
(void) write_fifo(ep, req); (void) write_fifo(ep, req);
} }
UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
/* 6 wait states before it'll tx */
} }
/* min 6 clock delay before clearing EP_SEL ... */
epn_stat = UDC_EPN_STAT_REG;
epn_stat = UDC_EPN_STAT_REG;
UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
/* then 6 clocks before it'd tx */
} }
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
...@@ -1939,6 +2046,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) ...@@ -1939,6 +2046,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
pullup_disable (udc); pullup_disable (udc);
} }
if (machine_is_omap_innovator())
omap_vbus_session(&udc->gadget, 1);
done: done:
return status; return status;
} }
...@@ -1954,6 +2064,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) ...@@ -1954,6 +2064,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!driver || driver != udc->driver) if (!driver || driver != udc->driver)
return -EINVAL; return -EINVAL;
if (machine_is_omap_innovator())
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver) if (udc->transceiver)
(void) otg_set_peripheral(udc->transceiver, 0); (void) otg_set_peripheral(udc->transceiver, 0);
else else
...@@ -2002,8 +2115,16 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep) ...@@ -2002,8 +2115,16 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
stat_flg = UDC_STAT_FLG_REG; stat_flg = UDC_STAT_FLG_REG;
seq_printf(s, seq_printf(s,
"\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n", "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
ep->name, buf, ep->irqs, stat_flg, ep->name, buf,
ep->double_buf ? "dbuf " : "",
({char *s; switch(ep->ackwait){
case 0: s = ""; break;
case 1: s = "(ackw) "; break;
case 2: s = "(ackw2) "; break;
default: s = "(?) "; break;
} s;}),
ep->irqs, stat_flg,
(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "", (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
(stat_flg & UDC_MISS_IN) ? "miss_in " : "", (stat_flg & UDC_MISS_IN) ? "miss_in " : "",
(stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "", (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "",
...@@ -2021,10 +2142,19 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep) ...@@ -2021,10 +2142,19 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
if (list_empty (&ep->queue)) if (list_empty (&ep->queue))
seq_printf(s, "\t(queue empty)\n"); seq_printf(s, "\t(queue empty)\n");
else else
list_for_each_entry (req, &ep->queue, queue) list_for_each_entry (req, &ep->queue, queue) {
unsigned length = req->req.actual;
if (use_dma && buf[0]) {
length += ((ep->bEndpointAddress & USB_DIR_IN)
? dma_src_len : dma_dest_len)
(ep, req->req.dma + length);
buf[0] = 0;
}
seq_printf(s, "\treq %p len %d/%d buf %p\n", seq_printf(s, "\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual, &req->req, length,
req->req.length, req->req.buf); req->req.length, req->req.buf);
}
} }
static char *trx_mode(unsigned m) static char *trx_mode(unsigned m)
...@@ -2125,7 +2255,11 @@ static int proc_udc_show(struct seq_file *s, void *_) ...@@ -2125,7 +2255,11 @@ static int proc_udc_show(struct seq_file *s, void *_)
fifo_mode, fifo_mode,
udc->driver ? udc->driver->driver.name : "(none)", udc->driver ? udc->driver->driver.name : "(none)",
HMC, HMC,
udc->transceiver ? udc->transceiver->label : ""); udc->transceiver ? udc->transceiver->label : "(none)");
seq_printf(s, "ULPD control %04x req %04x status %04x\n",
__REG16(ULPD_CLOCK_CTRL),
__REG16(ULPD_SOFT_REQ),
__REG16(ULPD_STATUS_REQ));
/* OTG controller registers */ /* OTG controller registers */
if (!cpu_is_omap15xx()) if (!cpu_is_omap15xx())
...@@ -2305,10 +2439,10 @@ omap_ep_setup(char *name, u8 addr, u8 type, ...@@ -2305,10 +2439,10 @@ omap_ep_setup(char *name, u8 addr, u8 type,
epn_rxtx |= UDC_EPN_RX_ISO; epn_rxtx |= UDC_EPN_RX_ISO;
dbuf = 1; dbuf = 1;
} else { } else {
/* pio-out could potentially double-buffer, /* double-buffering "not supported" on 15xx,
* as can (should!) DMA-IN * and ignored for PIO-IN on 16xx
*/ */
if (!use_dma || (addr & USB_DIR_IN)) if (!use_dma || cpu_is_omap15xx())
dbuf = 0; dbuf = 0;
switch (maxp) { switch (maxp) {
...@@ -2320,6 +2454,9 @@ omap_ep_setup(char *name, u8 addr, u8 type, ...@@ -2320,6 +2454,9 @@ omap_ep_setup(char *name, u8 addr, u8 type,
} }
if (dbuf && addr) if (dbuf && addr)
epn_rxtx |= UDC_EPN_RX_DB; epn_rxtx |= UDC_EPN_RX_DB;
init_timer(&ep->timer);
ep->timer.function = pio_out_timer;
ep->timer.data = (unsigned long) ep;
} }
if (addr) if (addr)
epn_rxtx |= UDC_EPN_RX_VALID; epn_rxtx |= UDC_EPN_RX_VALID;
...@@ -2509,23 +2646,35 @@ static int __init omap_udc_probe(struct device *dev) ...@@ -2509,23 +2646,35 @@ static int __init omap_udc_probe(struct device *dev)
return -EBUSY; return -EBUSY;
} }
INFO("OMAP UDC rev %d.%d, %s receptacle\n", INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf, UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
config->otg ? "Mini-AB" : "B/Mini-B"); config->otg ? ", Mini-AB" : "");
/* use the mode given to us by board init code */ /* use the mode given to us by board init code */
if (cpu_is_omap15xx()) { if (cpu_is_omap15xx()) {
hmc = HMC_1510; hmc = HMC_1510;
type = "(unknown)"; type = "(unknown)";
/* FIXME may need a GPIO-0 handler to call if (machine_is_omap_innovator()) {
* usb_gadget_vbus_{dis,}connect() on us... /* just set up software VBUS detect, and then
* later rig it so we always report VBUS.
* FIXME without really sensing VBUS, we can't
* know when to turn PULLUP_EN on/off; and that
* means we always "need" the 48MHz clock.
*/ */
u32 tmp = FUNC_MUX_CTRL_0_REG;
FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
tmp |= VBUS_MODE_1510;
tmp &= ~VBUS_CTRL_1510;
FUNC_MUX_CTRL_0_REG = tmp;
}
} else { } else {
hmc = HMC_1610; hmc = HMC_1610;
switch (hmc) { switch (hmc) {
case 3: case 3:
case 11: case 11:
case 16:
case 19: case 19:
case 25: case 25:
xceiv = otg_get_transceiver(); xceiv = otg_get_transceiver();
...@@ -2565,7 +2714,9 @@ static int __init omap_udc_probe(struct device *dev) ...@@ -2565,7 +2714,9 @@ static int __init omap_udc_probe(struct device *dev)
xceiv = 0; xceiv = 0;
// "udc" is now valid // "udc" is now valid
pullup_disable(udc); pullup_disable(udc);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
udc->gadget.is_otg = (config->otg != 0); udc->gadget.is_otg = (config->otg != 0);
#endif
/* USB general purpose IRQ: ep0, state changes, dma, etc */ /* USB general purpose IRQ: ep0, state changes, dma, etc */
status = request_irq(odev->resource[1].start, omap_udc_irq, status = request_irq(odev->resource[1].start, omap_udc_irq,
...@@ -2694,7 +2845,11 @@ static struct device_driver udc_driver = { ...@@ -2694,7 +2845,11 @@ static struct device_driver udc_driver = {
static int __init udc_init(void) static int __init udc_init(void)
{ {
INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc, INFO("%s, version: " DRIVER_VERSION
#ifdef USE_ISO
" (iso)"
#endif
"%s\n", driver_desc,
use_dma ? " (dma)" : ""); use_dma ? " (dma)" : "");
return driver_register(&udc_driver); return driver_register(&udc_driver);
} }
......
...@@ -146,11 +146,14 @@ struct omap_ep { ...@@ -146,11 +146,14 @@ struct omap_ep {
u8 bmAttributes; u8 bmAttributes;
unsigned double_buf:1; unsigned double_buf:1;
unsigned stopped:1; unsigned stopped:1;
unsigned ackwait:1; unsigned fnf:1;
unsigned has_dma:1; unsigned has_dma:1;
u8 ackwait;
u8 dma_channel; u8 dma_channel;
u16 dma_counter;
int lch; int lch;
struct omap_udc *udc; struct omap_udc *udc;
struct timer_list timer;
}; };
struct omap_udc { struct omap_udc {
...@@ -168,7 +171,6 @@ struct omap_udc { ...@@ -168,7 +171,6 @@ struct omap_udc {
unsigned ep0_set_config:1; unsigned ep0_set_config:1;
unsigned ep0_reset_config:1; unsigned ep0_reset_config:1;
unsigned ep0_setup:1; unsigned ep0_setup:1;
unsigned hmc:6;
struct completion *done; struct completion *done;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment