Commit e4ce4ecd authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman

usb: chipidea: udc: configure iso endpoints

This patch adds iso endpoint support to the device controller.
It makes use of the multiplication bits in the maxpacket field
of the endpoint and calculates the multiplier bits for each
transfer description on every request.
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Reviewed-by: default avatarPeter Chen <peter.chen@freescale.com>
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f6a57507
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
* *
* TODO List * TODO List
* - OTG * - OTG
* - Isochronous & Interrupt Traffic * - Interrupt Traffic
* - Handle requests which spawns into several TDs * - Handle requests which spawns into several TDs
* - GET_STATUS(device) - always reports 0 * - GET_STATUS(device) - always reports 0
* - Gadget API (majority of optional features) * - Gadget API (majority of optional features)
......
...@@ -466,6 +466,14 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) ...@@ -466,6 +466,14 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
mEp->qh.ptr->td.token &= mEp->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
u32 mul = mReq->req.length / mEp->ep.maxpacket;
if (mReq->req.length % mEp->ep.maxpacket)
mul++;
mEp->qh.ptr->cap |= mul << __ffs(QH_MULT);
}
wmb(); /* synchronize before ep prime */ wmb(); /* synchronize before ep prime */
ret = hw_ep_prime(ci, mEp->num, mEp->dir, ret = hw_ep_prime(ci, mEp->num, mEp->dir,
...@@ -678,6 +686,12 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req, ...@@ -678,6 +686,12 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
} }
} }
if (usb_endpoint_xfer_isoc(mEp->ep.desc) &&
mReq->req.length > (1 + mEp->ep.mult) * mEp->ep.maxpacket) {
dev_err(mEp->ci->dev, "request length too big for isochronous\n");
return -EMSGSIZE;
}
/* first nuke then test link, e.g. previous status has not sent */ /* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&mReq->queue)) { if (!list_empty(&mReq->queue)) {
dev_err(mEp->ci->dev, "request already in queue\n"); dev_err(mEp->ci->dev, "request already in queue\n");
...@@ -1060,7 +1074,8 @@ static int ep_enable(struct usb_ep *ep, ...@@ -1060,7 +1074,8 @@ static int ep_enable(struct usb_ep *ep,
mEp->num = usb_endpoint_num(desc); mEp->num = usb_endpoint_num(desc);
mEp->type = usb_endpoint_type(desc); mEp->type = usb_endpoint_type(desc);
mEp->ep.maxpacket = usb_endpoint_maxp(desc); mEp->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff;
mEp->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc));
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
cap |= QH_IOS; cap |= QH_IOS;
...@@ -1246,6 +1261,9 @@ static int ep_set_halt(struct usb_ep *ep, int value) ...@@ -1246,6 +1261,9 @@ static int ep_set_halt(struct usb_ep *ep, int value)
if (ep == NULL || mEp->ep.desc == NULL) if (ep == NULL || mEp->ep.desc == NULL)
return -EINVAL; return -EINVAL;
if (usb_endpoint_xfer_isoc(mEp->ep.desc))
return -EOPNOTSUPP;
spin_lock_irqsave(mEp->lock, flags); spin_lock_irqsave(mEp->lock, flags);
#ifndef STALL_IN #ifndef STALL_IN
......
...@@ -50,6 +50,7 @@ struct ci13xxx_qh { ...@@ -50,6 +50,7 @@ struct ci13xxx_qh {
#define QH_MAX_PKT (0x07FFUL << 16) #define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29) #define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30) #define QH_MULT (0x0003UL << 30)
#define QH_ISO_MULT(x) ((x >> 11) & 0x03)
/* 1 */ /* 1 */
u32 curr; u32 curr;
/* 2 - 8 */ /* 2 - 8 */
......
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