diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/usb/gadget/udc/net2280.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/usb/gadget/udc/net2280.c')
-rw-r--r-- | kernel/drivers/usb/gadget/udc/net2280.c | 237 |
1 files changed, 192 insertions, 45 deletions
diff --git a/kernel/drivers/usb/gadget/udc/net2280.c b/kernel/drivers/usb/gadget/udc/net2280.c index 9871b9019..6706aef90 100644 --- a/kernel/drivers/usb/gadget/udc/net2280.c +++ b/kernel/drivers/usb/gadget/udc/net2280.c @@ -74,19 +74,58 @@ static const char driver_desc[] = DRIVER_DESC; static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 }; static const char ep0name[] = "ep0"; -static const char *const ep_name[] = { - ep0name, - "ep-a", "ep-b", "ep-c", "ep-d", - "ep-e", "ep-f", "ep-g", "ep-h", -}; -/* Endpoint names for usb3380 advance mode */ -static const char *const ep_name_adv[] = { - ep0name, - "ep1in", "ep2out", "ep3in", "ep4out", - "ep1out", "ep2in", "ep3out", "ep4in", +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info_dft[] = { /* Default endpoint configuration */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-a", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-b", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-c", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-d", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-e", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-f", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-g", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-h", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), +}, ep_info_adv[] = { /* Endpoints for usb3380 advance mode */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep1out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep3out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), }; +#undef EP_INFO + /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable @@ -123,6 +162,11 @@ static char *type_string(u8 bmAttributes) #define valid_bit cpu_to_le32(BIT(VALID_BIT)) #define dma_done_ie cpu_to_le32(BIT(DMA_DONE_INTERRUPT_ENABLE)) +static void ep_clear_seqnum(struct net2280_ep *ep); +static void stop_activity(struct net2280 *dev, + struct usb_gadget_driver *driver); +static void ep0_start(struct net2280 *dev); + /*-------------------------------------------------------------------------*/ static inline void enable_pciirqenb(struct net2280_ep *ep) { @@ -142,7 +186,9 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct net2280 *dev; struct net2280_ep *ep; - u32 max, tmp; + u32 max; + u32 tmp = 0; + u32 type; unsigned long flags; static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; int ret = 0; @@ -198,15 +244,29 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* set type, direction, address; reset fifo counters */ writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); - tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - if (tmp == USB_ENDPOINT_XFER_INT) { + + if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + tmp = readl(&ep->cfg->ep_cfg); + /* If USB ep number doesn't match hardware ep number */ + if ((tmp & 0xf) != usb_endpoint_num(desc)) { + ret = -EINVAL; + spin_unlock_irqrestore(&dev->lock, flags); + goto print_err; + } + if (ep->is_in) + tmp &= ~USB3380_EP_CFG_MASK_IN; + else + tmp &= ~USB3380_EP_CFG_MASK_OUT; + } + type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + if (type == USB_ENDPOINT_XFER_INT) { /* erratum 0105 workaround prevents hs NYET */ if (dev->chiprev == 0100 && dev->gadget.speed == USB_SPEED_HIGH && !(desc->bEndpointAddress & USB_DIR_IN)) writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); - } else if (tmp == USB_ENDPOINT_XFER_BULK) { + } else if (type == USB_ENDPOINT_XFER_BULK) { /* catch some particularly blatant driver bugs */ if ((dev->gadget.speed == USB_SPEED_SUPER && max != 1024) || (dev->gadget.speed == USB_SPEED_HIGH && max != 512) || @@ -216,10 +276,10 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto print_err; } } - ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); + ep->is_iso = (type == USB_ENDPOINT_XFER_ISOC); /* Enable this endpoint */ if (dev->quirks & PLX_LEGACY) { - tmp <<= ENDPOINT_TYPE; + tmp |= type << ENDPOINT_TYPE; tmp |= desc->bEndpointAddress; /* default full fifo lines */ tmp |= (4 << ENDPOINT_BYTE_COUNT); @@ -228,17 +288,17 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } else { /* In Legacy mode, only OUT endpoints are used */ if (dev->enhanced_mode && ep->is_in) { - tmp <<= IN_ENDPOINT_TYPE; + tmp |= type << IN_ENDPOINT_TYPE; tmp |= BIT(IN_ENDPOINT_ENABLE); - /* Not applicable to Legacy */ - tmp |= BIT(ENDPOINT_DIRECTION); } else { - tmp <<= OUT_ENDPOINT_TYPE; + tmp |= type << OUT_ENDPOINT_TYPE; tmp |= BIT(OUT_ENDPOINT_ENABLE); tmp |= (ep->is_in << ENDPOINT_DIRECTION); } - tmp |= usb_endpoint_num(desc); + tmp |= (4 << ENDPOINT_BYTE_COUNT); + if (!dev->enhanced_mode) + tmp |= usb_endpoint_num(desc); tmp |= (ep->ep.maxburst << MAX_BURST_SIZE); } @@ -256,6 +316,8 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } + if (dev->quirks & PLX_SUPERSPEED) + ep_clear_seqnum(ep); writel(tmp, &ep->cfg->ep_cfg); /* enable irqs */ @@ -441,6 +503,13 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs, BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) | BIT(DATA_OUT_PING_TOKEN_INTERRUPT) | BIT(DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat); + + tmp = readl(&ep->cfg->ep_cfg); + if (ep->is_in) + tmp &= ~USB3380_EP_CFG_MASK_IN; + else + tmp &= ~USB3380_EP_CFG_MASK_OUT; + writel(tmp, &ep->cfg->ep_cfg); } static void nuke(struct net2280_ep *); @@ -1468,16 +1537,46 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) spin_lock_irqsave(&dev->lock, flags); tmp = readl(&dev->usb->usbctl); dev->softconnect = (is_on != 0); - if (is_on) - tmp |= BIT(USB_DETECT_ENABLE); - else - tmp &= ~BIT(USB_DETECT_ENABLE); - writel(tmp, &dev->usb->usbctl); + if (is_on) { + ep0_start(dev); + writel(tmp | BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); + } else { + writel(tmp & ~BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); + stop_activity(dev, dev->driver); + } + spin_unlock_irqrestore(&dev->lock, flags); return 0; } +static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + char name[8]; + struct usb_ep *ep; + + if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = gadget_find_ep_by_name(_gadget, "ep-e"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep-f"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } + + /* USB3380: use same address for usb and hardware endpoints */ + snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), + usb_endpoint_dir_in(desc) ? "in" : "out"); + ep = gadget_find_ep_by_name(_gadget, name); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + + return NULL; +} + static int net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); static int net2280_stop(struct usb_gadget *_gadget); @@ -1489,6 +1588,7 @@ static const struct usb_gadget_ops net2280_ops = { .pullup = net2280_pullup, .udc_start = net2280_start, .udc_stop = net2280_stop, + .match_ep = net2280_match_ep, }; /*-------------------------------------------------------------------------*/ @@ -1813,7 +1913,7 @@ static void defect7374_disable_data_eps(struct net2280 *dev) for (i = 1; i < 5; i++) { ep = &dev->ep[i]; - writel(0, &ep->cfg->ep_cfg); + writel(i, &ep->cfg->ep_cfg); } /* CSROUT, CSRIN, PCIOUT, PCIIN, STATIN, RCIN */ @@ -1860,8 +1960,8 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev) tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) | (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) | ((dev->enhanced_mode) ? - BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) | - BIT(IN_ENDPOINT_ENABLE)); + BIT(OUT_ENDPOINT_ENABLE) | BIT(IN_ENDPOINT_ENABLE) : + BIT(ENDPOINT_ENABLE))); for (i = 1; i < 5; i++) writel(tmp, &dev->ep[i].cfg->ep_cfg); @@ -1975,9 +2075,15 @@ static void usb_reset_338x(struct net2280 *dev) /* clear old dma and irq state */ for (tmp = 0; tmp < 4; tmp++) { struct net2280_ep *ep = &dev->ep[tmp + 1]; + struct net2280_dma_regs __iomem *dma; - if (ep->dma) + if (ep->dma) { abort_dma(ep); + } else { + dma = &dev->dma[tmp]; + writel(BIT(DMA_ABORT), &dma->dmastat); + writel(0, &dma->dmactl); + } } writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1); @@ -2016,7 +2122,8 @@ static void usb_reinit_228x(struct net2280 *dev) for (tmp = 0; tmp < 7; tmp++) { struct net2280_ep *ep = &dev->ep[tmp]; - ep->ep.name = ep_name[tmp]; + ep->ep.name = ep_info_dft[tmp].name; + ep->ep.caps = ep_info_dft[tmp].caps; ep->dev = dev; ep->num = tmp; @@ -2056,7 +2163,10 @@ static void usb_reinit_338x(struct net2280 *dev) for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep[i]; - ep->ep.name = dev->enhanced_mode ? ep_name_adv[i] : ep_name[i]; + ep->ep.name = dev->enhanced_mode ? ep_info_adv[i].name : + ep_info_dft[i].name; + ep->ep.caps = dev->enhanced_mode ? ep_info_adv[i].caps : + ep_info_dft[i].caps; ep->dev = dev; ep->num = i; @@ -2065,6 +2175,12 @@ static void usb_reinit_338x(struct net2280 *dev) if (dev->enhanced_mode) { ep->cfg = &dev->epregs[ne[i]]; + /* + * Set USB endpoint number, hardware allows same number + * in both directions. + */ + if (i > 0 && i < 5) + writel(ne[i], &ep->cfg->ep_cfg); ep->regs = (struct net2280_ep_regs __iomem *) (((void __iomem *)&dev->epregs[ne[i]]) + ep_reg_addr[i]); @@ -2874,6 +2990,26 @@ next_endpoints3: return; } +static void usb338x_handle_ep_intr(struct net2280 *dev, u32 stat0) +{ + u32 index; + u32 bit; + + for (index = 0; index < ARRAY_SIZE(ep_bit); index++) { + bit = BIT(ep_bit[index]); + + if (!stat0) + break; + + if (!(stat0 & bit)) + continue; + + stat0 &= ~bit; + + handle_ep_small(&dev->ep[index]); + } +} + static void handle_stat0_irqs(struct net2280 *dev, u32 stat) { struct net2280_ep *ep; @@ -3098,20 +3234,31 @@ do_stall: #undef w_length next_endpoints: - /* endpoint data irq ? */ - scratch = stat & 0x7f; - stat &= ~0x7f; - for (num = 0; scratch; num++) { - u32 t; - - /* do this endpoint's FIFO and queue need tending? */ - t = BIT(num); - if ((scratch & t) == 0) - continue; - scratch ^= t; + if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + u32 mask = (BIT(ENDPOINT_0_INTERRUPT) | + USB3380_IRQSTAT0_EP_INTR_MASK_IN | + USB3380_IRQSTAT0_EP_INTR_MASK_OUT); + + if (stat & mask) { + usb338x_handle_ep_intr(dev, stat & mask); + stat &= ~mask; + } + } else { + /* endpoint data irq ? */ + scratch = stat & 0x7f; + stat &= ~0x7f; + for (num = 0; scratch; num++) { + u32 t; + + /* do this endpoint's FIFO and queue need tending? */ + t = BIT(num); + if ((scratch & t) == 0) + continue; + scratch ^= t; - ep = &dev->ep[num]; - handle_ep_small(ep); + ep = &dev->ep[num]; + handle_ep_small(ep); + } } if (stat) |