summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
blob: d39f96352ef9d9c839fc879d9ef41c7df0323035 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
/*
 * Copyright 2009-2011 Freescale Semiconductor, Inc.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
#include <hwconfig.h>
#endif
#include <asm/fsl_serdes.h>
#include <asm/immap_85xx.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/fsl_law.h>
#include <asm/errno.h>
#include "fsl_corenet_serdes.h"

static u32 serdes_prtcl_map;

#define HWCONFIG_BUFFER_SIZE	128

#ifdef DEBUG
static const char *serdes_prtcl_str[] = {
	[NONE] = "NA",
	[PCIE1] = "PCIE1",
	[PCIE2] = "PCIE2",
	[PCIE3] = "PCIE3",
	[PCIE4] = "PCIE4",
	[SATA1] = "SATA1",
	[SATA2] = "SATA2",
	[SRIO1] = "SRIO1",
	[SRIO2] = "SRIO2",
	[SGMII_FM1_DTSEC1] = "SGMII_FM1_DTSEC1",
	[SGMII_FM1_DTSEC2] = "SGMII_FM1_DTSEC2",
	[SGMII_FM1_DTSEC3] = "SGMII_FM1_DTSEC3",
	[SGMII_FM1_DTSEC4] = "SGMII_FM1_DTSEC4",
	[SGMII_FM1_DTSEC5] = "SGMII_FM1_DTSEC5",
	[SGMII_FM2_DTSEC1] = "SGMII_FM2_DTSEC1",
	[SGMII_FM2_DTSEC2] = "SGMII_FM2_DTSEC2",
	[SGMII_FM2_DTSEC3] = "SGMII_FM2_DTSEC3",
	[SGMII_FM2_DTSEC4] = "SGMII_FM2_DTSEC4",
	[XAUI_FM1] = "XAUI_FM1",
	[XAUI_FM2] = "XAUI_FM2",
	[AURORA] = "DEBUG",
};
#endif

static const struct {
	int idx;
	unsigned int lpd; /* RCW lane powerdown bit */
	int bank;
} lanes[SRDS_MAX_LANES] = {
	{ 0, 152, FSL_SRDS_BANK_1 },
	{ 1, 153, FSL_SRDS_BANK_1 },
	{ 2, 154, FSL_SRDS_BANK_1 },
	{ 3, 155, FSL_SRDS_BANK_1 },
	{ 4, 156, FSL_SRDS_BANK_1 },
	{ 5, 157, FSL_SRDS_BANK_1 },
	{ 6, 158, FSL_SRDS_BANK_1 },
	{ 7, 159, FSL_SRDS_BANK_1 },
	{ 8, 160, FSL_SRDS_BANK_1 },
	{ 9, 161, FSL_SRDS_BANK_1 },
	{ 16, 162, FSL_SRDS_BANK_2 },
	{ 17, 163, FSL_SRDS_BANK_2 },
	{ 18, 164, FSL_SRDS_BANK_2 },
	{ 19, 165, FSL_SRDS_BANK_2 },
	{ 20, 170, FSL_SRDS_BANK_3 },
	{ 21, 171, FSL_SRDS_BANK_3 },
	{ 22, 172, FSL_SRDS_BANK_3 },
	{ 23, 173, FSL_SRDS_BANK_3 },
};

int serdes_get_lane_idx(int lane)
{
	return lanes[lane].idx;
}

int serdes_get_bank_by_lane(int lane)
{
	return lanes[lane].bank;
}

int serdes_lane_enabled(int lane)
{
	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
	serdes_corenet_t *regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;

	int bank = lanes[lane].bank;
	int word = lanes[lane].lpd / 32;
	int bit = lanes[lane].lpd % 32;

	if (in_be32(&regs->bank[bank].rstctl) & SRDS_RSTCTL_SDPD)
		return 0;

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
	/*
	 * For banks two and three, use the srds_lpd_b[] array instead of the
	 * RCW, because this array contains the real values of SRDS_LPD_B2 and
	 * SRDS_LPD_B3.
	 */
	if (bank > 0)
		return !(srds_lpd_b[bank] & (8 >> (lane - (6 + 4 * bank))));
#endif

	return !(in_be32(&gur->rcwsr[word]) & (0x80000000 >> bit));
}

