2 * Code to operate on PCI/E core, in NIC mode
4 * Copyright (C) 2009, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: nicpci.c,v 1.15.2.12 2009/04/23 05:17:12 Exp $
24 #include <pcie_core.h>
30 sbpcieregs_t
*pcieregs
;
32 } regs
; /* Memory mapped register to the core */
34 si_t
*sih
; /* System interconnect handle */
35 osl_t
*osh
; /* OSL handle */
36 uint8 pciecap_lcreg_offset
; /* PCIE capability LCreg offset in the config space */
39 uint8 pcie_war_aspm_ovr
; /* Override ASPM/Clkreq settings */
41 uint8 pmecap_offset
; /* PM Capability offset in the config space */
42 bool pmecap
; /* Capable of generating PME */
46 #define PCI_ERROR(args)
48 /* routines to access mdio slave device registers */
49 static bool pcie_mdiosetblock(pcicore_info_t
*pi
, uint blk
);
50 static int pcie_mdioop(pcicore_info_t
*pi
, uint physmedia
, uint regaddr
, bool write
, uint
*val
);
51 static int pcie_mdiowrite(pcicore_info_t
*pi
, uint physmedia
, uint readdr
, uint val
);
52 static int pcie_mdioread(pcicore_info_t
*pi
, uint physmedia
, uint readdr
, uint
*ret_val
);
54 static void pcie_extendL1timer(pcicore_info_t
*pi
, bool extend
);
55 static void pcie_clkreq_upd(pcicore_info_t
*pi
, uint state
);
57 static void pcie_war_aspm_clkreq(pcicore_info_t
*pi
);
58 static void pcie_war_serdes(pcicore_info_t
*pi
);
59 static void pcie_war_noplldown(pcicore_info_t
*pi
);
60 static void pcie_war_polarity(pcicore_info_t
*pi
);
61 static void pcie_war_pci_setup(pcicore_info_t
*pi
);
63 static bool pcicore_pmecap(pcicore_info_t
*pi
);
64 static void pcicore_fixlatencytimer(pcicore_info_t
* pch
, uint8 timer_val
);
66 #define PCIE(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
67 #define PCIE_ASPM(sih) ((PCIE(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
69 #define DWORD_ALIGN(x) (x & ~(0x03))
70 #define BYTE_POS(x) (x & 0x3)
71 #define WORD_POS(x) (x & 0x1)
73 #define BYTE_SHIFT(x) (8 * BYTE_POS(x))
74 #define WORD_SHIFT(x) (16 * WORD_POS(x))
76 #define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
77 #define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
79 #define read_pci_cfg_byte(a) \
80 (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
82 #define read_pci_cfg_word(a) \
83 (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
85 #define write_pci_cfg_byte(a, val) do { \
86 uint32 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
88 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
91 #define write_pci_cfg_word(a, val) do { \
92 uint32 tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
94 OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
97 /* delay needed between the mdio control/ mdiodata register data access */
98 #define PR28829_DELAY() OSL_DELAY(10)
100 /* Initialize the PCI core. It's caller's responsibility to make sure that this is done
104 pcicore_init(si_t
*sih
, osl_t
*osh
, void *regs
)
108 ASSERT(sih
->bustype
== PCI_BUS
);
110 /* alloc pcicore_info_t */
111 if ((pi
= MALLOC(osh
, sizeof(pcicore_info_t
))) == NULL
) {
112 PCI_ERROR(("pci_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh
)));
116 bzero(pi
, sizeof(pcicore_info_t
));
121 if (sih
->buscoretype
== PCIE_CORE_ID
) {
123 pi
->regs
.pcieregs
= (sbpcieregs_t
*)regs
;
124 cap_ptr
= pcicore_find_pci_capability(pi
->osh
, PCI_CAP_PCIECAP_ID
, NULL
, NULL
);
126 pi
->pciecap_lcreg_offset
= cap_ptr
+ PCIE_CAP_LINKCTRL_OFFSET
;
128 pi
->regs
.pciregs
= (sbpciregs_t
*)regs
;
134 pcicore_deinit(void *pch
)
136 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
140 MFREE(pi
->osh
, pi
, sizeof(pcicore_info_t
));
143 /* return cap_offset if requested capability exists in the PCI config space */
144 /* Note that it's caller's responsibility to make sure it's a pci bus */
146 pcicore_find_pci_capability(osl_t
*osh
, uint8 req_cap_id
, uchar
*buf
, uint32
*buflen
)
153 /* check for Header type 0 */
154 byte_val
= read_pci_cfg_byte(PCI_CFG_HDR
);
155 if ((byte_val
& 0x7f) != PCI_HEADER_NORMAL
)
158 /* check if the capability pointer field exists */
159 byte_val
= read_pci_cfg_byte(PCI_CFG_STAT
);
160 if (!(byte_val
& PCI_CAPPTR_PRESENT
))
163 cap_ptr
= read_pci_cfg_byte(PCI_CFG_CAPPTR
);
164 /* check if the capability pointer is 0x00 */
168 /* loop thr'u the capability list and see if the pcie capabilty exists */
170 cap_id
= read_pci_cfg_byte(cap_ptr
);
172 while (cap_id
!= req_cap_id
) {
173 cap_ptr
= read_pci_cfg_byte((cap_ptr
+1));
174 if (cap_ptr
== 0x00) break;
175 cap_id
= read_pci_cfg_byte(cap_ptr
);
177 if (cap_id
!= req_cap_id
) {
180 /* found the caller requested capability */
181 if ((buf
!= NULL
) && (buflen
!= NULL
)) {
185 if (!bufsize
) goto end
;
187 /* copy the cpability data excluding cap ID and next ptr */
188 cap_data
= cap_ptr
+ 2;
189 if ((bufsize
+ cap_data
) > SZPCR
)
190 bufsize
= SZPCR
- cap_data
;
193 *buf
= read_pci_cfg_byte(cap_data
);
202 /* ***** Register Access API */
204 pcie_readreg(osl_t
*osh
, sbpcieregs_t
*pcieregs
, uint addrtype
, uint offset
)
206 uint retval
= 0xFFFFFFFF;
208 ASSERT(pcieregs
!= NULL
);
211 case PCIE_CONFIGREGS
:
212 W_REG(osh
, (&pcieregs
->configaddr
), offset
);
213 (void)R_REG(osh
, (&pcieregs
->configaddr
));
214 retval
= R_REG(osh
, &(pcieregs
->configdata
));
217 W_REG(osh
, &(pcieregs
->pcieindaddr
), offset
);
218 (void)R_REG(osh
, (&pcieregs
->pcieindaddr
));
219 retval
= R_REG(osh
, &(pcieregs
->pcieinddata
));
230 pcie_writereg(osl_t
*osh
, sbpcieregs_t
*pcieregs
, uint addrtype
, uint offset
, uint val
)
232 ASSERT(pcieregs
!= NULL
);
235 case PCIE_CONFIGREGS
:
236 W_REG(osh
, (&pcieregs
->configaddr
), offset
);
237 W_REG(osh
, (&pcieregs
->configdata
), val
);
240 W_REG(osh
, (&pcieregs
->pcieindaddr
), offset
);
241 W_REG(osh
, (&pcieregs
->pcieinddata
), val
);
251 pcie_mdiosetblock(pcicore_info_t
*pi
, uint blk
)
253 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
254 uint mdiodata
, i
= 0;
255 uint pcie_serdes_spinwait
= 200;
257 mdiodata
= MDIODATA_START
| MDIODATA_WRITE
| (MDIODATA_DEV_ADDR
<< MDIODATA_DEVADDR_SHF
) | \
258 (MDIODATA_BLK_ADDR
<< MDIODATA_REGADDR_SHF
) | MDIODATA_TA
| (blk
<< 4);
259 W_REG(pi
->osh
, &pcieregs
->mdiodata
, mdiodata
);
262 /* retry till the transaction is complete */
263 while (i
< pcie_serdes_spinwait
) {
264 if (R_REG(pi
->osh
, &(pcieregs
->mdiocontrol
)) & MDIOCTL_ACCESS_DONE
) {
271 if (i
>= pcie_serdes_spinwait
) {
272 PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
280 pcie_mdioop(pcicore_info_t
*pi
, uint physmedia
, uint regaddr
, bool write
, uint
*val
)
282 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
285 uint pcie_serdes_spinwait
= 10;
287 /* enable mdio access to SERDES */
288 W_REG(pi
->osh
, (&pcieregs
->mdiocontrol
), MDIOCTL_PREAM_EN
| MDIOCTL_DIVISOR_VAL
);
290 if (pi
->sih
->buscorerev
>= 10) {
291 /* new serdes is slower in rw, using two layers of reg address mapping */
292 if (!pcie_mdiosetblock(pi
, physmedia
))
294 mdiodata
= (MDIODATA_DEV_ADDR
<< MDIODATA_DEVADDR_SHF
) | \
295 (regaddr
<< MDIODATA_REGADDR_SHF
);
296 pcie_serdes_spinwait
*= 20;
298 mdiodata
= (physmedia
<< MDIODATA_DEVADDR_SHF_OLD
) | \
299 (regaddr
<< MDIODATA_REGADDR_SHF_OLD
);
303 mdiodata
|= (MDIODATA_START
| MDIODATA_READ
| MDIODATA_TA
);
305 mdiodata
|= (MDIODATA_START
| MDIODATA_WRITE
| MDIODATA_TA
| *val
);
307 W_REG(pi
->osh
, &pcieregs
->mdiodata
, mdiodata
);
311 /* retry till the transaction is complete */
312 while (i
< pcie_serdes_spinwait
) {
313 if (R_REG(pi
->osh
, &(pcieregs
->mdiocontrol
)) & MDIOCTL_ACCESS_DONE
) {
316 *val
= (R_REG(pi
->osh
, &(pcieregs
->mdiodata
)) & MDIODATA_MASK
);
318 /* Disable mdio access to SERDES */
319 W_REG(pi
->osh
, (&pcieregs
->mdiocontrol
), 0);
326 PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write
));
327 /* Disable mdio access to SERDES */
328 W_REG(pi
->osh
, (&pcieregs
->mdiocontrol
), 0);
332 /* use the mdio interface to read from mdio slaves */
334 pcie_mdioread(pcicore_info_t
*pi
, uint physmedia
, uint regaddr
, uint
*regval
)
336 return pcie_mdioop(pi
, physmedia
, regaddr
, FALSE
, regval
);
339 /* use the mdio interface to write to mdio slaves */
341 pcie_mdiowrite(pcicore_info_t
*pi
, uint physmedia
, uint regaddr
, uint val
)
343 return pcie_mdioop(pi
, physmedia
, regaddr
, TRUE
, &val
);
346 /* ***** Support functions ***** */
348 pcie_clkreq(void *pch
, uint32 mask
, uint32 val
)
350 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
354 offset
= pi
->pciecap_lcreg_offset
;
358 reg_val
= OSL_PCI_READ_CONFIG(pi
->osh
, offset
, sizeof(uint32
));
362 reg_val
|= PCIE_CLKREQ_ENAB
;
364 reg_val
&= ~PCIE_CLKREQ_ENAB
;
365 OSL_PCI_WRITE_CONFIG(pi
->osh
, offset
, sizeof(uint32
), reg_val
);
366 reg_val
= OSL_PCI_READ_CONFIG(pi
->osh
, offset
, sizeof(uint32
));
368 if (reg_val
& PCIE_CLKREQ_ENAB
)
375 pcie_extendL1timer(pcicore_info_t
*pi
, bool extend
)
379 osl_t
*osh
= pi
->osh
;
380 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
383 !(sih
->buscorerev
== 7 || sih
->buscorerev
== 8))
386 w
= pcie_readreg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_PMTHRESHREG
);
388 w
|= PCIE_ASPMTIMER_EXTEND
;
390 w
&= ~PCIE_ASPMTIMER_EXTEND
;
391 pcie_writereg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_PMTHRESHREG
, w
);
392 w
= pcie_readreg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_PMTHRESHREG
);
395 /* centralized clkreq control policy */
397 pcie_clkreq_upd(pcicore_info_t
*pi
, uint state
)
405 pcie_clkreq((void *)pi
, 1, 0);
408 if (sih
->buscorerev
== 6) { /* turn on serdes PLL down */
409 si_corereg(sih
, SI_CC_IDX
, OFFSETOF(chipcregs_t
, chipcontrol_addr
),
411 si_corereg(sih
, SI_CC_IDX
, OFFSETOF(chipcregs_t
, chipcontrol_data
),
413 } else if (pi
->pcie_pr42767
) {
414 pcie_clkreq((void *)pi
, 1, 1);
418 if (sih
->buscorerev
== 6) { /* turn off serdes PLL down */
419 si_corereg(sih
, SI_CC_IDX
, OFFSETOF(chipcregs_t
, chipcontrol_addr
),
421 si_corereg(sih
, SI_CC_IDX
, OFFSETOF(chipcregs_t
, chipcontrol_data
),
423 } else if (PCIE_ASPM(sih
)) { /* disable clkreq */
424 pcie_clkreq((void *)pi
, 1, 0);
433 /* ***** PCI core WARs ***** */
434 /* Done only once at attach time */
436 pcie_war_polarity(pcicore_info_t
*pi
)
440 if (pi
->pcie_polarity
!= 0)
443 w
= pcie_readreg(pi
->osh
, pi
->regs
.pcieregs
, PCIE_PCIEREGS
, PCIE_PLP_STATUSREG
);
445 /* Detect the current polarity at attach and force that polarity and
446 * disable changing the polarity
448 if ((w
& PCIE_PLP_POLARITYINV_STAT
) == 0)
449 pi
->pcie_polarity
= (SERDES_RX_CTRL_FORCE
);
451 pi
->pcie_polarity
= (SERDES_RX_CTRL_FORCE
| SERDES_RX_CTRL_POLARITY
);
454 /* enable ASPM and CLKREQ if srom doesn't have it */
455 /* Needs to happen when update to shadow SROM is needed
456 * : Coming out of 'standby'/'hibernate'
457 * : If pcie_war_aspm_ovr state changed
460 pcie_war_aspm_clkreq(pcicore_info_t
*pi
)
462 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
464 uint16 val16
, *reg16
;
470 /* bypass this on QT or VSIM */
471 if (!ISSIM_ENAB(sih
)) {
473 reg16
= &pcieregs
->sprom
[SRSH_ASPM_OFFSET
];
474 val16
= R_REG(pi
->osh
, reg16
);
476 val16
&= ~SRSH_ASPM_ENB
;
477 if (pi
->pcie_war_aspm_ovr
== PCIE_ASPM_ENAB
)
478 val16
|= SRSH_ASPM_ENB
;
479 else if (pi
->pcie_war_aspm_ovr
== PCIE_ASPM_L1_ENAB
)
480 val16
|= SRSH_ASPM_L1_ENB
;
481 else if (pi
->pcie_war_aspm_ovr
== PCIE_ASPM_L0s_ENAB
)
482 val16
|= SRSH_ASPM_L0s_ENB
;
484 W_REG(pi
->osh
, reg16
, val16
);
486 w
= OSL_PCI_READ_CONFIG(pi
->osh
, pi
->pciecap_lcreg_offset
, sizeof(uint32
));
487 w
&= ~PCIE_ASPM_ENAB
;
488 w
|= pi
->pcie_war_aspm_ovr
;
489 OSL_PCI_WRITE_CONFIG(pi
->osh
, pi
->pciecap_lcreg_offset
, sizeof(uint32
), w
);
492 reg16
= &pcieregs
->sprom
[SRSH_CLKREQ_OFFSET_REV5
];
493 val16
= R_REG(pi
->osh
, reg16
);
495 if (pi
->pcie_war_aspm_ovr
!= PCIE_ASPM_DISAB
) {
496 val16
|= SRSH_CLKREQ_ENB
;
497 pi
->pcie_pr42767
= TRUE
;
499 val16
&= ~SRSH_CLKREQ_ENB
;
501 W_REG(pi
->osh
, reg16
, val16
);
504 /* Apply the polarity determined at the start */
505 /* Needs to happen when coming out of 'standby'/'hibernate' */
507 pcie_war_serdes(pcicore_info_t
*pi
)
511 if (pi
->pcie_polarity
!= 0)
512 pcie_mdiowrite(pi
, MDIODATA_DEV_RX
, SERDES_RX_CTRL
, pi
->pcie_polarity
);
514 pcie_mdioread(pi
, MDIODATA_DEV_PLL
, SERDES_PLL_CTRL
, &w
);
515 if (w
& PLL_CTRL_FREQDET_EN
) {
516 w
&= ~PLL_CTRL_FREQDET_EN
;
517 pcie_mdiowrite(pi
, MDIODATA_DEV_PLL
, SERDES_PLL_CTRL
, w
);
521 /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
522 /* Needs to happen when coming out of 'standby'/'hibernate' */
524 BCMINITFN(pcie_misc_config_fixup
)(pcicore_info_t
*pi
)
526 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
527 uint16 val16
, *reg16
;
529 reg16
= &pcieregs
->sprom
[SRSH_PCIE_MISC_CONFIG
];
530 val16
= R_REG(pi
->osh
, reg16
);
532 if ((val16
& SRSH_L23READY_EXIT_NOPERST
) == 0) {
533 val16
|= SRSH_L23READY_EXIT_NOPERST
;
534 W_REG(pi
->osh
, reg16
, val16
);
538 /* quick hack for testing */
539 /* Needs to happen when coming out of 'standby'/'hibernate' */
541 pcie_war_noplldown(pcicore_info_t
*pi
)
543 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
546 ASSERT(pi
->sih
->buscorerev
== 7);
548 /* turn off serdes PLL down */
549 si_corereg(pi
->sih
, SI_CC_IDX
, OFFSETOF(chipcregs_t
, chipcontrol
),
550 CHIPCTRL_4321_PLL_DOWN
, CHIPCTRL_4321_PLL_DOWN
);
552 /* clear srom shadow backdoor */
553 reg16
= &pcieregs
->sprom
[SRSH_BD_OFFSET
];
554 W_REG(pi
->osh
, reg16
, 0);
557 /* Needs to happen when coming out of 'standby'/'hibernate' */
559 pcie_war_pci_setup(pcicore_info_t
*pi
)
562 osl_t
*osh
= pi
->osh
;
563 sbpcieregs_t
*pcieregs
= pi
->regs
.pcieregs
;
566 if ((sih
->buscorerev
== 0) || (sih
->buscorerev
== 1)) {
567 w
= pcie_readreg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_TLP_WORKAROUNDSREG
);
569 pcie_writereg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_TLP_WORKAROUNDSREG
, w
);
572 if (sih
->buscorerev
== 1) {
573 w
= pcie_readreg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_LCREG
);
575 pcie_writereg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_LCREG
, w
);
578 if (sih
->buscorerev
== 0) {
579 pcie_mdiowrite(pi
, MDIODATA_DEV_RX
, SERDES_RX_TIMER1
, 0x8128);
580 pcie_mdiowrite(pi
, MDIODATA_DEV_RX
, SERDES_RX_CDR
, 0x0100);
581 pcie_mdiowrite(pi
, MDIODATA_DEV_RX
, SERDES_RX_CDRBW
, 0x1466);
582 } else if (PCIE_ASPM(sih
)) {
583 /* Change the L1 threshold for better performance */
584 w
= pcie_readreg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_PMTHRESHREG
);
585 w
&= ~(PCIE_L1THRESHOLDTIME_MASK
);
586 w
|= (PCIE_L1THRESHOLD_WARVAL
<< PCIE_L1THRESHOLDTIME_SHIFT
);
587 pcie_writereg(osh
, pcieregs
, PCIE_PCIEREGS
, PCIE_DLLP_PMTHRESHREG
, w
);
591 pcie_war_aspm_clkreq(pi
);
592 } else if (pi
->sih
->buscorerev
== 7)
593 pcie_war_noplldown(pi
);
595 /* Note that the fix is actually in the SROM, that's why this is open-ended */
596 if (pi
->sih
->buscorerev
>= 6)
597 pcie_misc_config_fixup(pi
);
601 pcie_war_ovr_aspm_update(void *pch
, uint8 aspm
)
603 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
605 if (!PCIE_ASPM(pi
->sih
))
609 if (aspm
> PCIE_ASPM_ENAB
)
612 pi
->pcie_war_aspm_ovr
= aspm
;
614 /* Update the current state */
615 pcie_war_aspm_clkreq(pi
);
618 /* ***** Functions called during driver state changes ***** */
620 BCMATTACHFN(pcicore_attach
)(void *pch
, char *pvars
, int state
)
622 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
625 /* Determine if this board needs override */
626 if (PCIE_ASPM(sih
)) {
627 if (((sih
->boardvendor
== VENDOR_APPLE
) &&
628 ((uint8
)getintvar(pvars
, "sromrev") == 4) &&
629 ((uint8
)getintvar(pvars
, "boardrev") <= 0x71)) ||
630 ((uint32
)getintvar(pvars
, "boardflags2") & BFL2_PCIEWAR_OVR
)) {
631 pi
->pcie_war_aspm_ovr
= PCIE_ASPM_DISAB
;
633 pi
->pcie_war_aspm_ovr
= PCIE_ASPM_ENAB
;
637 /* These need to happen in this order only */
638 pcie_war_polarity(pi
);
642 pcie_war_aspm_clkreq(pi
);
644 pcie_clkreq_upd(pi
, state
);
646 /* Default setting for increasing the TX drive strength */
647 if ((sih
->boardvendor
== VENDOR_APPLE
) &&
648 (sih
->boardtype
== 0x8d))
649 pcicore_pcieserdesreg(pch
, MDIO_DEV_TXCTRL0
, 0x18, 0xff, 0x7f);
654 pcicore_hwup(void *pch
)
656 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
658 if (!pi
|| !PCIE(pi
->sih
))
661 if (pi
->sih
->boardtype
== CB2_4321_BOARD
|| pi
->sih
->boardtype
== CB2_4321_AG_BOARD
)
662 pcicore_fixlatencytimer(pch
, 0x20);
664 pcie_war_pci_setup(pi
);
666 /* Default setting for increasing the TX drive strength */
667 if ((pi
->sih
->boardvendor
== VENDOR_APPLE
) &&
668 (pi
->sih
->boardtype
== 0x8d))
669 pcicore_pcieserdesreg(pch
, MDIO_DEV_TXCTRL0
, 0x18, 0xff, 0x7f);
673 pcicore_up(void *pch
, int state
)
675 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
677 if (!pi
|| !PCIE(pi
->sih
))
680 /* Restore L1 timer for better performance */
681 pcie_extendL1timer(pi
, TRUE
);
683 pcie_clkreq_upd(pi
, state
);
686 /* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */
688 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
, sizeof(uint32
));
697 w
&= ~PCIE_CAP_LCREG_ASPML1
;
698 OSL_PCI_WRITE_CONFIG(pi
->osh
, pi
->pciecap_lcreg_offset
, sizeof(uint32
), w
);
700 pi
->pcie_pr42767
= FALSE
;
704 pcicore_down(void *pch
, int state
)
706 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
708 if (!pi
|| !PCIE(pi
->sih
))
711 pcie_clkreq_upd(pi
, state
);
713 /* Reduce L1 timer for better power savings */
714 pcie_extendL1timer(pi
, FALSE
);
717 /* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
718 /* Just uses PCI config accesses to find out, when needed before sb_attach is done */
720 pcicore_pmecap_fast(osl_t
*osh
)
725 cap_ptr
= pcicore_find_pci_capability(osh
, PCI_CAP_POWERMGMTCAP_ID
, NULL
, NULL
);
730 pmecap
= OSL_PCI_READ_CONFIG(osh
, cap_ptr
, sizeof(uint32
));
732 return ((pmecap
& PME_CAP_PM_STATES
) != 0);
735 /* return TRUE if PM capability exists in the pci config space
736 * Uses and caches the information using core handle
739 pcicore_pmecap(pcicore_info_t
*pi
)
744 if (!pi
->pmecap_offset
) {
745 cap_ptr
= pcicore_find_pci_capability(pi
->osh
, PCI_CAP_POWERMGMTCAP_ID
, NULL
, NULL
);
749 pi
->pmecap_offset
= cap_ptr
;
751 pmecap
= OSL_PCI_READ_CONFIG(pi
->osh
, pi
->pmecap_offset
, sizeof(uint32
));
753 /* At least one state can generate PME */
754 pi
->pmecap
= (pmecap
& PME_CAP_PM_STATES
) != 0;
760 /* Enable PME generation */
762 pcicore_pmeen(void *pch
)
764 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
767 /* if not pmecapable return */
768 if (!pcicore_pmecap(pi
))
771 w
= OSL_PCI_READ_CONFIG(pi
->osh
, pi
->pmecap_offset
+ PME_CSR_OFFSET
, sizeof(uint32
));
772 w
|= (PME_CSR_PME_EN
);
773 OSL_PCI_WRITE_CONFIG(pi
->osh
, pi
->pmecap_offset
+ PME_CSR_OFFSET
, sizeof(uint32
), w
);
777 * Return TRUE if PME status set
780 pcicore_pmestat(void *pch
)
782 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
785 if (!pcicore_pmecap(pi
))
788 w
= OSL_PCI_READ_CONFIG(pi
->osh
, pi
->pmecap_offset
+ PME_CSR_OFFSET
, sizeof(uint32
));
790 return (w
& PME_CSR_PME_STAT
) == PME_CSR_PME_STAT
;
793 /* Disable PME generation, clear the PME status bit if set
796 pcicore_pmeclr(void *pch
)
798 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
801 if (!pcicore_pmecap(pi
))
804 w
= OSL_PCI_READ_CONFIG(pi
->osh
, pi
->pmecap_offset
+ PME_CSR_OFFSET
, sizeof(uint32
));
806 PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w
));
808 /* PMESTAT is cleared by writing 1 to it */
809 w
&= ~(PME_CSR_PME_EN
);
811 OSL_PCI_WRITE_CONFIG(pi
->osh
, pi
->pmecap_offset
+ PME_CSR_OFFSET
, sizeof(uint32
), w
);
815 pcicore_fixlatencytimer(pcicore_info_t
* pch
, uint8 timer_val
)
817 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
818 osl_t
*osh
= pi
->osh
;
819 uint8 lattim
= read_pci_cfg_byte(PCI_CFG_LATTIM
);
822 PCI_ERROR(("%s: Modifying PCI_CFG_LATTIM from 0x%x to 0x%x\n",
823 __FUNCTION__
, lattim
, timer_val
));
824 write_pci_cfg_byte(PCI_CFG_LATTIM
, timer_val
);
829 pcie_lcreg(void *pch
, uint32 mask
, uint32 val
)
831 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
834 offset
= pi
->pciecap_lcreg_offset
;
840 OSL_PCI_WRITE_CONFIG(pi
->osh
, offset
, sizeof(uint32
), val
);
842 return OSL_PCI_READ_CONFIG(pi
->osh
, offset
, sizeof(uint32
));
848 pcicore_pcieserdesreg(void *pch
, uint32 mdioslave
, uint32 offset
, uint32 mask
, uint32 val
)
851 pcicore_info_t
*pi
= (pcicore_info_t
*)pch
;
854 PCI_ERROR(("PCIEMDIOREG: 0x%x writeval 0x%x\n", offset
, val
));
855 pcie_mdiowrite(pi
, mdioslave
, offset
, val
);
858 if (pcie_mdioread(pi
, mdioslave
, offset
, ®_val
))
859 reg_val
= 0xFFFFFFFF;
860 PCI_ERROR(("PCIEMDIOREG: dev 0x%x offset 0x%x read 0x%x\n", mdioslave
, offset
, reg_val
));