summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJules Maselbas <jmaselbas@kalray.eu>2020-08-11 17:16:27 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2020-08-14 14:05:17 +0200
commitaff816e41739fbecaf23819b0ed8c863ede330c5 (patch)
treeb2a5a32ee37e35258b73e75686f3f593733754d7 /drivers/usb
parentacc46f0580a56f610b2a0158f71ef28bfe5034ae (diff)
downloadbarebox-aff816e41739fbecaf23819b0ed8c863ede330c5.tar.gz
barebox-aff816e41739fbecaf23819b0ed8c863ede330c5.tar.xz
usb: dwc2: host: Read dr_mode from device tree
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc2/core.c95
-rw-r--r--drivers/usb/dwc2/dwc2.c2
-rw-r--r--drivers/usb/dwc2/dwc2.h1
3 files changed, 98 insertions, 0 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 0046e955f4..6e8d30c224 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -1,6 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
#include "dwc2.h"
+/* Returns the controller's GHWCFG2.OTG_MODE. */
+static unsigned int dwc2_op_mode(struct dwc2 *dwc2)
+{
+ u32 ghwcfg2 = dwc2_readl(dwc2, GHWCFG2);
+
+ return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+ GHWCFG2_OP_MODE_SHIFT;
+}
+
+/* Returns true if the controller is host-only. */
+static bool dwc2_hw_is_host(struct dwc2 *dwc2)
+{
+ unsigned int op_mode = dwc2_op_mode(dwc2);
+
+ return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
+ (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
+}
+
+/* Returns true if the controller is device-only. */
+static bool dwc2_hw_is_device(struct dwc2 *dwc2)
+{
+ unsigned int op_mode = dwc2_op_mode(dwc2);
+
+ return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
+ (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
+}
+
void dwc2_set_param_otg_cap(struct dwc2 *dwc2)
{
u8 val;
@@ -494,6 +521,74 @@ void dwc2_gusbcfg_init(struct dwc2 *dwc2)
}
/*
+ * Check the dr_mode against the module configuration and hardware
+ * capabilities.
+ *
+ * The hardware, module, and dr_mode, can each be set to host, device,
+ * or otg. Check that all these values are compatible and adjust the
+ * value of dr_mode if possible.
+ *
+ * actual
+ * HW MOD dr_mode dr_mode
+ * ------------------------------
+ * HST HST any : HST
+ * HST DEV any : ---
+ * HST OTG any : HST
+ *
+ * DEV HST any : ---
+ * DEV DEV any : DEV
+ * DEV OTG any : DEV
+ *
+ * OTG HST any : HST
+ * OTG DEV any : DEV
+ * OTG OTG any : dr_mode
+ */
+int dwc2_get_dr_mode(struct dwc2 *dwc2)
+{
+ enum usb_dr_mode mode;
+
+ mode = of_usb_get_dr_mode(dwc2->dev->device_node, NULL);
+ dwc2->dr_mode = mode;
+
+ if (dwc2_hw_is_device(dwc2)) {
+ dwc2_dbg(dwc2, "Controller is device only\n");
+ if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
+ dwc2_err(dwc2,
+ "Controller does not support host mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_PERIPHERAL;
+ } else if (dwc2_hw_is_host(dwc2)) {
+ dwc2_dbg(dwc2, "Controller is host only\n");
+ if (IS_ENABLED(CONFIG_USB_DWC2_GADGET)) {
+ dwc2_err(dwc2,
+ "Controller does not support device mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_HOST;
+ } else {
+ dwc2_dbg(dwc2, "Controller is otg\n");
+ if (IS_ENABLED(CONFIG_USB_DWC2_HOST) &&
+ IS_ENABLED(CONFIG_USB_DWC2_GADGET))
+ mode = dwc2->dr_mode;
+ else if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
+ mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC2_GADGET))
+ mode = USB_DR_MODE_PERIPHERAL;
+ }
+
+ if (mode != dwc2->dr_mode) {
+ dwc2_warn(dwc2,
+ "Configuration mismatch. dr_mode forced to %s\n",
+ mode == USB_DR_MODE_HOST ? "host" : "device");
+
+ dwc2->dr_mode = mode;
+ }
+
+ return 0;
+}
+
+/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
diff --git a/drivers/usb/dwc2/dwc2.c b/drivers/usb/dwc2/dwc2.c
index a2f68d2507..5e1f73a8ab 100644
--- a/drivers/usb/dwc2/dwc2.c
+++ b/drivers/usb/dwc2/dwc2.c
@@ -57,6 +57,8 @@ static int dwc2_probe(struct device_d *dev)
/* Detect config values from hardware */
dwc2_get_hwparams(dwc2);
+ dwc2_get_dr_mode(dwc2);
+
dwc2_set_default_params(dwc2);
dma_set_mask(dev, DMA_BIT_MASK(32));
diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h
index 35c0d14153..d18b10cbff 100644
--- a/drivers/usb/dwc2/dwc2.h
+++ b/drivers/usb/dwc2/dwc2.h
@@ -21,6 +21,7 @@ void dwc2_flush_all_fifo(struct dwc2 *dwc2);
int dwc2_phy_init(struct dwc2 *dwc2, bool select_phy);
int dwc2_gahbcfg_init(struct dwc2 *dwc2);
void dwc2_gusbcfg_init(struct dwc2 *dwc2);
+int dwc2_get_dr_mode(struct dwc2 *dwc2);
int dwc2_core_reset(struct dwc2 *dwc2);
void dwc2_core_init(struct dwc2 *dwc2);