12480f5daSFrank Wang // SPDX-License-Identifier: GPL-2.0-or-later 22480f5daSFrank Wang /* 32480f5daSFrank Wang * Rockchip USBDP Combo PHY with Samsung IP block driver 42480f5daSFrank Wang * 52480f5daSFrank Wang * Copyright (C) 2021 Rockchip Electronics Co., Ltd 62480f5daSFrank Wang */ 72480f5daSFrank Wang 82480f5daSFrank Wang #include <common.h> 92480f5daSFrank Wang #include <clk.h> 102480f5daSFrank Wang #include <dm.h> 112480f5daSFrank Wang #include <dm/lists.h> 122480f5daSFrank Wang #include <dm/of.h> 132480f5daSFrank Wang #include <dm/of_access.h> 142480f5daSFrank Wang #include <generic-phy.h> 152480f5daSFrank Wang #include <linux/bitfield.h> 162480f5daSFrank Wang #include <linux/usb/ch9.h> 172480f5daSFrank Wang #include <linux/usb/otg.h> 182480f5daSFrank Wang #include <regmap.h> 192480f5daSFrank Wang #include <reset.h> 202480f5daSFrank Wang #include <syscon.h> 212480f5daSFrank Wang #include <asm/arch/clock.h> 222480f5daSFrank Wang #include <asm/arch/cpu.h> 232480f5daSFrank Wang 242480f5daSFrank Wang #include <linux/usb/phy-rockchip-usbdp.h> 252480f5daSFrank Wang 262480f5daSFrank Wang #define BIT_WRITEABLE_SHIFT 16 272480f5daSFrank Wang 282480f5daSFrank Wang enum { 29*bb3d2afbSZhang Yubing DP_BW_RBR, 30*bb3d2afbSZhang Yubing DP_BW_HBR, 31*bb3d2afbSZhang Yubing DP_BW_HBR2, 32*bb3d2afbSZhang Yubing DP_BW_HBR3, 33*bb3d2afbSZhang Yubing }; 34*bb3d2afbSZhang Yubing 35*bb3d2afbSZhang Yubing enum { 362480f5daSFrank Wang UDPHY_MODE_NONE = 0, 372480f5daSFrank Wang UDPHY_MODE_USB = BIT(0), 382480f5daSFrank Wang UDPHY_MODE_DP = BIT(1), 392480f5daSFrank Wang UDPHY_MODE_DP_USB = BIT(1) | BIT(0), 402480f5daSFrank Wang }; 412480f5daSFrank Wang 422480f5daSFrank Wang struct udphy_grf_reg { 432480f5daSFrank Wang unsigned int offset; 442480f5daSFrank Wang unsigned int bitend; 452480f5daSFrank Wang unsigned int bitstart; 462480f5daSFrank Wang unsigned int disable; 472480f5daSFrank Wang unsigned int enable; 482480f5daSFrank Wang }; 492480f5daSFrank Wang 502480f5daSFrank Wang /** 512480f5daSFrank Wang * struct reg_sequence - An individual write from a sequence of writes. 522480f5daSFrank Wang * 532480f5daSFrank Wang * @reg: Register address. 542480f5daSFrank Wang * @def: Register value. 552480f5daSFrank Wang * @delay_us: Delay to be applied after the register write in microseconds 562480f5daSFrank Wang * 572480f5daSFrank Wang * Register/value pairs for sequences of writes with an optional delay in 582480f5daSFrank Wang * microseconds to be applied after each write. 592480f5daSFrank Wang */ 602480f5daSFrank Wang struct reg_sequence { 612480f5daSFrank Wang unsigned int reg; 622480f5daSFrank Wang unsigned int def; 632480f5daSFrank Wang unsigned int delay_us; 642480f5daSFrank Wang }; 652480f5daSFrank Wang 662480f5daSFrank Wang struct udphy_grf_cfg { 672480f5daSFrank Wang /* u2phy-grf */ 682480f5daSFrank Wang struct udphy_grf_reg bvalid_phy_con; 692480f5daSFrank Wang struct udphy_grf_reg bvalid_grf_con; 702480f5daSFrank Wang 712480f5daSFrank Wang /* usb-grf */ 722480f5daSFrank Wang struct udphy_grf_reg usb3otg0_cfg; 732480f5daSFrank Wang struct udphy_grf_reg usb3otg1_cfg; 742480f5daSFrank Wang 752480f5daSFrank Wang /* usbdpphy-grf */ 762480f5daSFrank Wang struct udphy_grf_reg low_pwrn; 772480f5daSFrank Wang struct udphy_grf_reg rx_lfps; 782480f5daSFrank Wang }; 792480f5daSFrank Wang 80*bb3d2afbSZhang Yubing struct dp_tx_drv_ctrl { 81*bb3d2afbSZhang Yubing u32 trsv_reg0204; 82*bb3d2afbSZhang Yubing u32 trsv_reg0205; 83*bb3d2afbSZhang Yubing u32 trsv_reg0206; 84*bb3d2afbSZhang Yubing u32 trsv_reg0207; 85*bb3d2afbSZhang Yubing }; 86*bb3d2afbSZhang Yubing 872480f5daSFrank Wang struct rockchip_udphy; 882480f5daSFrank Wang 892480f5daSFrank Wang struct rockchip_udphy_cfg { 902480f5daSFrank Wang /* resets to be requested */ 912480f5daSFrank Wang const char * const *rst_list; 922480f5daSFrank Wang int num_rsts; 932480f5daSFrank Wang 942480f5daSFrank Wang struct udphy_grf_cfg grfcfg; 95*bb3d2afbSZhang Yubing const struct dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; 962480f5daSFrank Wang int (*combophy_init)(struct rockchip_udphy *udphy); 97*bb3d2afbSZhang Yubing int (*dp_phy_set_rate)(struct rockchip_udphy *udphy, 98*bb3d2afbSZhang Yubing struct phy_configure_opts_dp *dp); 99*bb3d2afbSZhang Yubing int (*dp_phy_set_voltages)(struct rockchip_udphy *udphy, 100*bb3d2afbSZhang Yubing struct phy_configure_opts_dp *dp); 101*bb3d2afbSZhang Yubing int (*dplane_enable)(struct rockchip_udphy *udphy, int dp_lanes); 102*bb3d2afbSZhang Yubing int (*dplane_select)(struct rockchip_udphy *udphy); 1032480f5daSFrank Wang }; 1042480f5daSFrank Wang 1052480f5daSFrank Wang struct rockchip_udphy { 1062480f5daSFrank Wang struct udevice *dev; 1072480f5daSFrank Wang struct regmap *pma_regmap; 1082480f5daSFrank Wang struct regmap *u2phygrf; 1092480f5daSFrank Wang struct regmap *udphygrf; 1102480f5daSFrank Wang struct regmap *usbgrf; 1112480f5daSFrank Wang struct regmap *vogrf; 1122480f5daSFrank Wang // struct typec_switch *sw; 1132480f5daSFrank Wang // struct typec_mux *mux; 1142480f5daSFrank Wang 1152480f5daSFrank Wang /* clocks and rests */ 1162480f5daSFrank Wang struct reset_ctl *rsts; 1172480f5daSFrank Wang 1182480f5daSFrank Wang /* PHY status management */ 1192480f5daSFrank Wang bool flip; 1202480f5daSFrank Wang bool mode_change; 1212480f5daSFrank Wang u8 mode; 1222480f5daSFrank Wang u8 status; 1232480f5daSFrank Wang 1242480f5daSFrank Wang /* utilized for USB */ 1252480f5daSFrank Wang bool hs; /* flag for high-speed */ 1262480f5daSFrank Wang 1272480f5daSFrank Wang /* utilized for DP */ 1282480f5daSFrank Wang struct gpio_desc *sbu1_dc_gpio; 1292480f5daSFrank Wang struct gpio_desc *sbu2_dc_gpio; 1302480f5daSFrank Wang u32 lane_mux_sel[4]; 1312480f5daSFrank Wang u32 dp_lane_sel[4]; 1322480f5daSFrank Wang u32 dp_aux_dout_sel; 1332480f5daSFrank Wang u32 dp_aux_din_sel; 134*bb3d2afbSZhang Yubing u8 bw; /* dp bandwidth */ 1352480f5daSFrank Wang int id; 1362480f5daSFrank Wang 1372480f5daSFrank Wang /* PHY const config */ 1382480f5daSFrank Wang const struct rockchip_udphy_cfg *cfgs; 1392480f5daSFrank Wang }; 1402480f5daSFrank Wang 141*bb3d2afbSZhang Yubing static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { 142*bb3d2afbSZhang Yubing /* voltage swing 0, pre-emphasis 0->3 */ 143*bb3d2afbSZhang Yubing { 144*bb3d2afbSZhang Yubing { 0x20, 0x10, 0x42, 0xe5 }, 145*bb3d2afbSZhang Yubing { 0x26, 0x14, 0x42, 0xe5 }, 146*bb3d2afbSZhang Yubing { 0x29, 0x18, 0x42, 0xe5 }, 147*bb3d2afbSZhang Yubing { 0x2b, 0x1c, 0x43, 0xe7 }, 148*bb3d2afbSZhang Yubing }, 149*bb3d2afbSZhang Yubing 150*bb3d2afbSZhang Yubing /* voltage swing 1, pre-emphasis 0->2 */ 151*bb3d2afbSZhang Yubing { 152*bb3d2afbSZhang Yubing { 0x23, 0x10, 0x42, 0xe7 }, 153*bb3d2afbSZhang Yubing { 0x2a, 0x17, 0x43, 0xe7 }, 154*bb3d2afbSZhang Yubing { 0x2b, 0x1a, 0x43, 0xe7 }, 155*bb3d2afbSZhang Yubing }, 156*bb3d2afbSZhang Yubing 157*bb3d2afbSZhang Yubing /* voltage swing 2, pre-emphasis 0->1 */ 158*bb3d2afbSZhang Yubing { 159*bb3d2afbSZhang Yubing { 0x27, 0x10, 0x42, 0xe7 }, 160*bb3d2afbSZhang Yubing { 0x2b, 0x17, 0x43, 0xe7 }, 161*bb3d2afbSZhang Yubing }, 162*bb3d2afbSZhang Yubing 163*bb3d2afbSZhang Yubing /* voltage swing 3, pre-emphasis 0 */ 164*bb3d2afbSZhang Yubing { 165*bb3d2afbSZhang Yubing { 0x29, 0x10, 0x43, 0xe7 }, 166*bb3d2afbSZhang Yubing }, 167*bb3d2afbSZhang Yubing }; 168*bb3d2afbSZhang Yubing 169*bb3d2afbSZhang Yubing static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { 170*bb3d2afbSZhang Yubing /* voltage swing 0, pre-emphasis 0->3 */ 171*bb3d2afbSZhang Yubing { 172*bb3d2afbSZhang Yubing { 0x21, 0x10, 0x42, 0xe5 }, 173*bb3d2afbSZhang Yubing { 0x26, 0x14, 0x42, 0xe5 }, 174*bb3d2afbSZhang Yubing { 0x26, 0x16, 0x43, 0xe5 }, 175*bb3d2afbSZhang Yubing { 0x2a, 0x19, 0x43, 0xe7 }, 176*bb3d2afbSZhang Yubing }, 177*bb3d2afbSZhang Yubing 178*bb3d2afbSZhang Yubing /* voltage swing 1, pre-emphasis 0->2 */ 179*bb3d2afbSZhang Yubing { 180*bb3d2afbSZhang Yubing { 0x24, 0x10, 0x42, 0xe7 }, 181*bb3d2afbSZhang Yubing { 0x2a, 0x17, 0x43, 0xe7 }, 182*bb3d2afbSZhang Yubing { 0x2b, 0x1a, 0x43, 0xe7 }, 183*bb3d2afbSZhang Yubing }, 184*bb3d2afbSZhang Yubing 185*bb3d2afbSZhang Yubing /* voltage swing 2, pre-emphasis 0->1 */ 186*bb3d2afbSZhang Yubing { 187*bb3d2afbSZhang Yubing { 0x28, 0x10, 0x42, 0xe7 }, 188*bb3d2afbSZhang Yubing { 0x2b, 0x17, 0x43, 0xe7 }, 189*bb3d2afbSZhang Yubing }, 190*bb3d2afbSZhang Yubing 191*bb3d2afbSZhang Yubing /* voltage swing 3, pre-emphasis 0 */ 192*bb3d2afbSZhang Yubing { 193*bb3d2afbSZhang Yubing { 0x28, 0x10, 0x43, 0xe7 }, 194*bb3d2afbSZhang Yubing }, 195*bb3d2afbSZhang Yubing }; 196*bb3d2afbSZhang Yubing 197*bb3d2afbSZhang Yubing static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { 198*bb3d2afbSZhang Yubing /* voltage swing 0, pre-emphasis 0->3 */ 199*bb3d2afbSZhang Yubing { 200*bb3d2afbSZhang Yubing { 0x21, 0x10, 0x42, 0xe5 }, 201*bb3d2afbSZhang Yubing { 0x26, 0x14, 0x42, 0xe5 }, 202*bb3d2afbSZhang Yubing { 0x26, 0x16, 0x43, 0xe5 }, 203*bb3d2afbSZhang Yubing { 0x29, 0x18, 0x43, 0xe7 }, 204*bb3d2afbSZhang Yubing }, 205*bb3d2afbSZhang Yubing 206*bb3d2afbSZhang Yubing /* voltage swing 1, pre-emphasis 0->2 */ 207*bb3d2afbSZhang Yubing { 208*bb3d2afbSZhang Yubing { 0x24, 0x10, 0x42, 0xe7 }, 209*bb3d2afbSZhang Yubing { 0x2a, 0x18, 0x43, 0xe7 }, 210*bb3d2afbSZhang Yubing { 0x2b, 0x1b, 0x43, 0xe7 } 211*bb3d2afbSZhang Yubing }, 212*bb3d2afbSZhang Yubing 213*bb3d2afbSZhang Yubing /* voltage swing 2, pre-emphasis 0->1 */ 214*bb3d2afbSZhang Yubing { 215*bb3d2afbSZhang Yubing { 0x27, 0x10, 0x42, 0xe7 }, 216*bb3d2afbSZhang Yubing { 0x2b, 0x18, 0x43, 0xe7 } 217*bb3d2afbSZhang Yubing }, 218*bb3d2afbSZhang Yubing 219*bb3d2afbSZhang Yubing /* voltage swing 3, pre-emphasis 0 */ 220*bb3d2afbSZhang Yubing { 221*bb3d2afbSZhang Yubing { 0x28, 0x10, 0x43, 0xe7 }, 222*bb3d2afbSZhang Yubing }, 223*bb3d2afbSZhang Yubing }; 224*bb3d2afbSZhang Yubing 2252480f5daSFrank Wang static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = { 2262480f5daSFrank Wang {0x0090, 0x68}, {0x0094, 0x68}, 2272480f5daSFrank Wang {0x0128, 0x24}, {0x012c, 0x44}, 2282480f5daSFrank Wang {0x0130, 0x3f}, {0x0134, 0x44}, 2292480f5daSFrank Wang {0x015c, 0xa9}, {0x0160, 0x71}, 2302480f5daSFrank Wang {0x0164, 0x71}, {0x0168, 0xa9}, 2312480f5daSFrank Wang {0x0174, 0xa9}, {0x0178, 0x71}, 2322480f5daSFrank Wang {0x017c, 0x71}, {0x0180, 0xa9}, 2332480f5daSFrank Wang {0x018c, 0x41}, {0x0190, 0x00}, 2342480f5daSFrank Wang {0x0194, 0x05}, {0x01ac, 0x2a}, 2352480f5daSFrank Wang {0x01b0, 0x17}, {0x01b4, 0x17}, 2362480f5daSFrank Wang {0x01b8, 0x2a}, {0x01c8, 0x04}, 2372480f5daSFrank Wang {0x01cc, 0x08}, {0x01d0, 0x08}, 2382480f5daSFrank Wang {0x01d4, 0x04}, {0x01d8, 0x20}, 2392480f5daSFrank Wang {0x01dc, 0x01}, {0x01e0, 0x09}, 2402480f5daSFrank Wang {0x01e4, 0x03}, {0x01f0, 0x29}, 2412480f5daSFrank Wang {0x01f4, 0x02}, {0x01f8, 0x02}, 2422480f5daSFrank Wang {0x01fc, 0x29}, {0x0208, 0x2a}, 2432480f5daSFrank Wang {0x020c, 0x17}, {0x0210, 0x17}, 2442480f5daSFrank Wang {0x0214, 0x2a}, {0x0224, 0x20}, 245*bb3d2afbSZhang Yubing {0x03f0, 0x0a}, {0x03f4, 0x07}, 246*bb3d2afbSZhang Yubing {0x03f8, 0x07}, {0x03fc, 0x0c}, 247*bb3d2afbSZhang Yubing {0x0404, 0x12}, {0x0408, 0x1a}, 248*bb3d2afbSZhang Yubing {0x040c, 0x1a}, {0x0410, 0x3f}, 2492480f5daSFrank Wang {0x0ce0, 0x68}, {0x0ce8, 0xd0}, 2502480f5daSFrank Wang {0x0cf0, 0x87}, {0x0cf8, 0x70}, 2512480f5daSFrank Wang {0x0d00, 0x70}, {0x0d08, 0xa9}, 2522480f5daSFrank Wang {0x1ce0, 0x68}, {0x1ce8, 0xd0}, 2532480f5daSFrank Wang {0x1cf0, 0x87}, {0x1cf8, 0x70}, 2542480f5daSFrank Wang {0x1d00, 0x70}, {0x1d08, 0xa9}, 2552480f5daSFrank Wang {0x0a3c, 0xd0}, {0x0a44, 0xd0}, 2562480f5daSFrank Wang {0x0a48, 0x01}, {0x0a4c, 0x0d}, 2572480f5daSFrank Wang {0x0a54, 0xe0}, {0x0a5c, 0xe0}, 2582480f5daSFrank Wang {0x0a64, 0xa8}, {0x1a3c, 0xd0}, 2592480f5daSFrank Wang {0x1a44, 0xd0}, {0x1a48, 0x01}, 2602480f5daSFrank Wang {0x1a4c, 0x0d}, {0x1a54, 0xe0}, 2612480f5daSFrank Wang {0x1a5c, 0xe0}, {0x1a64, 0xa8} 2622480f5daSFrank Wang }; 2632480f5daSFrank Wang 2642480f5daSFrank Wang static const struct reg_sequence rk3588_udphy_init_sequence[] = { 2652480f5daSFrank Wang {0x0104, 0x44}, {0x0234, 0xE8}, 2662480f5daSFrank Wang {0x0248, 0x44}, {0x028C, 0x18}, 2672480f5daSFrank Wang {0x081C, 0xE5}, {0x0878, 0x00}, 2682480f5daSFrank Wang {0x0994, 0x1C}, {0x0AF0, 0x00}, 2692480f5daSFrank Wang {0x181C, 0xE5}, {0x1878, 0x00}, 2702480f5daSFrank Wang {0x1994, 0x1C}, {0x1AF0, 0x00}, 2712480f5daSFrank Wang {0x0428, 0x60}, {0x0D58, 0x33}, 2722480f5daSFrank Wang {0x1D58, 0x33}, {0x0990, 0x74}, 2732480f5daSFrank Wang {0x0D64, 0x17}, {0x08C8, 0x13}, 2742480f5daSFrank Wang {0x1990, 0x74}, {0x1D64, 0x17}, 2752480f5daSFrank Wang {0x18C8, 0x13}, {0x0D90, 0x40}, 2762480f5daSFrank Wang {0x0DA8, 0x40}, {0x0DC0, 0x40}, 2772480f5daSFrank Wang {0x0DD8, 0x40}, {0x1D90, 0x40}, 2782480f5daSFrank Wang {0x1DA8, 0x40}, {0x1DC0, 0x40}, 2792480f5daSFrank Wang {0x1DD8, 0x40}, {0x03C0, 0x30}, 2802480f5daSFrank Wang {0x03C4, 0x06}, {0x0E10, 0x00}, 2812480f5daSFrank Wang {0x1E10, 0x00}, {0x043C, 0x0F}, 2822480f5daSFrank Wang {0x0D2C, 0xFF}, {0x1D2C, 0xFF}, 2832480f5daSFrank Wang {0x0D34, 0x0F}, {0x1D34, 0x0F}, 2842480f5daSFrank Wang {0x08FC, 0x2A}, {0x0914, 0x28}, 2852480f5daSFrank Wang {0x0A30, 0x03}, {0x0E38, 0x05}, 2862480f5daSFrank Wang {0x0ECC, 0x27}, {0x0ED0, 0x22}, 2872480f5daSFrank Wang {0x0ED4, 0x26}, {0x18FC, 0x2A}, 2882480f5daSFrank Wang {0x1914, 0x28}, {0x1A30, 0x03}, 2892480f5daSFrank Wang {0x1E38, 0x05}, {0x1ECC, 0x27}, 2902480f5daSFrank Wang {0x1ED0, 0x22}, {0x1ED4, 0x26}, 2912480f5daSFrank Wang {0x0048, 0x0F}, {0x0060, 0x3C}, 2922480f5daSFrank Wang {0x0064, 0xF7}, {0x006C, 0x20}, 2932480f5daSFrank Wang {0x0070, 0x7D}, {0x0074, 0x68}, 2942480f5daSFrank Wang {0x0AF4, 0x1A}, {0x1AF4, 0x1A}, 2952480f5daSFrank Wang {0x0440, 0x3F}, {0x10D4, 0x08}, 2962480f5daSFrank Wang {0x20D4, 0x08}, {0x00D4, 0x30}, 2972480f5daSFrank Wang {0x0024, 0x6e}, 2982480f5daSFrank Wang }; 2992480f5daSFrank Wang 3002480f5daSFrank Wang static inline int grfreg_write(struct regmap *base, 3012480f5daSFrank Wang const struct udphy_grf_reg *reg, bool en) 3022480f5daSFrank Wang { 3032480f5daSFrank Wang u32 val, mask, tmp; 3042480f5daSFrank Wang 3052480f5daSFrank Wang tmp = en ? reg->enable : reg->disable; 3062480f5daSFrank Wang mask = GENMASK(reg->bitend, reg->bitstart); 3072480f5daSFrank Wang val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); 3082480f5daSFrank Wang 3092480f5daSFrank Wang return regmap_write(base, reg->offset, val); 3102480f5daSFrank Wang } 3112480f5daSFrank Wang 3122480f5daSFrank Wang static int __regmap_multi_reg_write(struct regmap *map, 3132480f5daSFrank Wang const struct reg_sequence *regs, int num_regs) 3142480f5daSFrank Wang { 3152480f5daSFrank Wang int i, ret = 0; 3162480f5daSFrank Wang 3172480f5daSFrank Wang for (i = 0; i < num_regs; i++) { 3182480f5daSFrank Wang ret = regmap_write(map, regs[i].reg, regs[i].def); 3192480f5daSFrank Wang 3202480f5daSFrank Wang if (regs[i].delay_us) 3212480f5daSFrank Wang udelay(regs[i].delay_us); 3222480f5daSFrank Wang } 3232480f5daSFrank Wang 3242480f5daSFrank Wang return ret; 3252480f5daSFrank Wang } 3262480f5daSFrank Wang 3272480f5daSFrank Wang static int udphy_clk_init(struct rockchip_udphy *udphy, struct udevice *dev) 3282480f5daSFrank Wang { 3292480f5daSFrank Wang return 0; 3302480f5daSFrank Wang } 3312480f5daSFrank Wang 3322480f5daSFrank Wang static int udphy_reset_init(struct rockchip_udphy *udphy, struct udevice *dev) 3332480f5daSFrank Wang { 3342480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 3352480f5daSFrank Wang int idx; 3362480f5daSFrank Wang int ret; 3372480f5daSFrank Wang 3382480f5daSFrank Wang udphy->rsts = devm_kcalloc(dev, cfg->num_rsts, 3392480f5daSFrank Wang sizeof(*udphy->rsts), GFP_KERNEL); 3402480f5daSFrank Wang if (!udphy->rsts) 3412480f5daSFrank Wang return -ENOMEM; 3422480f5daSFrank Wang 3432480f5daSFrank Wang for (idx = 0; idx < cfg->num_rsts; idx++) { 3442480f5daSFrank Wang const char *name = cfg->rst_list[idx]; 3452480f5daSFrank Wang 3462480f5daSFrank Wang ret = reset_get_by_name(dev, name, &udphy->rsts[idx]); 3472480f5daSFrank Wang if (ret) { 3482480f5daSFrank Wang dev_err(dev, "failed to get %s reset\n", name); 3492480f5daSFrank Wang goto err; 3502480f5daSFrank Wang } 3512480f5daSFrank Wang 3522480f5daSFrank Wang reset_assert(&udphy->rsts[idx]); 3532480f5daSFrank Wang } 3542480f5daSFrank Wang 3552480f5daSFrank Wang return 0; 3562480f5daSFrank Wang 3572480f5daSFrank Wang err: 3582480f5daSFrank Wang devm_kfree(dev, udphy->rsts); 3592480f5daSFrank Wang return ret; 3602480f5daSFrank Wang } 3612480f5daSFrank Wang 3622480f5daSFrank Wang static int udphy_get_rst_idx(const char * const *list, int num, char *name) 3632480f5daSFrank Wang { 3642480f5daSFrank Wang int idx; 3652480f5daSFrank Wang 3662480f5daSFrank Wang for (idx = 0; idx < num; idx++) { 3672480f5daSFrank Wang if (!strcmp(list[idx], name)) 3682480f5daSFrank Wang return idx; 3692480f5daSFrank Wang } 3702480f5daSFrank Wang 3712480f5daSFrank Wang return -EINVAL; 3722480f5daSFrank Wang } 3732480f5daSFrank Wang 3742480f5daSFrank Wang static int udphy_reset_assert(struct rockchip_udphy *udphy, char *name) 3752480f5daSFrank Wang { 3762480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 3772480f5daSFrank Wang int idx; 3782480f5daSFrank Wang 3792480f5daSFrank Wang idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); 3802480f5daSFrank Wang if (idx < 0) 3812480f5daSFrank Wang return idx; 3822480f5daSFrank Wang 3832480f5daSFrank Wang return reset_assert(&udphy->rsts[idx]); 3842480f5daSFrank Wang } 3852480f5daSFrank Wang 3862480f5daSFrank Wang static int udphy_reset_deassert(struct rockchip_udphy *udphy, char *name) 3872480f5daSFrank Wang { 3882480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 3892480f5daSFrank Wang int idx; 3902480f5daSFrank Wang 3912480f5daSFrank Wang idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); 3922480f5daSFrank Wang if (idx < 0) 3932480f5daSFrank Wang return idx; 3942480f5daSFrank Wang 3952480f5daSFrank Wang return reset_deassert(&udphy->rsts[idx]); 3962480f5daSFrank Wang } 3972480f5daSFrank Wang 3982480f5daSFrank Wang static void udphy_u3_port_disable(struct rockchip_udphy *udphy, u8 disable) 3992480f5daSFrank Wang { 4002480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 4012480f5daSFrank Wang const struct udphy_grf_reg *preg; 4022480f5daSFrank Wang 4032480f5daSFrank Wang preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; 4042480f5daSFrank Wang grfreg_write(udphy->usbgrf, preg, disable); 4052480f5daSFrank Wang } 4062480f5daSFrank Wang 4072480f5daSFrank Wang __maybe_unused 4082480f5daSFrank Wang static void udphy_usb_bvalid_enable(struct rockchip_udphy *udphy, u8 enable) 4092480f5daSFrank Wang { 4102480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 4112480f5daSFrank Wang 4122480f5daSFrank Wang grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); 4132480f5daSFrank Wang grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); 4142480f5daSFrank Wang } 4152480f5daSFrank Wang 4162480f5daSFrank Wang /* 4172480f5daSFrank Wang * In usb/dp combo phy driver, here are 2 ways to mapping lanes. 4182480f5daSFrank Wang * 4192480f5daSFrank Wang * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) 4202480f5daSFrank Wang * --------------------------------------------------------------------------- 4212480f5daSFrank Wang * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 4222480f5daSFrank Wang * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 4232480f5daSFrank Wang * C/E(Normal) dpln3 dpln2 dpln0 dpln1 4242480f5daSFrank Wang * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 4252480f5daSFrank Wang * D/F(Normal) usbrx usbtx dpln0 dpln1 4262480f5daSFrank Wang * D/F(Flip ) dpln0 dpln1 usbrx usbtx 4272480f5daSFrank Wang * A(Normal ) dpln3 dpln1 dpln2 dpln0 4282480f5daSFrank Wang * A(Flip ) dpln2 dpln0 dpln3 dpln1 4292480f5daSFrank Wang * B(Normal ) usbrx usbtx dpln1 dpln0 4302480f5daSFrank Wang * B(Flip ) dpln1 dpln0 usbrx usbtx 4312480f5daSFrank Wang * --------------------------------------------------------------------------- 4322480f5daSFrank Wang * 4332480f5daSFrank Wang * 2 Mapping the lanes in dtsi 4342480f5daSFrank Wang * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = <x x x x>; 4352480f5daSFrank Wang * sample as follow: 4362480f5daSFrank Wang * --------------------------------------------------------------------------- 4372480f5daSFrank Wang * B11-B10 A2-A3 A11-A10 B2-B3 4382480f5daSFrank Wang * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 4392480f5daSFrank Wang * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 4402480f5daSFrank Wang * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 4412480f5daSFrank Wang * --------------------------------------------------------------------------- 4422480f5daSFrank Wang * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x x>; 4432480f5daSFrank Wang * sample as follow: 4442480f5daSFrank Wang * --------------------------------------------------------------------------- 4452480f5daSFrank Wang * B11-B10 A2-A3 A11-A10 B2-B3 4462480f5daSFrank Wang * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 4472480f5daSFrank Wang * <0 1> dpln0 dpln1 usbrx usbtx 4482480f5daSFrank Wang * <2 3> usbrx usbtx dpln0 dpln1 4492480f5daSFrank Wang * --------------------------------------------------------------------------- 4502480f5daSFrank Wang */ 451*bb3d2afbSZhang Yubing static int udphy_dplane_select(struct rockchip_udphy *udphy) 452*bb3d2afbSZhang Yubing { 453*bb3d2afbSZhang Yubing const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 454*bb3d2afbSZhang Yubing 455*bb3d2afbSZhang Yubing if (cfg->dplane_select) 456*bb3d2afbSZhang Yubing return cfg->dplane_select(udphy); 457*bb3d2afbSZhang Yubing 458*bb3d2afbSZhang Yubing return 0; 459*bb3d2afbSZhang Yubing } 460*bb3d2afbSZhang Yubing 461*bb3d2afbSZhang Yubing static int udphy_dplane_get(struct rockchip_udphy *udphy) 462*bb3d2afbSZhang Yubing { 463*bb3d2afbSZhang Yubing int dp_lanes; 464*bb3d2afbSZhang Yubing 465*bb3d2afbSZhang Yubing switch (udphy->mode) { 466*bb3d2afbSZhang Yubing case UDPHY_MODE_DP: 467*bb3d2afbSZhang Yubing dp_lanes = 4; 468*bb3d2afbSZhang Yubing break; 469*bb3d2afbSZhang Yubing case UDPHY_MODE_DP_USB: 470*bb3d2afbSZhang Yubing dp_lanes = 2; 471*bb3d2afbSZhang Yubing break; 472*bb3d2afbSZhang Yubing case UDPHY_MODE_USB: 473*bb3d2afbSZhang Yubing /* fallthrough; */ 474*bb3d2afbSZhang Yubing default: 475*bb3d2afbSZhang Yubing dp_lanes = 0; 476*bb3d2afbSZhang Yubing break; 477*bb3d2afbSZhang Yubing } 478*bb3d2afbSZhang Yubing 479*bb3d2afbSZhang Yubing return dp_lanes; 480*bb3d2afbSZhang Yubing } 481*bb3d2afbSZhang Yubing 482*bb3d2afbSZhang Yubing static int udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) 483*bb3d2afbSZhang Yubing { 484*bb3d2afbSZhang Yubing const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 485*bb3d2afbSZhang Yubing int ret = 0; 486*bb3d2afbSZhang Yubing 487*bb3d2afbSZhang Yubing if (cfg->dplane_enable) 488*bb3d2afbSZhang Yubing ret = cfg->dplane_enable(udphy, dp_lanes); 489*bb3d2afbSZhang Yubing 490*bb3d2afbSZhang Yubing return ret; 491*bb3d2afbSZhang Yubing } 492*bb3d2afbSZhang Yubing 4932480f5daSFrank Wang 4942480f5daSFrank Wang __maybe_unused 4952480f5daSFrank Wang static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy) 4962480f5daSFrank Wang { 4972480f5daSFrank Wang if (udphy->flip) { 4982480f5daSFrank Wang udphy->dp_lane_sel[0] = 0; 4992480f5daSFrank Wang udphy->dp_lane_sel[1] = 1; 5002480f5daSFrank Wang udphy->dp_lane_sel[2] = 3; 5012480f5daSFrank Wang udphy->dp_lane_sel[3] = 2; 5022480f5daSFrank Wang udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; 5032480f5daSFrank Wang udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; 5042480f5daSFrank Wang udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; 5052480f5daSFrank Wang udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; 5062480f5daSFrank Wang udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; 5072480f5daSFrank Wang udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; 5082480f5daSFrank Wang } else { 5092480f5daSFrank Wang udphy->dp_lane_sel[0] = 2; 5102480f5daSFrank Wang udphy->dp_lane_sel[1] = 3; 5112480f5daSFrank Wang udphy->dp_lane_sel[2] = 1; 5122480f5daSFrank Wang udphy->dp_lane_sel[3] = 0; 5132480f5daSFrank Wang udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; 5142480f5daSFrank Wang udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; 5152480f5daSFrank Wang udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; 5162480f5daSFrank Wang udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; 5172480f5daSFrank Wang udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; 5182480f5daSFrank Wang udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; 5192480f5daSFrank Wang } 5202480f5daSFrank Wang 5212480f5daSFrank Wang udphy->mode = UDPHY_MODE_DP_USB; 5222480f5daSFrank Wang 5232480f5daSFrank Wang return 0; 5242480f5daSFrank Wang } 5252480f5daSFrank Wang 5262480f5daSFrank Wang static int udphy_setup(struct rockchip_udphy *udphy) 5272480f5daSFrank Wang { 5282480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 5292480f5daSFrank Wang int ret = 0; 5302480f5daSFrank Wang 5312480f5daSFrank Wang if (cfg->combophy_init) { 5322480f5daSFrank Wang ret = cfg->combophy_init(udphy); 5332480f5daSFrank Wang if (ret) 5342480f5daSFrank Wang dev_err(udphy->dev, "failed to init combophy\n"); 5352480f5daSFrank Wang } 5362480f5daSFrank Wang 5372480f5daSFrank Wang return ret; 5382480f5daSFrank Wang } 5392480f5daSFrank Wang 5402480f5daSFrank Wang static int udphy_disable(struct rockchip_udphy *udphy) 5412480f5daSFrank Wang { 5422480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 5432480f5daSFrank Wang int i; 5442480f5daSFrank Wang 5452480f5daSFrank Wang for (i = 0; i < cfg->num_rsts; i++) 5462480f5daSFrank Wang reset_assert(&udphy->rsts[i]); 5472480f5daSFrank Wang 5482480f5daSFrank Wang return 0; 5492480f5daSFrank Wang } 5502480f5daSFrank Wang 5512480f5daSFrank Wang static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, const struct device_node *np) 5522480f5daSFrank Wang { 5532480f5daSFrank Wang struct property *prop; 5542480f5daSFrank Wang int ret, i, len, num_lanes; 5552480f5daSFrank Wang 5562480f5daSFrank Wang prop = of_find_property(np, "rockchip,dp-lane-mux", &len); 5572480f5daSFrank Wang if (!prop) { 5582480f5daSFrank Wang dev_dbg(udphy->dev, "failed to find dp lane mux, following dp alt mode\n"); 5592480f5daSFrank Wang udphy->mode = UDPHY_MODE_USB; 5602480f5daSFrank Wang return 0; 5612480f5daSFrank Wang } 5622480f5daSFrank Wang 5632480f5daSFrank Wang num_lanes = len / sizeof(u32); 5642480f5daSFrank Wang 5652480f5daSFrank Wang if (num_lanes != 2 && num_lanes != 4) { 5662480f5daSFrank Wang dev_err(udphy->dev, "invalid number of lane mux\n"); 5672480f5daSFrank Wang return -EINVAL; 5682480f5daSFrank Wang } 5692480f5daSFrank Wang 5702480f5daSFrank Wang ret = of_read_u32_array(np, "rockchip,dp-lane-mux", udphy->dp_lane_sel, num_lanes); 5712480f5daSFrank Wang if (ret) { 5722480f5daSFrank Wang dev_err(udphy->dev, "get dp lane mux failed\n"); 5732480f5daSFrank Wang return -EINVAL; 5742480f5daSFrank Wang } 5752480f5daSFrank Wang 5762480f5daSFrank Wang for (i = 0; i < num_lanes; i++) { 5772480f5daSFrank Wang int j; 5782480f5daSFrank Wang 5792480f5daSFrank Wang if (udphy->dp_lane_sel[i] > 3) { 5802480f5daSFrank Wang dev_err(udphy->dev, "lane mux between 0 and 3, exceeding the range\n"); 5812480f5daSFrank Wang return -EINVAL; 5822480f5daSFrank Wang } 5832480f5daSFrank Wang 5842480f5daSFrank Wang udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; 5852480f5daSFrank Wang 5862480f5daSFrank Wang for (j = i + 1; j < num_lanes; j++) { 5872480f5daSFrank Wang if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) { 5882480f5daSFrank Wang dev_err(udphy->dev, "set repeat lane mux value\n"); 5892480f5daSFrank Wang return -EINVAL; 5902480f5daSFrank Wang } 5912480f5daSFrank Wang } 5922480f5daSFrank Wang } 5932480f5daSFrank Wang 5942480f5daSFrank Wang udphy->mode = UDPHY_MODE_DP; 5952480f5daSFrank Wang if (num_lanes == 2) 5962480f5daSFrank Wang udphy->mode |= UDPHY_MODE_USB; 5972480f5daSFrank Wang 5982480f5daSFrank Wang return 0; 5992480f5daSFrank Wang } 6002480f5daSFrank Wang 6012480f5daSFrank Wang static int udphy_parse_dt(struct rockchip_udphy *udphy, struct udevice *dev) 6022480f5daSFrank Wang { 6032480f5daSFrank Wang const struct device_node *np = ofnode_to_np(dev->node); 6042480f5daSFrank Wang enum usb_device_speed maximum_speed; 6052480f5daSFrank Wang int ret; 6062480f5daSFrank Wang 6072480f5daSFrank Wang udphy->u2phygrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,u2phy-grf"); 6082480f5daSFrank Wang if (IS_ERR(udphy->u2phygrf)) { 6092480f5daSFrank Wang if (PTR_ERR(udphy->u2phygrf) == -ENODEV) { 6102480f5daSFrank Wang dev_warn(dev, "missing u2phy-grf dt node\n"); 6112480f5daSFrank Wang udphy->u2phygrf = NULL; 6122480f5daSFrank Wang } else { 6132480f5daSFrank Wang return PTR_ERR(udphy->u2phygrf); 6142480f5daSFrank Wang } 6152480f5daSFrank Wang } 6162480f5daSFrank Wang 6172480f5daSFrank Wang udphy->udphygrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,usbdpphy-grf"); 6182480f5daSFrank Wang if (IS_ERR(udphy->udphygrf)) { 6192480f5daSFrank Wang if (PTR_ERR(udphy->udphygrf) == -ENODEV) { 6202480f5daSFrank Wang dev_warn(dev, "missing usbdpphy-grf dt node\n"); 6212480f5daSFrank Wang udphy->udphygrf = NULL; 6222480f5daSFrank Wang } else { 6232480f5daSFrank Wang return PTR_ERR(udphy->udphygrf); 6242480f5daSFrank Wang } 6252480f5daSFrank Wang } 6262480f5daSFrank Wang 6272480f5daSFrank Wang udphy->usbgrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,usb-grf"); 6282480f5daSFrank Wang if (IS_ERR(udphy->usbgrf)) { 6292480f5daSFrank Wang if (PTR_ERR(udphy->usbgrf) == -ENODEV) { 6302480f5daSFrank Wang dev_warn(dev, "missing usb-grf dt node\n"); 6312480f5daSFrank Wang udphy->usbgrf = NULL; 6322480f5daSFrank Wang } else { 6332480f5daSFrank Wang return PTR_ERR(udphy->usbgrf); 6342480f5daSFrank Wang } 6352480f5daSFrank Wang } 6362480f5daSFrank Wang 6372480f5daSFrank Wang udphy->vogrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,vo-grf"); 6382480f5daSFrank Wang if (IS_ERR(udphy->vogrf)) { 6392480f5daSFrank Wang if (PTR_ERR(udphy->vogrf) == -ENODEV) { 6402480f5daSFrank Wang dev_warn(dev, "missing vo-grf dt node\n"); 6412480f5daSFrank Wang udphy->vogrf = NULL; 6422480f5daSFrank Wang } else { 6432480f5daSFrank Wang return PTR_ERR(udphy->vogrf); 6442480f5daSFrank Wang } 6452480f5daSFrank Wang } 6462480f5daSFrank Wang 6472480f5daSFrank Wang ret = udphy_parse_lane_mux_data(udphy, np); 6482480f5daSFrank Wang if (ret) 6492480f5daSFrank Wang return ret; 6502480f5daSFrank Wang 6512480f5daSFrank Wang if (dev_read_prop(dev, "maximum-speed", NULL)) { 6522480f5daSFrank Wang maximum_speed = usb_get_maximum_speed(dev->node); 6532480f5daSFrank Wang udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false; 6542480f5daSFrank Wang } 6552480f5daSFrank Wang 6562480f5daSFrank Wang ret = udphy_clk_init(udphy, dev); 6572480f5daSFrank Wang if (ret) 6582480f5daSFrank Wang return ret; 6592480f5daSFrank Wang 6602480f5daSFrank Wang ret = udphy_reset_init(udphy, dev); 6612480f5daSFrank Wang if (ret) 6622480f5daSFrank Wang return ret; 6632480f5daSFrank Wang 6642480f5daSFrank Wang return 0; 6652480f5daSFrank Wang } 6662480f5daSFrank Wang 6672480f5daSFrank Wang static int udphy_power_on(struct rockchip_udphy *udphy, u8 mode) 6682480f5daSFrank Wang { 6692480f5daSFrank Wang int ret; 6702480f5daSFrank Wang 6712480f5daSFrank Wang if (!(udphy->mode & mode)) { 672*bb3d2afbSZhang Yubing printf("%s: mode 0x%02x is not support\n", udphy->dev->name, 673*bb3d2afbSZhang Yubing mode); 674*bb3d2afbSZhang Yubing return -EINVAL; 6752480f5daSFrank Wang } 6762480f5daSFrank Wang 6772480f5daSFrank Wang if (udphy->status == UDPHY_MODE_NONE) { 6782480f5daSFrank Wang udphy->mode_change = false; 6792480f5daSFrank Wang ret = udphy_setup(udphy); 6802480f5daSFrank Wang if (ret) 6812480f5daSFrank Wang return ret; 6822480f5daSFrank Wang 6832480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 6842480f5daSFrank Wang udphy_u3_port_disable(udphy, false); 6852480f5daSFrank Wang } else if (udphy->mode_change) { 6862480f5daSFrank Wang udphy->mode_change = false; 6872480f5daSFrank Wang udphy->status = UDPHY_MODE_NONE; 6882480f5daSFrank Wang if (udphy->mode == UDPHY_MODE_DP) 6892480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 6902480f5daSFrank Wang 6912480f5daSFrank Wang ret = udphy_disable(udphy); 6922480f5daSFrank Wang if (ret) 6932480f5daSFrank Wang return ret; 6942480f5daSFrank Wang ret = udphy_setup(udphy); 6952480f5daSFrank Wang if (ret) 6962480f5daSFrank Wang return ret; 6972480f5daSFrank Wang } 6982480f5daSFrank Wang 6992480f5daSFrank Wang udphy->status |= mode; 7002480f5daSFrank Wang 7012480f5daSFrank Wang return 0; 7022480f5daSFrank Wang } 7032480f5daSFrank Wang 7042480f5daSFrank Wang static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode) 7052480f5daSFrank Wang { 7062480f5daSFrank Wang int ret; 7072480f5daSFrank Wang 7082480f5daSFrank Wang if (!(udphy->mode & mode)) { 7092480f5daSFrank Wang dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); 7102480f5daSFrank Wang return 0; 7112480f5daSFrank Wang } 7122480f5daSFrank Wang 7132480f5daSFrank Wang if (!udphy->status) 7142480f5daSFrank Wang return 0; 7152480f5daSFrank Wang 7162480f5daSFrank Wang udphy->status &= ~mode; 7172480f5daSFrank Wang 7182480f5daSFrank Wang if (udphy->status == UDPHY_MODE_NONE) { 7192480f5daSFrank Wang ret = udphy_disable(udphy); 7202480f5daSFrank Wang if (ret) 7212480f5daSFrank Wang return ret; 7222480f5daSFrank Wang } 7232480f5daSFrank Wang 7242480f5daSFrank Wang return 0; 7252480f5daSFrank Wang } 7262480f5daSFrank Wang 727*bb3d2afbSZhang Yubing static int rockchip_dpphy_power_on(struct phy *phy) 728*bb3d2afbSZhang Yubing { 729*bb3d2afbSZhang Yubing struct udevice *parent = phy->dev->parent; 730*bb3d2afbSZhang Yubing struct rockchip_udphy *udphy = dev_get_priv(parent); 731*bb3d2afbSZhang Yubing int ret, dp_lanes; 732*bb3d2afbSZhang Yubing 733*bb3d2afbSZhang Yubing dp_lanes = udphy_dplane_get(udphy); 734*bb3d2afbSZhang Yubing phy->attrs.bus_width = dp_lanes; 735*bb3d2afbSZhang Yubing 736*bb3d2afbSZhang Yubing ret = udphy_power_on(udphy, UDPHY_MODE_DP); 737*bb3d2afbSZhang Yubing if (ret) 738*bb3d2afbSZhang Yubing return ret; 739*bb3d2afbSZhang Yubing 740*bb3d2afbSZhang Yubing ret = udphy_dplane_enable(udphy, dp_lanes); 741*bb3d2afbSZhang Yubing if (ret) 742*bb3d2afbSZhang Yubing return ret; 743*bb3d2afbSZhang Yubing 744*bb3d2afbSZhang Yubing return udphy_dplane_select(udphy); 745*bb3d2afbSZhang Yubing } 746*bb3d2afbSZhang Yubing 747*bb3d2afbSZhang Yubing static int rockchip_dpphy_power_off(struct phy *phy) 748*bb3d2afbSZhang Yubing { 749*bb3d2afbSZhang Yubing struct udevice *parent = phy->dev->parent; 750*bb3d2afbSZhang Yubing struct rockchip_udphy *udphy = dev_get_priv(parent); 751*bb3d2afbSZhang Yubing int ret; 752*bb3d2afbSZhang Yubing 753*bb3d2afbSZhang Yubing ret = udphy_dplane_enable(udphy, 0); 754*bb3d2afbSZhang Yubing if (ret) 755*bb3d2afbSZhang Yubing return ret; 756*bb3d2afbSZhang Yubing 757*bb3d2afbSZhang Yubing return udphy_power_off(udphy, UDPHY_MODE_DP); 758*bb3d2afbSZhang Yubing } 759*bb3d2afbSZhang Yubing 760*bb3d2afbSZhang Yubing static int rockchip_dpphy_verify_config(struct rockchip_udphy *udphy, 761*bb3d2afbSZhang Yubing struct phy_configure_opts_dp *dp) 762*bb3d2afbSZhang Yubing { 763*bb3d2afbSZhang Yubing int i; 764*bb3d2afbSZhang Yubing 765*bb3d2afbSZhang Yubing /* If changing link rate was required, verify it's supported. */ 766*bb3d2afbSZhang Yubing if (dp->set_rate) { 767*bb3d2afbSZhang Yubing switch (dp->link_rate) { 768*bb3d2afbSZhang Yubing case 1620: 769*bb3d2afbSZhang Yubing case 2700: 770*bb3d2afbSZhang Yubing case 5400: 771*bb3d2afbSZhang Yubing case 8100: 772*bb3d2afbSZhang Yubing /* valid bit rate */ 773*bb3d2afbSZhang Yubing break; 774*bb3d2afbSZhang Yubing default: 775*bb3d2afbSZhang Yubing return -EINVAL; 776*bb3d2afbSZhang Yubing } 777*bb3d2afbSZhang Yubing } 778*bb3d2afbSZhang Yubing 779*bb3d2afbSZhang Yubing /* Verify lane count. */ 780*bb3d2afbSZhang Yubing switch (dp->lanes) { 781*bb3d2afbSZhang Yubing case 1: 782*bb3d2afbSZhang Yubing case 2: 783*bb3d2afbSZhang Yubing case 4: 784*bb3d2afbSZhang Yubing /* valid lane count. */ 785*bb3d2afbSZhang Yubing break; 786*bb3d2afbSZhang Yubing default: 787*bb3d2afbSZhang Yubing return -EINVAL; 788*bb3d2afbSZhang Yubing } 789*bb3d2afbSZhang Yubing 790*bb3d2afbSZhang Yubing /* 791*bb3d2afbSZhang Yubing * If changing voltages is required, check swing and pre-emphasis 792*bb3d2afbSZhang Yubing * levels, per-lane. 793*bb3d2afbSZhang Yubing */ 794*bb3d2afbSZhang Yubing if (dp->set_voltages) { 795*bb3d2afbSZhang Yubing /* Lane count verified previously. */ 796*bb3d2afbSZhang Yubing for (i = 0; i < dp->lanes; i++) { 797*bb3d2afbSZhang Yubing if (dp->voltage[i] > 3 || dp->pre[i] > 3) 798*bb3d2afbSZhang Yubing return -EINVAL; 799*bb3d2afbSZhang Yubing 800*bb3d2afbSZhang Yubing /* 801*bb3d2afbSZhang Yubing * Sum of voltage swing and pre-emphasis levels cannot 802*bb3d2afbSZhang Yubing * exceed 3. 803*bb3d2afbSZhang Yubing */ 804*bb3d2afbSZhang Yubing if (dp->voltage[i] + dp->pre[i] > 3) 805*bb3d2afbSZhang Yubing return -EINVAL; 806*bb3d2afbSZhang Yubing } 807*bb3d2afbSZhang Yubing } 808*bb3d2afbSZhang Yubing 809*bb3d2afbSZhang Yubing return 0; 810*bb3d2afbSZhang Yubing } 811*bb3d2afbSZhang Yubing 812*bb3d2afbSZhang Yubing static int rockchip_dpphy_configure(struct phy *phy, 813*bb3d2afbSZhang Yubing union phy_configure_opts *opts) 814*bb3d2afbSZhang Yubing { 815*bb3d2afbSZhang Yubing struct udevice *parent = phy->dev->parent; 816*bb3d2afbSZhang Yubing struct rockchip_udphy *udphy = dev_get_priv(parent); 817*bb3d2afbSZhang Yubing const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 818*bb3d2afbSZhang Yubing int ret; 819*bb3d2afbSZhang Yubing 820*bb3d2afbSZhang Yubing ret = rockchip_dpphy_verify_config(udphy, &opts->dp); 821*bb3d2afbSZhang Yubing if (ret) 822*bb3d2afbSZhang Yubing return ret; 823*bb3d2afbSZhang Yubing 824*bb3d2afbSZhang Yubing if (opts->dp.set_rate && cfg->dp_phy_set_rate) { 825*bb3d2afbSZhang Yubing ret = cfg->dp_phy_set_rate(udphy, &opts->dp); 826*bb3d2afbSZhang Yubing if (ret) { 827*bb3d2afbSZhang Yubing printf("%s: rockchip_hdptx_phy_set_rate failed\n", 828*bb3d2afbSZhang Yubing udphy->dev->name); 829*bb3d2afbSZhang Yubing return ret; 830*bb3d2afbSZhang Yubing } 831*bb3d2afbSZhang Yubing } 832*bb3d2afbSZhang Yubing 833*bb3d2afbSZhang Yubing if (opts->dp.set_voltages && cfg->dp_phy_set_voltages) { 834*bb3d2afbSZhang Yubing ret = cfg->dp_phy_set_voltages(udphy, &opts->dp); 835*bb3d2afbSZhang Yubing if (ret) { 836*bb3d2afbSZhang Yubing printf("%s: rockchip_dp_phy_set_voltages failed\n", 837*bb3d2afbSZhang Yubing udphy->dev->name); 838*bb3d2afbSZhang Yubing return ret; 839*bb3d2afbSZhang Yubing } 840*bb3d2afbSZhang Yubing } 841*bb3d2afbSZhang Yubing 842*bb3d2afbSZhang Yubing return 0; 843*bb3d2afbSZhang Yubing } 844*bb3d2afbSZhang Yubing 845*bb3d2afbSZhang Yubing static const struct phy_ops rockchip_dpphy_ops = { 846*bb3d2afbSZhang Yubing .power_on = rockchip_dpphy_power_on, 847*bb3d2afbSZhang Yubing .power_off = rockchip_dpphy_power_off, 848*bb3d2afbSZhang Yubing .configure = rockchip_dpphy_configure, 849*bb3d2afbSZhang Yubing }; 850*bb3d2afbSZhang Yubing 8512480f5daSFrank Wang static int rockchip_u3phy_init(struct phy *phy) 8522480f5daSFrank Wang { 8532480f5daSFrank Wang struct udevice *parent = phy->dev->parent; 8542480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(parent); 8552480f5daSFrank Wang 8562480f5daSFrank Wang /* DP only or high-speed, disable U3 port */ 8572480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { 8582480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 8592480f5daSFrank Wang return 0; 8602480f5daSFrank Wang } 8612480f5daSFrank Wang 8622480f5daSFrank Wang return udphy_power_on(udphy, UDPHY_MODE_USB); 8632480f5daSFrank Wang } 8642480f5daSFrank Wang 8652480f5daSFrank Wang static int rockchip_u3phy_exit(struct phy *phy) 8662480f5daSFrank Wang { 8672480f5daSFrank Wang struct udevice *parent = phy->dev->parent; 8682480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(parent); 8692480f5daSFrank Wang 8702480f5daSFrank Wang /* DP only or high-speed */ 8712480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) 8722480f5daSFrank Wang return 0; 8732480f5daSFrank Wang 8742480f5daSFrank Wang return udphy_power_off(udphy, UDPHY_MODE_USB); 8752480f5daSFrank Wang } 8762480f5daSFrank Wang 8772480f5daSFrank Wang static const struct phy_ops rockchip_u3phy_ops = { 8782480f5daSFrank Wang .init = rockchip_u3phy_init, 8792480f5daSFrank Wang .exit = rockchip_u3phy_exit, 8802480f5daSFrank Wang }; 8812480f5daSFrank Wang 8822480f5daSFrank Wang int rockchip_u3phy_uboot_init(void) 8832480f5daSFrank Wang { 8842480f5daSFrank Wang struct udevice *udev; 8852480f5daSFrank Wang struct rockchip_udphy *udphy; 8862480f5daSFrank Wang int ret; 8872480f5daSFrank Wang 8882480f5daSFrank Wang ret = uclass_get_device_by_driver(UCLASS_PHY, 8892480f5daSFrank Wang DM_GET_DRIVER(rockchip_udphy_u3_port), 8902480f5daSFrank Wang &udev); 8912480f5daSFrank Wang if (ret) { 8922480f5daSFrank Wang pr_err("%s: get u3-port failed: %d\n", __func__, ret); 8932480f5daSFrank Wang return ret; 8942480f5daSFrank Wang } 8952480f5daSFrank Wang 8962480f5daSFrank Wang /* DP only or high-speed, disable U3 port */ 8972480f5daSFrank Wang udphy = dev_get_priv(udev->parent); 8982480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { 8992480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 9002480f5daSFrank Wang return 0; 9012480f5daSFrank Wang } 9022480f5daSFrank Wang 9032480f5daSFrank Wang return udphy_power_on(udphy, UDPHY_MODE_USB); 9042480f5daSFrank Wang } 9052480f5daSFrank Wang 9062480f5daSFrank Wang static int rockchip_udphy_probe(struct udevice *dev) 9072480f5daSFrank Wang { 9082480f5daSFrank Wang const struct device_node *np = ofnode_to_np(dev->node); 9092480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(dev); 9102480f5daSFrank Wang const struct rockchip_udphy_cfg *phy_cfgs; 9112480f5daSFrank Wang int id, ret; 9122480f5daSFrank Wang 9132480f5daSFrank Wang udphy->dev = dev; 9142480f5daSFrank Wang 9152480f5daSFrank Wang id = of_alias_get_id(np, "usbdp"); 9162480f5daSFrank Wang if (id < 0) 9172480f5daSFrank Wang id = 0; 9182480f5daSFrank Wang udphy->id = id; 9192480f5daSFrank Wang 9202480f5daSFrank Wang phy_cfgs = (const struct rockchip_udphy_cfg *) dev_get_driver_data(dev); 9212480f5daSFrank Wang if (!phy_cfgs) { 9222480f5daSFrank Wang dev_err(dev, "unable to get phy_cfgs\n"); 9232480f5daSFrank Wang return -EINVAL; 9242480f5daSFrank Wang } 9252480f5daSFrank Wang udphy->cfgs = phy_cfgs; 9262480f5daSFrank Wang 9272480f5daSFrank Wang ret = regmap_init_mem(dev, &udphy->pma_regmap); 9282480f5daSFrank Wang if (ret) 9292480f5daSFrank Wang return ret; 9302480f5daSFrank Wang udphy->pma_regmap->base += UDPHY_PMA; 9312480f5daSFrank Wang 9322480f5daSFrank Wang ret = udphy_parse_dt(udphy, dev); 9332480f5daSFrank Wang if (ret) 9342480f5daSFrank Wang return ret; 9352480f5daSFrank Wang 9362480f5daSFrank Wang return 0; 9372480f5daSFrank Wang } 9382480f5daSFrank Wang 9392480f5daSFrank Wang static int rockchip_udphy_bind(struct udevice *parent) 9402480f5daSFrank Wang { 9412480f5daSFrank Wang struct udevice *child; 9422480f5daSFrank Wang ofnode subnode; 9432480f5daSFrank Wang const char *node_name; 9442480f5daSFrank Wang int ret; 9452480f5daSFrank Wang 9462480f5daSFrank Wang dev_for_each_subnode(subnode, parent) { 9472480f5daSFrank Wang if (!ofnode_valid(subnode)) { 9482480f5daSFrank Wang printf("%s: no subnode for %s", __func__, parent->name); 9492480f5daSFrank Wang return -ENXIO; 9502480f5daSFrank Wang } 9512480f5daSFrank Wang 9522480f5daSFrank Wang node_name = ofnode_get_name(subnode); 9532480f5daSFrank Wang debug("%s: subnode %s\n", __func__, node_name); 9542480f5daSFrank Wang 9552480f5daSFrank Wang if (!strcasecmp(node_name, "u3-port")) { 9562480f5daSFrank Wang ret = device_bind_driver_to_node(parent, 9572480f5daSFrank Wang "rockchip_udphy_u3_port", 9582480f5daSFrank Wang node_name, subnode, &child); 9592480f5daSFrank Wang if (ret) { 9602480f5daSFrank Wang printf("%s: '%s' cannot bind its driver\n", 9612480f5daSFrank Wang __func__, node_name); 9622480f5daSFrank Wang return ret; 9632480f5daSFrank Wang } 964*bb3d2afbSZhang Yubing } else if (!strcasecmp(node_name, "dp-port")) { 965*bb3d2afbSZhang Yubing ret = device_bind_driver_to_node(parent, 966*bb3d2afbSZhang Yubing "rockchip_udphy_dp_port", 967*bb3d2afbSZhang Yubing node_name, subnode, &child); 968*bb3d2afbSZhang Yubing if (ret) { 969*bb3d2afbSZhang Yubing printf("%s: '%s' cannot bind its driver\n", 970*bb3d2afbSZhang Yubing __func__, node_name); 971*bb3d2afbSZhang Yubing return ret; 972*bb3d2afbSZhang Yubing } 9732480f5daSFrank Wang } 9742480f5daSFrank Wang } 9752480f5daSFrank Wang 9762480f5daSFrank Wang return 0; 9772480f5daSFrank Wang } 9782480f5daSFrank Wang 9792480f5daSFrank Wang static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy) 9802480f5daSFrank Wang { 9812480f5daSFrank Wang int ret; 9822480f5daSFrank Wang 9832480f5daSFrank Wang /* configure phy reference clock */ 9842480f5daSFrank Wang ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_24m_refclk_cfg, 9852480f5daSFrank Wang ARRAY_SIZE(rk3588_udphy_24m_refclk_cfg)); 9862480f5daSFrank Wang if (ret) 9872480f5daSFrank Wang return ret; 9882480f5daSFrank Wang 9892480f5daSFrank Wang return 0; 9902480f5daSFrank Wang } 9912480f5daSFrank Wang 9922480f5daSFrank Wang static int rk3588_udphy_status_check(struct rockchip_udphy *udphy) 9932480f5daSFrank Wang { 9942480f5daSFrank Wang unsigned int val; 9952480f5daSFrank Wang int ret; 9962480f5daSFrank Wang 9972480f5daSFrank Wang /* LCPLL check */ 9982480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 9992480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, 10002480f5daSFrank Wang val, (val & CMN_ANA_LCPLL_AFC_DONE) && 10012480f5daSFrank Wang (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100); 10022480f5daSFrank Wang if (ret) { 10032480f5daSFrank Wang dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); 10042480f5daSFrank Wang return ret; 10052480f5daSFrank Wang } 10062480f5daSFrank Wang } 10072480f5daSFrank Wang 10082480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 10092480f5daSFrank Wang if (!udphy->flip) { 10102480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, 10112480f5daSFrank Wang TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, 10122480f5daSFrank Wang val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, 10132480f5daSFrank Wang 200, 100); 10142480f5daSFrank Wang if (ret) 10152480f5daSFrank Wang dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); 10162480f5daSFrank Wang } else { 10172480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, 10182480f5daSFrank Wang TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, 10192480f5daSFrank Wang val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, 10202480f5daSFrank Wang 200, 100); 10212480f5daSFrank Wang if (ret) 10222480f5daSFrank Wang dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); 10232480f5daSFrank Wang } 10242480f5daSFrank Wang } 10252480f5daSFrank Wang 10262480f5daSFrank Wang return 0; 10272480f5daSFrank Wang } 10282480f5daSFrank Wang 10292480f5daSFrank Wang static int rk3588_udphy_init(struct rockchip_udphy *udphy) 10302480f5daSFrank Wang { 10312480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 10322480f5daSFrank Wang int ret; 10332480f5daSFrank Wang 10342480f5daSFrank Wang /* enable rx lfps for usb */ 10352480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 10362480f5daSFrank Wang grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); 10372480f5daSFrank Wang 10382480f5daSFrank Wang /* Step 1: power on pma and deassert apb rstn */ 10392480f5daSFrank Wang grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); 10402480f5daSFrank Wang 10412480f5daSFrank Wang udphy_reset_deassert(udphy, "pma_apb"); 10422480f5daSFrank Wang udphy_reset_deassert(udphy, "pcs_apb"); 10432480f5daSFrank Wang 10442480f5daSFrank Wang /* Step 2: set init sequence and phy refclk */ 10452480f5daSFrank Wang ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_init_sequence, 10462480f5daSFrank Wang ARRAY_SIZE(rk3588_udphy_init_sequence)); 10472480f5daSFrank Wang if (ret) { 10482480f5daSFrank Wang dev_err(udphy->dev, "init sequence set error %d\n", ret); 10492480f5daSFrank Wang goto assert_apb; 10502480f5daSFrank Wang } 10512480f5daSFrank Wang 10522480f5daSFrank Wang ret = rk3588_udphy_refclk_set(udphy); 10532480f5daSFrank Wang if (ret) { 10542480f5daSFrank Wang dev_err(udphy->dev, "refclk set error %d\n", ret); 10552480f5daSFrank Wang goto assert_apb; 10562480f5daSFrank Wang } 10572480f5daSFrank Wang 10582480f5daSFrank Wang /* Step 3: configure lane mux */ 10592480f5daSFrank Wang regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, 10602480f5daSFrank Wang CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, 10612480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | 10622480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | 10632480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | 10642480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | 10652480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); 10662480f5daSFrank Wang 10672480f5daSFrank Wang /* Step 4: deassert init rstn and wait for 200ns from datasheet */ 10682480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 10692480f5daSFrank Wang udphy_reset_deassert(udphy, "init"); 10702480f5daSFrank Wang 10712480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_DP) { 10722480f5daSFrank Wang regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 10732480f5daSFrank Wang CMN_DP_INIT_RSTN, 10742480f5daSFrank Wang FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); 10752480f5daSFrank Wang } 10762480f5daSFrank Wang 10772480f5daSFrank Wang udelay(1); 10782480f5daSFrank Wang 10792480f5daSFrank Wang /* Step 5: deassert cmn/lane rstn */ 10802480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 10812480f5daSFrank Wang udphy_reset_deassert(udphy, "cmn"); 10822480f5daSFrank Wang udphy_reset_deassert(udphy, "lane"); 10832480f5daSFrank Wang } 10842480f5daSFrank Wang 10852480f5daSFrank Wang /* Step 6: wait for lock done of pll */ 10862480f5daSFrank Wang ret = rk3588_udphy_status_check(udphy); 10872480f5daSFrank Wang if (ret) 10882480f5daSFrank Wang goto assert_phy; 10892480f5daSFrank Wang 10902480f5daSFrank Wang return 0; 10912480f5daSFrank Wang 10922480f5daSFrank Wang assert_phy: 10932480f5daSFrank Wang udphy_reset_assert(udphy, "init"); 10942480f5daSFrank Wang udphy_reset_assert(udphy, "cmn"); 10952480f5daSFrank Wang udphy_reset_assert(udphy, "lane"); 10962480f5daSFrank Wang 10972480f5daSFrank Wang assert_apb: 10982480f5daSFrank Wang udphy_reset_assert(udphy, "pma_apb"); 10992480f5daSFrank Wang udphy_reset_assert(udphy, "pcs_apb"); 11002480f5daSFrank Wang return ret; 11012480f5daSFrank Wang } 11022480f5daSFrank Wang 1103*bb3d2afbSZhang Yubing static int rk3588_udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) 1104*bb3d2afbSZhang Yubing { 1105*bb3d2afbSZhang Yubing int i; 1106*bb3d2afbSZhang Yubing u32 val = 0; 1107*bb3d2afbSZhang Yubing 1108*bb3d2afbSZhang Yubing for (i = 0; i < dp_lanes; i++) 1109*bb3d2afbSZhang Yubing val |= BIT(udphy->dp_lane_sel[i]); 1110*bb3d2afbSZhang Yubing 1111*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, 1112*bb3d2afbSZhang Yubing FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); 1113*bb3d2afbSZhang Yubing 1114*bb3d2afbSZhang Yubing if (!dp_lanes) 1115*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 1116*bb3d2afbSZhang Yubing CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); 1117*bb3d2afbSZhang Yubing 1118*bb3d2afbSZhang Yubing return 0; 1119*bb3d2afbSZhang Yubing } 1120*bb3d2afbSZhang Yubing 1121*bb3d2afbSZhang Yubing static int rk3588_udphy_dplane_select(struct rockchip_udphy *udphy) 1122*bb3d2afbSZhang Yubing { 1123*bb3d2afbSZhang Yubing u32 value = 0; 1124*bb3d2afbSZhang Yubing 1125*bb3d2afbSZhang Yubing switch (udphy->mode) { 1126*bb3d2afbSZhang Yubing case UDPHY_MODE_DP: 1127*bb3d2afbSZhang Yubing value |= 2 << udphy->dp_lane_sel[2] * 2; 1128*bb3d2afbSZhang Yubing value |= 3 << udphy->dp_lane_sel[3] * 2; 1129*bb3d2afbSZhang Yubing case UDPHY_MODE_DP_USB: 1130*bb3d2afbSZhang Yubing value |= 0 << udphy->dp_lane_sel[0] * 2; 1131*bb3d2afbSZhang Yubing value |= 1 << udphy->dp_lane_sel[1] * 2; 1132*bb3d2afbSZhang Yubing break; 1133*bb3d2afbSZhang Yubing case UDPHY_MODE_USB: 1134*bb3d2afbSZhang Yubing break; 1135*bb3d2afbSZhang Yubing default: 1136*bb3d2afbSZhang Yubing break; 1137*bb3d2afbSZhang Yubing } 1138*bb3d2afbSZhang Yubing 1139*bb3d2afbSZhang Yubing regmap_write(udphy->vogrf, udphy->id ? RK3588_GRF_VO0_CON2 : RK3588_GRF_VO0_CON0, 1140*bb3d2afbSZhang Yubing ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | 1141*bb3d2afbSZhang Yubing FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | 1142*bb3d2afbSZhang Yubing FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); 1143*bb3d2afbSZhang Yubing 1144*bb3d2afbSZhang Yubing return 0; 1145*bb3d2afbSZhang Yubing } 1146*bb3d2afbSZhang Yubing 1147*bb3d2afbSZhang Yubing static int rk3588_dp_phy_set_rate(struct rockchip_udphy *udphy, 1148*bb3d2afbSZhang Yubing struct phy_configure_opts_dp *dp) 1149*bb3d2afbSZhang Yubing { 1150*bb3d2afbSZhang Yubing u32 val; 1151*bb3d2afbSZhang Yubing int ret; 1152*bb3d2afbSZhang Yubing 1153*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 1154*bb3d2afbSZhang Yubing CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); 1155*bb3d2afbSZhang Yubing 1156*bb3d2afbSZhang Yubing switch (dp->link_rate) { 1157*bb3d2afbSZhang Yubing case 1620: 1158*bb3d2afbSZhang Yubing udphy->bw = DP_BW_RBR; 1159*bb3d2afbSZhang Yubing break; 1160*bb3d2afbSZhang Yubing case 2700: 1161*bb3d2afbSZhang Yubing udphy->bw = DP_BW_HBR; 1162*bb3d2afbSZhang Yubing break; 1163*bb3d2afbSZhang Yubing case 5400: 1164*bb3d2afbSZhang Yubing udphy->bw = DP_BW_HBR2; 1165*bb3d2afbSZhang Yubing break; 1166*bb3d2afbSZhang Yubing case 8100: 1167*bb3d2afbSZhang Yubing udphy->bw = DP_BW_HBR3; 1168*bb3d2afbSZhang Yubing break; 1169*bb3d2afbSZhang Yubing default: 1170*bb3d2afbSZhang Yubing return -EINVAL; 1171*bb3d2afbSZhang Yubing } 1172*bb3d2afbSZhang Yubing 1173*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, 1174*bb3d2afbSZhang Yubing FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); 1175*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, 1176*bb3d2afbSZhang Yubing FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc)); 1177*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, 1178*bb3d2afbSZhang Yubing FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); 1179*bb3d2afbSZhang Yubing 1180*bb3d2afbSZhang Yubing ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, 1181*bb3d2afbSZhang Yubing FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && 1182*bb3d2afbSZhang Yubing FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), 1183*bb3d2afbSZhang Yubing 0, 1000); 1184*bb3d2afbSZhang Yubing if (ret) { 1185*bb3d2afbSZhang Yubing printf("ROPLL is not lock\n"); 1186*bb3d2afbSZhang Yubing return ret; 1187*bb3d2afbSZhang Yubing } 1188*bb3d2afbSZhang Yubing 1189*bb3d2afbSZhang Yubing return 0; 1190*bb3d2afbSZhang Yubing } 1191*bb3d2afbSZhang Yubing 1192*bb3d2afbSZhang Yubing static void rk3588_dp_phy_set_voltage(struct rockchip_udphy *udphy, u8 bw, 1193*bb3d2afbSZhang Yubing u32 voltage, u32 pre, u32 lane) 1194*bb3d2afbSZhang Yubing { 1195*bb3d2afbSZhang Yubing u32 offset = 0x800 * lane; 1196*bb3d2afbSZhang Yubing u32 val; 1197*bb3d2afbSZhang Yubing const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 1198*bb3d2afbSZhang Yubing const struct dp_tx_drv_ctrl (*dp_ctrl)[4]; 1199*bb3d2afbSZhang Yubing 1200*bb3d2afbSZhang Yubing dp_ctrl = cfg->dp_tx_ctrl_cfg[bw]; 1201*bb3d2afbSZhang Yubing val = dp_ctrl[voltage][pre].trsv_reg0204; 1202*bb3d2afbSZhang Yubing regmap_write(udphy->pma_regmap, 0x0810 + offset, val); 1203*bb3d2afbSZhang Yubing 1204*bb3d2afbSZhang Yubing val = dp_ctrl[voltage][pre].trsv_reg0205; 1205*bb3d2afbSZhang Yubing regmap_write(udphy->pma_regmap, 0x0814 + offset, val); 1206*bb3d2afbSZhang Yubing 1207*bb3d2afbSZhang Yubing val = dp_ctrl[voltage][pre].trsv_reg0206; 1208*bb3d2afbSZhang Yubing regmap_write(udphy->pma_regmap, 0x0818 + offset, val); 1209*bb3d2afbSZhang Yubing 1210*bb3d2afbSZhang Yubing val = dp_ctrl[voltage][pre].trsv_reg0207; 1211*bb3d2afbSZhang Yubing regmap_write(udphy->pma_regmap, 0x081c + offset, val); 1212*bb3d2afbSZhang Yubing } 1213*bb3d2afbSZhang Yubing 1214*bb3d2afbSZhang Yubing static int rk3588_dp_phy_set_voltages(struct rockchip_udphy *udphy, 1215*bb3d2afbSZhang Yubing struct phy_configure_opts_dp *dp) 1216*bb3d2afbSZhang Yubing { 1217*bb3d2afbSZhang Yubing u32 i, lane; 1218*bb3d2afbSZhang Yubing 1219*bb3d2afbSZhang Yubing for (i = 0; i < dp->lanes; i++) { 1220*bb3d2afbSZhang Yubing lane = udphy->dp_lane_sel[i]; 1221*bb3d2afbSZhang Yubing switch (dp->link_rate) { 1222*bb3d2afbSZhang Yubing case 1620: 1223*bb3d2afbSZhang Yubing case 2700: 1224*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), 1225*bb3d2afbSZhang Yubing LN_ANA_TX_SER_TXCLK_INV, 1226*bb3d2afbSZhang Yubing FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 1227*bb3d2afbSZhang Yubing udphy->lane_mux_sel[lane])); 1228*bb3d2afbSZhang Yubing break; 1229*bb3d2afbSZhang Yubing case 5400: 1230*bb3d2afbSZhang Yubing case 8100: 1231*bb3d2afbSZhang Yubing regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), 1232*bb3d2afbSZhang Yubing LN_ANA_TX_SER_TXCLK_INV, 1233*bb3d2afbSZhang Yubing FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); 1234*bb3d2afbSZhang Yubing break; 1235*bb3d2afbSZhang Yubing } 1236*bb3d2afbSZhang Yubing 1237*bb3d2afbSZhang Yubing rk3588_dp_phy_set_voltage(udphy, udphy->bw, dp->voltage[i], dp->pre[i], lane); 1238*bb3d2afbSZhang Yubing } 1239*bb3d2afbSZhang Yubing 1240*bb3d2afbSZhang Yubing return 0; 1241*bb3d2afbSZhang Yubing } 1242*bb3d2afbSZhang Yubing 12432480f5daSFrank Wang static const char * const rk3588_udphy_rst_l[] = { 12442480f5daSFrank Wang "init", "cmn", "lane", "pcs_apb", "pma_apb" 12452480f5daSFrank Wang }; 12462480f5daSFrank Wang 12472480f5daSFrank Wang static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = { 12482480f5daSFrank Wang .num_rsts = ARRAY_SIZE(rk3588_udphy_rst_l), 12492480f5daSFrank Wang .rst_list = rk3588_udphy_rst_l, 12502480f5daSFrank Wang .grfcfg = { 12512480f5daSFrank Wang /* u2phy-grf */ 12522480f5daSFrank Wang .bvalid_phy_con = { 0x0008, 1, 0, 0x2, 0x3 }, 12532480f5daSFrank Wang .bvalid_grf_con = { 0x0010, 3, 2, 0x2, 0x3 }, 12542480f5daSFrank Wang 12552480f5daSFrank Wang /* usb-grf */ 12562480f5daSFrank Wang .usb3otg0_cfg = { 0x001c, 15, 0, 0x1100, 0x0188 }, 12572480f5daSFrank Wang .usb3otg1_cfg = { 0x0034, 15, 0, 0x1100, 0x0188 }, 12582480f5daSFrank Wang 12592480f5daSFrank Wang /* usbdpphy-grf */ 12602480f5daSFrank Wang .low_pwrn = { 0x0004, 13, 13, 0, 1 }, 12612480f5daSFrank Wang .rx_lfps = { 0x0004, 14, 14, 0, 1 }, 12622480f5daSFrank Wang }, 1263*bb3d2afbSZhang Yubing .dp_tx_ctrl_cfg = { 1264*bb3d2afbSZhang Yubing rk3588_dp_tx_drv_ctrl_rbr_hbr, 1265*bb3d2afbSZhang Yubing rk3588_dp_tx_drv_ctrl_rbr_hbr, 1266*bb3d2afbSZhang Yubing rk3588_dp_tx_drv_ctrl_hbr2, 1267*bb3d2afbSZhang Yubing rk3588_dp_tx_drv_ctrl_hbr3, 1268*bb3d2afbSZhang Yubing }, 12692480f5daSFrank Wang .combophy_init = rk3588_udphy_init, 1270*bb3d2afbSZhang Yubing .dp_phy_set_rate = rk3588_dp_phy_set_rate, 1271*bb3d2afbSZhang Yubing .dp_phy_set_voltages = rk3588_dp_phy_set_voltages, 1272*bb3d2afbSZhang Yubing .dplane_enable = rk3588_udphy_dplane_enable, 1273*bb3d2afbSZhang Yubing .dplane_select = rk3588_udphy_dplane_select, 12742480f5daSFrank Wang }; 12752480f5daSFrank Wang 12762480f5daSFrank Wang static const struct udevice_id rockchip_udphy_dt_match[] = { 12772480f5daSFrank Wang { 12782480f5daSFrank Wang .compatible = "rockchip,rk3588-usbdp-phy", 12792480f5daSFrank Wang .data = (ulong)&rk3588_udphy_cfgs 12802480f5daSFrank Wang }, 12812480f5daSFrank Wang { /* sentinel */ } 12822480f5daSFrank Wang }; 12832480f5daSFrank Wang 12842480f5daSFrank Wang U_BOOT_DRIVER(rockchip_udphy_u3_port) = { 12852480f5daSFrank Wang .name = "rockchip_udphy_u3_port", 12862480f5daSFrank Wang .id = UCLASS_PHY, 12872480f5daSFrank Wang .ops = &rockchip_u3phy_ops, 12882480f5daSFrank Wang }; 12892480f5daSFrank Wang 1290*bb3d2afbSZhang Yubing U_BOOT_DRIVER(rockchip_udphy_dp_port) = { 1291*bb3d2afbSZhang Yubing .name = "rockchip_udphy_dp_port", 1292*bb3d2afbSZhang Yubing .id = UCLASS_PHY, 1293*bb3d2afbSZhang Yubing .ops = &rockchip_dpphy_ops, 1294*bb3d2afbSZhang Yubing }; 1295*bb3d2afbSZhang Yubing 12962480f5daSFrank Wang U_BOOT_DRIVER(rockchip_udphy) = { 12972480f5daSFrank Wang .name = "rockchip_udphy", 12982480f5daSFrank Wang .id = UCLASS_PHY, 12992480f5daSFrank Wang .of_match = rockchip_udphy_dt_match, 13002480f5daSFrank Wang .probe = rockchip_udphy_probe, 13012480f5daSFrank Wang .bind = rockchip_udphy_bind, 13022480f5daSFrank Wang .priv_auto_alloc_size = sizeof(struct rockchip_udphy), 13032480f5daSFrank Wang }; 1304