1*2480f5daSFrank Wang // SPDX-License-Identifier: GPL-2.0-or-later 2*2480f5daSFrank Wang /* 3*2480f5daSFrank Wang * Rockchip USBDP Combo PHY with Samsung IP block driver 4*2480f5daSFrank Wang * 5*2480f5daSFrank Wang * Copyright (C) 2021 Rockchip Electronics Co., Ltd 6*2480f5daSFrank Wang */ 7*2480f5daSFrank Wang 8*2480f5daSFrank Wang #include <common.h> 9*2480f5daSFrank Wang #include <clk.h> 10*2480f5daSFrank Wang #include <dm.h> 11*2480f5daSFrank Wang #include <dm/lists.h> 12*2480f5daSFrank Wang #include <dm/of.h> 13*2480f5daSFrank Wang #include <dm/of_access.h> 14*2480f5daSFrank Wang #include <generic-phy.h> 15*2480f5daSFrank Wang #include <linux/bitfield.h> 16*2480f5daSFrank Wang #include <linux/usb/ch9.h> 17*2480f5daSFrank Wang #include <linux/usb/otg.h> 18*2480f5daSFrank Wang #include <regmap.h> 19*2480f5daSFrank Wang #include <reset.h> 20*2480f5daSFrank Wang #include <syscon.h> 21*2480f5daSFrank Wang #include <asm/arch/clock.h> 22*2480f5daSFrank Wang #include <asm/arch/cpu.h> 23*2480f5daSFrank Wang 24*2480f5daSFrank Wang #include <linux/usb/phy-rockchip-usbdp.h> 25*2480f5daSFrank Wang 26*2480f5daSFrank Wang #define BIT_WRITEABLE_SHIFT 16 27*2480f5daSFrank Wang 28*2480f5daSFrank Wang enum { 29*2480f5daSFrank Wang UDPHY_MODE_NONE = 0, 30*2480f5daSFrank Wang UDPHY_MODE_USB = BIT(0), 31*2480f5daSFrank Wang UDPHY_MODE_DP = BIT(1), 32*2480f5daSFrank Wang UDPHY_MODE_DP_USB = BIT(1) | BIT(0), 33*2480f5daSFrank Wang }; 34*2480f5daSFrank Wang 35*2480f5daSFrank Wang struct udphy_grf_reg { 36*2480f5daSFrank Wang unsigned int offset; 37*2480f5daSFrank Wang unsigned int bitend; 38*2480f5daSFrank Wang unsigned int bitstart; 39*2480f5daSFrank Wang unsigned int disable; 40*2480f5daSFrank Wang unsigned int enable; 41*2480f5daSFrank Wang }; 42*2480f5daSFrank Wang 43*2480f5daSFrank Wang /** 44*2480f5daSFrank Wang * struct reg_sequence - An individual write from a sequence of writes. 45*2480f5daSFrank Wang * 46*2480f5daSFrank Wang * @reg: Register address. 47*2480f5daSFrank Wang * @def: Register value. 48*2480f5daSFrank Wang * @delay_us: Delay to be applied after the register write in microseconds 49*2480f5daSFrank Wang * 50*2480f5daSFrank Wang * Register/value pairs for sequences of writes with an optional delay in 51*2480f5daSFrank Wang * microseconds to be applied after each write. 52*2480f5daSFrank Wang */ 53*2480f5daSFrank Wang struct reg_sequence { 54*2480f5daSFrank Wang unsigned int reg; 55*2480f5daSFrank Wang unsigned int def; 56*2480f5daSFrank Wang unsigned int delay_us; 57*2480f5daSFrank Wang }; 58*2480f5daSFrank Wang 59*2480f5daSFrank Wang struct udphy_grf_cfg { 60*2480f5daSFrank Wang /* u2phy-grf */ 61*2480f5daSFrank Wang struct udphy_grf_reg bvalid_phy_con; 62*2480f5daSFrank Wang struct udphy_grf_reg bvalid_grf_con; 63*2480f5daSFrank Wang 64*2480f5daSFrank Wang /* usb-grf */ 65*2480f5daSFrank Wang struct udphy_grf_reg usb3otg0_cfg; 66*2480f5daSFrank Wang struct udphy_grf_reg usb3otg1_cfg; 67*2480f5daSFrank Wang 68*2480f5daSFrank Wang /* usbdpphy-grf */ 69*2480f5daSFrank Wang struct udphy_grf_reg low_pwrn; 70*2480f5daSFrank Wang struct udphy_grf_reg rx_lfps; 71*2480f5daSFrank Wang }; 72*2480f5daSFrank Wang 73*2480f5daSFrank Wang struct rockchip_udphy; 74*2480f5daSFrank Wang 75*2480f5daSFrank Wang struct rockchip_udphy_cfg { 76*2480f5daSFrank Wang /* resets to be requested */ 77*2480f5daSFrank Wang const char * const *rst_list; 78*2480f5daSFrank Wang int num_rsts; 79*2480f5daSFrank Wang 80*2480f5daSFrank Wang struct udphy_grf_cfg grfcfg; 81*2480f5daSFrank Wang int (*combophy_init)(struct rockchip_udphy *udphy); 82*2480f5daSFrank Wang }; 83*2480f5daSFrank Wang 84*2480f5daSFrank Wang struct rockchip_udphy { 85*2480f5daSFrank Wang struct udevice *dev; 86*2480f5daSFrank Wang struct regmap *pma_regmap; 87*2480f5daSFrank Wang struct regmap *u2phygrf; 88*2480f5daSFrank Wang struct regmap *udphygrf; 89*2480f5daSFrank Wang struct regmap *usbgrf; 90*2480f5daSFrank Wang struct regmap *vogrf; 91*2480f5daSFrank Wang // struct typec_switch *sw; 92*2480f5daSFrank Wang // struct typec_mux *mux; 93*2480f5daSFrank Wang 94*2480f5daSFrank Wang /* clocks and rests */ 95*2480f5daSFrank Wang struct reset_ctl *rsts; 96*2480f5daSFrank Wang 97*2480f5daSFrank Wang /* PHY status management */ 98*2480f5daSFrank Wang bool flip; 99*2480f5daSFrank Wang bool mode_change; 100*2480f5daSFrank Wang u8 mode; 101*2480f5daSFrank Wang u8 status; 102*2480f5daSFrank Wang 103*2480f5daSFrank Wang /* utilized for USB */ 104*2480f5daSFrank Wang bool hs; /* flag for high-speed */ 105*2480f5daSFrank Wang 106*2480f5daSFrank Wang /* utilized for DP */ 107*2480f5daSFrank Wang struct gpio_desc *sbu1_dc_gpio; 108*2480f5daSFrank Wang struct gpio_desc *sbu2_dc_gpio; 109*2480f5daSFrank Wang u32 lane_mux_sel[4]; 110*2480f5daSFrank Wang u32 dp_lane_sel[4]; 111*2480f5daSFrank Wang u32 dp_aux_dout_sel; 112*2480f5daSFrank Wang u32 dp_aux_din_sel; 113*2480f5daSFrank Wang int id; 114*2480f5daSFrank Wang 115*2480f5daSFrank Wang /* PHY const config */ 116*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfgs; 117*2480f5daSFrank Wang }; 118*2480f5daSFrank Wang 119*2480f5daSFrank Wang static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = { 120*2480f5daSFrank Wang {0x0090, 0x68}, {0x0094, 0x68}, 121*2480f5daSFrank Wang {0x0128, 0x24}, {0x012c, 0x44}, 122*2480f5daSFrank Wang {0x0130, 0x3f}, {0x0134, 0x44}, 123*2480f5daSFrank Wang {0x015c, 0xa9}, {0x0160, 0x71}, 124*2480f5daSFrank Wang {0x0164, 0x71}, {0x0168, 0xa9}, 125*2480f5daSFrank Wang {0x0174, 0xa9}, {0x0178, 0x71}, 126*2480f5daSFrank Wang {0x017c, 0x71}, {0x0180, 0xa9}, 127*2480f5daSFrank Wang {0x018c, 0x41}, {0x0190, 0x00}, 128*2480f5daSFrank Wang {0x0194, 0x05}, {0x01ac, 0x2a}, 129*2480f5daSFrank Wang {0x01b0, 0x17}, {0x01b4, 0x17}, 130*2480f5daSFrank Wang {0x01b8, 0x2a}, {0x01c8, 0x04}, 131*2480f5daSFrank Wang {0x01cc, 0x08}, {0x01d0, 0x08}, 132*2480f5daSFrank Wang {0x01d4, 0x04}, {0x01d8, 0x20}, 133*2480f5daSFrank Wang {0x01dc, 0x01}, {0x01e0, 0x09}, 134*2480f5daSFrank Wang {0x01e4, 0x03}, {0x01f0, 0x29}, 135*2480f5daSFrank Wang {0x01f4, 0x02}, {0x01f8, 0x02}, 136*2480f5daSFrank Wang {0x01fc, 0x29}, {0x0208, 0x2a}, 137*2480f5daSFrank Wang {0x020c, 0x17}, {0x0210, 0x17}, 138*2480f5daSFrank Wang {0x0214, 0x2a}, {0x0224, 0x20}, 139*2480f5daSFrank Wang {0x03f0, 0x0d}, {0x03f4, 0x09}, 140*2480f5daSFrank Wang {0x03f8, 0x09}, {0x03fc, 0x0d}, 141*2480f5daSFrank Wang {0x0404, 0x0e}, {0x0408, 0x14}, 142*2480f5daSFrank Wang {0x040c, 0x14}, {0x0410, 0x3b}, 143*2480f5daSFrank Wang {0x0ce0, 0x68}, {0x0ce8, 0xd0}, 144*2480f5daSFrank Wang {0x0cf0, 0x87}, {0x0cf8, 0x70}, 145*2480f5daSFrank Wang {0x0d00, 0x70}, {0x0d08, 0xa9}, 146*2480f5daSFrank Wang {0x1ce0, 0x68}, {0x1ce8, 0xd0}, 147*2480f5daSFrank Wang {0x1cf0, 0x87}, {0x1cf8, 0x70}, 148*2480f5daSFrank Wang {0x1d00, 0x70}, {0x1d08, 0xa9}, 149*2480f5daSFrank Wang {0x0a3c, 0xd0}, {0x0a44, 0xd0}, 150*2480f5daSFrank Wang {0x0a48, 0x01}, {0x0a4c, 0x0d}, 151*2480f5daSFrank Wang {0x0a54, 0xe0}, {0x0a5c, 0xe0}, 152*2480f5daSFrank Wang {0x0a64, 0xa8}, {0x1a3c, 0xd0}, 153*2480f5daSFrank Wang {0x1a44, 0xd0}, {0x1a48, 0x01}, 154*2480f5daSFrank Wang {0x1a4c, 0x0d}, {0x1a54, 0xe0}, 155*2480f5daSFrank Wang {0x1a5c, 0xe0}, {0x1a64, 0xa8} 156*2480f5daSFrank Wang }; 157*2480f5daSFrank Wang 158*2480f5daSFrank Wang static const struct reg_sequence rk3588_udphy_init_sequence[] = { 159*2480f5daSFrank Wang {0x0104, 0x44}, {0x0234, 0xE8}, 160*2480f5daSFrank Wang {0x0248, 0x44}, {0x028C, 0x18}, 161*2480f5daSFrank Wang {0x081C, 0xE5}, {0x0878, 0x00}, 162*2480f5daSFrank Wang {0x0994, 0x1C}, {0x0AF0, 0x00}, 163*2480f5daSFrank Wang {0x181C, 0xE5}, {0x1878, 0x00}, 164*2480f5daSFrank Wang {0x1994, 0x1C}, {0x1AF0, 0x00}, 165*2480f5daSFrank Wang {0x0428, 0x60}, {0x0D58, 0x33}, 166*2480f5daSFrank Wang {0x1D58, 0x33}, {0x0990, 0x74}, 167*2480f5daSFrank Wang {0x0D64, 0x17}, {0x08C8, 0x13}, 168*2480f5daSFrank Wang {0x1990, 0x74}, {0x1D64, 0x17}, 169*2480f5daSFrank Wang {0x18C8, 0x13}, {0x0D90, 0x40}, 170*2480f5daSFrank Wang {0x0DA8, 0x40}, {0x0DC0, 0x40}, 171*2480f5daSFrank Wang {0x0DD8, 0x40}, {0x1D90, 0x40}, 172*2480f5daSFrank Wang {0x1DA8, 0x40}, {0x1DC0, 0x40}, 173*2480f5daSFrank Wang {0x1DD8, 0x40}, {0x03C0, 0x30}, 174*2480f5daSFrank Wang {0x03C4, 0x06}, {0x0E10, 0x00}, 175*2480f5daSFrank Wang {0x1E10, 0x00}, {0x043C, 0x0F}, 176*2480f5daSFrank Wang {0x0D2C, 0xFF}, {0x1D2C, 0xFF}, 177*2480f5daSFrank Wang {0x0D34, 0x0F}, {0x1D34, 0x0F}, 178*2480f5daSFrank Wang {0x08FC, 0x2A}, {0x0914, 0x28}, 179*2480f5daSFrank Wang {0x0A30, 0x03}, {0x0E38, 0x05}, 180*2480f5daSFrank Wang {0x0ECC, 0x27}, {0x0ED0, 0x22}, 181*2480f5daSFrank Wang {0x0ED4, 0x26}, {0x18FC, 0x2A}, 182*2480f5daSFrank Wang {0x1914, 0x28}, {0x1A30, 0x03}, 183*2480f5daSFrank Wang {0x1E38, 0x05}, {0x1ECC, 0x27}, 184*2480f5daSFrank Wang {0x1ED0, 0x22}, {0x1ED4, 0x26}, 185*2480f5daSFrank Wang {0x0048, 0x0F}, {0x0060, 0x3C}, 186*2480f5daSFrank Wang {0x0064, 0xF7}, {0x006C, 0x20}, 187*2480f5daSFrank Wang {0x0070, 0x7D}, {0x0074, 0x68}, 188*2480f5daSFrank Wang {0x0AF4, 0x1A}, {0x1AF4, 0x1A}, 189*2480f5daSFrank Wang {0x0440, 0x3F}, {0x10D4, 0x08}, 190*2480f5daSFrank Wang {0x20D4, 0x08}, {0x00D4, 0x30}, 191*2480f5daSFrank Wang {0x0024, 0x6e}, 192*2480f5daSFrank Wang }; 193*2480f5daSFrank Wang 194*2480f5daSFrank Wang static inline int grfreg_write(struct regmap *base, 195*2480f5daSFrank Wang const struct udphy_grf_reg *reg, bool en) 196*2480f5daSFrank Wang { 197*2480f5daSFrank Wang u32 val, mask, tmp; 198*2480f5daSFrank Wang 199*2480f5daSFrank Wang tmp = en ? reg->enable : reg->disable; 200*2480f5daSFrank Wang mask = GENMASK(reg->bitend, reg->bitstart); 201*2480f5daSFrank Wang val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); 202*2480f5daSFrank Wang 203*2480f5daSFrank Wang return regmap_write(base, reg->offset, val); 204*2480f5daSFrank Wang } 205*2480f5daSFrank Wang 206*2480f5daSFrank Wang static int __regmap_multi_reg_write(struct regmap *map, 207*2480f5daSFrank Wang const struct reg_sequence *regs, int num_regs) 208*2480f5daSFrank Wang { 209*2480f5daSFrank Wang int i, ret = 0; 210*2480f5daSFrank Wang 211*2480f5daSFrank Wang for (i = 0; i < num_regs; i++) { 212*2480f5daSFrank Wang ret = regmap_write(map, regs[i].reg, regs[i].def); 213*2480f5daSFrank Wang 214*2480f5daSFrank Wang if (regs[i].delay_us) 215*2480f5daSFrank Wang udelay(regs[i].delay_us); 216*2480f5daSFrank Wang } 217*2480f5daSFrank Wang 218*2480f5daSFrank Wang return ret; 219*2480f5daSFrank Wang } 220*2480f5daSFrank Wang 221*2480f5daSFrank Wang static int udphy_clk_init(struct rockchip_udphy *udphy, struct udevice *dev) 222*2480f5daSFrank Wang { 223*2480f5daSFrank Wang return 0; 224*2480f5daSFrank Wang } 225*2480f5daSFrank Wang 226*2480f5daSFrank Wang static int udphy_reset_init(struct rockchip_udphy *udphy, struct udevice *dev) 227*2480f5daSFrank Wang { 228*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 229*2480f5daSFrank Wang int idx; 230*2480f5daSFrank Wang int ret; 231*2480f5daSFrank Wang 232*2480f5daSFrank Wang udphy->rsts = devm_kcalloc(dev, cfg->num_rsts, 233*2480f5daSFrank Wang sizeof(*udphy->rsts), GFP_KERNEL); 234*2480f5daSFrank Wang if (!udphy->rsts) 235*2480f5daSFrank Wang return -ENOMEM; 236*2480f5daSFrank Wang 237*2480f5daSFrank Wang for (idx = 0; idx < cfg->num_rsts; idx++) { 238*2480f5daSFrank Wang const char *name = cfg->rst_list[idx]; 239*2480f5daSFrank Wang 240*2480f5daSFrank Wang ret = reset_get_by_name(dev, name, &udphy->rsts[idx]); 241*2480f5daSFrank Wang if (ret) { 242*2480f5daSFrank Wang dev_err(dev, "failed to get %s reset\n", name); 243*2480f5daSFrank Wang goto err; 244*2480f5daSFrank Wang } 245*2480f5daSFrank Wang 246*2480f5daSFrank Wang reset_assert(&udphy->rsts[idx]); 247*2480f5daSFrank Wang } 248*2480f5daSFrank Wang 249*2480f5daSFrank Wang return 0; 250*2480f5daSFrank Wang 251*2480f5daSFrank Wang err: 252*2480f5daSFrank Wang devm_kfree(dev, udphy->rsts); 253*2480f5daSFrank Wang return ret; 254*2480f5daSFrank Wang } 255*2480f5daSFrank Wang 256*2480f5daSFrank Wang static int udphy_get_rst_idx(const char * const *list, int num, char *name) 257*2480f5daSFrank Wang { 258*2480f5daSFrank Wang int idx; 259*2480f5daSFrank Wang 260*2480f5daSFrank Wang for (idx = 0; idx < num; idx++) { 261*2480f5daSFrank Wang if (!strcmp(list[idx], name)) 262*2480f5daSFrank Wang return idx; 263*2480f5daSFrank Wang } 264*2480f5daSFrank Wang 265*2480f5daSFrank Wang return -EINVAL; 266*2480f5daSFrank Wang } 267*2480f5daSFrank Wang 268*2480f5daSFrank Wang static int udphy_reset_assert(struct rockchip_udphy *udphy, char *name) 269*2480f5daSFrank Wang { 270*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 271*2480f5daSFrank Wang int idx; 272*2480f5daSFrank Wang 273*2480f5daSFrank Wang idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); 274*2480f5daSFrank Wang if (idx < 0) 275*2480f5daSFrank Wang return idx; 276*2480f5daSFrank Wang 277*2480f5daSFrank Wang return reset_assert(&udphy->rsts[idx]); 278*2480f5daSFrank Wang } 279*2480f5daSFrank Wang 280*2480f5daSFrank Wang static int udphy_reset_deassert(struct rockchip_udphy *udphy, char *name) 281*2480f5daSFrank Wang { 282*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 283*2480f5daSFrank Wang int idx; 284*2480f5daSFrank Wang 285*2480f5daSFrank Wang idx = udphy_get_rst_idx(cfg->rst_list, cfg->num_rsts, name); 286*2480f5daSFrank Wang if (idx < 0) 287*2480f5daSFrank Wang return idx; 288*2480f5daSFrank Wang 289*2480f5daSFrank Wang return reset_deassert(&udphy->rsts[idx]); 290*2480f5daSFrank Wang } 291*2480f5daSFrank Wang 292*2480f5daSFrank Wang static void udphy_u3_port_disable(struct rockchip_udphy *udphy, u8 disable) 293*2480f5daSFrank Wang { 294*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 295*2480f5daSFrank Wang const struct udphy_grf_reg *preg; 296*2480f5daSFrank Wang 297*2480f5daSFrank Wang preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; 298*2480f5daSFrank Wang grfreg_write(udphy->usbgrf, preg, disable); 299*2480f5daSFrank Wang } 300*2480f5daSFrank Wang 301*2480f5daSFrank Wang __maybe_unused 302*2480f5daSFrank Wang static void udphy_usb_bvalid_enable(struct rockchip_udphy *udphy, u8 enable) 303*2480f5daSFrank Wang { 304*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 305*2480f5daSFrank Wang 306*2480f5daSFrank Wang grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); 307*2480f5daSFrank Wang grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); 308*2480f5daSFrank Wang } 309*2480f5daSFrank Wang 310*2480f5daSFrank Wang /* 311*2480f5daSFrank Wang * In usb/dp combo phy driver, here are 2 ways to mapping lanes. 312*2480f5daSFrank Wang * 313*2480f5daSFrank Wang * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) 314*2480f5daSFrank Wang * --------------------------------------------------------------------------- 315*2480f5daSFrank Wang * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 316*2480f5daSFrank Wang * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 317*2480f5daSFrank Wang * C/E(Normal) dpln3 dpln2 dpln0 dpln1 318*2480f5daSFrank Wang * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 319*2480f5daSFrank Wang * D/F(Normal) usbrx usbtx dpln0 dpln1 320*2480f5daSFrank Wang * D/F(Flip ) dpln0 dpln1 usbrx usbtx 321*2480f5daSFrank Wang * A(Normal ) dpln3 dpln1 dpln2 dpln0 322*2480f5daSFrank Wang * A(Flip ) dpln2 dpln0 dpln3 dpln1 323*2480f5daSFrank Wang * B(Normal ) usbrx usbtx dpln1 dpln0 324*2480f5daSFrank Wang * B(Flip ) dpln1 dpln0 usbrx usbtx 325*2480f5daSFrank Wang * --------------------------------------------------------------------------- 326*2480f5daSFrank Wang * 327*2480f5daSFrank Wang * 2 Mapping the lanes in dtsi 328*2480f5daSFrank Wang * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = <x x x x>; 329*2480f5daSFrank Wang * sample as follow: 330*2480f5daSFrank Wang * --------------------------------------------------------------------------- 331*2480f5daSFrank Wang * B11-B10 A2-A3 A11-A10 B2-B3 332*2480f5daSFrank Wang * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 333*2480f5daSFrank Wang * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 334*2480f5daSFrank Wang * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 335*2480f5daSFrank Wang * --------------------------------------------------------------------------- 336*2480f5daSFrank Wang * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x x>; 337*2480f5daSFrank Wang * sample as follow: 338*2480f5daSFrank Wang * --------------------------------------------------------------------------- 339*2480f5daSFrank Wang * B11-B10 A2-A3 A11-A10 B2-B3 340*2480f5daSFrank Wang * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) 341*2480f5daSFrank Wang * <0 1> dpln0 dpln1 usbrx usbtx 342*2480f5daSFrank Wang * <2 3> usbrx usbtx dpln0 dpln1 343*2480f5daSFrank Wang * --------------------------------------------------------------------------- 344*2480f5daSFrank Wang */ 345*2480f5daSFrank Wang 346*2480f5daSFrank Wang __maybe_unused 347*2480f5daSFrank Wang static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy) 348*2480f5daSFrank Wang { 349*2480f5daSFrank Wang if (udphy->flip) { 350*2480f5daSFrank Wang udphy->dp_lane_sel[0] = 0; 351*2480f5daSFrank Wang udphy->dp_lane_sel[1] = 1; 352*2480f5daSFrank Wang udphy->dp_lane_sel[2] = 3; 353*2480f5daSFrank Wang udphy->dp_lane_sel[3] = 2; 354*2480f5daSFrank Wang udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; 355*2480f5daSFrank Wang udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; 356*2480f5daSFrank Wang udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; 357*2480f5daSFrank Wang udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; 358*2480f5daSFrank Wang udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; 359*2480f5daSFrank Wang udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; 360*2480f5daSFrank Wang } else { 361*2480f5daSFrank Wang udphy->dp_lane_sel[0] = 2; 362*2480f5daSFrank Wang udphy->dp_lane_sel[1] = 3; 363*2480f5daSFrank Wang udphy->dp_lane_sel[2] = 1; 364*2480f5daSFrank Wang udphy->dp_lane_sel[3] = 0; 365*2480f5daSFrank Wang udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; 366*2480f5daSFrank Wang udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; 367*2480f5daSFrank Wang udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; 368*2480f5daSFrank Wang udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; 369*2480f5daSFrank Wang udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; 370*2480f5daSFrank Wang udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; 371*2480f5daSFrank Wang } 372*2480f5daSFrank Wang 373*2480f5daSFrank Wang udphy->mode = UDPHY_MODE_DP_USB; 374*2480f5daSFrank Wang 375*2480f5daSFrank Wang return 0; 376*2480f5daSFrank Wang } 377*2480f5daSFrank Wang 378*2480f5daSFrank Wang static int udphy_setup(struct rockchip_udphy *udphy) 379*2480f5daSFrank Wang { 380*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 381*2480f5daSFrank Wang int ret = 0; 382*2480f5daSFrank Wang 383*2480f5daSFrank Wang if (cfg->combophy_init) { 384*2480f5daSFrank Wang ret = cfg->combophy_init(udphy); 385*2480f5daSFrank Wang if (ret) 386*2480f5daSFrank Wang dev_err(udphy->dev, "failed to init combophy\n"); 387*2480f5daSFrank Wang } 388*2480f5daSFrank Wang 389*2480f5daSFrank Wang return ret; 390*2480f5daSFrank Wang } 391*2480f5daSFrank Wang 392*2480f5daSFrank Wang static int udphy_disable(struct rockchip_udphy *udphy) 393*2480f5daSFrank Wang { 394*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 395*2480f5daSFrank Wang int i; 396*2480f5daSFrank Wang 397*2480f5daSFrank Wang for (i = 0; i < cfg->num_rsts; i++) 398*2480f5daSFrank Wang reset_assert(&udphy->rsts[i]); 399*2480f5daSFrank Wang 400*2480f5daSFrank Wang return 0; 401*2480f5daSFrank Wang } 402*2480f5daSFrank Wang 403*2480f5daSFrank Wang static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, const struct device_node *np) 404*2480f5daSFrank Wang { 405*2480f5daSFrank Wang struct property *prop; 406*2480f5daSFrank Wang int ret, i, len, num_lanes; 407*2480f5daSFrank Wang 408*2480f5daSFrank Wang prop = of_find_property(np, "rockchip,dp-lane-mux", &len); 409*2480f5daSFrank Wang if (!prop) { 410*2480f5daSFrank Wang dev_dbg(udphy->dev, "failed to find dp lane mux, following dp alt mode\n"); 411*2480f5daSFrank Wang udphy->mode = UDPHY_MODE_USB; 412*2480f5daSFrank Wang return 0; 413*2480f5daSFrank Wang } 414*2480f5daSFrank Wang 415*2480f5daSFrank Wang num_lanes = len / sizeof(u32); 416*2480f5daSFrank Wang 417*2480f5daSFrank Wang if (num_lanes != 2 && num_lanes != 4) { 418*2480f5daSFrank Wang dev_err(udphy->dev, "invalid number of lane mux\n"); 419*2480f5daSFrank Wang return -EINVAL; 420*2480f5daSFrank Wang } 421*2480f5daSFrank Wang 422*2480f5daSFrank Wang ret = of_read_u32_array(np, "rockchip,dp-lane-mux", udphy->dp_lane_sel, num_lanes); 423*2480f5daSFrank Wang if (ret) { 424*2480f5daSFrank Wang dev_err(udphy->dev, "get dp lane mux failed\n"); 425*2480f5daSFrank Wang return -EINVAL; 426*2480f5daSFrank Wang } 427*2480f5daSFrank Wang 428*2480f5daSFrank Wang for (i = 0; i < num_lanes; i++) { 429*2480f5daSFrank Wang int j; 430*2480f5daSFrank Wang 431*2480f5daSFrank Wang if (udphy->dp_lane_sel[i] > 3) { 432*2480f5daSFrank Wang dev_err(udphy->dev, "lane mux between 0 and 3, exceeding the range\n"); 433*2480f5daSFrank Wang return -EINVAL; 434*2480f5daSFrank Wang } 435*2480f5daSFrank Wang 436*2480f5daSFrank Wang udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; 437*2480f5daSFrank Wang 438*2480f5daSFrank Wang for (j = i + 1; j < num_lanes; j++) { 439*2480f5daSFrank Wang if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) { 440*2480f5daSFrank Wang dev_err(udphy->dev, "set repeat lane mux value\n"); 441*2480f5daSFrank Wang return -EINVAL; 442*2480f5daSFrank Wang } 443*2480f5daSFrank Wang } 444*2480f5daSFrank Wang } 445*2480f5daSFrank Wang 446*2480f5daSFrank Wang udphy->mode = UDPHY_MODE_DP; 447*2480f5daSFrank Wang if (num_lanes == 2) 448*2480f5daSFrank Wang udphy->mode |= UDPHY_MODE_USB; 449*2480f5daSFrank Wang 450*2480f5daSFrank Wang return 0; 451*2480f5daSFrank Wang } 452*2480f5daSFrank Wang 453*2480f5daSFrank Wang static int udphy_parse_dt(struct rockchip_udphy *udphy, struct udevice *dev) 454*2480f5daSFrank Wang { 455*2480f5daSFrank Wang const struct device_node *np = ofnode_to_np(dev->node); 456*2480f5daSFrank Wang enum usb_device_speed maximum_speed; 457*2480f5daSFrank Wang int ret; 458*2480f5daSFrank Wang 459*2480f5daSFrank Wang udphy->u2phygrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,u2phy-grf"); 460*2480f5daSFrank Wang if (IS_ERR(udphy->u2phygrf)) { 461*2480f5daSFrank Wang if (PTR_ERR(udphy->u2phygrf) == -ENODEV) { 462*2480f5daSFrank Wang dev_warn(dev, "missing u2phy-grf dt node\n"); 463*2480f5daSFrank Wang udphy->u2phygrf = NULL; 464*2480f5daSFrank Wang } else { 465*2480f5daSFrank Wang return PTR_ERR(udphy->u2phygrf); 466*2480f5daSFrank Wang } 467*2480f5daSFrank Wang } 468*2480f5daSFrank Wang 469*2480f5daSFrank Wang udphy->udphygrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,usbdpphy-grf"); 470*2480f5daSFrank Wang if (IS_ERR(udphy->udphygrf)) { 471*2480f5daSFrank Wang if (PTR_ERR(udphy->udphygrf) == -ENODEV) { 472*2480f5daSFrank Wang dev_warn(dev, "missing usbdpphy-grf dt node\n"); 473*2480f5daSFrank Wang udphy->udphygrf = NULL; 474*2480f5daSFrank Wang } else { 475*2480f5daSFrank Wang return PTR_ERR(udphy->udphygrf); 476*2480f5daSFrank Wang } 477*2480f5daSFrank Wang } 478*2480f5daSFrank Wang 479*2480f5daSFrank Wang udphy->usbgrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,usb-grf"); 480*2480f5daSFrank Wang if (IS_ERR(udphy->usbgrf)) { 481*2480f5daSFrank Wang if (PTR_ERR(udphy->usbgrf) == -ENODEV) { 482*2480f5daSFrank Wang dev_warn(dev, "missing usb-grf dt node\n"); 483*2480f5daSFrank Wang udphy->usbgrf = NULL; 484*2480f5daSFrank Wang } else { 485*2480f5daSFrank Wang return PTR_ERR(udphy->usbgrf); 486*2480f5daSFrank Wang } 487*2480f5daSFrank Wang } 488*2480f5daSFrank Wang 489*2480f5daSFrank Wang udphy->vogrf = syscon_regmap_lookup_by_phandle(dev, "rockchip,vo-grf"); 490*2480f5daSFrank Wang if (IS_ERR(udphy->vogrf)) { 491*2480f5daSFrank Wang if (PTR_ERR(udphy->vogrf) == -ENODEV) { 492*2480f5daSFrank Wang dev_warn(dev, "missing vo-grf dt node\n"); 493*2480f5daSFrank Wang udphy->vogrf = NULL; 494*2480f5daSFrank Wang } else { 495*2480f5daSFrank Wang return PTR_ERR(udphy->vogrf); 496*2480f5daSFrank Wang } 497*2480f5daSFrank Wang } 498*2480f5daSFrank Wang 499*2480f5daSFrank Wang ret = udphy_parse_lane_mux_data(udphy, np); 500*2480f5daSFrank Wang if (ret) 501*2480f5daSFrank Wang return ret; 502*2480f5daSFrank Wang 503*2480f5daSFrank Wang if (dev_read_prop(dev, "maximum-speed", NULL)) { 504*2480f5daSFrank Wang maximum_speed = usb_get_maximum_speed(dev->node); 505*2480f5daSFrank Wang udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false; 506*2480f5daSFrank Wang } 507*2480f5daSFrank Wang 508*2480f5daSFrank Wang ret = udphy_clk_init(udphy, dev); 509*2480f5daSFrank Wang if (ret) 510*2480f5daSFrank Wang return ret; 511*2480f5daSFrank Wang 512*2480f5daSFrank Wang ret = udphy_reset_init(udphy, dev); 513*2480f5daSFrank Wang if (ret) 514*2480f5daSFrank Wang return ret; 515*2480f5daSFrank Wang 516*2480f5daSFrank Wang return 0; 517*2480f5daSFrank Wang } 518*2480f5daSFrank Wang 519*2480f5daSFrank Wang static int udphy_power_on(struct rockchip_udphy *udphy, u8 mode) 520*2480f5daSFrank Wang { 521*2480f5daSFrank Wang int ret; 522*2480f5daSFrank Wang 523*2480f5daSFrank Wang if (!(udphy->mode & mode)) { 524*2480f5daSFrank Wang dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); 525*2480f5daSFrank Wang return 0; 526*2480f5daSFrank Wang } 527*2480f5daSFrank Wang 528*2480f5daSFrank Wang if (udphy->status == UDPHY_MODE_NONE) { 529*2480f5daSFrank Wang udphy->mode_change = false; 530*2480f5daSFrank Wang ret = udphy_setup(udphy); 531*2480f5daSFrank Wang if (ret) 532*2480f5daSFrank Wang return ret; 533*2480f5daSFrank Wang 534*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 535*2480f5daSFrank Wang udphy_u3_port_disable(udphy, false); 536*2480f5daSFrank Wang } else if (udphy->mode_change) { 537*2480f5daSFrank Wang udphy->mode_change = false; 538*2480f5daSFrank Wang udphy->status = UDPHY_MODE_NONE; 539*2480f5daSFrank Wang if (udphy->mode == UDPHY_MODE_DP) 540*2480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 541*2480f5daSFrank Wang 542*2480f5daSFrank Wang ret = udphy_disable(udphy); 543*2480f5daSFrank Wang if (ret) 544*2480f5daSFrank Wang return ret; 545*2480f5daSFrank Wang ret = udphy_setup(udphy); 546*2480f5daSFrank Wang if (ret) 547*2480f5daSFrank Wang return ret; 548*2480f5daSFrank Wang } 549*2480f5daSFrank Wang 550*2480f5daSFrank Wang udphy->status |= mode; 551*2480f5daSFrank Wang 552*2480f5daSFrank Wang return 0; 553*2480f5daSFrank Wang } 554*2480f5daSFrank Wang 555*2480f5daSFrank Wang static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode) 556*2480f5daSFrank Wang { 557*2480f5daSFrank Wang int ret; 558*2480f5daSFrank Wang 559*2480f5daSFrank Wang if (!(udphy->mode & mode)) { 560*2480f5daSFrank Wang dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); 561*2480f5daSFrank Wang return 0; 562*2480f5daSFrank Wang } 563*2480f5daSFrank Wang 564*2480f5daSFrank Wang if (!udphy->status) 565*2480f5daSFrank Wang return 0; 566*2480f5daSFrank Wang 567*2480f5daSFrank Wang udphy->status &= ~mode; 568*2480f5daSFrank Wang 569*2480f5daSFrank Wang if (udphy->status == UDPHY_MODE_NONE) { 570*2480f5daSFrank Wang ret = udphy_disable(udphy); 571*2480f5daSFrank Wang if (ret) 572*2480f5daSFrank Wang return ret; 573*2480f5daSFrank Wang } 574*2480f5daSFrank Wang 575*2480f5daSFrank Wang return 0; 576*2480f5daSFrank Wang } 577*2480f5daSFrank Wang 578*2480f5daSFrank Wang static int rockchip_u3phy_init(struct phy *phy) 579*2480f5daSFrank Wang { 580*2480f5daSFrank Wang struct udevice *parent = phy->dev->parent; 581*2480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(parent); 582*2480f5daSFrank Wang 583*2480f5daSFrank Wang /* DP only or high-speed, disable U3 port */ 584*2480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { 585*2480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 586*2480f5daSFrank Wang return 0; 587*2480f5daSFrank Wang } 588*2480f5daSFrank Wang 589*2480f5daSFrank Wang return udphy_power_on(udphy, UDPHY_MODE_USB); 590*2480f5daSFrank Wang } 591*2480f5daSFrank Wang 592*2480f5daSFrank Wang static int rockchip_u3phy_exit(struct phy *phy) 593*2480f5daSFrank Wang { 594*2480f5daSFrank Wang struct udevice *parent = phy->dev->parent; 595*2480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(parent); 596*2480f5daSFrank Wang 597*2480f5daSFrank Wang /* DP only or high-speed */ 598*2480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) 599*2480f5daSFrank Wang return 0; 600*2480f5daSFrank Wang 601*2480f5daSFrank Wang return udphy_power_off(udphy, UDPHY_MODE_USB); 602*2480f5daSFrank Wang } 603*2480f5daSFrank Wang 604*2480f5daSFrank Wang static const struct phy_ops rockchip_u3phy_ops = { 605*2480f5daSFrank Wang .init = rockchip_u3phy_init, 606*2480f5daSFrank Wang .exit = rockchip_u3phy_exit, 607*2480f5daSFrank Wang }; 608*2480f5daSFrank Wang 609*2480f5daSFrank Wang int rockchip_u3phy_uboot_init(void) 610*2480f5daSFrank Wang { 611*2480f5daSFrank Wang struct udevice *udev; 612*2480f5daSFrank Wang struct rockchip_udphy *udphy; 613*2480f5daSFrank Wang int ret; 614*2480f5daSFrank Wang 615*2480f5daSFrank Wang ret = uclass_get_device_by_driver(UCLASS_PHY, 616*2480f5daSFrank Wang DM_GET_DRIVER(rockchip_udphy_u3_port), 617*2480f5daSFrank Wang &udev); 618*2480f5daSFrank Wang if (ret) { 619*2480f5daSFrank Wang pr_err("%s: get u3-port failed: %d\n", __func__, ret); 620*2480f5daSFrank Wang return ret; 621*2480f5daSFrank Wang } 622*2480f5daSFrank Wang 623*2480f5daSFrank Wang /* DP only or high-speed, disable U3 port */ 624*2480f5daSFrank Wang udphy = dev_get_priv(udev->parent); 625*2480f5daSFrank Wang if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { 626*2480f5daSFrank Wang udphy_u3_port_disable(udphy, true); 627*2480f5daSFrank Wang return 0; 628*2480f5daSFrank Wang } 629*2480f5daSFrank Wang 630*2480f5daSFrank Wang return udphy_power_on(udphy, UDPHY_MODE_USB); 631*2480f5daSFrank Wang } 632*2480f5daSFrank Wang 633*2480f5daSFrank Wang static int rockchip_udphy_probe(struct udevice *dev) 634*2480f5daSFrank Wang { 635*2480f5daSFrank Wang const struct device_node *np = ofnode_to_np(dev->node); 636*2480f5daSFrank Wang struct rockchip_udphy *udphy = dev_get_priv(dev); 637*2480f5daSFrank Wang const struct rockchip_udphy_cfg *phy_cfgs; 638*2480f5daSFrank Wang int id, ret; 639*2480f5daSFrank Wang 640*2480f5daSFrank Wang udphy->dev = dev; 641*2480f5daSFrank Wang 642*2480f5daSFrank Wang id = of_alias_get_id(np, "usbdp"); 643*2480f5daSFrank Wang if (id < 0) 644*2480f5daSFrank Wang id = 0; 645*2480f5daSFrank Wang udphy->id = id; 646*2480f5daSFrank Wang 647*2480f5daSFrank Wang phy_cfgs = (const struct rockchip_udphy_cfg *) dev_get_driver_data(dev); 648*2480f5daSFrank Wang if (!phy_cfgs) { 649*2480f5daSFrank Wang dev_err(dev, "unable to get phy_cfgs\n"); 650*2480f5daSFrank Wang return -EINVAL; 651*2480f5daSFrank Wang } 652*2480f5daSFrank Wang udphy->cfgs = phy_cfgs; 653*2480f5daSFrank Wang 654*2480f5daSFrank Wang ret = regmap_init_mem(dev, &udphy->pma_regmap); 655*2480f5daSFrank Wang if (ret) 656*2480f5daSFrank Wang return ret; 657*2480f5daSFrank Wang udphy->pma_regmap->base += UDPHY_PMA; 658*2480f5daSFrank Wang 659*2480f5daSFrank Wang ret = udphy_parse_dt(udphy, dev); 660*2480f5daSFrank Wang if (ret) 661*2480f5daSFrank Wang return ret; 662*2480f5daSFrank Wang 663*2480f5daSFrank Wang return 0; 664*2480f5daSFrank Wang } 665*2480f5daSFrank Wang 666*2480f5daSFrank Wang static int rockchip_udphy_bind(struct udevice *parent) 667*2480f5daSFrank Wang { 668*2480f5daSFrank Wang struct udevice *child; 669*2480f5daSFrank Wang ofnode subnode; 670*2480f5daSFrank Wang const char *node_name; 671*2480f5daSFrank Wang int ret; 672*2480f5daSFrank Wang 673*2480f5daSFrank Wang dev_for_each_subnode(subnode, parent) { 674*2480f5daSFrank Wang if (!ofnode_valid(subnode)) { 675*2480f5daSFrank Wang printf("%s: no subnode for %s", __func__, parent->name); 676*2480f5daSFrank Wang return -ENXIO; 677*2480f5daSFrank Wang } 678*2480f5daSFrank Wang 679*2480f5daSFrank Wang node_name = ofnode_get_name(subnode); 680*2480f5daSFrank Wang debug("%s: subnode %s\n", __func__, node_name); 681*2480f5daSFrank Wang 682*2480f5daSFrank Wang if (!strcasecmp(node_name, "u3-port")) { 683*2480f5daSFrank Wang ret = device_bind_driver_to_node(parent, 684*2480f5daSFrank Wang "rockchip_udphy_u3_port", 685*2480f5daSFrank Wang node_name, subnode, &child); 686*2480f5daSFrank Wang if (ret) { 687*2480f5daSFrank Wang printf("%s: '%s' cannot bind its driver\n", 688*2480f5daSFrank Wang __func__, node_name); 689*2480f5daSFrank Wang return ret; 690*2480f5daSFrank Wang } 691*2480f5daSFrank Wang } 692*2480f5daSFrank Wang } 693*2480f5daSFrank Wang 694*2480f5daSFrank Wang return 0; 695*2480f5daSFrank Wang } 696*2480f5daSFrank Wang 697*2480f5daSFrank Wang static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy) 698*2480f5daSFrank Wang { 699*2480f5daSFrank Wang int ret; 700*2480f5daSFrank Wang 701*2480f5daSFrank Wang /* configure phy reference clock */ 702*2480f5daSFrank Wang ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_24m_refclk_cfg, 703*2480f5daSFrank Wang ARRAY_SIZE(rk3588_udphy_24m_refclk_cfg)); 704*2480f5daSFrank Wang if (ret) 705*2480f5daSFrank Wang return ret; 706*2480f5daSFrank Wang 707*2480f5daSFrank Wang return 0; 708*2480f5daSFrank Wang } 709*2480f5daSFrank Wang 710*2480f5daSFrank Wang static int rk3588_udphy_status_check(struct rockchip_udphy *udphy) 711*2480f5daSFrank Wang { 712*2480f5daSFrank Wang unsigned int val; 713*2480f5daSFrank Wang int ret; 714*2480f5daSFrank Wang 715*2480f5daSFrank Wang /* LCPLL check */ 716*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 717*2480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, 718*2480f5daSFrank Wang val, (val & CMN_ANA_LCPLL_AFC_DONE) && 719*2480f5daSFrank Wang (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100); 720*2480f5daSFrank Wang if (ret) { 721*2480f5daSFrank Wang dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); 722*2480f5daSFrank Wang return ret; 723*2480f5daSFrank Wang } 724*2480f5daSFrank Wang } 725*2480f5daSFrank Wang 726*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 727*2480f5daSFrank Wang if (!udphy->flip) { 728*2480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, 729*2480f5daSFrank Wang TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, 730*2480f5daSFrank Wang val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, 731*2480f5daSFrank Wang 200, 100); 732*2480f5daSFrank Wang if (ret) 733*2480f5daSFrank Wang dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); 734*2480f5daSFrank Wang } else { 735*2480f5daSFrank Wang ret = regmap_read_poll_timeout(udphy->pma_regmap, 736*2480f5daSFrank Wang TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, 737*2480f5daSFrank Wang val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, 738*2480f5daSFrank Wang 200, 100); 739*2480f5daSFrank Wang if (ret) 740*2480f5daSFrank Wang dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); 741*2480f5daSFrank Wang } 742*2480f5daSFrank Wang } 743*2480f5daSFrank Wang 744*2480f5daSFrank Wang return 0; 745*2480f5daSFrank Wang } 746*2480f5daSFrank Wang 747*2480f5daSFrank Wang static int rk3588_udphy_init(struct rockchip_udphy *udphy) 748*2480f5daSFrank Wang { 749*2480f5daSFrank Wang const struct rockchip_udphy_cfg *cfg = udphy->cfgs; 750*2480f5daSFrank Wang int ret; 751*2480f5daSFrank Wang 752*2480f5daSFrank Wang /* enable rx lfps for usb */ 753*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 754*2480f5daSFrank Wang grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); 755*2480f5daSFrank Wang 756*2480f5daSFrank Wang /* Step 1: power on pma and deassert apb rstn */ 757*2480f5daSFrank Wang grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); 758*2480f5daSFrank Wang 759*2480f5daSFrank Wang udphy_reset_deassert(udphy, "pma_apb"); 760*2480f5daSFrank Wang udphy_reset_deassert(udphy, "pcs_apb"); 761*2480f5daSFrank Wang 762*2480f5daSFrank Wang /* Step 2: set init sequence and phy refclk */ 763*2480f5daSFrank Wang ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_init_sequence, 764*2480f5daSFrank Wang ARRAY_SIZE(rk3588_udphy_init_sequence)); 765*2480f5daSFrank Wang if (ret) { 766*2480f5daSFrank Wang dev_err(udphy->dev, "init sequence set error %d\n", ret); 767*2480f5daSFrank Wang goto assert_apb; 768*2480f5daSFrank Wang } 769*2480f5daSFrank Wang 770*2480f5daSFrank Wang ret = rk3588_udphy_refclk_set(udphy); 771*2480f5daSFrank Wang if (ret) { 772*2480f5daSFrank Wang dev_err(udphy->dev, "refclk set error %d\n", ret); 773*2480f5daSFrank Wang goto assert_apb; 774*2480f5daSFrank Wang } 775*2480f5daSFrank Wang 776*2480f5daSFrank Wang /* Step 3: configure lane mux */ 777*2480f5daSFrank Wang regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, 778*2480f5daSFrank Wang CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, 779*2480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | 780*2480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | 781*2480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | 782*2480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | 783*2480f5daSFrank Wang FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); 784*2480f5daSFrank Wang 785*2480f5daSFrank Wang /* Step 4: deassert init rstn and wait for 200ns from datasheet */ 786*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) 787*2480f5daSFrank Wang udphy_reset_deassert(udphy, "init"); 788*2480f5daSFrank Wang 789*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_DP) { 790*2480f5daSFrank Wang regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, 791*2480f5daSFrank Wang CMN_DP_INIT_RSTN, 792*2480f5daSFrank Wang FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); 793*2480f5daSFrank Wang } 794*2480f5daSFrank Wang 795*2480f5daSFrank Wang udelay(1); 796*2480f5daSFrank Wang 797*2480f5daSFrank Wang /* Step 5: deassert cmn/lane rstn */ 798*2480f5daSFrank Wang if (udphy->mode & UDPHY_MODE_USB) { 799*2480f5daSFrank Wang udphy_reset_deassert(udphy, "cmn"); 800*2480f5daSFrank Wang udphy_reset_deassert(udphy, "lane"); 801*2480f5daSFrank Wang } 802*2480f5daSFrank Wang 803*2480f5daSFrank Wang /* Step 6: wait for lock done of pll */ 804*2480f5daSFrank Wang ret = rk3588_udphy_status_check(udphy); 805*2480f5daSFrank Wang if (ret) 806*2480f5daSFrank Wang goto assert_phy; 807*2480f5daSFrank Wang 808*2480f5daSFrank Wang return 0; 809*2480f5daSFrank Wang 810*2480f5daSFrank Wang assert_phy: 811*2480f5daSFrank Wang udphy_reset_assert(udphy, "init"); 812*2480f5daSFrank Wang udphy_reset_assert(udphy, "cmn"); 813*2480f5daSFrank Wang udphy_reset_assert(udphy, "lane"); 814*2480f5daSFrank Wang 815*2480f5daSFrank Wang assert_apb: 816*2480f5daSFrank Wang udphy_reset_assert(udphy, "pma_apb"); 817*2480f5daSFrank Wang udphy_reset_assert(udphy, "pcs_apb"); 818*2480f5daSFrank Wang return ret; 819*2480f5daSFrank Wang } 820*2480f5daSFrank Wang 821*2480f5daSFrank Wang static const char * const rk3588_udphy_rst_l[] = { 822*2480f5daSFrank Wang "init", "cmn", "lane", "pcs_apb", "pma_apb" 823*2480f5daSFrank Wang }; 824*2480f5daSFrank Wang 825*2480f5daSFrank Wang static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = { 826*2480f5daSFrank Wang .num_rsts = ARRAY_SIZE(rk3588_udphy_rst_l), 827*2480f5daSFrank Wang .rst_list = rk3588_udphy_rst_l, 828*2480f5daSFrank Wang .grfcfg = { 829*2480f5daSFrank Wang /* u2phy-grf */ 830*2480f5daSFrank Wang .bvalid_phy_con = { 0x0008, 1, 0, 0x2, 0x3 }, 831*2480f5daSFrank Wang .bvalid_grf_con = { 0x0010, 3, 2, 0x2, 0x3 }, 832*2480f5daSFrank Wang 833*2480f5daSFrank Wang /* usb-grf */ 834*2480f5daSFrank Wang .usb3otg0_cfg = { 0x001c, 15, 0, 0x1100, 0x0188 }, 835*2480f5daSFrank Wang .usb3otg1_cfg = { 0x0034, 15, 0, 0x1100, 0x0188 }, 836*2480f5daSFrank Wang 837*2480f5daSFrank Wang /* usbdpphy-grf */ 838*2480f5daSFrank Wang .low_pwrn = { 0x0004, 13, 13, 0, 1 }, 839*2480f5daSFrank Wang .rx_lfps = { 0x0004, 14, 14, 0, 1 }, 840*2480f5daSFrank Wang }, 841*2480f5daSFrank Wang .combophy_init = rk3588_udphy_init, 842*2480f5daSFrank Wang }; 843*2480f5daSFrank Wang 844*2480f5daSFrank Wang static const struct udevice_id rockchip_udphy_dt_match[] = { 845*2480f5daSFrank Wang { 846*2480f5daSFrank Wang .compatible = "rockchip,rk3588-usbdp-phy", 847*2480f5daSFrank Wang .data = (ulong)&rk3588_udphy_cfgs 848*2480f5daSFrank Wang }, 849*2480f5daSFrank Wang { /* sentinel */ } 850*2480f5daSFrank Wang }; 851*2480f5daSFrank Wang 852*2480f5daSFrank Wang U_BOOT_DRIVER(rockchip_udphy_u3_port) = { 853*2480f5daSFrank Wang .name = "rockchip_udphy_u3_port", 854*2480f5daSFrank Wang .id = UCLASS_PHY, 855*2480f5daSFrank Wang .ops = &rockchip_u3phy_ops, 856*2480f5daSFrank Wang }; 857*2480f5daSFrank Wang 858*2480f5daSFrank Wang U_BOOT_DRIVER(rockchip_udphy) = { 859*2480f5daSFrank Wang .name = "rockchip_udphy", 860*2480f5daSFrank Wang .id = UCLASS_PHY, 861*2480f5daSFrank Wang .of_match = rockchip_udphy_dt_match, 862*2480f5daSFrank Wang .probe = rockchip_udphy_probe, 863*2480f5daSFrank Wang .bind = rockchip_udphy_bind, 864*2480f5daSFrank Wang .priv_auto_alloc_size = sizeof(struct rockchip_udphy), 865*2480f5daSFrank Wang }; 866