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