[U-Boot] [PATCH v3 0/4] Extend xhci-dwc3

From: Patrice Chotard patrice.chotard@st.com
v3: _ introduce generic_phy_valid() method _ add Reviewed-by v2: _ use dev_get_addr() in PATCH 1 and removed useless piece of code
Patrice Chotard (4): usb: host: xhci-dwc3: Convert driver to DM usb: host: xhci-dwc3: Add dual role mode support from DT drivers: phy: add generic_phy_valid() method usb: host: xhci-dwc3: Add generic PHY support
drivers/phy/phy-uclass.c | 5 +++ drivers/usb/host/xhci-dwc3.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/generic-phy.h | 8 ++++ 3 files changed, 104 insertions(+)

From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org ---
v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..ab75fb7 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h> + +#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR; + +struct xhci_dwc3_priv { + struct xhci_ctrl ctrl; +}; + void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, @@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); } + +static int xhci_dwc3_probe(struct udevice *dev) +{ + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + struct xhci_hcor *hcor; + struct xhci_hccr *hccr; + struct dwc3 *dwc3_reg; + + hccr = (struct xhci_hccr *)dev_get_addr(dev); + hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); + + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET); + + dwc3_core_init(dwc3_reg); + + return xhci_register(dev, hccr, hcor); +} + +static int xhci_dwc3_remove(struct udevice *dev) +{ + return xhci_deregister(dev); +} + +static const struct udevice_id xhci_dwc3_ids[] = { + { .compatible = "snps,dwc3" }, + { } +}; + +U_BOOT_DRIVER(xhci_dwc3) = { + .name = "xhci-dwc3", + .id = UCLASS_USB, + .of_match = xhci_dwc3_ids, + .probe = xhci_dwc3_probe, + .remove = xhci_dwc3_remove, + .ops = &xhci_usb_ops, + .priv_auto_alloc_size = sizeof(struct xhci_dwc3_priv), + .platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +};

From: Patrice Chotard patrice.chotard@st.com
DWC3 dual role mode is selected using DT "dr_mode" property. If not found, DWC3 controller is configured in HOST mode by default
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
v3: _ none v2: _ none
drivers/usb/host/xhci-dwc3.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index ab75fb7..8367ba2 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -15,6 +15,7 @@ #include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h> +#include <linux/usb/otg.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -114,6 +115,7 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hcor *hcor; struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; + enum usb_dr_mode dr_mode;
hccr = (struct xhci_hccr *)dev_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + @@ -123,6 +125,13 @@ static int xhci_dwc3_probe(struct udevice *dev)
dwc3_core_init(dwc3_reg);
+ dr_mode = usb_get_dr_mode(dev_of_offset(dev)); + if (dr_mode == USB_DR_MODE_UNKNOWN) + /* by default set dual role mode to HOST */ + dr_mode = USB_DR_MODE_HOST; + + dwc3_set_mode(dwc3_reg, dr_mode); + return xhci_register(dev, hccr, hcor); }

From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0d8bef7..43a7c18 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -133,6 +133,11 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; }
+bool generic_phy_valid(struct phy *phy) +{ + return phy->dev != NULL; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index d8cf0c9..53206f0 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -221,4 +221,12 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy);
+/** + * generic_phy_valid() - check if PHY port is valid + * + * @phy: the PHY port to check + * @return TRUE if valid, or FALSE + */ +bool generic_phy_valid(struct phy *phy); + #endif /*__GENERIC_PHY_H */

On 23/05/2017 11:57, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0d8bef7..43a7c18 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -133,6 +133,11 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; }
+bool generic_phy_valid(struct phy *phy) +{
- return phy->dev != NULL;
+}
Not that it has big impact but I would have made it an inline function
Also note that there is a loophole in generic_phy_get_by_index() that needs to be fixed before phy->dev can be used to check if the phy is valid; phy->dev must be set to NULL if generic_phy_get_by_index() fails.
Jean-Jacques
UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index d8cf0c9..53206f0 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -221,4 +221,12 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy);
+/**
- generic_phy_valid() - check if PHY port is valid
- @phy: the PHY port to check
- @return TRUE if valid, or FALSE
- */
+bool generic_phy_valid(struct phy *phy);
- #endif /*__GENERIC_PHY_H */

