usb: dwc3: gadget: Track connected SSP rate and lane count
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Wed, 20 Jan 2021 01:36:34 +0000 (17:36 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 6 Feb 2021 13:21:21 +0000 (14:21 +0100)
Track the number of connected lanes and speed in corresponding enum
usb_ssp_rate for SuperSpeed Plus capable device.

Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/2389592188d2e37a2ee45edaf04d942b19f3af82.1611106162.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c

index 61ac298..052b20d 100644 (file)
 #define DWC3_DEVTEN_USBRSTEN           BIT(1)
 #define DWC3_DEVTEN_DISCONNEVTEN       BIT(0)
 
+#define DWC3_DSTS_CONNLANES(n)         (((n) >> 30) & 0x3) /* DWC_usb32 only */
+
 /* Device Status Register */
 #define DWC3_DSTS_DCNRD                        BIT(29)
 
index 14ab559..0aa89e7 100644 (file)
@@ -2120,6 +2120,12 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
                                reg |= DWC3_DCFG_SUPERSPEED_PLUS;
                }
        }
+
+       if (DWC3_IP_IS(DWC32) &&
+           dwc->gadget_max_speed > USB_SPEED_UNKNOWN &&
+           dwc->gadget_max_speed < USB_SPEED_SUPER_PLUS)
+               reg &= ~DWC3_DCFG_NUMLANES(~0);
+
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 }
 
@@ -3369,12 +3375,18 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        struct dwc3_ep          *dep;
        int                     ret;
        u32                     reg;
+       u8                      lanes = 1;
        u8                      speed;
 
        reg = dwc3_readl(dwc->regs, DWC3_DSTS);
        speed = reg & DWC3_DSTS_CONNECTSPD;
        dwc->speed = speed;
 
+       if (DWC3_IP_IS(DWC32))
+               lanes = DWC3_DSTS_CONNLANES(reg) + 1;
+
+       dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN;
+
        /*
         * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
         * each time on Connect Done.
@@ -3389,6 +3401,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget->ep0->maxpacket = 512;
                dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
+
+               if (lanes > 1)
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_2x2;
+               else
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_2x1;
                break;
        case DWC3_DSTS_SUPERSPEED:
                /*
@@ -3410,6 +3427,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget->ep0->maxpacket = 512;
                dwc->gadget->speed = USB_SPEED_SUPER;
+
+               if (lanes > 1) {
+                       dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_1x2;
+               }
                break;
        case DWC3_DSTS_HIGHSPEED:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
@@ -3904,6 +3926,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        dev->platform_data              = dwc;
        dwc->gadget->ops                = &dwc3_gadget_ops;
        dwc->gadget->speed              = USB_SPEED_UNKNOWN;
+       dwc->gadget->ssp_rate           = USB_SSP_GEN_UNKNOWN;
        dwc->gadget->sg_supported       = true;
        dwc->gadget->name               = "dwc3-gadget";
        dwc->gadget->lpm_capable        = true;