usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src-rt / shared / nicpci.c
blobad2df79029dde7abfb74bd64abc3ec6b1ff7edc5
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.
18 * $Id: nicpci.c,v 1.33.10.24 2011-02-03 01:11:15 Exp $
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>
34 typedef struct {
35 union {
36 sbpcieregs_t *pcieregs;
37 sbpciregs_t *pciregs;
38 } regs; /* Memory mapped register to the core */
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;
54 /* debug/trace */
55 #ifdef BCMDBG_ERR
56 #define PCI_ERROR(args) printf args
57 #else
58 #define PCI_ERROR(args)
59 #endif /* BCMDBG_ERR */
61 /* routines to access mdio slave device registers */
62 static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk);
63 static int pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write, uint *val);
64 static int pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint readdr, uint val);
65 static int pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint readdr, uint *ret_val);
67 static void pcie_extendL1timer(pcicore_info_t *pi, bool extend);
68 static void pcie_clkreq_upd(pcicore_info_t *pi, uint state);
70 static void pcie_war_aspm_clkreq(pcicore_info_t *pi);
71 static void pcie_war_serdes(pcicore_info_t *pi);
72 static void pcie_war_noplldown(pcicore_info_t *pi);
73 static void pcie_war_polarity(pcicore_info_t *pi);
74 static void pcie_war_pci_setup(pcicore_info_t *pi);
75 static void pcie_power_save_upd(pcicore_info_t *pi, bool up);
77 static bool pcicore_pmecap(pcicore_info_t *pi);
78 static void pcicore_fixlatencytimer(pcicore_info_t* pch, uint8 timer_val);
80 #define PCIE(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
81 #define PCIE_ASPM(sih) ((PCIE(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
83 #define DWORD_ALIGN(x) (x & ~(0x03))
84 #define BYTE_POS(x) (x & 0x3)
85 #define WORD_POS(x) (x & 0x1)
87 #define BYTE_SHIFT(x) (8 * BYTE_POS(x))
88 #define WORD_SHIFT(x) (16 * WORD_POS(x))
90 #define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
91 #define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
93 #define read_pci_cfg_byte(a) \
94 (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
96 #define read_pci_cfg_word(a) \
97 (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
99 #define write_pci_cfg_byte(a, val) do { \
100 uint32 tmpval; \
101 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
102 val << BYTE_POS(a); \
103 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
104 } while (0)
106 #define write_pci_cfg_word(a, val) do { \
107 uint32 tmpval; \
108 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
109 val << WORD_POS(a); \
110 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
111 } while (0)
113 /* delay needed between the mdio control/ mdiodata register data access */
114 #define PR28829_DELAY() OSL_DELAY(10)
116 /* Initialize the PCI core. It's caller's responsibility to make sure that this is done
117 * only once
119 void *
120 pcicore_init(si_t *sih, osl_t *osh, void *regs)
122 pcicore_info_t *pi;
124 ASSERT(sih->bustype == PCI_BUS);
126 /* alloc pcicore_info_t */
127 if ((pi = MALLOC(osh, sizeof(pcicore_info_t))) == NULL) {
128 PCI_ERROR(("pci_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
129 return (NULL);
132 bzero(pi, sizeof(pcicore_info_t));
134 pi->sih = sih;
135 pi->osh = osh;
137 if (sih->buscoretype == PCIE_CORE_ID) {
138 uint8 cap_ptr;
139 pi->regs.pcieregs = (sbpcieregs_t*)regs;
140 cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_PCIECAP_ID, NULL, NULL);
141 ASSERT(cap_ptr);
142 pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
143 pi->pciecap_devctrl_offset = cap_ptr + PCIE_CAP_DEVCTRL_OFFSET;
144 pi->pcie_power_save = TRUE; /* Enable pcie_power_save by default */
145 } else
146 pi->regs.pciregs = (sbpciregs_t*)regs;
148 return pi;
151 void
152 pcicore_deinit(void *pch)
154 pcicore_info_t *pi = (pcicore_info_t *)pch;
157 if (pi == NULL)
158 return;
159 MFREE(pi->osh, pi, sizeof(pcicore_info_t));
162 /* return cap_offset if requested capability exists in the PCI config space */
163 /* Note that it's caller's responsibility to make sure it's a pci bus */
164 uint8
165 pcicore_find_pci_capability(osl_t *osh, uint8 req_cap_id, uchar *buf, uint32 *buflen)
167 uint8 cap_id;
168 uint8 cap_ptr = 0;
169 uint32 bufsize;
170 uint8 byte_val;
172 /* check for Header type 0 */
173 byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
174 if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
175 goto end;
177 /* check if the capability pointer field exists */
178 byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
179 if (!(byte_val & PCI_CAPPTR_PRESENT))
180 goto end;
182 cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
183 /* check if the capability pointer is 0x00 */
184 if (cap_ptr == 0x00)
185 goto end;
187 /* loop thr'u the capability list and see if the pcie capabilty exists */
189 cap_id = read_pci_cfg_byte(cap_ptr);
191 while (cap_id != req_cap_id) {
192 cap_ptr = read_pci_cfg_byte((cap_ptr+1));
193 if (cap_ptr == 0x00) break;
194 cap_id = read_pci_cfg_byte(cap_ptr);
196 if (cap_id != req_cap_id) {
197 goto end;
199 /* found the caller requested capability */
200 if ((buf != NULL) && (buflen != NULL)) {
201 uint8 cap_data;
203 bufsize = *buflen;
204 if (!bufsize) goto end;
205 *buflen = 0;
206 /* copy the cpability data excluding cap ID and next ptr */
207 cap_data = cap_ptr + 2;
208 if ((bufsize + cap_data) > SZPCR)
209 bufsize = SZPCR - cap_data;
210 *buflen = bufsize;
211 while (bufsize--) {
212 *buf = read_pci_cfg_byte(cap_data);
213 cap_data++;
214 buf++;
217 end:
218 return cap_ptr;
221 /* ***** Register Access API */
222 uint
223 pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset)
225 uint retval = 0xFFFFFFFF;
227 ASSERT(pcieregs != NULL);
229 switch (addrtype) {
230 case PCIE_CONFIGREGS:
231 W_REG(osh, (&pcieregs->configaddr), offset);
232 (void)R_REG(osh, (&pcieregs->configaddr));
233 retval = R_REG(osh, &(pcieregs->configdata));
234 break;
235 case PCIE_PCIEREGS:
236 W_REG(osh, &(pcieregs->pcieindaddr), offset);
237 (void)R_REG(osh, (&pcieregs->pcieindaddr));
238 retval = R_REG(osh, &(pcieregs->pcieinddata));
239 break;
240 default:
241 ASSERT(0);
242 break;
245 return retval;
248 uint
249 pcie_writereg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset, uint val)
251 ASSERT(pcieregs != NULL);
253 switch (addrtype) {
254 case PCIE_CONFIGREGS:
255 W_REG(osh, (&pcieregs->configaddr), offset);
256 W_REG(osh, (&pcieregs->configdata), val);
257 break;
258 case PCIE_PCIEREGS:
259 W_REG(osh, (&pcieregs->pcieindaddr), offset);
260 W_REG(osh, (&pcieregs->pcieinddata), val);
261 break;
262 default:
263 ASSERT(0);
264 break;
266 return 0;
269 static bool
270 pcie_mdiosetblock(pcicore_info_t *pi, uint blk)
272 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
273 uint mdiodata, i = 0;
274 uint pcie_serdes_spinwait = 200;
276 mdiodata = MDIODATA_START | MDIODATA_WRITE | (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
277 (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | MDIODATA_TA | (blk << 4);
278 W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
280 PR28829_DELAY();
281 /* retry till the transaction is complete */
282 while (i < pcie_serdes_spinwait) {
283 if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
284 break;
286 OSL_DELAY(1000);
287 i++;
290 if (i >= pcie_serdes_spinwait) {
291 PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
292 return FALSE;
295 return TRUE;
298 static int
299 pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write, uint *val)
301 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
302 uint mdiodata;
303 uint i = 0;
304 uint pcie_serdes_spinwait = 10;
306 /* enable mdio access to SERDES */
307 W_REG(pi->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
309 if (pi->sih->buscorerev >= 10) {
310 /* new serdes is slower in rw, using two layers of reg address mapping */
311 if (!pcie_mdiosetblock(pi, physmedia))
312 return 1;
313 mdiodata = (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
314 (regaddr << MDIODATA_REGADDR_SHF);
315 pcie_serdes_spinwait *= 20;
316 } else {
317 mdiodata = (physmedia << MDIODATA_DEVADDR_SHF_OLD) |
318 (regaddr << MDIODATA_REGADDR_SHF_OLD);
321 if (!write)
322 mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
323 else
324 mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val);
326 W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
328 PR28829_DELAY();
330 /* retry till the transaction is complete */
331 while (i < pcie_serdes_spinwait) {
332 if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
333 if (!write) {
334 PR28829_DELAY();
335 *val = (R_REG(pi->osh, &(pcieregs->mdiodata)) & MDIODATA_MASK);
337 /* Disable mdio access to SERDES */
338 W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
339 return 0;
341 OSL_DELAY(1000);
342 i++;
345 PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write));
346 /* Disable mdio access to SERDES */
347 W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
348 return 1;
351 /* use the mdio interface to read from mdio slaves */
352 static int
353 pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint regaddr, uint *regval)
355 return pcie_mdioop(pi, physmedia, regaddr, FALSE, regval);
358 /* use the mdio interface to write to mdio slaves */
359 static int
360 pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint regaddr, uint val)
362 return pcie_mdioop(pi, physmedia, regaddr, TRUE, &val);
365 /* ***** Support functions ***** */
366 static uint32
367 pcie_devcontrol_mrrs(void *pch, uint32 mask, uint32 val)
369 pcicore_info_t *pi = (pcicore_info_t *)pch;
370 uint32 reg_val;
371 uint8 offset;
373 offset = pi->pciecap_devctrl_offset;
374 if (!offset)
375 return 0;
377 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
378 /* set operation */
379 if (mask) {
380 if (val > PCIE_CAP_DEVCTRL_MRRS_128B) {
381 if (pi->sih->buscorerev < 18) {
382 PCI_ERROR(("%s pcie corerev %d doesn't support >128B MRRS",
383 __FUNCTION__, pi->sih->buscorerev));
384 val = PCIE_CAP_DEVCTRL_MRRS_128B;
388 reg_val &= ~PCIE_CAP_DEVCTRL_MRRS_MASK;
389 reg_val |= (val << PCIE_CAP_DEVCTRL_MRRS_SHIFT) & PCIE_CAP_DEVCTRL_MRRS_MASK;
391 OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val);
392 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
394 return reg_val;
397 uint8
398 pcie_clkreq(void *pch, uint32 mask, uint32 val)
400 pcicore_info_t *pi = (pcicore_info_t *)pch;
401 uint32 reg_val;
402 uint8 offset;
404 offset = pi->pciecap_lcreg_offset;
405 if (!offset)
406 return 0;
408 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
409 /* set operation */
410 if (mask) {
411 if (val)
412 reg_val |= PCIE_CLKREQ_ENAB;
413 else
414 reg_val &= ~PCIE_CLKREQ_ENAB;
415 OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val);
416 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
418 if (reg_val & PCIE_CLKREQ_ENAB)
419 return 1;
420 else
421 return 0;
424 static void
425 pcie_extendL1timer(pcicore_info_t *pi, bool extend)
427 uint32 w;
428 si_t *sih = pi->sih;
429 osl_t *osh = pi->osh;
430 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
432 if (!PCIE(sih))
433 return;
435 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
437 if (extend && sih->buscorerev >= 7)
438 w |= PCIE_ASPMTIMER_EXTEND;
439 else
440 w &= ~PCIE_ASPMTIMER_EXTEND;
441 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
442 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
445 /* centralized clkreq control policy */
446 static void
447 pcie_clkreq_upd(pcicore_info_t *pi, uint state)
449 si_t *sih = pi->sih;
450 ASSERT(PCIE(sih));
452 switch (state) {
453 case SI_DOATTACH:
454 if (PCIE_ASPM(sih))
455 pcie_clkreq((void *)pi, 1, 0);
456 break;
457 case SI_PCIDOWN:
458 if (sih->buscorerev == 6) { /* turn on serdes PLL down */
459 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr),
460 ~0, 0);
461 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data),
462 ~0x40, 0);
463 } else if (pi->pcie_pr42767) {
464 pcie_clkreq((void *)pi, 1, 1);
466 break;
467 case SI_PCIUP:
468 if (sih->buscorerev == 6) { /* turn off serdes PLL down */
469 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_addr),
470 ~0, 0);
471 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol_data),
472 ~0x40, 0x40);
473 } else if (PCIE_ASPM(sih)) { /* disable clkreq */
474 pcie_clkreq((void *)pi, 1, 0);
476 break;
477 default:
478 ASSERT(0);
479 break;
483 /* ***** PCI core WARs ***** */
484 /* Done only once at attach time */
485 static void
486 pcie_war_polarity(pcicore_info_t *pi)
488 uint32 w;
490 if (pi->pcie_polarity != 0)
491 return;
493 w = pcie_readreg(pi->osh, pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
495 /* Detect the current polarity at attach and force that polarity and
496 * disable changing the polarity
498 if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
499 pi->pcie_polarity = (SERDES_RX_CTRL_FORCE);
500 else
501 pi->pcie_polarity = (SERDES_RX_CTRL_FORCE | SERDES_RX_CTRL_POLARITY);
504 /* enable ASPM and CLKREQ if srom doesn't have it */
505 /* Needs to happen when update to shadow SROM is needed
506 * : Coming out of 'standby'/'hibernate'
507 * : If pcie_war_aspm_ovr state changed
509 static void
510 pcie_war_aspm_clkreq(pcicore_info_t *pi)
512 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
513 si_t *sih = pi->sih;
514 uint16 val16, *reg16;
515 uint32 w;
517 if (!PCIE_ASPM(sih))
518 return;
520 /* bypass this on QT or VSIM */
521 if (!ISSIM_ENAB(sih)) {
523 reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET];
524 val16 = R_REG(pi->osh, reg16);
526 val16 &= ~SRSH_ASPM_ENB;
527 if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
528 val16 |= SRSH_ASPM_ENB;
529 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
530 val16 |= SRSH_ASPM_L1_ENB;
531 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
532 val16 |= SRSH_ASPM_L0s_ENB;
534 W_REG(pi->osh, reg16, val16);
536 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32));
537 w &= ~PCIE_ASPM_ENAB;
538 w |= pi->pcie_war_aspm_ovr;
539 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w);
542 reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
543 val16 = R_REG(pi->osh, reg16);
545 if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
546 val16 |= SRSH_CLKREQ_ENB;
547 pi->pcie_pr42767 = TRUE;
548 } else
549 val16 &= ~SRSH_CLKREQ_ENB;
551 W_REG(pi->osh, reg16, val16);
554 static void
555 pcie_war_pmebits(pcicore_info_t *pi)
557 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
558 uint16 val16, *reg16;
560 if (pi->sih->buscorerev != 18 && pi->sih->buscorerev != 19)
561 return;
563 reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8];
564 val16 = R_REG(pi->osh, reg16);
565 if (val16 != pi->pmebits) {
566 PCI_ERROR(("pcie_war_pmebits: pmebits mismatch 0x%x (was 0x%x)\n",
567 val16, pi->pmebits));
568 pi->pmebits = 0x1f30;
569 W_REG(pi->osh, reg16, pi->pmebits);
570 val16 = R_REG(pi->osh, reg16);
571 PCI_ERROR(("pcie_war_pmebits: update pmebits to 0x%x\n", val16));
575 /* Apply the polarity determined at the start */
576 /* Needs to happen when coming out of 'standby'/'hibernate' */
577 static void
578 pcie_war_serdes(pcicore_info_t *pi)
580 uint32 w = 0;
582 if (pi->pcie_polarity != 0)
583 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL, pi->pcie_polarity);
585 pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
586 if (w & PLL_CTRL_FREQDET_EN) {
587 w &= ~PLL_CTRL_FREQDET_EN;
588 pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
592 /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
593 /* Needs to happen when coming out of 'standby'/'hibernate' */
594 static void
595 BCMINITFN(pcie_misc_config_fixup)(pcicore_info_t *pi)
597 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
598 uint16 val16, *reg16;
600 reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
601 val16 = R_REG(pi->osh, reg16);
603 if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
604 val16 |= SRSH_L23READY_EXIT_NOPERST;
605 W_REG(pi->osh, reg16, val16);
609 /* quick hack for testing */
610 /* Needs to happen when coming out of 'standby'/'hibernate' */
611 static void
612 pcie_war_noplldown(pcicore_info_t *pi)
614 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
615 uint16 *reg16;
617 ASSERT(pi->sih->buscorerev == 7);
619 /* turn off serdes PLL down */
620 si_corereg(pi->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
621 CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
623 /* clear srom shadow backdoor */
624 reg16 = &pcieregs->sprom[SRSH_BD_OFFSET];
625 W_REG(pi->osh, reg16, 0);
628 /* Needs to happen when coming out of 'standby'/'hibernate' */
629 static void
630 pcie_war_pci_setup(pcicore_info_t *pi)
632 si_t *sih = pi->sih;
633 osl_t *osh = pi->osh;
634 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
635 uint32 w;
637 if ((sih->buscorerev == 0) || (sih->buscorerev == 1)) {
638 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG);
639 w |= 0x8;
640 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG, w);
643 if (sih->buscorerev == 1) {
644 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
645 w |= (0x40);
646 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
649 if (sih->buscorerev == 0) {
650 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
651 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
652 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
653 } else if (PCIE_ASPM(sih)) {
654 /* Change the L1 threshold for better performance */
655 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
656 w &= ~(PCIE_L1THRESHOLDTIME_MASK);
657 w |= (PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT);
658 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
660 pcie_war_serdes(pi);
662 pcie_war_aspm_clkreq(pi);
663 } else if (pi->sih->buscorerev == 7)
664 pcie_war_noplldown(pi);
666 /* Note that the fix is actually in the SROM, that's why this is open-ended */
667 if (pi->sih->buscorerev >= 6)
668 pcie_misc_config_fixup(pi);
671 void
672 pcie_war_ovr_aspm_update(void *pch, uint8 aspm)
674 pcicore_info_t *pi = (pcicore_info_t *)pch;
676 if (!PCIE_ASPM(pi->sih))
677 return;
679 /* Validate */
680 if (aspm > PCIE_ASPM_ENAB)
681 return;
683 pi->pcie_war_aspm_ovr = aspm;
685 /* Update the current state */
686 pcie_war_aspm_clkreq(pi);
690 void
691 pcie_power_save_enable(void *pch, bool enable)
693 pcicore_info_t *pi = (pcicore_info_t *)pch;
696 if (!pi)
697 return;
699 pi->pcie_power_save = enable;
702 static void
703 pcie_power_save_upd(pcicore_info_t *pi, bool up)
705 si_t *sih = pi->sih;
707 if (!pi->pcie_power_save)
708 return;
711 if ((sih->buscorerev >= 15) && (sih->buscorerev <= 20)) {
713 pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT1, 1, 0x7F64);
715 if (up)
716 pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT3, 1, 0x74);
717 else
718 pcicore_pcieserdesreg(pi, MDIO_DEV_BLK1, BLK1_PWR_MGMT3, 1, 0x7C);
722 void
723 pcie_set_request_size(void *pch, uint16 size)
725 pcicore_info_t *pi = (pcicore_info_t *)pch;
727 if (!pi)
728 return;
729 if (size == 128)
730 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
731 else if (size == 256)
732 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_256B;
733 else if (size == 512)
734 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_512B;
735 else
736 return;
738 if (pi->sih->buscorerev == 18 || pi->sih->buscorerev == 19)
739 pcie_devcontrol_mrrs(pi, PCIE_CAP_DEVCTRL_MRRS_MASK, (uint32)pi->pcie_reqsize);
742 uint16
743 pcie_get_request_size(void *pch)
745 pcicore_info_t *pi = (pcicore_info_t *)pch;
747 if (!pi)
748 return (0);
750 if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_128B)
751 return (128);
752 else if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_256B)
753 return (256);
754 else if (pi->pcie_reqsize == PCIE_CAP_DEVCTRL_MRRS_512B)
755 return (512);
756 return (0);
759 /* ***** Functions called during driver state changes ***** */
760 void
761 BCMATTACHFN(pcicore_attach)(void *pch, char *pvars, int state)
763 pcicore_info_t *pi = (pcicore_info_t *)pch;
764 si_t *sih = pi->sih;
766 if (PCIE_ASPM(sih)) {
767 if (((sih->boardvendor == VENDOR_APPLE) &&
768 ((uint8)getintvar(pvars, "sromrev") == 4) &&
769 ((uint8)getintvar(pvars, "boardrev") <= 0x71)) ||
770 ((uint32)getintvar(pvars, "boardflags2") & BFL2_PCIEWAR_OVR)) {
771 pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
772 } else {
773 pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
777 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
778 if (BCM4331_CHIP_ID == CHIPID(sih->chip))
779 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_512B;
781 /* These need to happen in this order only */
782 pcie_war_polarity(pi);
784 pcie_war_serdes(pi);
786 pcie_war_aspm_clkreq(pi);
788 pcie_clkreq_upd(pi, state);
790 /* Alter default TX drive strength setting */
791 if (sih->boardvendor == VENDOR_APPLE) {
792 if (sih->boardtype == 0x8d)
793 /* change the TX drive strength to max */
794 pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x7f);
795 else if (BCM4331_CHIP_ID == CHIPID(sih->chip))
796 /* change the drive strength for X19b & X28 to 700mv */
797 pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x70);
801 void
802 pcicore_hwup(void *pch)
804 pcicore_info_t *pi = (pcicore_info_t *)pch;
806 if (!pi || !PCIE(pi->sih))
807 return;
809 pcie_power_save_upd(pi, TRUE);
811 if (pi->sih->boardtype == CB2_4321_BOARD || pi->sih->boardtype == CB2_4321_AG_BOARD)
812 pcicore_fixlatencytimer(pch, 0x20);
814 pcie_war_pci_setup(pi);
816 /* Alter default TX drive strength setting */
817 if (pi->sih->boardvendor == VENDOR_APPLE) {
818 if (pi->sih->boardtype == 0x8d)
819 /* change the TX drive strength to max */
820 pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x7f);
821 else if (BCM4331_CHIP_ID == CHIPID(pi->sih->chip))
822 /* change the drive strength for X19b & X28 to 700mv */
823 pcicore_pcieserdesreg(pch, MDIO_DEV_TXCTRL0, 0x18, 0xff, 0x70);
827 void
828 pcicore_up(void *pch, int state)
830 pcicore_info_t *pi = (pcicore_info_t *)pch;
831 bool is_x19_x28 = FALSE;
833 if (!pi || !PCIE(pi->sih))
834 return;
836 pcie_power_save_upd(pi, TRUE);
838 /* Restore L1 timer for better performance */
839 pcie_extendL1timer(pi, TRUE);
841 pcie_clkreq_upd(pi, state);
843 is_x19_x28 = ((pi->sih->boardvendor == VENDOR_APPLE) &&
844 ((pi->sih->boardtype == BCM94331X19) ||
845 (pi->sih->boardtype == BCM94331PCIEBT3Ax_SSID)));
847 if (pi->sih->buscorerev == 18 ||
848 (pi->sih->buscorerev == 19 && !is_x19_x28))
849 pi->pcie_reqsize = PCIE_CAP_DEVCTRL_MRRS_128B;
851 pcie_devcontrol_mrrs(pi, PCIE_CAP_DEVCTRL_MRRS_MASK, pi->pcie_reqsize);
854 /* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */
855 void
856 pcicore_sleep(void *pch)
858 pcicore_info_t *pi = (pcicore_info_t *)pch;
859 uint32 w;
861 if (!pi || !PCIE(pi->sih))
862 return;
864 pcie_power_save_upd(pi, FALSE);
867 if (!PCIE_ASPM(pi->sih))
868 return;
871 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32));
872 w &= ~PCIE_CAP_LCREG_ASPML1;
873 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32), w);
876 pi->pcie_pr42767 = FALSE;
879 void
880 pcicore_down(void *pch, int state)
882 pcicore_info_t *pi = (pcicore_info_t *)pch;
884 if (!pi || !PCIE(pi->sih))
885 return;
887 pcie_clkreq_upd(pi, state);
889 /* Reduce L1 timer for better power savings */
890 pcie_extendL1timer(pi, FALSE);
892 pcie_power_save_upd(pi, FALSE);
895 /* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
896 /* Just uses PCI config accesses to find out, when needed before sb_attach is done */
897 bool
898 pcicore_pmecap_fast(osl_t *osh)
900 uint8 cap_ptr;
901 uint32 pmecap;
903 cap_ptr = pcicore_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL);
905 if (!cap_ptr)
906 return FALSE;
908 pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(uint32));
910 return ((pmecap & PME_CAP_PM_STATES) != 0);
913 /* return TRUE if PM capability exists in the pci config space
914 * Uses and caches the information using core handle
916 static bool
917 pcicore_pmecap(pcicore_info_t *pi)
919 uint8 cap_ptr;
920 uint32 pmecap;
921 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
922 uint16*reg16;
924 if (!pi->pmecap_offset) {
925 cap_ptr = pcicore_find_pci_capability(pi->osh, PCI_CAP_POWERMGMTCAP_ID, NULL, NULL);
926 if (!cap_ptr)
927 return FALSE;
929 pi->pmecap_offset = cap_ptr;
931 reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV8];
932 pi->pmebits = R_REG(pi->osh, reg16);
934 pmecap = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset, sizeof(uint32));
936 /* At least one state can generate PME */
937 pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0;
940 return (pi->pmecap);
943 /* Enable PME generation */
944 void
945 pcicore_pmeen(void *pch)
947 pcicore_info_t *pi = (pcicore_info_t *)pch;
948 uint32 w;
950 /* if not pmecapable return */
951 if (!pcicore_pmecap(pi))
952 return;
954 pcie_war_pmebits(pi);
955 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
956 w |= (PME_CSR_PME_EN);
957 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w);
961 * Return TRUE if PME status set
963 bool
964 pcicore_pmestat(void *pch)
966 pcicore_info_t *pi = (pcicore_info_t *)pch;
967 uint32 w;
969 if (!pcicore_pmecap(pi))
970 return FALSE;
972 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
974 return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT;
977 /* Disable PME generation, clear the PME status bit if set
979 void
980 pcicore_pmeclr(void *pch)
982 pcicore_info_t *pi = (pcicore_info_t *)pch;
983 uint32 w;
985 if (!pcicore_pmecap(pi))
986 return;
988 pcie_war_pmebits(pi);
989 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32));
991 PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w));
993 /* PMESTAT is cleared by writing 1 to it */
994 w &= ~(PME_CSR_PME_EN);
996 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, sizeof(uint32), w);
999 static void
1000 pcicore_fixlatencytimer(pcicore_info_t* pch, uint8 timer_val)
1002 pcicore_info_t *pi = (pcicore_info_t *)pch;
1003 osl_t *osh;
1004 uint8 lattim;
1006 osh = pi->osh;
1007 lattim = read_pci_cfg_byte(PCI_CFG_LATTIM);
1009 if (!lattim) {
1010 PCI_ERROR(("%s: Modifying PCI_CFG_LATTIM from 0x%x to 0x%x\n",
1011 __FUNCTION__, lattim, timer_val));
1012 write_pci_cfg_byte(PCI_CFG_LATTIM, timer_val);
1016 uint32
1017 pcie_lcreg(void *pch, uint32 mask, uint32 val)
1019 pcicore_info_t *pi = (pcicore_info_t *)pch;
1020 uint8 offset;
1022 offset = pi->pciecap_lcreg_offset;
1023 if (!offset)
1024 return 0;
1026 /* set operation */
1027 if (mask)
1028 OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), val);
1030 return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
1033 #ifdef BCMDBG
1034 void
1035 pcicore_dump(void *pch, struct bcmstrbuf *b)
1037 pcicore_info_t *pi = (pcicore_info_t *)pch;
1039 bcm_bprintf(b, "FORCEHT %d pcie_polarity 0x%x pcie_aspm_ovr 0x%x\n",
1040 pi->sih->pci_pr32414, pi->pcie_polarity, pi->pcie_war_aspm_ovr);
1042 #endif /* BCMDBG */
1044 uint32
1045 pcicore_pciereg(void *pch, uint32 offset, uint32 mask, uint32 val, uint type)
1047 uint32 reg_val = 0;
1048 pcicore_info_t *pi = (pcicore_info_t *)pch;
1049 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
1050 osl_t *osh = pi->osh;
1052 if (mask) {
1053 PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val));
1054 pcie_writereg(osh, pcieregs, type, offset, val);
1057 /* Should not read register 0x154 */
1058 if (pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11 && type == PCIE_PCIEREGS)
1059 return reg_val;
1061 reg_val = pcie_readreg(osh, pcieregs, type, offset);
1062 PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val));
1064 return reg_val;
1067 uint32
1068 pcicore_pcieserdesreg(void *pch, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val)
1070 uint32 reg_val = 0;
1071 pcicore_info_t *pi = (pcicore_info_t *)pch;
1073 if (mask) {
1074 pcie_mdiowrite(pi, mdioslave, offset, val);
1077 if (pcie_mdioread(pi, mdioslave, offset, &reg_val))
1078 reg_val = 0xFFFFFFFF;
1080 return reg_val;
1084 #if defined(BCMDBG_DUMP)
1086 /* size that can take bitfielddump */
1087 #define BITFIELD_DUMP_SIZE 2048
1089 /* Dump PCIE PLP/DLLP/TLP diagnostic registers */
1091 pcicore_dump_pcieregs(void *pch, struct bcmstrbuf *b)
1093 pcicore_info_t *pi = (pcicore_info_t *)pch;
1094 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
1095 si_t *sih = pi->sih;
1096 uint reg_val = 0;
1097 char *bitfield_dump_buf;
1099 if (!(bitfield_dump_buf = MALLOC(pi->osh, BITFIELD_DUMP_SIZE))) {
1100 printf("bitfield dump allocation failed\n");
1101 return BCME_NOMEM;
1104 bcm_bprintf(b, "PLPRegs \t");
1105 bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1106 (struct fielddesc *)(uintptr)pcie_plp_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 bcm_bprintf(b, "DLLPRegs \t");
1112 bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1113 (struct fielddesc *)(uintptr)pcie_dllp_regdesc,
1114 bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1115 bcm_bprintf(b, "%s", bitfield_dump_buf);
1116 bzero(bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1117 bcm_bprintf(b, "\n");
1118 bcm_bprintf(b, "TLPRegs \t");
1119 bcmdumpfields(si_pcie_readreg, (void *)(uintptr)pi->sih, PCIE_PCIEREGS,
1120 (struct fielddesc *)(uintptr)pcie_tlp_regdesc,
1121 bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1122 bcm_bprintf(b, "%s", bitfield_dump_buf);
1123 bzero(bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1124 bcm_bprintf(b, "\n");
1126 /* enable mdio access to SERDES */
1127 W_REG(pi->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
1129 bcm_bprintf(b, "SERDES regs \n");
1130 if (sih->buscorerev >= 10) {
1131 pcie_mdioread(pi, MDIO_DEV_IEEE0, 0x2, &reg_val);
1132 bcm_bprintf(b, "block IEEE0, offset 2: 0x%x\n", reg_val);
1133 pcie_mdioread(pi, MDIO_DEV_IEEE0, 0x3, &reg_val);
1134 bcm_bprintf(b, "block IEEE0, offset 2: 0x%x\n", reg_val);
1135 pcie_mdioread(pi, MDIO_DEV_IEEE1, 0x08, &reg_val);
1136 bcm_bprintf(b, "block IEEE1, lanestatus: 0x%x\n", reg_val);
1137 pcie_mdioread(pi, MDIO_DEV_IEEE1, 0x0a, &reg_val);
1138 bcm_bprintf(b, "block IEEE1, lanestatus2: 0x%x\n", reg_val);
1139 pcie_mdioread(pi, MDIO_DEV_BLK4, 0x16, &reg_val);
1140 bcm_bprintf(b, "MDIO_DEV_BLK4, lanetest0: 0x%x\n", reg_val);
1141 pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x11, &reg_val);
1142 bcm_bprintf(b, "MDIO_DEV_TXPLL, pllcontrol: 0x%x\n", reg_val);
1143 pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x12, &reg_val);
1144 bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer1: 0x%x\n", reg_val);
1145 pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x13, &reg_val);
1146 bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer2: 0x%x\n", reg_val);
1147 pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x14, &reg_val);
1148 bcm_bprintf(b, "MDIO_DEV_TXPLL, plltimer3: 0x%x\n", reg_val);
1149 pcie_mdioread(pi, MDIO_DEV_TXPLL, 0x17, &reg_val);
1150 bcm_bprintf(b, "MDIO_DEV_TXPLL, freqdetcounter: 0x%x\n", reg_val);
1151 } else {
1152 pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, &reg_val);
1153 bcm_bprintf(b, "rxtimer1 0x%x ", reg_val);
1154 pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, &reg_val);
1155 bcm_bprintf(b, "rxCDR 0x%x ", reg_val);
1156 pcie_mdioread(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, &reg_val);
1157 bcm_bprintf(b, "rxCDRBW 0x%x\n", reg_val);
1160 /* disable mdio access to SERDES */
1161 W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
1163 MFREE(pi->osh, bitfield_dump_buf, BITFIELD_DUMP_SIZE);
1165 return 0;
1167 #endif