2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 #include <pcie_core.h>
32 sbpcieregs_t *pcieregs;
34 } regs; /* Memory mapped register to the core */
36 si_t *sih; /* System interconnect handle */
37 osl_t *osh; /* OSL handle */
38 uint8 pciecap_lcreg_offset; /* PCIE capability LCreg offset in the config space */
41 uint8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */
43 uint8 pmecap_offset; /* PM Capability offset in the config space */
44 bool pmecap; /* Capable of generating PME */
48 #define PCI_ERROR(args)
49 #define PCIE_PUB(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
51 /* routines to access mdio slave device registers */
52 static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk);
53 static int pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr,
54 bool write, uint *val);
55 static int pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint readdr,
57 static int pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint readdr,
60 static void pcie_extendL1timer(pcicore_info_t *pi, bool extend);
61 static void pcie_clkreq_upd(pcicore_info_t *pi, uint state);
63 static void pcie_war_aspm_clkreq(pcicore_info_t *pi);
64 static void pcie_war_serdes(pcicore_info_t *pi);
65 static void pcie_war_noplldown(pcicore_info_t *pi);
66 static void pcie_war_polarity(pcicore_info_t *pi);
67 static void pcie_war_pci_setup(pcicore_info_t *pi);
69 static bool pcicore_pmecap(pcicore_info_t *pi);
71 #define PCIE_ASPM(sih) ((PCIE_PUB(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
73 #define DWORD_ALIGN(x) (x & ~(0x03))
74 #define BYTE_POS(x) (x & 0x3)
75 #define WORD_POS(x) (x & 0x1)
77 #define BYTE_SHIFT(x) (8 * BYTE_POS(x))
78 #define WORD_SHIFT(x) (16 * WORD_POS(x))
80 #define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
81 #define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
83 #define read_pci_cfg_byte(a) \
84 (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
86 #define read_pci_cfg_word(a) \
87 (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
89 #define write_pci_cfg_byte(a, val) do { \
91 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
93 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
96 #define write_pci_cfg_word(a, val) do { \
98 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
100 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
103 /* delay needed between the mdio control/ mdiodata register data access */
104 #define PR28829_DELAY() OSL_DELAY(10)
106 /* Initialize the PCI core. It's caller's responsibility to make sure that this is done
109 void *pcicore_init(si_t *sih, osl_t *osh, void *regs)
113 ASSERT(sih->bustype == PCI_BUS);
115 /* alloc pcicore_info_t */
116 if ((pi = MALLOC(osh, sizeof(pcicore_info_t))) == NULL) {
117 PCI_ERROR(("pci_attach: malloc failed! malloced %d bytes\n",
122 bzero(pi, sizeof(pcicore_info_t));
127 if (sih->buscoretype == PCIE_CORE_ID) {
129 pi->regs.pcieregs = (sbpcieregs_t *) regs;
131 pcicore_find_pci_capability(pi->osh, PCI_CAP_PCIECAP_ID,
134 pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
136 pi->regs.pciregs = (sbpciregs_t *) regs;
141 void pcicore_deinit(void *pch)
143 pcicore_info_t *pi = (pcicore_info_t *) pch;
147 MFREE(pi->osh, pi, sizeof(pcicore_info_t));
150 /* return cap_offset if requested capability exists in the PCI config space */
151 /* Note that it's caller's responsibility to make sure it's a pci bus */
153 pcicore_find_pci_capability(osl_t *osh, uint8 req_cap_id, uchar *buf,
161 /* check for Header type 0 */
162 byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
163 if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
166 /* check if the capability pointer field exists */
167 byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
168 if (!(byte_val & PCI_CAPPTR_PRESENT))
171 cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
172 /* check if the capability pointer is 0x00 */
176 /* loop thr'u the capability list and see if the pcie capabilty exists */
178 cap_id = read_pci_cfg_byte(cap_ptr);
180 while (cap_id != req_cap_id) {
181 cap_ptr = read_pci_cfg_byte((cap_ptr + 1));
184 cap_id = read_pci_cfg_byte(cap_ptr);
186 if (cap_id != req_cap_id) {
189 /* found the caller requested capability */
190 if ((buf != NULL) && (buflen != NULL)) {
197 /* copy the cpability data excluding cap ID and next ptr */
198 cap_data = cap_ptr + 2;
199 if ((bufsize + cap_data) > SZPCR)
200 bufsize = SZPCR - cap_data;
203 *buf = read_pci_cfg_byte(cap_data);
212 /* ***** Register Access API */
214 pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset)
216 uint retval = 0xFFFFFFFF;
218 ASSERT(pcieregs != NULL);
221 case PCIE_CONFIGREGS:
222 W_REG(osh, (&pcieregs->configaddr), offset);
223 (void)R_REG(osh, (&pcieregs->configaddr));
224 retval = R_REG(osh, &(pcieregs->configdata));
227 W_REG(osh, &(pcieregs->pcieindaddr), offset);
228 (void)R_REG(osh, (&pcieregs->pcieindaddr));
229 retval = R_REG(osh, &(pcieregs->pcieinddata));
240 pcie_writereg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset,
243 ASSERT(pcieregs != NULL);
246 case PCIE_CONFIGREGS:
247 W_REG(osh, (&pcieregs->configaddr), offset);
248 W_REG(osh, (&pcieregs->configdata), val);
251 W_REG(osh, (&pcieregs->pcieindaddr), offset);
252 W_REG(osh, (&pcieregs->pcieinddata), val);
261 static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk)
263 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
264 uint mdiodata, i = 0;
265 uint pcie_serdes_spinwait = 200;
268 MDIODATA_START | MDIODATA_WRITE | (MDIODATA_DEV_ADDR <<
269 MDIODATA_DEVADDR_SHF) |
270 (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | MDIODATA_TA | (blk <<
272 W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
275 /* retry till the transaction is complete */
276 while (i < pcie_serdes_spinwait) {
277 if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) &
278 MDIOCTL_ACCESS_DONE) {
285 if (i >= pcie_serdes_spinwait) {
286 PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
294 pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write,
297 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
300 uint pcie_serdes_spinwait = 10;
302 /* enable mdio access to SERDES */
303 W_REG(pi->osh, (&pcieregs->mdiocontrol),
304 MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
306 if (pi->sih->buscorerev >= 10) {
307 /* new serdes is slower in rw, using two layers of reg address mapping */
308 if (!pcie_mdiosetblock(pi, physmedia))
310 mdiodata = (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
311 (regaddr << MDIODATA_REGADDR_SHF);
312 pcie_serdes_spinwait *= 20;
314 mdiodata = (physmedia << MDIODATA_DEVADDR_SHF_OLD) |
315 (regaddr << MDIODATA_REGADDR_SHF_OLD);
319 mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
322 (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val);
324 W_REG(pi->osh, &pcieregs->mdiodata, mdiodata);
328 /* retry till the transaction is complete */
329 while (i < pcie_serdes_spinwait) {
330 if (R_REG(pi->osh, &(pcieregs->mdiocontrol)) &
331 MDIOCTL_ACCESS_DONE) {
335 (R_REG(pi->osh, &(pcieregs->mdiodata)) &
338 /* Disable mdio access to SERDES */
339 W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
346 PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write));
347 /* Disable mdio access to SERDES */
348 W_REG(pi->osh, (&pcieregs->mdiocontrol), 0);
352 /* use the mdio interface to read from mdio slaves */
354 pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint regaddr, uint *regval)
356 return pcie_mdioop(pi, physmedia, regaddr, FALSE, regval);
359 /* use the mdio interface to write to mdio slaves */
361 pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint regaddr, uint val)
363 return pcie_mdioop(pi, physmedia, regaddr, TRUE, &val);
366 /* ***** Support functions ***** */
367 uint8 pcie_clkreq(void *pch, uint32 mask, uint32 val)
369 pcicore_info_t *pi = (pcicore_info_t *) pch;
373 offset = pi->pciecap_lcreg_offset;
377 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
381 reg_val |= PCIE_CLKREQ_ENAB;
383 reg_val &= ~PCIE_CLKREQ_ENAB;
384 OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), reg_val);
385 reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
387 if (reg_val & PCIE_CLKREQ_ENAB)
393 static void pcie_extendL1timer(pcicore_info_t *pi, bool extend)
397 osl_t *osh = pi->osh;
398 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
400 if (!PCIE_PUB(sih) || sih->buscorerev < 7)
403 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
405 w |= PCIE_ASPMTIMER_EXTEND;
407 w &= ~PCIE_ASPMTIMER_EXTEND;
408 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
409 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
412 /* centralized clkreq control policy */
413 static void pcie_clkreq_upd(pcicore_info_t *pi, uint state)
416 ASSERT(PCIE_PUB(sih));
421 pcie_clkreq((void *)pi, 1, 0);
424 if (sih->buscorerev == 6) { /* turn on serdes PLL down */
425 si_corereg(sih, SI_CC_IDX,
426 OFFSETOF(chipcregs_t, chipcontrol_addr), ~0,
428 si_corereg(sih, SI_CC_IDX,
429 OFFSETOF(chipcregs_t, chipcontrol_data),
431 } else if (pi->pcie_pr42767) {
432 pcie_clkreq((void *)pi, 1, 1);
436 if (sih->buscorerev == 6) { /* turn off serdes PLL down */
437 si_corereg(sih, SI_CC_IDX,
438 OFFSETOF(chipcregs_t, chipcontrol_addr), ~0,
440 si_corereg(sih, SI_CC_IDX,
441 OFFSETOF(chipcregs_t, chipcontrol_data),
443 } else if (PCIE_ASPM(sih)) { /* disable clkreq */
444 pcie_clkreq((void *)pi, 1, 0);
453 /* ***** PCI core WARs ***** */
454 /* Done only once at attach time */
455 static void pcie_war_polarity(pcicore_info_t *pi)
459 if (pi->pcie_polarity != 0)
462 w = pcie_readreg(pi->osh, pi->regs.pcieregs, PCIE_PCIEREGS,
465 /* Detect the current polarity at attach and force that polarity and
466 * disable changing the polarity
468 if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
469 pi->pcie_polarity = (SERDES_RX_CTRL_FORCE);
472 (SERDES_RX_CTRL_FORCE | SERDES_RX_CTRL_POLARITY);
475 /* enable ASPM and CLKREQ if srom doesn't have it */
476 /* Needs to happen when update to shadow SROM is needed
477 * : Coming out of 'standby'/'hibernate'
478 * : If pcie_war_aspm_ovr state changed
480 static void pcie_war_aspm_clkreq(pcicore_info_t *pi)
482 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
484 uint16 val16, *reg16;
490 /* bypass this on QT or VSIM */
491 if (!ISSIM_ENAB(sih)) {
493 reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET];
494 val16 = R_REG(pi->osh, reg16);
496 val16 &= ~SRSH_ASPM_ENB;
497 if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
498 val16 |= SRSH_ASPM_ENB;
499 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
500 val16 |= SRSH_ASPM_L1_ENB;
501 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
502 val16 |= SRSH_ASPM_L0s_ENB;
504 W_REG(pi->osh, reg16, val16);
506 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
508 w &= ~PCIE_ASPM_ENAB;
509 w |= pi->pcie_war_aspm_ovr;
510 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
514 reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
515 val16 = R_REG(pi->osh, reg16);
517 if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
518 val16 |= SRSH_CLKREQ_ENB;
519 pi->pcie_pr42767 = TRUE;
521 val16 &= ~SRSH_CLKREQ_ENB;
523 W_REG(pi->osh, reg16, val16);
526 /* Apply the polarity determined at the start */
527 /* Needs to happen when coming out of 'standby'/'hibernate' */
528 static void pcie_war_serdes(pcicore_info_t *pi)
532 if (pi->pcie_polarity != 0)
533 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
536 pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
537 if (w & PLL_CTRL_FREQDET_EN) {
538 w &= ~PLL_CTRL_FREQDET_EN;
539 pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
543 /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
544 /* Needs to happen when coming out of 'standby'/'hibernate' */
545 static void BCMINITFN(pcie_misc_config_fixup) (pcicore_info_t *pi) {
546 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
547 uint16 val16, *reg16;
549 reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
550 val16 = R_REG(pi->osh, reg16);
552 if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
553 val16 |= SRSH_L23READY_EXIT_NOPERST;
554 W_REG(pi->osh, reg16, val16);
558 /* quick hack for testing */
559 /* Needs to happen when coming out of 'standby'/'hibernate' */
560 static void pcie_war_noplldown(pcicore_info_t *pi)
562 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
565 ASSERT(pi->sih->buscorerev == 7);
567 /* turn off serdes PLL down */
568 si_corereg(pi->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
569 CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
571 /* clear srom shadow backdoor */
572 reg16 = &pcieregs->sprom[SRSH_BD_OFFSET];
573 W_REG(pi->osh, reg16, 0);
576 /* Needs to happen when coming out of 'standby'/'hibernate' */
577 static void pcie_war_pci_setup(pcicore_info_t *pi)
580 osl_t *osh = pi->osh;
581 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
584 if ((sih->buscorerev == 0) || (sih->buscorerev == 1)) {
585 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS,
586 PCIE_TLP_WORKAROUNDSREG);
588 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS,
589 PCIE_TLP_WORKAROUNDSREG, w);
592 if (sih->buscorerev == 1) {
593 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
595 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
598 if (sih->buscorerev == 0) {
599 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
600 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
601 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
602 } else if (PCIE_ASPM(sih)) {
603 /* Change the L1 threshold for better performance */
604 w = pcie_readreg(osh, pcieregs, PCIE_PCIEREGS,
605 PCIE_DLLP_PMTHRESHREG);
606 w &= ~(PCIE_L1THRESHOLDTIME_MASK);
607 w |= (PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT);
608 pcie_writereg(osh, pcieregs, PCIE_PCIEREGS,
609 PCIE_DLLP_PMTHRESHREG, w);
613 pcie_war_aspm_clkreq(pi);
614 } else if (pi->sih->buscorerev == 7)
615 pcie_war_noplldown(pi);
617 /* Note that the fix is actually in the SROM, that's why this is open-ended */
618 if (pi->sih->buscorerev >= 6)
619 pcie_misc_config_fixup(pi);
622 void pcie_war_ovr_aspm_update(void *pch, uint8 aspm)
624 pcicore_info_t *pi = (pcicore_info_t *) pch;
626 if (!PCIE_ASPM(pi->sih))
630 if (aspm > PCIE_ASPM_ENAB)
633 pi->pcie_war_aspm_ovr = aspm;
635 /* Update the current state */
636 pcie_war_aspm_clkreq(pi);
639 /* ***** Functions called during driver state changes ***** */
640 void BCMATTACHFN(pcicore_attach) (void *pch, char *pvars, int state) {
641 pcicore_info_t *pi = (pcicore_info_t *) pch;
644 /* Determine if this board needs override */
645 if (PCIE_ASPM(sih)) {
646 if ((uint32) getintvar(pvars, "boardflags2") & BFL2_PCIEWAR_OVR) {
647 pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
649 pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
653 /* These need to happen in this order only */
654 pcie_war_polarity(pi);
658 pcie_war_aspm_clkreq(pi);
660 pcie_clkreq_upd(pi, state);
664 void pcicore_hwup(void *pch)
666 pcicore_info_t *pi = (pcicore_info_t *) pch;
668 if (!pi || !PCIE_PUB(pi->sih))
671 pcie_war_pci_setup(pi);
674 void pcicore_up(void *pch, int state)
676 pcicore_info_t *pi = (pcicore_info_t *) pch;
678 if (!pi || !PCIE_PUB(pi->sih))
681 /* Restore L1 timer for better performance */
682 pcie_extendL1timer(pi, TRUE);
684 pcie_clkreq_upd(pi, state);
687 /* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */
688 void pcicore_sleep(void *pch)
690 pcicore_info_t *pi = (pcicore_info_t *) pch;
693 if (!pi || !PCIE_ASPM(pi->sih))
696 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
698 w &= ~PCIE_CAP_LCREG_ASPML1;
699 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(uint32),
702 pi->pcie_pr42767 = FALSE;
705 void pcicore_down(void *pch, int state)
707 pcicore_info_t *pi = (pcicore_info_t *) pch;
709 if (!pi || !PCIE_PUB(pi->sih))
712 pcie_clkreq_upd(pi, state);
714 /* Reduce L1 timer for better power savings */
715 pcie_extendL1timer(pi, FALSE);
718 /* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
719 /* Just uses PCI config accesses to find out, when needed before sb_attach is done */
720 bool pcicore_pmecap_fast(osl_t *osh)
726 pcicore_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID, NULL,
732 pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(uint32));
734 return ((pmecap & PME_CAP_PM_STATES) != 0);
737 /* return TRUE if PM capability exists in the pci config space
738 * Uses and caches the information using core handle
740 static bool pcicore_pmecap(pcicore_info_t *pi)
745 if (!pi->pmecap_offset) {
747 pcicore_find_pci_capability(pi->osh,
748 PCI_CAP_POWERMGMTCAP_ID, NULL,
753 pi->pmecap_offset = cap_ptr;
756 OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset,
759 /* At least one state can generate PME */
760 pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0;
766 /* Enable PME generation */
767 void pcicore_pmeen(void *pch)
769 pcicore_info_t *pi = (pcicore_info_t *) pch;
772 /* if not pmecapable return */
773 if (!pcicore_pmecap(pi))
776 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
778 w |= (PME_CSR_PME_EN);
779 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
784 * Return TRUE if PME status set
786 bool pcicore_pmestat(void *pch)
788 pcicore_info_t *pi = (pcicore_info_t *) pch;
791 if (!pcicore_pmecap(pi))
794 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
797 return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT;
800 /* Disable PME generation, clear the PME status bit if set
802 void pcicore_pmeclr(void *pch)
804 pcicore_info_t *pi = (pcicore_info_t *) pch;
807 if (!pcicore_pmecap(pi))
810 w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
813 PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w));
815 /* PMESTAT is cleared by writing 1 to it */
816 w &= ~(PME_CSR_PME_EN);
818 OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
822 uint32 pcie_lcreg(void *pch, uint32 mask, uint32 val)
824 pcicore_info_t *pi = (pcicore_info_t *) pch;
827 offset = pi->pciecap_lcreg_offset;
833 OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(uint32), val);
835 return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(uint32));
839 pcicore_pciereg(void *pch, uint32 offset, uint32 mask, uint32 val, uint type)
842 pcicore_info_t *pi = (pcicore_info_t *) pch;
843 sbpcieregs_t *pcieregs = pi->regs.pcieregs;
844 osl_t *osh = pi->osh;
847 PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val));
848 pcie_writereg(osh, pcieregs, type, offset, val);
851 /* Should not read register 0x154 */
852 if (pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11
853 && type == PCIE_PCIEREGS)
856 reg_val = pcie_readreg(osh, pcieregs, type, offset);
857 PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val));
863 pcicore_pcieserdesreg(void *pch, uint32 mdioslave, uint32 offset, uint32 mask,
867 pcicore_info_t *pi = (pcicore_info_t *) pch;
870 PCI_ERROR(("PCIEMDIOREG: 0x%x writeval 0x%x\n", offset, val));
871 pcie_mdiowrite(pi, mdioslave, offset, val);
874 if (pcie_mdioread(pi, mdioslave, offset, ®_val))
875 reg_val = 0xFFFFFFFF;
876 PCI_ERROR(("PCIEMDIOREG: dev 0x%x offset 0x%x read 0x%x\n", mdioslave,