int is_serdes_configured(enum srds_prtcl device)
{
	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);

	/* Is serdes enabled at all? */
	if (!(in_be32(&gur->rcwsr[5]) & FSL_CORENET_RCWSR5_SRDS_EN))
		return 0;

	return (1 << device) & serdes_prtcl_map;
}

static int __serdes_get_first_lane(uint32_t prtcl, enum srds_prtcl device)
{
	int i;

	for (i = 0; i < SRDS_MAX_LANES; i++) {
		if (serdes_get_prtcl(prtcl, i) == device)
			return i;
	}

	return -ENODEV;
}

/*
 * Returns the SERDES lane (0..SRDS_MAX_LANES-1) that routes to the given
 * device. This depends on the current SERDES protocol, as defined in the RCW.
 *
 * Returns a negative error code if SERDES is disabled or the given device is
 * not supported in the current SERDES protocol.
 */
int serdes_get_first_lane(enum srds_prtcl device)
{
	u32 prtcl;
	const ccsr_gur_t *gur;

	gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;

	/* Is serdes enabled at all? */
	if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
		return -ENODEV;

	prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;

	return __serdes_get_first_lane(prtcl, device);
}

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
/*
 * Returns the SERDES bank (1, 2, or 3) that a given device is on for a given
 * SERDES protocol.
 *
 * Returns a negative error code if the given device is not supported for the
 * given SERDES protocol.
 */
static int serdes_get_bank_by_device(uint32_t prtcl, enum srds_prtcl device)
{
	int lane;

	lane = __serdes_get_first_lane(prtcl, device);
	if (unlikely(lane < 0))
		return lane;

	return serdes_get_bank_by_lane(lane);
}

static uint32_t __serdes_get_lane_count(uint32_t prtcl, enum srds_prtcl device,
					int first)
{
	int lane;

	for (lane = first; lane < SRDS_MAX_LANES; lane++) {
		if (serdes_get_prtcl(prtcl, lane) != device)
			break;
	}

	return lane - first;
}

static void __serdes_reset_rx(serdes_corenet_t *regs,
			      uint32_t prtcl,
			      enum srds_prtcl device)
{
	int lane, idx, first, last;

	lane = __serdes_get_first_lane(prtcl, device);
	if (unlikely(lane < 0))
		return;
	first = serdes_get_lane_idx(lane);
	last = first + __serdes_get_lane_count(prtcl, device, lane);

	/*
	 * Set BnGCRy0[RRST] = 0 for each lane in the each bank that is
	 * selected as XAUI to place the lane into reset.
	*/
	for (idx = first; idx < last; idx++)
		clrbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);

	/* Wait at least 250 ns */
	udelay(1);

	/*
	 * Set BnGCRy0[RRST] = 1 for each lane in the each bank that is
	 * selected as XAUI to bring the lane out of reset.
	 */
	for (idx = first; idx < last; idx++)
		setbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);
}

void serdes_reset_rx(enum srds_prtcl device)
{
	u32 prtcl;
	const ccsr_gur_t *gur;
	serdes_corenet_t *regs;

	if (unlikely(device == NONE))
		return;

	gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;

	/* Is serdes enabled at all? */
	if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
		return;

	regs = (typeof(regs))CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
	prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;

	__serdes_reset_rx(regs, prtcl, device);
}
#endif

