diff options
-rw-r--r-- | drivers/usb/dwc2/core.c | 190 | ||||
-rw-r--r-- | drivers/usb/dwc2/core.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.c | 190 |
3 files changed, 192 insertions, 190 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 55d5ae2a7ec7..01ac4a064feb 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -1020,6 +1020,196 @@ int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, return -ETIMEDOUT; } +/* + * Initializes the FSLSPClkSel field of the HCFG register depending on the + * PHY type + */ +void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) +{ + u32 hcfg, val; + + if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && + hsotg->params.ulpi_fs_ls) || + hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { + /* Full speed PHY */ + val = HCFG_FSLSPCLKSEL_48_MHZ; + } else { + /* High speed PHY running at full speed or high speed */ + val = HCFG_FSLSPCLKSEL_30_60_MHZ; + } + + dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); + hcfg = dwc2_readl(hsotg, HCFG); + hcfg &= ~HCFG_FSLSPCLKSEL_MASK; + hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; + dwc2_writel(hsotg, hcfg, HCFG); +} + +static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ + u32 usbcfg, ggpio, i2cctl; + int retval = 0; + + /* + * core_init() is now called on every switch so only call the + * following for the first time through + */ + if (select_phy) { + dev_dbg(hsotg->dev, "FS PHY selected\n"); + + usbcfg = dwc2_readl(hsotg, GUSBCFG); + if (!(usbcfg & GUSBCFG_PHYSEL)) { + usbcfg |= GUSBCFG_PHYSEL; + dwc2_writel(hsotg, usbcfg, GUSBCFG); + + /* Reset after a PHY select */ + retval = dwc2_core_reset(hsotg, false); + + if (retval) { + dev_err(hsotg->dev, + "%s: Reset failed, aborting", __func__); + return retval; + } + } + + if (hsotg->params.activate_stm_fs_transceiver) { + ggpio = dwc2_readl(hsotg, GGPIO); + if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { + dev_dbg(hsotg->dev, "Activating transceiver\n"); + /* + * STM32F4x9 uses the GGPIO register as general + * core configuration register. + */ + ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; + dwc2_writel(hsotg, ggpio, GGPIO); + } + } + } + + /* + * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also + * do this on HNP Dev/Host mode switches (done in dev_init and + * host_init). + */ + if (dwc2_is_host_mode(hsotg)) + dwc2_init_fs_ls_pclk_sel(hsotg); + + if (hsotg->params.i2c_enable) { + dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); + + /* Program GUSBCFG.OtgUtmiFsSel to I2C */ + usbcfg = dwc2_readl(hsotg, GUSBCFG); + usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; + dwc2_writel(hsotg, usbcfg, GUSBCFG); + + /* Program GI2CCTL.I2CEn */ + i2cctl = dwc2_readl(hsotg, GI2CCTL); + i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; + i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; + i2cctl &= ~GI2CCTL_I2CEN; + dwc2_writel(hsotg, i2cctl, GI2CCTL); + i2cctl |= GI2CCTL_I2CEN; + dwc2_writel(hsotg, i2cctl, GI2CCTL); + } + + return retval; +} + +static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ + u32 usbcfg, usbcfg_old; + int retval = 0; + + if (!select_phy) + return 0; + + usbcfg = dwc2_readl(hsotg, GUSBCFG); + usbcfg_old = usbcfg; + + /* + * HS PHY parameters. These parameters are preserved during soft reset + * so only program the first time. Do a soft reset immediately after + * setting phyif. + */ + switch (hsotg->params.phy_type) { + case DWC2_PHY_TYPE_PARAM_ULPI: + /* ULPI interface */ + dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); + usbcfg |= GUSBCFG_ULPI_UTMI_SEL; + usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); + if (hsotg->params.phy_ulpi_ddr) + usbcfg |= GUSBCFG_DDRSEL; + + /* Set external VBUS indicator as needed. */ + if (hsotg->params.oc_disable) + usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | + GUSBCFG_INDICATORPASSTHROUGH); + break; + case DWC2_PHY_TYPE_PARAM_UTMI: + /* UTMI+ interface */ + dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); + usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); + if (hsotg->params.phy_utmi_width == 16) + usbcfg |= GUSBCFG_PHYIF16; + break; + default: + dev_err(hsotg->dev, "FS PHY selected at HS!\n"); + break; + } + + if (usbcfg != usbcfg_old) { + dwc2_writel(hsotg, usbcfg, GUSBCFG); + + /* Reset after setting the PHY parameters */ + retval = dwc2_core_reset(hsotg, false); + if (retval) { + dev_err(hsotg->dev, + "%s: Reset failed, aborting", __func__); + return retval; + } + } + + return retval; +} + +int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ + u32 usbcfg; + int retval = 0; + + if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || + hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && + hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { + /* If FS/LS mode with FS/LS PHY */ + retval = dwc2_fs_phy_init(hsotg, select_phy); + if (retval) + return retval; + } else { + /* High speed PHY */ + retval = dwc2_hs_phy_init(hsotg, select_phy); + if (retval) + return retval; + } + + if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && + hsotg->params.ulpi_fs_ls) { + dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); + usbcfg = dwc2_readl(hsotg, GUSBCFG); + usbcfg |= GUSBCFG_ULPI_FS_LS; + usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; + dwc2_writel(hsotg, usbcfg, GUSBCFG); + } else { + usbcfg = dwc2_readl(hsotg, GUSBCFG); + usbcfg &= ~GUSBCFG_ULPI_FS_LS; + usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; + dwc2_writel(hsotg, usbcfg, GUSBCFG); + } + + return retval; +} + MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); MODULE_AUTHOR("Synopsys, Inc."); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 8e3edf10d76d..9f3fc8e18277 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1286,6 +1286,8 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore); int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host); int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset, int is_host); +void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg); +int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy); void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host); void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 978232a9e4a8..7ac7b524243d 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -97,196 +97,6 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg) dwc2_writel(hsotg, intmsk, GINTMSK); } -/* - * Initializes the FSLSPClkSel field of the HCFG register depending on the - * PHY type - */ -static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) -{ - u32 hcfg, val; - - if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && - hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls) || - hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { - /* Full speed PHY */ - val = HCFG_FSLSPCLKSEL_48_MHZ; - } else { - /* High speed PHY running at full speed or high speed */ - val = HCFG_FSLSPCLKSEL_30_60_MHZ; - } - - dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); - hcfg = dwc2_readl(hsotg, HCFG); - hcfg &= ~HCFG_FSLSPCLKSEL_MASK; - hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; - dwc2_writel(hsotg, hcfg, HCFG); -} - -static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) -{ - u32 usbcfg, ggpio, i2cctl; - int retval = 0; - - /* - * core_init() is now called on every switch so only call the - * following for the first time through - */ - if (select_phy) { - dev_dbg(hsotg->dev, "FS PHY selected\n"); - - usbcfg = dwc2_readl(hsotg, GUSBCFG); - if (!(usbcfg & GUSBCFG_PHYSEL)) { - usbcfg |= GUSBCFG_PHYSEL; - dwc2_writel(hsotg, usbcfg, GUSBCFG); - - /* Reset after a PHY select */ - retval = dwc2_core_reset(hsotg, false); - - if (retval) { - dev_err(hsotg->dev, - "%s: Reset failed, aborting", __func__); - return retval; - } - } - - if (hsotg->params.activate_stm_fs_transceiver) { - ggpio = dwc2_readl(hsotg, GGPIO); - if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { - dev_dbg(hsotg->dev, "Activating transceiver\n"); - /* - * STM32F4x9 uses the GGPIO register as general - * core configuration register. - */ - ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; - dwc2_writel(hsotg, ggpio, GGPIO); - } - } - } - - /* - * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also - * do this on HNP Dev/Host mode switches (done in dev_init and - * host_init). - */ - if (dwc2_is_host_mode(hsotg)) - dwc2_init_fs_ls_pclk_sel(hsotg); - - if (hsotg->params.i2c_enable) { - dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); - - /* Program GUSBCFG.OtgUtmiFsSel to I2C */ - usbcfg = dwc2_readl(hsotg, GUSBCFG); - usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; - dwc2_writel(hsotg, usbcfg, GUSBCFG); - - /* Program GI2CCTL.I2CEn */ - i2cctl = dwc2_readl(hsotg, GI2CCTL); - i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; - i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; - i2cctl &= ~GI2CCTL_I2CEN; - dwc2_writel(hsotg, i2cctl, GI2CCTL); - i2cctl |= GI2CCTL_I2CEN; - dwc2_writel(hsotg, i2cctl, GI2CCTL); - } - - return retval; -} - -static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) -{ - u32 usbcfg, usbcfg_old; - int retval = 0; - - if (!select_phy) - return 0; - - usbcfg = dwc2_readl(hsotg, GUSBCFG); - usbcfg_old = usbcfg; - - /* - * HS PHY parameters. These parameters are preserved during soft reset - * so only program the first time. Do a soft reset immediately after - * setting phyif. - */ - switch (hsotg->params.phy_type) { - case DWC2_PHY_TYPE_PARAM_ULPI: - /* ULPI interface */ - dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); - usbcfg |= GUSBCFG_ULPI_UTMI_SEL; - usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); - if (hsotg->params.phy_ulpi_ddr) - usbcfg |= GUSBCFG_DDRSEL; - - /* Set external VBUS indicator as needed. */ - if (hsotg->params.oc_disable) - usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | - GUSBCFG_INDICATORPASSTHROUGH); - break; - case DWC2_PHY_TYPE_PARAM_UTMI: - /* UTMI+ interface */ - dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); - usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); - if (hsotg->params.phy_utmi_width == 16) - usbcfg |= GUSBCFG_PHYIF16; - break; - default: - dev_err(hsotg->dev, "FS PHY selected at HS!\n"); - break; - } - - if (usbcfg != usbcfg_old) { - dwc2_writel(hsotg, usbcfg, GUSBCFG); - - /* Reset after setting the PHY parameters */ - retval = dwc2_core_reset(hsotg, false); - if (retval) { - dev_err(hsotg->dev, - "%s: Reset failed, aborting", __func__); - return retval; - } - } - - return retval; -} - -static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) -{ - u32 usbcfg; - int retval = 0; - - if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || - hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && - hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { - /* If FS/LS mode with FS/LS PHY */ - retval = dwc2_fs_phy_init(hsotg, select_phy); - if (retval) - return retval; - } else { - /* High speed PHY */ - retval = dwc2_hs_phy_init(hsotg, select_phy); - if (retval) - return retval; - } - - if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && - hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls) { - dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); - usbcfg = dwc2_readl(hsotg, GUSBCFG); - usbcfg |= GUSBCFG_ULPI_FS_LS; - usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; - dwc2_writel(hsotg, usbcfg, GUSBCFG); - } else { - usbcfg = dwc2_readl(hsotg, GUSBCFG); - usbcfg &= ~GUSBCFG_ULPI_FS_LS; - usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; - dwc2_writel(hsotg, usbcfg, GUSBCFG); - } - - return retval; -} - static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) { u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); |