]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/brcm80211/brcmsmac/nicpci.c
51d56b6b63d560cfb3378aed905271e0c88dde7f
[mv-sheeva.git] / drivers / staging / brcm80211 / brcmsmac / nicpci.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
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.
7  *
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.
15  */
16
17 #include <linux/delay.h>
18 #include <linux/string.h>
19 #include <linux/pci.h>
20 #include <bcmdefs.h>
21 #include <bcmutils.h>
22 #include <bcmnvram.h>
23 #include <aiutils.h>
24 #include <bcmsoc.h>
25 #include <bcmdevs.h>
26 #include <sbchipc.h>
27 #include <pci_core.h>
28 #include <pcie_core.h>
29 #include <nicpci.h>
30 #include <pcicfg.h>
31
32 typedef struct {
33         union {
34                 sbpcieregs_t *pcieregs;
35                 struct sbpciregs *pciregs;
36         } regs;                 /* Memory mapped register to the core */
37
38         si_t *sih;              /* System interconnect handle */
39         struct pci_dev *dev;
40         u8 pciecap_lcreg_offset;        /* PCIE capability LCreg offset in the config space */
41         bool pcie_pr42767;
42         u8 pcie_polarity;
43         u8 pcie_war_aspm_ovr;   /* Override ASPM/Clkreq settings */
44
45         u8 pmecap_offset;       /* PM Capability offset in the config space */
46         bool pmecap;            /* Capable of generating PME */
47 } pcicore_info_t;
48
49 /* debug/trace */
50 #define PCI_ERROR(args)
51 #define PCIE_PUB(sih) \
52         (((sih)->bustype == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
53
54 /* routines to access mdio slave device registers */
55 static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk);
56 static int pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr,
57                        bool write, uint *val);
58 static int pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint readdr,
59                           uint val);
60 static int pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint readdr,
61                          uint *ret_val);
62
63 static void pcie_extendL1timer(pcicore_info_t *pi, bool extend);
64 static void pcie_clkreq_upd(pcicore_info_t *pi, uint state);
65
66 static void pcie_war_aspm_clkreq(pcicore_info_t *pi);
67 static void pcie_war_serdes(pcicore_info_t *pi);
68 static void pcie_war_noplldown(pcicore_info_t *pi);
69 static void pcie_war_polarity(pcicore_info_t *pi);
70 static void pcie_war_pci_setup(pcicore_info_t *pi);
71
72 static bool pcicore_pmecap(pcicore_info_t *pi);
73
74 #define PCIE_ASPM(sih)  ((PCIE_PUB(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
75
76
77 /* delay needed between the mdio control/ mdiodata register data access */
78 #define PR28829_DELAY() udelay(10)
79
80 /* Initialize the PCI core. It's caller's responsibility to make sure that this is done
81  * only once
82  */
83 void *pcicore_init(si_t *sih, void *pdev, void *regs)
84 {
85         pcicore_info_t *pi;
86
87         /* alloc pcicore_info_t */
88         pi = kzalloc(sizeof(pcicore_info_t), GFP_ATOMIC);
89         if (pi == NULL) {
90                 PCI_ERROR(("pci_attach: malloc failed!\n"));
91                 return NULL;
92         }
93
94         pi->sih = sih;
95         pi->dev = pdev;
96
97         if (sih->buscoretype == PCIE_CORE_ID) {
98                 u8 cap_ptr;
99                 pi->regs.pcieregs = (sbpcieregs_t *) regs;
100                 cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP,
101                                                       NULL, NULL);
102                 pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
103         } else
104                 pi->regs.pciregs = (struct sbpciregs *) regs;
105
106         return pi;
107 }
108
109 void pcicore_deinit(void *pch)
110 {
111         pcicore_info_t *pi = (pcicore_info_t *) pch;
112
113         if (pi == NULL)
114                 return;
115         kfree(pi);
116 }
117
118 /* return cap_offset if requested capability exists in the PCI config space */
119 /* Note that it's caller's responsibility to make sure it's a pci bus */
120 u8
121 pcicore_find_pci_capability(void *dev, u8 req_cap_id,
122                             unsigned char *buf, u32 *buflen)
123 {
124         u8 cap_id;
125         u8 cap_ptr = 0;
126         u32 bufsize;
127         u8 byte_val;
128
129         /* check for Header type 0 */
130         pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val);
131         if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
132                 goto end;
133
134         /* check if the capability pointer field exists */
135         pci_read_config_byte(dev, PCI_STATUS, &byte_val);
136         if (!(byte_val & PCI_STATUS_CAP_LIST))
137                 goto end;
138
139         pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
140         /* check if the capability pointer is 0x00 */
141         if (cap_ptr == 0x00)
142                 goto end;
143
144         /* loop thr'u the capability list and see if the pcie capabilty exists */
145
146         pci_read_config_byte(dev, cap_ptr, &cap_id);
147
148         while (cap_id != req_cap_id) {
149                 pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr);
150                 if (cap_ptr == 0x00)
151                         break;
152                 pci_read_config_byte(dev, cap_ptr, &cap_id);
153         }
154         if (cap_id != req_cap_id) {
155                 goto end;
156         }
157         /* found the caller requested capability */
158         if ((buf != NULL) && (buflen != NULL)) {
159                 u8 cap_data;
160
161                 bufsize = *buflen;
162                 if (!bufsize)
163                         goto end;
164                 *buflen = 0;
165                 /* copy the cpability data excluding cap ID and next ptr */
166                 cap_data = cap_ptr + 2;
167                 if ((bufsize + cap_data) > PCI_SZPCR)
168                         bufsize = PCI_SZPCR - cap_data;
169                 *buflen = bufsize;
170                 while (bufsize--) {
171                         pci_read_config_byte(dev, cap_data, buf);
172                         cap_data++;
173                         buf++;
174                 }
175         }
176  end:
177         return cap_ptr;
178 }
179
180 /* ***** Register Access API */
181 uint
182 pcie_readreg(sbpcieregs_t *pcieregs, uint addrtype,
183              uint offset)
184 {
185         uint retval = 0xFFFFFFFF;
186
187         switch (addrtype) {
188         case PCIE_CONFIGREGS:
189                 W_REG((&pcieregs->configaddr), offset);
190                 (void)R_REG((&pcieregs->configaddr));
191                 retval = R_REG(&(pcieregs->configdata));
192                 break;
193         case PCIE_PCIEREGS:
194                 W_REG(&(pcieregs->pcieindaddr), offset);
195                 (void)R_REG((&pcieregs->pcieindaddr));
196                 retval = R_REG(&(pcieregs->pcieinddata));
197                 break;
198         default:
199                 break;
200         }
201
202         return retval;
203 }
204
205 uint
206 pcie_writereg(sbpcieregs_t *pcieregs, uint addrtype,
207               uint offset, uint val)
208 {
209         switch (addrtype) {
210         case PCIE_CONFIGREGS:
211                 W_REG((&pcieregs->configaddr), offset);
212                 W_REG((&pcieregs->configdata), val);
213                 break;
214         case PCIE_PCIEREGS:
215                 W_REG((&pcieregs->pcieindaddr), offset);
216                 W_REG((&pcieregs->pcieinddata), val);
217                 break;
218         default:
219                 break;
220         }
221         return 0;
222 }
223
224 static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk)
225 {
226         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
227         uint mdiodata, i = 0;
228         uint pcie_serdes_spinwait = 200;
229
230         mdiodata =
231             MDIODATA_START | MDIODATA_WRITE | (MDIODATA_DEV_ADDR <<
232                                                MDIODATA_DEVADDR_SHF) |
233             (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | MDIODATA_TA | (blk <<
234                                                                          4);
235         W_REG(&pcieregs->mdiodata, mdiodata);
236
237         PR28829_DELAY();
238         /* retry till the transaction is complete */
239         while (i < pcie_serdes_spinwait) {
240                 if (R_REG(&(pcieregs->mdiocontrol)) &
241                     MDIOCTL_ACCESS_DONE) {
242                         break;
243                 }
244                 udelay(1000);
245                 i++;
246         }
247
248         if (i >= pcie_serdes_spinwait) {
249                 PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
250                 return false;
251         }
252
253         return true;
254 }
255
256 static int
257 pcie_mdioop(pcicore_info_t *pi, uint physmedia, uint regaddr, bool write,
258             uint *val)
259 {
260         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
261         uint mdiodata;
262         uint i = 0;
263         uint pcie_serdes_spinwait = 10;
264
265         /* enable mdio access to SERDES */
266         W_REG((&pcieregs->mdiocontrol),
267               MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
268
269         if (pi->sih->buscorerev >= 10) {
270                 /* new serdes is slower in rw, using two layers of reg address mapping */
271                 if (!pcie_mdiosetblock(pi, physmedia))
272                         return 1;
273                 mdiodata = (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
274                     (regaddr << MDIODATA_REGADDR_SHF);
275                 pcie_serdes_spinwait *= 20;
276         } else {
277                 mdiodata = (physmedia << MDIODATA_DEVADDR_SHF_OLD) |
278                     (regaddr << MDIODATA_REGADDR_SHF_OLD);
279         }
280
281         if (!write)
282                 mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
283         else
284                 mdiodata |=
285                     (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val);
286
287         W_REG(&pcieregs->mdiodata, mdiodata);
288
289         PR28829_DELAY();
290
291         /* retry till the transaction is complete */
292         while (i < pcie_serdes_spinwait) {
293                 if (R_REG(&(pcieregs->mdiocontrol)) &
294                     MDIOCTL_ACCESS_DONE) {
295                         if (!write) {
296                                 PR28829_DELAY();
297                                 *val =
298                                     (R_REG(&(pcieregs->mdiodata)) &
299                                      MDIODATA_MASK);
300                         }
301                         /* Disable mdio access to SERDES */
302                         W_REG((&pcieregs->mdiocontrol), 0);
303                         return 0;
304                 }
305                 udelay(1000);
306                 i++;
307         }
308
309         PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write));
310         /* Disable mdio access to SERDES */
311         W_REG((&pcieregs->mdiocontrol), 0);
312         return 1;
313 }
314
315 /* use the mdio interface to read from mdio slaves */
316 static int
317 pcie_mdioread(pcicore_info_t *pi, uint physmedia, uint regaddr, uint *regval)
318 {
319         return pcie_mdioop(pi, physmedia, regaddr, false, regval);
320 }
321
322 /* use the mdio interface to write to mdio slaves */
323 static int
324 pcie_mdiowrite(pcicore_info_t *pi, uint physmedia, uint regaddr, uint val)
325 {
326         return pcie_mdioop(pi, physmedia, regaddr, true, &val);
327 }
328
329 /* ***** Support functions ***** */
330 u8 pcie_clkreq(void *pch, u32 mask, u32 val)
331 {
332         pcicore_info_t *pi = (pcicore_info_t *) pch;
333         u32 reg_val;
334         u8 offset;
335
336         offset = pi->pciecap_lcreg_offset;
337         if (!offset)
338                 return 0;
339
340         pci_read_config_dword(pi->dev, offset, &reg_val);
341         /* set operation */
342         if (mask) {
343                 if (val)
344                         reg_val |= PCIE_CLKREQ_ENAB;
345                 else
346                         reg_val &= ~PCIE_CLKREQ_ENAB;
347                 pci_write_config_dword(pi->dev, offset, reg_val);
348                 pci_read_config_dword(pi->dev, offset, &reg_val);
349         }
350         if (reg_val & PCIE_CLKREQ_ENAB)
351                 return 1;
352         else
353                 return 0;
354 }
355
356 static void pcie_extendL1timer(pcicore_info_t *pi, bool extend)
357 {
358         u32 w;
359         si_t *sih = pi->sih;
360         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
361
362         if (!PCIE_PUB(sih) || sih->buscorerev < 7)
363                 return;
364
365         w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
366         if (extend)
367                 w |= PCIE_ASPMTIMER_EXTEND;
368         else
369                 w &= ~PCIE_ASPMTIMER_EXTEND;
370         pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
371         w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
372 }
373
374 /* centralized clkreq control policy */
375 static void pcie_clkreq_upd(pcicore_info_t *pi, uint state)
376 {
377         si_t *sih = pi->sih;
378
379         switch (state) {
380         case SI_DOATTACH:
381                 if (PCIE_ASPM(sih))
382                         pcie_clkreq((void *)pi, 1, 0);
383                 break;
384         case SI_PCIDOWN:
385                 if (sih->buscorerev == 6) {     /* turn on serdes PLL down */
386                         ai_corereg(sih, SI_CC_IDX,
387                                    offsetof(chipcregs_t, chipcontrol_addr), ~0,
388                                    0);
389                         ai_corereg(sih, SI_CC_IDX,
390                                    offsetof(chipcregs_t, chipcontrol_data),
391                                    ~0x40, 0);
392                 } else if (pi->pcie_pr42767) {
393                         pcie_clkreq((void *)pi, 1, 1);
394                 }
395                 break;
396         case SI_PCIUP:
397                 if (sih->buscorerev == 6) {     /* turn off serdes PLL down */
398                         ai_corereg(sih, SI_CC_IDX,
399                                    offsetof(chipcregs_t, chipcontrol_addr), ~0,
400                                    0);
401                         ai_corereg(sih, SI_CC_IDX,
402                                    offsetof(chipcregs_t, chipcontrol_data),
403                                    ~0x40, 0x40);
404                 } else if (PCIE_ASPM(sih)) {    /* disable clkreq */
405                         pcie_clkreq((void *)pi, 1, 0);
406                 }
407                 break;
408         default:
409                 break;
410         }
411 }
412
413 /* ***** PCI core WARs ***** */
414 /* Done only once at attach time */
415 static void pcie_war_polarity(pcicore_info_t *pi)
416 {
417         u32 w;
418
419         if (pi->pcie_polarity != 0)
420                 return;
421
422         w = pcie_readreg(pi->regs.pcieregs, PCIE_PCIEREGS,
423                          PCIE_PLP_STATUSREG);
424
425         /* Detect the current polarity at attach and force that polarity and
426          * disable changing the polarity
427          */
428         if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
429                 pi->pcie_polarity = (SERDES_RX_CTRL_FORCE);
430         else
431                 pi->pcie_polarity =
432                     (SERDES_RX_CTRL_FORCE | SERDES_RX_CTRL_POLARITY);
433 }
434
435 /* enable ASPM and CLKREQ if srom doesn't have it */
436 /* Needs to happen when update to shadow SROM is needed
437  *   : Coming out of 'standby'/'hibernate'
438  *   : If pcie_war_aspm_ovr state changed
439  */
440 static void pcie_war_aspm_clkreq(pcicore_info_t *pi)
441 {
442         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
443         si_t *sih = pi->sih;
444         u16 val16, *reg16;
445         u32 w;
446
447         if (!PCIE_ASPM(sih))
448                 return;
449
450         /* bypass this on QT or VSIM */
451         if (!ISSIM_ENAB(sih)) {
452
453                 reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET];
454                 val16 = R_REG(reg16);
455
456                 val16 &= ~SRSH_ASPM_ENB;
457                 if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
458                         val16 |= SRSH_ASPM_ENB;
459                 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
460                         val16 |= SRSH_ASPM_L1_ENB;
461                 else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
462                         val16 |= SRSH_ASPM_L0s_ENB;
463
464                 W_REG(reg16, val16);
465
466                 pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset,
467                                         &w);
468                 w &= ~PCIE_ASPM_ENAB;
469                 w |= pi->pcie_war_aspm_ovr;
470                 pci_write_config_dword(pi->dev,
471                                         pi->pciecap_lcreg_offset, w);
472         }
473
474         reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
475         val16 = R_REG(reg16);
476
477         if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
478                 val16 |= SRSH_CLKREQ_ENB;
479                 pi->pcie_pr42767 = true;
480         } else
481                 val16 &= ~SRSH_CLKREQ_ENB;
482
483         W_REG(reg16, val16);
484 }
485
486 /* Apply the polarity determined at the start */
487 /* Needs to happen when coming out of 'standby'/'hibernate' */
488 static void pcie_war_serdes(pcicore_info_t *pi)
489 {
490         u32 w = 0;
491
492         if (pi->pcie_polarity != 0)
493                 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
494                                pi->pcie_polarity);
495
496         pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
497         if (w & PLL_CTRL_FREQDET_EN) {
498                 w &= ~PLL_CTRL_FREQDET_EN;
499                 pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
500         }
501 }
502
503 /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
504 /* Needs to happen when coming out of 'standby'/'hibernate' */
505 static void pcie_misc_config_fixup(pcicore_info_t *pi)
506 {
507         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
508         u16 val16, *reg16;
509
510         reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
511         val16 = R_REG(reg16);
512
513         if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
514                 val16 |= SRSH_L23READY_EXIT_NOPERST;
515                 W_REG(reg16, val16);
516         }
517 }
518
519 /* quick hack for testing */
520 /* Needs to happen when coming out of 'standby'/'hibernate' */
521 static void pcie_war_noplldown(pcicore_info_t *pi)
522 {
523         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
524         u16 *reg16;
525
526         /* turn off serdes PLL down */
527         ai_corereg(pi->sih, SI_CC_IDX, offsetof(chipcregs_t, chipcontrol),
528                    CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
529
530         /*  clear srom shadow backdoor */
531         reg16 = &pcieregs->sprom[SRSH_BD_OFFSET];
532         W_REG(reg16, 0);
533 }
534
535 /* Needs to happen when coming out of 'standby'/'hibernate' */
536 static void pcie_war_pci_setup(pcicore_info_t *pi)
537 {
538         si_t *sih = pi->sih;
539         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
540         u32 w;
541
542         if ((sih->buscorerev == 0) || (sih->buscorerev == 1)) {
543                 w = pcie_readreg(pcieregs, PCIE_PCIEREGS,
544                                  PCIE_TLP_WORKAROUNDSREG);
545                 w |= 0x8;
546                 pcie_writereg(pcieregs, PCIE_PCIEREGS,
547                               PCIE_TLP_WORKAROUNDSREG, w);
548         }
549
550         if (sih->buscorerev == 1) {
551                 w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
552                 w |= (0x40);
553                 pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
554         }
555
556         if (sih->buscorerev == 0) {
557                 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
558                 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
559                 pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
560         } else if (PCIE_ASPM(sih)) {
561                 /* Change the L1 threshold for better performance */
562                 w = pcie_readreg(pcieregs, PCIE_PCIEREGS,
563                                  PCIE_DLLP_PMTHRESHREG);
564                 w &= ~(PCIE_L1THRESHOLDTIME_MASK);
565                 w |= (PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT);
566                 pcie_writereg(pcieregs, PCIE_PCIEREGS,
567                               PCIE_DLLP_PMTHRESHREG, w);
568
569                 pcie_war_serdes(pi);
570
571                 pcie_war_aspm_clkreq(pi);
572         } else if (pi->sih->buscorerev == 7)
573                 pcie_war_noplldown(pi);
574
575         /* Note that the fix is actually in the SROM, that's why this is open-ended */
576         if (pi->sih->buscorerev >= 6)
577                 pcie_misc_config_fixup(pi);
578 }
579
580 void pcie_war_ovr_aspm_update(void *pch, u8 aspm)
581 {
582         pcicore_info_t *pi = (pcicore_info_t *) pch;
583
584         if (!PCIE_ASPM(pi->sih))
585                 return;
586
587         /* Validate */
588         if (aspm > PCIE_ASPM_ENAB)
589                 return;
590
591         pi->pcie_war_aspm_ovr = aspm;
592
593         /* Update the current state */
594         pcie_war_aspm_clkreq(pi);
595 }
596
597 /* ***** Functions called during driver state changes ***** */
598 void pcicore_attach(void *pch, char *pvars, int state)
599 {
600         pcicore_info_t *pi = (pcicore_info_t *) pch;
601         si_t *sih = pi->sih;
602
603         /* Determine if this board needs override */
604         if (PCIE_ASPM(sih)) {
605                 if ((u32) getintvar(pvars, "boardflags2") & BFL2_PCIEWAR_OVR) {
606                         pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
607                 } else {
608                         pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
609                 }
610         }
611
612         /* These need to happen in this order only */
613         pcie_war_polarity(pi);
614
615         pcie_war_serdes(pi);
616
617         pcie_war_aspm_clkreq(pi);
618
619         pcie_clkreq_upd(pi, state);
620
621 }
622
623 void pcicore_hwup(void *pch)
624 {
625         pcicore_info_t *pi = (pcicore_info_t *) pch;
626
627         if (!pi || !PCIE_PUB(pi->sih))
628                 return;
629
630         pcie_war_pci_setup(pi);
631 }
632
633 void pcicore_up(void *pch, int state)
634 {
635         pcicore_info_t *pi = (pcicore_info_t *) pch;
636
637         if (!pi || !PCIE_PUB(pi->sih))
638                 return;
639
640         /* Restore L1 timer for better performance */
641         pcie_extendL1timer(pi, true);
642
643         pcie_clkreq_upd(pi, state);
644 }
645
646 /* When the device is going to enter D3 state (or the system is going to enter S3/S4 states */
647 void pcicore_sleep(void *pch)
648 {
649         pcicore_info_t *pi = (pcicore_info_t *) pch;
650         u32 w;
651
652         if (!pi || !PCIE_ASPM(pi->sih))
653                 return;
654
655         pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
656         w &= ~PCIE_CAP_LCREG_ASPML1;
657         pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
658
659         pi->pcie_pr42767 = false;
660 }
661
662 void pcicore_down(void *pch, int state)
663 {
664         pcicore_info_t *pi = (pcicore_info_t *) pch;
665
666         if (!pi || !PCIE_PUB(pi->sih))
667                 return;
668
669         pcie_clkreq_upd(pi, state);
670
671         /* Reduce L1 timer for better power savings */
672         pcie_extendL1timer(pi, false);
673 }
674
675 /* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
676 /* Just uses PCI config accesses to find out, when needed before sb_attach is done */
677 bool pcicore_pmecap_fast(void *pch)
678 {
679         pcicore_info_t *pi = (pcicore_info_t *) pch;
680         u8 cap_ptr;
681         u32 pmecap;
682
683         cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_PM, NULL,
684                                               NULL);
685
686         if (!cap_ptr)
687                 return false;
688
689         pci_read_config_dword(pi->dev, cap_ptr, &pmecap);
690
691         return (pmecap & (PCI_PM_CAP_PME_MASK << 16)) != 0;
692 }
693
694 /* return true if PM capability exists in the pci config space
695  * Uses and caches the information using core handle
696  */
697 static bool pcicore_pmecap(pcicore_info_t *pi)
698 {
699         u8 cap_ptr;
700         u32 pmecap;
701
702         if (!pi->pmecap_offset) {
703                 cap_ptr = pcicore_find_pci_capability(pi->dev,
704                                                       PCI_CAP_ID_PM,
705                                                       NULL, NULL);
706                 if (!cap_ptr)
707                         return false;
708
709                 pi->pmecap_offset = cap_ptr;
710
711                 pci_read_config_dword(pi->dev, pi->pmecap_offset,
712                                         &pmecap);
713
714                 /* At least one state can generate PME */
715                 pi->pmecap = (pmecap & (PCI_PM_CAP_PME_MASK << 16)) != 0;
716         }
717
718         return pi->pmecap;
719 }
720
721 /* Enable PME generation */
722 void pcicore_pmeen(void *pch)
723 {
724         pcicore_info_t *pi = (pcicore_info_t *) pch;
725         u32 w;
726
727         /* if not pmecapable return */
728         if (!pcicore_pmecap(pi))
729                 return;
730
731         pci_read_config_dword(pi->dev, pi->pmecap_offset + PCI_PM_CTRL,
732                                 &w);
733         w |= (PCI_PM_CTRL_PME_ENABLE);
734         pci_write_config_dword(pi->dev,
735                                 pi->pmecap_offset + PCI_PM_CTRL, w);
736 }
737
738 /*
739  * Return true if PME status set
740  */
741 bool pcicore_pmestat(void *pch)
742 {
743         pcicore_info_t *pi = (pcicore_info_t *) pch;
744         u32 w;
745
746         if (!pcicore_pmecap(pi))
747                 return false;
748
749         pci_read_config_dword(pi->dev, pi->pmecap_offset + PCI_PM_CTRL,
750                                 &w);
751
752         return (w & PCI_PM_CTRL_PME_STATUS) == PCI_PM_CTRL_PME_STATUS;
753 }
754
755 /* Disable PME generation, clear the PME status bit if set
756  */
757 void pcicore_pmeclr(void *pch)
758 {
759         pcicore_info_t *pi = (pcicore_info_t *) pch;
760         u32 w;
761
762         if (!pcicore_pmecap(pi))
763                 return;
764
765         pci_read_config_dword(pi->dev, pi->pmecap_offset + PCI_PM_CTRL,
766                                 &w);
767
768         PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w));
769
770         /* PMESTAT is cleared by writing 1 to it */
771         w &= ~(PCI_PM_CTRL_PME_ENABLE);
772
773         pci_write_config_dword(pi->dev,
774                                 pi->pmecap_offset + PCI_PM_CTRL, w);
775 }
776
777 u32 pcie_lcreg(void *pch, u32 mask, u32 val)
778 {
779         pcicore_info_t *pi = (pcicore_info_t *) pch;
780         u8 offset;
781         u32 tmpval;
782
783         offset = pi->pciecap_lcreg_offset;
784         if (!offset)
785                 return 0;
786
787         /* set operation */
788         if (mask)
789                 pci_write_config_dword(pi->dev, offset, val);
790
791         pci_read_config_dword(pi->dev, offset, &tmpval);
792         return tmpval;
793 }
794
795 u32
796 pcicore_pciereg(void *pch, u32 offset, u32 mask, u32 val, uint type)
797 {
798         u32 reg_val = 0;
799         pcicore_info_t *pi = (pcicore_info_t *) pch;
800         sbpcieregs_t *pcieregs = pi->regs.pcieregs;
801
802         if (mask) {
803                 PCI_ERROR(("PCIEREG: 0x%x writeval  0x%x\n", offset, val));
804                 pcie_writereg(pcieregs, type, offset, val);
805         }
806
807         /* Should not read register 0x154 */
808         if (pi->sih->buscorerev <= 5 && offset == PCIE_DLLP_PCIE11
809             && type == PCIE_PCIEREGS)
810                 return reg_val;
811
812         reg_val = pcie_readreg(pcieregs, type, offset);
813         PCI_ERROR(("PCIEREG: 0x%x readval is 0x%x\n", offset, reg_val));
814
815         return reg_val;
816 }
817
818 u32
819 pcicore_pcieserdesreg(void *pch, u32 mdioslave, u32 offset, u32 mask,
820                       u32 val)
821 {
822         u32 reg_val = 0;
823         pcicore_info_t *pi = (pcicore_info_t *) pch;
824
825         if (mask) {
826                 PCI_ERROR(("PCIEMDIOREG: 0x%x writeval  0x%x\n", offset, val));
827                 pcie_mdiowrite(pi, mdioslave, offset, val);
828         }
829
830         if (pcie_mdioread(pi, mdioslave, offset, &reg_val))
831                 reg_val = 0xFFFFFFFF;
832         PCI_ERROR(("PCIEMDIOREG: dev 0x%x offset 0x%x read 0x%x\n", mdioslave,
833                    offset, reg_val));
834
835         return reg_val;
836 }