xref: /OK3568_Linux_fs/kernel/drivers/phy/cadence/phy-cadence-sierra.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Cadence Sierra PHY Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2018 Cadence Design Systems
6*4882a593Smuzhiyun  * Author: Alan Douglas <adouglas@cadence.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include <linux/clk.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/err.h>
12*4882a593Smuzhiyun #include <linux/io.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/phy/phy.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/pm_runtime.h>
17*4882a593Smuzhiyun #include <linux/regmap.h>
18*4882a593Smuzhiyun #include <linux/reset.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/of_platform.h>
22*4882a593Smuzhiyun #include <dt-bindings/phy/phy.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* PHY register offsets */
25*4882a593Smuzhiyun #define SIERRA_COMMON_CDB_OFFSET			0x0
26*4882a593Smuzhiyun #define SIERRA_MACRO_ID_REG				0x0
27*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_MODE_PREG			0x48
28*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG		0x49
29*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG		0x4A
30*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_LOCK_CNTSTART_PREG		0x4B
31*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG		0x4F
32*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG		0x50
33*4882a593Smuzhiyun #define SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG	0x62
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define SIERRA_LANE_CDB_OFFSET(ln, block_offset, reg_offset)	\
36*4882a593Smuzhiyun 				((0x4000 << (block_offset)) + \
37*4882a593Smuzhiyun 				 (((ln) << 9) << (reg_offset)))
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define SIERRA_DET_STANDEC_A_PREG			0x000
40*4882a593Smuzhiyun #define SIERRA_DET_STANDEC_B_PREG			0x001
41*4882a593Smuzhiyun #define SIERRA_DET_STANDEC_C_PREG			0x002
42*4882a593Smuzhiyun #define SIERRA_DET_STANDEC_D_PREG			0x003
43*4882a593Smuzhiyun #define SIERRA_DET_STANDEC_E_PREG			0x004
44*4882a593Smuzhiyun #define SIERRA_PSM_LANECAL_DLY_A1_RESETS_PREG		0x008
45*4882a593Smuzhiyun #define SIERRA_PSM_A0IN_TMR_PREG			0x009
46*4882a593Smuzhiyun #define SIERRA_PSM_DIAG_PREG				0x015
47*4882a593Smuzhiyun #define SIERRA_PSC_TX_A0_PREG				0x028
48*4882a593Smuzhiyun #define SIERRA_PSC_TX_A1_PREG				0x029
49*4882a593Smuzhiyun #define SIERRA_PSC_TX_A2_PREG				0x02A
50*4882a593Smuzhiyun #define SIERRA_PSC_TX_A3_PREG				0x02B
51*4882a593Smuzhiyun #define SIERRA_PSC_RX_A0_PREG				0x030
52*4882a593Smuzhiyun #define SIERRA_PSC_RX_A1_PREG				0x031
53*4882a593Smuzhiyun #define SIERRA_PSC_RX_A2_PREG				0x032
54*4882a593Smuzhiyun #define SIERRA_PSC_RX_A3_PREG				0x033
55*4882a593Smuzhiyun #define SIERRA_PLLCTRL_SUBRATE_PREG			0x03A
56*4882a593Smuzhiyun #define SIERRA_PLLCTRL_GEN_D_PREG			0x03E
57*4882a593Smuzhiyun #define SIERRA_PLLCTRL_CPGAIN_MODE_PREG			0x03F
58*4882a593Smuzhiyun #define SIERRA_PLLCTRL_STATUS_PREG			0x044
59*4882a593Smuzhiyun #define SIERRA_CLKPATH_BIASTRIM_PREG			0x04B
60*4882a593Smuzhiyun #define SIERRA_DFE_BIASTRIM_PREG			0x04C
61*4882a593Smuzhiyun #define SIERRA_DRVCTRL_ATTEN_PREG			0x06A
62*4882a593Smuzhiyun #define SIERRA_CLKPATHCTRL_TMR_PREG			0x081
63*4882a593Smuzhiyun #define SIERRA_RX_CREQ_FLTR_A_MODE3_PREG		0x085
64*4882a593Smuzhiyun #define SIERRA_RX_CREQ_FLTR_A_MODE2_PREG		0x086
65*4882a593Smuzhiyun #define SIERRA_RX_CREQ_FLTR_A_MODE1_PREG		0x087
66*4882a593Smuzhiyun #define SIERRA_RX_CREQ_FLTR_A_MODE0_PREG		0x088
67*4882a593Smuzhiyun #define SIERRA_CREQ_CCLKDET_MODE01_PREG			0x08E
68*4882a593Smuzhiyun #define SIERRA_RX_CTLE_MAINTENANCE_PREG			0x091
69*4882a593Smuzhiyun #define SIERRA_CREQ_FSMCLK_SEL_PREG			0x092
70*4882a593Smuzhiyun #define SIERRA_CREQ_EQ_CTRL_PREG			0x093
71*4882a593Smuzhiyun #define SIERRA_CREQ_SPARE_PREG				0x096
72*4882a593Smuzhiyun #define SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG		0x097
73*4882a593Smuzhiyun #define SIERRA_CTLELUT_CTRL_PREG			0x098
74*4882a593Smuzhiyun #define SIERRA_DFE_ECMP_RATESEL_PREG			0x0C0
75*4882a593Smuzhiyun #define SIERRA_DFE_SMP_RATESEL_PREG			0x0C1
76*4882a593Smuzhiyun #define SIERRA_DEQ_PHALIGN_CTRL				0x0C4
77*4882a593Smuzhiyun #define SIERRA_DEQ_CONCUR_CTRL1_PREG			0x0C8
78*4882a593Smuzhiyun #define SIERRA_DEQ_CONCUR_CTRL2_PREG			0x0C9
79*4882a593Smuzhiyun #define SIERRA_DEQ_EPIPWR_CTRL2_PREG			0x0CD
80*4882a593Smuzhiyun #define SIERRA_DEQ_FAST_MAINT_CYCLES_PREG		0x0CE
81*4882a593Smuzhiyun #define SIERRA_DEQ_ERRCMP_CTRL_PREG			0x0D0
82*4882a593Smuzhiyun #define SIERRA_DEQ_OFFSET_CTRL_PREG			0x0D8
83*4882a593Smuzhiyun #define SIERRA_DEQ_GAIN_CTRL_PREG			0x0E0
84*4882a593Smuzhiyun #define SIERRA_DEQ_VGATUNE_CTRL_PREG			0x0E1
85*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT0				0x0E8
86*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT1				0x0E9
87*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT2				0x0EA
88*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT3				0x0EB
89*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT4				0x0EC
90*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT5				0x0ED
91*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT6				0x0EE
92*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT7				0x0EF
93*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT8				0x0F0
94*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT9				0x0F1
95*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT10				0x0F2
96*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT11				0x0F3
97*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT12				0x0F4
98*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT13				0x0F5
99*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT14				0x0F6
100*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT15				0x0F7
101*4882a593Smuzhiyun #define SIERRA_DEQ_GLUT16				0x0F8
102*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT0				0x108
103*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT1				0x109
104*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT2				0x10A
105*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT3				0x10B
106*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT4				0x10C
107*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT5				0x10D
108*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT6				0x10E
109*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT7				0x10F
110*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT8				0x110
111*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT9				0x111
112*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT10				0x112
113*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT11				0x113
114*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT12				0x114
115*4882a593Smuzhiyun #define SIERRA_DEQ_ALUT13				0x115
116*4882a593Smuzhiyun #define SIERRA_DEQ_DFETAP_CTRL_PREG			0x128
117*4882a593Smuzhiyun #define SIERRA_DFE_EN_1010_IGNORE_PREG			0x134
118*4882a593Smuzhiyun #define SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG		0x150
119*4882a593Smuzhiyun #define SIERRA_DEQ_TAU_CTRL2_PREG			0x151
120*4882a593Smuzhiyun #define SIERRA_DEQ_PICTRL_PREG				0x161
121*4882a593Smuzhiyun #define SIERRA_CPICAL_TMRVAL_MODE1_PREG			0x170
122*4882a593Smuzhiyun #define SIERRA_CPICAL_TMRVAL_MODE0_PREG			0x171
123*4882a593Smuzhiyun #define SIERRA_CPICAL_PICNT_MODE1_PREG			0x174
124*4882a593Smuzhiyun #define SIERRA_CPI_OUTBUF_RATESEL_PREG			0x17C
125*4882a593Smuzhiyun #define SIERRA_CPICAL_RES_STARTCODE_MODE23_PREG		0x183
126*4882a593Smuzhiyun #define SIERRA_LFPSDET_SUPPORT_PREG			0x188
127*4882a593Smuzhiyun #define SIERRA_LFPSFILT_NS_PREG				0x18A
128*4882a593Smuzhiyun #define SIERRA_LFPSFILT_RD_PREG				0x18B
129*4882a593Smuzhiyun #define SIERRA_LFPSFILT_MP_PREG				0x18C
130*4882a593Smuzhiyun #define SIERRA_SIGDET_SUPPORT_PREG			0x190
131*4882a593Smuzhiyun #define SIERRA_SDFILT_H2L_A_PREG			0x191
132*4882a593Smuzhiyun #define SIERRA_SDFILT_L2H_PREG				0x193
133*4882a593Smuzhiyun #define SIERRA_RXBUFFER_CTLECTRL_PREG			0x19E
134*4882a593Smuzhiyun #define SIERRA_RXBUFFER_RCDFECTRL_PREG			0x19F
135*4882a593Smuzhiyun #define SIERRA_RXBUFFER_DFECTRL_PREG			0x1A0
136*4882a593Smuzhiyun #define SIERRA_DEQ_TAU_CTRL1_FAST_MAINT_PREG		0x14F
137*4882a593Smuzhiyun #define SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG		0x150
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #define SIERRA_PHY_CONFIG_CTRL_OFFSET(block_offset)	\
140*4882a593Smuzhiyun 				      (0xc000 << (block_offset))
141*4882a593Smuzhiyun #define SIERRA_PHY_PLL_CFG				0xe
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun #define SIERRA_MACRO_ID					0x00007364
144*4882a593Smuzhiyun #define SIERRA_MAX_LANES				16
145*4882a593Smuzhiyun #define PLL_LOCK_TIME					100000
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun static const struct reg_field macro_id_type =
148*4882a593Smuzhiyun 				REG_FIELD(SIERRA_MACRO_ID_REG, 0, 15);
149*4882a593Smuzhiyun static const struct reg_field phy_pll_cfg_1 =
150*4882a593Smuzhiyun 				REG_FIELD(SIERRA_PHY_PLL_CFG, 1, 1);
151*4882a593Smuzhiyun static const struct reg_field pllctrl_lock =
152*4882a593Smuzhiyun 				REG_FIELD(SIERRA_PLLCTRL_STATUS_PREG, 0, 0);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun struct cdns_sierra_inst {
155*4882a593Smuzhiyun 	struct phy *phy;
156*4882a593Smuzhiyun 	u32 phy_type;
157*4882a593Smuzhiyun 	u32 num_lanes;
158*4882a593Smuzhiyun 	u32 mlane;
159*4882a593Smuzhiyun 	struct reset_control *lnk_rst;
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun struct cdns_reg_pairs {
163*4882a593Smuzhiyun 	u16 val;
164*4882a593Smuzhiyun 	u32 off;
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun struct cdns_sierra_data {
168*4882a593Smuzhiyun 		u32 id_value;
169*4882a593Smuzhiyun 		u8 block_offset_shift;
170*4882a593Smuzhiyun 		u8 reg_offset_shift;
171*4882a593Smuzhiyun 		u32 pcie_cmn_regs;
172*4882a593Smuzhiyun 		u32 pcie_ln_regs;
173*4882a593Smuzhiyun 		u32 usb_cmn_regs;
174*4882a593Smuzhiyun 		u32 usb_ln_regs;
175*4882a593Smuzhiyun 		const struct cdns_reg_pairs *pcie_cmn_vals;
176*4882a593Smuzhiyun 		const struct cdns_reg_pairs *pcie_ln_vals;
177*4882a593Smuzhiyun 		const struct cdns_reg_pairs *usb_cmn_vals;
178*4882a593Smuzhiyun 		const struct cdns_reg_pairs *usb_ln_vals;
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun struct cdns_regmap_cdb_context {
182*4882a593Smuzhiyun 	struct device *dev;
183*4882a593Smuzhiyun 	void __iomem *base;
184*4882a593Smuzhiyun 	u8 reg_offset_shift;
185*4882a593Smuzhiyun };
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun struct cdns_sierra_phy {
188*4882a593Smuzhiyun 	struct device *dev;
189*4882a593Smuzhiyun 	struct regmap *regmap;
190*4882a593Smuzhiyun 	struct cdns_sierra_data *init_data;
191*4882a593Smuzhiyun 	struct cdns_sierra_inst phys[SIERRA_MAX_LANES];
192*4882a593Smuzhiyun 	struct reset_control *phy_rst;
193*4882a593Smuzhiyun 	struct reset_control *apb_rst;
194*4882a593Smuzhiyun 	struct regmap *regmap_lane_cdb[SIERRA_MAX_LANES];
195*4882a593Smuzhiyun 	struct regmap *regmap_phy_config_ctrl;
196*4882a593Smuzhiyun 	struct regmap *regmap_common_cdb;
197*4882a593Smuzhiyun 	struct regmap_field *macro_id_type;
198*4882a593Smuzhiyun 	struct regmap_field *phy_pll_cfg_1;
199*4882a593Smuzhiyun 	struct regmap_field *pllctrl_lock[SIERRA_MAX_LANES];
200*4882a593Smuzhiyun 	struct clk *clk;
201*4882a593Smuzhiyun 	struct clk *cmn_refclk_dig_div;
202*4882a593Smuzhiyun 	struct clk *cmn_refclk1_dig_div;
203*4882a593Smuzhiyun 	int nsubnodes;
204*4882a593Smuzhiyun 	u32 num_lanes;
205*4882a593Smuzhiyun 	bool autoconf;
206*4882a593Smuzhiyun };
207*4882a593Smuzhiyun 
cdns_regmap_write(void * context,unsigned int reg,unsigned int val)208*4882a593Smuzhiyun static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct cdns_regmap_cdb_context *ctx = context;
211*4882a593Smuzhiyun 	u32 offset = reg << ctx->reg_offset_shift;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	writew(val, ctx->base + offset);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
cdns_regmap_read(void * context,unsigned int reg,unsigned int * val)218*4882a593Smuzhiyun static int cdns_regmap_read(void *context, unsigned int reg, unsigned int *val)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	struct cdns_regmap_cdb_context *ctx = context;
221*4882a593Smuzhiyun 	u32 offset = reg << ctx->reg_offset_shift;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	*val = readw(ctx->base + offset);
224*4882a593Smuzhiyun 	return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun #define SIERRA_LANE_CDB_REGMAP_CONF(n) \
228*4882a593Smuzhiyun { \
229*4882a593Smuzhiyun 	.name = "sierra_lane" n "_cdb", \
230*4882a593Smuzhiyun 	.reg_stride = 1, \
231*4882a593Smuzhiyun 	.fast_io = true, \
232*4882a593Smuzhiyun 	.reg_write = cdns_regmap_write, \
233*4882a593Smuzhiyun 	.reg_read = cdns_regmap_read, \
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun static const struct regmap_config cdns_sierra_lane_cdb_config[] = {
237*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("0"),
238*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("1"),
239*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("2"),
240*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("3"),
241*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("4"),
242*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("5"),
243*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("6"),
244*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("7"),
245*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("8"),
246*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("9"),
247*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("10"),
248*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("11"),
249*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("12"),
250*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("13"),
251*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("14"),
252*4882a593Smuzhiyun 	SIERRA_LANE_CDB_REGMAP_CONF("15"),
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun static const struct regmap_config cdns_sierra_common_cdb_config = {
256*4882a593Smuzhiyun 	.name = "sierra_common_cdb",
257*4882a593Smuzhiyun 	.reg_stride = 1,
258*4882a593Smuzhiyun 	.fast_io = true,
259*4882a593Smuzhiyun 	.reg_write = cdns_regmap_write,
260*4882a593Smuzhiyun 	.reg_read = cdns_regmap_read,
261*4882a593Smuzhiyun };
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun static const struct regmap_config cdns_sierra_phy_config_ctrl_config = {
264*4882a593Smuzhiyun 	.name = "sierra_phy_config_ctrl",
265*4882a593Smuzhiyun 	.reg_stride = 1,
266*4882a593Smuzhiyun 	.fast_io = true,
267*4882a593Smuzhiyun 	.reg_write = cdns_regmap_write,
268*4882a593Smuzhiyun 	.reg_read = cdns_regmap_read,
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun 
cdns_sierra_phy_init(struct phy * gphy)271*4882a593Smuzhiyun static int cdns_sierra_phy_init(struct phy *gphy)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
274*4882a593Smuzhiyun 	struct cdns_sierra_phy *phy = dev_get_drvdata(gphy->dev.parent);
275*4882a593Smuzhiyun 	struct regmap *regmap;
276*4882a593Smuzhiyun 	int i, j;
277*4882a593Smuzhiyun 	const struct cdns_reg_pairs *cmn_vals, *ln_vals;
278*4882a593Smuzhiyun 	u32 num_cmn_regs, num_ln_regs;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* Initialise the PHY registers, unless auto configured */
281*4882a593Smuzhiyun 	if (phy->autoconf)
282*4882a593Smuzhiyun 		return 0;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	clk_set_rate(phy->cmn_refclk_dig_div, 25000000);
285*4882a593Smuzhiyun 	clk_set_rate(phy->cmn_refclk1_dig_div, 25000000);
286*4882a593Smuzhiyun 	if (ins->phy_type == PHY_TYPE_PCIE) {
287*4882a593Smuzhiyun 		num_cmn_regs = phy->init_data->pcie_cmn_regs;
288*4882a593Smuzhiyun 		num_ln_regs = phy->init_data->pcie_ln_regs;
289*4882a593Smuzhiyun 		cmn_vals = phy->init_data->pcie_cmn_vals;
290*4882a593Smuzhiyun 		ln_vals = phy->init_data->pcie_ln_vals;
291*4882a593Smuzhiyun 	} else if (ins->phy_type == PHY_TYPE_USB3) {
292*4882a593Smuzhiyun 		num_cmn_regs = phy->init_data->usb_cmn_regs;
293*4882a593Smuzhiyun 		num_ln_regs = phy->init_data->usb_ln_regs;
294*4882a593Smuzhiyun 		cmn_vals = phy->init_data->usb_cmn_vals;
295*4882a593Smuzhiyun 		ln_vals = phy->init_data->usb_ln_vals;
296*4882a593Smuzhiyun 	} else {
297*4882a593Smuzhiyun 		return -EINVAL;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	regmap = phy->regmap_common_cdb;
301*4882a593Smuzhiyun 	for (j = 0; j < num_cmn_regs ; j++)
302*4882a593Smuzhiyun 		regmap_write(regmap, cmn_vals[j].off, cmn_vals[j].val);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	for (i = 0; i < ins->num_lanes; i++) {
305*4882a593Smuzhiyun 		for (j = 0; j < num_ln_regs ; j++) {
306*4882a593Smuzhiyun 			regmap = phy->regmap_lane_cdb[i + ins->mlane];
307*4882a593Smuzhiyun 			regmap_write(regmap, ln_vals[j].off, ln_vals[j].val);
308*4882a593Smuzhiyun 		}
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
cdns_sierra_phy_on(struct phy * gphy)314*4882a593Smuzhiyun static int cdns_sierra_phy_on(struct phy *gphy)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	struct cdns_sierra_phy *sp = dev_get_drvdata(gphy->dev.parent);
317*4882a593Smuzhiyun 	struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
318*4882a593Smuzhiyun 	struct device *dev = sp->dev;
319*4882a593Smuzhiyun 	u32 val;
320*4882a593Smuzhiyun 	int ret;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	ret = reset_control_deassert(sp->phy_rst);
323*4882a593Smuzhiyun 	if (ret) {
324*4882a593Smuzhiyun 		dev_err(dev, "Failed to take the PHY out of reset\n");
325*4882a593Smuzhiyun 		return ret;
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/* Take the PHY lane group out of reset */
329*4882a593Smuzhiyun 	ret = reset_control_deassert(ins->lnk_rst);
330*4882a593Smuzhiyun 	if (ret) {
331*4882a593Smuzhiyun 		dev_err(dev, "Failed to take the PHY lane out of reset\n");
332*4882a593Smuzhiyun 		return ret;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	ret = regmap_field_read_poll_timeout(sp->pllctrl_lock[ins->mlane],
336*4882a593Smuzhiyun 					     val, val, 1000, PLL_LOCK_TIME);
337*4882a593Smuzhiyun 	if (ret < 0)
338*4882a593Smuzhiyun 		dev_err(dev, "PLL lock of lane failed\n");
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return ret;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
cdns_sierra_phy_off(struct phy * gphy)343*4882a593Smuzhiyun static int cdns_sierra_phy_off(struct phy *gphy)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return reset_control_assert(ins->lnk_rst);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
cdns_sierra_phy_reset(struct phy * gphy)350*4882a593Smuzhiyun static int cdns_sierra_phy_reset(struct phy *gphy)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct cdns_sierra_phy *sp = dev_get_drvdata(gphy->dev.parent);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	reset_control_assert(sp->phy_rst);
355*4882a593Smuzhiyun 	reset_control_deassert(sp->phy_rst);
356*4882a593Smuzhiyun 	return 0;
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun static const struct phy_ops ops = {
360*4882a593Smuzhiyun 	.init		= cdns_sierra_phy_init,
361*4882a593Smuzhiyun 	.power_on	= cdns_sierra_phy_on,
362*4882a593Smuzhiyun 	.power_off	= cdns_sierra_phy_off,
363*4882a593Smuzhiyun 	.reset		= cdns_sierra_phy_reset,
364*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
365*4882a593Smuzhiyun };
366*4882a593Smuzhiyun 
cdns_sierra_get_optional(struct cdns_sierra_inst * inst,struct device_node * child)367*4882a593Smuzhiyun static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst,
368*4882a593Smuzhiyun 				    struct device_node *child)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	if (of_property_read_u32(child, "reg", &inst->mlane))
371*4882a593Smuzhiyun 		return -EINVAL;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (of_property_read_u32(child, "cdns,num-lanes", &inst->num_lanes))
374*4882a593Smuzhiyun 		return -EINVAL;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (of_property_read_u32(child, "cdns,phy-type", &inst->phy_type))
377*4882a593Smuzhiyun 		return -EINVAL;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun static const struct of_device_id cdns_sierra_id_table[];
383*4882a593Smuzhiyun 
cdns_regmap_init(struct device * dev,void __iomem * base,u32 block_offset,u8 reg_offset_shift,const struct regmap_config * config)384*4882a593Smuzhiyun static struct regmap *cdns_regmap_init(struct device *dev, void __iomem *base,
385*4882a593Smuzhiyun 				       u32 block_offset, u8 reg_offset_shift,
386*4882a593Smuzhiyun 				       const struct regmap_config *config)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	struct cdns_regmap_cdb_context *ctx;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
391*4882a593Smuzhiyun 	if (!ctx)
392*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	ctx->dev = dev;
395*4882a593Smuzhiyun 	ctx->base = base + block_offset;
396*4882a593Smuzhiyun 	ctx->reg_offset_shift = reg_offset_shift;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return devm_regmap_init(dev, NULL, ctx, config);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
cdns_regfield_init(struct cdns_sierra_phy * sp)401*4882a593Smuzhiyun static int cdns_regfield_init(struct cdns_sierra_phy *sp)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	struct device *dev = sp->dev;
404*4882a593Smuzhiyun 	struct regmap_field *field;
405*4882a593Smuzhiyun 	struct regmap *regmap;
406*4882a593Smuzhiyun 	int i;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	regmap = sp->regmap_common_cdb;
409*4882a593Smuzhiyun 	field = devm_regmap_field_alloc(dev, regmap, macro_id_type);
410*4882a593Smuzhiyun 	if (IS_ERR(field)) {
411*4882a593Smuzhiyun 		dev_err(dev, "MACRO_ID_TYPE reg field init failed\n");
412*4882a593Smuzhiyun 		return PTR_ERR(field);
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 	sp->macro_id_type = field;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	regmap = sp->regmap_phy_config_ctrl;
417*4882a593Smuzhiyun 	field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg_1);
418*4882a593Smuzhiyun 	if (IS_ERR(field)) {
419*4882a593Smuzhiyun 		dev_err(dev, "PHY_PLL_CFG_1 reg field init failed\n");
420*4882a593Smuzhiyun 		return PTR_ERR(field);
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 	sp->phy_pll_cfg_1 = field;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	for (i = 0; i < SIERRA_MAX_LANES; i++) {
425*4882a593Smuzhiyun 		regmap = sp->regmap_lane_cdb[i];
426*4882a593Smuzhiyun 		field = devm_regmap_field_alloc(dev, regmap, pllctrl_lock);
427*4882a593Smuzhiyun 		if (IS_ERR(field)) {
428*4882a593Smuzhiyun 			dev_err(dev, "P%d_ENABLE reg field init failed\n", i);
429*4882a593Smuzhiyun 			return PTR_ERR(field);
430*4882a593Smuzhiyun 		}
431*4882a593Smuzhiyun 		sp->pllctrl_lock[i] =  field;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
cdns_regmap_init_blocks(struct cdns_sierra_phy * sp,void __iomem * base,u8 block_offset_shift,u8 reg_offset_shift)437*4882a593Smuzhiyun static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp,
438*4882a593Smuzhiyun 				   void __iomem *base, u8 block_offset_shift,
439*4882a593Smuzhiyun 				   u8 reg_offset_shift)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	struct device *dev = sp->dev;
442*4882a593Smuzhiyun 	struct regmap *regmap;
443*4882a593Smuzhiyun 	u32 block_offset;
444*4882a593Smuzhiyun 	int i;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	for (i = 0; i < SIERRA_MAX_LANES; i++) {
447*4882a593Smuzhiyun 		block_offset = SIERRA_LANE_CDB_OFFSET(i, block_offset_shift,
448*4882a593Smuzhiyun 						      reg_offset_shift);
449*4882a593Smuzhiyun 		regmap = cdns_regmap_init(dev, base, block_offset,
450*4882a593Smuzhiyun 					  reg_offset_shift,
451*4882a593Smuzhiyun 					  &cdns_sierra_lane_cdb_config[i]);
452*4882a593Smuzhiyun 		if (IS_ERR(regmap)) {
453*4882a593Smuzhiyun 			dev_err(dev, "Failed to init lane CDB regmap\n");
454*4882a593Smuzhiyun 			return PTR_ERR(regmap);
455*4882a593Smuzhiyun 		}
456*4882a593Smuzhiyun 		sp->regmap_lane_cdb[i] = regmap;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	regmap = cdns_regmap_init(dev, base, SIERRA_COMMON_CDB_OFFSET,
460*4882a593Smuzhiyun 				  reg_offset_shift,
461*4882a593Smuzhiyun 				  &cdns_sierra_common_cdb_config);
462*4882a593Smuzhiyun 	if (IS_ERR(regmap)) {
463*4882a593Smuzhiyun 		dev_err(dev, "Failed to init common CDB regmap\n");
464*4882a593Smuzhiyun 		return PTR_ERR(regmap);
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 	sp->regmap_common_cdb = regmap;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	block_offset = SIERRA_PHY_CONFIG_CTRL_OFFSET(block_offset_shift);
469*4882a593Smuzhiyun 	regmap = cdns_regmap_init(dev, base, block_offset, reg_offset_shift,
470*4882a593Smuzhiyun 				  &cdns_sierra_phy_config_ctrl_config);
471*4882a593Smuzhiyun 	if (IS_ERR(regmap)) {
472*4882a593Smuzhiyun 		dev_err(dev, "Failed to init PHY config and control regmap\n");
473*4882a593Smuzhiyun 		return PTR_ERR(regmap);
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 	sp->regmap_phy_config_ctrl = regmap;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
cdns_sierra_phy_probe(struct platform_device * pdev)480*4882a593Smuzhiyun static int cdns_sierra_phy_probe(struct platform_device *pdev)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct cdns_sierra_phy *sp;
483*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
484*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
485*4882a593Smuzhiyun 	const struct of_device_id *match;
486*4882a593Smuzhiyun 	struct cdns_sierra_data *data;
487*4882a593Smuzhiyun 	unsigned int id_value;
488*4882a593Smuzhiyun 	struct resource *res;
489*4882a593Smuzhiyun 	int i, ret, node = 0;
490*4882a593Smuzhiyun 	void __iomem *base;
491*4882a593Smuzhiyun 	struct clk *clk;
492*4882a593Smuzhiyun 	struct device_node *dn = dev->of_node, *child;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (of_get_child_count(dn) == 0)
495*4882a593Smuzhiyun 		return -ENODEV;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	/* Get init data for this PHY */
498*4882a593Smuzhiyun 	match = of_match_device(cdns_sierra_id_table, dev);
499*4882a593Smuzhiyun 	if (!match)
500*4882a593Smuzhiyun 		return -EINVAL;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	data = (struct cdns_sierra_data *)match->data;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL);
505*4882a593Smuzhiyun 	if (!sp)
506*4882a593Smuzhiyun 		return -ENOMEM;
507*4882a593Smuzhiyun 	dev_set_drvdata(dev, sp);
508*4882a593Smuzhiyun 	sp->dev = dev;
509*4882a593Smuzhiyun 	sp->init_data = data;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
512*4882a593Smuzhiyun 	base = devm_ioremap_resource(dev, res);
513*4882a593Smuzhiyun 	if (IS_ERR(base)) {
514*4882a593Smuzhiyun 		dev_err(dev, "missing \"reg\"\n");
515*4882a593Smuzhiyun 		return PTR_ERR(base);
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	ret = cdns_regmap_init_blocks(sp, base, data->block_offset_shift,
519*4882a593Smuzhiyun 				      data->reg_offset_shift);
520*4882a593Smuzhiyun 	if (ret)
521*4882a593Smuzhiyun 		return ret;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	ret = cdns_regfield_init(sp);
524*4882a593Smuzhiyun 	if (ret)
525*4882a593Smuzhiyun 		return ret;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	platform_set_drvdata(pdev, sp);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	sp->clk = devm_clk_get_optional(dev, "phy_clk");
530*4882a593Smuzhiyun 	if (IS_ERR(sp->clk)) {
531*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock phy_clk\n");
532*4882a593Smuzhiyun 		return PTR_ERR(sp->clk);
533*4882a593Smuzhiyun 	}
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	sp->phy_rst = devm_reset_control_get(dev, "sierra_reset");
536*4882a593Smuzhiyun 	if (IS_ERR(sp->phy_rst)) {
537*4882a593Smuzhiyun 		dev_err(dev, "failed to get reset\n");
538*4882a593Smuzhiyun 		return PTR_ERR(sp->phy_rst);
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb");
542*4882a593Smuzhiyun 	if (IS_ERR(sp->apb_rst)) {
543*4882a593Smuzhiyun 		dev_err(dev, "failed to get apb reset\n");
544*4882a593Smuzhiyun 		return PTR_ERR(sp->apb_rst);
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div");
548*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
549*4882a593Smuzhiyun 		dev_err(dev, "cmn_refclk_dig_div clock not found\n");
550*4882a593Smuzhiyun 		ret = PTR_ERR(clk);
551*4882a593Smuzhiyun 		return ret;
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 	sp->cmn_refclk_dig_div = clk;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div");
556*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
557*4882a593Smuzhiyun 		dev_err(dev, "cmn_refclk1_dig_div clock not found\n");
558*4882a593Smuzhiyun 		ret = PTR_ERR(clk);
559*4882a593Smuzhiyun 		return ret;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 	sp->cmn_refclk1_dig_div = clk;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	ret = clk_prepare_enable(sp->clk);
564*4882a593Smuzhiyun 	if (ret)
565*4882a593Smuzhiyun 		return ret;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Enable APB */
568*4882a593Smuzhiyun 	reset_control_deassert(sp->apb_rst);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* Check that PHY is present */
571*4882a593Smuzhiyun 	regmap_field_read(sp->macro_id_type, &id_value);
572*4882a593Smuzhiyun 	if  (sp->init_data->id_value != id_value) {
573*4882a593Smuzhiyun 		ret = -EINVAL;
574*4882a593Smuzhiyun 		goto clk_disable;
575*4882a593Smuzhiyun 	}
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	sp->autoconf = of_property_read_bool(dn, "cdns,autoconf");
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	for_each_available_child_of_node(dn, child) {
580*4882a593Smuzhiyun 		struct phy *gphy;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 		sp->phys[node].lnk_rst =
583*4882a593Smuzhiyun 			of_reset_control_array_get_exclusive(child);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		if (IS_ERR(sp->phys[node].lnk_rst)) {
586*4882a593Smuzhiyun 			dev_err(dev, "failed to get reset %s\n",
587*4882a593Smuzhiyun 				child->full_name);
588*4882a593Smuzhiyun 			ret = PTR_ERR(sp->phys[node].lnk_rst);
589*4882a593Smuzhiyun 			goto put_child2;
590*4882a593Smuzhiyun 		}
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		if (!sp->autoconf) {
593*4882a593Smuzhiyun 			ret = cdns_sierra_get_optional(&sp->phys[node], child);
594*4882a593Smuzhiyun 			if (ret) {
595*4882a593Smuzhiyun 				dev_err(dev, "missing property in node %s\n",
596*4882a593Smuzhiyun 					child->name);
597*4882a593Smuzhiyun 				goto put_child;
598*4882a593Smuzhiyun 			}
599*4882a593Smuzhiyun 		}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 		sp->num_lanes += sp->phys[node].num_lanes;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 		gphy = devm_phy_create(dev, child, &ops);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 		if (IS_ERR(gphy)) {
606*4882a593Smuzhiyun 			ret = PTR_ERR(gphy);
607*4882a593Smuzhiyun 			goto put_child;
608*4882a593Smuzhiyun 		}
609*4882a593Smuzhiyun 		sp->phys[node].phy = gphy;
610*4882a593Smuzhiyun 		phy_set_drvdata(gphy, &sp->phys[node]);
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 		node++;
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 	sp->nsubnodes = node;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	if (sp->num_lanes > SIERRA_MAX_LANES) {
617*4882a593Smuzhiyun 		ret = -EINVAL;
618*4882a593Smuzhiyun 		dev_err(dev, "Invalid lane configuration\n");
619*4882a593Smuzhiyun 		goto put_child2;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	/* If more than one subnode, configure the PHY as multilink */
623*4882a593Smuzhiyun 	if (!sp->autoconf && sp->nsubnodes > 1)
624*4882a593Smuzhiyun 		regmap_field_write(sp->phy_pll_cfg_1, 0x1);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	pm_runtime_enable(dev);
627*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
628*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(phy_provider);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun put_child:
631*4882a593Smuzhiyun 	node++;
632*4882a593Smuzhiyun put_child2:
633*4882a593Smuzhiyun 	for (i = 0; i < node; i++)
634*4882a593Smuzhiyun 		reset_control_put(sp->phys[i].lnk_rst);
635*4882a593Smuzhiyun 	of_node_put(child);
636*4882a593Smuzhiyun clk_disable:
637*4882a593Smuzhiyun 	clk_disable_unprepare(sp->clk);
638*4882a593Smuzhiyun 	reset_control_assert(sp->apb_rst);
639*4882a593Smuzhiyun 	return ret;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun 
cdns_sierra_phy_remove(struct platform_device * pdev)642*4882a593Smuzhiyun static int cdns_sierra_phy_remove(struct platform_device *pdev)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun 	struct cdns_sierra_phy *phy = platform_get_drvdata(pdev);
645*4882a593Smuzhiyun 	int i;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	reset_control_assert(phy->phy_rst);
648*4882a593Smuzhiyun 	reset_control_assert(phy->apb_rst);
649*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	/*
652*4882a593Smuzhiyun 	 * The device level resets will be put automatically.
653*4882a593Smuzhiyun 	 * Need to put the subnode resets here though.
654*4882a593Smuzhiyun 	 */
655*4882a593Smuzhiyun 	for (i = 0; i < phy->nsubnodes; i++) {
656*4882a593Smuzhiyun 		reset_control_assert(phy->phys[i].lnk_rst);
657*4882a593Smuzhiyun 		reset_control_put(phy->phys[i].lnk_rst);
658*4882a593Smuzhiyun 	}
659*4882a593Smuzhiyun 	return 0;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun /* refclk100MHz_32b_PCIe_cmn_pll_ext_ssc */
663*4882a593Smuzhiyun static const struct cdns_reg_pairs cdns_pcie_cmn_regs_ext_ssc[] = {
664*4882a593Smuzhiyun 	{0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
665*4882a593Smuzhiyun 	{0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG},
666*4882a593Smuzhiyun 	{0x8A06, SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG},
667*4882a593Smuzhiyun 	{0x8A06, SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG},
668*4882a593Smuzhiyun 	{0x1B1B, SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG}
669*4882a593Smuzhiyun };
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun /* refclk100MHz_32b_PCIe_ln_ext_ssc */
672*4882a593Smuzhiyun static const struct cdns_reg_pairs cdns_pcie_ln_regs_ext_ssc[] = {
673*4882a593Smuzhiyun 	{0x813E, SIERRA_CLKPATHCTRL_TMR_PREG},
674*4882a593Smuzhiyun 	{0x8047, SIERRA_RX_CREQ_FLTR_A_MODE3_PREG},
675*4882a593Smuzhiyun 	{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE2_PREG},
676*4882a593Smuzhiyun 	{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
677*4882a593Smuzhiyun 	{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
678*4882a593Smuzhiyun 	{0x033C, SIERRA_RX_CTLE_MAINTENANCE_PREG},
679*4882a593Smuzhiyun 	{0x44CC, SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG}
680*4882a593Smuzhiyun };
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun /* refclk100MHz_20b_USB_cmn_pll_ext_ssc */
683*4882a593Smuzhiyun static const struct cdns_reg_pairs cdns_usb_cmn_regs_ext_ssc[] = {
684*4882a593Smuzhiyun 	{0x2085, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
685*4882a593Smuzhiyun 	{0x2085, SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG},
686*4882a593Smuzhiyun 	{0x0000, SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG},
687*4882a593Smuzhiyun 	{0x0000, SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG}
688*4882a593Smuzhiyun };
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun /* refclk100MHz_20b_USB_ln_ext_ssc */
691*4882a593Smuzhiyun static const struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
692*4882a593Smuzhiyun 	{0xFE0A, SIERRA_DET_STANDEC_A_PREG},
693*4882a593Smuzhiyun 	{0x000F, SIERRA_DET_STANDEC_B_PREG},
694*4882a593Smuzhiyun 	{0x55A5, SIERRA_DET_STANDEC_C_PREG},
695*4882a593Smuzhiyun 	{0x69ad, SIERRA_DET_STANDEC_D_PREG},
696*4882a593Smuzhiyun 	{0x0241, SIERRA_DET_STANDEC_E_PREG},
697*4882a593Smuzhiyun 	{0x0110, SIERRA_PSM_LANECAL_DLY_A1_RESETS_PREG},
698*4882a593Smuzhiyun 	{0x0014, SIERRA_PSM_A0IN_TMR_PREG},
699*4882a593Smuzhiyun 	{0xCF00, SIERRA_PSM_DIAG_PREG},
700*4882a593Smuzhiyun 	{0x001F, SIERRA_PSC_TX_A0_PREG},
701*4882a593Smuzhiyun 	{0x0007, SIERRA_PSC_TX_A1_PREG},
702*4882a593Smuzhiyun 	{0x0003, SIERRA_PSC_TX_A2_PREG},
703*4882a593Smuzhiyun 	{0x0003, SIERRA_PSC_TX_A3_PREG},
704*4882a593Smuzhiyun 	{0x0FFF, SIERRA_PSC_RX_A0_PREG},
705*4882a593Smuzhiyun 	{0x0003, SIERRA_PSC_RX_A1_PREG},
706*4882a593Smuzhiyun 	{0x0003, SIERRA_PSC_RX_A2_PREG},
707*4882a593Smuzhiyun 	{0x0001, SIERRA_PSC_RX_A3_PREG},
708*4882a593Smuzhiyun 	{0x0001, SIERRA_PLLCTRL_SUBRATE_PREG},
709*4882a593Smuzhiyun 	{0x0406, SIERRA_PLLCTRL_GEN_D_PREG},
710*4882a593Smuzhiyun 	{0x5233, SIERRA_PLLCTRL_CPGAIN_MODE_PREG},
711*4882a593Smuzhiyun 	{0x00CA, SIERRA_CLKPATH_BIASTRIM_PREG},
712*4882a593Smuzhiyun 	{0x2512, SIERRA_DFE_BIASTRIM_PREG},
713*4882a593Smuzhiyun 	{0x0000, SIERRA_DRVCTRL_ATTEN_PREG},
714*4882a593Smuzhiyun 	{0x823E, SIERRA_CLKPATHCTRL_TMR_PREG},
715*4882a593Smuzhiyun 	{0x078F, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
716*4882a593Smuzhiyun 	{0x078F, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
717*4882a593Smuzhiyun 	{0x7B3C, SIERRA_CREQ_CCLKDET_MODE01_PREG},
718*4882a593Smuzhiyun 	{0x023C, SIERRA_RX_CTLE_MAINTENANCE_PREG},
719*4882a593Smuzhiyun 	{0x3232, SIERRA_CREQ_FSMCLK_SEL_PREG},
720*4882a593Smuzhiyun 	{0x0000, SIERRA_CREQ_EQ_CTRL_PREG},
721*4882a593Smuzhiyun 	{0x0000, SIERRA_CREQ_SPARE_PREG},
722*4882a593Smuzhiyun 	{0xCC44, SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG},
723*4882a593Smuzhiyun 	{0x8452, SIERRA_CTLELUT_CTRL_PREG},
724*4882a593Smuzhiyun 	{0x4121, SIERRA_DFE_ECMP_RATESEL_PREG},
725*4882a593Smuzhiyun 	{0x4121, SIERRA_DFE_SMP_RATESEL_PREG},
726*4882a593Smuzhiyun 	{0x0003, SIERRA_DEQ_PHALIGN_CTRL},
727*4882a593Smuzhiyun 	{0x3200, SIERRA_DEQ_CONCUR_CTRL1_PREG},
728*4882a593Smuzhiyun 	{0x5064, SIERRA_DEQ_CONCUR_CTRL2_PREG},
729*4882a593Smuzhiyun 	{0x0030, SIERRA_DEQ_EPIPWR_CTRL2_PREG},
730*4882a593Smuzhiyun 	{0x0048, SIERRA_DEQ_FAST_MAINT_CYCLES_PREG},
731*4882a593Smuzhiyun 	{0x5A5A, SIERRA_DEQ_ERRCMP_CTRL_PREG},
732*4882a593Smuzhiyun 	{0x02F5, SIERRA_DEQ_OFFSET_CTRL_PREG},
733*4882a593Smuzhiyun 	{0x02F5, SIERRA_DEQ_GAIN_CTRL_PREG},
734*4882a593Smuzhiyun 	{0x9999, SIERRA_DEQ_VGATUNE_CTRL_PREG},
735*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT0},
736*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT1},
737*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT2},
738*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT3},
739*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT4},
740*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT5},
741*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT6},
742*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT7},
743*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT8},
744*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT9},
745*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT10},
746*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT11},
747*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT12},
748*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT13},
749*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT14},
750*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT15},
751*4882a593Smuzhiyun 	{0x0014, SIERRA_DEQ_GLUT16},
752*4882a593Smuzhiyun 	{0x0BAE, SIERRA_DEQ_ALUT0},
753*4882a593Smuzhiyun 	{0x0AEB, SIERRA_DEQ_ALUT1},
754*4882a593Smuzhiyun 	{0x0A28, SIERRA_DEQ_ALUT2},
755*4882a593Smuzhiyun 	{0x0965, SIERRA_DEQ_ALUT3},
756*4882a593Smuzhiyun 	{0x08A2, SIERRA_DEQ_ALUT4},
757*4882a593Smuzhiyun 	{0x07DF, SIERRA_DEQ_ALUT5},
758*4882a593Smuzhiyun 	{0x071C, SIERRA_DEQ_ALUT6},
759*4882a593Smuzhiyun 	{0x0659, SIERRA_DEQ_ALUT7},
760*4882a593Smuzhiyun 	{0x0596, SIERRA_DEQ_ALUT8},
761*4882a593Smuzhiyun 	{0x0514, SIERRA_DEQ_ALUT9},
762*4882a593Smuzhiyun 	{0x0492, SIERRA_DEQ_ALUT10},
763*4882a593Smuzhiyun 	{0x0410, SIERRA_DEQ_ALUT11},
764*4882a593Smuzhiyun 	{0x038E, SIERRA_DEQ_ALUT12},
765*4882a593Smuzhiyun 	{0x030C, SIERRA_DEQ_ALUT13},
766*4882a593Smuzhiyun 	{0x03F4, SIERRA_DEQ_DFETAP_CTRL_PREG},
767*4882a593Smuzhiyun 	{0x0001, SIERRA_DFE_EN_1010_IGNORE_PREG},
768*4882a593Smuzhiyun 	{0x3C01, SIERRA_DEQ_TAU_CTRL1_FAST_MAINT_PREG},
769*4882a593Smuzhiyun 	{0x3C40, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
770*4882a593Smuzhiyun 	{0x1C08, SIERRA_DEQ_TAU_CTRL2_PREG},
771*4882a593Smuzhiyun 	{0x0033, SIERRA_DEQ_PICTRL_PREG},
772*4882a593Smuzhiyun 	{0x0400, SIERRA_CPICAL_TMRVAL_MODE1_PREG},
773*4882a593Smuzhiyun 	{0x0330, SIERRA_CPICAL_TMRVAL_MODE0_PREG},
774*4882a593Smuzhiyun 	{0x01FF, SIERRA_CPICAL_PICNT_MODE1_PREG},
775*4882a593Smuzhiyun 	{0x0009, SIERRA_CPI_OUTBUF_RATESEL_PREG},
776*4882a593Smuzhiyun 	{0x3232, SIERRA_CPICAL_RES_STARTCODE_MODE23_PREG},
777*4882a593Smuzhiyun 	{0x0005, SIERRA_LFPSDET_SUPPORT_PREG},
778*4882a593Smuzhiyun 	{0x000F, SIERRA_LFPSFILT_NS_PREG},
779*4882a593Smuzhiyun 	{0x0009, SIERRA_LFPSFILT_RD_PREG},
780*4882a593Smuzhiyun 	{0x0001, SIERRA_LFPSFILT_MP_PREG},
781*4882a593Smuzhiyun 	{0x6013, SIERRA_SIGDET_SUPPORT_PREG},
782*4882a593Smuzhiyun 	{0x8013, SIERRA_SDFILT_H2L_A_PREG},
783*4882a593Smuzhiyun 	{0x8009, SIERRA_SDFILT_L2H_PREG},
784*4882a593Smuzhiyun 	{0x0024, SIERRA_RXBUFFER_CTLECTRL_PREG},
785*4882a593Smuzhiyun 	{0x0020, SIERRA_RXBUFFER_RCDFECTRL_PREG},
786*4882a593Smuzhiyun 	{0x4243, SIERRA_RXBUFFER_DFECTRL_PREG}
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun static const struct cdns_sierra_data cdns_map_sierra = {
790*4882a593Smuzhiyun 	SIERRA_MACRO_ID,
791*4882a593Smuzhiyun 	0x2,
792*4882a593Smuzhiyun 	0x2,
793*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_pcie_cmn_regs_ext_ssc),
794*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_pcie_ln_regs_ext_ssc),
795*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_usb_cmn_regs_ext_ssc),
796*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_usb_ln_regs_ext_ssc),
797*4882a593Smuzhiyun 	cdns_pcie_cmn_regs_ext_ssc,
798*4882a593Smuzhiyun 	cdns_pcie_ln_regs_ext_ssc,
799*4882a593Smuzhiyun 	cdns_usb_cmn_regs_ext_ssc,
800*4882a593Smuzhiyun 	cdns_usb_ln_regs_ext_ssc,
801*4882a593Smuzhiyun };
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun static const struct cdns_sierra_data cdns_ti_map_sierra = {
804*4882a593Smuzhiyun 	SIERRA_MACRO_ID,
805*4882a593Smuzhiyun 	0x0,
806*4882a593Smuzhiyun 	0x1,
807*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_pcie_cmn_regs_ext_ssc),
808*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_pcie_ln_regs_ext_ssc),
809*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_usb_cmn_regs_ext_ssc),
810*4882a593Smuzhiyun 	ARRAY_SIZE(cdns_usb_ln_regs_ext_ssc),
811*4882a593Smuzhiyun 	cdns_pcie_cmn_regs_ext_ssc,
812*4882a593Smuzhiyun 	cdns_pcie_ln_regs_ext_ssc,
813*4882a593Smuzhiyun 	cdns_usb_cmn_regs_ext_ssc,
814*4882a593Smuzhiyun 	cdns_usb_ln_regs_ext_ssc,
815*4882a593Smuzhiyun };
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun static const struct of_device_id cdns_sierra_id_table[] = {
818*4882a593Smuzhiyun 	{
819*4882a593Smuzhiyun 		.compatible = "cdns,sierra-phy-t0",
820*4882a593Smuzhiyun 		.data = &cdns_map_sierra,
821*4882a593Smuzhiyun 	},
822*4882a593Smuzhiyun 	{
823*4882a593Smuzhiyun 		.compatible = "ti,sierra-phy-t0",
824*4882a593Smuzhiyun 		.data = &cdns_ti_map_sierra,
825*4882a593Smuzhiyun 	},
826*4882a593Smuzhiyun 	{}
827*4882a593Smuzhiyun };
828*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, cdns_sierra_id_table);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun static struct platform_driver cdns_sierra_driver = {
831*4882a593Smuzhiyun 	.probe		= cdns_sierra_phy_probe,
832*4882a593Smuzhiyun 	.remove		= cdns_sierra_phy_remove,
833*4882a593Smuzhiyun 	.driver		= {
834*4882a593Smuzhiyun 		.name	= "cdns-sierra-phy",
835*4882a593Smuzhiyun 		.of_match_table = cdns_sierra_id_table,
836*4882a593Smuzhiyun 	},
837*4882a593Smuzhiyun };
838*4882a593Smuzhiyun module_platform_driver(cdns_sierra_driver);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun MODULE_ALIAS("platform:cdns_sierra");
841*4882a593Smuzhiyun MODULE_AUTHOR("Cadence Design Systems");
842*4882a593Smuzhiyun MODULE_DESCRIPTION("CDNS sierra phy driver");
843*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
844