Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}