usb: dwc2: add otg_rev and otg_caps information for gadget driver
authorFabrice Gasnier <fabrice.gasnier@foss.st.com>
Wed, 13 Oct 2021 13:57:04 +0000 (15:57 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 25 Oct 2021 07:20:26 +0000 (09:20 +0200)
Currently the dwc2 doesn't fill in the 'otg_caps' of usb_gadget structure.
When registering a gadget device (e.g. via configfs), the
usb_otg_descriptor_init() checks the 'otg_caps' and 'otg_rev'. It defaults
to HNP and SRP bmAttributes if unspecified. There may be a mismatch with
what's being set in dwc2 params structure. This result in the descriptors
to be miss-configured in this case.

So replace 'otg_cap' bit field by 'otg_caps' structure, so hnp, srp and
otg_rev' can be configured directly in the params.
It's then provided to the gadget struct. These parameters can be tuned
for each platform. In case it's not set, it will default to current
behavior.

Also add option to setup these from the device tree by calling
of_usb_update_otg_caps(). This provides support for standard properties
such as "otg-rev", "hnp-disable" and "srp-disable" (see usb-drd.yaml).

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/1634133425-25670-4-git-send-email-fabrice.gasnier@foss.st.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core.h
drivers/usb/dwc2/debugfs.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/params.c

index cb9059a8444b5a601e56e141dfe87c7793181760..37185eb66ae4cd2f1e37e583cbb4ad1551a49602 100644 (file)
@@ -238,11 +238,14 @@ enum dwc2_ep0_state {
 /**
  * struct dwc2_core_params - Parameters for configuring the core
  *
- * @otg_cap:            Specifies the OTG capabilities.
- *                       0 - HNP and SRP capable
- *                       1 - SRP Only capable
- *                       2 - No HNP/SRP capable (always available)
- *                      Defaults to best available option (0, 1, then 2)
+ * @otg_caps:           Specifies the OTG capabilities. OTG caps from the platform parameters,
+ *                      used to setup the:
+ *                       - HNP and SRP capable
+ *                       - SRP Only capable
+ *                       - No HNP/SRP capable (always available)
+ *                       Defaults to best available option
+ *                       - OTG revision number the device is compliant with, in binary-coded
+ *                         decimal (i.e. 2.0 is 0200H). (see struct usb_otg_caps)
  * @host_dma:           Specifies whether to use slave or DMA mode for accessing
  *                      the data FIFOs. The driver will automatically detect the
  *                      value for this parameter if none is specified.
@@ -453,11 +456,7 @@ enum dwc2_ep0_state {
  * default described above.
  */
 struct dwc2_core_params {
-       u8 otg_cap;
-#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE         0
-#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE                1
-#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE      2
-
+       struct usb_otg_caps otg_caps;
        u8 phy_type;
 #define DWC2_PHY_TYPE_PARAM_FS         0
 #define DWC2_PHY_TYPE_PARAM_UTMI       1
index f13eed4231e1842daca0d9a4d73fb5a0dc1de992..1d72ece9cfe480d15b0a733bc3ad7e3e869d49c5 100644 (file)
@@ -670,7 +670,9 @@ static int params_show(struct seq_file *seq, void *v)
        struct dwc2_core_params *p = &hsotg->params;
        int i;
 
-       print_param(seq, p, otg_cap);
+       print_param(seq, p, otg_caps.hnp_support);
+       print_param(seq, p, otg_caps.srp_support);
+       print_param(seq, p, otg_caps.otg_rev);
        print_param(seq, p, dma_desc_enable);
        print_param(seq, p, dma_desc_fs_enable);
        print_param(seq, p, speed);
index 11d85a6e0b0dcade3c1bef40efa96924ce12e06a..4ab4a1d5062b2a0ebeecf5c0b77ef3537d1f25e6 100644 (file)
@@ -4966,6 +4966,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
        hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
        hsotg->gadget.name = dev_name(dev);
+       hsotg->gadget.otg_caps = &hsotg->params.otg_caps;
        hsotg->remote_wakeup_allowed = 0;
 
        if (hsotg->params.lpm)
index a215ec9e172e69747e5d7c099def5a363b172431..13c779a28e94fa01b6219ca941625f187579c320 100644 (file)
@@ -138,19 +138,15 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
 
        switch (hsotg->hw_params.op_mode) {
        case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-               if (hsotg->params.otg_cap ==
-                               DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
+               if (hsotg->params.otg_caps.hnp_support &&
+                   hsotg->params.otg_caps.srp_support)
                        usbcfg |= GUSBCFG_HNPCAP;
-               if (hsotg->params.otg_cap !=
-                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
-                       usbcfg |= GUSBCFG_SRPCAP;
-               break;
+               fallthrough;
 
        case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
        case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
        case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-               if (hsotg->params.otg_cap !=
-                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+               if (hsotg->params.otg_caps.srp_support)
                        usbcfg |= GUSBCFG_SRPCAP;
                break;
 
index 59e119345994756166a4a4d4ef44bfd0c6302d03..99d3b6284e01117cf3a897c7831c91450e84c5b9 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/usb/of.h>
 
 #include "core.h"
 
@@ -53,7 +54,8 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->speed = DWC2_SPEED_PARAM_HIGH;
        p->host_rx_fifo_size = 512;
        p->host_nperio_tx_fifo_size = 512;
@@ -84,7 +86,8 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->host_rx_fifo_size = 525;
        p->host_nperio_tx_fifo_size = 128;
        p->host_perio_tx_fifo_size = 256;
@@ -97,7 +100,8 @@ static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = 2;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->host_rx_fifo_size = 288;
        p->host_nperio_tx_fifo_size = 128;
        p->host_perio_tx_fifo_size = 96;
@@ -111,7 +115,8 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->speed = DWC2_SPEED_PARAM_HIGH;
        p->host_rx_fifo_size = 512;
        p->host_nperio_tx_fifo_size = 500;
@@ -144,7 +149,8 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->speed = DWC2_SPEED_PARAM_FULL;
        p->host_rx_fifo_size = 128;
        p->host_nperio_tx_fifo_size = 96;
@@ -168,7 +174,8 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->speed = DWC2_SPEED_PARAM_FULL;
        p->host_rx_fifo_size = 128;
        p->host_nperio_tx_fifo_size = 96;
@@ -188,7 +195,8 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
-       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->otg_caps.hnp_support = false;
+       p->otg_caps.srp_support = false;
        p->activate_stm_id_vb_detection = !device_property_read_bool(hsotg->dev, "usb-role-switch");
        p->host_rx_fifo_size = 440;
        p->host_nperio_tx_fifo_size = 256;
@@ -241,23 +249,22 @@ MODULE_DEVICE_TABLE(acpi, dwc2_acpi_match);
 
 static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg)
 {
-       u8 val;
-
        switch (hsotg->hw_params.op_mode) {
        case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-               val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
+               hsotg->params.otg_caps.hnp_support = true;
+               hsotg->params.otg_caps.srp_support = true;
                break;
        case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
        case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
        case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-               val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
+               hsotg->params.otg_caps.hnp_support = false;
+               hsotg->params.otg_caps.srp_support = true;
                break;
        default:
-               val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+               hsotg->params.otg_caps.hnp_support = false;
+               hsotg->params.otg_caps.srp_support = false;
                break;
        }
-
-       hsotg->params.otg_cap = val;
 }
 
 static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg)
@@ -463,6 +470,8 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
                                                       &p->g_tx_fifo_size[1],
                                                       num);
                }
+
+               of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps);
        }
 
        if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
@@ -473,29 +482,27 @@ static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
 {
        int valid = 1;
 
-       switch (hsotg->params.otg_cap) {
-       case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
+       if (hsotg->params.otg_caps.hnp_support && hsotg->params.otg_caps.srp_support) {
+               /* check HNP && SRP capable */
                if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
                        valid = 0;
-               break;
-       case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
-               switch (hsotg->hw_params.op_mode) {
-               case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-               case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-                       break;
-               default:
-                       valid = 0;
-                       break;
+       } else if (!hsotg->params.otg_caps.hnp_support) {
+               /* check SRP only capable */
+               if (hsotg->params.otg_caps.srp_support) {
+                       switch (hsotg->hw_params.op_mode) {
+                       case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+                       case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+                       case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+                       case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+                               break;
+                       default:
+                               valid = 0;
+                               break;
+                       }
                }
-               break;
-       case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE:
-               /* always valid */
-               break;
-       default:
+               /* else: NO HNP && NO SRP capable: always valid */
+       } else {
                valid = 0;
-               break;
        }
 
        if (!valid)