12f70bbddSSebastian Reichel // SPDX-License-Identifier: GPL-2.0-or-later 22f70bbddSSebastian Reichel /* 32f70bbddSSebastian Reichel * Rockchip USBDP Combo PHY with Samsung IP block driver 42f70bbddSSebastian Reichel * 52f70bbddSSebastian Reichel * Copyright (C) 2021-2024 Rockchip Electronics Co., Ltd 62f70bbddSSebastian Reichel * Copyright (C) 2024 Collabora Ltd 72f70bbddSSebastian Reichel */ 82f70bbddSSebastian Reichel 92f70bbddSSebastian Reichel #include <dt-bindings/phy/phy.h> 102f70bbddSSebastian Reichel #include <linux/bitfield.h> 112f70bbddSSebastian Reichel #include <linux/bits.h> 122f70bbddSSebastian Reichel #include <linux/clk.h> 132f70bbddSSebastian Reichel #include <linux/delay.h> 142f70bbddSSebastian Reichel #include <linux/gpio.h> 152f70bbddSSebastian Reichel #include <linux/mfd/syscon.h> 162f70bbddSSebastian Reichel #include <linux/mod_devicetable.h> 172f70bbddSSebastian Reichel #include <linux/module.h> 182f70bbddSSebastian Reichel #include <linux/mutex.h> 192f70bbddSSebastian Reichel #include <linux/phy/phy.h> 202f70bbddSSebastian Reichel #include <linux/platform_device.h> 212f70bbddSSebastian Reichel #include <linux/property.h> 222f70bbddSSebastian Reichel #include <linux/regmap.h> 232f70bbddSSebastian Reichel #include <linux/reset.h> 242f70bbddSSebastian Reichel #include <linux/usb/ch9.h> 252f70bbddSSebastian Reichel #include <linux/usb/typec_dp.h> 262f70bbddSSebastian Reichel #include <linux/usb/typec_mux.h> 272f70bbddSSebastian Reichel 282f70bbddSSebastian Reichel /* USBDP PHY Register Definitions */ 292f70bbddSSebastian Reichel #define UDPHY_PCS 0x4000 302f70bbddSSebastian Reichel #define UDPHY_PMA 0x8000 312f70bbddSSebastian Reichel 322f70bbddSSebastian Reichel /* VO0 GRF Registers */ 332f70bbddSSebastian Reichel #define DP_SINK_HPD_CFG BIT(11) 342f70bbddSSebastian Reichel #define DP_SINK_HPD_SEL BIT(10) 352f70bbddSSebastian Reichel #define DP_AUX_DIN_SEL BIT(9) 362f70bbddSSebastian Reichel #define DP_AUX_DOUT_SEL BIT(8) 372f70bbddSSebastian Reichel #define DP_LANE_SEL_N(n) GENMASK(2 * (n) + 1, 2 * (n)) 382f70bbddSSebastian Reichel #define DP_LANE_SEL_ALL GENMASK(7, 0) 392f70bbddSSebastian Reichel 402f70bbddSSebastian Reichel /* PMA CMN Registers */ 412f70bbddSSebastian Reichel #define CMN_LANE_MUX_AND_EN_OFFSET 0x0288 /* cmn_reg00A2 */ 422f70bbddSSebastian Reichel #define CMN_DP_LANE_MUX_N(n) BIT((n) + 4) 432f70bbddSSebastian Reichel #define CMN_DP_LANE_EN_N(n) BIT(n) 442f70bbddSSebastian Reichel #define CMN_DP_LANE_MUX_ALL GENMASK(7, 4) 452f70bbddSSebastian Reichel #define CMN_DP_LANE_EN_ALL GENMASK(3, 0) 462f70bbddSSebastian Reichel 472f70bbddSSebastian Reichel #define CMN_DP_LINK_OFFSET 0x28c /* cmn_reg00A3 */ 482f70bbddSSebastian Reichel #define CMN_DP_TX_LINK_BW GENMASK(6, 5) 492f70bbddSSebastian Reichel #define CMN_DP_TX_LANE_SWAP_EN BIT(2) 502f70bbddSSebastian Reichel 512f70bbddSSebastian Reichel #define CMN_SSC_EN_OFFSET 0x2d0 /* cmn_reg00B4 */ 522f70bbddSSebastian Reichel #define CMN_ROPLL_SSC_EN BIT(1) 532f70bbddSSebastian Reichel #define CMN_LCPLL_SSC_EN BIT(0) 542f70bbddSSebastian Reichel 552f70bbddSSebastian Reichel #define CMN_ANA_LCPLL_DONE_OFFSET 0x0350 /* cmn_reg00D4 */ 562f70bbddSSebastian Reichel #define CMN_ANA_LCPLL_LOCK_DONE BIT(7) 572f70bbddSSebastian Reichel #define CMN_ANA_LCPLL_AFC_DONE BIT(6) 582f70bbddSSebastian Reichel 592f70bbddSSebastian Reichel #define CMN_ANA_ROPLL_DONE_OFFSET 0x0354 /* cmn_reg00D5 */ 602f70bbddSSebastian Reichel #define CMN_ANA_ROPLL_LOCK_DONE BIT(1) 612f70bbddSSebastian Reichel #define CMN_ANA_ROPLL_AFC_DONE BIT(0) 622f70bbddSSebastian Reichel 632f70bbddSSebastian Reichel #define CMN_DP_RSTN_OFFSET 0x038c /* cmn_reg00E3 */ 642f70bbddSSebastian Reichel #define CMN_DP_INIT_RSTN BIT(3) 652f70bbddSSebastian Reichel #define CMN_DP_CMN_RSTN BIT(2) 662f70bbddSSebastian Reichel #define CMN_CDR_WTCHDG_EN BIT(1) 672f70bbddSSebastian Reichel #define CMN_CDR_WTCHDG_MSK_CDR_EN BIT(0) 682f70bbddSSebastian Reichel 692f70bbddSSebastian Reichel #define TRSV_ANA_TX_CLK_OFFSET_N(n) (0x854 + (n) * 0x800) /* trsv_reg0215 */ 702f70bbddSSebastian Reichel #define LN_ANA_TX_SER_TXCLK_INV BIT(1) 712f70bbddSSebastian Reichel 722f70bbddSSebastian Reichel #define TRSV_LN0_MON_RX_CDR_DONE_OFFSET 0x0b84 /* trsv_reg02E1 */ 732f70bbddSSebastian Reichel #define TRSV_LN0_MON_RX_CDR_LOCK_DONE BIT(0) 742f70bbddSSebastian Reichel 752f70bbddSSebastian Reichel #define TRSV_LN2_MON_RX_CDR_DONE_OFFSET 0x1b84 /* trsv_reg06E1 */ 762f70bbddSSebastian Reichel #define TRSV_LN2_MON_RX_CDR_LOCK_DONE BIT(0) 772f70bbddSSebastian Reichel 782f70bbddSSebastian Reichel #define BIT_WRITEABLE_SHIFT 16 792f70bbddSSebastian Reichel #define PHY_AUX_DP_DATA_POL_NORMAL 0 802f70bbddSSebastian Reichel #define PHY_AUX_DP_DATA_POL_INVERT 1 812f70bbddSSebastian Reichel #define PHY_LANE_MUX_USB 0 822f70bbddSSebastian Reichel #define PHY_LANE_MUX_DP 1 832f70bbddSSebastian Reichel 842f70bbddSSebastian Reichel enum { 852f70bbddSSebastian Reichel DP_BW_RBR, 862f70bbddSSebastian Reichel DP_BW_HBR, 872f70bbddSSebastian Reichel DP_BW_HBR2, 882f70bbddSSebastian Reichel DP_BW_HBR3, 892f70bbddSSebastian Reichel }; 902f70bbddSSebastian Reichel 912f70bbddSSebastian Reichel enum { 922f70bbddSSebastian Reichel UDPHY_MODE_NONE = 0, 932f70bbddSSebastian Reichel UDPHY_MODE_USB = BIT(0), 942f70bbddSSebastian Reichel UDPHY_MODE_DP = BIT(1), 952f70bbddSSebastian Reichel UDPHY_MODE_DP_USB = BIT(1) | BIT(0), 962f70bbddSSebastian Reichel }; 972f70bbddSSebastian Reichel 982f70bbddSSebastian Reichel struct rk_udphy_grf_reg { 992f70bbddSSebastian Reichel unsigned int offset; 1002f70bbddSSebastian Reichel unsigned int disable; 1012f70bbddSSebastian Reichel unsigned int enable; 1022f70bbddSSebastian Reichel }; 1032f70bbddSSebastian Reichel 1042f70bbddSSebastian Reichel #define _RK_UDPHY_GEN_GRF_REG(offset, mask, disable, enable) \ 1052f70bbddSSebastian Reichel {\ 1062f70bbddSSebastian Reichel offset, \ 1072f70bbddSSebastian Reichel FIELD_PREP_CONST(mask, disable) | (mask << BIT_WRITEABLE_SHIFT), \ 1082f70bbddSSebastian Reichel FIELD_PREP_CONST(mask, enable) | (mask << BIT_WRITEABLE_SHIFT), \ 1092f70bbddSSebastian Reichel } 1102f70bbddSSebastian Reichel 1112f70bbddSSebastian Reichel #define RK_UDPHY_GEN_GRF_REG(offset, bitend, bitstart, disable, enable) \ 1122f70bbddSSebastian Reichel _RK_UDPHY_GEN_GRF_REG(offset, GENMASK(bitend, bitstart), disable, enable) 1132f70bbddSSebastian Reichel 1142f70bbddSSebastian Reichel struct rk_udphy_grf_cfg { 1152f70bbddSSebastian Reichel /* u2phy-grf */ 1162f70bbddSSebastian Reichel struct rk_udphy_grf_reg bvalid_phy_con; 1172f70bbddSSebastian Reichel struct rk_udphy_grf_reg bvalid_grf_con; 1182f70bbddSSebastian Reichel 1192f70bbddSSebastian Reichel /* usb-grf */ 1202f70bbddSSebastian Reichel struct rk_udphy_grf_reg usb3otg0_cfg; 1212f70bbddSSebastian Reichel struct rk_udphy_grf_reg usb3otg1_cfg; 1222f70bbddSSebastian Reichel 1232f70bbddSSebastian Reichel /* usbdpphy-grf */ 1242f70bbddSSebastian Reichel struct rk_udphy_grf_reg low_pwrn; 1252f70bbddSSebastian Reichel struct rk_udphy_grf_reg rx_lfps; 1262f70bbddSSebastian Reichel }; 1272f70bbddSSebastian Reichel 1282f70bbddSSebastian Reichel struct rk_udphy_vogrf_cfg { 1292f70bbddSSebastian Reichel /* vo-grf */ 1302f70bbddSSebastian Reichel struct rk_udphy_grf_reg hpd_trigger; 1312f70bbddSSebastian Reichel u32 dp_lane_reg; 1322f70bbddSSebastian Reichel }; 1332f70bbddSSebastian Reichel 1342f70bbddSSebastian Reichel struct rk_udphy_dp_tx_drv_ctrl { 1352f70bbddSSebastian Reichel u32 trsv_reg0204; 1362f70bbddSSebastian Reichel u32 trsv_reg0205; 1372f70bbddSSebastian Reichel u32 trsv_reg0206; 1382f70bbddSSebastian Reichel u32 trsv_reg0207; 1392f70bbddSSebastian Reichel }; 1402f70bbddSSebastian Reichel 1412f70bbddSSebastian Reichel struct rk_udphy_cfg { 1422f70bbddSSebastian Reichel unsigned int num_phys; 1432f70bbddSSebastian Reichel unsigned int phy_ids[2]; 1442f70bbddSSebastian Reichel /* resets to be requested */ 1452f70bbddSSebastian Reichel const char * const *rst_list; 1462f70bbddSSebastian Reichel int num_rsts; 1472f70bbddSSebastian Reichel 1482f70bbddSSebastian Reichel struct rk_udphy_grf_cfg grfcfg; 1492f70bbddSSebastian Reichel struct rk_udphy_vogrf_cfg vogrfcfg[2]; 1502f70bbddSSebastian Reichel const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; 1512f70bbddSSebastian Reichel const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg_typec[4])[4]; 1522f70bbddSSebastian Reichel }; 1532f70bbddSSebastian Reichel 1542f70bbddSSebastian Reichel struct rk_udphy { 1552f70bbddSSebastian Reichel struct device *dev; 1562f70bbddSSebastian Reichel struct regmap *pma_regmap; 1572f70bbddSSebastian Reichel struct regmap *u2phygrf; 1582f70bbddSSebastian Reichel struct regmap *udphygrf; 1592f70bbddSSebastian Reichel struct regmap *usbgrf; 1602f70bbddSSebastian Reichel struct regmap *vogrf; 1612f70bbddSSebastian Reichel struct typec_switch_dev *sw; 1622f70bbddSSebastian Reichel struct typec_mux_dev *mux; 1632f70bbddSSebastian Reichel struct mutex mutex; /* mutex to protect access to individual PHYs */ 1642f70bbddSSebastian Reichel 1652f70bbddSSebastian Reichel /* clocks and rests */ 1662f70bbddSSebastian Reichel int num_clks; 1672f70bbddSSebastian Reichel struct clk_bulk_data *clks; 1682f70bbddSSebastian Reichel struct clk *refclk; 1692f70bbddSSebastian Reichel int num_rsts; 1702f70bbddSSebastian Reichel struct reset_control_bulk_data *rsts; 1712f70bbddSSebastian Reichel 1722f70bbddSSebastian Reichel /* PHY status management */ 1732f70bbddSSebastian Reichel bool flip; 1742f70bbddSSebastian Reichel bool mode_change; 1752f70bbddSSebastian Reichel u8 mode; 1762f70bbddSSebastian Reichel u8 status; 1772f70bbddSSebastian Reichel 1782f70bbddSSebastian Reichel /* utilized for USB */ 1792f70bbddSSebastian Reichel bool hs; /* flag for high-speed */ 1802f70bbddSSebastian Reichel 1812f70bbddSSebastian Reichel /* utilized for DP */ 1822f70bbddSSebastian Reichel struct gpio_desc *sbu1_dc_gpio; 1832f70bbddSSebastian Reichel struct gpio_desc *sbu2_dc_gpio; 1842f70bbddSSebastian Reichel u32 lane_mux_sel[4]; 1852f70bbddSSebastian Reichel u32 dp_lane_sel[4]; 1862f70bbddSSebastian Reichel u32 dp_aux_dout_sel; 1872f70bbddSSebastian Reichel u32 dp_aux_din_sel; 1882f70bbddSSebastian Reichel bool dp_sink_hpd_sel; 1892f70bbddSSebastian Reichel bool dp_sink_hpd_cfg; 190969a38beSAndy Yan unsigned int link_rate; 191969a38beSAndy Yan unsigned int lanes; 1922f70bbddSSebastian Reichel u8 bw; 1932f70bbddSSebastian Reichel int id; 1942f70bbddSSebastian Reichel 1952f70bbddSSebastian Reichel bool dp_in_use; 1962f70bbddSSebastian Reichel 1972f70bbddSSebastian Reichel /* PHY const config */ 1982f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfgs; 1992f70bbddSSebastian Reichel 2002f70bbddSSebastian Reichel /* PHY devices */ 2012f70bbddSSebastian Reichel struct phy *phy_dp; 2022f70bbddSSebastian Reichel struct phy *phy_u3; 2032f70bbddSSebastian Reichel }; 2042f70bbddSSebastian Reichel 2052f70bbddSSebastian Reichel static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { 2062f70bbddSSebastian Reichel /* voltage swing 0, pre-emphasis 0->3 */ 2072f70bbddSSebastian Reichel { 2082f70bbddSSebastian Reichel { 0x20, 0x10, 0x42, 0xe5 }, 2092f70bbddSSebastian Reichel { 0x26, 0x14, 0x42, 0xe5 }, 2102f70bbddSSebastian Reichel { 0x29, 0x18, 0x42, 0xe5 }, 2112f70bbddSSebastian Reichel { 0x2b, 0x1c, 0x43, 0xe7 }, 2122f70bbddSSebastian Reichel }, 2132f70bbddSSebastian Reichel 2142f70bbddSSebastian Reichel /* voltage swing 1, pre-emphasis 0->2 */ 2152f70bbddSSebastian Reichel { 2162f70bbddSSebastian Reichel { 0x23, 0x10, 0x42, 0xe7 }, 2172f70bbddSSebastian Reichel { 0x2a, 0x17, 0x43, 0xe7 }, 2182f70bbddSSebastian Reichel { 0x2b, 0x1a, 0x43, 0xe7 }, 2192f70bbddSSebastian Reichel }, 2202f70bbddSSebastian Reichel 2212f70bbddSSebastian Reichel /* voltage swing 2, pre-emphasis 0->1 */ 2222f70bbddSSebastian Reichel { 2232f70bbddSSebastian Reichel { 0x27, 0x10, 0x42, 0xe7 }, 2242f70bbddSSebastian Reichel { 0x2b, 0x17, 0x43, 0xe7 }, 2252f70bbddSSebastian Reichel }, 2262f70bbddSSebastian Reichel 2272f70bbddSSebastian Reichel /* voltage swing 3, pre-emphasis 0 */ 2282f70bbddSSebastian Reichel { 2292f70bbddSSebastian Reichel { 0x29, 0x10, 0x43, 0xe7 }, 2302f70bbddSSebastian Reichel }, 2312f70bbddSSebastian Reichel }; 2322f70bbddSSebastian Reichel 2332f70bbddSSebastian Reichel static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr_typec[4][4] = { 2342f70bbddSSebastian Reichel /* voltage swing 0, pre-emphasis 0->3 */ 2352f70bbddSSebastian Reichel { 2362f70bbddSSebastian Reichel { 0x20, 0x10, 0x42, 0xe5 }, 2372f70bbddSSebastian Reichel { 0x26, 0x14, 0x42, 0xe5 }, 2382f70bbddSSebastian Reichel { 0x29, 0x18, 0x42, 0xe5 }, 2392f70bbddSSebastian Reichel { 0x2b, 0x1c, 0x43, 0xe7 }, 2402f70bbddSSebastian Reichel }, 2412f70bbddSSebastian Reichel 2422f70bbddSSebastian Reichel /* voltage swing 1, pre-emphasis 0->2 */ 2432f70bbddSSebastian Reichel { 2442f70bbddSSebastian Reichel { 0x23, 0x10, 0x42, 0xe7 }, 2452f70bbddSSebastian Reichel { 0x2a, 0x17, 0x43, 0xe7 }, 2462f70bbddSSebastian Reichel { 0x2b, 0x1a, 0x43, 0xe7 }, 2472f70bbddSSebastian Reichel }, 2482f70bbddSSebastian Reichel 2492f70bbddSSebastian Reichel /* voltage swing 2, pre-emphasis 0->1 */ 2502f70bbddSSebastian Reichel { 2512f70bbddSSebastian Reichel { 0x27, 0x10, 0x43, 0x67 }, 2522f70bbddSSebastian Reichel { 0x2b, 0x17, 0x43, 0xe7 }, 2532f70bbddSSebastian Reichel }, 2542f70bbddSSebastian Reichel 2552f70bbddSSebastian Reichel /* voltage swing 3, pre-emphasis 0 */ 2562f70bbddSSebastian Reichel { 2572f70bbddSSebastian Reichel { 0x29, 0x10, 0x43, 0xe7 }, 2582f70bbddSSebastian Reichel }, 2592f70bbddSSebastian Reichel }; 2602f70bbddSSebastian Reichel 2612f70bbddSSebastian Reichel static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { 2622f70bbddSSebastian Reichel /* voltage swing 0, pre-emphasis 0->3 */ 2632f70bbddSSebastian Reichel { 2642f70bbddSSebastian Reichel { 0x21, 0x10, 0x42, 0xe5 }, 2652f70bbddSSebastian Reichel { 0x26, 0x14, 0x42, 0xe5 }, 2662f70bbddSSebastian Reichel { 0x26, 0x16, 0x43, 0xe5 }, 2672f70bbddSSebastian Reichel { 0x2a, 0x19, 0x43, 0xe7 }, 2682f70bbddSSebastian Reichel }, 2692f70bbddSSebastian Reichel 2702f70bbddSSebastian Reichel /* voltage swing 1, pre-emphasis 0->2 */ 2712f70bbddSSebastian Reichel { 2722f70bbddSSebastian Reichel { 0x24, 0x10, 0x42, 0xe7 }, 2732f70bbddSSebastian Reichel { 0x2a, 0x17, 0x43, 0xe7 }, 2742f70bbddSSebastian Reichel { 0x2b, 0x1a, 0x43, 0xe7 }, 2752f70bbddSSebastian Reichel }, 2762f70bbddSSebastian Reichel 2772f70bbddSSebastian Reichel /* voltage swing 2, pre-emphasis 0->1 */ 2782f70bbddSSebastian Reichel { 2792f70bbddSSebastian Reichel { 0x28, 0x10, 0x42, 0xe7 }, 2802f70bbddSSebastian Reichel { 0x2b, 0x17, 0x43, 0xe7 }, 2812f70bbddSSebastian Reichel }, 2822f70bbddSSebastian Reichel 2832f70bbddSSebastian Reichel /* voltage swing 3, pre-emphasis 0 */ 2842f70bbddSSebastian Reichel { 2852f70bbddSSebastian Reichel { 0x28, 0x10, 0x43, 0xe7 }, 2862f70bbddSSebastian Reichel }, 2872f70bbddSSebastian Reichel }; 2882f70bbddSSebastian Reichel 2892f70bbddSSebastian Reichel static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { 2902f70bbddSSebastian Reichel /* voltage swing 0, pre-emphasis 0->3 */ 2912f70bbddSSebastian Reichel { 2922f70bbddSSebastian Reichel { 0x21, 0x10, 0x42, 0xe5 }, 2932f70bbddSSebastian Reichel { 0x26, 0x14, 0x42, 0xe5 }, 2942f70bbddSSebastian Reichel { 0x26, 0x16, 0x43, 0xe5 }, 2952f70bbddSSebastian Reichel { 0x29, 0x18, 0x43, 0xe7 }, 2962f70bbddSSebastian Reichel }, 2972f70bbddSSebastian Reichel 2982f70bbddSSebastian Reichel /* voltage swing 1, pre-emphasis 0->2 */ 2992f70bbddSSebastian Reichel { 3002f70bbddSSebastian Reichel { 0x24, 0x10, 0x42, 0xe7 }, 3012f70bbddSSebastian Reichel { 0x2a, 0x18, 0x43, 0xe7 }, 3022f70bbddSSebastian Reichel { 0x2b, 0x1b, 0x43, 0xe7 } 3032f70bbddSSebastian Reichel }, 3042f70bbddSSebastian Reichel 3052f70bbddSSebastian Reichel /* voltage swing 2, pre-emphasis 0->1 */ 3062f70bbddSSebastian Reichel { 3072f70bbddSSebastian Reichel { 0x27, 0x10, 0x42, 0xe7 }, 3082f70bbddSSebastian Reichel { 0x2b, 0x18, 0x43, 0xe7 } 3092f70bbddSSebastian Reichel }, 3102f70bbddSSebastian Reichel 3112f70bbddSSebastian Reichel /* voltage swing 3, pre-emphasis 0 */ 3122f70bbddSSebastian Reichel { 3132f70bbddSSebastian Reichel { 0x28, 0x10, 0x43, 0xe7 }, 3142f70bbddSSebastian Reichel }, 3152f70bbddSSebastian Reichel }; 3162f70bbddSSebastian Reichel 3172f70bbddSSebastian Reichel static const struct reg_sequence rk_udphy_24m_refclk_cfg[] = { 3182f70bbddSSebastian Reichel {0x0090, 0x68}, {0x0094, 0x68}, 3192f70bbddSSebastian Reichel {0x0128, 0x24}, {0x012c, 0x44}, 3202f70bbddSSebastian Reichel {0x0130, 0x3f}, {0x0134, 0x44}, 3212f70bbddSSebastian Reichel {0x015c, 0xa9}, {0x0160, 0x71}, 3222f70bbddSSebastian Reichel {0x0164, 0x71}, {0x0168, 0xa9}, 3232f70bbddSSebastian Reichel {0x0174, 0xa9}, {0x0178, 0x71}, 3242f70bbddSSebastian Reichel {0x017c, 0x71}, {0x0180, 0xa9}, 3252f70bbddSSebastian Reichel {0x018c, 0x41}, {0x0190, 0x00}, 3262f70bbddSSebastian Reichel {0x0194, 0x05}, {0x01ac, 0x2a}, 3272f70bbddSSebastian Reichel {0x01b0, 0x17}, {0x01b4, 0x17}, 3282f70bbddSSebastian Reichel {0x01b8, 0x2a}, {0x01c8, 0x04}, 3292f70bbddSSebastian Reichel {0x01cc, 0x08}, {0x01d0, 0x08}, 3302f70bbddSSebastian Reichel {0x01d4, 0x04}, {0x01d8, 0x20}, 3312f70bbddSSebastian Reichel {0x01dc, 0x01}, {0x01e0, 0x09}, 3322f70bbddSSebastian Reichel {0x01e4, 0x03}, {0x01f0, 0x29}, 3332f70bbddSSebastian Reichel {0x01f4, 0x02}, {0x01f8, 0x02}, 3342f70bbddSSebastian Reichel {0x01fc, 0x29}, {0x0208, 0x2a}, 3352f70bbddSSebastian Reichel {0x020c, 0x17}, {0x0210, 0x17}, 3362f70bbddSSebastian Reichel {0x0214, 0x2a}, {0x0224, 0x20}, 3372f70bbddSSebastian Reichel {0x03f0, 0x0a}, {0x03f4, 0x07}, 3382f70bbddSSebastian Reichel {0x03f8, 0x07}, {0x03fc, 0x0c}, 3392f70bbddSSebastian Reichel {0x0404, 0x12}, {0x0408, 0x1a}, 3402f70bbddSSebastian Reichel {0x040c, 0x1a}, {0x0410, 0x3f}, 3412f70bbddSSebastian Reichel {0x0ce0, 0x68}, {0x0ce8, 0xd0}, 3422f70bbddSSebastian Reichel {0x0cf0, 0x87}, {0x0cf8, 0x70}, 3432f70bbddSSebastian Reichel {0x0d00, 0x70}, {0x0d08, 0xa9}, 3442f70bbddSSebastian Reichel {0x1ce0, 0x68}, {0x1ce8, 0xd0}, 3452f70bbddSSebastian Reichel {0x1cf0, 0x87}, {0x1cf8, 0x70}, 3462f70bbddSSebastian Reichel {0x1d00, 0x70}, {0x1d08, 0xa9}, 3472f70bbddSSebastian Reichel {0x0a3c, 0xd0}, {0x0a44, 0xd0}, 3482f70bbddSSebastian Reichel {0x0a48, 0x01}, {0x0a4c, 0x0d}, 3492f70bbddSSebastian Reichel {0x0a54, 0xe0}, {0x0a5c, 0xe0}, 3502f70bbddSSebastian Reichel {0x0a64, 0xa8}, {0x1a3c, 0xd0}, 3512f70bbddSSebastian Reichel {0x1a44, 0xd0}, {0x1a48, 0x01}, 3522f70bbddSSebastian Reichel {0x1a4c, 0x0d}, {0x1a54, 0xe0}, 3532f70bbddSSebastian Reichel {0x1a5c, 0xe0}, {0x1a64, 0xa8} 3542f70bbddSSebastian Reichel }; 3552f70bbddSSebastian Reichel 3562f70bbddSSebastian Reichel static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = { 3572f70bbddSSebastian Reichel {0x0830, 0x07}, {0x085c, 0x80}, 3582f70bbddSSebastian Reichel {0x1030, 0x07}, {0x105c, 0x80}, 3592f70bbddSSebastian Reichel {0x1830, 0x07}, {0x185c, 0x80}, 3602f70bbddSSebastian Reichel {0x2030, 0x07}, {0x205c, 0x80}, 3612f70bbddSSebastian Reichel {0x0228, 0x38}, {0x0104, 0x44}, 3622f70bbddSSebastian Reichel {0x0248, 0x44}, {0x038c, 0x02}, 3632f70bbddSSebastian Reichel {0x0878, 0x04}, {0x1878, 0x04}, 3642f70bbddSSebastian Reichel {0x0898, 0x77}, {0x1898, 0x77}, 3652f70bbddSSebastian Reichel {0x0054, 0x01}, {0x00e0, 0x38}, 3662f70bbddSSebastian Reichel {0x0060, 0x24}, {0x0064, 0x77}, 3672f70bbddSSebastian Reichel {0x0070, 0x76}, {0x0234, 0xe8}, 3682f70bbddSSebastian Reichel {0x0af4, 0x15}, {0x1af4, 0x15}, 3692f70bbddSSebastian Reichel {0x081c, 0xe5}, {0x181c, 0xe5}, 3702f70bbddSSebastian Reichel {0x099c, 0x48}, {0x199c, 0x48}, 3712f70bbddSSebastian Reichel {0x09a4, 0x07}, {0x09a8, 0x22}, 3722f70bbddSSebastian Reichel {0x19a4, 0x07}, {0x19a8, 0x22}, 3732f70bbddSSebastian Reichel {0x09b8, 0x3e}, {0x19b8, 0x3e}, 3742f70bbddSSebastian Reichel {0x09e4, 0x02}, {0x19e4, 0x02}, 3752f70bbddSSebastian Reichel {0x0a34, 0x1e}, {0x1a34, 0x1e}, 3762f70bbddSSebastian Reichel {0x0a98, 0x2f}, {0x1a98, 0x2f}, 3772f70bbddSSebastian Reichel {0x0c30, 0x0e}, {0x0c48, 0x06}, 3782f70bbddSSebastian Reichel {0x1c30, 0x0e}, {0x1c48, 0x06}, 3792f70bbddSSebastian Reichel {0x028c, 0x18}, {0x0af0, 0x00}, 3802f70bbddSSebastian Reichel {0x1af0, 0x00} 3812f70bbddSSebastian Reichel }; 3822f70bbddSSebastian Reichel 3832f70bbddSSebastian Reichel static const struct reg_sequence rk_udphy_init_sequence[] = { 3842f70bbddSSebastian Reichel {0x0104, 0x44}, {0x0234, 0xe8}, 3852f70bbddSSebastian Reichel {0x0248, 0x44}, {0x028c, 0x18}, 3862f70bbddSSebastian Reichel {0x081c, 0xe5}, {0x0878, 0x00}, 3872f70bbddSSebastian Reichel {0x0994, 0x1c}, {0x0af0, 0x00}, 3882f70bbddSSebastian Reichel {0x181c, 0xe5}, {0x1878, 0x00}, 3892f70bbddSSebastian Reichel {0x1994, 0x1c}, {0x1af0, 0x00}, 3902f70bbddSSebastian Reichel {0x0428, 0x60}, {0x0d58, 0x33}, 3912f70bbddSSebastian Reichel {0x1d58, 0x33}, {0x0990, 0x74}, 3922f70bbddSSebastian Reichel {0x0d64, 0x17}, {0x08c8, 0x13}, 3932f70bbddSSebastian Reichel {0x1990, 0x74}, {0x1d64, 0x17}, 3942f70bbddSSebastian Reichel {0x18c8, 0x13}, {0x0d90, 0x40}, 3952f70bbddSSebastian Reichel {0x0da8, 0x40}, {0x0dc0, 0x40}, 3962f70bbddSSebastian Reichel {0x0dd8, 0x40}, {0x1d90, 0x40}, 3972f70bbddSSebastian Reichel {0x1da8, 0x40}, {0x1dc0, 0x40}, 3982f70bbddSSebastian Reichel {0x1dd8, 0x40}, {0x03c0, 0x30}, 3992f70bbddSSebastian Reichel {0x03c4, 0x06}, {0x0e10, 0x00}, 4002f70bbddSSebastian Reichel {0x1e10, 0x00}, {0x043c, 0x0f}, 4012f70bbddSSebastian Reichel {0x0d2c, 0xff}, {0x1d2c, 0xff}, 4022f70bbddSSebastian Reichel {0x0d34, 0x0f}, {0x1d34, 0x0f}, 4032f70bbddSSebastian Reichel {0x08fc, 0x2a}, {0x0914, 0x28}, 4042f70bbddSSebastian Reichel {0x0a30, 0x03}, {0x0e38, 0x03}, 4052f70bbddSSebastian Reichel {0x0ecc, 0x27}, {0x0ed0, 0x22}, 4062f70bbddSSebastian Reichel {0x0ed4, 0x26}, {0x18fc, 0x2a}, 4072f70bbddSSebastian Reichel {0x1914, 0x28}, {0x1a30, 0x03}, 4082f70bbddSSebastian Reichel {0x1e38, 0x03}, {0x1ecc, 0x27}, 4092f70bbddSSebastian Reichel {0x1ed0, 0x22}, {0x1ed4, 0x26}, 4102f70bbddSSebastian Reichel {0x0048, 0x0f}, {0x0060, 0x3c}, 4112f70bbddSSebastian Reichel {0x0064, 0xf7}, {0x006c, 0x20}, 4122f70bbddSSebastian Reichel {0x0070, 0x7d}, {0x0074, 0x68}, 4132f70bbddSSebastian Reichel {0x0af4, 0x1a}, {0x1af4, 0x1a}, 4142f70bbddSSebastian Reichel {0x0440, 0x3f}, {0x10d4, 0x08}, 4152f70bbddSSebastian Reichel {0x20d4, 0x08}, {0x00d4, 0x30}, 4162f70bbddSSebastian Reichel {0x0024, 0x6e}, 4172f70bbddSSebastian Reichel }; 4182f70bbddSSebastian Reichel 4192f70bbddSSebastian Reichel static inline int rk_udphy_grfreg_write(struct regmap *base, 4202f70bbddSSebastian Reichel const struct rk_udphy_grf_reg *reg, bool en) 4212f70bbddSSebastian Reichel { 4222f70bbddSSebastian Reichel return regmap_write(base, reg->offset, en ? reg->enable : reg->disable); 4232f70bbddSSebastian Reichel } 4242f70bbddSSebastian Reichel 4252f70bbddSSebastian Reichel static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev) 4262f70bbddSSebastian Reichel { 4272f70bbddSSebastian Reichel int i; 4282f70bbddSSebastian Reichel 4292f70bbddSSebastian Reichel udphy->num_clks = devm_clk_bulk_get_all(dev, &udphy->clks); 4302f70bbddSSebastian Reichel if (udphy->num_clks < 1) 4312f70bbddSSebastian Reichel return -ENODEV; 4322f70bbddSSebastian Reichel 4332f70bbddSSebastian Reichel /* used for configure phy reference clock frequency */ 4342f70bbddSSebastian Reichel for (i = 0; i < udphy->num_clks; i++) { 4352f70bbddSSebastian Reichel if (!strncmp(udphy->clks[i].id, "refclk", 6)) { 4362f70bbddSSebastian Reichel udphy->refclk = udphy->clks[i].clk; 4372f70bbddSSebastian Reichel break; 4382f70bbddSSebastian Reichel } 4392f70bbddSSebastian Reichel } 4402f70bbddSSebastian Reichel 4412f70bbddSSebastian Reichel if (!udphy->refclk) 4422f70bbddSSebastian Reichel return dev_err_probe(udphy->dev, -EINVAL, "no refclk found\n"); 4432f70bbddSSebastian Reichel 4442f70bbddSSebastian Reichel return 0; 4452f70bbddSSebastian Reichel } 4462f70bbddSSebastian Reichel 4472f70bbddSSebastian Reichel static int rk_udphy_reset_assert_all(struct rk_udphy *udphy) 4482f70bbddSSebastian Reichel { 4492f70bbddSSebastian Reichel return reset_control_bulk_assert(udphy->num_rsts, udphy->rsts); 4502f70bbddSSebastian Reichel } 4512f70bbddSSebastian Reichel 4522f70bbddSSebastian Reichel static int rk_udphy_reset_deassert_all(struct rk_udphy *udphy) 4532f70bbddSSebastian Reichel { 4542f70bbddSSebastian Reichel return reset_control_bulk_deassert(udphy->num_rsts, udphy->rsts); 4552f70bbddSSebastian Reichel } 4562f70bbddSSebastian Reichel 4572f70bbddSSebastian Reichel static int rk_udphy_reset_deassert(struct rk_udphy *udphy, char *name) 4582f70bbddSSebastian Reichel { 4592f70bbddSSebastian Reichel struct reset_control_bulk_data *list = udphy->rsts; 4602f70bbddSSebastian Reichel int idx; 4612f70bbddSSebastian Reichel 4622f70bbddSSebastian Reichel for (idx = 0; idx < udphy->num_rsts; idx++) { 4632f70bbddSSebastian Reichel if (!strcmp(list[idx].id, name)) 4642f70bbddSSebastian Reichel return reset_control_deassert(list[idx].rstc); 4652f70bbddSSebastian Reichel } 4662f70bbddSSebastian Reichel 4672f70bbddSSebastian Reichel return -EINVAL; 4682f70bbddSSebastian Reichel } 4692f70bbddSSebastian Reichel 4702f70bbddSSebastian Reichel static int rk_udphy_reset_init(struct rk_udphy *udphy, struct device *dev) 4712f70bbddSSebastian Reichel { 4722f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 4732f70bbddSSebastian Reichel int idx; 4742f70bbddSSebastian Reichel 4752f70bbddSSebastian Reichel udphy->num_rsts = cfg->num_rsts; 4762f70bbddSSebastian Reichel udphy->rsts = devm_kcalloc(dev, udphy->num_rsts, 4772f70bbddSSebastian Reichel sizeof(*udphy->rsts), GFP_KERNEL); 4782f70bbddSSebastian Reichel if (!udphy->rsts) 4792f70bbddSSebastian Reichel return -ENOMEM; 4802f70bbddSSebastian Reichel 4812f70bbddSSebastian Reichel for (idx = 0; idx < cfg->num_rsts; idx++) 4822f70bbddSSebastian Reichel udphy->rsts[idx].id = cfg->rst_list[idx]; 4832f70bbddSSebastian Reichel 4842f70bbddSSebastian Reichel return devm_reset_control_bulk_get_exclusive(dev, cfg->num_rsts, 4852f70bbddSSebastian Reichel udphy->rsts); 4862f70bbddSSebastian Reichel } 4872f70bbddSSebastian Reichel 4882f70bbddSSebastian Reichel static void rk_udphy_u3_port_disable(struct rk_udphy *udphy, u8 disable) 4892f70bbddSSebastian Reichel { 4902f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 4912f70bbddSSebastian Reichel const struct rk_udphy_grf_reg *preg; 4922f70bbddSSebastian Reichel 4932f70bbddSSebastian Reichel preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; 4942f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->usbgrf, preg, disable); 4952f70bbddSSebastian Reichel } 4962f70bbddSSebastian Reichel 4972f70bbddSSebastian Reichel static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable) 4982f70bbddSSebastian Reichel { 4992f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 5002f70bbddSSebastian Reichel 5012f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); 5022f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); 5032f70bbddSSebastian Reichel } 5042f70bbddSSebastian Reichel 5052f70bbddSSebastian Reichel /* 5062f70bbddSSebastian Reichel * In usb/dp combo phy driver, here are 2 ways to mapping lanes. 5072f70bbddSSebastian Reichel * 5082f70bbddSSebastian Reichel * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) 5092f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5102f70bbddSSebastian Reichel * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 5112f70bbddSSebastian Reichel * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 5122f70bbddSSebastian Reichel * C/E(Normal) dpln3 dpln2 dpln0 dpln1 5132f70bbddSSebastian Reichel * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 5142f70bbddSSebastian Reichel * D/F(Normal) usbrx usbtx dpln0 dpln1 5152f70bbddSSebastian Reichel * D/F(Flip ) dpln0 dpln1 usbrx usbtx 5162f70bbddSSebastian Reichel * A(Normal ) dpln3 dpln1 dpln2 dpln0 5172f70bbddSSebastian Reichel * A(Flip ) dpln2 dpln0 dpln3 dpln1 5182f70bbddSSebastian Reichel * B(Normal ) usbrx usbtx dpln1 dpln0 5192f70bbddSSebastian Reichel * B(Flip ) dpln1 dpln0 usbrx usbtx 5202f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5212f70bbddSSebastian Reichel * 5222f70bbddSSebastian Reichel * 2 Mapping the lanes in dtsi 5232f70bbddSSebastian Reichel * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = <x x x x>; 5242f70bbddSSebastian Reichel * sample as follow: 5252f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5262f70bbddSSebastian Reichel * B11-B10 A2-A3 A11-A10 B2-B3 5272f70bbddSSebastian Reichel * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 5282f70bbddSSebastian Reichel * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 5292f70bbddSSebastian Reichel * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 5302f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5312f70bbddSSebastian Reichel * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x x>; 5322f70bbddSSebastian Reichel * sample as follow: 5332f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5342f70bbddSSebastian Reichel * B11-B10 A2-A3 A11-A10 B2-B3 5352f70bbddSSebastian Reichel * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 5362f70bbddSSebastian Reichel * <0 1> dpln0 dpln1 usbrx usbtx 5372f70bbddSSebastian Reichel * <2 3> usbrx usbtx dpln0 dpln1 5382f70bbddSSebastian Reichel * --------------------------------------------------------------------------- 5392f70bbddSSebastian Reichel */ 5402f70bbddSSebastian Reichel 5412f70bbddSSebastian Reichel static void rk_udphy_dplane_select(struct rk_udphy *udphy) 5422f70bbddSSebastian Reichel { 5432f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 5442f70bbddSSebastian Reichel u32 value = 0; 5452f70bbddSSebastian Reichel 5462f70bbddSSebastian Reichel switch (udphy->mode) { 5472f70bbddSSebastian Reichel case UDPHY_MODE_DP: 5482f70bbddSSebastian Reichel value |= 2 << udphy->dp_lane_sel[2] * 2; 5492f70bbddSSebastian Reichel value |= 3 << udphy->dp_lane_sel[3] * 2; 5502f70bbddSSebastian Reichel fallthrough; 5512f70bbddSSebastian Reichel 5522f70bbddSSebastian Reichel case UDPHY_MODE_DP_USB: 5532f70bbddSSebastian Reichel value |= 0 << udphy->dp_lane_sel[0] * 2; 5542f70bbddSSebastian Reichel value |= 1 << udphy->dp_lane_sel[1] * 2; 5552f70bbddSSebastian Reichel break; 5562f70bbddSSebastian Reichel 5572f70bbddSSebastian Reichel case UDPHY_MODE_USB: 5582f70bbddSSebastian Reichel break; 5592f70bbddSSebastian Reichel 5602f70bbddSSebastian Reichel default: 5612f70bbddSSebastian Reichel break; 5622f70bbddSSebastian Reichel } 5632f70bbddSSebastian Reichel 5642f70bbddSSebastian Reichel regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, 5652f70bbddSSebastian Reichel ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | 5662f70bbddSSebastian Reichel FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | 5672f70bbddSSebastian Reichel FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); 5682f70bbddSSebastian Reichel } 5692f70bbddSSebastian Reichel 5702f70bbddSSebastian Reichel static int rk_udphy_dplane_get(struct rk_udphy *udphy) 5712f70bbddSSebastian Reichel { 5722f70bbddSSebastian Reichel int dp_lanes; 5732f70bbddSSebastian Reichel 5742f70bbddSSebastian Reichel switch (udphy->mode) { 5752f70bbddSSebastian Reichel case UDPHY_MODE_DP: 5762f70bbddSSebastian Reichel dp_lanes = 4; 5772f70bbddSSebastian Reichel break; 5782f70bbddSSebastian Reichel 5792f70bbddSSebastian Reichel case UDPHY_MODE_DP_USB: 5802f70bbddSSebastian Reichel dp_lanes = 2; 5812f70bbddSSebastian Reichel break; 5822f70bbddSSebastian Reichel 5832f70bbddSSebastian Reichel case UDPHY_MODE_USB: 5842f70bbddSSebastian Reichel default: 5852f70bbddSSebastian Reichel dp_lanes = 0; 5862f70bbddSSebastian Reichel break; 5872f70bbddSSebastian Reichel } 5882f70bbddSSebastian Reichel 5892f70bbddSSebastian Reichel return dp_lanes; 5902f70bbddSSebastian Reichel } 5912f70bbddSSebastian Reichel 5922f70bbddSSebastian Reichel static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes) 5932f70bbddSSebastian Reichel { 5942f70bbddSSebastian Reichel u32 val = 0; 5952f70bbddSSebastian Reichel int i; 5962f70bbddSSebastian Reichel 5972f70bbddSSebastian Reichel for (i = 0; i < dp_lanes; i++) 5982f70bbddSSebastian Reichel val |= BIT(udphy->dp_lane_sel[i]); 5992f70bbddSSebastian Reichel 6002f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, 6012f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); 6022f70bbddSSebastian Reichel 6032f70bbddSSebastian Reichel if (!dp_lanes) 6042f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 6052f70bbddSSebastian Reichel CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); 6062f70bbddSSebastian Reichel } 6072f70bbddSSebastian Reichel 6082f70bbddSSebastian Reichel static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd) 6092f70bbddSSebastian Reichel { 6102f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 6112f70bbddSSebastian Reichel 6122f70bbddSSebastian Reichel udphy->dp_sink_hpd_sel = true; 6132f70bbddSSebastian Reichel udphy->dp_sink_hpd_cfg = hpd; 6142f70bbddSSebastian Reichel 6152f70bbddSSebastian Reichel if (!udphy->dp_in_use) 6162f70bbddSSebastian Reichel return; 6172f70bbddSSebastian Reichel 6182f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); 6192f70bbddSSebastian Reichel } 6202f70bbddSSebastian Reichel 6212f70bbddSSebastian Reichel static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy) 6222f70bbddSSebastian Reichel { 6232f70bbddSSebastian Reichel if (udphy->flip) { 6242f70bbddSSebastian Reichel udphy->dp_lane_sel[0] = 0; 6252f70bbddSSebastian Reichel udphy->dp_lane_sel[1] = 1; 6262f70bbddSSebastian Reichel udphy->dp_lane_sel[2] = 3; 6272f70bbddSSebastian Reichel udphy->dp_lane_sel[3] = 2; 6282f70bbddSSebastian Reichel udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; 6292f70bbddSSebastian Reichel udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; 6302f70bbddSSebastian Reichel udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; 6312f70bbddSSebastian Reichel udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; 6322f70bbddSSebastian Reichel udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; 6332f70bbddSSebastian Reichel udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; 6342f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1); 6352f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); 6362f70bbddSSebastian Reichel } else { 6372f70bbddSSebastian Reichel udphy->dp_lane_sel[0] = 2; 6382f70bbddSSebastian Reichel udphy->dp_lane_sel[1] = 3; 6392f70bbddSSebastian Reichel udphy->dp_lane_sel[2] = 1; 6402f70bbddSSebastian Reichel udphy->dp_lane_sel[3] = 0; 6412f70bbddSSebastian Reichel udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; 6422f70bbddSSebastian Reichel udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; 6432f70bbddSSebastian Reichel udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; 6442f70bbddSSebastian Reichel udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; 6452f70bbddSSebastian Reichel udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; 6462f70bbddSSebastian Reichel udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; 6472f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); 6482f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1); 6492f70bbddSSebastian Reichel } 6502f70bbddSSebastian Reichel 6512f70bbddSSebastian Reichel udphy->mode = UDPHY_MODE_DP_USB; 6522f70bbddSSebastian Reichel } 6532f70bbddSSebastian Reichel 6542f70bbddSSebastian Reichel static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw, 6552f70bbddSSebastian Reichel enum typec_orientation orien) 6562f70bbddSSebastian Reichel { 6572f70bbddSSebastian Reichel struct rk_udphy *udphy = typec_switch_get_drvdata(sw); 6582f70bbddSSebastian Reichel 6592f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 6602f70bbddSSebastian Reichel 6612f70bbddSSebastian Reichel if (orien == TYPEC_ORIENTATION_NONE) { 6622f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); 6632f70bbddSSebastian Reichel gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); 6642f70bbddSSebastian Reichel /* unattached */ 6652f70bbddSSebastian Reichel rk_udphy_usb_bvalid_enable(udphy, false); 6662f70bbddSSebastian Reichel goto unlock_ret; 6672f70bbddSSebastian Reichel } 6682f70bbddSSebastian Reichel 6692f70bbddSSebastian Reichel udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; 6702f70bbddSSebastian Reichel rk_udphy_set_typec_default_mapping(udphy); 6712f70bbddSSebastian Reichel rk_udphy_usb_bvalid_enable(udphy, true); 6722f70bbddSSebastian Reichel 6732f70bbddSSebastian Reichel unlock_ret: 6742f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 6752f70bbddSSebastian Reichel return 0; 6762f70bbddSSebastian Reichel } 6772f70bbddSSebastian Reichel 6782f70bbddSSebastian Reichel static void rk_udphy_orien_switch_unregister(void *data) 6792f70bbddSSebastian Reichel { 6802f70bbddSSebastian Reichel struct rk_udphy *udphy = data; 6812f70bbddSSebastian Reichel 6822f70bbddSSebastian Reichel typec_switch_unregister(udphy->sw); 6832f70bbddSSebastian Reichel } 6842f70bbddSSebastian Reichel 6852f70bbddSSebastian Reichel static int rk_udphy_setup_orien_switch(struct rk_udphy *udphy) 6862f70bbddSSebastian Reichel { 6872f70bbddSSebastian Reichel struct typec_switch_desc sw_desc = { }; 6882f70bbddSSebastian Reichel 6892f70bbddSSebastian Reichel sw_desc.drvdata = udphy; 6902f70bbddSSebastian Reichel sw_desc.fwnode = dev_fwnode(udphy->dev); 6912f70bbddSSebastian Reichel sw_desc.set = rk_udphy_orien_sw_set; 6922f70bbddSSebastian Reichel 6932f70bbddSSebastian Reichel udphy->sw = typec_switch_register(udphy->dev, &sw_desc); 6942f70bbddSSebastian Reichel if (IS_ERR(udphy->sw)) { 6952f70bbddSSebastian Reichel dev_err(udphy->dev, "Error register typec orientation switch: %ld\n", 6962f70bbddSSebastian Reichel PTR_ERR(udphy->sw)); 6972f70bbddSSebastian Reichel return PTR_ERR(udphy->sw); 6982f70bbddSSebastian Reichel } 6992f70bbddSSebastian Reichel 7002f70bbddSSebastian Reichel return devm_add_action_or_reset(udphy->dev, 7012f70bbddSSebastian Reichel rk_udphy_orien_switch_unregister, udphy); 7022f70bbddSSebastian Reichel } 7032f70bbddSSebastian Reichel 7042f70bbddSSebastian Reichel static int rk_udphy_refclk_set(struct rk_udphy *udphy) 7052f70bbddSSebastian Reichel { 7062f70bbddSSebastian Reichel unsigned long rate; 7072f70bbddSSebastian Reichel int ret; 7082f70bbddSSebastian Reichel 7092f70bbddSSebastian Reichel /* configure phy reference clock */ 7102f70bbddSSebastian Reichel rate = clk_get_rate(udphy->refclk); 7112f70bbddSSebastian Reichel dev_dbg(udphy->dev, "refclk freq %ld\n", rate); 7122f70bbddSSebastian Reichel 7132f70bbddSSebastian Reichel switch (rate) { 7142f70bbddSSebastian Reichel case 24000000: 7152f70bbddSSebastian Reichel ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_24m_refclk_cfg, 7162f70bbddSSebastian Reichel ARRAY_SIZE(rk_udphy_24m_refclk_cfg)); 7172f70bbddSSebastian Reichel if (ret) 7182f70bbddSSebastian Reichel return ret; 7192f70bbddSSebastian Reichel break; 7202f70bbddSSebastian Reichel 7212f70bbddSSebastian Reichel case 26000000: 7222f70bbddSSebastian Reichel /* register default is 26MHz */ 7232f70bbddSSebastian Reichel ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_26m_refclk_cfg, 7242f70bbddSSebastian Reichel ARRAY_SIZE(rk_udphy_26m_refclk_cfg)); 7252f70bbddSSebastian Reichel if (ret) 7262f70bbddSSebastian Reichel return ret; 7272f70bbddSSebastian Reichel break; 7282f70bbddSSebastian Reichel 7292f70bbddSSebastian Reichel default: 7302f70bbddSSebastian Reichel dev_err(udphy->dev, "unsupported refclk freq %ld\n", rate); 7312f70bbddSSebastian Reichel return -EINVAL; 7322f70bbddSSebastian Reichel } 7332f70bbddSSebastian Reichel 7342f70bbddSSebastian Reichel return 0; 7352f70bbddSSebastian Reichel } 7362f70bbddSSebastian Reichel 7372f70bbddSSebastian Reichel static int rk_udphy_status_check(struct rk_udphy *udphy) 7382f70bbddSSebastian Reichel { 7392f70bbddSSebastian Reichel unsigned int val; 7402f70bbddSSebastian Reichel int ret; 7412f70bbddSSebastian Reichel 7422f70bbddSSebastian Reichel /* LCPLL check */ 7432f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_USB) { 7442f70bbddSSebastian Reichel ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, 7452f70bbddSSebastian Reichel val, (val & CMN_ANA_LCPLL_AFC_DONE) && 7462f70bbddSSebastian Reichel (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000); 7472f70bbddSSebastian Reichel if (ret) { 7482f70bbddSSebastian Reichel dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); 7492f70bbddSSebastian Reichel /* 7502f70bbddSSebastian Reichel * If earlier software (U-Boot) enabled USB once already 7512f70bbddSSebastian Reichel * the PLL may have problems locking on the first try. 7522f70bbddSSebastian Reichel * It will be successful on the second try, so for the 7532f70bbddSSebastian Reichel * time being a -EPROBE_DEFER will solve the issue. 7542f70bbddSSebastian Reichel * 7552f70bbddSSebastian Reichel * This requires further investigation to understand the 7562f70bbddSSebastian Reichel * root cause, especially considering that the driver is 7572f70bbddSSebastian Reichel * asserting all reset lines at probe time. 7582f70bbddSSebastian Reichel */ 7592f70bbddSSebastian Reichel return -EPROBE_DEFER; 7602f70bbddSSebastian Reichel } 7612f70bbddSSebastian Reichel 7622f70bbddSSebastian Reichel if (!udphy->flip) { 7632f70bbddSSebastian Reichel ret = regmap_read_poll_timeout(udphy->pma_regmap, 7642f70bbddSSebastian Reichel TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, 7652f70bbddSSebastian Reichel val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, 7662f70bbddSSebastian Reichel 200, 100000); 7672f70bbddSSebastian Reichel if (ret) 7682f70bbddSSebastian Reichel dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); 7692f70bbddSSebastian Reichel } else { 7702f70bbddSSebastian Reichel ret = regmap_read_poll_timeout(udphy->pma_regmap, 7712f70bbddSSebastian Reichel TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, 7722f70bbddSSebastian Reichel val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, 7732f70bbddSSebastian Reichel 200, 100000); 7742f70bbddSSebastian Reichel if (ret) 7752f70bbddSSebastian Reichel dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); 7762f70bbddSSebastian Reichel } 7772f70bbddSSebastian Reichel } 7782f70bbddSSebastian Reichel 7792f70bbddSSebastian Reichel return 0; 7802f70bbddSSebastian Reichel } 7812f70bbddSSebastian Reichel 7822f70bbddSSebastian Reichel static int rk_udphy_init(struct rk_udphy *udphy) 7832f70bbddSSebastian Reichel { 7842f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 7852f70bbddSSebastian Reichel int ret; 7862f70bbddSSebastian Reichel 7872f70bbddSSebastian Reichel rk_udphy_reset_assert_all(udphy); 7882f70bbddSSebastian Reichel usleep_range(10000, 11000); 7892f70bbddSSebastian Reichel 7902f70bbddSSebastian Reichel /* enable rx lfps for usb */ 7912f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_USB) 7922f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); 7932f70bbddSSebastian Reichel 7942f70bbddSSebastian Reichel /* Step 1: power on pma and deassert apb rstn */ 7952f70bbddSSebastian Reichel rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); 7962f70bbddSSebastian Reichel 7972f70bbddSSebastian Reichel rk_udphy_reset_deassert(udphy, "pma_apb"); 7982f70bbddSSebastian Reichel rk_udphy_reset_deassert(udphy, "pcs_apb"); 7992f70bbddSSebastian Reichel 8002f70bbddSSebastian Reichel /* Step 2: set init sequence and phy refclk */ 8012f70bbddSSebastian Reichel ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_init_sequence, 8022f70bbddSSebastian Reichel ARRAY_SIZE(rk_udphy_init_sequence)); 8032f70bbddSSebastian Reichel if (ret) { 8042f70bbddSSebastian Reichel dev_err(udphy->dev, "init sequence set error %d\n", ret); 8052f70bbddSSebastian Reichel goto assert_resets; 8062f70bbddSSebastian Reichel } 8072f70bbddSSebastian Reichel 8082f70bbddSSebastian Reichel ret = rk_udphy_refclk_set(udphy); 8092f70bbddSSebastian Reichel if (ret) { 8102f70bbddSSebastian Reichel dev_err(udphy->dev, "refclk set error %d\n", ret); 8112f70bbddSSebastian Reichel goto assert_resets; 8122f70bbddSSebastian Reichel } 8132f70bbddSSebastian Reichel 8142f70bbddSSebastian Reichel /* Step 3: configure lane mux */ 8152f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, 8162f70bbddSSebastian Reichel CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, 8172f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | 8182f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | 8192f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | 8202f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | 8212f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); 8222f70bbddSSebastian Reichel 8232f70bbddSSebastian Reichel /* Step 4: deassert init rstn and wait for 200ns from datasheet */ 8242f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_USB) 8252f70bbddSSebastian Reichel rk_udphy_reset_deassert(udphy, "init"); 8262f70bbddSSebastian Reichel 8272f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_DP) { 8282f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 8292f70bbddSSebastian Reichel CMN_DP_INIT_RSTN, 8302f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); 8312f70bbddSSebastian Reichel } 8322f70bbddSSebastian Reichel 8332f70bbddSSebastian Reichel udelay(1); 8342f70bbddSSebastian Reichel 8352f70bbddSSebastian Reichel /* Step 5: deassert cmn/lane rstn */ 8362f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_USB) { 8372f70bbddSSebastian Reichel rk_udphy_reset_deassert(udphy, "cmn"); 8382f70bbddSSebastian Reichel rk_udphy_reset_deassert(udphy, "lane"); 8392f70bbddSSebastian Reichel } 8402f70bbddSSebastian Reichel 8412f70bbddSSebastian Reichel /* Step 6: wait for lock done of pll */ 8422f70bbddSSebastian Reichel ret = rk_udphy_status_check(udphy); 8432f70bbddSSebastian Reichel if (ret) 8442f70bbddSSebastian Reichel goto assert_resets; 8452f70bbddSSebastian Reichel 8462f70bbddSSebastian Reichel return 0; 8472f70bbddSSebastian Reichel 8482f70bbddSSebastian Reichel assert_resets: 8492f70bbddSSebastian Reichel rk_udphy_reset_assert_all(udphy); 8502f70bbddSSebastian Reichel return ret; 8512f70bbddSSebastian Reichel } 8522f70bbddSSebastian Reichel 8532f70bbddSSebastian Reichel static int rk_udphy_setup(struct rk_udphy *udphy) 8542f70bbddSSebastian Reichel { 8552f70bbddSSebastian Reichel int ret; 8562f70bbddSSebastian Reichel 8572f70bbddSSebastian Reichel ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); 8582f70bbddSSebastian Reichel if (ret) { 8592f70bbddSSebastian Reichel dev_err(udphy->dev, "failed to enable clk\n"); 8602f70bbddSSebastian Reichel return ret; 8612f70bbddSSebastian Reichel } 8622f70bbddSSebastian Reichel 8632f70bbddSSebastian Reichel ret = rk_udphy_init(udphy); 8642f70bbddSSebastian Reichel if (ret) { 8652f70bbddSSebastian Reichel dev_err(udphy->dev, "failed to init combophy\n"); 8662f70bbddSSebastian Reichel clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); 8672f70bbddSSebastian Reichel return ret; 8682f70bbddSSebastian Reichel } 8692f70bbddSSebastian Reichel 8702f70bbddSSebastian Reichel return 0; 8712f70bbddSSebastian Reichel } 8722f70bbddSSebastian Reichel 8732f70bbddSSebastian Reichel static void rk_udphy_disable(struct rk_udphy *udphy) 8742f70bbddSSebastian Reichel { 8752f70bbddSSebastian Reichel clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); 8762f70bbddSSebastian Reichel rk_udphy_reset_assert_all(udphy); 8772f70bbddSSebastian Reichel } 8782f70bbddSSebastian Reichel 8792f70bbddSSebastian Reichel static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy) 8802f70bbddSSebastian Reichel { 8812f70bbddSSebastian Reichel int ret, i, num_lanes; 8822f70bbddSSebastian Reichel 8832f70bbddSSebastian Reichel num_lanes = device_property_count_u32(udphy->dev, "rockchip,dp-lane-mux"); 8842f70bbddSSebastian Reichel if (num_lanes < 0) { 8852f70bbddSSebastian Reichel dev_dbg(udphy->dev, "no dp-lane-mux, following dp alt mode\n"); 8862f70bbddSSebastian Reichel udphy->mode = UDPHY_MODE_USB; 8872f70bbddSSebastian Reichel return 0; 8882f70bbddSSebastian Reichel } 8892f70bbddSSebastian Reichel 8902f70bbddSSebastian Reichel if (num_lanes != 2 && num_lanes != 4) 8912f70bbddSSebastian Reichel return dev_err_probe(udphy->dev, -EINVAL, 8922f70bbddSSebastian Reichel "invalid number of lane mux\n"); 8932f70bbddSSebastian Reichel 8942f70bbddSSebastian Reichel ret = device_property_read_u32_array(udphy->dev, "rockchip,dp-lane-mux", 8952f70bbddSSebastian Reichel udphy->dp_lane_sel, num_lanes); 8962f70bbddSSebastian Reichel if (ret) 8972f70bbddSSebastian Reichel return dev_err_probe(udphy->dev, ret, "get dp lane mux failed\n"); 8982f70bbddSSebastian Reichel 8992f70bbddSSebastian Reichel for (i = 0; i < num_lanes; i++) { 9002f70bbddSSebastian Reichel int j; 9012f70bbddSSebastian Reichel 9022f70bbddSSebastian Reichel if (udphy->dp_lane_sel[i] > 3) 9032f70bbddSSebastian Reichel return dev_err_probe(udphy->dev, -EINVAL, 9042f70bbddSSebastian Reichel "lane mux between 0 and 3, exceeding the range\n"); 9052f70bbddSSebastian Reichel 9062f70bbddSSebastian Reichel udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; 9072f70bbddSSebastian Reichel 9082f70bbddSSebastian Reichel for (j = i + 1; j < num_lanes; j++) { 9092f70bbddSSebastian Reichel if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) 9102f70bbddSSebastian Reichel return dev_err_probe(udphy->dev, -EINVAL, 9112f70bbddSSebastian Reichel "set repeat lane mux value\n"); 9122f70bbddSSebastian Reichel } 9132f70bbddSSebastian Reichel } 9142f70bbddSSebastian Reichel 9152f70bbddSSebastian Reichel udphy->mode = UDPHY_MODE_DP; 9162f70bbddSSebastian Reichel if (num_lanes == 2) { 9172f70bbddSSebastian Reichel udphy->mode |= UDPHY_MODE_USB; 9182f70bbddSSebastian Reichel udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP); 9192f70bbddSSebastian Reichel } 9202f70bbddSSebastian Reichel 9212f70bbddSSebastian Reichel return 0; 9222f70bbddSSebastian Reichel } 9232f70bbddSSebastian Reichel 9242f70bbddSSebastian Reichel static int rk_udphy_get_initial_status(struct rk_udphy *udphy) 9252f70bbddSSebastian Reichel { 9262f70bbddSSebastian Reichel int ret; 9272f70bbddSSebastian Reichel u32 value; 9282f70bbddSSebastian Reichel 9292f70bbddSSebastian Reichel ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); 9302f70bbddSSebastian Reichel if (ret) { 9312f70bbddSSebastian Reichel dev_err(udphy->dev, "failed to enable clk\n"); 9322f70bbddSSebastian Reichel return ret; 9332f70bbddSSebastian Reichel } 9342f70bbddSSebastian Reichel 9352f70bbddSSebastian Reichel rk_udphy_reset_deassert_all(udphy); 9362f70bbddSSebastian Reichel 9372f70bbddSSebastian Reichel regmap_read(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, &value); 9382f70bbddSSebastian Reichel if (FIELD_GET(CMN_DP_LANE_MUX_ALL, value) && FIELD_GET(CMN_DP_LANE_EN_ALL, value)) 9392f70bbddSSebastian Reichel udphy->status = UDPHY_MODE_DP; 9402f70bbddSSebastian Reichel else 9412f70bbddSSebastian Reichel rk_udphy_disable(udphy); 9422f70bbddSSebastian Reichel 9432f70bbddSSebastian Reichel return 0; 9442f70bbddSSebastian Reichel } 9452f70bbddSSebastian Reichel 9462f70bbddSSebastian Reichel static int rk_udphy_parse_dt(struct rk_udphy *udphy) 9472f70bbddSSebastian Reichel { 9482f70bbddSSebastian Reichel struct device *dev = udphy->dev; 9492f70bbddSSebastian Reichel struct device_node *np = dev_of_node(dev); 9502f70bbddSSebastian Reichel enum usb_device_speed maximum_speed; 9512f70bbddSSebastian Reichel int ret; 9522f70bbddSSebastian Reichel 9532f70bbddSSebastian Reichel udphy->u2phygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,u2phy-grf"); 9542f70bbddSSebastian Reichel if (IS_ERR(udphy->u2phygrf)) 9552f70bbddSSebastian Reichel return dev_err_probe(dev, PTR_ERR(udphy->u2phygrf), "failed to get u2phy-grf\n"); 9562f70bbddSSebastian Reichel 9572f70bbddSSebastian Reichel udphy->udphygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbdpphy-grf"); 9582f70bbddSSebastian Reichel if (IS_ERR(udphy->udphygrf)) 9592f70bbddSSebastian Reichel return dev_err_probe(dev, PTR_ERR(udphy->udphygrf), "failed to get usbdpphy-grf\n"); 9602f70bbddSSebastian Reichel 9612f70bbddSSebastian Reichel udphy->usbgrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usb-grf"); 9622f70bbddSSebastian Reichel if (IS_ERR(udphy->usbgrf)) 9632f70bbddSSebastian Reichel return dev_err_probe(dev, PTR_ERR(udphy->usbgrf), "failed to get usb-grf\n"); 9642f70bbddSSebastian Reichel 9652f70bbddSSebastian Reichel udphy->vogrf = syscon_regmap_lookup_by_phandle(np, "rockchip,vo-grf"); 9662f70bbddSSebastian Reichel if (IS_ERR(udphy->vogrf)) 9672f70bbddSSebastian Reichel return dev_err_probe(dev, PTR_ERR(udphy->vogrf), "failed to get vo-grf\n"); 9682f70bbddSSebastian Reichel 9692f70bbddSSebastian Reichel ret = rk_udphy_parse_lane_mux_data(udphy); 9702f70bbddSSebastian Reichel if (ret) 9712f70bbddSSebastian Reichel return ret; 9722f70bbddSSebastian Reichel 9732f70bbddSSebastian Reichel udphy->sbu1_dc_gpio = devm_gpiod_get_optional(dev, "sbu1-dc", GPIOD_OUT_LOW); 9742f70bbddSSebastian Reichel if (IS_ERR(udphy->sbu1_dc_gpio)) 9752f70bbddSSebastian Reichel return PTR_ERR(udphy->sbu1_dc_gpio); 9762f70bbddSSebastian Reichel 9772f70bbddSSebastian Reichel udphy->sbu2_dc_gpio = devm_gpiod_get_optional(dev, "sbu2-dc", GPIOD_OUT_LOW); 9782f70bbddSSebastian Reichel if (IS_ERR(udphy->sbu2_dc_gpio)) 9792f70bbddSSebastian Reichel return PTR_ERR(udphy->sbu2_dc_gpio); 9802f70bbddSSebastian Reichel 9812f70bbddSSebastian Reichel if (device_property_present(dev, "maximum-speed")) { 9822f70bbddSSebastian Reichel maximum_speed = usb_get_maximum_speed(dev); 983*b52b3300SThorsten Blum udphy->hs = maximum_speed <= USB_SPEED_HIGH; 9842f70bbddSSebastian Reichel } 9852f70bbddSSebastian Reichel 9862f70bbddSSebastian Reichel ret = rk_udphy_clk_init(udphy, dev); 9872f70bbddSSebastian Reichel if (ret) 9882f70bbddSSebastian Reichel return ret; 9892f70bbddSSebastian Reichel 9902f70bbddSSebastian Reichel return rk_udphy_reset_init(udphy, dev); 9912f70bbddSSebastian Reichel } 9922f70bbddSSebastian Reichel 9932f70bbddSSebastian Reichel static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode) 9942f70bbddSSebastian Reichel { 9952f70bbddSSebastian Reichel int ret; 9962f70bbddSSebastian Reichel 9972f70bbddSSebastian Reichel if (!(udphy->mode & mode)) { 9982f70bbddSSebastian Reichel dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); 9992f70bbddSSebastian Reichel return 0; 10002f70bbddSSebastian Reichel } 10012f70bbddSSebastian Reichel 10022f70bbddSSebastian Reichel if (udphy->status == UDPHY_MODE_NONE) { 10032f70bbddSSebastian Reichel udphy->mode_change = false; 10042f70bbddSSebastian Reichel ret = rk_udphy_setup(udphy); 10052f70bbddSSebastian Reichel if (ret) 10062f70bbddSSebastian Reichel return ret; 10072f70bbddSSebastian Reichel 10082f70bbddSSebastian Reichel if (udphy->mode & UDPHY_MODE_USB) 10092f70bbddSSebastian Reichel rk_udphy_u3_port_disable(udphy, false); 10102f70bbddSSebastian Reichel } else if (udphy->mode_change) { 10112f70bbddSSebastian Reichel udphy->mode_change = false; 10122f70bbddSSebastian Reichel udphy->status = UDPHY_MODE_NONE; 10132f70bbddSSebastian Reichel if (udphy->mode == UDPHY_MODE_DP) 10142f70bbddSSebastian Reichel rk_udphy_u3_port_disable(udphy, true); 10152f70bbddSSebastian Reichel 10162f70bbddSSebastian Reichel rk_udphy_disable(udphy); 10172f70bbddSSebastian Reichel ret = rk_udphy_setup(udphy); 10182f70bbddSSebastian Reichel if (ret) 10192f70bbddSSebastian Reichel return ret; 10202f70bbddSSebastian Reichel } 10212f70bbddSSebastian Reichel 10222f70bbddSSebastian Reichel udphy->status |= mode; 10232f70bbddSSebastian Reichel 10242f70bbddSSebastian Reichel return 0; 10252f70bbddSSebastian Reichel } 10262f70bbddSSebastian Reichel 10272f70bbddSSebastian Reichel static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode) 10282f70bbddSSebastian Reichel { 10292f70bbddSSebastian Reichel if (!(udphy->mode & mode)) { 10302f70bbddSSebastian Reichel dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); 10312f70bbddSSebastian Reichel return; 10322f70bbddSSebastian Reichel } 10332f70bbddSSebastian Reichel 10342f70bbddSSebastian Reichel if (!udphy->status) 10352f70bbddSSebastian Reichel return; 10362f70bbddSSebastian Reichel 10372f70bbddSSebastian Reichel udphy->status &= ~mode; 10382f70bbddSSebastian Reichel 10392f70bbddSSebastian Reichel if (udphy->status == UDPHY_MODE_NONE) 10402f70bbddSSebastian Reichel rk_udphy_disable(udphy); 10412f70bbddSSebastian Reichel } 10422f70bbddSSebastian Reichel 10432f70bbddSSebastian Reichel static int rk_udphy_dp_phy_init(struct phy *phy) 10442f70bbddSSebastian Reichel { 10452f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 10462f70bbddSSebastian Reichel 10472f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 10482f70bbddSSebastian Reichel 10492f70bbddSSebastian Reichel udphy->dp_in_use = true; 10502f70bbddSSebastian Reichel 10512f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 10522f70bbddSSebastian Reichel 10532f70bbddSSebastian Reichel return 0; 10542f70bbddSSebastian Reichel } 10552f70bbddSSebastian Reichel 10562f70bbddSSebastian Reichel static int rk_udphy_dp_phy_exit(struct phy *phy) 10572f70bbddSSebastian Reichel { 10582f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 10592f70bbddSSebastian Reichel 10602f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 10612f70bbddSSebastian Reichel udphy->dp_in_use = false; 10622f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 10632f70bbddSSebastian Reichel return 0; 10642f70bbddSSebastian Reichel } 10652f70bbddSSebastian Reichel 10662f70bbddSSebastian Reichel static int rk_udphy_dp_phy_power_on(struct phy *phy) 10672f70bbddSSebastian Reichel { 10682f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 10692f70bbddSSebastian Reichel int ret, dp_lanes; 10702f70bbddSSebastian Reichel 10712f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 10722f70bbddSSebastian Reichel 10732f70bbddSSebastian Reichel dp_lanes = rk_udphy_dplane_get(udphy); 10742f70bbddSSebastian Reichel phy_set_bus_width(phy, dp_lanes); 10752f70bbddSSebastian Reichel 10762f70bbddSSebastian Reichel ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP); 10772f70bbddSSebastian Reichel if (ret) 10782f70bbddSSebastian Reichel goto unlock; 10792f70bbddSSebastian Reichel 10802f70bbddSSebastian Reichel rk_udphy_dplane_enable(udphy, dp_lanes); 10812f70bbddSSebastian Reichel 10822f70bbddSSebastian Reichel rk_udphy_dplane_select(udphy); 10832f70bbddSSebastian Reichel 10842f70bbddSSebastian Reichel unlock: 10852f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 10862f70bbddSSebastian Reichel /* 10872f70bbddSSebastian Reichel * If data send by aux channel too fast after phy power on, 10882f70bbddSSebastian Reichel * the aux may be not ready which will cause aux error. Adding 10892f70bbddSSebastian Reichel * delay to avoid this issue. 10902f70bbddSSebastian Reichel */ 10912f70bbddSSebastian Reichel usleep_range(10000, 11000); 10922f70bbddSSebastian Reichel return ret; 10932f70bbddSSebastian Reichel } 10942f70bbddSSebastian Reichel 10952f70bbddSSebastian Reichel static int rk_udphy_dp_phy_power_off(struct phy *phy) 10962f70bbddSSebastian Reichel { 10972f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 10982f70bbddSSebastian Reichel 10992f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 11002f70bbddSSebastian Reichel rk_udphy_dplane_enable(udphy, 0); 11012f70bbddSSebastian Reichel rk_udphy_power_off(udphy, UDPHY_MODE_DP); 11022f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 11032f70bbddSSebastian Reichel 11042f70bbddSSebastian Reichel return 0; 11052f70bbddSSebastian Reichel } 11062f70bbddSSebastian Reichel 1107969a38beSAndy Yan /* 1108969a38beSAndy Yan * Verify link rate 1109969a38beSAndy Yan */ 1110969a38beSAndy Yan static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy, 1111969a38beSAndy Yan struct phy_configure_opts_dp *dp) 11122f70bbddSSebastian Reichel { 1113969a38beSAndy Yan switch (dp->link_rate) { 11142f70bbddSSebastian Reichel case 1620: 11152f70bbddSSebastian Reichel case 2700: 11162f70bbddSSebastian Reichel case 5400: 11172f70bbddSSebastian Reichel case 8100: 1118969a38beSAndy Yan udphy->link_rate = dp->link_rate; 1119969a38beSAndy Yan break; 1120969a38beSAndy Yan default: 1121969a38beSAndy Yan return -EINVAL; 1122969a38beSAndy Yan } 1123969a38beSAndy Yan 1124969a38beSAndy Yan return 0; 1125969a38beSAndy Yan } 1126969a38beSAndy Yan 1127969a38beSAndy Yan static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy, 1128969a38beSAndy Yan struct phy_configure_opts_dp *dp) 1129969a38beSAndy Yan { 1130969a38beSAndy Yan switch (dp->lanes) { 1131969a38beSAndy Yan case 1: 1132969a38beSAndy Yan case 2: 1133969a38beSAndy Yan case 4: 1134969a38beSAndy Yan /* valid lane count. */ 1135969a38beSAndy Yan udphy->lanes = dp->lanes; 11362f70bbddSSebastian Reichel break; 11372f70bbddSSebastian Reichel 11382f70bbddSSebastian Reichel default: 11392f70bbddSSebastian Reichel return -EINVAL; 11402f70bbddSSebastian Reichel } 11412f70bbddSSebastian Reichel 11422f70bbddSSebastian Reichel return 0; 11432f70bbddSSebastian Reichel } 11442f70bbddSSebastian Reichel 11452f70bbddSSebastian Reichel /* 11462f70bbddSSebastian Reichel * If changing voltages is required, check swing and pre-emphasis 11472f70bbddSSebastian Reichel * levels, per-lane. 11482f70bbddSSebastian Reichel */ 1149969a38beSAndy Yan static int rk_udphy_dp_phy_verify_voltages(struct rk_udphy *udphy, 1150969a38beSAndy Yan struct phy_configure_opts_dp *dp) 1151969a38beSAndy Yan { 1152969a38beSAndy Yan int i; 1153969a38beSAndy Yan 11542f70bbddSSebastian Reichel /* Lane count verified previously. */ 1155969a38beSAndy Yan for (i = 0; i < udphy->lanes; i++) { 11562f70bbddSSebastian Reichel if (dp->voltage[i] > 3 || dp->pre[i] > 3) 11572f70bbddSSebastian Reichel return -EINVAL; 11582f70bbddSSebastian Reichel 11592f70bbddSSebastian Reichel /* 11602f70bbddSSebastian Reichel * Sum of voltage swing and pre-emphasis levels cannot 11612f70bbddSSebastian Reichel * exceed 3. 11622f70bbddSSebastian Reichel */ 11632f70bbddSSebastian Reichel if (dp->voltage[i] + dp->pre[i] > 3) 11642f70bbddSSebastian Reichel return -EINVAL; 11652f70bbddSSebastian Reichel } 11662f70bbddSSebastian Reichel 11672f70bbddSSebastian Reichel return 0; 11682f70bbddSSebastian Reichel } 11692f70bbddSSebastian Reichel 11702f70bbddSSebastian Reichel static void rk_udphy_dp_set_voltage(struct rk_udphy *udphy, u8 bw, 11712f70bbddSSebastian Reichel u32 voltage, u32 pre, u32 lane) 11722f70bbddSSebastian Reichel { 11732f70bbddSSebastian Reichel const struct rk_udphy_cfg *cfg = udphy->cfgs; 11742f70bbddSSebastian Reichel const struct rk_udphy_dp_tx_drv_ctrl (*dp_ctrl)[4]; 11752f70bbddSSebastian Reichel u32 offset = 0x800 * lane; 11762f70bbddSSebastian Reichel u32 val; 11772f70bbddSSebastian Reichel 11782f70bbddSSebastian Reichel if (udphy->mux) 11792f70bbddSSebastian Reichel dp_ctrl = cfg->dp_tx_ctrl_cfg_typec[bw]; 11802f70bbddSSebastian Reichel else 11812f70bbddSSebastian Reichel dp_ctrl = cfg->dp_tx_ctrl_cfg[bw]; 11822f70bbddSSebastian Reichel 11832f70bbddSSebastian Reichel val = dp_ctrl[voltage][pre].trsv_reg0204; 11842f70bbddSSebastian Reichel regmap_write(udphy->pma_regmap, 0x0810 + offset, val); 11852f70bbddSSebastian Reichel 11862f70bbddSSebastian Reichel val = dp_ctrl[voltage][pre].trsv_reg0205; 11872f70bbddSSebastian Reichel regmap_write(udphy->pma_regmap, 0x0814 + offset, val); 11882f70bbddSSebastian Reichel 11892f70bbddSSebastian Reichel val = dp_ctrl[voltage][pre].trsv_reg0206; 11902f70bbddSSebastian Reichel regmap_write(udphy->pma_regmap, 0x0818 + offset, val); 11912f70bbddSSebastian Reichel 11922f70bbddSSebastian Reichel val = dp_ctrl[voltage][pre].trsv_reg0207; 11932f70bbddSSebastian Reichel regmap_write(udphy->pma_regmap, 0x081c + offset, val); 11942f70bbddSSebastian Reichel } 11952f70bbddSSebastian Reichel 11962f70bbddSSebastian Reichel static int rk_udphy_dp_phy_configure(struct phy *phy, 11972f70bbddSSebastian Reichel union phy_configure_opts *opts) 11982f70bbddSSebastian Reichel { 11992f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 12002f70bbddSSebastian Reichel struct phy_configure_opts_dp *dp = &opts->dp; 12012f70bbddSSebastian Reichel u32 i, val, lane; 12022f70bbddSSebastian Reichel int ret; 12032f70bbddSSebastian Reichel 1204969a38beSAndy Yan if (dp->set_rate) { 1205969a38beSAndy Yan ret = rk_udphy_dp_phy_verify_link_rate(udphy, dp); 12062f70bbddSSebastian Reichel if (ret) 12072f70bbddSSebastian Reichel return ret; 1208969a38beSAndy Yan } 1209969a38beSAndy Yan 1210969a38beSAndy Yan if (dp->set_lanes) { 1211969a38beSAndy Yan ret = rk_udphy_dp_phy_verify_lanes(udphy, dp); 1212969a38beSAndy Yan if (ret) 1213969a38beSAndy Yan return ret; 1214969a38beSAndy Yan } 1215969a38beSAndy Yan 1216969a38beSAndy Yan if (dp->set_voltages) { 1217969a38beSAndy Yan ret = rk_udphy_dp_phy_verify_voltages(udphy, dp); 1218969a38beSAndy Yan if (ret) 1219969a38beSAndy Yan return ret; 1220969a38beSAndy Yan } 12212f70bbddSSebastian Reichel 12222f70bbddSSebastian Reichel if (dp->set_rate) { 12232f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 12242f70bbddSSebastian Reichel CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); 12252f70bbddSSebastian Reichel 12262f70bbddSSebastian Reichel switch (dp->link_rate) { 12272f70bbddSSebastian Reichel case 1620: 12282f70bbddSSebastian Reichel udphy->bw = DP_BW_RBR; 12292f70bbddSSebastian Reichel break; 12302f70bbddSSebastian Reichel 12312f70bbddSSebastian Reichel case 2700: 12322f70bbddSSebastian Reichel udphy->bw = DP_BW_HBR; 12332f70bbddSSebastian Reichel break; 12342f70bbddSSebastian Reichel 12352f70bbddSSebastian Reichel case 5400: 12362f70bbddSSebastian Reichel udphy->bw = DP_BW_HBR2; 12372f70bbddSSebastian Reichel break; 12382f70bbddSSebastian Reichel 12392f70bbddSSebastian Reichel case 8100: 12402f70bbddSSebastian Reichel udphy->bw = DP_BW_HBR3; 12412f70bbddSSebastian Reichel break; 12422f70bbddSSebastian Reichel 12432f70bbddSSebastian Reichel default: 12442f70bbddSSebastian Reichel return -EINVAL; 12452f70bbddSSebastian Reichel } 12462f70bbddSSebastian Reichel 12472f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, 12482f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); 12492f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, 12502f70bbddSSebastian Reichel FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc)); 12512f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, 12522f70bbddSSebastian Reichel FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); 12532f70bbddSSebastian Reichel 12542f70bbddSSebastian Reichel ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, 12552f70bbddSSebastian Reichel FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && 12562f70bbddSSebastian Reichel FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), 12572f70bbddSSebastian Reichel 0, 1000); 12582f70bbddSSebastian Reichel if (ret) { 12592f70bbddSSebastian Reichel dev_err(udphy->dev, "ROPLL is not lock, set_rate failed\n"); 12602f70bbddSSebastian Reichel return ret; 12612f70bbddSSebastian Reichel } 12622f70bbddSSebastian Reichel } 12632f70bbddSSebastian Reichel 12642f70bbddSSebastian Reichel if (dp->set_voltages) { 1265969a38beSAndy Yan for (i = 0; i < udphy->lanes; i++) { 12662f70bbddSSebastian Reichel lane = udphy->dp_lane_sel[i]; 1267969a38beSAndy Yan switch (udphy->link_rate) { 12682f70bbddSSebastian Reichel case 1620: 12692f70bbddSSebastian Reichel case 2700: 12702f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, 12712f70bbddSSebastian Reichel TRSV_ANA_TX_CLK_OFFSET_N(lane), 12722f70bbddSSebastian Reichel LN_ANA_TX_SER_TXCLK_INV, 12732f70bbddSSebastian Reichel FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 12742f70bbddSSebastian Reichel udphy->lane_mux_sel[lane])); 12752f70bbddSSebastian Reichel break; 12762f70bbddSSebastian Reichel 12772f70bbddSSebastian Reichel case 5400: 12782f70bbddSSebastian Reichel case 8100: 12792f70bbddSSebastian Reichel regmap_update_bits(udphy->pma_regmap, 12802f70bbddSSebastian Reichel TRSV_ANA_TX_CLK_OFFSET_N(lane), 12812f70bbddSSebastian Reichel LN_ANA_TX_SER_TXCLK_INV, 12822f70bbddSSebastian Reichel FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); 12832f70bbddSSebastian Reichel break; 12842f70bbddSSebastian Reichel } 12852f70bbddSSebastian Reichel 12862f70bbddSSebastian Reichel rk_udphy_dp_set_voltage(udphy, udphy->bw, dp->voltage[i], 12872f70bbddSSebastian Reichel dp->pre[i], lane); 12882f70bbddSSebastian Reichel } 12892f70bbddSSebastian Reichel } 12902f70bbddSSebastian Reichel 12912f70bbddSSebastian Reichel return 0; 12922f70bbddSSebastian Reichel } 12932f70bbddSSebastian Reichel 12942f70bbddSSebastian Reichel static const struct phy_ops rk_udphy_dp_phy_ops = { 12952f70bbddSSebastian Reichel .init = rk_udphy_dp_phy_init, 12962f70bbddSSebastian Reichel .exit = rk_udphy_dp_phy_exit, 12972f70bbddSSebastian Reichel .power_on = rk_udphy_dp_phy_power_on, 12982f70bbddSSebastian Reichel .power_off = rk_udphy_dp_phy_power_off, 12992f70bbddSSebastian Reichel .configure = rk_udphy_dp_phy_configure, 13002f70bbddSSebastian Reichel .owner = THIS_MODULE, 13012f70bbddSSebastian Reichel }; 13022f70bbddSSebastian Reichel 13032f70bbddSSebastian Reichel static int rk_udphy_usb3_phy_init(struct phy *phy) 13042f70bbddSSebastian Reichel { 13052f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 1306c9342d1aSSebastian Reichel int ret = 0; 13072f70bbddSSebastian Reichel 13082f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 13092f70bbddSSebastian Reichel /* DP only or high-speed, disable U3 port */ 13102f70bbddSSebastian Reichel if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { 13112f70bbddSSebastian Reichel rk_udphy_u3_port_disable(udphy, true); 13122f70bbddSSebastian Reichel goto unlock; 13132f70bbddSSebastian Reichel } 13142f70bbddSSebastian Reichel 13152f70bbddSSebastian Reichel ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB); 13162f70bbddSSebastian Reichel 13172f70bbddSSebastian Reichel unlock: 13182f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 13192f70bbddSSebastian Reichel return ret; 13202f70bbddSSebastian Reichel } 13212f70bbddSSebastian Reichel 13222f70bbddSSebastian Reichel static int rk_udphy_usb3_phy_exit(struct phy *phy) 13232f70bbddSSebastian Reichel { 13242f70bbddSSebastian Reichel struct rk_udphy *udphy = phy_get_drvdata(phy); 13252f70bbddSSebastian Reichel 13262f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 13272f70bbddSSebastian Reichel /* DP only or high-speed */ 13282f70bbddSSebastian Reichel if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) 13292f70bbddSSebastian Reichel goto unlock; 13302f70bbddSSebastian Reichel 13312f70bbddSSebastian Reichel rk_udphy_power_off(udphy, UDPHY_MODE_USB); 13322f70bbddSSebastian Reichel 13332f70bbddSSebastian Reichel unlock: 13342f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 13352f70bbddSSebastian Reichel return 0; 13362f70bbddSSebastian Reichel } 13372f70bbddSSebastian Reichel 13382f70bbddSSebastian Reichel static const struct phy_ops rk_udphy_usb3_phy_ops = { 13392f70bbddSSebastian Reichel .init = rk_udphy_usb3_phy_init, 13402f70bbddSSebastian Reichel .exit = rk_udphy_usb3_phy_exit, 13412f70bbddSSebastian Reichel .owner = THIS_MODULE, 13422f70bbddSSebastian Reichel }; 13432f70bbddSSebastian Reichel 13442f70bbddSSebastian Reichel static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux, 13452f70bbddSSebastian Reichel struct typec_mux_state *state) 13462f70bbddSSebastian Reichel { 13472f70bbddSSebastian Reichel struct rk_udphy *udphy = typec_mux_get_drvdata(mux); 13482f70bbddSSebastian Reichel u8 mode; 13492f70bbddSSebastian Reichel 13502f70bbddSSebastian Reichel mutex_lock(&udphy->mutex); 13512f70bbddSSebastian Reichel 13522f70bbddSSebastian Reichel switch (state->mode) { 13532f70bbddSSebastian Reichel case TYPEC_DP_STATE_C: 13542f70bbddSSebastian Reichel case TYPEC_DP_STATE_E: 13552f70bbddSSebastian Reichel udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; 13562f70bbddSSebastian Reichel udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; 13572f70bbddSSebastian Reichel udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; 13582f70bbddSSebastian Reichel udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; 13592f70bbddSSebastian Reichel mode = UDPHY_MODE_DP; 13602f70bbddSSebastian Reichel break; 13612f70bbddSSebastian Reichel 13622f70bbddSSebastian Reichel case TYPEC_DP_STATE_D: 13632f70bbddSSebastian Reichel default: 13642f70bbddSSebastian Reichel if (udphy->flip) { 13652f70bbddSSebastian Reichel udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; 13662f70bbddSSebastian Reichel udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; 13672f70bbddSSebastian Reichel udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; 13682f70bbddSSebastian Reichel udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; 13692f70bbddSSebastian Reichel } else { 13702f70bbddSSebastian Reichel udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; 13712f70bbddSSebastian Reichel udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; 13722f70bbddSSebastian Reichel udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; 13732f70bbddSSebastian Reichel udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; 13742f70bbddSSebastian Reichel } 13752f70bbddSSebastian Reichel mode = UDPHY_MODE_DP_USB; 13762f70bbddSSebastian Reichel break; 13772f70bbddSSebastian Reichel } 13782f70bbddSSebastian Reichel 13792f70bbddSSebastian Reichel if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) { 13802f70bbddSSebastian Reichel struct typec_displayport_data *data = state->data; 13812f70bbddSSebastian Reichel 13822f70bbddSSebastian Reichel if (!data) { 13832f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, false); 13842f70bbddSSebastian Reichel } else if (data->status & DP_STATUS_IRQ_HPD) { 13852f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, false); 13862f70bbddSSebastian Reichel usleep_range(750, 800); 13872f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, true); 13882f70bbddSSebastian Reichel } else if (data->status & DP_STATUS_HPD_STATE) { 13892f70bbddSSebastian Reichel if (udphy->mode != mode) { 13902f70bbddSSebastian Reichel udphy->mode = mode; 13912f70bbddSSebastian Reichel udphy->mode_change = true; 13922f70bbddSSebastian Reichel } 13932f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, true); 13942f70bbddSSebastian Reichel } else { 13952f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, false); 13962f70bbddSSebastian Reichel } 13972f70bbddSSebastian Reichel } 13982f70bbddSSebastian Reichel 13992f70bbddSSebastian Reichel mutex_unlock(&udphy->mutex); 14002f70bbddSSebastian Reichel return 0; 14012f70bbddSSebastian Reichel } 14022f70bbddSSebastian Reichel 14032f70bbddSSebastian Reichel static void rk_udphy_typec_mux_unregister(void *data) 14042f70bbddSSebastian Reichel { 14052f70bbddSSebastian Reichel struct rk_udphy *udphy = data; 14062f70bbddSSebastian Reichel 14072f70bbddSSebastian Reichel typec_mux_unregister(udphy->mux); 14082f70bbddSSebastian Reichel } 14092f70bbddSSebastian Reichel 14102f70bbddSSebastian Reichel static int rk_udphy_setup_typec_mux(struct rk_udphy *udphy) 14112f70bbddSSebastian Reichel { 14122f70bbddSSebastian Reichel struct typec_mux_desc mux_desc = {}; 14132f70bbddSSebastian Reichel 14142f70bbddSSebastian Reichel mux_desc.drvdata = udphy; 14152f70bbddSSebastian Reichel mux_desc.fwnode = dev_fwnode(udphy->dev); 14162f70bbddSSebastian Reichel mux_desc.set = rk_udphy_typec_mux_set; 14172f70bbddSSebastian Reichel 14182f70bbddSSebastian Reichel udphy->mux = typec_mux_register(udphy->dev, &mux_desc); 14192f70bbddSSebastian Reichel if (IS_ERR(udphy->mux)) { 14202f70bbddSSebastian Reichel dev_err(udphy->dev, "Error register typec mux: %ld\n", 14212f70bbddSSebastian Reichel PTR_ERR(udphy->mux)); 14222f70bbddSSebastian Reichel return PTR_ERR(udphy->mux); 14232f70bbddSSebastian Reichel } 14242f70bbddSSebastian Reichel 14252f70bbddSSebastian Reichel return devm_add_action_or_reset(udphy->dev, rk_udphy_typec_mux_unregister, 14262f70bbddSSebastian Reichel udphy); 14272f70bbddSSebastian Reichel } 14282f70bbddSSebastian Reichel 14292f70bbddSSebastian Reichel static const struct regmap_config rk_udphy_pma_regmap_cfg = { 14302f70bbddSSebastian Reichel .reg_bits = 32, 14312f70bbddSSebastian Reichel .reg_stride = 4, 14322f70bbddSSebastian Reichel .val_bits = 32, 14332f70bbddSSebastian Reichel .fast_io = true, 14342f70bbddSSebastian Reichel .max_register = 0x20dc, 14352f70bbddSSebastian Reichel }; 14362f70bbddSSebastian Reichel 14372f70bbddSSebastian Reichel static struct phy *rk_udphy_phy_xlate(struct device *dev, const struct of_phandle_args *args) 14382f70bbddSSebastian Reichel { 14392f70bbddSSebastian Reichel struct rk_udphy *udphy = dev_get_drvdata(dev); 14402f70bbddSSebastian Reichel 14412f70bbddSSebastian Reichel if (args->args_count == 0) 14422f70bbddSSebastian Reichel return ERR_PTR(-EINVAL); 14432f70bbddSSebastian Reichel 14442f70bbddSSebastian Reichel switch (args->args[0]) { 14452f70bbddSSebastian Reichel case PHY_TYPE_USB3: 14462f70bbddSSebastian Reichel return udphy->phy_u3; 14472f70bbddSSebastian Reichel case PHY_TYPE_DP: 14482f70bbddSSebastian Reichel return udphy->phy_dp; 14492f70bbddSSebastian Reichel } 14502f70bbddSSebastian Reichel 14512f70bbddSSebastian Reichel return ERR_PTR(-EINVAL); 14522f70bbddSSebastian Reichel } 14532f70bbddSSebastian Reichel 14542f70bbddSSebastian Reichel static int rk_udphy_probe(struct platform_device *pdev) 14552f70bbddSSebastian Reichel { 14562f70bbddSSebastian Reichel struct device *dev = &pdev->dev; 14572f70bbddSSebastian Reichel struct phy_provider *phy_provider; 14582f70bbddSSebastian Reichel struct resource *res; 14592f70bbddSSebastian Reichel struct rk_udphy *udphy; 14602f70bbddSSebastian Reichel void __iomem *base; 14612f70bbddSSebastian Reichel int id, ret; 14622f70bbddSSebastian Reichel 14632f70bbddSSebastian Reichel udphy = devm_kzalloc(dev, sizeof(*udphy), GFP_KERNEL); 14642f70bbddSSebastian Reichel if (!udphy) 14652f70bbddSSebastian Reichel return -ENOMEM; 14662f70bbddSSebastian Reichel 14672f70bbddSSebastian Reichel udphy->cfgs = device_get_match_data(dev); 14682f70bbddSSebastian Reichel if (!udphy->cfgs) 14692f70bbddSSebastian Reichel return dev_err_probe(dev, -EINVAL, "missing match data\n"); 14702f70bbddSSebastian Reichel 14712f70bbddSSebastian Reichel base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 14722f70bbddSSebastian Reichel if (IS_ERR(base)) 14732f70bbddSSebastian Reichel return PTR_ERR(base); 14742f70bbddSSebastian Reichel 14752f70bbddSSebastian Reichel /* find the phy-id from the io address */ 14762f70bbddSSebastian Reichel udphy->id = -ENODEV; 14772f70bbddSSebastian Reichel for (id = 0; id < udphy->cfgs->num_phys; id++) { 14782f70bbddSSebastian Reichel if (res->start == udphy->cfgs->phy_ids[id]) { 14792f70bbddSSebastian Reichel udphy->id = id; 14802f70bbddSSebastian Reichel break; 14812f70bbddSSebastian Reichel } 14822f70bbddSSebastian Reichel } 14832f70bbddSSebastian Reichel 14842f70bbddSSebastian Reichel if (udphy->id < 0) 14852f70bbddSSebastian Reichel return dev_err_probe(dev, -ENODEV, "no matching device found\n"); 14862f70bbddSSebastian Reichel 14872f70bbddSSebastian Reichel udphy->pma_regmap = devm_regmap_init_mmio(dev, base + UDPHY_PMA, 14882f70bbddSSebastian Reichel &rk_udphy_pma_regmap_cfg); 14892f70bbddSSebastian Reichel if (IS_ERR(udphy->pma_regmap)) 14902f70bbddSSebastian Reichel return PTR_ERR(udphy->pma_regmap); 14912f70bbddSSebastian Reichel 14922f70bbddSSebastian Reichel udphy->dev = dev; 14932f70bbddSSebastian Reichel ret = rk_udphy_parse_dt(udphy); 14942f70bbddSSebastian Reichel if (ret) 14952f70bbddSSebastian Reichel return ret; 14962f70bbddSSebastian Reichel 14972f70bbddSSebastian Reichel ret = rk_udphy_get_initial_status(udphy); 14982f70bbddSSebastian Reichel if (ret) 14992f70bbddSSebastian Reichel return ret; 15002f70bbddSSebastian Reichel 15012f70bbddSSebastian Reichel mutex_init(&udphy->mutex); 15022f70bbddSSebastian Reichel platform_set_drvdata(pdev, udphy); 15032f70bbddSSebastian Reichel 15042f70bbddSSebastian Reichel if (device_property_present(dev, "orientation-switch")) { 15052f70bbddSSebastian Reichel ret = rk_udphy_setup_orien_switch(udphy); 15062f70bbddSSebastian Reichel if (ret) 15072f70bbddSSebastian Reichel return ret; 15082f70bbddSSebastian Reichel } 15092f70bbddSSebastian Reichel 15102f70bbddSSebastian Reichel if (device_property_present(dev, "mode-switch")) { 15112f70bbddSSebastian Reichel ret = rk_udphy_setup_typec_mux(udphy); 15122f70bbddSSebastian Reichel if (ret) 15132f70bbddSSebastian Reichel return ret; 15142f70bbddSSebastian Reichel } 15152f70bbddSSebastian Reichel 15162f70bbddSSebastian Reichel udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops); 15172f70bbddSSebastian Reichel if (IS_ERR(udphy->phy_u3)) { 15182f70bbddSSebastian Reichel ret = PTR_ERR(udphy->phy_u3); 15192f70bbddSSebastian Reichel return dev_err_probe(dev, ret, "failed to create USB3 phy\n"); 15202f70bbddSSebastian Reichel } 15212f70bbddSSebastian Reichel phy_set_drvdata(udphy->phy_u3, udphy); 15222f70bbddSSebastian Reichel 15232f70bbddSSebastian Reichel udphy->phy_dp = devm_phy_create(dev, dev->of_node, &rk_udphy_dp_phy_ops); 15242f70bbddSSebastian Reichel if (IS_ERR(udphy->phy_dp)) { 15252f70bbddSSebastian Reichel ret = PTR_ERR(udphy->phy_dp); 15262f70bbddSSebastian Reichel return dev_err_probe(dev, ret, "failed to create DP phy\n"); 15272f70bbddSSebastian Reichel } 15282f70bbddSSebastian Reichel phy_set_bus_width(udphy->phy_dp, rk_udphy_dplane_get(udphy)); 15292f70bbddSSebastian Reichel udphy->phy_dp->attrs.max_link_rate = 8100; 15302f70bbddSSebastian Reichel phy_set_drvdata(udphy->phy_dp, udphy); 15312f70bbddSSebastian Reichel 15322f70bbddSSebastian Reichel phy_provider = devm_of_phy_provider_register(dev, rk_udphy_phy_xlate); 15332f70bbddSSebastian Reichel if (IS_ERR(phy_provider)) { 15342f70bbddSSebastian Reichel ret = PTR_ERR(phy_provider); 15352f70bbddSSebastian Reichel return dev_err_probe(dev, ret, "failed to register phy provider\n"); 15362f70bbddSSebastian Reichel } 15372f70bbddSSebastian Reichel 15382f70bbddSSebastian Reichel return 0; 15392f70bbddSSebastian Reichel } 15402f70bbddSSebastian Reichel 15412f70bbddSSebastian Reichel static int __maybe_unused rk_udphy_resume(struct device *dev) 15422f70bbddSSebastian Reichel { 15432f70bbddSSebastian Reichel struct rk_udphy *udphy = dev_get_drvdata(dev); 15442f70bbddSSebastian Reichel 15452f70bbddSSebastian Reichel if (udphy->dp_sink_hpd_sel) 15462f70bbddSSebastian Reichel rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg); 15472f70bbddSSebastian Reichel 15482f70bbddSSebastian Reichel return 0; 15492f70bbddSSebastian Reichel } 15502f70bbddSSebastian Reichel 15512f70bbddSSebastian Reichel static const struct dev_pm_ops rk_udphy_pm_ops = { 15522f70bbddSSebastian Reichel SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, rk_udphy_resume) 15532f70bbddSSebastian Reichel }; 15542f70bbddSSebastian Reichel 15552f70bbddSSebastian Reichel static const char * const rk_udphy_rst_list[] = { 15562f70bbddSSebastian Reichel "init", "cmn", "lane", "pcs_apb", "pma_apb" 15572f70bbddSSebastian Reichel }; 15582f70bbddSSebastian Reichel 1559a76de028SFrank Wang static const struct rk_udphy_cfg rk3576_udphy_cfgs = { 1560a76de028SFrank Wang .num_phys = 1, 1561a76de028SFrank Wang .phy_ids = { 0x2b010000 }, 1562a76de028SFrank Wang .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), 1563a76de028SFrank Wang .rst_list = rk_udphy_rst_list, 1564a76de028SFrank Wang .grfcfg = { 1565a76de028SFrank Wang /* u2phy-grf */ 1566a76de028SFrank Wang .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0010, 1, 0, 0x2, 0x3), 1567a76de028SFrank Wang .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0000, 15, 14, 0x1, 0x3), 1568a76de028SFrank Wang 1569a76de028SFrank Wang /* usb-grf */ 1570a76de028SFrank Wang .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x0030, 15, 0, 0x1100, 0x0188), 1571a76de028SFrank Wang 1572a76de028SFrank Wang /* usbdpphy-grf */ 1573a76de028SFrank Wang .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), 1574a76de028SFrank Wang .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), 1575a76de028SFrank Wang }, 1576a76de028SFrank Wang .vogrfcfg = { 1577a76de028SFrank Wang { 1578a76de028SFrank Wang .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), 1579a76de028SFrank Wang .dp_lane_reg = 0x0000, 1580a76de028SFrank Wang }, 1581a76de028SFrank Wang }, 1582a76de028SFrank Wang .dp_tx_ctrl_cfg = { 1583a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 1584a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 1585a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_hbr2, 1586a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_hbr3, 1587a76de028SFrank Wang }, 1588a76de028SFrank Wang .dp_tx_ctrl_cfg_typec = { 1589a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 1590a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 1591a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_hbr2, 1592a76de028SFrank Wang rk3588_dp_tx_drv_ctrl_hbr3, 1593a76de028SFrank Wang }, 1594a76de028SFrank Wang }; 1595a76de028SFrank Wang 15962f70bbddSSebastian Reichel static const struct rk_udphy_cfg rk3588_udphy_cfgs = { 15972f70bbddSSebastian Reichel .num_phys = 2, 15982f70bbddSSebastian Reichel .phy_ids = { 15992f70bbddSSebastian Reichel 0xfed80000, 16002f70bbddSSebastian Reichel 0xfed90000, 16012f70bbddSSebastian Reichel }, 16022f70bbddSSebastian Reichel .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), 16032f70bbddSSebastian Reichel .rst_list = rk_udphy_rst_list, 16042f70bbddSSebastian Reichel .grfcfg = { 16052f70bbddSSebastian Reichel /* u2phy-grf */ 16062f70bbddSSebastian Reichel .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0008, 1, 0, 0x2, 0x3), 16072f70bbddSSebastian Reichel .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0010, 3, 2, 0x2, 0x3), 16082f70bbddSSebastian Reichel 16092f70bbddSSebastian Reichel /* usb-grf */ 16102f70bbddSSebastian Reichel .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x001c, 15, 0, 0x1100, 0x0188), 16112f70bbddSSebastian Reichel .usb3otg1_cfg = RK_UDPHY_GEN_GRF_REG(0x0034, 15, 0, 0x1100, 0x0188), 16122f70bbddSSebastian Reichel 16132f70bbddSSebastian Reichel /* usbdpphy-grf */ 16142f70bbddSSebastian Reichel .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), 16152f70bbddSSebastian Reichel .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), 16162f70bbddSSebastian Reichel }, 16172f70bbddSSebastian Reichel .vogrfcfg = { 16182f70bbddSSebastian Reichel { 16192f70bbddSSebastian Reichel .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), 16202f70bbddSSebastian Reichel .dp_lane_reg = 0x0000, 16212f70bbddSSebastian Reichel }, 16222f70bbddSSebastian Reichel { 16232f70bbddSSebastian Reichel .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0008, 11, 10, 1, 3), 16242f70bbddSSebastian Reichel .dp_lane_reg = 0x0008, 16252f70bbddSSebastian Reichel }, 16262f70bbddSSebastian Reichel }, 16272f70bbddSSebastian Reichel .dp_tx_ctrl_cfg = { 16282f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_rbr_hbr, 16292f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_rbr_hbr, 16302f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_hbr2, 16312f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_hbr3, 16322f70bbddSSebastian Reichel }, 16332f70bbddSSebastian Reichel .dp_tx_ctrl_cfg_typec = { 16342f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 16352f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, 16362f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_hbr2, 16372f70bbddSSebastian Reichel rk3588_dp_tx_drv_ctrl_hbr3, 16382f70bbddSSebastian Reichel }, 16392f70bbddSSebastian Reichel }; 16402f70bbddSSebastian Reichel 16412f70bbddSSebastian Reichel static const struct of_device_id rk_udphy_dt_match[] = { 16422f70bbddSSebastian Reichel { 1643a76de028SFrank Wang .compatible = "rockchip,rk3576-usbdp-phy", 1644a76de028SFrank Wang .data = &rk3576_udphy_cfgs 1645a76de028SFrank Wang }, 1646a76de028SFrank Wang { 16472f70bbddSSebastian Reichel .compatible = "rockchip,rk3588-usbdp-phy", 16482f70bbddSSebastian Reichel .data = &rk3588_udphy_cfgs 16492f70bbddSSebastian Reichel }, 16502f70bbddSSebastian Reichel { /* sentinel */ } 16512f70bbddSSebastian Reichel }; 16522f70bbddSSebastian Reichel MODULE_DEVICE_TABLE(of, rk_udphy_dt_match); 16532f70bbddSSebastian Reichel 16542f70bbddSSebastian Reichel static struct platform_driver rk_udphy_driver = { 16552f70bbddSSebastian Reichel .probe = rk_udphy_probe, 16562f70bbddSSebastian Reichel .driver = { 16572f70bbddSSebastian Reichel .name = "rockchip-usbdp-phy", 16582f70bbddSSebastian Reichel .of_match_table = rk_udphy_dt_match, 16592f70bbddSSebastian Reichel .pm = &rk_udphy_pm_ops, 16602f70bbddSSebastian Reichel }, 16612f70bbddSSebastian Reichel }; 16622f70bbddSSebastian Reichel module_platform_driver(rk_udphy_driver); 16632f70bbddSSebastian Reichel 16642f70bbddSSebastian Reichel MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>"); 16652f70bbddSSebastian Reichel MODULE_AUTHOR("Zhang Yubing <yubing.zhang@rock-chips.com>"); 16662f70bbddSSebastian Reichel MODULE_DESCRIPTION("Rockchip USBDP Combo PHY driver"); 16672f70bbddSSebastian Reichel MODULE_LICENSE("GPL"); 1668