18281c58fSMingkai Hu /*
28281c58fSMingkai Hu  * Copyright 2015 Freescale Semiconductor, Inc.
38281c58fSMingkai Hu  *
48281c58fSMingkai Hu  * SPDX-License-Identifier:	GPL-2.0+
58281c58fSMingkai Hu  */
68281c58fSMingkai Hu 
78281c58fSMingkai Hu #include <common.h>
88281c58fSMingkai Hu #include <asm/io.h>
91221ce45SMasahiro Yamada #include <linux/errno.h>
108281c58fSMingkai Hu #include <asm/arch/fsl_serdes.h>
118281c58fSMingkai Hu #include <asm/arch/soc.h>
128281c58fSMingkai Hu 
138281c58fSMingkai Hu #ifdef CONFIG_SYS_FSL_SRDS_1
148281c58fSMingkai Hu static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT];
158281c58fSMingkai Hu #endif
16da4d620cSQianyu Gong #ifdef CONFIG_SYS_FSL_SRDS_2
17da4d620cSQianyu Gong static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT];
18da4d620cSQianyu Gong #endif
198281c58fSMingkai Hu 
208281c58fSMingkai Hu int is_serdes_configured(enum srds_prtcl device)
218281c58fSMingkai Hu {
228281c58fSMingkai Hu 	int ret = 0;
238281c58fSMingkai Hu 
248281c58fSMingkai Hu #ifdef CONFIG_SYS_FSL_SRDS_1
2571fe2225SHou Zhiqiang 	if (!serdes1_prtcl_map[NONE])
2671fe2225SHou Zhiqiang 		fsl_serdes_init();
2771fe2225SHou Zhiqiang 
288281c58fSMingkai Hu 	ret |= serdes1_prtcl_map[device];
298281c58fSMingkai Hu #endif
30da4d620cSQianyu Gong #ifdef CONFIG_SYS_FSL_SRDS_2
3171fe2225SHou Zhiqiang 	if (!serdes2_prtcl_map[NONE])
3271fe2225SHou Zhiqiang 		fsl_serdes_init();
3371fe2225SHou Zhiqiang 
34da4d620cSQianyu Gong 	ret |= serdes2_prtcl_map[device];
35da4d620cSQianyu Gong #endif
368281c58fSMingkai Hu 
378281c58fSMingkai Hu 	return !!ret;
388281c58fSMingkai Hu }
398281c58fSMingkai Hu 
408281c58fSMingkai Hu int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
418281c58fSMingkai Hu {
428281c58fSMingkai Hu 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
438281c58fSMingkai Hu 	u32 cfg = gur_in32(&gur->rcwsr[4]);
448281c58fSMingkai Hu 	int i;
458281c58fSMingkai Hu 
468281c58fSMingkai Hu 	switch (sd) {
478281c58fSMingkai Hu #ifdef CONFIG_SYS_FSL_SRDS_1
488281c58fSMingkai Hu 	case FSL_SRDS_1:
498281c58fSMingkai Hu 		cfg &= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
508281c58fSMingkai Hu 		cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
518281c58fSMingkai Hu 		break;
528281c58fSMingkai Hu #endif
53da4d620cSQianyu Gong #ifdef CONFIG_SYS_FSL_SRDS_2
54da4d620cSQianyu Gong 	case FSL_SRDS_2:
55da4d620cSQianyu Gong 		cfg &= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
56da4d620cSQianyu Gong 		cfg >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
57da4d620cSQianyu Gong 		break;
58da4d620cSQianyu Gong #endif
598281c58fSMingkai Hu 	default:
608281c58fSMingkai Hu 		printf("invalid SerDes%d\n", sd);
618281c58fSMingkai Hu 		break;
628281c58fSMingkai Hu 	}
638281c58fSMingkai Hu 
648281c58fSMingkai Hu 	/* Is serdes enabled at all? */
658281c58fSMingkai Hu 	if (unlikely(cfg == 0))
668281c58fSMingkai Hu 		return -ENODEV;
678281c58fSMingkai Hu 
688281c58fSMingkai Hu 	for (i = 0; i < SRDS_MAX_LANES; i++) {
698281c58fSMingkai Hu 		if (serdes_get_prtcl(sd, cfg, i) == device)
708281c58fSMingkai Hu 			return i;
718281c58fSMingkai Hu 	}
728281c58fSMingkai Hu 
738281c58fSMingkai Hu 	return -ENODEV;
748281c58fSMingkai Hu }
758281c58fSMingkai Hu 
768281c58fSMingkai Hu int get_serdes_protocol(void)
778281c58fSMingkai Hu {
788281c58fSMingkai Hu 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
798281c58fSMingkai Hu 	u32 cfg = gur_in32(&gur->rcwsr[4]) &
808281c58fSMingkai Hu 			  FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
818281c58fSMingkai Hu 	cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
828281c58fSMingkai Hu 
838281c58fSMingkai Hu 	return cfg;
848281c58fSMingkai Hu }
858281c58fSMingkai Hu 
868281c58fSMingkai Hu const char *serdes_clock_to_string(u32 clock)
878281c58fSMingkai Hu {
888281c58fSMingkai Hu 	switch (clock) {
898281c58fSMingkai Hu 	case SRDS_PLLCR0_RFCK_SEL_100:
908281c58fSMingkai Hu 		return "100";
918281c58fSMingkai Hu 	case SRDS_PLLCR0_RFCK_SEL_125:
928281c58fSMingkai Hu 		return "125";
938281c58fSMingkai Hu 	case SRDS_PLLCR0_RFCK_SEL_156_25:
948281c58fSMingkai Hu 		return "156.25";
958281c58fSMingkai Hu 	default:
968281c58fSMingkai Hu 		return "100";
978281c58fSMingkai Hu 	}
988281c58fSMingkai Hu }
998281c58fSMingkai Hu 
1008281c58fSMingkai Hu void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
1018281c58fSMingkai Hu 		 u8 serdes_prtcl_map[SERDES_PRCTL_COUNT])
1028281c58fSMingkai Hu {
1038281c58fSMingkai Hu 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
1048281c58fSMingkai Hu 	u32 cfg;
1058281c58fSMingkai Hu 	int lane;
1068281c58fSMingkai Hu 
10771fe2225SHou Zhiqiang 	if (serdes_prtcl_map[NONE])
10871fe2225SHou Zhiqiang 		return;
10971fe2225SHou Zhiqiang 
1101a338921STom Rini 	memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
1118281c58fSMingkai Hu 
1128281c58fSMingkai Hu 	cfg = gur_in32(&gur->rcwsr[4]) & sd_prctl_mask;
1138281c58fSMingkai Hu 	cfg >>= sd_prctl_shift;
1148281c58fSMingkai Hu 	printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
1158281c58fSMingkai Hu 
1168281c58fSMingkai Hu 	if (!is_serdes_prtcl_valid(sd, cfg))
1178281c58fSMingkai Hu 		printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
1188281c58fSMingkai Hu 
1198281c58fSMingkai Hu 	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
1208281c58fSMingkai Hu 		enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
1218281c58fSMingkai Hu 
1228281c58fSMingkai Hu 		if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT))
1238281c58fSMingkai Hu 			debug("Unknown SerDes lane protocol %d\n", lane_prtcl);
1248281c58fSMingkai Hu 		else
1258281c58fSMingkai Hu 			serdes_prtcl_map[lane_prtcl] = 1;
1268281c58fSMingkai Hu 	}
12771fe2225SHou Zhiqiang 
12871fe2225SHou Zhiqiang 	/* Set the first element to indicate serdes has been initialized */
12971fe2225SHou Zhiqiang 	serdes_prtcl_map[NONE] = 1;
1308281c58fSMingkai Hu }
1318281c58fSMingkai Hu 
132*031acdbaSHou Zhiqiang __weak int get_serdes_volt(void)
133*031acdbaSHou Zhiqiang {
134*031acdbaSHou Zhiqiang 	return -1;
135*031acdbaSHou Zhiqiang }
136*031acdbaSHou Zhiqiang 
137*031acdbaSHou Zhiqiang __weak int set_serdes_volt(int svdd)
138*031acdbaSHou Zhiqiang {
139*031acdbaSHou Zhiqiang 	return -1;
140*031acdbaSHou Zhiqiang }
141*031acdbaSHou Zhiqiang 
142*031acdbaSHou Zhiqiang int setup_serdes_volt(u32 svdd)
143*031acdbaSHou Zhiqiang {
144*031acdbaSHou Zhiqiang 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
145*031acdbaSHou Zhiqiang 	struct ccsr_serdes *serdes1_base;
146*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
147*031acdbaSHou Zhiqiang 	struct ccsr_serdes *serdes2_base;
148*031acdbaSHou Zhiqiang #endif
149*031acdbaSHou Zhiqiang 	u32 cfg_rcw4 = gur_in32(&gur->rcwsr[4]);
150*031acdbaSHou Zhiqiang 	u32 cfg_rcw5 = gur_in32(&gur->rcwsr[5]);
151*031acdbaSHou Zhiqiang 	u32 cfg_tmp, reg = 0;
152*031acdbaSHou Zhiqiang 	int svdd_cur, svdd_tar;
153*031acdbaSHou Zhiqiang 	int ret;
154*031acdbaSHou Zhiqiang 	int i;
155*031acdbaSHou Zhiqiang 
156*031acdbaSHou Zhiqiang 	/* Only support switch SVDD to 900mV/1000mV */
157*031acdbaSHou Zhiqiang 	if (svdd != 900 && svdd != 1000)
158*031acdbaSHou Zhiqiang 		return -EINVAL;
159*031acdbaSHou Zhiqiang 
160*031acdbaSHou Zhiqiang 	svdd_tar = svdd;
161*031acdbaSHou Zhiqiang 	svdd_cur = get_serdes_volt();
162*031acdbaSHou Zhiqiang 	if (svdd_cur < 0)
163*031acdbaSHou Zhiqiang 		return -EINVAL;
164*031acdbaSHou Zhiqiang 
165*031acdbaSHou Zhiqiang 	debug("%s: current SVDD: %dmV; target SVDD: %dmV\n",
166*031acdbaSHou Zhiqiang 	      __func__, svdd_cur, svdd_tar);
167*031acdbaSHou Zhiqiang 	if (svdd_cur == svdd_tar)
168*031acdbaSHou Zhiqiang 		return 0;
169*031acdbaSHou Zhiqiang 
170*031acdbaSHou Zhiqiang 	serdes1_base = (void *)CONFIG_SYS_FSL_SERDES_ADDR;
171*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
172*031acdbaSHou Zhiqiang 	serdes2_base = (void *)serdes1_base + 0x10000;
173*031acdbaSHou Zhiqiang #endif
174*031acdbaSHou Zhiqiang 
175*031acdbaSHou Zhiqiang 	/* Put the all enabled lanes in reset */
176*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
177*031acdbaSHou Zhiqiang 	cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
178*031acdbaSHou Zhiqiang 	cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
179*031acdbaSHou Zhiqiang 
180*031acdbaSHou Zhiqiang 	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
181*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->lane[i].gcr0);
182*031acdbaSHou Zhiqiang 		reg &= 0xFF9FFFFF;
183*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->lane[i].gcr0, reg);
184*031acdbaSHou Zhiqiang 	}
185*031acdbaSHou Zhiqiang #endif
186*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
187*031acdbaSHou Zhiqiang 	cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
188*031acdbaSHou Zhiqiang 	cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
189*031acdbaSHou Zhiqiang 
190*031acdbaSHou Zhiqiang 	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
191*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->lane[i].gcr0);
192*031acdbaSHou Zhiqiang 		reg &= 0xFF9FFFFF;
193*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->lane[i].gcr0, reg);
194*031acdbaSHou Zhiqiang 	}
195*031acdbaSHou Zhiqiang #endif
196*031acdbaSHou Zhiqiang 
197*031acdbaSHou Zhiqiang 	/* Put the all enabled PLL in reset */
198*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
199*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
200*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
201*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].rstctl);
202*031acdbaSHou Zhiqiang 		reg &= 0xFFFFFFBF;
203*031acdbaSHou Zhiqiang 		reg |= 0x10000000;
204*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->bank[i].rstctl, reg);
205*031acdbaSHou Zhiqiang 		udelay(1);
206*031acdbaSHou Zhiqiang 
207*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].rstctl);
208*031acdbaSHou Zhiqiang 		reg &= 0xFFFFFF1F;
209*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->bank[i].rstctl, reg);
210*031acdbaSHou Zhiqiang 	}
211*031acdbaSHou Zhiqiang 	udelay(1);
212*031acdbaSHou Zhiqiang #endif
213*031acdbaSHou Zhiqiang 
214*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
215*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
216*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
217*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].rstctl);
218*031acdbaSHou Zhiqiang 		reg &= 0xFFFFFFBF;
219*031acdbaSHou Zhiqiang 		reg |= 0x10000000;
220*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->bank[i].rstctl, reg);
221*031acdbaSHou Zhiqiang 		udelay(1);
222*031acdbaSHou Zhiqiang 
223*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].rstctl);
224*031acdbaSHou Zhiqiang 		reg &= 0xFFFFFF1F;
225*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->bank[i].rstctl, reg);
226*031acdbaSHou Zhiqiang 	}
227*031acdbaSHou Zhiqiang 	udelay(1);
228*031acdbaSHou Zhiqiang #endif
229*031acdbaSHou Zhiqiang 
230*031acdbaSHou Zhiqiang 	/* Put the Rx/Tx calibration into reset */
231*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
232*031acdbaSHou Zhiqiang 	reg = in_be32(&serdes1_base->srdstcalcr);
233*031acdbaSHou Zhiqiang 	reg &= 0xF7FFFFFF;
234*031acdbaSHou Zhiqiang 	out_be32(&serdes1_base->srdstcalcr, reg);
235*031acdbaSHou Zhiqiang 	reg = in_be32(&serdes1_base->srdsrcalcr);
236*031acdbaSHou Zhiqiang 	reg &= 0xF7FFFFFF;
237*031acdbaSHou Zhiqiang 	out_be32(&serdes1_base->srdsrcalcr, reg);
238*031acdbaSHou Zhiqiang 
239*031acdbaSHou Zhiqiang #endif
240*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
241*031acdbaSHou Zhiqiang 	reg = in_be32(&serdes2_base->srdstcalcr);
242*031acdbaSHou Zhiqiang 	reg &= 0xF7FFFFFF;
243*031acdbaSHou Zhiqiang 	out_be32(&serdes2_base->srdstcalcr, reg);
244*031acdbaSHou Zhiqiang 	reg = in_be32(&serdes2_base->srdsrcalcr);
245*031acdbaSHou Zhiqiang 	reg &= 0xF7FFFFFF;
246*031acdbaSHou Zhiqiang 	out_be32(&serdes2_base->srdsrcalcr, reg);
247*031acdbaSHou Zhiqiang #endif
248*031acdbaSHou Zhiqiang 
249*031acdbaSHou Zhiqiang 	/*
250*031acdbaSHou Zhiqiang 	 * If SVDD set failed, will not return directly, so that the
251*031acdbaSHou Zhiqiang 	 * serdes lanes can complete reseting.
252*031acdbaSHou Zhiqiang 	 */
253*031acdbaSHou Zhiqiang 	ret = set_serdes_volt(svdd_tar);
254*031acdbaSHou Zhiqiang 	if (ret)
255*031acdbaSHou Zhiqiang 		printf("%s: Failed to set SVDD\n", __func__);
256*031acdbaSHou Zhiqiang 
257*031acdbaSHou Zhiqiang 	/* Wait for SVDD to stabilize */
258*031acdbaSHou Zhiqiang 	udelay(100);
259*031acdbaSHou Zhiqiang 
260*031acdbaSHou Zhiqiang 	/* For each PLL that’s not disabled via RCW */
261*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
262*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
263*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
264*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].rstctl);
265*031acdbaSHou Zhiqiang 		reg |= 0x00000020;
266*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->bank[i].rstctl, reg);
267*031acdbaSHou Zhiqiang 		udelay(1);
268*031acdbaSHou Zhiqiang 
269*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].rstctl);
270*031acdbaSHou Zhiqiang 		reg |= 0x00000080;
271*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->bank[i].rstctl, reg);
272*031acdbaSHou Zhiqiang 
273*031acdbaSHou Zhiqiang 		/* Take the Rx/Tx calibration out of reset */
274*031acdbaSHou Zhiqiang 		if (!(cfg_tmp == 0x3 && i == 1)) {
275*031acdbaSHou Zhiqiang 			udelay(1);
276*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes1_base->srdstcalcr);
277*031acdbaSHou Zhiqiang 			reg |= 0x08000000;
278*031acdbaSHou Zhiqiang 			out_be32(&serdes1_base->srdstcalcr, reg);
279*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes1_base->srdsrcalcr);
280*031acdbaSHou Zhiqiang 			reg |= 0x08000000;
281*031acdbaSHou Zhiqiang 			out_be32(&serdes1_base->srdsrcalcr, reg);
282*031acdbaSHou Zhiqiang 		}
283*031acdbaSHou Zhiqiang 	}
284*031acdbaSHou Zhiqiang 	udelay(1);
285*031acdbaSHou Zhiqiang #endif
286*031acdbaSHou Zhiqiang 
287*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
288*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
289*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
290*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].rstctl);
291*031acdbaSHou Zhiqiang 		reg |= 0x00000020;
292*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->bank[i].rstctl, reg);
293*031acdbaSHou Zhiqiang 		udelay(1);
294*031acdbaSHou Zhiqiang 
295*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].rstctl);
296*031acdbaSHou Zhiqiang 		reg |= 0x00000080;
297*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->bank[i].rstctl, reg);
298*031acdbaSHou Zhiqiang 
299*031acdbaSHou Zhiqiang 		/* Take the Rx/Tx calibration out of reset */
300*031acdbaSHou Zhiqiang 		if (!(cfg_tmp == 0x3 && i == 1)) {
301*031acdbaSHou Zhiqiang 			udelay(1);
302*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes2_base->srdstcalcr);
303*031acdbaSHou Zhiqiang 			reg |= 0x08000000;
304*031acdbaSHou Zhiqiang 			out_be32(&serdes2_base->srdstcalcr, reg);
305*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes2_base->srdsrcalcr);
306*031acdbaSHou Zhiqiang 			reg |= 0x08000000;
307*031acdbaSHou Zhiqiang 			out_be32(&serdes2_base->srdsrcalcr, reg);
308*031acdbaSHou Zhiqiang 		}
309*031acdbaSHou Zhiqiang 	}
310*031acdbaSHou Zhiqiang 	udelay(1);
311*031acdbaSHou Zhiqiang 
312*031acdbaSHou Zhiqiang #endif
313*031acdbaSHou Zhiqiang 
314*031acdbaSHou Zhiqiang 	/* Wait for at lesat 625us to ensure the PLLs being reset are locked */
315*031acdbaSHou Zhiqiang 	udelay(800);
316*031acdbaSHou Zhiqiang 
317*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
318*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
319*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
320*031acdbaSHou Zhiqiang 		/* if the PLL is not locked, set RST_ERR */
321*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].pllcr0);
322*031acdbaSHou Zhiqiang 		if (!((reg >> 23) & 0x1)) {
323*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes1_base->bank[i].rstctl);
324*031acdbaSHou Zhiqiang 			reg |= 0x20000000;
325*031acdbaSHou Zhiqiang 			out_be32(&serdes1_base->bank[i].rstctl, reg);
326*031acdbaSHou Zhiqiang 		} else {
327*031acdbaSHou Zhiqiang 			udelay(1);
328*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes1_base->bank[i].rstctl);
329*031acdbaSHou Zhiqiang 			reg &= 0xFFFFFFEF;
330*031acdbaSHou Zhiqiang 			reg |= 0x00000040;
331*031acdbaSHou Zhiqiang 			out_be32(&serdes1_base->bank[i].rstctl, reg);
332*031acdbaSHou Zhiqiang 			udelay(1);
333*031acdbaSHou Zhiqiang 		}
334*031acdbaSHou Zhiqiang 	}
335*031acdbaSHou Zhiqiang #endif
336*031acdbaSHou Zhiqiang 
337*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
338*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
339*031acdbaSHou Zhiqiang 	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
340*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].pllcr0);
341*031acdbaSHou Zhiqiang 		if (!((reg >> 23) & 0x1)) {
342*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes2_base->bank[i].rstctl);
343*031acdbaSHou Zhiqiang 			reg |= 0x20000000;
344*031acdbaSHou Zhiqiang 			out_be32(&serdes2_base->bank[i].rstctl, reg);
345*031acdbaSHou Zhiqiang 		} else {
346*031acdbaSHou Zhiqiang 			udelay(1);
347*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes2_base->bank[i].rstctl);
348*031acdbaSHou Zhiqiang 			reg &= 0xFFFFFFEF;
349*031acdbaSHou Zhiqiang 			reg |= 0x00000040;
350*031acdbaSHou Zhiqiang 			out_be32(&serdes2_base->bank[i].rstctl, reg);
351*031acdbaSHou Zhiqiang 			udelay(1);
352*031acdbaSHou Zhiqiang 		}
353*031acdbaSHou Zhiqiang 	}
354*031acdbaSHou Zhiqiang #endif
355*031acdbaSHou Zhiqiang 
356*031acdbaSHou Zhiqiang 	/* Take the all enabled lanes out of reset */
357*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
358*031acdbaSHou Zhiqiang 	cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
359*031acdbaSHou Zhiqiang 	cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
360*031acdbaSHou Zhiqiang 
361*031acdbaSHou Zhiqiang 	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
362*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->lane[i].gcr0);
363*031acdbaSHou Zhiqiang 		reg |= 0x00600000;
364*031acdbaSHou Zhiqiang 		out_be32(&serdes1_base->lane[i].gcr0, reg);
365*031acdbaSHou Zhiqiang 	}
366*031acdbaSHou Zhiqiang #endif
367*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
368*031acdbaSHou Zhiqiang 	cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
369*031acdbaSHou Zhiqiang 	cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
370*031acdbaSHou Zhiqiang 
371*031acdbaSHou Zhiqiang 	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
372*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->lane[i].gcr0);
373*031acdbaSHou Zhiqiang 		reg |= 0x00600000;
374*031acdbaSHou Zhiqiang 		out_be32(&serdes2_base->lane[i].gcr0, reg);
375*031acdbaSHou Zhiqiang 	}
376*031acdbaSHou Zhiqiang #endif
377*031acdbaSHou Zhiqiang 	/* For each PLL being reset, and achieved PLL lock set RST_DONE */
378*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_1
379*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
380*031acdbaSHou Zhiqiang 	for (i = 0; i < 2; i++) {
381*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes1_base->bank[i].pllcr0);
382*031acdbaSHou Zhiqiang 		if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
383*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes1_base->bank[i].rstctl);
384*031acdbaSHou Zhiqiang 			reg |= 0x40000000;
385*031acdbaSHou Zhiqiang 			out_be32(&serdes1_base->bank[i].rstctl, reg);
386*031acdbaSHou Zhiqiang 		}
387*031acdbaSHou Zhiqiang 	}
388*031acdbaSHou Zhiqiang #endif
389*031acdbaSHou Zhiqiang #ifdef CONFIG_SYS_FSL_SRDS_2
390*031acdbaSHou Zhiqiang 	cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
391*031acdbaSHou Zhiqiang 	for (i = 0; i < 2; i++) {
392*031acdbaSHou Zhiqiang 		reg = in_be32(&serdes2_base->bank[i].pllcr0);
393*031acdbaSHou Zhiqiang 		if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
394*031acdbaSHou Zhiqiang 			reg = in_be32(&serdes2_base->bank[i].rstctl);
395*031acdbaSHou Zhiqiang 			reg |= 0x40000000;
396*031acdbaSHou Zhiqiang 			out_be32(&serdes2_base->bank[i].rstctl, reg);
397*031acdbaSHou Zhiqiang 		}
398*031acdbaSHou Zhiqiang 	}
399*031acdbaSHou Zhiqiang #endif
400*031acdbaSHou Zhiqiang 
401*031acdbaSHou Zhiqiang 	return ret;
402*031acdbaSHou Zhiqiang }
403*031acdbaSHou Zhiqiang 
4048281c58fSMingkai Hu void fsl_serdes_init(void)
4058281c58fSMingkai Hu {
4068281c58fSMingkai Hu #ifdef CONFIG_SYS_FSL_SRDS_1
4078281c58fSMingkai Hu 	serdes_init(FSL_SRDS_1,
4088281c58fSMingkai Hu 		    CONFIG_SYS_FSL_SERDES_ADDR,
4098281c58fSMingkai Hu 		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK,
4108281c58fSMingkai Hu 		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT,
4118281c58fSMingkai Hu 		    serdes1_prtcl_map);
4128281c58fSMingkai Hu #endif
413da4d620cSQianyu Gong #ifdef CONFIG_SYS_FSL_SRDS_2
414da4d620cSQianyu Gong 	serdes_init(FSL_SRDS_2,
415da4d620cSQianyu Gong 		    CONFIG_SYS_FSL_SERDES_ADDR,
416da4d620cSQianyu Gong 		    FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK,
417da4d620cSQianyu Gong 		    FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT,
418da4d620cSQianyu Gong 		    serdes2_prtcl_map);
419da4d620cSQianyu Gong #endif
4208281c58fSMingkai Hu }
421