161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* 261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Sonics Silicon Backplane 361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Broadcom PCI-core driver 461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * 561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright 2005, Broadcom Corporation 6eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * 861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Licensed under the GNU/GPL. See COPYING for details. 961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch */ 1061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 1161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/ssb/ssb.h> 1261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/pci.h> 131014c22e42a6692660d1a77888d07f4811b2914dPaul Gortmaker#include <linux/export.h> 1461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/delay.h> 157cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch#include <linux/ssb/ssb_embedded.h> 1661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 1761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include "ssb_private.h" 1861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 19ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address); 20ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data); 21ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); 22ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, 23ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki u8 address, u16 data); 2461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 2561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline 2661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschu32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) 2761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 2861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return ssb_read32(pc->dev, offset); 2961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 3061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 3161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline 3261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschvoid pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) 3361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 3461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_write32(pc->dev, offset, value); 3561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 3661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 377cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Bueschstatic inline 387cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Bueschu16 pcicore_read16(struct ssb_pcicore *pc, u16 offset) 397cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch{ 407cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch return ssb_read16(pc->dev, offset); 417cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch} 427cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch 437cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Bueschstatic inline 447cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Bueschvoid pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value) 457cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch{ 467cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch ssb_write16(pc->dev, offset, value); 477cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch} 487cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch 4961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/************************************************** 5061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Code for hostmode operation. 5161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch **************************************************/ 5261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 5361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#ifdef CONFIG_SSB_PCICORE_HOSTMODE 5461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 5561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <asm/paccess.h> 5661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Probe a 32bit value on the bus and catch bus exceptions. 5761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Returns nonzero on a bus exception. 5861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * This is MIPS specific */ 5961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr))) 6061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Assume one-hot slot wiring */ 6261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#define SSB_PCI_SLOT_MAX 16 6361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Global lock is OK, as we won't have more than one extpci anyway. */ 6561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic DEFINE_SPINLOCK(cfgspace_lock); 6661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Core to access the external PCI config space. Can only have one. */ 6761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic struct ssb_pcicore *extpci_core; 6861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 7061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic u32 get_cfgspace_addr(struct ssb_pcicore *pc, 7161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int bus, unsigned int dev, 7261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int func, unsigned int off) 7361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 7461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 addr = 0; 7561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 tmp; 7661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 777cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch /* We do only have one cardbus device behind the bridge. */ 78a6c84622b7fa3ea5417a9d1d0ce0bc3e7fbe3be1Hauke Mehrtens if (pc->cardbusmode && (dev > 1)) 7961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 807cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch 8161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (bus == 0) { 8261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Type 0 transaction */ 8361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (unlikely(dev >= SSB_PCI_SLOT_MAX)) 8461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 8561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Slide the window */ 8661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch tmp = SSB_PCICORE_SBTOPCI_CFG0; 8761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK); 8861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp); 8961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Calculate the address */ 9061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr = SSB_PCI_CFG; 9161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK); 9261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (func << 8); 9361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (off & ~3); 9461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } else { 9561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Type 1 transaction */ 9661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, 9761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_PCICORE_SBTOPCI_CFG1); 9861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Calculate the address */ 9961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr = SSB_PCI_CFG; 10061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (bus << 16); 10161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (dev << 11); 10261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (func << 8); 10361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr |= (off & ~3); 10461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 10561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout: 10661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return addr; 10761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 10861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 10961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_extpci_read_config(struct ssb_pcicore *pc, 11061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int bus, unsigned int dev, 11161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int func, unsigned int off, 11261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch void *buf, int len) 11361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 11461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int err = -EINVAL; 11561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 addr, val; 11661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch void __iomem *mmio; 11761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 11861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_WARN_ON(!pc->hostmode); 11961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (unlikely(len != 1 && len != 2 && len != 4)) 12061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 12161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr = get_cfgspace_addr(pc, bus, dev, func, off); 12261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (unlikely(!addr)) 12361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 12461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = -ENOMEM; 12561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch mmio = ioremap_nocache(addr, len); 12661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!mmio) 12761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 12861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 12961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (mips_busprobe32(val, mmio)) { 13061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = 0xffffffff; 13161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto unmap; 13261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 13361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 13461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = readl(mmio); 13561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val >>= (8 * (off & 3)); 13661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 13761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch switch (len) { 13861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 1: 13961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *((u8 *)buf) = (u8)val; 14061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 14161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 2: 14261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *((u16 *)buf) = (u16)val; 14361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 14461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 4: 14561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *((u32 *)buf) = (u32)val; 14661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 14761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 14861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = 0; 14961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschunmap: 15061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch iounmap(mmio); 15161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout: 15261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return err; 15361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 15461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 15561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_extpci_write_config(struct ssb_pcicore *pc, 15661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int bus, unsigned int dev, 15761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned int func, unsigned int off, 15861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch const void *buf, int len) 15961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 16061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int err = -EINVAL; 16161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 addr, val = 0; 16261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch void __iomem *mmio; 16361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 16461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_WARN_ON(!pc->hostmode); 16561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (unlikely(len != 1 && len != 2 && len != 4)) 16661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 16761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch addr = get_cfgspace_addr(pc, bus, dev, func, off); 16861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (unlikely(!addr)) 16961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 17061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = -ENOMEM; 17161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch mmio = ioremap_nocache(addr, len); 17261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!mmio) 17361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 17461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 17561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (mips_busprobe32(val, mmio)) { 17661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = 0xffffffff; 17761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto unmap; 17861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 17961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 18061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch switch (len) { 18161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 1: 18261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = readl(mmio); 18361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val &= ~(0xFF << (8 * (off & 3))); 18461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val |= *((const u8 *)buf) << (8 * (off & 3)); 18561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 18661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 2: 18761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = readl(mmio); 18861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val &= ~(0xFFFF << (8 * (off & 3))); 18961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val |= *((const u16 *)buf) << (8 * (off & 3)); 19061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 19161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch case 4: 19261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = *((const u32 *)buf); 19361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 19461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 19561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch writel(val, mmio); 19661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 19761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = 0; 19861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschunmap: 19961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch iounmap(mmio); 20061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout: 20161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return err; 20261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 20361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 20461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn, 20561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int reg, int size, u32 *val) 20661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 20761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned long flags; 20861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int err; 20961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 21061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch spin_lock_irqsave(&cfgspace_lock, flags); 21161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn), 21261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch PCI_FUNC(devfn), reg, val, size); 21361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch spin_unlock_irqrestore(&cfgspace_lock, flags); 21461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 21561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 21661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 21761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 21861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn, 21961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int reg, int size, u32 val) 22061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 22161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch unsigned long flags; 22261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int err; 22361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 22461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch spin_lock_irqsave(&cfgspace_lock, flags); 22561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn), 22661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch PCI_FUNC(devfn), reg, &val, size); 22761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch spin_unlock_irqrestore(&cfgspace_lock, flags); 22861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 22961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 23061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 23161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 23261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic struct pci_ops ssb_pcicore_pciops = { 23361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .read = ssb_pcicore_read_config, 23461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .write = ssb_pcicore_write_config, 23561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}; 23661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 23761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic struct resource ssb_pcicore_mem_resource = { 23861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .name = "SSB PCIcore external memory", 23961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .start = SSB_PCI_DMA, 24061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, 241fc71acc846c577473ada72a46c5ea9c935eca086Michael Buesch .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED, 24261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}; 24361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 24461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic struct resource ssb_pcicore_io_resource = { 24561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .name = "SSB PCIcore external I/O", 24661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .start = 0x100, 24761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .end = 0x7FF, 248fc71acc846c577473ada72a46c5ea9c935eca086Michael Buesch .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED, 24961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}; 25061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 25161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic struct pci_controller ssb_pcicore_controller = { 25261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .pci_ops = &ssb_pcicore_pciops, 25361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .io_resource = &ssb_pcicore_io_resource, 25461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch .mem_resource = &ssb_pcicore_mem_resource, 25561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}; 25661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 257aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/* This function is called when doing a pci_enable_device(). 258aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * We must first check if the device is a device on the PCI-core bridge. */ 259aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_pcicore_plat_dev_init(struct pci_dev *d) 260aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{ 261aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch if (d->bus->ops != &ssb_pcicore_pciops) { 262aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* This is not a device on the PCI-core bridge. */ 263aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return -ENODEV; 264aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch } 265aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 266aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", 267aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_name(d)); 268aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 269aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* Fix up interrupt lines */ 270aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch d->irq = ssb_mips_irq(extpci_core->dev) + 2; 271aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); 272aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 273aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return 0; 274aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch} 275aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 276aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/* Early PCI fixup for a device on the PCI-core bridge. */ 277aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev) 278aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{ 279aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch u8 lat; 280aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 281aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch if (dev->bus->ops != &ssb_pcicore_pciops) { 282aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* This is not a device on the PCI-core bridge. */ 283aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return; 284aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch } 285aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) 286aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return; 287aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 288aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); 289aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 290aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* Enable PCI bridge bus mastering and memory space */ 291aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_set_master(dev); 292aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch if (pcibios_enable_device(dev, ~0) < 0) { 293aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); 294aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return; 295aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch } 296aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 297aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* Enable PCI bridge BAR1 prefetch and burst */ 298aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); 299aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 300aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* Make sure our latency is high enough to handle the devices behind us */ 301aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch lat = 168; 302aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", 303aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_name(dev), lat); 304aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); 305aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch} 306aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschDECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); 307aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 308aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/* PCI device IRQ mapping. */ 309aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 310aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{ 311aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch if (dev->bus->ops != &ssb_pcicore_pciops) { 312aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch /* This is not a device on the PCI-core bridge. */ 313aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return -ENODEV; 314aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch } 315aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch return ssb_mips_irq(extpci_core->dev) + 2; 316aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch} 317aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch 318cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic void __devinit ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) 31961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 32061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 val; 32161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 32261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (WARN_ON(extpci_core)) 32361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return; 32461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch extpci_core = pc; 32561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 32661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); 32761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Reset devices on the external PCI bus */ 32861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = SSB_PCICORE_CTL_RST_OE; 32961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val |= SSB_PCICORE_CTL_CLK_OE; 33061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_CTL, val); 33161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val |= SSB_PCICORE_CTL_CLK; /* Clock on */ 33261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_CTL, val); 33361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch udelay(150); /* Assertion time demanded by the PCI standard */ 33461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ 33561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_CTL, val); 33661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = SSB_PCICORE_ARBCTL_INTERN; 33761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); 33861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch udelay(1); /* Assertion time demanded by the PCI standard */ 33961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 3407cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch if (pc->dev->bus->has_cardbus_slot) { 3417cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n"); 3427cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch pc->cardbusmode = 1; 3437cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch /* GPIO 1 resets the bridge */ 3447cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch ssb_gpio_out(pc->dev->bus, 1, 1); 3457cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch ssb_gpio_outen(pc->dev->bus, 1, 1); 3467cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch pcicore_write16(pc, SSB_PCICORE_SPROM(0), 3477cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch pcicore_read16(pc, SSB_PCICORE_SPROM(0)) 3487cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch | 0x0400); 3497cb4461520f307a6e3fb2bb32cb8daee45aa1faeMichael Buesch } 35061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 35161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* 64MB I/O window */ 35261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, 35361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_PCICORE_SBTOPCI_IO); 35461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* 64MB config space */ 35561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, 35661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_PCICORE_SBTOPCI_CFG0); 35761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* 1GB memory window */ 35861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, 35961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); 36061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 36161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Enable PCI bridge BAR0 prefetch and burst */ 36261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; 36361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); 36461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Clear error conditions */ 36561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch val = 0; 36661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2); 36761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 36861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Enable PCI interrupts */ 36961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, SSB_PCICORE_IMASK, 37061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch SSB_PCICORE_IMASK_INTA); 37161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 37261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Ok, ready to run, register it to the system. 37361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * The following needs change, if we want to port hostmode 37461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * to non-MIPS platform. */ 375fc71acc846c577473ada72a46c5ea9c935eca086Michael Buesch ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000); 376fc71acc846c577473ada72a46c5ea9c935eca086Michael Buesch set_io_port_base(ssb_pcicore_controller.io_map_base); 37761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Give some time to the PCI controller to configure itself with the new 37861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * values. Not waiting at this point causes crashes of the machine. */ 37961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch mdelay(10); 38061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch register_pci_controller(&ssb_pcicore_controller); 38161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 38261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 383cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic int __devinit pcicore_is_in_hostmode(struct ssb_pcicore *pc) 38461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 38561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch struct ssb_bus *bus = pc->dev->bus; 38661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u16 chipid_top; 38761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 tmp; 38861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 38961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch chipid_top = (bus->chip_id & 0xFF00); 39061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (chipid_top != 0x4700 && 39161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch chipid_top != 0x5300) 39261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return 0; 39361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 3942d8d4fdf78488f3362dccfd2a6bfdb4bc65c0858Aurelien Jarno if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI) 39561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return 0; 39661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 39761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* The 200-pin BCM4712 package does not bond out PCI. Even when 39861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * PCI is bonded out, some boards may leave the pins floating. */ 39961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (bus->chip_id == 0x4712) { 40061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (bus->chip_package == SSB_CHIPPACK_BCM4712S) 40161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return 0; 40261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (bus->chip_package == SSB_CHIPPACK_BCM4712M) 40361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return 0; 40461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 40561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (bus->chip_id == 0x5350) 40661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return 0; 40761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 40861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); 40961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 41061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ 41161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 412ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki/************************************************** 413ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki * Workarounds. 414ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki **************************************************/ 415ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki 416cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc) 417af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki{ 418af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0)); 419af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki if (((tmp & 0xF000) >> 12) != pc->dev->core_index) { 420af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki tmp &= ~0xF000; 421af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki tmp |= (pc->dev->core_index << 12); 422af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp); 423af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki } 424af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki} 425af335a6cbc3dfcba64ad31561c0da563d1c43a2dRafał Miłecki 426ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) 427ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki{ 428ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; 429ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki} 430ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki 431ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłeckistatic void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) 432ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki{ 433ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki const u8 serdes_pll_device = 0x1D; 434ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki const u8 serdes_rx_device = 0x1F; 435ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki u16 tmp; 436ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki 437ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, 438ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki ssb_pcicore_polarity_workaround(pc)); 439ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); 440ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki if (tmp & 0x4000) 441ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); 442ccc7c28af205888798b51b6cbc0b557ac1170a49Rafał Miłecki} 44361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 4446e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłeckistatic void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) 4456e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki{ 4466e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki struct ssb_device *pdev = pc->dev; 4476e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki struct ssb_bus *bus = pdev->bus; 4486e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki u32 tmp; 4496e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 4506e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); 4516e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= SSB_PCICORE_SBTOPCI_PREF; 4526e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= SSB_PCICORE_SBTOPCI_BURST; 4536e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); 4546e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 4556e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki if (pdev->id.revision < 5) { 4566e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp = ssb_read32(pdev, SSB_IMCFGLO); 4576e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp &= ~SSB_IMCFGLO_SERTO; 4586e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= 2; 4596e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp &= ~SSB_IMCFGLO_REQTO; 4606e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; 4616e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_write32(pdev, SSB_IMCFGLO, tmp); 4626e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_commit_settings(bus); 4636e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki } else if (pdev->id.revision >= 11) { 4646e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); 4656e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= SSB_PCICORE_SBTOPCI_MRM; 4666e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); 4676e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki } 4686e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki} 4696e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 4706e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłeckistatic void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) 4716e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki{ 4726e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki u32 tmp; 4735890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki u8 rev = pc->dev->id.revision; 4746e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 4755890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki if (rev == 0 || rev == 1) { 4766e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki /* TLP Workaround register. */ 4776e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp = ssb_pcie_read(pc, 0x4); 4786e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki tmp |= 0x8; 4796e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcie_write(pc, 0x4, tmp); 4806e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki } 4815890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki if (rev == 1) { 4825890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki /* DLLP Link Control register. */ 4835890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki tmp = ssb_pcie_read(pc, 0x100); 4845890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki tmp |= 0x40; 4855890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki ssb_pcie_write(pc, 0x100, tmp); 4865890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki } 4875890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki 4885890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki if (rev == 0) { 4896e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki const u8 serdes_rx_device = 0x1F; 4906e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 4916e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcie_mdio_write(pc, serdes_rx_device, 4926e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 2 /* Timer */, 0x8128); 4936e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcie_mdio_write(pc, serdes_rx_device, 4946e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 6 /* CDR */, 0x0100); 4956e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcie_mdio_write(pc, serdes_rx_device, 4966e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 7 /* CDR BW */, 0x1466); 4975890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki } else if (rev == 3 || rev == 4 || rev == 5) { 4985890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki /* TODO: DLLP Power Management Threshold */ 4995890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki ssb_pcicore_serdes_workaround(pc); 5005890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki /* TODO: ASPM */ 5015890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki } else if (rev == 7) { 5025890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki /* TODO: No PLL down */ 5035890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki } 5045890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki 5055890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki if (rev >= 6) { 5065890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki /* Miscellaneous Configuration Fixup */ 5075890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5)); 5085890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki if (!(tmp & 0x8000)) 5095890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki pcicore_write16(pc, SSB_PCICORE_SPROM(5), 5105890a3ca34aae94dd736557ad8cb898ac2802aa0Rafał Miłecki tmp | 0x8000); 5116e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki } 5126e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki} 5136e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki 51461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/************************************************** 51561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Generic and Clientmode operation code. 51661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch **************************************************/ 51761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 518cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) 51961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 520329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens struct ssb_device *pdev = pc->dev; 521329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens struct ssb_bus *bus = pdev->bus; 522329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens 523329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens if (bus->bustype == SSB_BUSTYPE_PCI) 524329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens ssb_pcicore_fix_sprom_core_index(pc); 5256ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki 52661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Disable PCI interrupts. */ 527329456d1ffb416c220813725b7363cda9975c9aaHauke Mehrtens ssb_write32(pdev, SSB_INTVEC, 0); 5286ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki 5296ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki /* Additional PCIe always once-executed workarounds */ 5306ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki if (pc->dev->id.coreid == SSB_DEV_PCIE) { 5316ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki ssb_pcicore_serdes_workaround(pc); 5326ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki /* TODO: ASPM */ 5336ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki /* TODO: Clock Request Update */ 5346ae8ec27868bfdbb815287bee8146acbefaee867Rafał Miłecki } 53561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 53661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 537cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensvoid __devinit ssb_pcicore_init(struct ssb_pcicore *pc) 53861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 53961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch struct ssb_device *dev = pc->dev; 54061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 54161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!dev) 54261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return; 54361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!ssb_device_is_enabled(dev)) 54461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_device_enable(dev, 0); 54561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 54661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#ifdef CONFIG_SSB_PCICORE_HOSTMODE 54761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pc->hostmode = pcicore_is_in_hostmode(pc); 54861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (pc->hostmode) 54961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_pcicore_init_hostmode(pc); 55061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ 55161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!pc->hostmode) 55261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_pcicore_init_clientmode(pc); 55361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 55461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 55561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) 55661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 55761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, 0x130, address); 55861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return pcicore_read32(pc, 0x134); 55961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 56061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 56161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) 56261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 56361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, 0x130, address); 56461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, 0x134, data); 56561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 56661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 5671b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłeckistatic void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) 5681b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki{ 5691b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki const u16 mdio_control = 0x128; 5701b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki const u16 mdio_data = 0x12C; 5711b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki u32 v; 5721b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki int i; 5731b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki 5741b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v = (1 << 30); /* Start of Transaction */ 5751b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v |= (1 << 28); /* Write Transaction */ 5761b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v |= (1 << 17); /* Turnaround */ 5771b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v |= (0x1F << 18); 5781b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v |= (phy << 4); 5791b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki pcicore_write32(pc, mdio_data, v); 5801b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki 5811b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki udelay(10); 5821b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki for (i = 0; i < 200; i++) { 5831b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v = pcicore_read32(pc, mdio_control); 5841b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki if (v & 0x100 /* Trans complete */) 5851b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki break; 5861b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki msleep(1); 5871b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki } 5881b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki} 5891b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki 590ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłeckistatic u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) 591ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki{ 592ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki const u16 mdio_control = 0x128; 593ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki const u16 mdio_data = 0x12C; 594ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki int max_retries = 10; 595ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki u16 ret = 0; 596ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki u32 v; 597ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki int i; 598ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki 599ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v = 0x80; /* Enable Preamble Sequence */ 600ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v |= 0x2; /* MDIO Clock Divisor */ 601ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki pcicore_write32(pc, mdio_control, v); 602ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki 603ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki if (pc->dev->id.revision >= 10) { 604ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki max_retries = 200; 605ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki ssb_pcie_mdio_set_phy(pc, device); 606ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki } 607ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki 608ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v = (1 << 30); /* Start of Transaction */ 609ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v |= (1 << 29); /* Read Transaction */ 610ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v |= (1 << 17); /* Turnaround */ 611ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki if (pc->dev->id.revision < 10) 612ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v |= (u32)device << 22; 613ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v |= (u32)address << 18; 614ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki pcicore_write32(pc, mdio_data, v); 615ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki /* Wait for the device to complete the transaction */ 616ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki udelay(10); 6179be1cb39c6551231a4f210097685da11aa6a537bRafał Miłecki for (i = 0; i < max_retries; i++) { 618ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki v = pcicore_read32(pc, mdio_control); 619ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki if (v & 0x100 /* Trans complete */) { 620ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki udelay(10); 621ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki ret = pcicore_read32(pc, mdio_data); 622ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki break; 623ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki } 624ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki msleep(1); 625ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki } 626ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki pcicore_write32(pc, mdio_control, 0); 627ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki return ret; 628ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki} 629ba91d1a1bcccd90247b5b9703c1a236cc2e95698Rafał Miłecki 63061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, 63161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u8 address, u16 data) 63261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 63361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch const u16 mdio_control = 0x128; 63461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch const u16 mdio_data = 0x12C; 6351b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki int max_retries = 10; 63661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 v; 63761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int i; 63861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 63961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v = 0x80; /* Enable Preamble Sequence */ 64061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v |= 0x2; /* MDIO Clock Divisor */ 64161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, mdio_control, v); 64261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6431b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki if (pc->dev->id.revision >= 10) { 6441b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki max_retries = 200; 6451b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki ssb_pcie_mdio_set_phy(pc, device); 6461b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki } 6471b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki 64861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v = (1 << 30); /* Start of Transaction */ 64961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v |= (1 << 28); /* Write Transaction */ 65061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v |= (1 << 17); /* Turnaround */ 6511b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki if (pc->dev->id.revision < 10) 6521b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki v |= (u32)device << 22; 65361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v |= (u32)address << 18; 65461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v |= data; 65561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, mdio_data, v); 65661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Wait for the device to complete the transaction */ 65761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch udelay(10); 6581b1c7acd9709e545399d1b6b89888f025911c0a2Rafał Miłecki for (i = 0; i < max_retries; i++) { 65961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch v = pcicore_read32(pc, mdio_control); 66061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (v & 0x100 /* Trans complete */) 66161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch break; 66261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch msleep(1); 66361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 66461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pcicore_write32(pc, mdio_control, 0); 66561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 66661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 66761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, 66861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch struct ssb_device *dev) 66961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{ 67061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch struct ssb_device *pdev = pc->dev; 67161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch struct ssb_bus *bus; 67261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch int err = 0; 67361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 tmp; 67461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6759e095a687b3561972272063260e14ab1bc21de08Michael Buesch if (dev->bus->bustype != SSB_BUSTYPE_PCI) { 6769e095a687b3561972272063260e14ab1bc21de08Michael Buesch /* This SSB device is not on a PCI host-bus. So the IRQs are 6779e095a687b3561972272063260e14ab1bc21de08Michael Buesch * not routed through the PCI core. 6789e095a687b3561972272063260e14ab1bc21de08Michael Buesch * So we must not enable routing through the PCI core. */ 6799e095a687b3561972272063260e14ab1bc21de08Michael Buesch goto out; 6809e095a687b3561972272063260e14ab1bc21de08Michael Buesch } 6819e095a687b3561972272063260e14ab1bc21de08Michael Buesch 68261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (!pdev) 68361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 68461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch bus = pdev->bus; 68561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 686a3bafeedfff2ac5fa0a316bea4570e27900b6fccMichael Buesch might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); 687a3bafeedfff2ac5fa0a316bea4570e27900b6fccMichael Buesch 68861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Enable interrupts for this device. */ 6898b45499ccb8a93cd68b1a8766786c2f8ea991ae2Michael Buesch if ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE)) { 69061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 coremask; 69161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 69261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Calculate the "coremask" for the device. */ 69361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch coremask = (1 << dev->core_index); 69461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 6958b45499ccb8a93cd68b1a8766786c2f8ea991ae2Michael Buesch SSB_WARN_ON(bus->bustype != SSB_BUSTYPE_PCI); 69661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); 69761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (err) 69861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 69961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch tmp |= coremask << 8; 70061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp); 70161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (err) 70261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 70361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } else { 70461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch u32 intvec; 70561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 70661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch intvec = ssb_read32(pdev, SSB_INTVEC); 70751e8b885902fc8cc2ded48322ad9402bbcff23feMichael Buesch tmp = ssb_read32(dev, SSB_TPSFLAG); 70851e8b885902fc8cc2ded48322ad9402bbcff23feMichael Buesch tmp &= SSB_TPSFLAG_BPFLAG; 70951e8b885902fc8cc2ded48322ad9402bbcff23feMichael Buesch intvec |= (1 << tmp); 71061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch ssb_write32(pdev, SSB_INTVEC, intvec); 71161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 71261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch 71361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch /* Setup PCIcore operation. */ 71461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (pc->setup_done) 71561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch goto out; 71661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch if (pdev->id.coreid == SSB_DEV_PCI) { 7176e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcicore_pci_setup_workarounds(pc); 71861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } else { 71961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); 7206e914101d47c76e09b0568d094ef44257dd3d6e9Rafał Miłecki ssb_pcicore_pcie_setup_workarounds(pc); 72161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch } 72261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch pc->setup_done = 1; 72361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout: 72461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch return err; 72561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch} 72661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael BueschEXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable); 727