diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/cache/Kconfig | 6 | ||||
-rw-r--r-- | drivers/cache/Makefile | 2 | ||||
-rw-r--r-- | drivers/cache/cache-andes-l2.c (renamed from drivers/cache/cache-v5l2.c) | 40 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk_rk3328.c | 4 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk_rk3399.c | 67 | ||||
-rw-r--r-- | drivers/cpu/riscv_cpu.c | 2 | ||||
-rw-r--r-- | drivers/phy/phy-npcm-usb.c | 27 | ||||
-rw-r--r-- | drivers/phy/rockchip/phy-rockchip-usbdp.c | 126 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-uclass.c | 2 | ||||
-rw-r--r-- | drivers/usb/cdns3/gadget.c | 4 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 47 |
12 files changed, 204 insertions, 125 deletions
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 26c2d80a1c5..4f358657444 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -22,11 +22,11 @@ config L2X0_CACHE ARMv7(32-bit) devices. The driver configures the cache settings found in the device tree. -config V5L2_CACHE - bool "Andes V5L2 cache driver" +config ANDES_L2_CACHE + bool "Andes L2 cache driver" select CACHE help - Support Andes V5L2 cache controller in AE350 platform. + Support Andes L2 cache controller in AE350 platform. It will configure tag and data ram timing control from the device tree and enable L2 cache. diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 78e673d09e5..e1b71e0ed51 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache-uclass.o obj-$(CONFIG_SANDBOX) += sandbox_cache.o obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o obj-$(CONFIG_NCORE_CACHE) += cache-ncore.o -obj-$(CONFIG_V5L2_CACHE) += cache-v5l2.o +obj-$(CONFIG_ANDES_L2_CACHE) += cache-andes-l2.o obj-$(CONFIG_SIFIVE_CCACHE) += cache-sifive-ccache.o obj-$(CONFIG_SIFIVE_PL2) += cache-sifive-pl2.o diff --git a/drivers/cache/cache-v5l2.c b/drivers/cache/cache-andes-l2.c index f0b8ecc8807..7de8f16852d 100644 --- a/drivers/cache/cache-v5l2.c +++ b/drivers/cache/cache-andes-l2.c @@ -72,7 +72,7 @@ static u32 status_bit_offset = 0x4; DECLARE_GLOBAL_DATA_PTR; -struct v5l2_plat { +struct andes_l2_plat { struct l2cache *regs; u32 iprefetch; u32 dprefetch; @@ -80,9 +80,9 @@ struct v5l2_plat { u32 dram_ctl[2]; }; -static int v5l2_enable(struct udevice *dev) +static int andes_l2_enable(struct udevice *dev) { - struct v5l2_plat *plat = dev_get_plat(dev); + struct andes_l2_plat *plat = dev_get_plat(dev); volatile struct l2cache *regs = plat->regs; if (regs) @@ -91,9 +91,9 @@ static int v5l2_enable(struct udevice *dev) return 0; } -static int v5l2_disable(struct udevice *dev) +static int andes_l2_disable(struct udevice *dev) { - struct v5l2_plat *plat = dev_get_plat(dev); + struct andes_l2_plat *plat = dev_get_plat(dev); volatile struct l2cache *regs = plat->regs; u8 hart = gd->arch.boot_hart; void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart); @@ -113,9 +113,9 @@ static int v5l2_disable(struct udevice *dev) return 0; } -static int v5l2_of_to_plat(struct udevice *dev) +static int andes_l2_of_to_plat(struct udevice *dev) { - struct v5l2_plat *plat = dev_get_plat(dev); + struct andes_l2_plat *plat = dev_get_plat(dev); struct l2cache *regs; regs = dev_read_addr_ptr(dev); @@ -137,9 +137,9 @@ static int v5l2_of_to_plat(struct udevice *dev) return 0; } -static int v5l2_probe(struct udevice *dev) +static int andes_l2_probe(struct udevice *dev) { - struct v5l2_plat *plat = dev_get_plat(dev); + struct andes_l2_plat *plat = dev_get_plat(dev); struct l2cache *regs = plat->regs; u32 cfg_val, ctl_val; @@ -182,23 +182,23 @@ static int v5l2_probe(struct udevice *dev) return 0; } -static const struct udevice_id v5l2_cache_ids[] = { +static const struct udevice_id andes_l2_cache_ids[] = { { .compatible = "cache" }, {} }; -static const struct cache_ops v5l2_cache_ops = { - .enable = v5l2_enable, - .disable = v5l2_disable, +static const struct cache_ops andes_l2_cache_ops = { + .enable = andes_l2_enable, + .disable = andes_l2_disable, }; -U_BOOT_DRIVER(v5l2_cache) = { - .name = "v5l2_cache", +U_BOOT_DRIVER(andes_l2_cache) = { + .name = "andes_l2_cache", .id = UCLASS_CACHE, - .of_match = v5l2_cache_ids, - .of_to_plat = v5l2_of_to_plat, - .probe = v5l2_probe, - .plat_auto = sizeof(struct v5l2_plat), - .ops = &v5l2_cache_ops, + .of_match = andes_l2_cache_ids, + .of_to_plat = andes_l2_of_to_plat, + .probe = andes_l2_probe, + .plat_auto = sizeof(struct andes_l2_plat), + .ops = &andes_l2_cache_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index 4b94d6364d1..a4f6dd5a0f5 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -705,6 +705,9 @@ static ulong rk3328_clk_get_rate(struct clk *clk) case PCLK_HDMIPHY: rate = rk3328_hdmiphy_get_clk(priv->cru); break; + case SCLK_USB3OTG_REF: + rate = OSC_HZ; + break; default: return -ENOENT; } @@ -779,6 +782,7 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) case PCLK_DDR: case ACLK_GMAC: case PCLK_GMAC: + case SCLK_USB3OTG_REF: case SCLK_USB3OTG_SUSPEND: case USB480M: return 0; diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index cc414c38432..24cefebd1b2 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -925,6 +925,26 @@ static ulong rk3399_saradc_set_clk(struct rockchip_cru *cru, uint hz) return rk3399_saradc_get_clk(cru); } +static ulong rk3399_pciephy_get_clk(struct rockchip_cru *cru) +{ + if (readl(&cru->clksel_con[18]) & BIT(10)) + return 100 * MHz; + else + return OSC_HZ; +} + +static ulong rk3399_pciephy_set_clk(struct rockchip_cru *cru, uint hz) +{ + if (hz == 100 * MHz) + rk_setreg(&cru->clksel_con[18], BIT(10)); + else if (hz == OSC_HZ) + rk_clrreg(&cru->clksel_con[18], BIT(10)); + else + return -EINVAL; + + return rk3399_pciephy_get_clk(cru); +} + static ulong rk3399_clk_get_rate(struct clk *clk) { struct rk3399_clk_priv *priv = dev_get_priv(clk->dev); @@ -955,7 +975,9 @@ static ulong rk3399_clk_get_rate(struct clk *clk) case SCLK_UART1: case SCLK_UART2: case SCLK_UART3: - return 24000000; + case SCLK_USB3OTG0_REF: + case SCLK_USB3OTG1_REF: + return OSC_HZ; case PCLK_HDMI_CTRL: break; case DCLK_VOP0: @@ -966,10 +988,14 @@ static ulong rk3399_clk_get_rate(struct clk *clk) case SCLK_SARADC: rate = rk3399_saradc_get_clk(priv->cru); break; + case SCLK_PCIEPHY_REF: + rate = rk3399_pciephy_get_clk(priv->cru); + break; case ACLK_VIO: case ACLK_HDCP: case ACLK_GIC_PRE: case PCLK_DDR: + case ACLK_VDU: break; case PCLK_ALIVE: case PCLK_WDT: @@ -1048,7 +1074,7 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate) * return 0 to satisfy clk_set_defaults during device probe. */ return 0; - case SCLK_DDRCLK: + case SCLK_DDRC: ret = rk3399_ddr_set_clk(priv->cru, rate); break; case PCLK_EFUSE1024NS: @@ -1056,10 +1082,14 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate) case SCLK_SARADC: ret = rk3399_saradc_set_clk(priv->cru, rate); break; + case SCLK_PCIEPHY_REF: + ret = rk3399_pciephy_set_clk(priv->cru, rate); + break; case ACLK_VIO: case ACLK_HDCP: case ACLK_GIC_PRE: case PCLK_DDR: + case ACLK_VDU: return 0; default: log_debug("Unknown clock %lu\n", clk->id); @@ -1105,12 +1135,39 @@ static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, return -EINVAL; } +static int __maybe_unused rk3399_pciephy_set_parent(struct clk *clk, + struct clk *parent) +{ + struct rk3399_clk_priv *priv = dev_get_priv(clk->dev); + const char *clock_output_name; + int ret; + + if (parent->dev == clk->dev && parent->id == SCLK_PCIEPHY_REF100M) { + rk_setreg(&priv->cru->clksel_con[18], BIT(10)); + return 0; + } + + ret = dev_read_string_index(parent->dev, "clock-output-names", + parent->id, &clock_output_name); + if (ret < 0) + return -ENODATA; + + if (!strcmp(clock_output_name, "xin24m")) { + rk_clrreg(&priv->cru->clksel_con[18], BIT(10)); + return 0; + } + + return -EINVAL; +} + static int __maybe_unused rk3399_clk_set_parent(struct clk *clk, struct clk *parent) { switch (clk->id) { case SCLK_RMII_SRC: return rk3399_gmac_set_parent(clk, parent); + case SCLK_PCIEPHY_REF: + return rk3399_pciephy_set_parent(clk, parent); } debug("%s: unsupported clk %ld\n", __func__, clk->id); @@ -1201,7 +1258,8 @@ static int rk3399_clk_enable(struct clk *clk) rk_clrreg(&priv->cru->clkgate_con[13], BIT(7)); break; case SCLK_PCIEPHY_REF: - rk_clrreg(&priv->cru->clksel_con[18], BIT(10)); + if (readl(&priv->cru->clksel_con[18]) & BIT(10)) + rk_clrreg(&priv->cru->clkgate_con[12], BIT(6)); break; default: debug("%s: unsupported clk %ld\n", __func__, clk->id); @@ -1295,7 +1353,8 @@ static int rk3399_clk_disable(struct clk *clk) rk_setreg(&priv->cru->clkgate_con[13], BIT(7)); break; case SCLK_PCIEPHY_REF: - rk_clrreg(&priv->cru->clksel_con[18], BIT(10)); + if (readl(&priv->cru->clksel_con[18]) & BIT(10)) + rk_setreg(&priv->cru->clkgate_con[12], BIT(6)); break; default: debug("%s: unsupported clk %ld\n", __func__, clk->id); diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c index 4f2958a23ce..4fff4658b5f 100644 --- a/drivers/cpu/riscv_cpu.c +++ b/drivers/cpu/riscv_cpu.c @@ -23,7 +23,7 @@ static int riscv_cpu_get_desc(const struct udevice *dev, char *buf, int size) const char *cpu; cpu = dev_read_string(dev, "compatible"); - if (size < (strlen(cpu) + 1)) + if (!cpu || size < (strlen(cpu) + 1)) return -ENOSPC; strcpy(buf, cpu); diff --git a/drivers/phy/phy-npcm-usb.c b/drivers/phy/phy-npcm-usb.c index 028fedf92dc..2cca0f4a054 100644 --- a/drivers/phy/phy-npcm-usb.c +++ b/drivers/phy/phy-npcm-usb.c @@ -11,6 +11,7 @@ #include <dm/device_compat.h> #include <linux/bitfield.h> #include <linux/delay.h> +#include <dt-bindings/phy/nuvoton,npcm-usbphy.h> /* GCR Register Offsets */ #define GCR_INTCR3 0x9C @@ -31,14 +32,6 @@ #define USBPHY3SW_HOST2 FIELD_PREP(USBPHY3SW, 1) #define USBPHY3SW_DEV8_PHY3 FIELD_PREP(USBPHY3SW, 3) -enum controller_id { - UDC0_7, - UDC8, - UDC9, - USBH1, - USBH2, -}; - enum phy_id { PHY1 = 1, PHY2, @@ -46,13 +39,13 @@ enum phy_id { }; /* Phy Switch Settings */ -#define USBDPHY1 ((PHY1 << 8) | UDC0_7) /* Connect UDC0~7 to PHY1 */ -#define USBD8PHY1 ((PHY1 << 8) | UDC8) /* Connect UDC8 to PHY1 */ -#define USBD9PHY1 ((PHY1 << 8) | UDC9) /* Connect UDC9 to PHY1 */ -#define USBD9PHY2 ((PHY2 << 8) | UDC9) /* Connect UDC9 to PHY2 */ -#define USBH1PHY2 ((PHY2 << 8) | USBH1) /* Connect USBH1 to PHY2 */ -#define USBD8PHY3 ((PHY3 << 8) | UDC8) /* Connect UDC8 to PHY3 */ -#define USBH2PHY3 ((PHY3 << 8) | USBH2) /* Connect USBH2 to PHY3 */ +#define USBDPHY1 ((PHY1 << 8) | NPCM_UDC0_7) /* Connect UDC0~7 to PHY1 */ +#define USBD8PHY1 ((PHY1 << 8) | NPCM_UDC8) /* Connect UDC8 to PHY1 */ +#define USBD9PHY1 ((PHY1 << 8) | NPCM_UDC9) /* Connect UDC9 to PHY1 */ +#define USBD9PHY2 ((PHY2 << 8) | NPCM_UDC9) /* Connect UDC9 to PHY2 */ +#define USBH1PHY2 ((PHY2 << 8) | NPCM_USBH1) /* Connect USBH1 to PHY2 */ +#define USBD8PHY3 ((PHY3 << 8) | NPCM_UDC8) /* Connect UDC8 to PHY3 */ +#define USBH2PHY3 ((PHY3 << 8) | NPCM_USBH2) /* Connect USBH2 to PHY3 */ struct npcm_usbphy { struct regmap *syscon; @@ -152,12 +145,12 @@ static int npcm_usb_phy_exit(struct phy *phy) return 0; } -static int npcm_usb_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args) +static int npcm_usb_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args) { struct npcm_usbphy *priv = dev_get_priv(phy->dev); u16 phy_switch; - if (args->args_count < 1 || args->args[0] > USBH2) + if (args->args_count < 1 || args->args[0] > NPCM_MAX_USB_CTRL_ID) return -EINVAL; phy_switch = (priv->id << 8) | args->args[0]; diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 5bcc76613d1..9deec47ae46 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -20,7 +20,7 @@ #include <reset.h> #include <syscon.h> #include <asm/arch-rockchip/clock.h> - +#include <dt-bindings/phy/phy.h> #include <linux/usb/phy-rockchip-usbdp.h> #define BIT_WRITEABLE_SHIFT 16 @@ -73,6 +73,8 @@ struct udphy_grf_cfg { struct rockchip_udphy; struct rockchip_udphy_cfg { + unsigned int num_phys; + unsigned int phy_ids[2]; /* resets to be requested */ const char * const *rst_list; int num_rsts; @@ -582,10 +584,21 @@ static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode) return 0; } +static int rockchip_u3phy_of_xlate(struct phy *phy, + struct ofnode_phandle_args *args) +{ + if (args->args_count == 0) + return -EINVAL; + + if (args->args[0] != PHY_TYPE_USB3) + return -EINVAL; + + return 0; +} + static int rockchip_u3phy_init(struct phy *phy) { - struct udevice *parent = phy->dev->parent; - struct rockchip_udphy *udphy = dev_get_priv(parent); + struct rockchip_udphy *udphy = dev_get_priv(phy->dev); /* DP only or high-speed, disable U3 port */ if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { @@ -598,8 +611,7 @@ static int rockchip_u3phy_init(struct phy *phy) static int rockchip_u3phy_exit(struct phy *phy) { - struct udevice *parent = phy->dev->parent; - struct rockchip_udphy *udphy = dev_get_priv(parent); + struct rockchip_udphy *udphy = dev_get_priv(phy->dev); /* DP only or high-speed */ if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) @@ -609,47 +621,32 @@ static int rockchip_u3phy_exit(struct phy *phy) } static const struct phy_ops rockchip_u3phy_ops = { + .of_xlate = rockchip_u3phy_of_xlate, .init = rockchip_u3phy_init, .exit = rockchip_u3phy_exit, }; -int rockchip_u3phy_uboot_init(void) -{ - struct udevice *udev; - struct rockchip_udphy *udphy; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_PHY, - DM_DRIVER_GET(rockchip_udphy_u3_port), - &udev); - if (ret) { - pr_err("%s: get u3-port failed: %d\n", __func__, ret); - return ret; - } - - /* DP only or high-speed, disable U3 port */ - udphy = dev_get_priv(udev->parent); - if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { - udphy_u3_port_disable(udphy, true); - return 0; - } - - return udphy_power_on(udphy, UDPHY_MODE_USB); -} - static int rockchip_udphy_probe(struct udevice *dev) { - const struct device_node *np = ofnode_to_np(dev_ofnode(dev)); struct rockchip_udphy *udphy = dev_get_priv(dev); const struct rockchip_udphy_cfg *phy_cfgs; + unsigned int reg; int id, ret; udphy->dev = dev; - id = of_alias_get_id(np, "usbdp"); - if (id < 0) - id = 0; - udphy->id = id; + ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, ®); + if (ret) { + dev_err(dev, "failed to read reg[0] property\n"); + return ret; + } + if (reg == 0 && dev_read_addr_cells(dev) == 2) { + ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 1, ®); + if (ret) { + dev_err(dev, "failed to read reg[1] property\n"); + return ret; + } + } phy_cfgs = (const struct rockchip_udphy_cfg *)dev_get_driver_data(dev); if (!phy_cfgs) { @@ -658,6 +655,20 @@ static int rockchip_udphy_probe(struct udevice *dev) } udphy->cfgs = phy_cfgs; + /* find the phy-id from the io address */ + udphy->id = -ENODEV; + for (id = 0; id < udphy->cfgs->num_phys; id++) { + if (reg == udphy->cfgs->phy_ids[id]) { + udphy->id = id; + break; + } + } + + if (udphy->id < 0) { + dev_err(dev, "no matching device found\n"); + return -ENODEV; + } + ret = regmap_init_mem(dev_ofnode(dev), &udphy->pma_regmap); if (ret) return ret; @@ -670,40 +681,6 @@ static int rockchip_udphy_probe(struct udevice *dev) return 0; } -static int rockchip_udphy_bind(struct udevice *parent) -{ - struct udevice *child; - ofnode subnode; - const char *node_name; - int ret; - - dev_for_each_subnode(subnode, parent) { - if (!ofnode_valid(subnode)) { - printf("%s: no subnode for %s", __func__, parent->name); - return -ENXIO; - } - - node_name = ofnode_get_name(subnode); - debug("%s: subnode %s\n", __func__, node_name); - - /* if there is no match, continue */ - if (strcasecmp(node_name, "usb3-port")) - continue; - - /* node name is usb3-port */ - ret = device_bind_driver_to_node(parent, - "rockchip_udphy_u3_port", - node_name, subnode, &child); - if (ret) { - printf("%s: '%s' cannot bind its driver\n", - __func__, node_name); - return ret; - } - } - - return 0; -} - static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy) { /* configure phy reference clock */ @@ -837,6 +814,11 @@ static const char * const rk3588_udphy_rst_l[] = { }; static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = { + .num_phys = 2, + .phy_ids = { + 0xfed80000, + 0xfed90000, + }, .num_rsts = ARRAY_SIZE(rk3588_udphy_rst_l), .rst_list = rk3588_udphy_rst_l, .grfcfg = { @@ -863,17 +845,11 @@ static const struct udevice_id rockchip_udphy_dt_match[] = { { /* sentinel */ } }; -U_BOOT_DRIVER(rockchip_udphy_u3_port) = { - .name = "rockchip_udphy_u3_port", - .id = UCLASS_PHY, - .ops = &rockchip_u3phy_ops, -}; - U_BOOT_DRIVER(rockchip_udphy) = { .name = "rockchip_udphy", .id = UCLASS_PHY, .of_match = rockchip_udphy_dt_match, .probe = rockchip_udphy_probe, - .bind = rockchip_udphy_bind, + .ops = &rockchip_u3phy_ops, .priv_auto = sizeof(struct rockchip_udphy), }; diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index d9bda7494e2..d9c76898a96 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -209,7 +209,7 @@ pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset, pfc_base = args.args[1]; pfc_pins = args.args[2]; - if (offset >= gpio_offset && offset <= gpio_offset + pfc_pins) + if (offset >= gpio_offset && offset < gpio_offset + pfc_pins) break; } diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 7aa0c6b2bee..d11175dc5b6 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -2325,6 +2325,9 @@ static void cdns3_gadget_config(struct cdns3_device *priv_dev) writel(USB_IEN_INIT, ®s->usb_ien); writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); + /* Set the Fast access bit */ + writel(PUSB_PWR_FST_REG_ACCESS, &priv_dev->regs->usb_pwr); + cdns3_configure_dmult(priv_dev, NULL); cdns3_gadget_pullup(&priv_dev->gadget, 1); @@ -2383,6 +2386,7 @@ static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) /* disable interrupt for device */ writel(0, &priv_dev->regs->usb_ien); + writel(0, &priv_dev->regs->usb_pwr); writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); return ret; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4162a682298..7374ce950da 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -405,6 +405,8 @@ #define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0) #define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0) +#define DWC3_DEPCMD_CMD(x) ((x) & 0xf) + /* The EP number goes 0..31 so ep0 is always out and ep1 is always in */ #define DWC3_DALEPENA_EP(n) (1 << n) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4de007cb0c3..fab32575647 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -300,8 +300,38 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { u32 timeout = 500; + u32 saved_config = 0; u32 reg; + int ret = -EINVAL; + + /* + * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or + * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an + * endpoint command. + * + * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY + * settings. Restore them after the command is completed. + * + * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2 + */ + if (dwc->gadget.speed <= USB_SPEED_HIGH || + DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { + saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + } + + if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) { + saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM; + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + } + + if (saved_config) + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); @@ -312,7 +342,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, if (!(reg & DWC3_DEPCMD_CMDACT)) { dev_vdbg(dwc->dev, "Command Complete --> %d\n", DWC3_DEPCMD_STATUS(reg)); - return 0; + ret = 0; + break; } /* @@ -320,11 +351,21 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, * interrupt context. */ timeout--; - if (!timeout) - return -ETIMEDOUT; + if (!timeout) { + ret = -ETIMEDOUT; + break; + } udelay(1); } while (1); + + if (saved_config) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= saved_config; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + + return ret; } static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, |