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

Configure Feed

Select the types of activity you want to include in your feed.

phy: exynos5-usbdrd: support Exynos USBDRD 3.1 combo phy (HS & SS)

Add support for the Exynos USB 3.1 DRD combo phy, as found in Exynos 9
SoCs like Google GS101. It supports USB SS, HS and DisplayPort.

In terms of UTMI+, this is very similar to the existing Exynos850
support in this driver. The difference is that this combo phy supports
both UTMI+ (HS) and PIPE3 (SS). It also supports DP alt mode.

The number of ports for UTMI+ and PIPE3 can be determined using the
LINKPORT register (which also exists on Exynos E850).

For SuperSpeed (SS) a new SS phy is in use and its PIPE3 interface is
new compared to Exynos E850, and also very different from the existing
support for older Exynos SoCs in this driver.

The SS phy needs a bit more configuration work and register tuning for
signal quality to work reliably, presumably due to the higher
frequency, e.g. to account for different board layouts. Additionally,
power needs to be enabled before writing to the SS phy registers.

This commit adds the necessary changes for USB HS and SS to work.
DisplayPort is out of scope in this commit.

Notes:
* For the register tuning, exynos5_usbdrd_apply_phy_tunes() has been
added with the appropriate data structures to support tuning at
various stages during initialisation. Since these are hardware
specific, the platform data is supposed to be populated accordingly.
The implementation is loosely modelled after the Samsung UFS PHY
driver.

There is one tuning state for UTMI+, PTS_UTMI_POSTINIT, to execute
after init and generally intended for HS signal tuning, as done in
this commit.

PTS_PIPE3_PREINIT PTS_PIPE3_INIT PTS_PIPE3_POSTINIT
PTS_PIPE3_POSTLOCK are tuning states for PIPE3. In the downstream
driver, preinit differs by Exynos SoC, and postinit and postlock
are different per board. The latter haven't been implemented for
gs101 here, because downstream doesn't use them on gs101 either.

* Signal lock acquisition for SS depends on the orientation of the
USB-C plug. Since there currently is no infrastructure to chain
connector events to both the USB DWC3 driver and this phy driver, a
work-around has been added in
exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock() to check both
registers if it failed in one of the orientations.

* Equally, we can only establish SS speed in one of the connector
orientations due to programming differences when selecting the lane
mux in exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(), which really
needs to be dynamic, based on the orientation of the connector.

* As is, we can establish a HS link using any cable, and an SS link in
one orientation of the plug, falling back to HS if the orientation is
reversed to the expectation.

Signed-off-by: André Draszik <andre.draszik@linaro.org>
Reviewed-by: Peter Griffin <peter.griffin@linaro.org>
Tested-by: Peter Griffin <peter.griffin@linaro.org>
Tested-by: Will McVicker <willmcvicker@google.com>
Link: https://lore.kernel.org/r/20240617-usb-phy-gs101-v3-6-b66de9ae7424@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

André Draszik and committed by
Vinod Koul
32267c29 497ddafe

