18369ae33SRafał Miłecki /* 28369ae33SRafał Miłecki * Broadcom specific AMBA 38369ae33SRafał Miłecki * PCI Core 48369ae33SRafał Miłecki * 58369ae33SRafał Miłecki * Copyright 2005, Broadcom Corporation 6eb032b98SMichael Büsch * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 72be25cacSHauke Mehrtens * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de> 88369ae33SRafał Miłecki * 98369ae33SRafał Miłecki * Licensed under the GNU/GPL. See COPYING for details. 108369ae33SRafał Miłecki */ 118369ae33SRafał Miłecki 128369ae33SRafał Miłecki #include "bcma_private.h" 1344a8e377SPaul Gortmaker #include <linux/export.h> 148369ae33SRafał Miłecki #include <linux/bcma/bcma.h> 158369ae33SRafał Miłecki 168369ae33SRafał Miłecki /************************************************** 178369ae33SRafał Miłecki * R/W ops. 188369ae33SRafał Miłecki **************************************************/ 198369ae33SRafał Miłecki 204b259a5cSHauke Mehrtens u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) 218369ae33SRafał Miłecki { 222be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address); 232be25cacSHauke Mehrtens pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR); 242be25cacSHauke Mehrtens return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA); 258369ae33SRafał Miłecki } 268369ae33SRafał Miłecki 278369ae33SRafał Miłecki #if 0 288369ae33SRafał Miłecki static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) 298369ae33SRafał Miłecki { 302be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address); 312be25cacSHauke Mehrtens pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR); 322be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data); 338369ae33SRafał Miłecki } 348369ae33SRafał Miłecki #endif 358369ae33SRafał Miłecki 368369ae33SRafał Miłecki static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) 378369ae33SRafał Miłecki { 388369ae33SRafał Miłecki u32 v; 398369ae33SRafał Miłecki int i; 408369ae33SRafał Miłecki 412be25cacSHauke Mehrtens v = BCMA_CORE_PCI_MDIODATA_START; 422be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_WRITE; 432be25cacSHauke Mehrtens v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR << 442be25cacSHauke Mehrtens BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF); 452be25cacSHauke Mehrtens v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR << 462be25cacSHauke Mehrtens BCMA_CORE_PCI_MDIODATA_REGADDR_SHF); 472be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_TA; 488369ae33SRafał Miłecki v |= (phy << 4); 492be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v); 508369ae33SRafał Miłecki 518369ae33SRafał Miłecki udelay(10); 528369ae33SRafał Miłecki for (i = 0; i < 200; i++) { 532be25cacSHauke Mehrtens v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL); 542be25cacSHauke Mehrtens if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) 558369ae33SRafał Miłecki break; 568369ae33SRafał Miłecki msleep(1); 578369ae33SRafał Miłecki } 588369ae33SRafał Miłecki } 598369ae33SRafał Miłecki 608369ae33SRafał Miłecki static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address) 618369ae33SRafał Miłecki { 628369ae33SRafał Miłecki int max_retries = 10; 638369ae33SRafał Miłecki u16 ret = 0; 648369ae33SRafał Miłecki u32 v; 658369ae33SRafał Miłecki int i; 668369ae33SRafał Miłecki 672be25cacSHauke Mehrtens /* enable mdio access to SERDES */ 682be25cacSHauke Mehrtens v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN; 692be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL; 702be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v); 718369ae33SRafał Miłecki 728369ae33SRafał Miłecki if (pc->core->id.rev >= 10) { 738369ae33SRafał Miłecki max_retries = 200; 748369ae33SRafał Miłecki bcma_pcie_mdio_set_phy(pc, device); 752be25cacSHauke Mehrtens v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR << 762be25cacSHauke Mehrtens BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF); 772be25cacSHauke Mehrtens v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF); 782be25cacSHauke Mehrtens } else { 792be25cacSHauke Mehrtens v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD); 802be25cacSHauke Mehrtens v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); 818369ae33SRafał Miłecki } 828369ae33SRafał Miłecki 832be25cacSHauke Mehrtens v = BCMA_CORE_PCI_MDIODATA_START; 842be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_READ; 852be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_TA; 862be25cacSHauke Mehrtens 872be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v); 888369ae33SRafał Miłecki /* Wait for the device to complete the transaction */ 898369ae33SRafał Miłecki udelay(10); 90f1a9c1e6SRafał Miłecki for (i = 0; i < max_retries; i++) { 912be25cacSHauke Mehrtens v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL); 922be25cacSHauke Mehrtens if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) { 938369ae33SRafał Miłecki udelay(10); 942be25cacSHauke Mehrtens ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA); 958369ae33SRafał Miłecki break; 968369ae33SRafał Miłecki } 978369ae33SRafał Miłecki msleep(1); 988369ae33SRafał Miłecki } 992be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0); 1008369ae33SRafał Miłecki return ret; 1018369ae33SRafał Miłecki } 1028369ae33SRafał Miłecki 1038369ae33SRafał Miłecki static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device, 1048369ae33SRafał Miłecki u8 address, u16 data) 1058369ae33SRafał Miłecki { 1068369ae33SRafał Miłecki int max_retries = 10; 1078369ae33SRafał Miłecki u32 v; 1088369ae33SRafał Miłecki int i; 1098369ae33SRafał Miłecki 1102be25cacSHauke Mehrtens /* enable mdio access to SERDES */ 1112be25cacSHauke Mehrtens v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN; 1122be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL; 1132be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v); 1148369ae33SRafał Miłecki 1158369ae33SRafał Miłecki if (pc->core->id.rev >= 10) { 1168369ae33SRafał Miłecki max_retries = 200; 1178369ae33SRafał Miłecki bcma_pcie_mdio_set_phy(pc, device); 1182be25cacSHauke Mehrtens v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR << 1192be25cacSHauke Mehrtens BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF); 1202be25cacSHauke Mehrtens v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF); 1212be25cacSHauke Mehrtens } else { 1222be25cacSHauke Mehrtens v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD); 1232be25cacSHauke Mehrtens v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); 1248369ae33SRafał Miłecki } 1258369ae33SRafał Miłecki 1262be25cacSHauke Mehrtens v = BCMA_CORE_PCI_MDIODATA_START; 1272be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_WRITE; 1282be25cacSHauke Mehrtens v |= BCMA_CORE_PCI_MDIODATA_TA; 1298369ae33SRafał Miłecki v |= data; 1302be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v); 1318369ae33SRafał Miłecki /* Wait for the device to complete the transaction */ 1328369ae33SRafał Miłecki udelay(10); 1338369ae33SRafał Miłecki for (i = 0; i < max_retries; i++) { 1342be25cacSHauke Mehrtens v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL); 1352be25cacSHauke Mehrtens if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) 1368369ae33SRafał Miłecki break; 1378369ae33SRafał Miłecki msleep(1); 1388369ae33SRafał Miłecki } 1392be25cacSHauke Mehrtens pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0); 1408369ae33SRafał Miłecki } 1418369ae33SRafał Miłecki 1428369ae33SRafał Miłecki /************************************************** 1438369ae33SRafał Miłecki * Workarounds. 1448369ae33SRafał Miłecki **************************************************/ 1458369ae33SRafał Miłecki 1468369ae33SRafał Miłecki static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc) 1478369ae33SRafał Miłecki { 1482be25cacSHauke Mehrtens u32 tmp; 1492be25cacSHauke Mehrtens 1502be25cacSHauke Mehrtens tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG); 1512be25cacSHauke Mehrtens if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT) 1522be25cacSHauke Mehrtens return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE | 1532be25cacSHauke Mehrtens BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY; 1542be25cacSHauke Mehrtens else 1552be25cacSHauke Mehrtens return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE; 1568369ae33SRafał Miłecki } 1578369ae33SRafał Miłecki 1588369ae33SRafał Miłecki static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) 1598369ae33SRafał Miłecki { 1608369ae33SRafał Miłecki u16 tmp; 1618369ae33SRafał Miłecki 1622be25cacSHauke Mehrtens bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX, 1632be25cacSHauke Mehrtens BCMA_CORE_PCI_SERDES_RX_CTRL, 1648369ae33SRafał Miłecki bcma_pcicore_polarity_workaround(pc)); 1652be25cacSHauke Mehrtens tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL, 1662be25cacSHauke Mehrtens BCMA_CORE_PCI_SERDES_PLL_CTRL); 1672be25cacSHauke Mehrtens if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN) 1682be25cacSHauke Mehrtens bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL, 1692be25cacSHauke Mehrtens BCMA_CORE_PCI_SERDES_PLL_CTRL, 1702be25cacSHauke Mehrtens tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); 1718369ae33SRafał Miłecki } 1728369ae33SRafał Miłecki 1738369ae33SRafał Miłecki /************************************************** 1748369ae33SRafał Miłecki * Init. 1758369ae33SRafał Miłecki **************************************************/ 1768369ae33SRafał Miłecki 177*d1a7a8e1SHauke Mehrtens static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) 1788369ae33SRafał Miłecki { 1798369ae33SRafał Miłecki bcma_pcicore_serdes_workaround(pc); 1808369ae33SRafał Miłecki } 1811de520f4SRafał Miłecki 182*d1a7a8e1SHauke Mehrtens static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) 1839352f69cSRafał Miłecki { 1849352f69cSRafał Miłecki struct bcma_bus *bus = pc->core->bus; 1859352f69cSRafał Miłecki u16 chipid_top; 1869352f69cSRafał Miłecki 1879352f69cSRafał Miłecki chipid_top = (bus->chipinfo.id & 0xFF00); 1889352f69cSRafał Miłecki if (chipid_top != 0x4700 && 1899352f69cSRafał Miłecki chipid_top != 0x5300) 1909352f69cSRafał Miłecki return false; 1919352f69cSRafał Miłecki 1926e6e8c51SJohn W. Linville #ifdef CONFIG_SSB_DRIVER_PCICORE 19326f2622eSRafał Miłecki if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI) 1949352f69cSRafał Miłecki return false; 1956e6e8c51SJohn W. Linville #endif /* CONFIG_SSB_DRIVER_PCICORE */ 1969352f69cSRafał Miłecki 1979352f69cSRafał Miłecki #if 0 1989352f69cSRafał Miłecki /* TODO: on BCMA we use address from EROM instead of magic formula */ 1999352f69cSRafał Miłecki u32 tmp; 2009352f69cSRafał Miłecki return !mips_busprobe32(tmp, (bus->mmio + 2019352f69cSRafał Miłecki (pc->core->core_index * BCMA_CORE_SIZE))); 2029352f69cSRafał Miłecki #endif 2039352f69cSRafał Miłecki 2049352f69cSRafał Miłecki return true; 2059352f69cSRafał Miłecki } 2069352f69cSRafał Miłecki 207*d1a7a8e1SHauke Mehrtens void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) 2089352f69cSRafał Miłecki { 209517f43e5SHauke Mehrtens if (pc->setup_done) 210517f43e5SHauke Mehrtens return; 211517f43e5SHauke Mehrtens 2129352f69cSRafał Miłecki if (bcma_core_pci_is_in_hostmode(pc)) { 2139352f69cSRafał Miłecki #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE 2149352f69cSRafał Miłecki bcma_core_pci_hostmode_init(pc); 2159352f69cSRafał Miłecki #else 2169352f69cSRafał Miłecki pr_err("Driver compiled without support for hostmode PCI\n"); 2179352f69cSRafał Miłecki #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ 2189352f69cSRafał Miłecki } else { 2199352f69cSRafał Miłecki bcma_core_pci_clientmode_init(pc); 2209352f69cSRafał Miłecki } 221517f43e5SHauke Mehrtens 222517f43e5SHauke Mehrtens pc->setup_done = true; 2239352f69cSRafał Miłecki } 2249352f69cSRafał Miłecki 2251de520f4SRafał Miłecki int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, 2261de520f4SRafał Miłecki bool enable) 2271de520f4SRafał Miłecki { 2281de520f4SRafał Miłecki struct pci_dev *pdev = pc->core->bus->host_pci; 2291de520f4SRafał Miłecki u32 coremask, tmp; 230ecd177c2SHauke Mehrtens int err = 0; 231ecd177c2SHauke Mehrtens 232ecd177c2SHauke Mehrtens if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) { 233ecd177c2SHauke Mehrtens /* This bcma device is not on a PCI host-bus. So the IRQs are 234ecd177c2SHauke Mehrtens * not routed through the PCI core. 235ecd177c2SHauke Mehrtens * So we must not enable routing through the PCI core. */ 236ecd177c2SHauke Mehrtens goto out; 237ecd177c2SHauke Mehrtens } 2381de520f4SRafał Miłecki 2391de520f4SRafał Miłecki err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); 2401de520f4SRafał Miłecki if (err) 2411de520f4SRafał Miłecki goto out; 2421de520f4SRafał Miłecki 2431de520f4SRafał Miłecki coremask = BIT(core->core_index) << 8; 2441de520f4SRafał Miłecki if (enable) 2451de520f4SRafał Miłecki tmp |= coremask; 2461de520f4SRafał Miłecki else 2471de520f4SRafał Miłecki tmp &= ~coremask; 2481de520f4SRafał Miłecki 2491de520f4SRafał Miłecki err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); 2501de520f4SRafał Miłecki 2511de520f4SRafał Miłecki out: 2521de520f4SRafał Miłecki return err; 2531de520f4SRafał Miłecki } 254440ca98fSRafał Miłecki EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); 255