On 05/24/2017 03:24 PM, Jean-Jacques Hiblot wrote:
On 23/05/2017 11:57, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0d8bef7..43a7c18 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -133,6 +133,11 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; } +bool generic_phy_valid(struct phy *phy) +{
- return phy->dev != NULL;
+}
Not that it has big impact but I would have made it an inline function
The inline is just a hint , the compiler can decide on that itself.
Also note that there is a loophole in generic_phy_get_by_index() that needs to be fixed before phy->dev can be used to check if the phy is valid; phy->dev must be set to NULL if generic_phy_get_by_index() fails.
Jean-Jacques
UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index d8cf0c9..53206f0 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -221,4 +221,12 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +/**
- generic_phy_valid() - check if PHY port is valid
- @phy: the PHY port to check
- @return TRUE if valid, or FALSE
- */
+bool generic_phy_valid(struct phy *phy);
- #endif /*__GENERIC_PHY_H */

Hi Jean-Jacques
On 05/24/2017 03:24 PM, Jean-Jacques Hiblot wrote:
On 23/05/2017 11:57, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0d8bef7..43a7c18 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -133,6 +133,11 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; } +bool generic_phy_valid(struct phy *phy) +{
- return phy->dev != NULL;
+}
Not that it has big impact but I would have made it an inline function
Also note that there is a loophole in generic_phy_get_by_index() that needs to be fixed before phy->dev can be used to check if the phy is valid; phy->dev must be set to NULL if generic_phy_get_by_index() fails.
Thanks for pointing this. I will send a patch fixing this and include it in the v4 of my series " Extend xhci-dwc3"
Thanks
Patrice
Jean-Jacques
UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index d8cf0c9..53206f0 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -221,4 +221,12 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +/**
- generic_phy_valid() - check if PHY port is valid
- @phy: the PHY port to check
- @return TRUE if valid, or FALSE
- */
+bool generic_phy_valid(struct phy *phy);
- #endif /*__GENERIC_PHY_H */

On 23 May 2017 at 03:57, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

From: Patrice Chotard patrice.chotard@st.com
Add support of generic PHY framework support
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
v3: _ use generic_phy_valid() method v2: _ none
drivers/usb/host/xhci-dwc3.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 8367ba2..b8004f5 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -10,6 +10,8 @@
#include <common.h> #include <dm.h> +#include <fdtdec.h> +#include <generic-phy.h> #include <usb.h>
#include "xhci.h" @@ -19,6 +21,10 @@
DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_platdata { + struct phy usb_phy; +}; + struct xhci_dwc3_priv { struct xhci_ctrl ctrl; }; @@ -116,11 +122,26 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; enum usb_dr_mode dr_mode; + int ret;
hccr = (struct xhci_hccr *)dev_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
+ ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy); + if (ret) { + if (ret != -ENOENT) { + error("Failed to get USB PHY for %s\n", dev->name); + return ret; + } + } else { + ret = generic_phy_init(&plat->usb_phy); + if (ret) { + error("Can't init USB PHY for %s\n", dev->name); + return ret; + } + } + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg); @@ -137,6 +158,17 @@ static int xhci_dwc3_probe(struct udevice *dev)
static int xhci_dwc3_remove(struct udevice *dev) { + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + int ret; + + if (generic_phy_valid(&plat->usb_phy)) { + ret = generic_phy_exit(&plat->usb_phy); + if (ret) { + error("Can't deinit USB PHY for %s\n", dev->name); + return ret; + } + } + return xhci_deregister(dev); }

Fyi, a v4 is available with a fix reported by Jean-Jacques Hiblot
On 05/23/2017 11:57 AM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
v3: _ introduce generic_phy_valid() method _ add Reviewed-by v2: _ use dev_get_addr() in PATCH 1 and removed useless piece of code
Patrice Chotard (4): usb: host: xhci-dwc3: Convert driver to DM usb: host: xhci-dwc3: Add dual role mode support from DT drivers: phy: add generic_phy_valid() method usb: host: xhci-dwc3: Add generic PHY support
drivers/phy/phy-uclass.c | 5 +++ drivers/usb/host/xhci-dwc3.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/generic-phy.h | 8 ++++ 3 files changed, 104 insertions(+)
participants (5)
-
Jean-Jacques Hiblot
-
Marek Vasut
-
Patrice CHOTARD
-
patrice.chotard@st.com
-
Simon Glass