#ifndef CONFIG_SYS_DCSRBAR_PHYS
#define CONFIG_SYS_DCSRBAR_PHYS	0x80000000 /* Must be 1GB-aligned for rev1.0 */
#define CONFIG_SYS_DCSRBAR	0x80000000
#define __DCSR_NOT_DEFINED_BY_CONFIG
#endif

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
static void enable_bank(ccsr_gur_t *gur, int bank)
{
	u32 rcw5;

	/*
	 * Enable the lanes SRDS_LPD_Bn.  The RCW bits are read-only in
	 * CCSR, and read/write in DSCR.
	 */
	rcw5 = in_be32(gur->rcwsr + 5);
	if (bank == FSL_SRDS_BANK_2) {
		rcw5 &= ~FSL_CORENET_RCWSRn_SRDS_LPD_B2;
		rcw5 |= srds_lpd_b[bank] << 26;
	} else if (bank == FSL_SRDS_BANK_3) {
		rcw5 &= ~FSL_CORENET_RCWSRn_SRDS_LPD_B3;
		rcw5 |= srds_lpd_b[bank] << 18;
	} else {
		printf("SERDES: enable_bank: bad bank %d\n", bank + 1);
		return;
	}

	/* See similar code in cpu/mpc85xx/cpu_init.c for an explanation
	 * of the DCSR mapping.
	 */
	{
#ifdef __DCSR_NOT_DEFINED_BY_CONFIG
		struct law_entry law = find_law(CONFIG_SYS_DCSRBAR_PHYS);
		int law_index;
		if (law.index == -1)
			law_index = set_next_law(CONFIG_SYS_DCSRBAR_PHYS,
						 LAW_SIZE_1M, LAW_TRGT_IF_DCSR);
		else
			set_law(law.index, CONFIG_SYS_DCSRBAR_PHYS, LAW_SIZE_1M,
				LAW_TRGT_IF_DCSR);
#endif
		u32 *p = (void *)CONFIG_SYS_DCSRBAR + 0x20114;
		out_be32(p, rcw5);
#ifdef __DCSR_NOT_DEFINED_BY_CONFIG
		if (law.index == -1)
			disable_law(law_index);
		else
			set_law(law.index, law.addr, law.size, law.trgt_id);
#endif
	}
}

/*
 * To avoid problems with clock jitter, rev 2 p4080 uses the pll from
 * bank 3 to clock banks 2 and 3, as well as a limited selection of
 * protocol configurations.  This requires that banks 2 and 3's lanes be
 * disabled in the RCW, and enabled with some fixup here to re-enable
 * them, and to configure bank 2's clock parameters in bank 3's pll in
 * cases where they differ.
 */
static void p4080_erratum_serdes8(serdes_corenet_t *regs, ccsr_gur_t *gur,
				  u32 devdisr, u32 devdisr2, int cfg)
{
	int srds_ratio_b2;
	int rfck_sel;

	/*
	 * The disabled lanes of bank 2 will cause the associated
	 * logic blocks to be disabled in DEVDISR.  We reverse that here.
	 *
	 * Note that normally it is not permitted to clear DEVDISR bits
	 * once the device has been disabled, but the hardware people
	 * say that this special case is OK.
	 */
	clrbits_be32(&gur->devdisr, devdisr);
	clrbits_be32(&gur->devdisr2, devdisr2);

	/*
	 * Some protocols require special handling.  There are a few
	 * additional protocol configurations that can be used, which are
	 * not listed here.  See app note 4065 for supported protocol
	 * configurations.
	 */
	switch (cfg) {
	case 0x19:
		/*
		 * Bank 2 has PCIe which wants BWSEL -- tell bank 3's PLL.
		 * SGMII on bank 3 should still be usable.
		 */
		setbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr1,
			     SRDS_PLLCR1_PLL_BWSEL);

		enable_bank(gur, FSL_SRDS_BANK_3);
		break;

	case 0x0f:
	case 0x10:
		/*
		 * Banks 2 (XAUI) and 3 (SGMII) have different clocking
		 * requirements in these configurations.  Bank 3 cannot
		 * be used and should have its lanes (but not the bank
		 * itself) disabled in the RCW.  We set up bank 3's pll
		 * for bank 2's needs here.
		 */
		srds_ratio_b2 = (in_be32(&gur->rcwsr[4]) >> 13) & 7;

		/* Determine refclock from XAUI ratio */
		switch (srds_ratio_b2) {
		case 1: /* 20:1 */
			rfck_sel = SRDS_PLLCR0_RFCK_SEL_156_25;
			break;
		case 2: /* 25:1 */
			rfck_sel = SRDS_PLLCR0_RFCK_SEL_125;
			break;
		default:
			printf("SERDES: bad SRDS_RATIO_B2 %d\n",
			       srds_ratio_b2);
			return;
		}

		clrsetbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr0,
				SRDS_PLLCR0_RFCK_SEL_MASK, rfck_sel);

		clrsetbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr0,
				SRDS_PLLCR0_FRATE_SEL_MASK,
				SRDS_PLLCR0_FRATE_SEL_6_25);
		break;
	default:
		enable_bank(gur, FSL_SRDS_BANK_3);
	}

}
#endif

