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: gs101: configure SS lanes based on orientation

USB SS lanes need to be configured based on the connector orientation -
at most two lanes will be in use for USB (and the remaining two for
alternate modes like DP).

For the USB link to come up in SS, the lane configuration registers
have to be programmed accordingly.

While we still need a way to be notified of the actual connector
orientation and then reprogram the registers accordingly (at the moment
the configuration happens just once during phy_init() and never again),
we can prepare the code doing the configuration to take the orientation
into account.

Do so.

Note: the mutex is needed to synchronize this with the upcoming
connector orientation callback.

Reviewed-by: Peter Griffin <peter.griffin@linaro.org>
Tested-by: Peter Griffin <peter.griffin@linaro.org>
Signed-off-by: André Draszik <andre.draszik@linaro.org>
Tested-by: Will McVicker <willmcvicker@google.com>
Link: https://lore.kernel.org/r/20241206-gs101-phy-lanes-orientation-phy-v4-5-f5961268b149@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

André Draszik and committed by
Vinod Koul
0bccdcb3 21860f34

+51 -21
+51 -21
drivers/phy/samsung/phy-exynos5-usbdrd.c
··· 23 23 #include <linux/regmap.h> 24 24 #include <linux/regulator/consumer.h> 25 25 #include <linux/soc/samsung/exynos-regs-pmu.h> 26 + #include <linux/usb/typec.h> 26 27 27 28 /* Exynos USB PHY registers */ 28 29 #define EXYNOS5_FSEL_9MHZ6 0x0 ··· 210 209 211 210 #define EXYNOS9_PMA_USBDP_CMN_REG00B8 0x02e0 212 211 #define CMN_REG00B8_LANE_MUX_SEL_DP GENMASK(3, 0) 212 + #define CMN_REG00B8_LANE_MUX_SEL_DP_LANE3 BIT(3) 213 + #define CMN_REG00B8_LANE_MUX_SEL_DP_LANE2 BIT(2) 214 + #define CMN_REG00B8_LANE_MUX_SEL_DP_LANE1 BIT(1) 215 + #define CMN_REG00B8_LANE_MUX_SEL_DP_LANE0 BIT(0) 213 216 214 217 #define EXYNOS9_PMA_USBDP_CMN_REG01C0 0x0700 215 218 #define CMN_REG01C0_ANA_LCPLL_LOCK_DONE BIT(7) ··· 388 383 * @clks: clocks for register access 389 384 * @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required) 390 385 * @drv_data: pointer to SoC level driver data structure 386 + * @phy_mutex: mutex protecting phy_init/exit & TCPC callbacks 391 387 * @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY 392 388 * instances each with its 'phy' and 'phy_cfg'. 393 389 * @extrefclk: frequency select settings when using 'separate 394 390 * reference clocks' for SS and HS operations 395 391 * @regulators: regulators for phy 392 + * @orientation: TypeC connector orientation - normal or flipped 396 393 */ 397 394 struct exynos5_usbdrd_phy { 398 395 struct device *dev; ··· 404 397 struct clk_bulk_data *clks; 405 398 struct clk_bulk_data *core_clks; 406 399 const struct exynos5_usbdrd_phy_drvdata *drv_data; 400 + struct mutex phy_mutex; 407 401 struct phy_usb_instance { 408 402 struct phy *phy; 409 403 u32 index; ··· 414 406 } phys[EXYNOS5_DRDPHYS_NUM]; 415 407 u32 extrefclk; 416 408 struct regulator_bulk_data *regulators; 409 + 410 + enum typec_orientation orientation; 417 411 }; 418 412 419 413 static inline ··· 657 647 /* lane configuration: USB on all lanes */ 658 648 reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8); 659 649 reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP; 650 + /* 651 + * USB on lanes 0 & 1 in normal mode, or 2 & 3 if reversed, DP on the 652 + * other ones. 653 + */ 654 + reg |= FIELD_PREP(CMN_REG00B8_LANE_MUX_SEL_DP, 655 + ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) 656 + ? (CMN_REG00B8_LANE_MUX_SEL_DP_LANE3 657 + | CMN_REG00B8_LANE_MUX_SEL_DP_LANE2) 658 + : (CMN_REG00B8_LANE_MUX_SEL_DP_LANE1 659 + | CMN_REG00B8_LANE_MUX_SEL_DP_LANE0))); 660 660 writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8); 661 661 662 - /* 663 - * FIXME: below code supports one connector orientation only. It needs 664 - * updating once we can receive connector events. 665 - */ 666 662 /* override of TX receiver detector and comparator: lane 1 */ 667 663 reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413); 668 - reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN; 669 - reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN; 664 + if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) { 665 + reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN; 666 + reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN; 667 + } else { 668 + reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN; 669 + reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_EN; 670 + } 670 671 writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413); 671 672 672 673 /* lane 3 */ 673 674 reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813); 674 - reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN; 675 - reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN; 675 + if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) { 676 + reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN; 677 + reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN; 678 + } else { 679 + reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN; 680 + reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_EN; 681 + } 676 682 writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813); 677 683 } 678 684 ··· 726 700 int err; 727 701 728 702 err = readl_poll_timeout( 729 - phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG03C3, 730 - reg, (reg & locked) == locked, sleep_us, timeout_us); 731 - if (!err) 732 - return; 733 - 734 - dev_err(phy_drd->dev, 735 - "timed out waiting for CDR lock (l0): %#.8x, retrying\n", reg); 736 - 737 - /* based on cable orientation, this might be on the other phy port */ 738 - err = readl_poll_timeout( 739 - phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG07C3, 703 + /* lane depends on cable orientation */ 704 + (phy_drd->reg_pma 705 + + ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) 706 + ? EXYNOS9_PMA_USBDP_TRSV_REG03C3 707 + : EXYNOS9_PMA_USBDP_TRSV_REG07C3)), 740 708 reg, (reg & locked) == locked, sleep_us, timeout_us); 741 709 if (err) 742 710 dev_err(phy_drd->dev, 743 - "timed out waiting for CDR lock (l2): %#.8x\n", reg); 711 + "timed out waiting for CDR(l%d) lock: %#.8x\n", 712 + ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) 713 + ? 0 714 + : 2), reg); 744 715 } 745 716 746 717 static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) ··· 1207 1184 return ret; 1208 1185 1209 1186 /* UTMI or PIPE3 specific init */ 1210 - inst->phy_cfg->phy_init(phy_drd); 1187 + scoped_guard(mutex, &phy_drd->phy_mutex) 1188 + inst->phy_cfg->phy_init(phy_drd); 1211 1189 1212 1190 clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); 1213 1191 ··· 1226 1202 ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); 1227 1203 if (ret) 1228 1204 return ret; 1205 + 1206 + guard(mutex)(&phy_drd->phy_mutex); 1229 1207 1230 1208 /* Set PHY clock and control HS PHY */ 1231 1209 reg = readl(regs_base + EXYNOS850_DRD_UTMI); ··· 1723 1697 if (!drv_data) 1724 1698 return -EINVAL; 1725 1699 phy_drd->drv_data = drv_data; 1700 + 1701 + ret = devm_mutex_init(dev, &phy_drd->phy_mutex); 1702 + if (ret) 1703 + return ret; 1726 1704 1727 1705 if (of_property_present(dev->of_node, "reg-names")) { 1728 1706 void __iomem *reg;