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