Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: stm32: rework PLL Lock detection

USBPHYC has a register per phy to control and monitor the debug interface
of the HS PHY through a digital debug access.
With this register, it is possible to know if PLL Lock input to phy is
high. That means the PLL is ready for HS operation.
Instead of using an hard-coded delay after PLL enable and PLL disable, use
this bit to ensure good operating of the HS PHY.
Also use an atomic counter (n_pll_cons) to count the actual number of PLL
consumers and get rid of stm32_usbphyc_has_one_phy_active.
The boolean active in the usbphyc_phy structure is kept, because we need to
know in remove if a phy_exit is required to properly disable the PLL.

Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Link: https://lore.kernel.org/r/20210105090525.23164-7-amelie.delaunay@foss.st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Amelie Delaunay and committed by
Vinod Koul
5b1af712 64962724

+54 -34
+54 -34
drivers/phy/st/phy-stm32-usbphyc.c
··· 17 17 18 18 #define STM32_USBPHYC_PLL 0x0 19 19 #define STM32_USBPHYC_MISC 0x8 20 + #define STM32_USBPHYC_MONITOR(X) (0x108 + ((X) * 0x100)) 20 21 #define STM32_USBPHYC_VERSION 0x3F4 21 22 22 23 /* STM32_USBPHYC_PLL bit fields */ ··· 33 32 /* STM32_USBPHYC_MISC bit fields */ 34 33 #define SWITHOST BIT(0) 35 34 35 + /* STM32_USBPHYC_MONITOR bit fields */ 36 + #define STM32_USBPHYC_MON_OUT GENMASK(3, 0) 37 + #define STM32_USBPHYC_MON_SEL GENMASK(8, 4) 38 + #define STM32_USBPHYC_MON_SEL_LOCKP 0x1F 39 + #define STM32_USBPHYC_MON_OUT_LOCKP BIT(3) 40 + 36 41 /* STM32_USBPHYC_VERSION bit fields */ 37 42 #define MINREV GENMASK(3, 0) 38 43 #define MAJREV GENMASK(7, 4) 39 44 40 - #define PLL_LOCK_TIME_US 100 41 - #define PLL_PWR_DOWN_TIME_US 5 42 45 #define PLL_FVCO_MHZ 2880 43 46 #define PLL_INFF_MIN_RATE_HZ 19200000 44 47 #define PLL_INFF_MAX_RATE_HZ 38400000 ··· 69 64 int nphys; 70 65 struct regulator *vdda1v1; 71 66 struct regulator *vdda1v8; 67 + atomic_t n_pll_cons; 72 68 int switch_setup; 73 69 }; 74 70 ··· 177 171 return 0; 178 172 } 179 173 180 - static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) 174 + static int __stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) 181 175 { 182 - int i; 176 + void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; 177 + u32 pllen; 183 178 184 - for (i = 0; i < usbphyc->nphys; i++) 185 - if (usbphyc->phys[i]->active) 186 - return true; 179 + stm32_usbphyc_clr_bits(pll_reg, PLLEN); 187 180 188 - return false; 181 + /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ 182 + if (readl_relaxed_poll_timeout(pll_reg, pllen, !(pllen & PLLEN), 5, 50)) 183 + dev_err(usbphyc->dev, "PLL not reset\n"); 184 + 185 + return stm32_usbphyc_regulators_disable(usbphyc); 189 186 } 190 187 191 188 static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) 192 189 { 193 - void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; 194 - 195 - /* Check if other phy port active */ 196 - if (stm32_usbphyc_has_one_phy_active(usbphyc)) 190 + /* Check if a phy port is still active or clk48 in use */ 191 + if (atomic_dec_return(&usbphyc->n_pll_cons) > 0) 197 192 return 0; 198 193 199 - stm32_usbphyc_clr_bits(pll_reg, PLLEN); 200 - /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ 201 - udelay(PLL_PWR_DOWN_TIME_US); 202 - 203 - if (readl_relaxed(pll_reg) & PLLEN) { 204 - dev_err(usbphyc->dev, "PLL not reset\n"); 205 - return -EIO; 206 - } 207 - 208 - return stm32_usbphyc_regulators_disable(usbphyc); 194 + return __stm32_usbphyc_pll_disable(usbphyc); 209 195 } 210 196 211 197 static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) ··· 206 208 bool pllen = readl_relaxed(pll_reg) & PLLEN; 207 209 int ret; 208 210 209 - /* Check if one phy port has already configured the pll */ 210 - if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc)) 211 + /* 212 + * Check if a phy port or clk48 prepare has configured the pll 213 + * and ensure the PLL is enabled 214 + */ 215 + if (atomic_inc_return(&usbphyc->n_pll_cons) > 1 && pllen) 211 216 return 0; 212 217 213 218 if (pllen) { 214 - ret = stm32_usbphyc_pll_disable(usbphyc); 219 + /* 220 + * PLL shouldn't be enabled without known consumer, 221 + * disable it and reinit n_pll_cons 222 + */ 223 + dev_warn(usbphyc->dev, "PLL enabled without known consumers\n"); 224 + 225 + ret = __stm32_usbphyc_pll_disable(usbphyc); 215 226 if (ret) 216 227 return ret; 217 228 } 218 229 219 230 ret = stm32_usbphyc_regulators_enable(usbphyc); 220 231 if (ret) 221 - return ret; 232 + goto dec_n_pll_cons; 222 233 223 234 ret = stm32_usbphyc_pll_init(usbphyc); 224 235 if (ret) 225 236 goto reg_disable; 226 237 227 238 stm32_usbphyc_set_bits(pll_reg, PLLEN); 228 - /* Wait for maximum lock time */ 229 - udelay(PLL_LOCK_TIME_US); 230 - 231 - if (!(readl_relaxed(pll_reg) & PLLEN)) { 232 - dev_err(usbphyc->dev, "PLLEN not set\n"); 233 - ret = -EIO; 234 - goto reg_disable; 235 - } 236 239 237 240 return 0; 238 241 239 242 reg_disable: 240 243 stm32_usbphyc_regulators_disable(usbphyc); 244 + 245 + dec_n_pll_cons: 246 + atomic_dec(&usbphyc->n_pll_cons); 241 247 242 248 return ret; 243 249 } ··· 250 248 { 251 249 struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); 252 250 struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc; 251 + u32 reg_mon = STM32_USBPHYC_MONITOR(usbphyc_phy->index); 252 + u32 monsel = FIELD_PREP(STM32_USBPHYC_MON_SEL, 253 + STM32_USBPHYC_MON_SEL_LOCKP); 254 + u32 monout; 253 255 int ret; 254 256 255 257 ret = stm32_usbphyc_pll_enable(usbphyc); 256 258 if (ret) 257 259 return ret; 258 260 261 + /* Check that PLL Lock input to PHY is High */ 262 + writel_relaxed(monsel, usbphyc->base + reg_mon); 263 + ret = readl_relaxed_poll_timeout(usbphyc->base + reg_mon, monout, 264 + (monout & STM32_USBPHYC_MON_OUT_LOCKP), 265 + 100, 1000); 266 + if (ret) { 267 + dev_err(usbphyc->dev, "PLL Lock input to PHY is Low (val=%x)\n", 268 + (u32)(monout & STM32_USBPHYC_MON_OUT)); 269 + goto pll_disable; 270 + } 271 + 259 272 usbphyc_phy->active = true; 260 273 261 274 return 0; 275 + 276 + pll_disable: 277 + return stm32_usbphyc_pll_disable(usbphyc); 262 278 } 263 279 264 280 static int stm32_usbphyc_phy_exit(struct phy *phy)