void fsl_serdes_init(void)
{
	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
	int cfg;
	serdes_corenet_t *srds_regs;
	int lane, bank, idx;
	enum srds_prtcl lane_prtcl;
	long long end_tick;
	int have_bank[SRDS_MAX_BANK] = {};
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
	u32 serdes8_devdisr = 0;
	u32 serdes8_devdisr2 = 0;
	char srds_lpd_opt[16];
	const char *srds_lpd_arg;
	size_t arglen;
#endif
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
	enum srds_prtcl device;
#endif
	char buffer[HWCONFIG_BUFFER_SIZE];
	char *buf = NULL;

	/*
	 * Extract hwconfig from environment since we have not properly setup
	 * the environment but need it for ddr config params
	 */
	if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
		buf = buffer;

	/* Is serdes enabled at all? */
	if (!(in_be32(&gur->rcwsr[5]) & FSL_CORENET_RCWSR5_SRDS_EN))
		return;

	srds_regs = (void *)(CONFIG_SYS_FSL_CORENET_SERDES_ADDR);
	cfg = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
	debug("Using SERDES configuration 0x%x, lane settings:\n", cfg);

	if (!is_serdes_prtcl_valid(cfg)) {
		printf("SERDES[PRTCL] = 0x%x is not valid\n", cfg);
		return;
	}

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
	/*
	 * Store the values of the fsl_srds_lpd_b2 and fsl_srds_lpd_b3
	 * hwconfig options into the srds_lpd_b[] array.  See README.p4080ds
	 * for a description of these options.
	 */
	for (bank = 1; bank < ARRAY_SIZE(srds_lpd_b); bank++) {
		sprintf(srds_lpd_opt, "fsl_srds_lpd_b%u", bank + 1);
		srds_lpd_arg =
			hwconfig_subarg_f("serdes", srds_lpd_opt, &arglen, buf);
		if (srds_lpd_arg)
			srds_lpd_b[bank] =
				simple_strtoul(srds_lpd_arg, NULL, 0) & 0xf;
	}
#endif

	/* Look for banks with all lanes disabled, and power down the bank. */
	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
		enum srds_prtcl lane_prtcl = serdes_get_prtcl(cfg, lane);
		if (serdes_lane_enabled(lane)) {
			have_bank[serdes_get_bank_by_lane(lane)] = 1;
			serdes_prtcl_map |= (1 << lane_prtcl);
		}
	}

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
	/*
	 * Bank two uses the clock from bank three, so if bank two is enabled,
	 * then bank three must also be enabled.
	 */
	if (have_bank[FSL_SRDS_BANK_2])
		have_bank[FSL_SRDS_BANK_3] = 1;
#endif

	for (bank = 0; bank < SRDS_MAX_BANK; bank++) {
		if (!have_bank[bank]) {
			printf("SERDES: bank %d disabled\n", bank + 1);
			setbits_be32(&srds_regs->bank[bank].rstctl,
				     SRDS_RSTCTL_SDPD);
		}
	}

	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
		idx = serdes_get_lane_idx(lane);
		lane_prtcl = serdes_get_prtcl(cfg, lane);

#ifdef DEBUG
		switch (lane) {
		case 0:
			puts("Bank1: ");
			break;
		case 10:
			puts("\nBank2: ");
			break;
		case 14:
			puts("\nBank3: ");
			break;
		default:
			break;
		}

		printf("%s ", serdes_prtcl_str[lane_prtcl]);
