/* * Indicates the presence of external SPROM. */ static bool bcma_sprom_ext_available(struct bcma_bus *bus) { u32 chip_status; u32 srom_control; u32 present_mask; if (bus->drv_cc.core->id.rev >= 31) { if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) return false; srom_control = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL); return srom_control & BCMA_CC_SROM_CONTROL_PRESENT; } /* older chipcommon revisions use chip status register */ chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { case BCMA_CHIP_ID_BCM4313: present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT; break; case BCMA_CHIP_ID_BCM4331: present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT; break; default: return true; } return chip_status & present_mask; }
static int pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, uint *val) { uint mdiodata; uint i = 0; uint pcie_serdes_spinwait = 10; /* enable mdio access to SERDES */ bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); if (ai_get_buscorerev(pi->sih) >= 10) { /* new serdes is slower in rw, * using two layers of reg address mapping */ if (!pcie_mdiosetblock(pi, physmedia)) return 1; mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | (regaddr << MDIODATA_REGADDR_SHF)); pcie_serdes_spinwait *= 20; } else { mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) | (regaddr << MDIODATA_REGADDR_SHF_OLD)); } if (!write) mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); else mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val); bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); pr28829_delay(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & MDIOCTL_ACCESS_DONE) { if (!write) { pr28829_delay(); *val = (bcma_read32(pi->core, PCIEREGOFFS(mdiodata)) & MDIODATA_MASK); } /* Disable mdio access to SERDES */ bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 0; } udelay(1000); i++; } /* Timed out. Disable mdio access to SERDES. */ bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 1; }
static int pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, uint *val) { uint mdiodata; uint i = 0; uint pcie_serdes_spinwait = 10; bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); if (ai_get_buscorerev(pi->sih) >= 10) { if (!pcie_mdiosetblock(pi, physmedia)) return 1; mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | (regaddr << MDIODATA_REGADDR_SHF)); pcie_serdes_spinwait *= 20; } else { mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) | (regaddr << MDIODATA_REGADDR_SHF_OLD)); } if (!write) mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); else mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | *val); bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); pr28829_delay(); while (i < pcie_serdes_spinwait) { if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & MDIOCTL_ACCESS_DONE) { if (!write) { pr28829_delay(); *val = (bcma_read32(pi->core, PCIEREGOFFS(mdiodata)) & MDIODATA_MASK); } bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 0; } udelay(1000); i++; } bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); return 1; }
/* * Verify OTP is filled and determine the byte * offset where SPROM data is located. * * On error, returns 0; byte offset otherwise. */ static int bcma_sprom_onchip_offset(struct bcma_bus *bus) { struct bcma_device *cc = bus->drv_cc.core; u32 offset; /* verify OTP status */ if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0) return 0; /* obtain bit offset from otplayout register */ offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET); return BCMA_CC_SPROM + (offset >> 3); }
static u16 bcma_mdio_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg) { struct bcma_device *core; u16 phy_access_addr; u16 phy_ctl_addr; u32 tmp; BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK); BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK); BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT); BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK); BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT); BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE); BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START); BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK); BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK); BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT); BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE); if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) { core = bgmac->bcma.core->bus->drv_gmac_cmn.core; phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS; phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL; } else { core = bgmac->bcma.core; phy_access_addr = BGMAC_PHY_ACCESS; phy_ctl_addr = BGMAC_PHY_CNTL; } tmp = bcma_read32(core, phy_ctl_addr); tmp &= ~BGMAC_PC_EPA_MASK; tmp |= phyaddr; bcma_write32(core, phy_ctl_addr, tmp); tmp = BGMAC_PA_START; tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT; tmp |= reg << BGMAC_PA_REG_SHIFT; bcma_write32(core, phy_access_addr, tmp); if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) { dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n", phyaddr, reg); return 0xffff; } return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK; }
u32 si_pmu_measure_alpclk(struct si_pub *sih) { struct si_info *sii = container_of(sih, struct si_info, pub); struct bcma_device *core; u32 alp_khz; if (ai_get_pmurev(sih) < 10) return 0; /* Remember original core before switch to chipc */ core = sii->icbus->drv_cc.core; if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { u32 ilp_ctr, alp_hz; /* * Enable the reg to measure the freq, * in case it was disabled before */ bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); /* Delay for well over 4 ILP clocks */ udelay(1000); /* Read the latched number of ALP ticks per 4 ILP ticks */ ilp_ctr = bcma_read32(core, CHIPCREGOFFS(pmu_xtalfreq)) & PMU_XTALFREQ_REG_ILPCTR_MASK; /* * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT * bit to save power */ bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), 0); /* Calculate ALP frequency */ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; /* * Round to nearest 100KHz, and at * the same time convert to KHz */ alp_khz = (alp_hz + 50000) / 100000 * 100; } else alp_khz = 0; return alp_khz; }
void bcma_core_set_clockmode(struct bcma_device *core, enum bcma_clkmode clkmode) { u16 i; WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON && core->id.id != BCMA_CORE_PCIE && core->id.id != BCMA_CORE_80211); switch (clkmode) { case BCMA_CLKMODE_FAST: bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT); udelay(64); for (i = 0; i < 1500; i++) { if (bcma_read32(core, BCMA_CLKCTLST) & BCMA_CLKCTLST_HAVEHT) { i = 0; break; } udelay(10); } if (i) pr_err("HT force timeout\n"); break; case BCMA_CLKMODE_DYNAMIC: bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); break; } }
static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) { uint mdiodata, i = 0; uint pcie_serdes_spinwait = 200; mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | (blk << 4)); bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); pr28829_delay(); /* retry till the transaction is complete */ while (i < pcie_serdes_spinwait) { if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & MDIOCTL_ACCESS_DONE) break; udelay(1000); i++; } if (i >= pcie_serdes_spinwait) return false; return true; }
static void bcma_hcd_4716wa(struct bcma_device *dev) { #ifdef CONFIG_BCMA_DRIVER_MIPS /* Work around for 4716 failures. */ if (dev->bus->chipinfo.id == 0x4716) { u32 tmp; tmp = bcma_cpu_clock(&dev->bus->drv_mips); if (tmp >= 480000000) tmp = 0x1846b; /* set CDR to 0x11(fast) */ else if (tmp == 453000000) tmp = 0x1046b; /* set CDR to 0x10(slow) */ else tmp = 0; /* Change Shim mdio control reg to fix host not acking at * high frequencies */ if (tmp) { bcma_write32(dev, 0x524, 0x1); /* write sel to enable */ udelay(500); bcma_write32(dev, 0x524, tmp); udelay(500); bcma_write32(dev, 0x524, 0x4ab); udelay(500); bcma_read32(dev, 0x528); bcma_write32(dev, 0x528, 0x80000000); } } #endif /* CONFIG_BCMA_DRIVER_MIPS */ }
u32 si_pmu_measure_alpclk(struct si_pub *sih) { struct bcma_device *core; u32 alp_khz; if (ai_get_pmurev(sih) < 10) return 0; /* */ core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { u32 ilp_ctr, alp_hz; /* */ bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); /* */ udelay(1000); /* */ ilp_ctr = bcma_read32(core, CHIPCREGOFFS(pmu_xtalfreq)) & PMU_XTALFREQ_REG_ILPCTR_MASK; /* */ bcma_write32(core, CHIPCREGOFFS(pmu_xtalfreq), 0); /* */ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; /* */ alp_khz = (alp_hz + 50000) / 100000 * 100; } else alp_khz = 0; return alp_khz; }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */ static int bcma_mdio_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value) { struct bcma_device *core; u16 phy_access_addr; u16 phy_ctl_addr; u32 tmp; if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) { core = bgmac->bcma.core->bus->drv_gmac_cmn.core; phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS; phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL; } else { core = bgmac->bcma.core; phy_access_addr = BGMAC_PHY_ACCESS; phy_ctl_addr = BGMAC_PHY_CNTL; } tmp = bcma_read32(core, phy_ctl_addr); tmp &= ~BGMAC_PC_EPA_MASK; tmp |= phyaddr; bcma_write32(core, phy_ctl_addr, tmp); bcma_write32(bgmac->bcma.core, BGMAC_INT_STATUS, BGMAC_IS_MDIO); if (bcma_read32(bgmac->bcma.core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO) dev_warn(&core->dev, "Error setting MDIO int\n"); tmp = BGMAC_PA_START; tmp |= BGMAC_PA_WRITE; tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT; tmp |= reg << BGMAC_PA_REG_SHIFT; tmp |= value; bcma_write32(core, phy_access_addr, tmp); if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) { dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n", phyaddr, reg); return -ETIMEDOUT; } return 0; }
static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev) { u32 val; /* * Delay after PHY initialized to ensure HC is ready to be configured */ usleep_range(1000, 2000); /* Set packet buffer OUT threshold */ val = bcma_read32(dev, 0x94); val &= 0xffff; val |= 0x80 << 16; bcma_write32(dev, 0x94, val); /* Enable break memory transfer */ val = bcma_read32(dev, 0x9c); val |= 1; bcma_write32(dev, 0x9c, val); }
/* ***** Register Access API */ static uint pcie_readreg(struct bcma_device *core, uint addrtype, uint offset) { uint retval = 0xFFFFFFFF; switch (addrtype) { case PCIE_CONFIGREGS: bcma_write32(core, PCIEREGOFFS(configaddr), offset); (void)bcma_read32(core, PCIEREGOFFS(configaddr)); retval = bcma_read32(core, PCIEREGOFFS(configdata)); break; case PCIE_PCIEREGS: bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset); (void)bcma_read32(core, PCIEREGOFFS(pcieindaddr)); retval = bcma_read32(core, PCIEREGOFFS(pcieinddata)); break; } return retval; }
static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, int timeout) { u32 val; int i; for (i = 0; i < timeout / 10; i++) { val = bcma_read32(core, reg); if ((val & mask) == value) return true; udelay(10); } pr_err("Timeout waiting for reg 0x%X\n", reg); return false; }
/* Wait for bitmask in a register to get set or cleared. * timeout is in units of ten-microseconds. */ static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask, int timeout) { int i; u32 val; for (i = 0; i < timeout; i++) { val = bcma_read32(dev, reg); if ((val & bitmask) == bitmask) return 0; udelay(10); } return -ETIMEDOUT; }
/* * Indicates that on-chip OTP memory is present and enabled. */ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) { u32 chip_status; u32 otpsize = 0; bool present; chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { case BCMA_CHIP_ID_BCM4313: present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT; break; case BCMA_CHIP_ID_BCM4331: present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; break; case BCMA_CHIP_ID_BCM43142: case BCMA_CHIP_ID_BCM43224: case BCMA_CHIP_ID_BCM43225: /* for these chips OTP is always available */ present = true; break; case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: case BCMA_CHIP_ID_BCM43428: present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT; break; default: present = false; break; } if (present) { otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS; otpsize >>= BCMA_CC_CAP_OTPS_SHIFT; } return otpsize != 0; }
void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on) { u16 i; WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ); WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST); if (on) { bcma_set32(core, BCMA_CLKCTLST, req); for (i = 0; i < 10000; i++) { if ((bcma_read32(core, BCMA_CLKCTLST) & status) == status) { i = 0; break; } udelay(10); } if (i) pr_err("PLL enable timeout\n"); } else { pr_warn("Disabling PLL not supported yet!\n"); } }
static u32 bcma_bgmac_read(struct bgmac *bgmac, u16 offset) { return bcma_read32(bgmac->bcma.core, offset); }
static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) { return bcma_read32(b53spi->core, offset); }
static u32 b43_bus_bcma_read32(struct b43_bus_dev *dev, u16 offset) { return bcma_read32(dev->bdev, offset); }
/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ static void bcma_hcd_init_chip_mips(struct bcma_device *dev) { u32 tmp; /* * USB 2.0 special considerations: * * 1. Since the core supports both OHCI and EHCI functions, it must * only be reset once. * * 2. In addition to the standard SI reset sequence, the Host Control * Register must be programmed to bring the USB core and various * phy components out of reset. */ if (!bcma_core_is_enabled(dev)) { bcma_core_enable(dev, 0); mdelay(10); if (dev->id.rev >= 5) { /* Enable Misc PLL */ tmp = bcma_read32(dev, 0x1e0); tmp |= 0x100; bcma_write32(dev, 0x1e0, tmp); if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100)) printk(KERN_EMERG "Failed to enable misc PPL!\n"); /* Take out of resets */ bcma_write32(dev, 0x200, 0x4ff); udelay(25); bcma_write32(dev, 0x200, 0x6ff); udelay(25); /* Make sure digital and AFE are locked in USB PHY */ bcma_write32(dev, 0x524, 0x6b); udelay(50); tmp = bcma_read32(dev, 0x524); udelay(50); bcma_write32(dev, 0x524, 0xab); udelay(50); tmp = bcma_read32(dev, 0x524); udelay(50); bcma_write32(dev, 0x524, 0x2b); udelay(50); tmp = bcma_read32(dev, 0x524); udelay(50); bcma_write32(dev, 0x524, 0x10ab); udelay(50); tmp = bcma_read32(dev, 0x524); if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) { tmp = bcma_read32(dev, 0x528); printk(KERN_EMERG "USB20H mdio_rddata 0x%08x\n", tmp); } bcma_write32(dev, 0x528, 0x80000000); tmp = bcma_read32(dev, 0x314); udelay(265); bcma_write32(dev, 0x200, 0x7ff); udelay(10); /* Take USB and HSIC out of non-driving modes */ bcma_write32(dev, 0x510, 0); } else { bcma_write32(dev, 0x200, 0x7ff); udelay(1); } bcma_hcd_4716wa(dev); } }