.. | .. |
---|
524 | 524 | greset |= GRSTCTL_CSFTRST; |
---|
525 | 525 | dwc2_writel(hsotg, greset, GRSTCTL); |
---|
526 | 526 | |
---|
527 | | - if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) { |
---|
528 | | - dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n", |
---|
529 | | - __func__); |
---|
530 | | - return -EBUSY; |
---|
| 527 | + if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) < |
---|
| 528 | + (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) { |
---|
| 529 | + if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, |
---|
| 530 | + GRSTCTL_CSFTRST, 10000)) { |
---|
| 531 | + dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n", |
---|
| 532 | + __func__); |
---|
| 533 | + return -EBUSY; |
---|
| 534 | + } |
---|
| 535 | + } else { |
---|
| 536 | + if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, |
---|
| 537 | + GRSTCTL_CSFTRST_DONE, 10000)) { |
---|
| 538 | + dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n", |
---|
| 539 | + __func__); |
---|
| 540 | + return -EBUSY; |
---|
| 541 | + } |
---|
| 542 | + greset = dwc2_readl(hsotg, GRSTCTL); |
---|
| 543 | + greset &= ~GRSTCTL_CSFTRST; |
---|
| 544 | + greset |= GRSTCTL_CSFTRST_DONE; |
---|
| 545 | + dwc2_writel(hsotg, greset, GRSTCTL); |
---|
531 | 546 | } |
---|
532 | 547 | |
---|
533 | 548 | /* Wait for AHB master IDLE state */ |
---|
.. | .. |
---|
641 | 656 | */ |
---|
642 | 657 | void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) |
---|
643 | 658 | { |
---|
| 659 | + u32 count = 0; |
---|
| 660 | + |
---|
644 | 661 | switch (hsotg->dr_mode) { |
---|
645 | 662 | case USB_DR_MODE_HOST: |
---|
646 | 663 | /* |
---|
647 | 664 | * NOTE: This is required for some rockchip soc based |
---|
648 | 665 | * platforms on their host-only dwc2. |
---|
649 | 666 | */ |
---|
650 | | - if (!dwc2_hw_is_otg(hsotg)) |
---|
651 | | - msleep(50); |
---|
| 667 | + if (!dwc2_hw_is_otg(hsotg)) { |
---|
| 668 | + while (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_CONID_B) { |
---|
| 669 | + msleep(20); |
---|
| 670 | + if (++count > 10) |
---|
| 671 | + break; |
---|
| 672 | + } |
---|
| 673 | + if (count > 10) |
---|
| 674 | + dev_err(hsotg->dev, |
---|
| 675 | + "Waiting for Host Mode timed out"); |
---|
| 676 | + } |
---|
652 | 677 | |
---|
653 | 678 | break; |
---|
654 | 679 | case USB_DR_MODE_PERIPHERAL: |
---|
.. | .. |
---|
1020 | 1045 | return -ETIMEDOUT; |
---|
1021 | 1046 | } |
---|
1022 | 1047 | |
---|
| 1048 | +/* |
---|
| 1049 | + * Initializes the FSLSPClkSel field of the HCFG register depending on the |
---|
| 1050 | + * PHY type |
---|
| 1051 | + */ |
---|
| 1052 | +void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) |
---|
| 1053 | +{ |
---|
| 1054 | + u32 hcfg, val; |
---|
| 1055 | + |
---|
| 1056 | + if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && |
---|
| 1057 | + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && |
---|
| 1058 | + hsotg->params.ulpi_fs_ls) || |
---|
| 1059 | + hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { |
---|
| 1060 | + /* Full speed PHY */ |
---|
| 1061 | + val = HCFG_FSLSPCLKSEL_48_MHZ; |
---|
| 1062 | + } else { |
---|
| 1063 | + /* High speed PHY running at full speed or high speed */ |
---|
| 1064 | + val = HCFG_FSLSPCLKSEL_30_60_MHZ; |
---|
| 1065 | + } |
---|
| 1066 | + |
---|
| 1067 | + dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); |
---|
| 1068 | + hcfg = dwc2_readl(hsotg, HCFG); |
---|
| 1069 | + hcfg &= ~HCFG_FSLSPCLKSEL_MASK; |
---|
| 1070 | + hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; |
---|
| 1071 | + dwc2_writel(hsotg, hcfg, HCFG); |
---|
| 1072 | +} |
---|
| 1073 | + |
---|
| 1074 | +static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) |
---|
| 1075 | +{ |
---|
| 1076 | + u32 usbcfg, ggpio, i2cctl; |
---|
| 1077 | + int retval = 0; |
---|
| 1078 | + |
---|
| 1079 | + /* |
---|
| 1080 | + * core_init() is now called on every switch so only call the |
---|
| 1081 | + * following for the first time through |
---|
| 1082 | + */ |
---|
| 1083 | + if (select_phy) { |
---|
| 1084 | + dev_dbg(hsotg->dev, "FS PHY selected\n"); |
---|
| 1085 | + |
---|
| 1086 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1087 | + if (!(usbcfg & GUSBCFG_PHYSEL)) { |
---|
| 1088 | + usbcfg |= GUSBCFG_PHYSEL; |
---|
| 1089 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1090 | + |
---|
| 1091 | + /* Reset after a PHY select */ |
---|
| 1092 | + retval = dwc2_core_reset(hsotg, false); |
---|
| 1093 | + |
---|
| 1094 | + if (retval) { |
---|
| 1095 | + dev_err(hsotg->dev, |
---|
| 1096 | + "%s: Reset failed, aborting", __func__); |
---|
| 1097 | + return retval; |
---|
| 1098 | + } |
---|
| 1099 | + } |
---|
| 1100 | + |
---|
| 1101 | + if (hsotg->params.activate_stm_fs_transceiver) { |
---|
| 1102 | + ggpio = dwc2_readl(hsotg, GGPIO); |
---|
| 1103 | + if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { |
---|
| 1104 | + dev_dbg(hsotg->dev, "Activating transceiver\n"); |
---|
| 1105 | + /* |
---|
| 1106 | + * STM32F4x9 uses the GGPIO register as general |
---|
| 1107 | + * core configuration register. |
---|
| 1108 | + */ |
---|
| 1109 | + ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; |
---|
| 1110 | + dwc2_writel(hsotg, ggpio, GGPIO); |
---|
| 1111 | + } |
---|
| 1112 | + } |
---|
| 1113 | + } |
---|
| 1114 | + |
---|
| 1115 | + /* |
---|
| 1116 | + * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also |
---|
| 1117 | + * do this on HNP Dev/Host mode switches (done in dev_init and |
---|
| 1118 | + * host_init). |
---|
| 1119 | + */ |
---|
| 1120 | + if (dwc2_is_host_mode(hsotg)) |
---|
| 1121 | + dwc2_init_fs_ls_pclk_sel(hsotg); |
---|
| 1122 | + |
---|
| 1123 | + if (hsotg->params.i2c_enable) { |
---|
| 1124 | + dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); |
---|
| 1125 | + |
---|
| 1126 | + /* Program GUSBCFG.OtgUtmiFsSel to I2C */ |
---|
| 1127 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1128 | + usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; |
---|
| 1129 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1130 | + |
---|
| 1131 | + /* Program GI2CCTL.I2CEn */ |
---|
| 1132 | + i2cctl = dwc2_readl(hsotg, GI2CCTL); |
---|
| 1133 | + i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; |
---|
| 1134 | + i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; |
---|
| 1135 | + i2cctl &= ~GI2CCTL_I2CEN; |
---|
| 1136 | + dwc2_writel(hsotg, i2cctl, GI2CCTL); |
---|
| 1137 | + i2cctl |= GI2CCTL_I2CEN; |
---|
| 1138 | + dwc2_writel(hsotg, i2cctl, GI2CCTL); |
---|
| 1139 | + } |
---|
| 1140 | + |
---|
| 1141 | + return retval; |
---|
| 1142 | +} |
---|
| 1143 | + |
---|
| 1144 | +static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) |
---|
| 1145 | +{ |
---|
| 1146 | + u32 usbcfg, usbcfg_old; |
---|
| 1147 | + int retval = 0; |
---|
| 1148 | + |
---|
| 1149 | + if (!select_phy) |
---|
| 1150 | + return 0; |
---|
| 1151 | + |
---|
| 1152 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1153 | + usbcfg_old = usbcfg; |
---|
| 1154 | + |
---|
| 1155 | + /* |
---|
| 1156 | + * HS PHY parameters. These parameters are preserved during soft reset |
---|
| 1157 | + * so only program the first time. Do a soft reset immediately after |
---|
| 1158 | + * setting phyif. |
---|
| 1159 | + */ |
---|
| 1160 | + switch (hsotg->params.phy_type) { |
---|
| 1161 | + case DWC2_PHY_TYPE_PARAM_ULPI: |
---|
| 1162 | + /* ULPI interface */ |
---|
| 1163 | + dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); |
---|
| 1164 | + usbcfg |= GUSBCFG_ULPI_UTMI_SEL; |
---|
| 1165 | + usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); |
---|
| 1166 | + if (hsotg->params.phy_ulpi_ddr) |
---|
| 1167 | + usbcfg |= GUSBCFG_DDRSEL; |
---|
| 1168 | + |
---|
| 1169 | + /* Set external VBUS indicator as needed. */ |
---|
| 1170 | + if (hsotg->params.oc_disable) |
---|
| 1171 | + usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | |
---|
| 1172 | + GUSBCFG_INDICATORPASSTHROUGH); |
---|
| 1173 | + break; |
---|
| 1174 | + case DWC2_PHY_TYPE_PARAM_UTMI: |
---|
| 1175 | + /* UTMI+ interface */ |
---|
| 1176 | + dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); |
---|
| 1177 | + usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); |
---|
| 1178 | + if (hsotg->params.phy_utmi_width == 16) |
---|
| 1179 | + usbcfg |= GUSBCFG_PHYIF16; |
---|
| 1180 | + break; |
---|
| 1181 | + default: |
---|
| 1182 | + dev_err(hsotg->dev, "FS PHY selected at HS!\n"); |
---|
| 1183 | + break; |
---|
| 1184 | + } |
---|
| 1185 | + |
---|
| 1186 | + if (usbcfg != usbcfg_old) { |
---|
| 1187 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1188 | + |
---|
| 1189 | + /* Reset after setting the PHY parameters */ |
---|
| 1190 | + retval = dwc2_core_reset(hsotg, false); |
---|
| 1191 | + if (retval) { |
---|
| 1192 | + dev_err(hsotg->dev, |
---|
| 1193 | + "%s: Reset failed, aborting", __func__); |
---|
| 1194 | + return retval; |
---|
| 1195 | + } |
---|
| 1196 | + } |
---|
| 1197 | + |
---|
| 1198 | + return retval; |
---|
| 1199 | +} |
---|
| 1200 | + |
---|
| 1201 | +static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg) |
---|
| 1202 | +{ |
---|
| 1203 | + u32 usbcfg; |
---|
| 1204 | + |
---|
| 1205 | + if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI) |
---|
| 1206 | + return; |
---|
| 1207 | + |
---|
| 1208 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1209 | + |
---|
| 1210 | + usbcfg &= ~GUSBCFG_USBTRDTIM_MASK; |
---|
| 1211 | + if (hsotg->params.phy_utmi_width == 16) |
---|
| 1212 | + usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT; |
---|
| 1213 | + else |
---|
| 1214 | + usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT; |
---|
| 1215 | + |
---|
| 1216 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1217 | +} |
---|
| 1218 | + |
---|
| 1219 | +int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) |
---|
| 1220 | +{ |
---|
| 1221 | + u32 usbcfg; |
---|
| 1222 | + int retval = 0; |
---|
| 1223 | + |
---|
| 1224 | + if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || |
---|
| 1225 | + hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && |
---|
| 1226 | + hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { |
---|
| 1227 | + /* If FS/LS mode with FS/LS PHY */ |
---|
| 1228 | + retval = dwc2_fs_phy_init(hsotg, select_phy); |
---|
| 1229 | + if (retval) |
---|
| 1230 | + return retval; |
---|
| 1231 | + } else { |
---|
| 1232 | + /* High speed PHY */ |
---|
| 1233 | + retval = dwc2_hs_phy_init(hsotg, select_phy); |
---|
| 1234 | + if (retval) |
---|
| 1235 | + return retval; |
---|
| 1236 | + |
---|
| 1237 | + if (dwc2_is_device_mode(hsotg)) |
---|
| 1238 | + dwc2_set_turnaround_time(hsotg); |
---|
| 1239 | + } |
---|
| 1240 | + |
---|
| 1241 | + if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && |
---|
| 1242 | + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && |
---|
| 1243 | + hsotg->params.ulpi_fs_ls) { |
---|
| 1244 | + dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); |
---|
| 1245 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1246 | + usbcfg |= GUSBCFG_ULPI_FS_LS; |
---|
| 1247 | + usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; |
---|
| 1248 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1249 | + } else { |
---|
| 1250 | + usbcfg = dwc2_readl(hsotg, GUSBCFG); |
---|
| 1251 | + usbcfg &= ~GUSBCFG_ULPI_FS_LS; |
---|
| 1252 | + usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; |
---|
| 1253 | + dwc2_writel(hsotg, usbcfg, GUSBCFG); |
---|
| 1254 | + } |
---|
| 1255 | + |
---|
| 1256 | + return retval; |
---|
| 1257 | +} |
---|
| 1258 | + |
---|
1023 | 1259 | MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); |
---|
1024 | 1260 | MODULE_AUTHOR("Synopsys, Inc."); |
---|
1025 | 1261 | MODULE_LICENSE("Dual BSD/GPL"); |
---|