#endif

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
		switch (lane_prtcl) {
		case PCIE1:
		case PCIE2:
		case PCIE3:
			serdes8_devdisr |= FSL_CORENET_DEVDISR_PCIE1 >>
					   (lane_prtcl - PCIE1);
			break;
		case SRIO1:
		case SRIO2:
			serdes8_devdisr |= FSL_CORENET_DEVDISR_SRIO1 >>
					   (lane_prtcl - SRIO1);
			break;
		case SGMII_FM1_DTSEC1:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
					    FSL_CORENET_DEVDISR2_DTSEC1_1;
			break;
		case SGMII_FM1_DTSEC2:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
					    FSL_CORENET_DEVDISR2_DTSEC1_2;
			break;
		case SGMII_FM1_DTSEC3:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
					    FSL_CORENET_DEVDISR2_DTSEC1_3;
			break;
		case SGMII_FM1_DTSEC4:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
					    FSL_CORENET_DEVDISR2_DTSEC1_4;
			break;
		case SGMII_FM2_DTSEC1:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
					    FSL_CORENET_DEVDISR2_DTSEC2_1;
			break;
		case SGMII_FM2_DTSEC2:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
					    FSL_CORENET_DEVDISR2_DTSEC2_2;
			break;
		case SGMII_FM2_DTSEC3:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
					    FSL_CORENET_DEVDISR2_DTSEC2_3;
			break;
		case SGMII_FM2_DTSEC4:
			serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
					    FSL_CORENET_DEVDISR2_DTSEC2_4;
			break;
		case XAUI_FM1:
		case XAUI_FM2:
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
			/*
			 * Set BnTTLCRy0[FLT_SEL] = 000011 and set
			 * BnTTLCRy0[17] = 1 for each of the SerDes lanes
			 * selected as XAUI on each bank before XAUI is
			 * initialized.
			 */
			clrsetbits_be32(&srds_regs->lane[idx].ttlcr0,
					SRDS_TTLCR0_FLT_SEL_MASK,
					0x03000000 | SRDS_TTLCR0_PM_DIS);
#endif
			if (lane_prtcl == XAUI_FM1)
				serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1	|
						    FSL_CORENET_DEVDISR2_10GEC1;
			else
				serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2	|
						    FSL_CORENET_DEVDISR2_10GEC2;
			break;
		case AURORA:
			break;
		default:
			break;
		}

#endif
	}

#ifdef DEBUG
	puts("\n");
#endif

#endif

	for (idx = 0; idx < SRDS_MAX_BANK; idx++) {
		u32 rstctl;

		bank = idx;

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
		/*
		 * Change bank init order to 0, 2, 1, so that the third bank's
		 * PLL is established before we start the second bank.  The
		 * second bank uses the third bank's PLL.
		 */

		if (idx == 1)
			bank = FSL_SRDS_BANK_3;
		else if (idx == 2)
			bank = FSL_SRDS_BANK_2;
#endif

		/* Skip disabled banks */
		if (!have_bank[bank])
			continue;

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
		if (idx == 1) {
			/*
			 * Re-enable devices on banks two and three that were
			 * disabled by the RCW, and then enable bank three. The
			 * devices need to be enabled before either bank is
			 * powered up.
			 */
			p4080_erratum_serdes8(srds_regs, gur, serdes8_devdisr,
					      serdes8_devdisr2, cfg);
		} else if (idx == 2) {
			/* Eable bank two now that bank three is enabled. */
			enable_bank(gur, FSL_SRDS_BANK_2);
		}
#endif

		/* reset banks for errata */
		setbits_be32(&srds_regs->bank[bank].rstctl, SRDS_RSTCTL_RST);

		/* wait for reset complete or 1-second timeout */
		end_tick = usec2ticks(1000000) + get_ticks();
		do {
			rstctl = in_be32(&srds_regs->bank[bank].rstctl);
			if (rstctl & SRDS_RSTCTL_RSTDONE)
				break;
		} while (end_tick > get_ticks());

		if (!(rstctl & SRDS_RSTCTL_RSTDONE)) {
			printf("SERDES: timeout resetting bank %d\n",
			       bank + 1);
			continue;
		}
	}

#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
	for (device = XAUI_FM1; device <= XAUI_FM2; device++) {
		if (is_serdes_configured(device))
			__serdes_reset_rx(srds_regs, cfg, device);
	}
#endif
}
OpenPOWER on IntegriCloud