// SPDX-License-Identifier: GPL-2.0+ /* * omap_udc.c -- for OMAP full speed udc; most chips support OTG. * * Copyright (C) 2004 Texas Instruments, Inc. * Copyright (C) 2004-2005 David Brownell * * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com>
*/
/* * The OMAP UDC needs _very_ early endpoint setup: before enabling the * D+ pullup to allow enumeration. That's too early for the gadget * framework to use from usb_endpoint_enable(), which happens after * enumeration as part of activating an interface. (But if we add an * optional new "UDC not yet running" state to the gadget driver model, * even just during driver binding, the endpoint autoconfig logic is the * natural spot to manufacture new endpoints.) * * So instead of using endpoint enable calls to control the hardware setup, * this driver defines a "fifo mode" parameter. It's used during driver * initialization to choose among a set of pre-defined endpoint configs. * See omap_udc_setup() for available modes, or to add others. That code * lives in an init section, so use this driver as a module if you need * to change the fifo mode after the kernel boots. * * Gadget drivers normally ignore endpoints they don't care about, and * won't include them in configuration descriptors. That means only * misbehaving hosts would even notice they exist.
*/ #ifdef USE_ISO staticunsigned fifo_mode = 3; #else staticunsigned fifo_mode; #endif
/* "modprobe omap_udc fifo_mode=42", or else as a kernel * boot parameter "omap_udc:fifo_mode=42"
*/
module_param(fifo_mode, uint, 0);
MODULE_PARM_DESC(fifo_mode, "endpoint configuration");
#ifdef USE_DMA staticbool use_dma = 1;
/* "modprobe omap_udc use_dma=y", or else as a kernel * boot parameter "omap_udc:use_dma=y"
*/
module_param(use_dma, bool, 0);
MODULE_PARM_DESC(use_dma, "enable/disable DMA"); #else/* !USE_DMA */
/* save a bit of code */ #define use_dma 0 #endif/* !USE_DMA */
/* set endpoint to initial state */
ep->dma_channel = 0;
ep->has_dma = 0;
ep->lch = -1;
use_ep(ep, UDC_EP_SEL);
omap_writew(udc->clr_halt, UDC_CTRL);
ep->ackwait = 0;
deselect_ep();
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
list_add(&ep->iso, &udc->iso);
/* maybe assign a DMA channel to this endpoint */ if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK) /* FIXME ISO can dma, but prefers first channel */
dma_channel_claim(ep, 0);
/* PIO OUT may RX packets */ if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
&& !ep->has_dma
&& !(ep->bEndpointAddress & USB_DIR_IN)) {
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
ep->ackwait = 1 + ep->double_buf;
}
/* last packet is often short (sometimes a zlp) */ if (count != ep->ep.maxpacket)
is_last = 1; elseif (req->req.length == req->req.actual
&& !req->req.zero)
is_last = 1; else
is_last = 0;
/* NOTE: requests complete when all IN data is in a * FIFO (or sometimes later, if a zlp was needed). * Use usb_ep_fifo_status() where needed.
*/ if (is_last)
done(ep, req, 0); return is_last;
}
/* 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_get_dma_src_pos(ep->lch); if (end == ep->dma_counter) return 0;
end |= start & (0xffff << 16); if (end < start)
end += 0x10000; return end - start;
}
end = omap_get_dma_dst_pos(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. * When DMA completion isn't request completion, the UDC continues with * the next DMA transfer for that USB transfer.
*/
/* catch various bogus parameters */ if (!_req || !req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
DBG("%s, bad params\n", __func__); return -EINVAL;
} if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) {
DBG("%s, bad ep\n", __func__); return -EINVAL;
} if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE;
is_iso = 1;
}
/* this isn't bogus, but OMAP DMA isn't the only hardware to * have a hard time with partial packet reads... reject it.
*/ if (use_dma
&& ep->has_dma
&& ep->bEndpointAddress != 0
&& (ep->bEndpointAddress & USB_DIR_IN) == 0
&& (req->req.length % ep->ep.maxpacket) != 0) {
DBG("%s, no partial packet OUT reads\n", __func__); return -EMSGSIZE;
}
w = omap_readw(UDC_IRQ_EN);
w |= UDC_SOF_IE;
omap_writew(w, UDC_IRQ_EN);
} elseif (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { int is_in;
if (ep->bEndpointAddress == 0) { if (!udc->ep0_pending || !list_empty(&ep->queue)) {
spin_unlock_irqrestore(&udc->lock, flags); return -EL2HLT;
}
/* empty DATA stage? */
is_in = udc->ep0_in; if (!req->req.length) {
/* chip became CONFIGURED or ADDRESSED * earlier; drivers may already have queued * requests to non-control endpoints
*/ if (udc->ep0_set_config) {
u16 irq_en = omap_readw(UDC_IRQ_EN);
/* STATUS for zero length DATA stages is * always an IN ... even for IN transfers, * a weird case which seem to stall OMAP.
*/
omap_writew(UDC_EP_SEL | UDC_EP_DIR,
UDC_EP_NUM);
omap_writew(UDC_CLR_EP, UDC_CTRL);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
staticint omap_ep_set_halt(struct usb_ep *_ep, int value)
{ struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); unsignedlong flags; int status = -EOPNOTSUPP;
spin_lock_irqsave(&ep->udc->lock, flags);
/* just use protocol stalls for ep0; real halts are annoying */ if (ep->bEndpointAddress == 0) { if (!ep->udc->ep0_pending)
status = -EINVAL; elseif (value) { if (ep->udc->ep0_set_config) {
WARNING("error changing config?\n");
omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
}
omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
ep->udc->ep0_pending = 0;
status = 0;
} else/* NOP */
status = 0;
/* otherwise, all active non-ISO endpoints can halt */
} elseif (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) {
/* IN endpoints must already be idle */ if ((ep->bEndpointAddress & USB_DIR_IN)
&& !list_empty(&ep->queue)) {
status = -EAGAIN; goto done;
}
if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx()) {
u32 l;
l = omap_readl(OTG_CTRL);
l &= ~OTG_BSESSVLD;
omap_writel(l, OTG_CTRL);
}
omap_writew(UDC_DS_CHG_IE, UDC_IRQ_EN);
w = omap_readw(UDC_SYSCON1);
w &= ~UDC_PULLUP_EN;
omap_writew(w, UDC_SYSCON1);
}
/* Clear any pending requests and then scrub any rx/tx state * before starting to handle the SETUP request.
*/ if (irq_src & UDC_SETUP) {
u16 ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX);
/* IN/OUT packets mean we're in the DATA or STATUS stage. * This driver uses only uses protocol stalls (ep0 never halts), * and if we got this far the gadget driver already had a * chance to stall. Tries to be forgiving of host oddities. * * NOTE: the last chance gadget drivers have to stall control * requests is during their request completion callback.
*/ if (!list_empty(&ep0->queue))
req = container_of(ep0->queue.next, struct omap_req, queue);
/* IN == TX to host */ if (irq_src & UDC_EP0_TX) { int stat;
omap_writew(UDC_EP0_TX, UDC_IRQ_SRC);
omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
stat = omap_readw(UDC_STAT_FLG); if (stat & UDC_ACK) { if (udc->ep0_in) { /* write next IN packet from response, * or set up the status stage.
*/ if (req)
stat = write_fifo(ep0, req);
omap_writew(UDC_EP_DIR, UDC_EP_NUM); if (!req && udc->ep0_pending) {
omap_writew(UDC_EP_SEL, UDC_EP_NUM);
omap_writew(UDC_CLR_EP, UDC_CTRL);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(0, UDC_EP_NUM);
udc->ep0_pending = 0;
} /* else: 6 wait states before it'll tx */
} else { /* ack status stage of OUT transfer */
omap_writew(UDC_EP_DIR, UDC_EP_NUM); if (req)
done(ep0, req, 0);
}
req = NULL;
} elseif (stat & UDC_STALL) {
omap_writew(UDC_CLR_HALT, UDC_CTRL);
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
} else {
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
}
}
/* OUT == RX from host */ if (irq_src & UDC_EP0_RX) { int stat;
omap_writew(UDC_EP0_RX, UDC_IRQ_SRC);
omap_writew(UDC_EP_SEL, UDC_EP_NUM);
stat = omap_readw(UDC_STAT_FLG); if (stat & UDC_ACK) { if (!udc->ep0_in) {
stat = 0; /* read next OUT packet of request, maybe * reactivating the fifo; stall on errors.
*/
stat = read_fifo(ep0, req); if (!req || stat < 0) {
omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
udc->ep0_pending = 0;
stat = 0;
} elseif (stat == 0)
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(0, UDC_EP_NUM);
/* activate status stage */ if (stat == 1) {
done(ep0, req, 0); /* that may have STALLed ep0... */
omap_writew(UDC_EP_SEL | UDC_EP_DIR,
UDC_EP_NUM);
omap_writew(UDC_CLR_EP, UDC_CTRL);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
udc->ep0_pending = 0;
}
} else { /* ack status stage of IN transfer */
omap_writew(0, UDC_EP_NUM); if (req)
done(ep0, req, 0);
}
} elseif (stat & UDC_STALL) {
omap_writew(UDC_CLR_HALT, UDC_CTRL);
omap_writew(0, UDC_EP_NUM);
} else {
omap_writew(0, UDC_EP_NUM);
}
}
/* SETUP starts all control transfers */ if (irq_src & UDC_SETUP) { union u {
u16 word[4]; struct usb_ctrlrequest r;
} u; int status = -EINVAL; struct omap_ep *ep;
/* read the (latest) SETUP message */ do {
omap_writew(UDC_SETUP_SEL, UDC_EP_NUM); /* two bytes at a time */
u.word[0] = omap_readw(UDC_DATA);
u.word[1] = omap_readw(UDC_DATA);
u.word[2] = omap_readw(UDC_DATA);
u.word[3] = omap_readw(UDC_DATA);
omap_writew(0, UDC_EP_NUM);
} while (omap_readw(UDC_IRQ_SRC) & UDC_SETUP);
/* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that * hardware doesn't autodecode _and_ the gadget API hides.
*/
udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0;
udc->ep0_set_config = 0;
udc->ep0_pending = 1;
ep0->stopped = 0;
ep0->ackwait = 0; switch (u.r.bRequest) { case USB_REQ_SET_CONFIGURATION: /* udc needs to know when ep != 0 is valid */ if (u.r.bRequestType != USB_RECIP_DEVICE) goto delegate; if (w_length != 0) goto do_stall;
udc->ep0_set_config = 1;
udc->ep0_reset_config = (w_value == 0);
VDBG("set config %d\n", w_value);
/* update udc NOW since gadget driver may start * queueing requests immediately; clear config * later if it fails the request.
*/ if (udc->ep0_reset_config)
omap_writew(UDC_CLR_CFG, UDC_SYSCON2); else
omap_writew(UDC_DEV_CFG, UDC_SYSCON2);
update_otg(udc); goto delegate; case USB_REQ_CLEAR_FEATURE: /* clear endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; if (w_value != USB_ENDPOINT_HALT
|| w_length != 0) goto do_stall;
ep = &udc->ep[w_index & 0xf]; if (ep != ep0) { if (w_index & USB_DIR_IN)
ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|| !ep->ep.desc) goto do_stall;
use_ep(ep, 0);
omap_writew(udc->clr_halt, UDC_CTRL);
ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) {
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
ep->ackwait = 1 + ep->double_buf;
} /* NOTE: assumes the host behaves sanely, * only clearing real halts. Else we may * need to kill pending transfers and then * restart the queue... very messy for DMA!
*/
}
VDBG("%s halt cleared by host\n", ep->name); goto ep0out_status_stage; case USB_REQ_SET_FEATURE: /* set endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; if (w_value != USB_ENDPOINT_HALT
|| w_length != 0) goto do_stall;
ep = &udc->ep[w_index & 0xf]; if (w_index & USB_DIR_IN)
ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|| ep == ep0 || !ep->ep.desc) goto do_stall; if (use_dma && ep->has_dma) { /* this has rude side-effects (aborts) and * can't really work if DMA-IN is active
*/
DBG("%s host set_halt, NYET\n", ep->name); goto do_stall;
}
use_ep(ep, 0); /* can't halt if fifo isn't empty... */
omap_writew(UDC_CLR_EP, UDC_CTRL);
omap_writew(UDC_SET_HALT, UDC_CTRL);
VDBG("%s halted by host\n", ep->name);
ep0out_status_stage:
status = 0;
omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
omap_writew(UDC_CLR_EP, UDC_CTRL);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
udc->ep0_pending = 0; break; case USB_REQ_GET_STATUS: /* USB_ENDPOINT_HALT status? */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto intf_status;
/* ep0 never stalls */ if (!(w_index & 0xf)) goto zero_status;
/* only active endpoints count */
ep = &udc->ep[w_index & 0xf]; if (w_index & USB_DIR_IN)
ep += 16; if (!ep->ep.desc) goto do_stall;
/* iso never stalls */ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) goto zero_status;
intf_status: /* return interface status. if we were pedantic, * we'd detect non-existent interfaces, and stall.
*/ if (u.r.bRequestType
!= (USB_DIR_IN|USB_RECIP_INTERFACE)) goto delegate;
zero_status: /* return two zero bytes */
omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
omap_writew(0, UDC_DATA);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
status = 0;
VDBG("GET_STATUS, interface %d\n", w_index); /* next, status stage */ break; default:
delegate: /* activate the ep0out fifo right away */ if (!udc->ep0_in && w_length) {
omap_writew(0, UDC_EP_NUM);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
}
/* gadget drivers see class/vendor specific requests, * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, * and more
*/
VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
u.r.bRequestType, u.r.bRequest,
w_value, w_index, w_length);
#undef w_value #undef w_index #undef w_length
/* The gadget driver may return an error here, * causing an immediate protocol stall. * * Else it must issue a response, either queueing a * response buffer for the DATA stage, or halting ep0 * (causing a protocol stall, not a real halt). A * zero length buffer means no DATA stage. * * It's fine to issue that response after the setup() * call returns, and this IRQ was handled.
*/
udc->ep0_setup = 1;
spin_unlock(&udc->lock);
status = udc->driver->setup(&udc->gadget, &u.r);
spin_lock(&udc->lock);
udc->ep0_setup = 0;
}
if (status < 0) {
do_stall:
VDBG("req %02x.%02x protocol STALL; stat %d\n",
u.r.bRequestType, u.r.bRequest, status); if (udc->ep0_set_config) { if (udc->ep0_reset_config)
WARNING("error resetting config?\n"); else
omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
}
omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
udc->ep0_pending = 0;
}
}
}
use_ep(ep, UDC_EP_SEL);
stat = omap_readw(UDC_STAT_FLG);
/* NOTE: like the other controller drivers, this isn't * currently reporting lost or damaged frames.
*/ if (ep->bEndpointAddress & USB_DIR_IN) { if (stat & UDC_MISS_IN) /* done(ep, req, -EPROTO) */; else
write_fifo(ep, req);
} else { int status = 0;
if (stat & UDC_NO_RXPACKET)
status = -EREMOTEIO; elseif (stat & UDC_ISO_ERR)
status = -EILSEQ; elseif (stat & UDC_DATA_FLUSH)
status = -ENOSR;
if (status) /* done(ep, req, status) */; else
read_fifo(ep, req);
}
deselect_ep(); /* 6 wait states before next EP */
ep->irqs++; if (!list_empty(&ep->queue))
pending = 1;
} if (!pending) {
u16 w;
w = omap_readw(UDC_IRQ_EN);
w &= ~UDC_SOF_IE;
omap_writew(w, UDC_IRQ_EN);
}
omap_writew(UDC_IRQ_SOF, UDC_IRQ_SRC);
/* hook up the driver */
udc->driver = driver;
spin_unlock_irqrestore(&udc->lock, flags);
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);
omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
/* connect to bus through transceiver */ if (!IS_ERR_OR_NULL(udc->transceiver)) {
status = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget); if (status < 0) {
ERR("can't bind to transceiver\n");
udc->driver = NULL; goto done;
}
} else {
status = 0; if (can_pullup(udc))
pullup_enable(udc); else
pullup_disable(udc);
}
/* boards that don't have VBUS sensing can't autogate 48MHz; * can't enter deep sleep while a gadget driver is active.
*/ if (machine_without_vbus_sense())
omap_vbus_session(&udc->gadget, 1);
done: if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
staticchar *trx_mode(unsigned m, int enabled)
{ switch (m) { case 0: return enabled ? "*6wire" : "unused"; case 1: return"4wire"; case 2: return"3wire"; case 3: return"6wire"; default: return"unknown";
}
}
/* Before this controller can enumerate, we need to pick an endpoint * configuration, or "fifo_mode" That involves allocating 2KB of packet * buffer space among the endpoints we'll be operating. * * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when * UDC_SYSCON_1.CFG_LOCK is set can now work. We won't use that * capability yet though.
*/ staticunsigned
omap_ep_setup(char *name, u8 addr, u8 type, unsigned buf, unsigned maxp, int dbuf)
{ struct omap_ep *ep;
u16 epn_rxtx = 0;
/* OUT endpoints first, then IN */
ep = &udc->ep[addr & 0xf]; if (addr & USB_DIR_IN)
ep += 16;
/* in case of ep init table bugs */
BUG_ON(ep->name[0]);
/* chip setup ... bit values are same for IN, OUT */ if (type == USB_ENDPOINT_XFER_ISOC) { switch (maxp) { case 8:
epn_rxtx = 0 << 12; break; case 16:
epn_rxtx = 1 << 12; break; case 32:
epn_rxtx = 2 << 12; break; case 64:
epn_rxtx = 3 << 12; break; case 128:
epn_rxtx = 4 << 12; break; case 256:
epn_rxtx = 5 << 12; break; case 512:
epn_rxtx = 6 << 12; break; default:
BUG();
}
epn_rxtx |= UDC_EPN_RX_ISO;
dbuf = 1;
} else { /* double-buffering "not supported" on 15xx, * and ignored for PIO-IN on newer chips * (for more reliable behavior)
*/ if (!use_dma || cpu_is_omap15xx())
dbuf = 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.