static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, size_t count, u16 offset, u8 reg_width) { size_t saved_count = count; struct ssb_bus *bus = dev->bus; int error = 0; sdio_claim_host(bus->host_sdio); if (unlikely(ssb_sdio_switch_core(bus, dev))) { error = -EIO; memset((void *)buffer, 0xff, count); goto err_out; } offset |= bus->sdio_sbaddr & 0xffff; offset &= SBSDIO_SB_OFT_ADDR_MASK; switch (reg_width) { case sizeof(u8): error = sdio_writesb(bus->host_sdio, offset, (void *)buffer, count); break; case sizeof(u16): SSB_WARN_ON(count & 1); error = sdio_writesb(bus->host_sdio, offset, (void *)buffer, count); break; case sizeof(u32): SSB_WARN_ON(count & 3); offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ error = sdio_writesb(bus->host_sdio, offset, (void *)buffer, count); break; default: SSB_WARN_ON(1); } if (!error) goto out; err_out: dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n", bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); out: sdio_release_host(bus->host_sdio); }
int ssb_gpio_init(struct ssb_bus *bus) { if (ssb_chipco_available(&bus->chipco)) return ssb_gpio_chipco_init(bus); else if (ssb_extif_available(&bus->extif)) return ssb_gpio_extif_init(bus); else SSB_WARN_ON(1); return -1; }
int ssb_gpio_unregister(struct ssb_bus *bus) { if (ssb_chipco_available(&bus->chipco) || ssb_extif_available(&bus->extif)) { gpiochip_remove(&bus->gpio); return 0; } else { SSB_WARN_ON(1); } return -1; }
static int ssb_extpci_write_config(struct ssb_pcicore *pc, unsigned int bus, unsigned int dev, unsigned int func, unsigned int off, const void *buf, int len) { int err = -EINVAL; u32 addr, val = 0; void __iomem *mmio; SSB_WARN_ON(!pc->hostmode); if (unlikely(len != 1 && len != 2 && len != 4)) goto out; addr = get_cfgspace_addr(pc, bus, dev, func, off); if (unlikely(!addr)) goto out; err = -ENOMEM; mmio = ioremap_nocache(addr, len); if (!mmio) goto out; if (mips_busprobe32(val, mmio)) { val = 0xffffffff; goto unmap; } switch (len) { case 1: val = readl(mmio); val &= ~(0xFF << (8 * (off & 3))); val |= *((const u8 *)buf) << (8 * (off & 3)); break; case 2: val = readl(mmio); val &= ~(0xFFFF << (8 * (off & 3))); val |= *((const u16 *)buf) << (8 * (off & 3)); break; case 4: val = *((const u32 *)buf); break; } writel(val, mmio); err = 0; unmap: iounmap(mmio); out: return err; }
u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value) { unsigned long flags; u32 res = 0; spin_lock_irqsave(&bus->gpio_lock, flags); if (ssb_chipco_available(&bus->chipco)) res = ssb_chipco_gpio_outen(&bus->chipco, mask, value); else if (ssb_extif_available(&bus->extif)) res = ssb_extif_gpio_outen(&bus->extif, mask, value); else SSB_WARN_ON(1); spin_unlock_irqrestore(&bus->gpio_lock, flags); return res; }
int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, struct ssb_device *dev) { struct ssb_device *pdev = pc->dev; struct ssb_bus *bus; int err = 0; u32 tmp; if (dev->bus->bustype != SSB_BUSTYPE_PCI) { /* This SSB device is not on a PCI host-bus. So the IRQs are * not routed through the PCI core. * So we must not enable routing through the PCI core. */ goto out; } if (!pdev) goto out; bus = pdev->bus; might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); /* Enable interrupts for this device. */ if ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE)) { u32 coremask; /* Calculate the "coremask" for the device. */ coremask = (1 << dev->core_index); SSB_WARN_ON(bus->bustype != SSB_BUSTYPE_PCI); err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); if (err) goto out; tmp |= coremask << 8; err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp); if (err) goto out; } else { u32 intvec; intvec = ssb_read32(pdev, SSB_INTVEC); tmp = ssb_read32(dev, SSB_TPSFLAG); tmp &= SSB_TPSFLAG_BPFLAG; intvec |= (1 << tmp); ssb_write32(pdev, SSB_INTVEC, intvec); } /* Setup PCIcore operation. */ if (pc->setup_done) goto out; if (pdev->id.coreid == SSB_DEV_PCI) { tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); tmp |= SSB_PCICORE_SBTOPCI_PREF; tmp |= SSB_PCICORE_SBTOPCI_BURST; pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); if (pdev->id.revision < 5) { tmp = ssb_read32(pdev, SSB_IMCFGLO); tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 2; tmp &= ~SSB_IMCFGLO_REQTO; tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; ssb_write32(pdev, SSB_IMCFGLO, tmp); ssb_commit_settings(bus); } else if (pdev->id.revision >= 11) { tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); tmp |= SSB_PCICORE_SBTOPCI_MRM; pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); } } else { WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); //TODO: Better make defines for all these magic PCIE values. if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { /* TLP Workaround register. */ tmp = ssb_pcie_read(pc, 0x4); tmp |= 0x8; ssb_pcie_write(pc, 0x4, tmp); } if (pdev->id.revision == 0) { const u8 serdes_rx_device = 0x1F; ssb_pcie_mdio_write(pc, serdes_rx_device, 2 /* Timer */, 0x8128); ssb_pcie_mdio_write(pc, serdes_rx_device, 6 /* CDR */, 0x0100); ssb_pcie_mdio_write(pc, serdes_rx_device, 7 /* CDR BW */, 0x1466); } else if (pdev->id.revision == 1) { /* DLLP Link Control register. */ tmp = ssb_pcie_read(pc, 0x100); tmp |= 0x40; ssb_pcie_write(pc, 0x100, tmp); } } pc->setup_done = 1; out: return err; }