[ar71xx] add AR7240 specific PCI code
authorjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 5 Jul 2009 08:06:24 +0000 (08:06 +0000)
committerjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 5 Jul 2009 08:06:24 +0000 (08:06 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@16674 3c298f89-4303-0410-b956-a3cf2f4a3e73

target/linux/ar71xx/files/arch/mips/ar71xx/pci.c
target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar71xx.h
target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/pci.h
target/linux/ar71xx/files/arch/mips/pci/pci-ar724x.c [new file with mode: 0644]

index 7e18d8b..19199f1 100644 (file)
@@ -38,15 +38,48 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 
 int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
 {
-       return ar71xx_pcibios_map_irq(dev, slot, pin);
+       int ret = 0;
+
+       switch (ar71xx_soc) {
+       case AR71XX_SOC_AR7130:
+       case AR71XX_SOC_AR7141:
+       case AR71XX_SOC_AR7161:
+               ret = ar71xx_pcibios_map_irq(dev, slot, pin);
+               break;
+
+       case AR71XX_SOC_AR7240:
+               ret = ar724x_pcibios_map_irq(dev, slot, pin);
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
 }
 
 int __init ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map)
 {
+       int ret = 0;
+
+       switch (ar71xx_soc) {
+       case AR71XX_SOC_AR7130:
+       case AR71XX_SOC_AR7141:
+       case AR71XX_SOC_AR7161:
+               board_be_handler = ar71xx_be_handler;
+               ret = ar71xx_pcibios_init();
+               break;
+
+       case AR71XX_SOC_AR7240:
+               ret = ar724x_pcibios_init();
+               break;
+
+       default:
+               return 0;
+       }
+
        ar71xx_pci_nr_irqs = nr_irqs;
        ar71xx_pci_irq_map = map;
 
-       board_be_handler = ar71xx_be_handler;
-
-       return ar71xx_pcibios_init();
+       return ret;
 }
index 7ce34b2..4486997 100644 (file)
@@ -345,8 +345,8 @@ void ar71xx_ddr_flush(u32 reg);
 
 #define PCI_IDSEL_ADL_START    17
 
-#define AR7240_PCI_CFG_BASE    (AR71XX_PCI_MEM_BASE + PCI_WIN4_OFFS)
-#define AR7240_PCI_CFG_SIZE    0x100
+#define AR724X_PCI_CFG_BASE    (AR71XX_PCI_MEM_BASE + 0x4000000)
+#define AR724X_PCI_CFG_SIZE    0x1000
 
 #define AR724X_PCI_REG_INT_STATUS      0x4c
 #define AR724X_PCI_REG_INT_MASK                0x50
index 9de4e02..c5352ce 100644 (file)
@@ -30,6 +30,10 @@ int ar71xx_pcibios_init(void) __init;
 
 int ar71xx_pci_be_handler(int is_fixup);
 
+int ar724x_pcibios_map_irq(const struct pci_dev *dev,
+                          uint8_t slot, uint8_t pin) __init;
+int ar724x_pcibios_init(void) __init;
+
 int ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map) __init;
 
 #endif /* __ASM_MACH_AR71XX_PCI_H */
