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