|
@@ -129,3 +129,145 @@ static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|
|
spin_lock_irqsave(&orion5x_pcie_lock, flags);
|
|
|
ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val);
|
|
|
spin_unlock_irqrestore(&orion5x_pcie_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static struct pci_ops pcie_ops = {
|
|
|
+ .read = pcie_rd_conf,
|
|
|
+ .write = pcie_wr_conf,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static int __init pcie_setup(struct pci_sys_data *sys)
|
|
|
+{
|
|
|
+ struct resource *res;
|
|
|
+ int dev;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Generic PCIe unit setup.
|
|
|
+ */
|
|
|
+ orion_pcie_setup(PCIE_BASE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Check whether to apply Orion-1/Orion-NAS PCIe config
|
|
|
+ * read transaction workaround.
|
|
|
+ */
|
|
|
+ dev = orion_pcie_dev_id(PCIE_BASE);
|
|
|
+ if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) {
|
|
|
+ printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config "
|
|
|
+ "read transaction workaround\n");
|
|
|
+ orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE,
|
|
|
+ ORION5X_PCIE_WA_SIZE);
|
|
|
+ pcie_ops.read = pcie_rd_conf_wa;
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCIE_IO_PHYS_BASE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Request resources.
|
|
|
+ */
|
|
|
+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
|
|
|
+ if (!res)
|
|
|
+ panic("pcie_setup unable to alloc resources");
|
|
|
+
|
|
|
+ /*
|
|
|
+ * IORESOURCE_MEM
|
|
|
+ */
|
|
|
+ res->name = "PCIe Memory Space";
|
|
|
+ res->flags = IORESOURCE_MEM;
|
|
|
+ res->start = ORION5X_PCIE_MEM_PHYS_BASE;
|
|
|
+ res->end = res->start + ORION5X_PCIE_MEM_SIZE - 1;
|
|
|
+ if (request_resource(&iomem_resource, res))
|
|
|
+ panic("Request PCIe Memory resource failed\n");
|
|
|
+ pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ * PCI controller
|
|
|
+ ****************************************************************************/
|
|
|
+#define ORION5X_PCI_REG(x) (ORION5X_PCI_VIRT_BASE + (x))
|
|
|
+#define PCI_MODE ORION5X_PCI_REG(0xd00)
|
|
|
+#define PCI_CMD ORION5X_PCI_REG(0xc00)
|
|
|
+#define PCI_P2P_CONF ORION5X_PCI_REG(0x1d14)
|
|
|
+#define PCI_CONF_ADDR ORION5X_PCI_REG(0xc78)
|
|
|
+#define PCI_CONF_DATA ORION5X_PCI_REG(0xc7c)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI_MODE bits
|
|
|
+ */
|
|
|
+#define PCI_MODE_64BIT (1 << 2)
|
|
|
+#define PCI_MODE_PCIX ((1 << 4) | (1 << 5))
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI_CMD bits
|
|
|
+ */
|
|
|
+#define PCI_CMD_HOST_REORDER (1 << 29)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI_P2P_CONF bits
|
|
|
+ */
|
|
|
+#define PCI_P2P_BUS_OFFS 16
|
|
|
+#define PCI_P2P_BUS_MASK (0xff << PCI_P2P_BUS_OFFS)
|
|
|
+#define PCI_P2P_DEV_OFFS 24
|
|
|
+#define PCI_P2P_DEV_MASK (0x1f << PCI_P2P_DEV_OFFS)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI_CONF_ADDR bits
|
|
|
+ */
|
|
|
+#define PCI_CONF_REG(reg) ((reg) & 0xfc)
|
|
|
+#define PCI_CONF_FUNC(func) (((func) & 0x3) << 8)
|
|
|
+#define PCI_CONF_DEV(dev) (((dev) & 0x1f) << 11)
|
|
|
+#define PCI_CONF_BUS(bus) (((bus) & 0xff) << 16)
|
|
|
+#define PCI_CONF_ADDR_EN (1 << 31)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Internal configuration space
|
|
|
+ */
|
|
|
+#define PCI_CONF_FUNC_STAT_CMD 0
|
|
|
+#define PCI_CONF_REG_STAT_CMD 4
|
|
|
+#define PCIX_STAT 0x64
|
|
|
+#define PCIX_STAT_BUS_OFFS 8
|
|
|
+#define PCIX_STAT_BUS_MASK (0xff << PCIX_STAT_BUS_OFFS)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI Address Decode Windows registers
|
|
|
+ */
|
|
|
+#define PCI_BAR_SIZE_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc08) : \
|
|
|
+ ((n) == 1) ? ORION5X_PCI_REG(0xd08) : \
|
|
|
+ ((n) == 2) ? ORION5X_PCI_REG(0xc0c) : \
|
|
|
+ ((n) == 3) ? ORION5X_PCI_REG(0xd0c) : 0)
|
|
|
+#define PCI_BAR_REMAP_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc48) : \
|
|
|
+ ((n) == 1) ? ORION5X_PCI_REG(0xd48) : \
|
|
|
+ ((n) == 2) ? ORION5X_PCI_REG(0xc4c) : \
|
|
|
+ ((n) == 3) ? ORION5X_PCI_REG(0xd4c) : 0)
|
|
|
+#define PCI_BAR_ENABLE ORION5X_PCI_REG(0xc3c)
|
|
|
+#define PCI_ADDR_DECODE_CTRL ORION5X_PCI_REG(0xd3c)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI configuration helpers for BAR settings
|
|
|
+ */
|
|
|
+#define PCI_CONF_FUNC_BAR_CS(n) ((n) >> 1)
|
|
|
+#define PCI_CONF_REG_BAR_LO_CS(n) (((n) & 1) ? 0x18 : 0x10)
|
|
|
+#define PCI_CONF_REG_BAR_HI_CS(n) (((n) & 1) ? 0x1c : 0x14)
|
|
|
+
|
|
|
+/*
|
|
|
+ * PCI config cycles are done by programming the PCI_CONF_ADDR register
|
|
|
+ * and then reading the PCI_CONF_DATA register. Need to make sure these
|
|
|
+ * transactions are atomic.
|
|
|
+ */
|
|
|
+static DEFINE_SPINLOCK(orion5x_pci_lock);
|
|
|
+
|
|
|
+static int orion5x_pci_cardbus_mode;
|
|
|
+
|
|
|
+static int orion5x_pci_local_bus_nr(void)
|
|
|
+{
|
|
|
+ u32 conf = readl(PCI_P2P_CONF);
|
|
|
+ return((conf & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS);
|
|
|
+}
|
|
|
+
|
|
|
+static int orion5x_pci_hw_rd_conf(int bus, int dev, u32 func,
|
|
|
+ u32 where, u32 size, u32 *val)
|
|
|
+{
|