diff --git a/target/linux/ar71xx/files/arch/mips/pci/pci-ar724x.c b/target/linux/ar71xx/files/arch/mips/pci/pci-ar724x.c
new file mode 100644 (file)
index 0000000..0f9bd2f
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  Atheros AR724x PCI host controller driver
+ *
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt, args...)      printk(KERN_INFO fmt, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+static void __iomem *ar724x_pci_localcfg_base;
+static void __iomem *ar724x_pci_devcfg_base;
+
+static DEFINE_SPINLOCK(ar724x_pci_lock);
+
+static void ar724x_pci_read(void __iomem *base, int where, int size, u32 *value)
+{
+       unsigned long flags;
+       u32 data;
+
+       spin_lock_irqsave(&ar724x_pci_lock, flags);
+       data = __raw_readl(base + (where & ~3));
+
+       switch (size) {
+       case 1:
+               if (where & 1)
+                       data >>= 8;
+               if (where & 2)
+                       data >>= 16;
+               data &= 0xFF;
+               break;
+       case 2:
+               if (where & 2)
+                       data >>= 16;
+               data &= 0xFFFF;
+               break;
+       }
+
+       *value = data;
+       spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+}
+
+static void ar724x_pci_write(void __iomem *base, int where, int size, u32 value)
+{
+       unsigned long flags;
+       u32 data;
+       int s;
+
+       spin_lock_irqsave(&ar724x_pci_lock, flags);
+       data = __raw_readl(base + (where & ~3));
+
+       switch (size) {
+       case 1:
+               s = ((where & 3) << 3);
+               data &= ~(0xFF << s);
+               data |= ((value & 0xFF) << s);
+               break;
+       case 2:
+               s = ((where & 2) << 4);
+               data &= ~(0xFFFF << s);
+               data |= ((value & 0xFFFF) << s);
+               break;
+       case 4:
+               data = value;
+               break;
+       }
+
+       __raw_writel(data, base + (where & ~3));
+       /* flush write */
+       (void)__raw_readl(base + (where & ~3));
+       spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+}
+
+static int ar724x_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 *value)
+{
+
+       if (bus->number != 0 || devfn != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       ar724x_pci_read(ar724x_pci_devcfg_base, where, size, value);
+
+       DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
+                       bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                       where, size, *value);
+
+       /*
+        * WAR for BAR issue - We are unable to access the PCI device space
+        * if we set the BAR with proper base address
+        */
+       if ((where == 0x10) && (size == 4))
+               ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0xffff);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int ar724x_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 value)
+{
+       if (bus->number != 0 || devfn != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
+               bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+               where, size, value);
+
+       ar724x_pci_write(ar724x_pci_devcfg_base, where, size, value);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int __init ar724x_pcibios_map_irq(const struct pci_dev *dev, uint8_t slot,
+                                 uint8_t pin)
+{
+       int irq = -1;
+       int i;
+
+       for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
+               struct ar71xx_pci_irq *entry;
+               entry = &ar71xx_pci_irq_map[i];
+
+               if (entry->slot == slot && entry->pin == pin) {
+                       irq = entry->irq;
+                       break;
+               }
+       }
+
+       if (irq < 0)
+               printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
+                               pin, pci_name((struct pci_dev *)dev));
+       else
+               printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
+                               irq, pin, pci_name((struct pci_dev *)dev));
+
+       return irq;
+}
+
+static struct pci_ops ar724x_pci_ops = {
+       .read   = ar724x_pci_read_config,
+       .write  = ar724x_pci_write_config,
+};
+
+static struct resource ar724x_pci_io_resource = {
+       .name           = "PCI IO space",
+       .start          = 0,
+       .end            = 0,
+       .flags          = IORESOURCE_IO,
+};
+
+static struct resource ar724x_pci_mem_resource = {
+       .name           = "PCI memory space",
+       .start          = AR71XX_PCI_MEM_BASE,
+       .end            = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
+       .flags          = IORESOURCE_MEM
+};
+
+static struct pci_controller ar724x_pci_controller = {
+       .pci_ops        = &ar724x_pci_ops,
+       .mem_resource   = &ar724x_pci_mem_resource,
+       .io_resource    = &ar724x_pci_io_resource,
+};
+
+int __init ar724x_pcibios_init(void)
+{
+       u32 t;
+
+       ar724x_pci_localcfg_base = ioremap_nocache(AR724X_PCI_CRP_BASE,
+                                                  AR724X_PCI_CRP_SIZE);
+
+       ar724x_pci_devcfg_base = ioremap_nocache(AR724X_PCI_CFG_BASE,
+                                                AR724X_PCI_CFG_SIZE);
+
+       /* setup COMMAND register */
+       t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE |
+           PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
+
+       ar724x_pci_write(ar724x_pci_localcfg_base, PCI_COMMAND, 4, t);
+
+       register_pci_controller(&ar724x_pci_controller);
+
+       return 0;
+}