usb: gadget: net2280: physically disable endpoint on disable operation
[firefly-linux-kernel-4.4.55.git] / drivers / usb / gadget / udc / net2280.c
index 9871b90195ad8eea42f3746946d740a248ef9f2c..5740e0d885bcefcaf9ac747149202918a6d385f1 100644 (file)
@@ -123,6 +123,8 @@ 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 inline void enable_pciirqenb(struct net2280_ep *ep)
 {
@@ -142,7 +144,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 +202,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 +234,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 +246,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 +274,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 +461,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 *);
@@ -1860,8 +1887,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 +2002,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);
@@ -2065,6 +2098,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 +2913,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 +3157,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)