1/*
2 * Code to operate on PCI/E core, in NIC mode
3 * Implements pci_api.h
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: nicpci.c,v 1.33.10.24 2011-02-03 01:11:15 Exp $
19 */
20
21#include <typedefs.h>
22#include <bcmdefs.h>
23#include <osl.h>
24#include <bcmutils.h>
25#include <siutils.h>
26#include <hndsoc.h>
27#include <bcmdevs.h>
28#include <sbchipc.h>
29#include <pci_core.h>
30#include <pcie_core.h>
31#include <nicpci.h>
32#include <pcicfg.h>
33
34typedef struct {
35	union {
36		sbpcieregs_t *pcieregs;
37		sbpciregs_t *pciregs;
38	} regs;                         /* Memory mapped register to the core */
39
40	si_t 	*sih;					/* System interconnect handle */
41	osl_t 	*osh;					/* OSL handle */
42	uint8	pciecap_lcreg_offset;	/* PCIE capability LCreg offset in the config space */
43	uint8	pciecap_devctrl_offset;	/* PCIE DevControl reg offset in the config space */
44	bool	pcie_pr42767;
45	uint8	pcie_polarity;
46	uint8	pcie_war_aspm_ovr;	/* Override ASPM/Clkreq settings */
47	uint8	pmecap_offset;		/* PM Capability offset in the config space */
48	bool 	pmecap;				/* Capable of generating PME */
49	bool	pcie_power_save;
50	uint16	pmebits;
51	uint16	pcie_reqsize;
52} pcicore_info_t;
53
54/* debug/trace */
55#define	PCI_ERROR(args)
56
57/* routines to access mdio slave device registers */
58static bool pcie_mdiosetblock(pcicore_info_t *pi,  uint blk);
59static int pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write, uint *val);
60static int pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint readdr, uint val);
61static int pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint readdr, uint *ret_val);
62
63static void pcie_extendL1timer(pcicore_info_t *pi, bool extend);
64static void pcie_clkreq_upd(pcicore_info_t *pi, uint state);
65
66static void pcie_war_aspm_clkreq(pcicore_info_t *pi);
67static void pcie_war_serdes(pcicore_info_t *pi);
68static void pcie_war_noplldown(pcicore_info_t *pi);
69static void pcie_war_polarity(pcicore_info_t *pi);
70static void pcie_war_pci_setup(pcicore_info_t *pi);
71static void pcie_power_save_upd(pcicore_info_t *pi, bool up);
72
73static bool pcicore_pmecap(pcicore_info_t *pi);
74static void pcicore_fixlatencytimer(pcicore_info_t* pch, uint8 timer_val);
75
76#define PCIE(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
77#define PCIE_ASPM(sih)	((PCIE(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
78
79#define DWORD_ALIGN(x)  (x & ~(0x03))
80#define BYTE_POS(x) (x & 0x3)
81#define WORD_POS(x) (x & 0x1)
82
83#define BYTE_SHIFT(x)  (8 * BYTE_POS(x))
84#define WORD_SHIFT(x)  (16 * WORD_POS(x))
85
86#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
87#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
88
89#define read_pci_cfg_byte(a) \
90	(BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
91
92#define read_pci_cfg_word(a) \
93	(WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
94
95#define write_pci_cfg_byte(a, val) do { \
96	uint32 tmpval; \
97	tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
98	        val << BYTE_POS(a); \
99	OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
100	} while (0)
101
102#define write_pci_cfg_word(a, val) do { \
103	uint32 tmpval; \
104	tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
105	        val << WORD_POS(a); \
106	OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
107	} while (0)
108
109/* delay needed between the mdio control/ mdiodata register data access */
110#define PR28829_DELAY() OSL_DELAY(10)
111
112/* Initialize the PCI core. It's caller's responsibility to make sure that this is done
113 * only once
114 */
115void *
116pcicore_init(si_t *sih, osl_t *osh, void *regs)
117{
118	pcicore_info_t *pi;
119
120	ASSERT(sih->bustype == PCI_BUS);
121
122	/* alloc pcicore_info_t */
123	if ((pi = MALLOC(osh, sizeof(pcicore_info_t))) == NULL) {
124		PCI_ERROR(("pci_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
125		return (NULL);
126	}
127
128	bzero(pi, sizeof(pcicore_info_t));
129
130	pi->sih = sih;
131	pi->osh = osh;
132
133	if (sih->buscoretype == PCIE_CORE_ID) {
134		uint8 cap_ptr;
135		pi->regs.pcieregs = (sbpcieregs_t*)regs;
136		cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_PCIECAP_ID, NULL, NULL);
137		ASSERT(cap_ptr);
138		pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
139		pi->pciecap_devctrl_offset = cap_ptr + PCIE_CAP_DEVCTRL_OFFSET;
140		pi->pcie_power_save = TRUE; /* Enable pcie_power_save by default */
141	} else
142		pi->regs.pciregs = (sbpciregs_t*)regs;
143
144	return pi;
145}
146
147void
148pcicore_deinit(void *pch)
149{
150	pcicore_info_t *pi = (pcicore_info_t *)pch;
151
152
153	if (pi == NULL)
154		return;
155	MFREE(pi->osh, pi, sizeof(pcicore_info_t));
156}
157
158/* return cap_offset if requested capability exists in the PCI config space */
159/* Note that it's caller's responsibility to make sure it's a pci bus */
160uint8
161pcicore_find_pci_capability(osl_t *osh, uint8 req_cap_id, uchar *buf, uint32 *buflen)
162{
163	uint8 cap_id;
164	uint8 cap_ptr = 0;
165	uint32 bufsize;
166	uint8 byte_val;
167
168	/* check for Header type 0 */
169	byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
170	if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
171		goto end;
172
173	/* check if the capability pointer field exists */
174	byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
175	if (!(byte_val & PCI_CAPPTR_PRESENT))
176		goto end;
177
178	cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
179	/* check if the capability pointer is 0x00 */
180	if (cap_ptr == 0x00)
181		goto end;
182
183	/* loop thr'u the capability list and see if the pcie capabilty exists */
184
185	cap_id = read_pci_cfg_byte(cap_ptr);
186
187	while (cap_id != req_cap_id) {
188		cap_ptr = read_pci_cfg_byte((cap_ptr+1));
189		if (cap_ptr == 0x00) break;
190		cap_id = read_pci_cfg_byte(cap_ptr);
191	}
192	if (cap_id != req_cap_id) {
193		goto end;
194	}
195	/* found the caller requested capability */
196	if ((buf != NULL) && (buflen != NULL)) {
197		uint8 cap_data;
198
199		bufsize = *buflen;
200		if (!bufsize) goto end;
201		*buflen = 0;
202		/* copy the cpability data excluding cap ID and next ptr */
203		cap_data = cap_ptr + 2;
204		if ((bufsize + cap_data)  > SZPCR)
205			bufsize = SZPCR - cap_data;
206		*buflen = bufsize;
207		while (bufsize--) {
208			*buf = read_pci_cfg_byte(cap_data);
209			cap_data++;
210			buf++;
211		}
212	}
213end:
214	return cap_ptr;
215}
216
217/* ***** Register Access API */
218uint
219pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset)
220{
221	uint retval = 0xFFFFFFFF;
222
223	ASSERT(pcieregs != NULL);
224
225	switch (addrtype) {
226		case PCIE_CONFIGREGS:
227			W_REG(osh, (&pcieregs->configaddr), offset);
228			(void)R_REG(osh, (&pcieregs->configaddr));
229			retval = R_REG(osh, &(pcieregs->configdata));
230			break;
231		case PCIE_PCIEREGS:
232			W_REG(osh, &(pcieregs->pcieindaddr), offset);
233			(void)R_REG(osh, (&pcieregs->pcieindaddr));
234			retval = R_REG(osh, &(pcieregs->pcieinddata));
235			break;
236		default:
237			ASSERT(0);
238			break;
239	}
240
241	return retval;
242}
243
244uint
245pcie_writereg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset, uint val)
246{
247	ASSERT(pcieregs != NULL);
248
249	switch (addrtype) {
250		case PCIE_CONFIGREGS:
251			W_REG(osh, (&pcieregs->configaddr), offset);
252			W_REG(osh, (&pcieregs->configdata), val);
253			break;
254		case PCIE_PCIEREGS:
255			W_REG(osh, (&pcieregs->pcieindaddr), offset);
256			W_REG(osh, (&pcieregs->pcieinddata), val);
257			break;
258		default:
259			ASSERT(0);
260			break;
261	}
262	return 0;
263}
264
265static bool
266pcie_mdiosetblock(pcicore_info_t *pi, uint blk)
267{
268	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
269	uint mdiodata, i = 0;
270	uint pcie_serdes_spinwait = 200;
271
272	mdiodata = MDIODATA_START | MDIODATA_WRITE | (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
273	        (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | MDIODATA_TA | (blk << 4);
274	W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
275
276	PR28829_DELAY();
277	/* retry till the transaction is complete */
278	while (i < pcie_serdes_spinwait) {
279		if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
280			break;
281		}
282		OSL_DELAY(1000);
283		i++;
284	}
285
286	if (i >= pcie_serdes_spinwait) {
287		PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
288		return FALSE;
289	}
290
291	return TRUE;
292}
293
294static int
295pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write, uint *val)
296{
297	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
298	uint mdiodata;
299	uint i = 0;
300	uint pcie_serdes_spinwait = 10;
301
302	/* enable mdio access to SERDES */
303	W_REG(pi->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
304
305	if (pi->sih->buscorerev >= 10) {
306		/* new serdes is slower in rw, using two layers of reg address mapping */
307		if (!pcie_mdiosetblock(pi, physmedia))
308			return 1;
309		mdiodata = (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
310			(regaddr << MDIODATA_REGADDR_SHF);
311		pcie_serdes_spinwait *= 20;
312	} else {
313		mdiodata = (physmedia << MDIODATA_DEVADDR_SHF_OLD) |
314			(regaddr << MDIODATA_REGADDR_SHF_OLD);
315	}
316
317	if (!write)
318		mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
319	else
320		mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val);
321
322	W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
323
324	PR28829_DELAY();
325
326	/* retry till the transaction is complete */
327	while (i < pcie_serdes_spinwait) {
328		if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
329			if (!write) {
330				PR28829_DELAY();
331				*val = (R_REG(pi->osh, &(pcieregs->mdiodata)) & MDIODATA_MASK);
332			}
333			/* Disable mdio access to SERDES */
334			W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
335			return 0;
336		}
337		OSL_DELAY(1000);
338		i++;
339	}
340
341	PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write));
342	/* Disable mdio access to SERDES */
343	W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
344	return 1;
345}
346
347/* use the mdio interface to read from mdio slaves */
348static int
349pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint regaddr, uint *regval)
350{
351	return pcie_mdioop(pi, physmedia, regaddr, FALSE, regval);
352}
353
354/* use the mdio interface to write to mdio slaves */
355static int
356pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint regaddr, uint val)
357{
358	return pcie_mdioop(pi, physmedia, regaddr, TRUE, &val);
359}
360
361/* ***** Support functions ***** */
362static uint32
363pcie_devcontrol_mrrs(void *pch, uint32 mask, uint32 val)
364{
365	pcicore_info_t *pi = (pcicore_info_t *)pch;
366	uint32 reg_val;
367	uint8 offset;
368
369	offset = pi->pciecap_devctrl_offset;
370	if (!offset)
371		return 0;
372
373	reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
374	/* set operation */
375	if (mask) {
376		if (val > PCIE_CAP_DEVCTRL_MRRS_128B) {
377			if (pi->sih->buscorerev < 18) {
378				PCI_ERROR(("%s pcie corerev %d doesn't support >128B MRRS",
379					__FUNCTION__, pi->sih->buscorerev));
380				val = PCIE_CAP_DEVCTRL_MRRS_128B;
381			}
382		}
383
384		reg_val &= ~PCIE_CAP_DEVCTRL_MRRS_MASK;
385		reg_val |= (val << PCIE_CAP_DEVCTRL_MRRS_SHIFT) & PCIE_CAP_DEVCTRL_MRRS_MASK;
386
387		OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val);
388		reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
389	}
390	return reg_val;
391}
392
393uint8
394pcie_clkreq(void *pch, uint32 mask, uint32 val)
395{
396	pcicore_info_t *pi = (pcicore_info_t *)pch;
397	uint32 reg_val;
398	uint8 offset;
399
400	offset = pi->pciecap_lcreg_offset;
401	if (!offset)
402		return 0;
403
404	reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
405	/* set operation */
406	if (mask) {
407		if (val)
408			reg_val |= PCIE_CLKREQ_ENAB;
409		else
410			reg_val &= ~PCIE_CLKREQ_ENAB;
411		OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val);
412		reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
413	}
414	if (reg_val & PCIE_CLKREQ_ENAB)
415		return 1;
416	else
417		return 0;
418}
419
420static void
421pcie_extendL1timer(pcicore_info_t *pi, bool extend)
422{
423	uint32 w;
424	si_t *sih = pi->sih;
425	osl_t *osh = pi->osh;
426	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
427
428	if (!PCIE(sih))
429		return;
430
431	w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
432
433	if (extend && sih->buscorerev >= 7)
434		w |= PCIE_ASPMTIMER_EXTEND;
435	else
436		w &= ~PCIE_ASPMTIMER_EXTEND;
437	pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
438	w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
439}
440
441/* centralized clkreq control policy */
442static void
443pcie_clkreq_upd(pcicore_info_t *pi, uint state)
444{
445	si_t *sih = pi->sih;
446	ASSERT(PCIE(sih));
447
448	switch (state) {
449	case SI_DOATTACH:
450		if (PCIE_ASPM(sih))
451			pcie_clkreq((void *)pi, 1, 0);
452		break;
453	case SI_PCIDOWN:
454		if (sih->buscorerev == 6) {	/* turn on serdes PLL down */
455			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr),
456			           ~0, 0);
457			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data),
458			           ~0x40, 0);
459		} else if (pi->pcie_pr42767) {
460			pcie_clkreq((void *)pi, 1, 1);
461		}
462		break;
463	case SI_PCIUP:
464		if (sih->buscorerev == 6) {	/* turn off serdes PLL down */
465			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr),
466			           ~0, 0);
467			si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data),
468			           ~0x40, 0x40);
469		} else if (PCIE_ASPM(sih)) {		/* disable clkreq */
470			pcie_clkreq((void *)pi, 1, 0);
471		}
472		break;
473	default:
474		ASSERT(0);
475		break;
476	}
477}
478
479/* ***** PCI core WARs ***** */
480/* Done only once at attach time */
481static void
482pcie_war_polarity(pcicore_info_t *pi)
483{
484	uint32 w;
485
486	if (pi->pcie_polarity != 0)
487		return;
488
489	w = pcie_readreg(pi->osh, pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
490
491	/* Detect the current polarity at attach and force that polarity and
492	 * disable changing the polarity
493	 */
494	if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
495		pi->pcie_polarity = (SERDES_RX_CTRL_FORCE);
496	else
497		pi->pcie_polarity = (SERDES_RX_CTRL_FORCE | SERDES_RX_CTRL_POLARITY);
498}
499
500/* enable ASPM and CLKREQ if srom doesn't have it */
501/* Needs to happen when update to shadow SROM is needed
502 *   : Coming out of 'standby'/'hibernate'
503 *   : If pcie_war_aspm_ovr state changed
504 */
505static void
506pcie_war_aspm_clkreq(pcicore_info_t *pi)
507{
508	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
509	si_t *sih = pi->sih;
510	uint16 val16, *reg16;
511	uint32 w;
512
513	if (!PCIE_ASPM(sih))
514		return;
515
516	/* bypass this on QT or VSIM */
517	if (!ISSIM_ENAB(sih)) {
518
519		reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET];
520		val16 = R_REG(pi->osh, reg16);
521
522		val16 &= ~SRSH_ASPM_ENB;
523		if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
524			val16 |= SRSH_ASPM_ENB;
525		else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
526			val16 |= SRSH_ASPM_L1_ENB;
527		else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
528			val16 |= SRSH_ASPM_L0s_ENB;
529
530		W_REG(pi->osh, reg16, val16);
531
532		w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32));
533		w &= ~PCIE_ASPM_ENAB;
534		w |= pi->pcie_war_aspm_ovr;
535		OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w);
536	}
537
538	reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
539	val16 = R_REG(pi->osh, reg16);
540
541	if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
542		val16 |= SRSH_CLKREQ_ENB;
543		pi->pcie_pr42767 = TRUE;
544	} else
545		val16 &= ~SRSH_CLKREQ_ENB;
546
547	W_REG(pi->osh, reg16, val16);
548}
549
550static void
551pcie_war_pmebits(pcicore_info_t *pi)
552{
553	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
554	uint16 val16, *reg16;
555
556	if (pi->sih->buscorerev != 18 && pi->sih->buscorerev != 19)
557		return;
558
559	reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8];
560	val16 = R_REG(pi->osh, reg16);
561	if (val16 != pi->pmebits) {
562		PCI_ERROR(("pcie_war_pmebits: pmebits mismatch 0x%x (was 0x%x)\n",
563			val16, pi->pmebits));
564		pi->pmebits = 0x1f30;
565		W_REG(pi->osh, reg16, pi->pmebits);
566		val16 = R_REG(pi->osh, reg16);
567		PCI_ERROR(("pcie_war_pmebits: update pmebits to 0x%x\n", val16));
568	}
569}
570
571/* Apply the polarity determined at the start */
572/* Needs to happen when coming out of 'standby'/'hibernate' */
573static void
574pcie_war_serdes(pcicore_info_t *pi)
575{
576	uint32 w = 0;
577
578	if (pi->pcie_polarity != 0)
579		pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL, pi->pcie_polarity);
580
581	pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
582	if (w & PLL_CTRL_FREQDET_EN) {
583		w &= ~PLL_CTRL_FREQDET_EN;
584		pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
585	}
586}
587
588/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
589/* Needs to happen when coming out of 'standby'/'hibernate' */
590static void
591BCMINITFN(pcie_misc_config_fixup)(pcicore_info_t *pi)
592{
593	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
594	uint16 val16, *reg16;
595
596	reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
597	val16 = R_REG(pi->osh, reg16);
598
599	if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
600		val16 |= SRSH_L23READY_EXIT_NOPERST;
601		W_REG(pi->osh, reg16, val16);
602	}
603}
604
605/* quick hack for testing */
606/* Needs to happen when coming out of 'standby'/'hibernate' */
607static void
608pcie_war_noplldown(pcicore_info_t *pi)
609{
610	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
611	uint16 *reg16;
612
613	ASSERT(pi->sih->buscorerev == 7);
614
615	/* turn off serdes PLL down */
616	si_corereg(pi->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
617	           CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
618
619	/*  clear srom shadow backdoor */
620	reg16 = &pcieregs->sprom[SRSH_BD_OFFSET];
621	W_REG(pi->osh, reg16, 0);
622}
623
624/* Needs to happen when coming out of 'standby'/'hibernate' */
625static void
626pcie_war_pci_setup(pcicore_info_t *pi)
627{
628	si_t *sih = pi->sih;
629	osl_t *osh = pi->osh;
630	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
631	uint32 w;
632
633	if ((sih->buscorerev == 0) || (sih->buscorerev == 1)) {
634		w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG);
635		w |= 0x8;
636		pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG, w);
637	}
638
639	if (sih->buscorerev == 1) {
640		w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
641		w |= (0x40);
642		pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
643	}
644
645	if (sih->buscorerev == 0) {
646		pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
647		pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
648		pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
649	} else if (PCIE_ASPM(sih)) {
650		/* Change the L1 threshold for better performance */
651		w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
652		w &= ~(PCIE_L1THRESHOLDTIME_MASK);
653		w |= (PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT);
654		pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
655
656		pcie_war_serdes(pi);
657
658		pcie_war_aspm_clkreq(pi);
659	} else if (pi->sih->buscorerev == 7)
660		pcie_war_noplldown(pi);
661
662	/* Note that the fix is actually in the SROM, that's why this is open-ended */
663	if (pi->sih->buscorerev >= 6)
664		pcie_misc_config_fixup(pi);
665}
666
667void
668pcie_war_ovr_aspm_update(void *pch, uint8 aspm)
669{
670	pcicore_info_t *pi = (pcicore_info_t *)pch;
671
672	if (!PCIE_ASPM(pi->sih))
673		return;
674
675	/* Validate */
676	if (aspm > PCIE_ASPM_ENAB)
677		return;
678
679	pi->pcie_war_aspm_ovr = aspm;
680
681	/* Update the current state */
682	pcie_war_aspm_clkreq(pi);
683}
684
685
686void
687pcie_power_save_enable(void *pch, bool enable)
688{
689	pcicore_info_t *pi = (pcicore_info_t *)pch;
690
691
692	if (!pi)
693		return;
694
695	pi->pcie_power_save = enable;
696}
697
698static void
699pcie_power_save_upd(pcicore_info_t *pi, bool up)
700{
701	si_t *sih = pi->sih;
702
703	if (!pi->pcie_power_save)
704		return;
705
706
707	if ((sih->buscorerev >= 15) && (sih->buscorerev <= 20)) {
708
709		pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT1, 1, 0x7F64);
710
711		if (up)
712			pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT3, 1, 0x74);
713		else
714			pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT3, 1, 0x7C);
715	}
716}
717
718void
719pcie_set_request_size(void *pch, uint16 size)
720{
721	pcicore_info_t *pi = (pcicore_info_t *)pch;
722
723	if (!pi)
724		return;
725	if (size == 128)
726		pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
727	else if (size == 256)
728		pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_256B;
729	else if (size == 512)
730		pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_512B;
731	else
732		return;
733
734	if (pi->sih->buscorerev == 18 || pi->sih->buscorerev == 19)
735		pcie_devcontrol_mrrs(pi, PCIE_CAP_DEVCTRL_MRRS_MASK, (uint32)pi->pcie_reqsize);
736}
737
738uint16
739pcie_get_request_size(void *pch)
740{
741	pcicore_info_t *pi = (pcicore_info_t *)pch;
742
743	if (!pi)
744		return (0);
745
746	if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_128B)
747		return (128);
748	else if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_256B)
749		return (256);
750	else if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_512B)
751		return (512);
752	return (0);
753}
754
755/* ***** Functions called during driver state changes ***** */
756void
757BCMATTACHFN(pcicore_attach)(void *pch, char *pvars, int state)
758{
759	pcicore_info_t *pi = (pcicore_info_t *)pch;
760	si_t *sih = pi->sih;
761
762	if (PCIE_ASPM(sih)) {
763		if (((sih->boardvendor == VENDOR_APPLE) &&
764		     ((uint8)getintvar(pvars, "sromrev") == 4) &&
765		     ((uint8)getintvar(pvars, "boardrev") <= 0x71)) ||
766		    ((uint32)getintvar(pvars, "boardflags2") & BFL2_PCIEWAR_OVR)) {
767			pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
768		} else {
769			pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
770		}
771	}
772
773	pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
774	if (BCM4331_CHIP_ID == CHIPID(sih->chip))
775	    pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_512B;
776
777	/* These need to happen in this order only */
778	pcie_war_polarity(pi);
779
780	pcie_war_serdes(pi);
781
782	pcie_war_aspm_clkreq(pi);
783
784	pcie_clkreq_upd(pi, state);
785
786	/* Alter default TX drive strength setting */
787	if (sih->boardvendor == VENDOR_APPLE) {
788		if (sih->boardtype == 0x8d)
789			/* change the TX drive strength to max */
790			pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x7f);
791		else if (BCM4331_CHIP_ID == CHIPID(sih->chip))
792			/* change the drive strength for X19b & X28 to 700mv */
793			pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x70);
794	}
795}
796
797void
798pcicore_hwup(void *pch)
799{
800	pcicore_info_t *pi = (pcicore_info_t *)pch;
801
802	if (!pi || !PCIE(pi->sih))
803		return;
804
805	pcie_power_save_upd(pi, TRUE);
806
807	if (pi->sih->boardtype == CB2_4321_BOARD || pi->sih->boardtype == CB2_4321_AG_BOARD)
808		pcicore_fixlatencytimer(pch, 0x20);
809
810	pcie_war_pci_setup(pi);
811
812	/* Alter default TX drive strength setting */
813	if (pi->sih->boardvendor == VENDOR_APPLE) {
814		if (pi->sih->boardtype == 0x8d)
815			/* change the TX drive strength to max */
816			pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x7f);
817		else if (BCM4331_CHIP_ID == CHIPID(pi->sih->chip))
818			/* change the drive strength for X19b & X28 to 700mv */
819			pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x70);
820	}
821}
822
823void
824pcicore_up(void *pch, int state)
825{
826	pcicore_info_t *pi = (pcicore_info_t *)pch;
827	bool is_x19_x28 = FALSE;
828
829	if (!pi || !PCIE(pi->sih))
830		return;
831
832	pcie_power_save_upd(pi, TRUE);
833
834	/* Restore L1 timer for better performance */
835	pcie_extendL1timer(pi, TRUE);
836
837	pcie_clkreq_upd(pi, state);
838
839	is_x19_x28 = ((pi->sih->boardvendor == VENDOR_APPLE) &&
840	              ((pi->sih->boardtype == BCM94331X19) ||
841	               (pi->sih->boardtype == BCM94331PCIEBT3Ax_SSID)));
842
843	if (pi->sih->buscorerev == 18 ||
844	    (pi->sih->buscorerev == 19 && !is_x19_x28))
845		pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
846
847	pcie_devcontrol_mrrs(pi, PCIE_CAP_DEVCTRL_MRRS_MASK, pi->pcie_reqsize);
848}
849
850/* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */
851void
852pcicore_sleep(void *pch)
853{
854	pcicore_info_t *pi = (pcicore_info_t *)pch;
855	uint32 w;
856
857	if (!pi || !PCIE(pi->sih))
858		return;
859
860	pcie_power_save_upd(pi, FALSE);
861
862
863	if (!PCIE_ASPM(pi->sih))
864		return;
865
866
867	w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32));
868	w &= ~PCIE_CAP_LCREG_ASPML1;
869	OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w);
870
871
872	pi->pcie_pr42767 = FALSE;
873}
874
875void
876pcicore_down(void *pch, int state)
877{
878	pcicore_info_t *pi = (pcicore_info_t *)pch;
879
880	if (!pi || !PCIE(pi->sih))
881		return;
882
883	pcie_clkreq_upd(pi, state);
884
885	/* Reduce L1 timer for better power savings */
886	pcie_extendL1timer(pi, FALSE);
887
888	pcie_power_save_upd(pi, FALSE);
889}
890
891/* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
892/* Just uses PCI config accesses to find out, when needed before sb_attach is done */
893bool
894pcicore_pmecap_fast(osl_t *osh)
895{
896	uint8 cap_ptr;
897	uint32 pmecap;
898
899	cap_ptr = pcicore_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL);
900
901	if (!cap_ptr)
902		return FALSE;
903
904	pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(uint32));
905
906	return ((pmecap & PME_CAP_PM_STATES) != 0);
907}
908
909/* return TRUE if PM capability exists in the pci config space
910 * Uses and caches the information using core handle
911 */
912static bool
913pcicore_pmecap(pcicore_info_t *pi)
914{
915	uint8 cap_ptr;
916	uint32 pmecap;
917	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
918	uint16*reg16;
919
920	if (!pi->pmecap_offset) {
921		cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL);
922		if (!cap_ptr)
923			return FALSE;
924
925		pi->pmecap_offset = cap_ptr;
926
927		reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8];
928		pi->pmebits = R_REG(pi->osh, reg16);
929
930		pmecap = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset, sizeof(uint32));
931
932		/* At least one state can generate PME */
933		pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0;
934	}
935
936	return (pi->pmecap);
937}
938
939/* Enable PME generation */
940void
941pcicore_pmeen(void *pch)
942{
943	pcicore_info_t *pi = (pcicore_info_t *)pch;
944	uint32 w;
945
946	/* if not pmecapable return */
947	if (!pcicore_pmecap(pi))
948		return;
949
950	pcie_war_pmebits(pi);
951	w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
952	w |= (PME_CSR_PME_EN);
953	OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w);
954}
955
956/*
957 * Return TRUE if PME status set
958 */
959bool
960pcicore_pmestat(void *pch)
961{
962	pcicore_info_t *pi = (pcicore_info_t *)pch;
963	uint32 w;
964
965	if (!pcicore_pmecap(pi))
966		return FALSE;
967
968	w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
969
970	return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT;
971}
972
973/* Disable PME generation, clear the PME status bit if set
974 */
975void
976pcicore_pmeclr(void *pch)
977{
978	pcicore_info_t *pi = (pcicore_info_t *)pch;
979	uint32 w;
980
981	if (!pcicore_pmecap(pi))
982		return;
983
984	pcie_war_pmebits(pi);
985	w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
986
987	PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w));
988
989	/* PMESTAT is cleared by writing 1 to it */
990	w &= ~(PME_CSR_PME_EN);
991
992	OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w);
993}
994
995static void
996pcicore_fixlatencytimer(pcicore_info_t* pch, uint8 timer_val)
997{
998	pcicore_info_t *pi = (pcicore_info_t *)pch;
999	osl_t *osh;
1000	uint8 lattim;
1001
1002	osh = pi->osh;
1003	lattim = read_pci_cfg_byte(PCI_CFG_LATTIM);
1004
1005	if (!lattim) {
1006		PCI_ERROR(("%s: Modifying PCI_CFG_LATTIM from 0x%x to 0x%x\n",
1007		           __FUNCTION__, lattim, timer_val));
1008		write_pci_cfg_byte(PCI_CFG_LATTIM, timer_val);
1009	}
1010}
1011
1012uint32
1013pcie_lcreg(void *pch, uint32 mask, uint32 val)
1014{
1015	pcicore_info_t *pi = (pcicore_info_t *)pch;
1016	uint8 offset;
1017
1018	offset = pi->pciecap_lcreg_offset;
1019	if (!offset)
1020		return 0;
1021
1022	/* set operation */
1023	if (mask)
1024		OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), val);
1025
1026	return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
1027}
1028
1029
1030uint32
1031pcicore_pciereg(void *pch, uint32 offset, uint32 mask, uint32 val, uint type)
1032{
1033	uint32 reg_val = 0;
1034	pcicore_info_t *pi = (pcicore_info_t *)pch;
1035	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
1036	osl_t *osh = pi->osh;
1037
1038	if (mask) {
1039		PCI_ERROR(("PCIEREG: 0x%x writeval  0x%x\n", offset, val));
1040		pcie_writereg(osh, pcieregs, type, offset, val);
1041	}
1042
1043	/* Should not read register 0x154 */
1044	if (pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11 && type == PCIE_PCIEREGS)
1045		return reg_val;
1046
1047	reg_val = pcie_readreg(osh, pcieregs, type, offset);
1048	PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val));
1049
1050	return reg_val;
1051}
1052
1053uint32
1054pcicore_pcieserdesreg(void *pch, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val)
1055{
1056	uint32 reg_val = 0;
1057	pcicore_info_t *pi = (pcicore_info_t *)pch;
1058
1059	if (mask) {
1060		pcie_mdiowrite(pi, mdioslave, offset, val);
1061	}
1062
1063	if (pcie_mdioread(pi, mdioslave, offset, &reg_val))
1064		reg_val = 0xFFFFFFFF;
1065
1066	return reg_val;
1067}
1068
1069
1070#if defined(BCMDBG_DUMP)
1071
1072/* size that can take bitfielddump */
1073#define BITFIELD_DUMP_SIZE  2048
1074
1075/* Dump PCIE PLP/DLLP/TLP  diagnostic registers */
1076int
1077pcicore_dump_pcieregs(void *pch, struct bcmstrbuf *b)
1078{
1079	pcicore_info_t *pi = (pcicore_info_t *)pch;
1080	sbpcieregs_t *pcieregs = pi->regs.pcieregs;
1081	si_t *sih = pi->sih;
1082	uint reg_val = 0;
1083	char *bitfield_dump_buf;
1084
1085	if (!(bitfield_dump_buf = MALLOC(pi->osh, BITFIELD_DUMP_SIZE))) {
1086		printf("bitfield dump allocation failed\n");
1087		return BCME_NOMEM;
1088	}
1089
1090	bcm_bprintf(b, "PLPRegs \t");
1091	bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1092		(struct fielddesc *)(uintptr)pcie_plp_regdesc,
1093		bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1094	bcm_bprintf(b, "%s", bitfield_dump_buf);
1095	bzero(bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1096	bcm_bprintf(b, "\n");
1097	bcm_bprintf(b, "DLLPRegs \t");
1098	bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1099		(struct fielddesc *)(uintptr)pcie_dllp_regdesc,
1100		bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1101	bcm_bprintf(b, "%s", bitfield_dump_buf);
1102	bzero(bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1103	bcm_bprintf(b, "\n");
1104	bcm_bprintf(b, "TLPRegs \t");
1105	bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1106		(struct fielddesc *)(uintptr)pcie_tlp_regdesc,
1107		bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1108	bcm_bprintf(b, "%s", bitfield_dump_buf);
1109	bzero(bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1110	bcm_bprintf(b, "\n");
1111
1112	/* enable mdio access to SERDES */
1113	W_REG(pi->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
1114
1115	bcm_bprintf(b, "SERDES regs \n");
1116	if (sih->buscorerev >= 10) {
1117		pcie_mdioread(pi, MDIO_DEV_IEEE0, 0x2, &reg_val);
1118		bcm_bprintf(b, "block IEEE0, offset 2: 0x%x\n", reg_val);
1119		pcie_mdioread(pi, MDIO_DEV_IEEE0, 0x3, &reg_val);
1120		bcm_bprintf(b, "block IEEE0, offset 2: 0x%x\n", reg_val);
1121		pcie_mdioread(pi, MDIO_DEV_IEEE1, 0x08, &reg_val);
1122		bcm_bprintf(b, "block IEEE1, lanestatus: 0x%x\n", reg_val);
1123		pcie_mdioread(pi, MDIO_DEV_IEEE1, 0x0a, &reg_val);
1124		bcm_bprintf(b, "block IEEE1, lanestatus2: 0x%x\n", reg_val);
1125		pcie_mdioread(pi, MDIO_DEV_BLK4, 0x16, &reg_val);
1126		bcm_bprintf(b, "MDIO_DEV_BLK4, lanetest0: 0x%x\n", reg_val);
1127		pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x11, &reg_val);
1128		bcm_bprintf(b, "MDIO_DEV_TXPLL, pllcontrol: 0x%x\n", reg_val);
1129		pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x12, &reg_val);
1130		bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer1: 0x%x\n", reg_val);
1131		pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x13, &reg_val);
1132		bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer2: 0x%x\n", reg_val);
1133		pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x14, &reg_val);
1134		bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer3: 0x%x\n", reg_val);
1135		pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x17, &reg_val);
1136		bcm_bprintf(b, "MDIO_DEV_TXPLL, freqdetcounter: 0x%x\n", reg_val);
1137	} else {
1138		pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, &reg_val);
1139		bcm_bprintf(b, "rxtimer1 0x%x ", reg_val);
1140		pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, &reg_val);
1141		bcm_bprintf(b, "rxCDR 0x%x ", reg_val);
1142		pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, &reg_val);
1143		bcm_bprintf(b, "rxCDRBW 0x%x\n", reg_val);
1144	}
1145
1146	/* disable mdio access to SERDES */
1147	W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
1148
1149	MFREE(pi->osh, bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1150
1151	return 0;
1152}
1153#endif
1154