// SPDX-License-Identifier: GPL-2.0+ /* * Xilinx USB peripheral controller driver * * Copyright (C) 2004 by Thomas Rathbone * Copyright (C) 2005 by HP Labs * Copyright (C) 2005 by David Brownell * Copyright (C) 2010 - 2014 Xilinx, Inc. * * Some parts of this driver code is based on the driver for at91-series * USB peripheral controller (at91_udc.c).
*/
/* Endpoint Configuration Status Register */ #define XUSB_EP_CFG_VALID_MASK 0x80000000 /* Endpoint Valid bit */ #define XUSB_EP_CFG_STALL_MASK 0x40000000 /* Endpoint Stall bit */ #define XUSB_EP_CFG_DATA_TOGGLE_MASK 0x08000000 /* Endpoint Data toggle */
/* USB device specific global configuration constants.*/ #define XUSB_MAX_ENDPOINTS 8 /* Maximum End Points */ #define XUSB_EP_NUMBER_ZERO 0 /* End point Zero */ /* DPRAM is the source address for DMA transfer */ #define XUSB_DMA_READ_FROM_DPRAM 0x80000000 #define XUSB_DMA_DMASR_BUSY 0x80000000 /* DMA busy */ #define XUSB_DMA_DMASR_ERROR 0x40000000 /* DMA Error */ /* * When this bit is set, the DMA buffer ready bit is set by hardware upon * DMA transfer completion.
*/ #define XUSB_DMA_BRR_CTRL 0x40000000 /* DMA bufready ctrl bit */ /* Phase States */ #define SETUP_PHASE 0x0000 /* Setup Phase */ #define DATA_PHASE 0x0001 /* Data Phase */ #define STATUS_PHASE 0x0002 /* Status Phase */
#define EP0_MAX_PACKET 64 /* Endpoint 0 maximum packet length */ #define STATUSBUFF_SIZE 2 /* Buffer size for GET_STATUS command */ #define EPNAME_SIZE 4 /* Buffer size for endpoint name */
/** * struct xusb_req - Xilinx USB device request structure * @usb_req: Linux usb request structure * @queue: usb device request queue * @ep: pointer to xusb_endpoint structure
*/ struct xusb_req { struct usb_request usb_req; struct list_head queue; struct xusb_ep *ep;
};
/** * struct xusb_ep - USB end point structure. * @ep_usb: usb endpoint instance * @queue: endpoint message queue * @udc: xilinx usb peripheral driver instance pointer * @desc: pointer to the usb endpoint descriptor * @rambase: the endpoint buffer address * @offset: the endpoint register offset value * @name: name of the endpoint * @epnumber: endpoint number * @maxpacket: maximum packet size the endpoint can store * @buffer0count: the size of the packet recieved in the first buffer * @buffer1count: the size of the packet received in the second buffer * @curbufnum: current buffer of endpoint that will be processed next * @buffer0ready: the busy state of first buffer * @buffer1ready: the busy state of second buffer * @is_in: endpoint direction (IN or OUT) * @is_iso: endpoint type(isochronous or non isochronous)
*/ struct xusb_ep { struct usb_ep ep_usb; struct list_head queue; struct xusb_udc *udc; conststruct usb_endpoint_descriptor *desc;
u32 rambase;
u32 offset; char name[4];
u16 epnumber;
u16 maxpacket;
u16 buffer0count;
u16 buffer1count;
u8 curbufnum; bool buffer0ready; bool buffer1ready; bool is_in; bool is_iso;
};
/** * struct xusb_udc - USB peripheral driver structure * @gadget: USB gadget driver instance * @ep: an array of endpoint structures * @driver: pointer to the usb gadget driver instance * @setup: usb_ctrlrequest structure for control requests * @req: pointer to dummy request for get status command * @dev: pointer to device structure in gadget * @usb_state: device in suspended state or not * @remote_wkp: remote wakeup enabled by host * @setupseqtx: tx status * @setupseqrx: rx status * @addr: the usb device base address * @lock: instance of spinlock * @dma_enabled: flag indicating whether the dma is included in the system * @clk: pointer to struct clk * @read_fn: function pointer to read device registers * @write_fn: function pointer to write to device registers
*/ struct xusb_udc { struct usb_gadget gadget; struct xusb_ep ep[8]; struct usb_gadget_driver *driver; struct usb_ctrlrequest setup; struct xusb_req *req; struct device *dev;
u32 usb_state;
u32 remote_wkp;
u32 setupseqtx;
u32 setupseqrx; void __iomem *addr;
spinlock_t lock; bool dma_enabled; struct clk *clk;
/** * xudc_write32 - little endian write to device registers * @addr: base addr of device registers * @offset: register offset * @val: data to be written
*/ staticvoid xudc_write32(void __iomem *addr, u32 offset, u32 val)
{
iowrite32(val, addr + offset);
}
/** * xudc_read32 - little endian read from device registers * @addr: addr of device register * Return: value at addr
*/ staticunsignedint xudc_read32(void __iomem *addr)
{ return ioread32(addr);
}
/** * xudc_write32_be - big endian write to device registers * @addr: base addr of device registers * @offset: register offset * @val: data to be written
*/ staticvoid xudc_write32_be(void __iomem *addr, u32 offset, u32 val)
{
iowrite32be(val, addr + offset);
}
/** * xudc_read32_be - big endian read from device registers * @addr: addr of device register * Return: value at addr
*/ staticunsignedint xudc_read32_be(void __iomem *addr)
{ return ioread32be(addr);
}
/** * xudc_wrstatus - Sets up the usb device status stages. * @udc: pointer to the usb device controller structure.
*/ staticvoid xudc_wrstatus(struct xusb_udc *udc)
{ struct xusb_ep *ep0 = &udc->ep[XUSB_EP_NUMBER_ZERO];
u32 epcfgreg;
/** * xudc_epconfig - Configures the given endpoint. * @ep: pointer to the usb device endpoint structure. * @udc: pointer to the usb peripheral controller structure. * * This function configures a specific endpoint with the given configuration * data.
*/ staticvoid xudc_epconfig(struct xusb_ep *ep, struct xusb_udc *udc)
{
u32 epcfgreg;
/* * Configure the end point direction, type, Max Packet Size and the * EP buffer location.
*/
epcfgreg = ((ep->is_in << 29) | (ep->is_iso << 28) |
(ep->ep_usb.maxpacket << 15) | (ep->rambase));
udc->write_fn(udc->addr, ep->offset, epcfgreg);
/* Set the Buffer count and the Buffer ready bits.*/
udc->write_fn(udc->addr, ep->offset + XUSB_EP_BUF0COUNT_OFFSET,
ep->buffer0count);
udc->write_fn(udc->addr, ep->offset + XUSB_EP_BUF1COUNT_OFFSET,
ep->buffer1count); if (ep->buffer0ready)
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
1 << ep->epnumber); if (ep->buffer1ready)
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
1 << (ep->epnumber + XUSB_STATUS_EP_BUFF2_SHIFT));
}
/** * xudc_start_dma - Starts DMA transfer. * @ep: pointer to the usb device endpoint structure. * @src: DMA source address. * @dst: DMA destination address. * @length: number of bytes to transfer. * * Return: 0 on success, error code on failure * * This function starts DMA transfer by writing to DMA source, * destination and lenth registers.
*/ staticint xudc_start_dma(struct xusb_ep *ep, dma_addr_t src,
dma_addr_t dst, u32 length)
{ struct xusb_udc *udc = ep->udc; int rc = 0;
u32 timeout = 500;
u32 reg;
/* * Set the addresses in the DMA source and * destination registers and then set the length * into the DMA length register.
*/
udc->write_fn(udc->addr, XUSB_DMA_DSAR_ADDR_OFFSET, src);
udc->write_fn(udc->addr, XUSB_DMA_DDAR_ADDR_OFFSET, dst);
udc->write_fn(udc->addr, XUSB_DMA_LENGTH_OFFSET, length);
/* * Wait till DMA transaction is complete and * check whether the DMA transaction was * successful.
*/ do {
reg = udc->read_fn(udc->addr + XUSB_DMA_STATUS_OFFSET); if (!(reg & XUSB_DMA_DMASR_BUSY)) break;
/* * We can't sleep here, because it's also called from * interrupt context.
*/
timeout--; if (!timeout) {
dev_err(udc->dev, "DMA timeout\n"); return -ETIMEDOUT;
}
udelay(1);
} while (1);
/** * xudc_dma_send - Sends IN data using DMA. * @ep: pointer to the usb device endpoint structure. * @req: pointer to the usb request structure. * @buffer: pointer to data to be sent. * @length: number of bytes to send. * * Return: 0 on success, -EAGAIN if no buffer is free and error * code on failure. * * This function sends data using DMA.
*/ staticint xudc_dma_send(struct xusb_ep *ep, struct xusb_req *req,
u8 *buffer, u32 length)
{
u32 *eprambase;
dma_addr_t src;
dma_addr_t dst; struct xusb_udc *udc = ep->udc;
src = req->usb_req.dma + req->usb_req.actual; if (req->usb_req.length)
dma_sync_single_for_device(udc->dev, src,
length, DMA_TO_DEVICE); if (!ep->curbufnum && !ep->buffer0ready) { /* Get the Buffer address and copy the transmit data.*/
eprambase = (u32 __force *)(udc->addr + ep->rambase);
dst = virt_to_phys(eprambase);
udc->write_fn(udc->addr, ep->offset +
XUSB_EP_BUF0COUNT_OFFSET, length);
udc->write_fn(udc->addr, XUSB_DMA_CONTROL_OFFSET,
XUSB_DMA_BRR_CTRL | (1 << ep->epnumber));
ep->buffer0ready = 1;
ep->curbufnum = 1;
} elseif (ep->curbufnum && !ep->buffer1ready) { /* Get the Buffer address and copy the transmit data.*/
eprambase = (u32 __force *)(udc->addr + ep->rambase +
ep->ep_usb.maxpacket);
dst = virt_to_phys(eprambase);
udc->write_fn(udc->addr, ep->offset +
XUSB_EP_BUF1COUNT_OFFSET, length);
udc->write_fn(udc->addr, XUSB_DMA_CONTROL_OFFSET,
XUSB_DMA_BRR_CTRL | (1 << (ep->epnumber +
XUSB_STATUS_EP_BUFF2_SHIFT)));
ep->buffer1ready = 1;
ep->curbufnum = 0;
} else { /* None of ping pong buffers are ready currently .*/ return -EAGAIN;
}
return xudc_start_dma(ep, src, dst, length);
}
/** * xudc_dma_receive - Receives OUT data using DMA. * @ep: pointer to the usb device endpoint structure. * @req: pointer to the usb request structure. * @buffer: pointer to storage buffer of received data. * @length: number of bytes to receive. * * Return: 0 on success, -EAGAIN if no buffer is free and error * code on failure. * * This function receives data using DMA.
*/ staticint xudc_dma_receive(struct xusb_ep *ep, struct xusb_req *req,
u8 *buffer, u32 length)
{
u32 *eprambase;
dma_addr_t src;
dma_addr_t dst; struct xusb_udc *udc = ep->udc;
dst = req->usb_req.dma + req->usb_req.actual; if (!ep->curbufnum && !ep->buffer0ready) { /* Get the Buffer address and copy the transmit data */
eprambase = (u32 __force *)(udc->addr + ep->rambase);
src = virt_to_phys(eprambase);
udc->write_fn(udc->addr, XUSB_DMA_CONTROL_OFFSET,
XUSB_DMA_BRR_CTRL | XUSB_DMA_READ_FROM_DPRAM |
(1 << ep->epnumber));
ep->buffer0ready = 1;
ep->curbufnum = 1;
} elseif (ep->curbufnum && !ep->buffer1ready) { /* Get the Buffer address and copy the transmit data */
eprambase = (u32 __force *)(udc->addr +
ep->rambase + ep->ep_usb.maxpacket);
src = virt_to_phys(eprambase);
udc->write_fn(udc->addr, XUSB_DMA_CONTROL_OFFSET,
XUSB_DMA_BRR_CTRL | XUSB_DMA_READ_FROM_DPRAM |
(1 << (ep->epnumber +
XUSB_STATUS_EP_BUFF2_SHIFT)));
ep->buffer1ready = 1;
ep->curbufnum = 0;
} else { /* None of the ping-pong buffers are ready currently */ return -EAGAIN;
}
return xudc_start_dma(ep, src, dst, length);
}
/** * xudc_eptxrx - Transmits or receives data to or from an endpoint. * @ep: pointer to the usb endpoint configuration structure. * @req: pointer to the usb request structure. * @bufferptr: pointer to buffer containing the data to be sent. * @bufferlen: The number of data bytes to be sent. * * Return: 0 on success, -EAGAIN if no buffer is free. * * This function copies the transmit/receive data to/from the end point buffer * and enables the buffer for transmission/reception.
*/ staticint xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req,
u8 *bufferptr, u32 bufferlen)
{
u32 *eprambase;
u32 bytestosend; int rc = 0; struct xusb_udc *udc = ep->udc;
bytestosend = bufferlen; if (udc->dma_enabled) { if (ep->is_in)
rc = xudc_dma_send(ep, req, bufferptr, bufferlen); else
rc = xudc_dma_receive(ep, req, bufferptr, bufferlen); return rc;
} /* Put the transmit buffer into the correct ping-pong buffer.*/ if (!ep->curbufnum && !ep->buffer0ready) { /* Get the Buffer address and copy the transmit data.*/
eprambase = (u32 __force *)(udc->addr + ep->rambase); if (ep->is_in) {
memcpy_toio((void __iomem *)eprambase, bufferptr,
bytestosend);
udc->write_fn(udc->addr, ep->offset +
XUSB_EP_BUF0COUNT_OFFSET, bufferlen);
} else {
memcpy_toio((void __iomem *)bufferptr, eprambase,
bytestosend);
} /* * Enable the buffer for transmission.
*/
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
1 << ep->epnumber);
ep->buffer0ready = 1;
ep->curbufnum = 1;
} elseif (ep->curbufnum && !ep->buffer1ready) { /* Get the Buffer address and copy the transmit data.*/
eprambase = (u32 __force *)(udc->addr + ep->rambase +
ep->ep_usb.maxpacket); if (ep->is_in) {
memcpy_toio((void __iomem *)eprambase, bufferptr,
bytestosend);
udc->write_fn(udc->addr, ep->offset +
XUSB_EP_BUF1COUNT_OFFSET, bufferlen);
} else {
memcpy_toio((void __iomem *)bufferptr, eprambase,
bytestosend);
} /* * Enable the buffer for transmission.
*/
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
1 << (ep->epnumber + XUSB_STATUS_EP_BUFF2_SHIFT));
ep->buffer1ready = 1;
ep->curbufnum = 0;
} else { /* None of the ping-pong buffers are ready currently */ return -EAGAIN;
} return rc;
}
/** * xudc_done - Exeutes the endpoint data transfer completion tasks. * @ep: pointer to the usb device endpoint structure. * @req: pointer to the usb request structure. * @status: Status of the data transfer. * * Deletes the message from the queue and updates data transfer completion * status.
*/ staticvoid xudc_done(struct xusb_ep *ep, struct xusb_req *req, int status)
{ struct xusb_udc *udc = ep->udc;
list_del_init(&req->queue);
if (req->usb_req.status == -EINPROGRESS)
req->usb_req.status = status; else
status = req->usb_req.status;
if (status && status != -ESHUTDOWN)
dev_dbg(udc->dev, "%s done %p, status %d\n",
ep->ep_usb.name, req, status); /* unmap request if DMA is present*/ if (udc->dma_enabled && ep->epnumber && req->usb_req.length)
usb_gadget_unmap_request(&udc->gadget, &req->usb_req,
ep->is_in);
if (req->usb_req.complete) {
spin_unlock(&udc->lock);
req->usb_req.complete(&ep->ep_usb, &req->usb_req);
spin_lock(&udc->lock);
}
}
/** * xudc_read_fifo - Reads the data from the given endpoint buffer. * @ep: pointer to the usb device endpoint structure. * @req: pointer to the usb request structure. * * Return: 0 if request is completed and -EAGAIN if not completed. * * Pulls OUT packet data from the endpoint buffer.
*/ staticint xudc_read_fifo(struct xusb_ep *ep, struct xusb_req *req)
{
u8 *buf;
u32 is_short, count, bufferspace;
u8 bufoffset;
u8 two_pkts = 0; int ret; int retval = -EAGAIN; struct xusb_udc *udc = ep->udc;
if (ep->buffer0ready && ep->buffer1ready) {
dev_dbg(udc->dev, "Packet NOT ready!\n"); return retval;
}
top: if (ep->curbufnum)
bufoffset = XUSB_EP_BUF1COUNT_OFFSET; else
bufoffset = XUSB_EP_BUF0COUNT_OFFSET;
if (unlikely(!bufferspace)) { /* * This happens when the driver's buffer * is smaller than what the host sent. * discard the extra data.
*/ if (req->usb_req.status != -EOVERFLOW)
dev_dbg(udc->dev, "%s overflow %d\n",
ep->ep_usb.name, count);
req->usb_req.status = -EOVERFLOW;
xudc_done(ep, req, -EOVERFLOW); return 0;
}
/* Completion */ if ((req->usb_req.actual == req->usb_req.length) || is_short) { if (udc->dma_enabled && req->usb_req.length)
dma_sync_single_for_cpu(udc->dev,
req->usb_req.dma,
req->usb_req.actual,
DMA_FROM_DEVICE);
xudc_done(ep, req, 0); return 0;
} if (two_pkts) {
two_pkts = 0; goto top;
} break; case -EAGAIN:
dev_dbg(udc->dev, "receive busy\n"); break; case -EINVAL: case -ETIMEDOUT: /* DMA error, dequeue the request */
xudc_done(ep, req, -ECONNRESET);
retval = 0; break;
}
return retval;
}
/** * xudc_write_fifo - Writes data into the given endpoint buffer. * @ep: pointer to the usb device endpoint structure. * @req: pointer to the usb request structure. * * Return: 0 if request is completed and -EAGAIN if not completed. * * Loads endpoint buffer for an IN packet.
*/ staticint xudc_write_fifo(struct xusb_ep *ep, struct xusb_req *req)
{
u32 max;
u32 length; int ret; int retval = -EAGAIN; struct xusb_udc *udc = ep->udc; int is_last, is_short = 0;
u8 *buf;
ret = xudc_eptxrx(ep, req, buf, length); switch (ret) { case 0:
req->usb_req.actual += length; if (unlikely(length != max)) {
is_last = is_short = 1;
} else { if (likely(req->usb_req.length !=
req->usb_req.actual) || req->usb_req.zero)
is_last = 0; else
is_last = 1;
}
dev_dbg(udc->dev, "%s: wrote %s %d bytes%s%s %d left %p\n",
__func__, ep->ep_usb.name, length, is_last ? "/L" : "",
is_short ? "/S" : "",
req->usb_req.length - req->usb_req.actual, req); /* completion */ if (is_last) {
xudc_done(ep, req, 0);
retval = 0;
} break; case -EAGAIN:
dev_dbg(udc->dev, "Send busy\n"); break; case -EINVAL: case -ETIMEDOUT: /* DMA error, dequeue the request */
xudc_done(ep, req, -ECONNRESET);
retval = 0; break;
}
return retval;
}
/** * xudc_nuke - Cleans up the data transfer message list. * @ep: pointer to the usb device endpoint structure. * @status: Status of the data transfer.
*/ staticvoid xudc_nuke(struct xusb_ep *ep, int status)
{ struct xusb_req *req;
/** * xudc_ep_set_halt - Stalls/unstalls the given endpoint. * @_ep: pointer to the usb device endpoint structure. * @value: value to indicate stall/unstall. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep_set_halt(struct usb_ep *_ep, int value)
{ struct xusb_ep *ep = to_xusb_ep(_ep); struct xusb_udc *udc; unsignedlong flags;
u32 epcfgreg;
if (!_ep || (!ep->desc && ep->epnumber)) {
pr_debug("%s: bad ep or descriptor\n", __func__); return -EINVAL;
}
udc = ep->udc;
/* for OUT endpoint set buffers ready to receive */ if (ep->epnumber && !ep->is_in) {
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
1 << ep->epnumber);
ep->buffer0ready = true;
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET,
(1 << (ep->epnumber +
XUSB_STATUS_EP_BUFF2_SHIFT)));
ep->buffer1ready = true;
}
return 0;
}
/** * xudc_ep_enable - Enables the given endpoint. * @_ep: pointer to the usb endpoint structure. * @desc: pointer to usb endpoint descriptor. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep_enable(struct usb_ep *_ep, conststruct usb_endpoint_descriptor *desc)
{ struct xusb_ep *ep; struct xusb_udc *udc; unsignedlong flags; int ret;
if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
pr_debug("%s: bad ep or descriptor\n", __func__); return -EINVAL;
}
spin_lock_irqsave(&udc->lock, flags);
ret = __xudc_ep_enable(ep, desc);
spin_unlock_irqrestore(&udc->lock, flags);
return ret;
}
/** * xudc_ep_disable - Disables the given endpoint. * @_ep: pointer to the usb endpoint structure. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep_disable(struct usb_ep *_ep)
{ struct xusb_ep *ep; unsignedlong flags;
u32 epcfg; struct xusb_udc *udc;
if (!_ep) {
pr_debug("%s: invalid ep\n", __func__); return -EINVAL;
}
/** * xudc_ep_alloc_request - Initializes the request queue. * @_ep: pointer to the usb endpoint structure. * @gfp_flags: Flags related to the request call. * * Return: pointer to request structure on success and a NULL on failure.
*/ staticstruct usb_request *xudc_ep_alloc_request(struct usb_ep *_ep,
gfp_t gfp_flags)
{ struct xusb_ep *ep = to_xusb_ep(_ep); struct xusb_req *req;
req = kzalloc(sizeof(*req), gfp_flags); if (!req) return NULL;
/** * xudc_free_request - Releases the request from queue. * @_ep: pointer to the usb device endpoint structure. * @_req: pointer to the usb request structure.
*/ staticvoid xudc_free_request(struct usb_ep *_ep, struct usb_request *_req)
{ struct xusb_req *req = to_xusb_req(_req);
kfree(req);
}
/** * __xudc_ep0_queue - Adds the request to endpoint 0 queue. * @ep0: pointer to the xusb endpoint 0 structure. * @req: pointer to the xusb request structure. * * Return: 0 for success and error value on failure
*/ staticint __xudc_ep0_queue(struct xusb_ep *ep0, struct xusb_req *req)
{ struct xusb_udc *udc = ep0->udc;
u32 length;
u8 *corebuf;
/** * xudc_ep0_queue - Adds the request to endpoint 0 queue. * @_ep: pointer to the usb endpoint 0 structure. * @_req: pointer to the usb request structure. * @gfp_flags: Flags related to the request call. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep0_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags)
{ struct xusb_req *req = to_xusb_req(_req); struct xusb_ep *ep0 = to_xusb_ep(_ep); struct xusb_udc *udc = ep0->udc; unsignedlong flags; int ret;
spin_lock_irqsave(&udc->lock, flags);
ret = __xudc_ep0_queue(ep0, req);
spin_unlock_irqrestore(&udc->lock, flags);
return ret;
}
/** * xudc_ep_queue - Adds the request to endpoint queue. * @_ep: pointer to the usb endpoint structure. * @_req: pointer to the usb request structure. * @gfp_flags: Flags related to the request call. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags)
{ struct xusb_req *req = to_xusb_req(_req); struct xusb_ep *ep = to_xusb_ep(_ep); struct xusb_udc *udc = ep->udc; int ret; unsignedlong flags;
if (!ep->desc) {
dev_dbg(udc->dev, "%s: queuing request to disabled %s\n",
__func__, ep->name); return -ESHUTDOWN;
}
/** * xudc_ep_dequeue - Removes the request from the queue. * @_ep: pointer to the usb device endpoint structure. * @_req: pointer to the usb request structure. * * Return: 0 for success and error value on failure
*/ staticint xudc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{ struct xusb_ep *ep = to_xusb_ep(_ep); struct xusb_req *req = NULL; struct xusb_req *iter; struct xusb_udc *udc = ep->udc; unsignedlong flags;
spin_lock_irqsave(&udc->lock, flags); /* Make sure it's actually queued on this endpoint */
list_for_each_entry(iter, &ep->queue, queue) { if (&iter->usb_req != _req) continue;
req = iter; break;
} if (!req) {
spin_unlock_irqrestore(&udc->lock, flags); return -EINVAL;
}
xudc_done(ep, req, -ECONNRESET);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
/** * xudc_ep0_enable - Enables the given endpoint. * @ep: pointer to the usb endpoint structure. * @desc: pointer to usb endpoint descriptor. * * Return: error always. * * endpoint 0 enable should not be called by gadget layer.
*/ staticint xudc_ep0_enable(struct usb_ep *ep, conststruct usb_endpoint_descriptor *desc)
{ return -EINVAL;
}
/** * xudc_ep0_disable - Disables the given endpoint. * @ep: pointer to the usb endpoint structure. * * Return: error always. * * endpoint 0 disable should not be called by gadget layer.
*/ staticint xudc_ep0_disable(struct usb_ep *ep)
{ return -EINVAL;
}
/** * xudc_get_frame - Reads the current usb frame number. * @gadget: pointer to the usb gadget structure. * * Return: current frame number for success and error value on failure.
*/ staticint xudc_get_frame(struct usb_gadget *gadget)
{ struct xusb_udc *udc; int frame;
/** * xudc_wakeup - Send remote wakeup signal to host * @gadget: pointer to the usb gadget structure. * * Return: 0 on success and error on failure
*/ staticint xudc_wakeup(struct usb_gadget *gadget)
{ struct xusb_udc *udc = to_udc(gadget);
u32 crtlreg; int status = -EINVAL; unsignedlong flags;
spin_lock_irqsave(&udc->lock, flags);
/* Remote wake up not enabled by host */ if (!udc->remote_wkp) goto done;
crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET);
crtlreg |= XUSB_CONTROL_USB_RMTWAKE_MASK; /* set remote wake up bit */
udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg); /* * wait for a while and reset remote wake up bit since this bit * is not cleared by HW after sending remote wakeup to host.
*/
mdelay(2);
/** * xudc_pullup - start/stop USB traffic * @gadget: pointer to the usb gadget structure. * @is_on: flag to start or stop * * Return: 0 always * * This function starts/stops SIE engine of IP based on is_on.
*/ staticint xudc_pullup(struct usb_gadget *gadget, int is_on)
{ struct xusb_udc *udc = to_udc(gadget); unsignedlong flags;
u32 crtlreg;
/* Initialize one queue per endpoint */
INIT_LIST_HEAD(&ep->queue);
}
}
/** * xudc_stop_activity - Stops any further activity on the device. * @udc: pointer to the usb device controller structure.
*/ staticvoid xudc_stop_activity(struct xusb_udc *udc)
{ int i; struct xusb_ep *ep;
for (i = 0; i < XUSB_MAX_ENDPOINTS; i++) {
ep = &udc->ep[i];
xudc_nuke(ep, -ESHUTDOWN);
}
}
/** * xudc_start - Starts the device. * @gadget: pointer to the usb gadget structure * @driver: pointer to gadget driver structure * * Return: zero on success and error on failure
*/ staticint xudc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
{ struct xusb_udc *udc = to_udc(gadget); struct xusb_ep *ep0 = &udc->ep[XUSB_EP_NUMBER_ZERO]; conststruct usb_endpoint_descriptor *desc = &config_bulk_out_desc; unsignedlong flags; int ret = 0;
spin_lock_irqsave(&udc->lock, flags);
if (udc->driver) {
dev_err(udc->dev, "%s is already bound to %s\n",
udc->gadget.name, udc->driver->driver.name);
ret = -EBUSY; goto err;
}
/* hook up the driver */
udc->driver = driver;
udc->gadget.speed = driver->max_speed;
/* Enable the control endpoint. */
ret = __xudc_ep_enable(ep0, desc);
/* Set device address and remote wakeup to 0 */
udc->write_fn(udc->addr, XUSB_ADDRESS_OFFSET, 0);
udc->remote_wkp = 0;
err:
spin_unlock_irqrestore(&udc->lock, flags); return ret;
}
/** * xudc_stop - stops the device. * @gadget: pointer to the usb gadget structure * * Return: zero always
*/ staticint xudc_stop(struct usb_gadget *gadget)
{ struct xusb_udc *udc = to_udc(gadget); unsignedlong flags;
/** * xudc_clear_stall_all_ep - clears stall of every endpoint. * @udc: pointer to the udc structure.
*/ staticvoid xudc_clear_stall_all_ep(struct xusb_udc *udc)
{ struct xusb_ep *ep;
u32 epcfgreg; int i;
for (i = 0; i < XUSB_MAX_ENDPOINTS; i++) {
ep = &udc->ep[i];
epcfgreg = udc->read_fn(udc->addr + ep->offset);
epcfgreg &= ~XUSB_EP_CFG_STALL_MASK;
udc->write_fn(udc->addr, ep->offset, epcfgreg); if (ep->epnumber) { /* Reset the toggle bit.*/
epcfgreg = udc->read_fn(udc->addr + ep->offset);
epcfgreg &= ~XUSB_EP_CFG_DATA_TOGGLE_MASK;
udc->write_fn(udc->addr, ep->offset, epcfgreg);
}
}
}
/** * xudc_startup_handler - The usb device controller interrupt handler. * @udc: pointer to the udc structure. * @intrstatus: The mask value containing the interrupt sources. * * This function handles the RESET,SUSPEND,RESUME and DISCONNECT interrupts.
*/ staticvoid xudc_startup_handler(struct xusb_udc *udc, u32 intrstatus)
{
u32 intrreg;
if (udc->setup.bRequestType & USB_DIR_IN) { /* Execute the get command.*/
udc->setupseqrx = STATUS_PHASE;
udc->setupseqtx = DATA_PHASE;
} else { /* Execute the put command.*/
udc->setupseqrx = DATA_PHASE;
udc->setupseqtx = STATUS_PHASE;
}
switch (udc->setup.bRequest) { case USB_REQ_GET_STATUS: /* Data+Status phase form udc */ if ((udc->setup.bRequestType &
(USB_DIR_IN | USB_TYPE_MASK)) !=
(USB_DIR_IN | USB_TYPE_STANDARD)) break;
xudc_getstatus(udc); return; case USB_REQ_SET_ADDRESS: /* Status phase from udc */ if (udc->setup.bRequestType != (USB_DIR_OUT |
USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break;
xudc_setaddress(udc); return; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: /* Requests with no data phase, status phase from udc */ if ((udc->setup.bRequestType & USB_TYPE_MASK)
!= USB_TYPE_STANDARD) break;
xudc_set_clear_feature(udc); return; default: break;
}
spin_unlock(&udc->lock); if (udc->driver->setup(&udc->gadget, &setup) < 0)
xudc_ep0_stall(udc);
spin_lock(&udc->lock);
}
/** * xudc_ep0_out - Processes the endpoint 0 OUT token. * @udc: pointer to the usb device controller structure.
*/ staticvoid xudc_ep0_out(struct xusb_udc *udc)
{ struct xusb_ep *ep0 = &udc->ep[0]; struct xusb_req *req;
u8 *ep0rambase; unsignedint bytes_to_rx; void *buffer;
switch (udc->setupseqrx) { case STATUS_PHASE: /* * This resets both state machines for the next * Setup packet.
*/
udc->setupseqrx = SETUP_PHASE;
udc->setupseqtx = SETUP_PHASE;
req->usb_req.actual = req->usb_req.length;
xudc_done(ep0, req, 0); break; case DATA_PHASE:
bytes_to_rx = udc->read_fn(udc->addr +
XUSB_EP_BUF0COUNT_OFFSET); /* Copy the data to be received from the DPRAM. */
ep0rambase = (u8 __force *) (udc->addr +
(ep0->rambase << 2));
buffer = req->usb_req.buf + req->usb_req.actual;
req->usb_req.actual = req->usb_req.actual + bytes_to_rx;
memcpy_toio((void __iomem *)buffer, ep0rambase, bytes_to_rx);
if (req->usb_req.length == req->usb_req.actual) { /* Data transfer completed get ready for Status stage */
xudc_wrstatus(udc);
} else { /* Enable EP0 buffer to receive data */
udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, 0);
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1);
} break; default: break;
}
}
switch (udc->setupseqtx) { case STATUS_PHASE: switch (udc->setup.bRequest) { case USB_REQ_SET_ADDRESS: /* Set the address of the device.*/
udc->write_fn(udc->addr, XUSB_ADDRESS_OFFSET,
le16_to_cpu(udc->setup.wValue)); break; case USB_REQ_SET_FEATURE: if (udc->setup.bRequestType ==
USB_RECIP_DEVICE) { if (le16_to_cpu(udc->setup.wValue) ==
USB_DEVICE_TEST_MODE)
udc->write_fn(udc->addr,
XUSB_TESTMODE_OFFSET,
test_mode);
} break;
}
req->usb_req.actual = req->usb_req.length;
xudc_done(ep0, req, 0); break; case DATA_PHASE: if (!bytes_to_tx) { /* * We're done with data transfer, next * will be zero length OUT with data toggle of * 1. Setup data_toggle.
*/
epcfgreg = udc->read_fn(udc->addr + ep0->offset);
epcfgreg |= XUSB_EP_CFG_DATA_TOGGLE_MASK;
udc->write_fn(udc->addr, ep0->offset, epcfgreg);
udc->setupseqtx = STATUS_PHASE;
} else {
length = count = min_t(u32, bytes_to_tx,
EP0_MAX_PACKET); /* Copy the data to be transmitted into the DPRAM. */
ep0rambase = (u8 __force *) (udc->addr +
(ep0->rambase << 2));
buffer = req->usb_req.buf + req->usb_req.actual;
req->usb_req.actual = req->usb_req.actual + length;
memcpy_toio((void __iomem *)ep0rambase, buffer, length);
}
udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, count);
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1); break; default: break;
}
}
/** * xudc_ctrl_ep_handler - Endpoint 0 interrupt handler. * @udc: pointer to the udc structure. * @intrstatus: It's the mask value for the interrupt sources on endpoint 0. * * Processes the commands received during enumeration phase.
*/ staticvoid xudc_ctrl_ep_handler(struct xusb_udc *udc, u32 intrstatus)
{
/** * xudc_nonctrl_ep_handler - Non control endpoint interrupt handler. * @udc: pointer to the udc structure. * @epnum: End point number for which the interrupt is to be processed * @intrstatus: mask value for interrupt sources of endpoints other * than endpoint 0. * * Processes the buffer completion interrupts.
*/ staticvoid xudc_nonctrl_ep_handler(struct xusb_udc *udc, u8 epnum,
u32 intrstatus)
{
struct xusb_req *req; struct xusb_ep *ep;
ep = &udc->ep[epnum]; /* Process the End point interrupts.*/ if (intrstatus & (XUSB_STATUS_EP0_BUFF1_COMP_MASK << epnum))
ep->buffer0ready = 0; if (intrstatus & (XUSB_STATUS_EP0_BUFF2_COMP_MASK << epnum))
ep->buffer1ready = false;
if (ep->is_in)
xudc_write_fifo(ep, req); else
xudc_read_fifo(ep, req);
}
/** * xudc_irq - The main interrupt handler. * @irq: The interrupt number. * @_udc: pointer to the usb device controller structure. * * Return: IRQ_HANDLED after the interrupt is handled.
*/ static irqreturn_t xudc_irq(int irq, void *_udc)
{ struct xusb_udc *udc = _udc;
u32 intrstatus;
u32 ier;
u8 index;
u32 bufintr; unsignedlong flags;
spin_lock_irqsave(&udc->lock, flags);
/* * Event interrupts are level sensitive hence first disable * IER, read ISR and figure out active interrupts.
*/
ier = udc->read_fn(udc->addr + XUSB_IER_OFFSET);
ier &= ~XUSB_STATUS_INTR_EVENT_MASK;
udc->write_fn(udc->addr, XUSB_IER_OFFSET, ier);
/* Read the Interrupt Status Register.*/
intrstatus = udc->read_fn(udc->addr + XUSB_STATUS_OFFSET);
/* Call the handler for the event interrupt.*/ if (intrstatus & XUSB_STATUS_INTR_EVENT_MASK) { /* * Check if there is any action to be done for : * - USB Reset received {XUSB_STATUS_RESET_MASK} * - USB Suspend received {XUSB_STATUS_SUSPEND_MASK} * - USB Resume received {XUSB_STATUS_RESUME_MASK} * - USB Disconnect received {XUSB_STATUS_DISCONNECT_MASK}
*/
xudc_startup_handler(udc, intrstatus);
}
/** * xudc_probe - The device probe function for driver initialization. * @pdev: pointer to the platform device structure. * * Return: 0 for success and error value on failure
*/ staticint xudc_probe(struct platform_device *pdev)
{ struct device_node *np = pdev->dev.of_node; struct resource *res; struct xusb_udc *udc; int irq; int ret;
u32 ier;
u8 *buff;
udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); if (!udc) return -ENOMEM;
/* Create a dummy request for GET_STATUS, SET_ADDRESS */
udc->req = devm_kzalloc(&pdev->dev, sizeof(struct xusb_req),
GFP_KERNEL); if (!udc->req) return -ENOMEM;
buff = devm_kzalloc(&pdev->dev, STATUSBUFF_SIZE, GFP_KERNEL); if (!buff) return -ENOMEM;
udc->req->usb_req.buf = buff;
/* Map the registers */
udc->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(udc->addr)) return PTR_ERR(udc->addr);
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
ret = devm_request_irq(&pdev->dev, irq, xudc_irq, 0,
dev_name(&pdev->dev), udc); if (ret < 0) {
dev_dbg(&pdev->dev, "unable to request irq %d", irq); goto fail;
}
udc->clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); if (IS_ERR(udc->clk)) { if (PTR_ERR(udc->clk) != -ENOENT) {
ret = PTR_ERR(udc->clk); goto fail;
}
/* * Clock framework support is optional, continue on, * anyways if we don't find a matching clock
*/
dev_warn(&pdev->dev, "s_axi_aclk clock property is not found\n");
udc->clk = NULL;
}
ret = clk_prepare_enable(udc->clk); if (ret) {
dev_err(&pdev->dev, "Unable to enable clock.\n"); return ret;
}
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.