+667 -5
+663 -5
drivers/phy/samsung/phy-exynos5-usbdrd.c
··· 134 134 135 135 /* Exynos850: USB DRD PHY registers */ 136 136 #define EXYNOS850_DRD_LINKCTRL 0x04 137 + #define LINKCTRL_FORCE_RXELECIDLE BIT(18) 138 + #define LINKCTRL_FORCE_PHYSTATUS BIT(17) 139 + #define LINKCTRL_FORCE_PIPE_EN BIT(16) 137 140 #define LINKCTRL_FORCE_QACT BIT(8) 138 141 #define LINKCTRL_BUS_FILTER_BYPASS(_x) ((_x) << 4) 139 142 143 + #define EXYNOS850_DRD_LINKPORT 0x08 144 + #define LINKPORT_HOST_NUM_U3 GENMASK(19, 16) 145 + #define LINKPORT_HOST_NUM_U2 GENMASK(15, 12) 146 + 140 147 #define EXYNOS850_DRD_CLKRST 0x20 148 + /* 149 + * On versions without SS ports (like E850), bit 3 is for the 2.0 phy (HS), 150 + * while on versions with (like gs101), bits 2 and 3 are for the 3.0 phy (SS) 151 + * and bits 12 & 13 for the 2.0 phy. 152 + */ 153 + #define CLKRST_PHY20_SW_POR BIT(13) 154 + #define CLKRST_PHY20_SW_POR_SEL BIT(12) 155 + #define CLKRST_LINK_PCLK_SEL BIT(7) 141 156 #define CLKRST_PHY_SW_RST BIT(3) 157 + #define CLKRST_PHY_RESET_SEL BIT(2) 142 158 #define CLKRST_PORT_RST BIT(1) 143 159 #define CLKRST_LINK_SW_RST BIT(0) 144 160 ··· 176 160 #define HSP_EN_UTMISUSPEND BIT(9) 177 161 #define HSP_COMMONONN BIT(8) 178 162 163 + #define EXYNOS850_DRD_HSPPARACON 0x58 164 + #define HSPPARACON_TXVREF GENMASK(31, 28) 165 + #define HSPPARACON_TXRISE GENMASK(25, 24) 166 + #define HSPPARACON_TXRES GENMASK(22, 21) 167 + #define HSPPARACON_TXPREEMPPULSE BIT(20) 168 + #define HSPPARACON_TXPREEMPAMP GENMASK(19, 18) 169 + #define HSPPARACON_TXHSXV GENMASK(17, 16) 170 + #define HSPPARACON_TXFSLS GENMASK(15, 12) 171 + #define HSPPARACON_SQRX GENMASK(10, 8) 172 + #define HSPPARACON_OTG GENMASK(6, 4) 173 + #define HSPPARACON_COMPDIS GENMASK(2, 0) 174 + 179 175 #define EXYNOS850_DRD_HSP_TEST 0x5c 180 176 #define HSP_TEST_SIDDQ BIT(24) 181 177 178 + /* Exynos9 - GS101 */ 179 + #define EXYNOS850_DRD_SECPMACTL 0x48 180 + #define SECPMACTL_PMA_ROPLL_REF_CLK_SEL GENMASK(13, 12) 181 + #define SECPMACTL_PMA_LCPLL_REF_CLK_SEL GENMASK(11, 10) 182 + #define SECPMACTL_PMA_REF_FREQ_SEL GENMASK(9, 8) 183 + #define SECPMACTL_PMA_LOW_PWR BIT(4) 184 + #define SECPMACTL_PMA_TRSV_SW_RST BIT(3) 185 + #define SECPMACTL_PMA_CMN_SW_RST BIT(2) 186 + #define SECPMACTL_PMA_INIT_SW_RST BIT(1) 187 + #define SECPMACTL_PMA_APB_SW_RST BIT(0) 188 + 189 + /* PMA registers */ 190 + #define EXYNOS9_PMA_USBDP_CMN_REG0008 0x0020 191 + #define CMN_REG0008_OVRD_AUX_EN BIT(3) 192 + #define CMN_REG0008_AUX_EN BIT(2) 193 + 194 + #define EXYNOS9_PMA_USBDP_CMN_REG00B8 0x02e0 195 + #define CMN_REG00B8_LANE_MUX_SEL_DP GENMASK(3, 0) 196 + 197 + #define EXYNOS9_PMA_USBDP_CMN_REG01C0 0x0700 198 + #define CMN_REG01C0_ANA_LCPLL_LOCK_DONE BIT(7) 199 + #define CMN_REG01C0_ANA_LCPLL_AFC_DONE BIT(6) 200 + 201 + /* these have similar register layout, for lanes 0 and 2 */ 202 + #define EXYNOS9_PMA_USBDP_TRSV_REG03C3 0x0f0c 203 + #define EXYNOS9_PMA_USBDP_TRSV_REG07C3 0x1f0c 204 + #define TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE BIT(3) 205 + #define TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE BIT(2) 206 + #define TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE BIT(1) 207 + #define TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE BIT(0) 208 + 209 + /* TRSV_REG0413 and TRSV_REG0813 have similar register layout */ 210 + #define EXYNOS9_PMA_USBDP_TRSV_REG0413 0x104c 211 + #define TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN BIT(7) 212 + #define TRSV_REG0413_OVRD_LN1_TX_RXD_EN BIT(5) 213 + 214 + #define EXYNOS9_PMA_USBDP_TRSV_REG0813 0x204c 215 + #define TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN BIT(7) 216 + #define TRSV_REG0813_OVRD_LN3_TX_RXD_EN BIT(5) 217 + 218 + /* PCS registers */ 219 + #define EXYNOS9_PCS_NS_VEC_PS1_N1 0x010c 220 + #define EXYNOS9_PCS_NS_VEC_PS2_N0 0x0110 221 + #define EXYNOS9_PCS_NS_VEC_PS3_N0 0x0118 222 + #define NS_VEC_NS_REQ GENMASK(31, 24) 223 + #define NS_VEC_ENABLE_TIMER BIT(22) 224 + #define NS_VEC_SEL_TIMEOUT GENMASK(21, 20) 225 + #define NS_VEC_INV_MASK GENMASK(19, 16) 226 + #define NS_VEC_COND_MASK GENMASK(11, 8) 227 + #define NS_VEC_EXP_COND GENMASK(3, 0) 228 + 229 + #define EXYNOS9_PCS_OUT_VEC_2 0x014c 230 + #define EXYNOS9_PCS_OUT_VEC_3 0x0150 231 + #define PCS_OUT_VEC_B9_DYNAMIC BIT(19) 232 + #define PCS_OUT_VEC_B9_SEL_OUT BIT(18) 233 + #define PCS_OUT_VEC_B8_DYNAMIC BIT(17) 234 + #define PCS_OUT_VEC_B8_SEL_OUT BIT(16) 235 + #define PCS_OUT_VEC_B7_DYNAMIC BIT(15) 236 + #define PCS_OUT_VEC_B7_SEL_OUT BIT(14) 237 + #define PCS_OUT_VEC_B6_DYNAMIC BIT(13) 238 + #define PCS_OUT_VEC_B6_SEL_OUT BIT(12) 239 + #define PCS_OUT_VEC_B5_DYNAMIC BIT(11) 240 + #define PCS_OUT_VEC_B5_SEL_OUT BIT(10) 241 + #define PCS_OUT_VEC_B4_DYNAMIC BIT(9) 242 + #define PCS_OUT_VEC_B4_SEL_OUT BIT(8) 243 + #define PCS_OUT_VEC_B3_DYNAMIC BIT(7) 244 + #define PCS_OUT_VEC_B3_SEL_OUT BIT(6) 245 + #define PCS_OUT_VEC_B2_DYNAMIC BIT(5) 246 + #define PCS_OUT_VEC_B2_SEL_OUT BIT(4) 247 + #define PCS_OUT_VEC_B1_DYNAMIC BIT(3) 248 + #define PCS_OUT_VEC_B1_SEL_OUT BIT(2) 249 + #define PCS_OUT_VEC_B0_DYNAMIC BIT(1) 250 + #define PCS_OUT_VEC_B0_SEL_OUT BIT(0) 251 + 252 + #define EXYNOS9_PCS_TIMEOUT_0 0x0170 253 + 254 + #define EXYNOS9_PCS_TIMEOUT_3 0x017c 255 + 256 + #define EXYNOS9_PCS_EBUF_PARAM 0x0304 257 + #define EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE GENMASK(29, 24) 258 + 259 + #define EXYNOS9_PCS_BACK_END_MODE_VEC 0x030c 260 + #define BACK_END_MODE_VEC_FORCE_EBUF_EMPTY_MODE BIT(1) 261 + #define BACK_END_MODE_VEC_DISABLE_DATA_MASK BIT(0) 262 + 263 + #define EXYNOS9_PCS_RX_CONTROL 0x03f0 264 + #define RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B BIT(22) 265 + 266 + #define EXYNOS9_PCS_RX_CONTROL_DEBUG 0x03f4 267 + #define RX_CONTROL_DEBUG_EN_TS_CHECK BIT(5) 268 + #define RX_CONTROL_DEBUG_NUM_COM_FOUND GENMASK(3, 0) 269 + 270 + #define EXYNOS9_PCS_LOCAL_COEF 0x040c 271 + #define LOCAL_COEF_PMA_CENTER_COEF GENMASK(21, 16) 272 + #define LOCAL_COEF_LF GENMASK(13, 8) 273 + #define LOCAL_COEF_FS GENMASK(5, 0) 274 + 275 + #define EXYNOS9_PCS_HS_TX_COEF_MAP_0 0x0410 276 + #define HS_TX_COEF_MAP_0_SSTX_DEEMP GENMASK(17, 12) 277 + #define HS_TX_COEF_MAP_0_SSTX_LEVEL GENMASK(11, 6) 278 + #define HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT GENMASK(5, 0) 279 + 280 + 182 281 #define KHZ 1000 183 282 #define MHZ (KHZ * KHZ) 283 + 284 + #define PHY_TUNING_ENTRY_PHY(o, m, v) { \ 285 + .off = (o), \ 286 + .mask = (m), \ 287 + .val = (v), \ 288 + .region = PTR_PHY \ 289 + } 290 + 291 + #define PHY_TUNING_ENTRY_PCS(o, m, v) { \ 292 + .off = (o), \ 293 + .mask = (m), \ 294 + .val = (v), \ 295 + .region = PTR_PCS \ 296 + } 297 + 298 + #define PHY_TUNING_ENTRY_PMA(o, m, v) { \ 299 + .off = (o), \ 300 + .mask = (m), \ 301 + .val = (v), \ 302 + .region = PTR_PMA, \ 303 + } 304 + 305 + #define PHY_TUNING_ENTRY_LAST { .region = PTR_INVALID } 306 + 307 + #define for_each_phy_tune(tune) \ 308 + for (; (tune)->region != PTR_INVALID; ++(tune)) 309 + 310 + struct exynos5_usbdrd_phy_tuning { 311 + u32 off; 312 + u32 mask; 313 + u32 val; 314 + char region; 315 + #define PTR_INVALID 0 316 + #define PTR_PHY 1 317 + #define PTR_PCS 2 318 + #define PTR_PMA 3 319 + }; 320 + 321 + enum exynos5_usbdrd_phy_tuning_state { 322 + PTS_UTMI_POSTINIT, 323 + PTS_PIPE3_PREINIT, 324 + PTS_PIPE3_INIT, 325 + PTS_PIPE3_POSTINIT, 326 + PTS_PIPE3_POSTLOCK, 327 + PTS_MAX, 328 + }; 184 329 185 330 enum exynos5_usbdrd_phy_id { 186 331 EXYNOS5_DRDPHY_UTMI, ··· 361 184 362 185 struct exynos5_usbdrd_phy_drvdata { 363 186 const struct exynos5_usbdrd_phy_config *phy_cfg; 187 + const struct exynos5_usbdrd_phy_tuning **phy_tunes; 364 188 const struct phy_ops *phy_ops; 365 189 const char * const *clk_names; 366 190 int n_clks; ··· 378 200 * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY 379 201 * @dev: pointer to device instance of this platform device 380 202 * @reg_phy: usb phy controller register memory base 203 + * @reg_pcs: usb phy physical coding sublayer register memory base 204 + * @reg_pma: usb phy physical media attachment register memory base 381 205 * @clks: clocks for register access 382 206 * @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required) 383 207 * @drv_data: pointer to SoC level driver data structure ··· 392 212 struct exynos5_usbdrd_phy { 393 213 struct device *dev; 394 214 void __iomem *reg_phy; 215 + void __iomem *reg_pcs; 216 + void __iomem *reg_pma; 395 217 struct clk_bulk_data *clks; 396 218 struct clk_bulk_data *core_clks; 397 219 const struct exynos5_usbdrd_phy_drvdata *drv_data; ··· 540 358 return reg; 541 359 } 542 360 361 + static void 362 + exynos5_usbdrd_apply_phy_tunes(struct exynos5_usbdrd_phy *phy_drd, 363 + enum exynos5_usbdrd_phy_tuning_state state) 364 + { 365 + const struct exynos5_usbdrd_phy_tuning *tune; 366 + 367 + tune = phy_drd->drv_data->phy_tunes[state]; 368 + if (!tune) 369 + return; 370 + 371 + for_each_phy_tune(tune) { 372 + void __iomem *reg_base; 373 + u32 reg = 0; 374 + 375 + switch (tune->region) { 376 + case PTR_PHY: 377 + reg_base = phy_drd->reg_phy; 378 + break; 379 + case PTR_PCS: 380 + reg_base = phy_drd->reg_pcs; 381 + break; 382 + case PTR_PMA: 383 + reg_base = phy_drd->reg_pma; 384 + break; 385 + default: 386 + dev_warn_once(phy_drd->dev, 387 + "unknown phy region %d\n", tune->region); 388 + continue; 389 + } 390 + 391 + if (~tune->mask) { 392 + reg = readl(reg_base + tune->off); 393 + reg &= ~tune->mask; 394 + } 395 + reg |= tune->val; 396 + writel(reg, reg_base + tune->off); 397 + } 398 + } 399 + 543 400 static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) 544 401 { 545 402 u32 reg; ··· 592 371 reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 593 372 reg &= ~PHYTEST_POWERDOWN_SSP; 594 373 writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); 374 + } 375 + 376 + static void 377 + exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(struct exynos5_usbdrd_phy *phy_drd) 378 + { 379 + void __iomem *regs_base = phy_drd->reg_phy; 380 + u32 reg; 381 + 382 + /* link pipe_clock selection to pclk of PMA */ 383 + reg = readl(regs_base + EXYNOS850_DRD_CLKRST); 384 + reg |= CLKRST_LINK_PCLK_SEL; 385 + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); 386 + 387 + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); 388 + reg &= ~SECPMACTL_PMA_REF_FREQ_SEL; 389 + reg |= FIELD_PREP_CONST(SECPMACTL_PMA_REF_FREQ_SEL, 1); 390 + /* SFR reset */ 391 + reg |= (SECPMACTL_PMA_LOW_PWR | SECPMACTL_PMA_APB_SW_RST); 392 + reg &= ~(SECPMACTL_PMA_ROPLL_REF_CLK_SEL | 393 + SECPMACTL_PMA_LCPLL_REF_CLK_SEL); 394 + /* PMA power off */ 395 + reg |= (SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST | 396 + SECPMACTL_PMA_INIT_SW_RST); 397 + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); 398 + 399 + udelay(1); 400 + 401 + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); 402 + reg &= ~SECPMACTL_PMA_LOW_PWR; 403 + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); 404 + 405 + udelay(1); 406 + 407 + /* release override */ 408 + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); 409 + reg &= ~LINKCTRL_FORCE_PIPE_EN; 410 + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); 411 + 412 + udelay(1); 413 + 414 + /* APB enable */ 415 + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); 416 + reg &= ~SECPMACTL_PMA_APB_SW_RST; 417 + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); 418 + } 419 + 420 + static void 421 + exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(struct exynos5_usbdrd_phy *phy_drd) 422 + { 423 + void __iomem *regs_base = phy_drd->reg_pma; 424 + u32 reg; 425 + 426 + /* lane configuration: USB on all lanes */ 427 + reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8); 428 + reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP; 429 + writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8); 430 + 431 + /* 432 + * FIXME: below code supports one connector orientation only. It needs 433 + * updating once we can receive connector events. 434 + */ 435 + /* override of TX receiver detector and comparator: lane 1 */ 436 + reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413); 437 + reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN; 438 + reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN; 439 + writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413); 440 + 441 + /* lane 3 */ 442 + reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813); 443 + reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN; 444 + reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN; 445 + writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813); 446 + } 447 + 448 + static int 449 + exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(struct exynos5_usbdrd_phy *phy_drd) 450 + { 451 + static const unsigned int timeout_us = 40000; 452 + static const unsigned int sleep_us = 40; 453 + static const u32 locked = (CMN_REG01C0_ANA_LCPLL_LOCK_DONE | 454 + CMN_REG01C0_ANA_LCPLL_AFC_DONE); 455 + u32 reg; 456 + int err; 457 + 458 + err = readl_poll_timeout( 459 + phy_drd->reg_pma + EXYNOS9_PMA_USBDP_CMN_REG01C0, 460 + reg, (reg & locked) == locked, sleep_us, timeout_us); 461 + if (err) 462 + dev_err(phy_drd->dev, 463 + "timed out waiting for PLL lock: %#.8x\n", reg); 464 + 465 + return err; 466 + } 467 + 468 + static void 469 + exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(struct exynos5_usbdrd_phy *phy_drd) 470 + { 471 + static const unsigned int timeout_us = 40000; 472 + static const unsigned int sleep_us = 40; 473 + static const u32 locked = 474 + (TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE 475 + | TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE 476 + | TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE 477 + | TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE); 478 + u32 reg; 479 + int err; 480 + 481 + err = readl_poll_timeout( 482 + phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG03C3, 483 + reg, (reg & locked) == locked, sleep_us, timeout_us); 484 + if (!err) 485 + return; 486 + 487 + dev_err(phy_drd->dev, 488 + "timed out waiting for CDR lock (l0): %#.8x, retrying\n", reg); 489 + 490 + /* based on cable orientation, this might be on the other phy port */ 491 + err = readl_poll_timeout( 492 + phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG07C3, 493 + reg, (reg & locked) == locked, sleep_us, timeout_us); 494 + if (err) 495 + dev_err(phy_drd->dev, 496 + "timed out waiting for CDR lock (l2): %#.8x\n", reg); 595 497 } 596 498 597 499 static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) ··· 1049 705 .owner = THIS_MODULE, 1050 706 }; 1051 707 708 + static void 709 + exynos5_usbdrd_usb_v3p1_pipe_override(struct exynos5_usbdrd_phy *phy_drd) 710 + { 711 + void __iomem *regs_base = phy_drd->reg_phy; 712 + u32 reg; 713 + 714 + /* force pipe3 signal for link */ 715 + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); 716 + reg &= ~LINKCTRL_FORCE_PHYSTATUS; 717 + reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE; 718 + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); 719 + 720 + /* PMA disable */ 721 + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); 722 + reg |= SECPMACTL_PMA_LOW_PWR; 723 + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); 724 + } 725 + 1052 726 static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) 1053 727 { 1054 728 void __iomem *regs_base = phy_drd->reg_phy; 1055 729 u32 reg; 730 + u32 ss_ports; 1056 731 1057 732 /* 1058 733 * Disable HWACG (hardware auto clock gating control). This will force ··· 1082 719 reg |= LINKCTRL_FORCE_QACT; 1083 720 writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); 1084 721 722 + reg = readl(regs_base + EXYNOS850_DRD_LINKPORT); 723 + ss_ports = FIELD_GET(LINKPORT_HOST_NUM_U3, reg); 724 + 1085 725 /* Start PHY Reset (POR=high) */ 1086 726 reg = readl(regs_base + EXYNOS850_DRD_CLKRST); 727 + if (ss_ports) { 728 + reg |= CLKRST_PHY20_SW_POR; 729 + reg |= CLKRST_PHY20_SW_POR_SEL; 730 + reg |= CLKRST_PHY_RESET_SEL; 731 + } 1087 732 reg |= CLKRST_PHY_SW_RST; 1088 733 writel(reg, regs_base + EXYNOS850_DRD_CLKRST); 1089 734 ··· 1144 773 } 1145 774 writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL); 1146 775 776 + if (phy_drd->drv_data->phy_tunes) 777 + exynos5_usbdrd_apply_phy_tunes(phy_drd, 778 + PTS_UTMI_POSTINIT); 779 + 1147 780 /* Power up PHY analog blocks */ 1148 781 reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST); 1149 782 reg &= ~HSP_TEST_SIDDQ; ··· 1156 781 /* Finish PHY reset (POR=low) */ 1157 782 fsleep(10); /* required before doing POR=low */ 1158 783 reg = readl(regs_base + EXYNOS850_DRD_CLKRST); 784 + if (ss_ports) { 785 + reg |= CLKRST_PHY20_SW_POR_SEL; 786 + reg &= ~CLKRST_PHY20_SW_POR; 787 + } 1159 788 reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST); 1160 789 writel(reg, regs_base + EXYNOS850_DRD_CLKRST); 1161 790 fsleep(75); /* required after POR=low for guaranteed PHY clock */ ··· 1168 789 reg = readl(regs_base + EXYNOS850_DRD_HSP); 1169 790 reg &= ~HSP_FSV_OUT_EN; 1170 791 writel(reg, regs_base + EXYNOS850_DRD_HSP); 792 + 793 + if (ss_ports) 794 + exynos5_usbdrd_usb_v3p1_pipe_override(phy_drd); 1171 795 } 1172 796 1173 797 static int exynos850_usbdrd_phy_init(struct phy *phy) ··· 1232 850 .exit = exynos850_usbdrd_phy_exit, 1233 851 .power_on = exynos5_usbdrd_phy_power_on, 1234 852 .power_off = exynos5_usbdrd_phy_power_off, 853 + .owner = THIS_MODULE, 854 + }; 855 + 856 + static void exynos5_usbdrd_gs101_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) 857 + { 858 + void __iomem *regs_pma = phy_drd->reg_pma; 859 + void __iomem *regs_phy = phy_drd->reg_phy; 860 + u32 reg; 861 + 862 + exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(phy_drd); 863 + 864 + /* force aux off */ 865 + reg = readl(regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008); 866 + reg &= ~CMN_REG0008_AUX_EN; 867 + reg |= CMN_REG0008_OVRD_AUX_EN; 868 + writel(reg, regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008); 869 + 870 + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_PREINIT); 871 + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_INIT); 872 + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_POSTINIT); 873 + 874 + exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(phy_drd); 875 + 876 + /* reset release from port */ 877 + reg = readl(regs_phy + EXYNOS850_DRD_SECPMACTL); 878 + reg &= ~(SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST | 879 + SECPMACTL_PMA_INIT_SW_RST); 880 + writel(reg, regs_phy + EXYNOS850_DRD_SECPMACTL); 881 + 882 + if (!exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(phy_drd)) 883 + exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(phy_drd); 884 + } 885 + 886 + static int exynos5_usbdrd_gs101_phy_init(struct phy *phy) 887 + { 888 + struct phy_usb_instance *inst = phy_get_drvdata(phy); 889 + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 890 + int ret; 891 + 892 + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { 893 + /* Power-on PHY ... */ 894 + ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators, 895 + phy_drd->regulators); 896 + if (ret) { 897 + dev_err(phy_drd->dev, 898 + "Failed to enable PHY regulator(s)\n"); 899 + return ret; 900 + } 901 + } 902 + /* 903 + * ... and ungate power via PMU. Without this here, we get an SError 904 + * trying to access PMA registers 905 + */ 906 + exynos5_usbdrd_phy_isol(inst, false); 907 + 908 + return exynos850_usbdrd_phy_init(phy); 909 + } 910 + 911 + static int exynos5_usbdrd_gs101_phy_exit(struct phy *phy) 912 + { 913 + struct phy_usb_instance *inst = phy_get_drvdata(phy); 914 + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); 915 + int ret; 916 + 917 + if (inst->phy_cfg->id != EXYNOS5_DRDPHY_UTMI) 918 + return 0; 919 + 920 + ret = exynos850_usbdrd_phy_exit(phy); 921 + if (ret) 922 + return ret; 923 + 924 + exynos5_usbdrd_phy_isol(inst, true); 925 + return regulator_bulk_disable(phy_drd->drv_data->n_regulators, 926 + phy_drd->regulators); 927 + } 928 + 929 + static const struct phy_ops gs101_usbdrd_phy_ops = { 930 + .init = exynos5_usbdrd_gs101_phy_init, 931 + .exit = exynos5_usbdrd_gs101_phy_exit, 1235 932 .owner = THIS_MODULE, 1236 933 }; 1237 934 ··· 1472 1011 .n_regulators = ARRAY_SIZE(exynos5_regulator_names), 1473 1012 }; 1474 1013 1014 + static const struct exynos5_usbdrd_phy_config phy_cfg_gs101[] = { 1015 + { 1016 + .id = EXYNOS5_DRDPHY_UTMI, 1017 + .phy_isol = exynos5_usbdrd_phy_isol, 1018 + .phy_init = exynos850_usbdrd_utmi_init, 1019 + }, 1020 + { 1021 + .id = EXYNOS5_DRDPHY_PIPE3, 1022 + .phy_isol = exynos5_usbdrd_phy_isol, 1023 + .phy_init = exynos5_usbdrd_gs101_pipe3_init, 1024 + }, 1025 + }; 1026 + 1027 + static const struct exynos5_usbdrd_phy_tuning gs101_tunes_utmi_postinit[] = { 1028 + PHY_TUNING_ENTRY_PHY(EXYNOS850_DRD_HSPPARACON, 1029 + (HSPPARACON_TXVREF | HSPPARACON_TXRES | 1030 + HSPPARACON_TXPREEMPAMP | HSPPARACON_SQRX | 1031 + HSPPARACON_COMPDIS), 1032 + (FIELD_PREP_CONST(HSPPARACON_TXVREF, 6) | 1033 + FIELD_PREP_CONST(HSPPARACON_TXRES, 1) | 1034 + FIELD_PREP_CONST(HSPPARACON_TXPREEMPAMP, 3) | 1035 + FIELD_PREP_CONST(HSPPARACON_SQRX, 5) | 1036 + FIELD_PREP_CONST(HSPPARACON_COMPDIS, 7))), 1037 + PHY_TUNING_ENTRY_LAST 1038 + }; 1039 + 1040 + static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = { 1041 + /* preinit */ 1042 + /* CDR data mode exit GEN1 ON / GEN2 OFF */ 1043 + PHY_TUNING_ENTRY_PMA(0x0c8c, -1, 0xff), 1044 + PHY_TUNING_ENTRY_PMA(0x1c8c, -1, 0xff), 1045 + PHY_TUNING_ENTRY_PMA(0x0c9c, -1, 0x7d), 1046 + PHY_TUNING_ENTRY_PMA(0x1c9c, -1, 0x7d), 1047 + /* improve EDS distribution */ 1048 + PHY_TUNING_ENTRY_PMA(0x0e7c, -1, 0x06), 1049 + PHY_TUNING_ENTRY_PMA(0x09e0, -1, 0x00), 1050 + PHY_TUNING_ENTRY_PMA(0x09e4, -1, 0x36), 1051 + PHY_TUNING_ENTRY_PMA(0x1e7c, -1, 0x06), 1052 + PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x00), 1053 + PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x36), 1054 + /* improve LVCC */ 1055 + PHY_TUNING_ENTRY_PMA(0x08f0, -1, 0x30), 1056 + PHY_TUNING_ENTRY_PMA(0x18f0, -1, 0x30), 1057 + /* LFPS RX VIH shmoo hole */ 1058 + PHY_TUNING_ENTRY_PMA(0x0a08, -1, 0x0c), 1059 + PHY_TUNING_ENTRY_PMA(0x1a08, -1, 0x0c), 1060 + /* remove unrelated option for v4 phy */ 1061 + PHY_TUNING_ENTRY_PMA(0x0a0c, -1, 0x05), 1062 + PHY_TUNING_ENTRY_PMA(0x1a0c, -1, 0x05), 1063 + /* improve Gen2 LVCC */ 1064 + PHY_TUNING_ENTRY_PMA(0x00f8, -1, 0x1c), 1065 + PHY_TUNING_ENTRY_PMA(0x00fc, -1, 0x54), 1066 + /* Change Vth of RCV_DET because of TD 7.40 Polling Retry Test */ 1067 + PHY_TUNING_ENTRY_PMA(0x104c, -1, 0x07), 1068 + PHY_TUNING_ENTRY_PMA(0x204c, -1, 0x07), 1069 + /* reduce Ux Exit time, assuming 26MHz clock */ 1070 + /* Gen1 */ 1071 + PHY_TUNING_ENTRY_PMA(0x0ca8, -1, 0x00), 1072 + PHY_TUNING_ENTRY_PMA(0x0cac, -1, 0x04), 1073 + PHY_TUNING_ENTRY_PMA(0x1ca8, -1, 0x00), 1074 + PHY_TUNING_ENTRY_PMA(0x1cac, -1, 0x04), 1075 + /* Gen2 */ 1076 + PHY_TUNING_ENTRY_PMA(0x0cb8, -1, 0x00), 1077 + PHY_TUNING_ENTRY_PMA(0x0cbc, -1, 0x04), 1078 + PHY_TUNING_ENTRY_PMA(0x1cb8, -1, 0x00), 1079 + PHY_TUNING_ENTRY_PMA(0x1cbc, -1, 0x04), 1080 + /* RX impedance setting */ 1081 + PHY_TUNING_ENTRY_PMA(0x0bb0, 0x03, 0x01), 1082 + PHY_TUNING_ENTRY_PMA(0x0bb4, 0xf0, 0xa0), 1083 + PHY_TUNING_ENTRY_PMA(0x1bb0, 0x03, 0x01), 1084 + PHY_TUNING_ENTRY_PMA(0x1bb4, 0xf0, 0xa0), 1085 + 1086 + PHY_TUNING_ENTRY_LAST 1087 + }; 1088 + 1089 + static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_init[] = { 1090 + /* init */ 1091 + /* abnormal common pattern mask */ 1092 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_BACK_END_MODE_VEC, 1093 + BACK_END_MODE_VEC_DISABLE_DATA_MASK, 0), 1094 + /* de-serializer enabled when U2 */ 1095 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_2, PCS_OUT_VEC_B4_DYNAMIC, 1096 + PCS_OUT_VEC_B4_SEL_OUT), 1097 + /* TX Keeper Disable, Squelch on when U3 */ 1098 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B7_DYNAMIC, 1099 + PCS_OUT_VEC_B7_SEL_OUT | PCS_OUT_VEC_B2_SEL_OUT), 1100 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS1_N1, -1, 1101 + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 5) | 1102 + NS_VEC_ENABLE_TIMER | 1103 + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3))), 1104 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS2_N0, -1, 1105 + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) | 1106 + NS_VEC_ENABLE_TIMER | 1107 + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) | 1108 + FIELD_PREP_CONST(NS_VEC_COND_MASK, 2) | 1109 + FIELD_PREP_CONST(NS_VEC_EXP_COND, 2))), 1110 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS3_N0, -1, 1111 + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) | 1112 + NS_VEC_ENABLE_TIMER | 1113 + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) | 1114 + FIELD_PREP_CONST(NS_VEC_COND_MASK, 7) | 1115 + FIELD_PREP_CONST(NS_VEC_EXP_COND, 7))), 1116 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_0, -1, 112), 1117 + /* Block Aligner Type B */ 1118 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL, 0, 1119 + RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B), 1120 + /* Block align at TS1/TS2 for Gen2 stability (Gen2 only) */ 1121 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL_DEBUG, 1122 + RX_CONTROL_DEBUG_NUM_COM_FOUND, 1123 + (RX_CONTROL_DEBUG_EN_TS_CHECK | 1124 + /* 1125 + * increase pcs ts1 adding packet-cnt 1 --> 4 1126 + * lnx_rx_valid_rstn_delay_rise_sp/ssp : 1127 + * 19.6us(0x200) -> 15.3us(0x4) 1128 + */ 1129 + FIELD_PREP_CONST(RX_CONTROL_DEBUG_NUM_COM_FOUND, 4))), 1130 + /* Gen1 Tx DRIVER pre-shoot, de-emphasis, level ctrl */ 1131 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_HS_TX_COEF_MAP_0, 1132 + (HS_TX_COEF_MAP_0_SSTX_DEEMP | HS_TX_COEF_MAP_0_SSTX_LEVEL | 1133 + HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT), 1134 + (FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_DEEMP, 8) | 1135 + FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_LEVEL, 0xb) | 1136 + FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT, 0))), 1137 + /* Gen2 Tx DRIVER level ctrl */ 1138 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_LOCAL_COEF, 1139 + LOCAL_COEF_PMA_CENTER_COEF, 1140 + FIELD_PREP_CONST(LOCAL_COEF_PMA_CENTER_COEF, 0xb)), 1141 + /* Gen2 U1 exit LFPS duration : 900ns ~ 1.2us */ 1142 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_3, -1, 4096), 1143 + /* set skp_remove_th 0x2 -> 0x7 for avoiding retry problem. */ 1144 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_EBUF_PARAM, 1145 + EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE, 1146 + FIELD_PREP_CONST(EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE, 0x7)), 1147 + 1148 + PHY_TUNING_ENTRY_LAST 1149 + }; 1150 + 1151 + static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_postlock[] = { 1152 + /* Squelch off when U3 */ 1153 + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B2_SEL_OUT, 0), 1154 + 1155 + PHY_TUNING_ENTRY_LAST 1156 + }; 1157 + 1158 + static const struct exynos5_usbdrd_phy_tuning *gs101_tunes[PTS_MAX] = { 1159 + [PTS_UTMI_POSTINIT] = gs101_tunes_utmi_postinit, 1160 + [PTS_PIPE3_PREINIT] = gs101_tunes_pipe3_preinit, 1161 + [PTS_PIPE3_INIT] = gs101_tunes_pipe3_init, 1162 + [PTS_PIPE3_POSTLOCK] = gs101_tunes_pipe3_postlock, 1163 + }; 1164 + 1165 + static const char * const gs101_clk_names[] = { 1166 + "phy", "ctrl_aclk", "ctrl_pclk", "scl_pclk", 1167 + }; 1168 + 1169 + static const char * const gs101_regulator_names[] = { 1170 + "pll", 1171 + "dvdd-usb20", "vddh-usb20", "vdd33-usb20", 1172 + "vdda-usbdp", "vddh-usbdp", 1173 + }; 1174 + 1175 + static const struct exynos5_usbdrd_phy_drvdata gs101_usbd31rd_phy = { 1176 + .phy_cfg = phy_cfg_gs101, 1177 + .phy_tunes = gs101_tunes, 1178 + .phy_ops = &gs101_usbdrd_phy_ops, 1179 + .pmu_offset_usbdrd0_phy = GS101_PHY_CTRL_USB20, 1180 + .pmu_offset_usbdrd0_phy_ss = GS101_PHY_CTRL_USBDP, 1181 + .clk_names = gs101_clk_names, 1182 + .n_clks = ARRAY_SIZE(gs101_clk_names), 1183 + .core_clk_names = exynos5_core_clk_names, 1184 + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), 1185 + .regulator_names = gs101_regulator_names, 1186 + .n_regulators = ARRAY_SIZE(gs101_regulator_names), 1187 + }; 1188 + 1475 1189 static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { 1476 1190 { 1191 + .compatible = "google,gs101-usb31drd-phy", 1192 + .data = &gs101_usbd31rd_phy 1193 + }, { 1477 1194 .compatible = "samsung,exynos5250-usbdrd-phy", 1478 1195 .data = &exynos5250_usbdrd_phy 1479 1196 }, { ··· 1690 1051 dev_set_drvdata(dev, phy_drd); 1691 1052 phy_drd->dev = dev; 1692 1053 1693 - phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0); 1694 - if (IS_ERR(phy_drd->reg_phy)) 1695 - return PTR_ERR(phy_drd->reg_phy); 1696 - 1697 1054 drv_data = of_device_get_match_data(dev); 1698 1055 if (!drv_data) 1699 1056 return -EINVAL; 1700 - 1701 1057 phy_drd->drv_data = drv_data; 1058 + 1059 + if (of_property_present(dev->of_node, "reg-names")) { 1060 + void __iomem *reg; 1061 + 1062 + reg = devm_platform_ioremap_resource_byname(pdev, "phy"); 1063 + if (IS_ERR(reg)) 1064 + return PTR_ERR(reg); 1065 + phy_drd->reg_phy = reg; 1066 + 1067 + reg = devm_platform_ioremap_resource_byname(pdev, "pcs"); 1068 + if (IS_ERR(reg)) 1069 + return PTR_ERR(reg); 1070 + phy_drd->reg_pcs = reg; 1071 + 1072 + reg = devm_platform_ioremap_resource_byname(pdev, "pma"); 1073 + if (IS_ERR(reg)) 1074 + return PTR_ERR(reg); 1075 + phy_drd->reg_pma = reg; 1076 + } else { 1077 + /* DTB with just a single region */ 1078 + phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0); 1079 + if (IS_ERR(phy_drd->reg_phy)) 1080 + return PTR_ERR(phy_drd->reg_phy); 1081 + } 1702 1082 1703 1083 ret = exynos5_usbdrd_phy_clk_handle(phy_drd); 1704 1084 if (ret)
+4
include/linux/soc/samsung/exynos-regs-pmu.h
··· 657 657 #define EXYNOS5433_PAD_RETENTION_UFS_OPTION (0x3268) 658 658 #define EXYNOS5433_PAD_RETENTION_FSYSGENIO_OPTION (0x32A8) 659 659 660 + /* For GS101 */ 661 + #define GS101_PHY_CTRL_USB20 0x3eb0 662 + #define GS101_PHY_CTRL_USBDP 0x3eb4 663 + 660 664 #endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */