summaryrefslogtreecommitdiffstats
path: root/arch/mips/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci')
-rw-r--r--arch/mips/pci/Makefile6
-rw-r--r--arch/mips/pci/fixup-fuloong2e.c12
-rw-r--r--arch/mips/pci/fixup-lantiq.c40
-rw-r--r--arch/mips/pci/fixup-lemote2f.c12
-rw-r--r--arch/mips/pci/fixup-malta.c6
-rw-r--r--arch/mips/pci/fixup-mpc30x.c4
-rw-r--r--arch/mips/pci/fixup-sb1250.c6
-rw-r--r--arch/mips/pci/ops-loongson2.c1
-rw-r--r--arch/mips/pci/ops-tx4927.c2
-rw-r--r--arch/mips/pci/pci-ar71xx.c375
-rw-r--r--arch/mips/pci/pci-ar724x.c292
-rw-r--r--arch/mips/pci/pci-ath724x.c174
-rw-r--r--arch/mips/pci/pci-ip27.c2
-rw-r--r--arch/mips/pci/pci-lantiq.c219
-rw-r--r--arch/mips/pci/pci-xlr.c61
-rw-r--r--arch/mips/pci/pci.c55
16 files changed, 925 insertions, 342 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index c3ac4b086eb..c703f43a991 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -19,7 +19,8 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o
obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \
ops-bcm63xx.o
obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o
-obj-$(CONFIG_SOC_AR724X) += pci-ath724x.o
+obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o
+obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o
#
# These are still pretty much in the old state, watch, go blind.
@@ -41,7 +42,8 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
-obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o
+obj-$(CONFIG_LANTIQ) += fixup-lantiq.o
+obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/fixup-fuloong2e.c b/arch/mips/pci/fixup-fuloong2e.c
index d5d4c018fb0..0857ab8c391 100644
--- a/arch/mips/pci/fixup-fuloong2e.c
+++ b/arch/mips/pci/fixup-fuloong2e.c
@@ -48,7 +48,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
return 0;
}
-static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_nec_fixup(struct pci_dev *pdev)
{
unsigned int val;
@@ -60,7 +60,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
pci_write_config_dword(pdev, 0xe4, 1 << 5);
}
-static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func0_fixup(struct pci_dev *pdev)
{
unsigned char c;
@@ -135,7 +135,7 @@ static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
printk(KERN_INFO"via686b fix: ISA bridge done\n");
}
-static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func1_fixup(struct pci_dev *pdev)
{
printk(KERN_INFO"via686b fix: IDE\n");
@@ -168,19 +168,19 @@ static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
printk(KERN_INFO"via686b fix: IDE done\n");
}
-static void __init loongson2e_686b_func2_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func2_fixup(struct pci_dev *pdev)
{
/* irq routing */
pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 10);
}
-static void __init loongson2e_686b_func3_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func3_fixup(struct pci_dev *pdev)
{
/* irq routing */
pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 11);
}
-static void __init loongson2e_686b_func5_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func5_fixup(struct pci_dev *pdev)
{
unsigned int val;
unsigned char c;
diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c
new file mode 100644
index 00000000000..6c829df28dc
--- /dev/null
+++ b/arch/mips/pci/fixup-lantiq.c
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+
+int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL;
+int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ if (ltq_pci_plat_arch_init)
+ return ltq_pci_plat_arch_init(dev);
+
+ if (ltq_pci_plat_dev_init)
+ return ltq_pci_plat_dev_init(dev);
+
+ return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct of_irq dev_irq;
+ int irq;
+
+ if (of_irq_map_pci(dev, &dev_irq)) {
+ dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n",
+ slot, pin);
+ return 0;
+ }
+ irq = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier,
+ dev_irq.size);
+ dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq);
+ return irq;
+}
diff --git a/arch/mips/pci/fixup-lemote2f.c b/arch/mips/pci/fixup-lemote2f.c
index 4b9768d5d72..a7b917dcf60 100644
--- a/arch/mips/pci/fixup-lemote2f.c
+++ b/arch/mips/pci/fixup-lemote2f.c
@@ -96,21 +96,21 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
}
/* CS5536 SPEC. fixup */
-static void __init loongson_cs5536_isa_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_isa_fixup(struct pci_dev *pdev)
{
/* the uart1 and uart2 interrupt in PIC is enabled as default */
pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);
pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);
}
-static void __init loongson_cs5536_ide_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ide_fixup(struct pci_dev *pdev)
{
/* setting the mutex pin as IDE function */
pci_write_config_dword(pdev, PCI_IDE_CFG_REG,
CS5536_IDE_FLASH_SIGNATURE);
}
-static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_acc_fixup(struct pci_dev *pdev)
{
/* enable the AUDIO interrupt in PIC */
pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1);
@@ -118,14 +118,14 @@ static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);
}
-static void __init loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
{
/* enable the OHCI interrupt in PIC */
/* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */
pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);
}
-static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
{
u32 hi, lo;
@@ -137,7 +137,7 @@ static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);
}
-static void __init loongson_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson_nec_fixup(struct pci_dev *pdev)
{
unsigned int val;
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index 0f48498bc23..70073c98ed3 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -49,10 +49,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
return 0;
}
-static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func0_fixup(struct pci_dev *pdev)
{
unsigned char reg_val;
- static int piixirqmap[16] __initdata = { /* PIIX PIRQC[A:D] irq mappings */
+ static int piixirqmap[16] __devinitdata = { /* PIIX PIRQC[A:D] irq mappings */
0, 0, 0, 3,
4, 5, 6, 7,
0, 9, 10, 11,
@@ -83,7 +83,7 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
malta_piix_func0_fixup);
-static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev)
{
unsigned char reg_val;
diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c
index e08f49cb687..8e4f8288eca 100644
--- a/arch/mips/pci/fixup-mpc30x.c
+++ b/arch/mips/pci/fixup-mpc30x.c
@@ -22,13 +22,13 @@
#include <asm/vr41xx/mpc30x.h>
-static const int internal_func_irqs[] __initdata = {
+static const int internal_func_irqs[] __initconst = {
VRC4173_CASCADE_IRQ,
VRC4173_AC97_IRQ,
VRC4173_USB_IRQ,
};
-static const int irq_tab_mpc30x[] __initdata = {
+static const int irq_tab_mpc30x[] __initconst = {
[12] = VRC4173_PCMCIA1_IRQ,
[13] = VRC4173_PCMCIA2_IRQ,
[29] = MQ200_IRQ,
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
index f0bb9146e6c..d02900a7291 100644
--- a/arch/mips/pci/fixup-sb1250.c
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -15,7 +15,7 @@
* Set the BCM1250, etc. PCI host bridge's TRDY timeout
* to the finite max.
*/
-static void __init quirk_sb1250_pci(struct pci_dev *dev)
+static void __devinit quirk_sb1250_pci(struct pci_dev *dev)
{
pci_write_config_byte(dev, 0x40, 0xff);
}
@@ -25,7 +25,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
/*
* The BCM1250, etc. PCI/HT bridge reports as a host bridge.
*/
-static void __init quirk_sb1250_ht(struct pci_dev *dev)
+static void __devinit quirk_sb1250_ht(struct pci_dev *dev)
{
dev->class = PCI_CLASS_BRIDGE_PCI << 8;
}
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
/*
* Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
*/
-static void __init quirk_sp1011(struct pci_dev *dev)
+static void __devinit quirk_sp1011(struct pci_dev *dev)
{
pci_write_config_byte(dev, 0x64, 0xff);
}
diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c
index d657ee0bc13..afd221122d2 100644
--- a/arch/mips/pci/ops-loongson2.c
+++ b/arch/mips/pci/ops-loongson2.c
@@ -15,6 +15,7 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/export.h>
#include <loongson.h>
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c
index a1e7e6d80c8..bc13e29d2bb 100644
--- a/arch/mips/pci/ops-tx4927.c
+++ b/arch/mips/pci/ops-tx4927.c
@@ -495,7 +495,7 @@ irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
}
#ifdef CONFIG_TOSHIBA_FPCIB0
-static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __devinit tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
{
struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus);
diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c
new file mode 100644
index 00000000000..1552522b871
--- /dev/null
+++ b/arch/mips/pci/pci-ar71xx.c
@@ -0,0 +1,375 @@
+/*
+ * Atheros AR71xx PCI host controller driver
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@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 <linux/interrupt.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/pci.h>
+
+#define AR71XX_PCI_MEM_BASE 0x10000000
+#define AR71XX_PCI_MEM_SIZE 0x08000000
+
+#define AR71XX_PCI_WIN0_OFFS 0x10000000
+#define AR71XX_PCI_WIN1_OFFS 0x11000000
+#define AR71XX_PCI_WIN2_OFFS 0x12000000
+#define AR71XX_PCI_WIN3_OFFS 0x13000000
+#define AR71XX_PCI_WIN4_OFFS 0x14000000
+#define AR71XX_PCI_WIN5_OFFS 0x15000000
+#define AR71XX_PCI_WIN6_OFFS 0x16000000
+#define AR71XX_PCI_WIN7_OFFS 0x07000000
+
+#define AR71XX_PCI_CFG_BASE \
+ (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000)
+#define AR71XX_PCI_CFG_SIZE 0x100
+
+#define AR71XX_PCI_REG_CRP_AD_CBE 0x00
+#define AR71XX_PCI_REG_CRP_WRDATA 0x04
+#define AR71XX_PCI_REG_CRP_RDDATA 0x08
+#define AR71XX_PCI_REG_CFG_AD 0x0c
+#define AR71XX_PCI_REG_CFG_CBE 0x10
+#define AR71XX_PCI_REG_CFG_WRDATA 0x14
+#define AR71XX_PCI_REG_CFG_RDDATA 0x18
+#define AR71XX_PCI_REG_PCI_ERR 0x1c
+#define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20
+#define AR71XX_PCI_REG_AHB_ERR 0x24
+#define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28
+
+#define AR71XX_PCI_CRP_CMD_WRITE 0x00010000
+#define AR71XX_PCI_CRP_CMD_READ 0x00000000
+#define AR71XX_PCI_CFG_CMD_READ 0x0000000a
+#define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b
+
+#define AR71XX_PCI_INT_CORE BIT(4)
+#define AR71XX_PCI_INT_DEV2 BIT(2)
+#define AR71XX_PCI_INT_DEV1 BIT(1)
+#define AR71XX_PCI_INT_DEV0 BIT(0)
+
+#define AR71XX_PCI_IRQ_COUNT 5
+
+static DEFINE_SPINLOCK(ar71xx_pci_lock);
+static void __iomem *ar71xx_pcicfg_base;
+
+/* Byte lane enable bits */
+static const u8 ar71xx_pci_ble_table[4][4] = {
+ {0x0, 0xf, 0xf, 0xf},
+ {0xe, 0xd, 0xb, 0x7},
+ {0xc, 0xf, 0x3, 0xf},
+ {0xf, 0xf, 0xf, 0xf},
+};
+
+static const u32 ar71xx_pci_read_mask[8] = {
+ 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0
+};
+
+static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
+{
+ u32 t;
+
+ t = ar71xx_pci_ble_table[size & 3][where & 3];
+ BUG_ON(t == 0xf);
+ t <<= (local) ? 20 : 4;
+
+ return t;
+}
+
+static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ u32 ret;
+
+ if (!bus->number) {
+ /* type 0 */
+ ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) |
+ (where & ~3);
+ } else {
+ /* type 1 */
+ ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) |
+ (PCI_FUNC(devfn) << 8) | (where & ~3) | 1;
+ }
+
+ return ret;
+}
+
+static int ar71xx_pci_check_error(int quiet)
+{
+ void __iomem *base = ar71xx_pcicfg_base;
+ u32 pci_err;
+ u32 ahb_err;
+
+ pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3;
+ if (pci_err) {
+ if (!quiet) {
+ u32 addr;
+
+ addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR);
+ pr_crit("ar71xx: %s bus error %d at addr 0x%x\n",
+ "PCI", pci_err, addr);
+ }
+
+ /* clear PCI error status */
+ __raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR);
+ }
+
+ ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1;
+ if (ahb_err) {
+ if (!quiet) {
+ u32 addr;
+
+ addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR);
+ pr_crit("ar71xx: %s bus error %d at addr 0x%x\n",
+ "AHB", ahb_err, addr);
+ }
+
+ /* clear AHB error status */
+ __raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR);
+ }
+
+ return !!(ahb_err | pci_err);
+}
+
+static inline void ar71xx_pci_local_write(int where, int size, u32 value)
+{
+ void __iomem *base = ar71xx_pcicfg_base;
+ u32 ad_cbe;
+
+ value = value << (8 * (where & 3));
+
+ ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3);
+ ad_cbe |= ar71xx_pci_get_ble(where, size, 1);
+
+ __raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE);
+ __raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA);
+}
+
+static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus,
+ unsigned int devfn,
+ int where, int size, u32 cmd)
+{
+ void __iomem *base = ar71xx_pcicfg_base;
+ u32 addr;
+
+ addr = ar71xx_pci_bus_addr(bus, devfn, where);
+
+ __raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD);
+ __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0),
+ base + AR71XX_PCI_REG_CFG_CBE);
+
+ return ar71xx_pci_check_error(1);
+}
+
+static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ void __iomem *base = ar71xx_pcicfg_base;
+ unsigned long flags;
+ u32 data;
+ int err;
+ int ret;
+
+ ret = PCIBIOS_SUCCESSFUL;
+ data = ~0;
+
+ spin_lock_irqsave(&ar71xx_pci_lock, flags);
+
+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
+ AR71XX_PCI_CFG_CMD_READ);
+ if (err)
+ ret = PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA);
+
+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
+
+ *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7];
+
+ return ret;
+}
+
+static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ void __iomem *base = ar71xx_pcicfg_base;
+ unsigned long flags;
+ int err;
+ int ret;
+
+ value = value << (8 * (where & 3));
+ ret = PCIBIOS_SUCCESSFUL;
+
+ spin_lock_irqsave(&ar71xx_pci_lock, flags);
+
+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
+ AR71XX_PCI_CFG_CMD_WRITE);
+ if (err)
+ ret = PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA);
+
+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
+
+ return ret;
+}
+
+static struct pci_ops ar71xx_pci_ops = {
+ .read = ar71xx_pci_read_config,
+ .write = ar71xx_pci_write_config,
+};
+
+static struct resource ar71xx_pci_io_resource = {
+ .name = "PCI IO space",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IO,
+};
+
+static struct resource ar71xx_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 ar71xx_pci_controller = {
+ .pci_ops = &ar71xx_pci_ops,
+ .mem_resource = &ar71xx_pci_mem_resource,
+ .io_resource = &ar71xx_pci_io_resource,
+};
+
+static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 pending;
+
+ pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+
+ if (pending & AR71XX_PCI_INT_DEV0)
+ generic_handle_irq(ATH79_PCI_IRQ(0));
+
+ else if (pending & AR71XX_PCI_INT_DEV1)
+ generic_handle_irq(ATH79_PCI_IRQ(1));
+
+ else if (pending & AR71XX_PCI_INT_DEV2)
+ generic_handle_irq(ATH79_PCI_IRQ(2));
+
+ else if (pending & AR71XX_PCI_INT_CORE)
+ generic_handle_irq(ATH79_PCI_IRQ(4));
+
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_pci_irq_unmask(struct irq_data *d)
+{
+ unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE;
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+}
+
+static void ar71xx_pci_irq_mask(struct irq_data *d)
+{
+ unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE;
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+}
+
+static struct irq_chip ar71xx_pci_irq_chip = {
+ .name = "AR71XX PCI",
+ .irq_mask = ar71xx_pci_irq_mask,
+ .irq_unmask = ar71xx_pci_irq_unmask,
+ .irq_mask_ack = ar71xx_pci_irq_mask,
+};
+
+static __init void ar71xx_pci_irq_init(void)
+{
+ void __iomem *base = ath79_reset_base;
+ int i;
+
+ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
+
+ BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT);
+
+ for (i = ATH79_PCI_IRQ_BASE;
+ i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++)
+ irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip,
+ handle_level_irq);
+
+ irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler);
+}
+
+static __init void ar71xx_pci_reset(void)
+{
+ void __iomem *ddr_base = ath79_ddr_base;
+
+ ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
+ mdelay(100);
+
+ ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
+ mdelay(100);
+
+ __raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0);
+ __raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1);
+ __raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2);
+ __raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3);
+ __raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4);
+ __raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5);
+ __raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6);
+ __raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7);
+
+ mdelay(100);
+}
+
+__init int ar71xx_pcibios_init(void)
+{
+ u32 t;
+
+ ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE);
+ if (ar71xx_pcicfg_base == NULL)
+ return -ENOMEM;
+
+ ar71xx_pci_reset();
+
+ /* setup COMMAND register */
+ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
+ ar71xx_pci_local_write(PCI_COMMAND, 4, t);
+
+ /* clear bus errors */
+ ar71xx_pci_check_error(1);
+
+ ar71xx_pci_irq_init();
+
+ register_pci_controller(&ar71xx_pci_controller);
+
+ return 0;
+}
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c
new file mode 100644
index 00000000000..414a7459858
--- /dev/null
+++ b/arch/mips/pci/pci-ar724x.c
@@ -0,0 +1,292 @@
+/*
+ * Atheros AR724X PCI host controller driver
+ *
+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/irq.h>
+#include <linux/pci.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/pci.h>
+
+#define AR724X_PCI_CFG_BASE 0x14000000
+#define AR724X_PCI_CFG_SIZE 0x1000
+#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000)
+#define AR724X_PCI_CTRL_SIZE 0x100
+
+#define AR724X_PCI_MEM_BASE 0x10000000
+#define AR724X_PCI_MEM_SIZE 0x08000000
+
+#define AR724X_PCI_REG_INT_STATUS 0x4c
+#define AR724X_PCI_REG_INT_MASK 0x50
+
+#define AR724X_PCI_INT_DEV0 BIT(14)
+
+#define AR724X_PCI_IRQ_COUNT 1
+
+#define AR7240_BAR0_WAR_VALUE 0xffff
+
+static DEFINE_SPINLOCK(ar724x_pci_lock);
+static void __iomem *ar724x_pci_devcfg_base;
+static void __iomem *ar724x_pci_ctrl_base;
+
+static u32 ar724x_pci_bar0_value;
+static bool ar724x_pci_bar0_is_cached;
+
+static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, uint32_t *value)
+{
+ unsigned long flags;
+ void __iomem *base;
+ u32 data;
+
+ if (devfn)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ base = ar724x_pci_devcfg_base;
+
+ 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;
+ case 4:
+ break;
+ default:
+ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+
+ if (where == PCI_BASE_ADDRESS_0 && size == 4 &&
+ ar724x_pci_bar0_is_cached) {
+ /* use the cached value */
+ *value = ar724x_pci_bar0_value;
+ } else {
+ *value = data;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, uint32_t value)
+{
+ unsigned long flags;
+ void __iomem *base;
+ u32 data;
+ int s;
+
+ if (devfn)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) {
+ if (value != 0xffffffff) {
+ /*
+ * WAR for a hw issue. If the BAR0 register of the
+ * device is set to the proper base address, the
+ * memory space of the device is not accessible.
+ *
+ * Cache the intended value so it can be read back,
+ * and write a SoC specific constant value to the
+ * BAR0 register in order to make the device memory
+ * accessible.
+ */
+ ar724x_pci_bar0_is_cached = true;
+ ar724x_pci_bar0_value = value;
+
+ value = AR7240_BAR0_WAR_VALUE;
+ } else {
+ ar724x_pci_bar0_is_cached = false;
+ }
+ }
+
+ base = ar724x_pci_devcfg_base;
+
+ spin_lock_irqsave(&ar724x_pci_lock, flags);
+ data = __raw_readl(base + (where & ~3));
+
+ switch (size) {
+ case 1:
+ s = ((where & 3) * 8);
+ data &= ~(0xff << s);
+ data |= ((value & 0xff) << s);
+ break;
+ case 2:
+ s = ((where & 2) * 8);
+ data &= ~(0xffff << s);
+ data |= ((value & 0xffff) << s);
+ break;
+ case 4:
+ data = value;
+ break;
+ default:
+ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ __raw_writel(data, base + (where & ~3));
+ /* flush write */
+ __raw_readl(base + (where & ~3));
+ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ar724x_pci_ops = {
+ .read = ar724x_pci_read,
+ .write = ar724x_pci_write,
+};
+
+static struct resource ar724x_io_resource = {
+ .name = "PCI IO space",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IO,
+};
+
+static struct resource ar724x_mem_resource = {
+ .name = "PCI memory space",
+ .start = AR724X_PCI_MEM_BASE,
+ .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct pci_controller ar724x_pci_controller = {
+ .pci_ops = &ar724x_pci_ops,
+ .io_resource = &ar724x_io_resource,
+ .mem_resource = &ar724x_mem_resource,
+};
+
+static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *base;
+ u32 pending;
+
+ base = ar724x_pci_ctrl_base;
+
+ pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
+ __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+
+ if (pending & AR724X_PCI_INT_DEV0)
+ generic_handle_irq(ATH79_PCI_IRQ(0));
+
+ else
+ spurious_interrupt();
+}
+
+static void ar724x_pci_irq_unmask(struct irq_data *d)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ar724x_pci_ctrl_base;
+
+ switch (d->irq) {
+ case ATH79_PCI_IRQ(0):
+ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+ __raw_writel(t | AR724X_PCI_INT_DEV0,
+ base + AR724X_PCI_REG_INT_MASK);
+ /* flush write */
+ __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+ }
+}
+
+static void ar724x_pci_irq_mask(struct irq_data *d)
+{
+ void __iomem *base;
+ u32 t;
+
+ base = ar724x_pci_ctrl_base;
+
+ switch (d->irq) {
+ case ATH79_PCI_IRQ(0):
+ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+ __raw_writel(t & ~AR724X_PCI_INT_DEV0,
+ base + AR724X_PCI_REG_INT_MASK);
+
+ /* flush write */
+ __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+
+ t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
+ __raw_writel(t | AR724X_PCI_INT_DEV0,
+ base + AR724X_PCI_REG_INT_STATUS);
+
+ /* flush write */
+ __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
+ }
+}
+
+static struct irq_chip ar724x_pci_irq_chip = {
+ .name = "AR724X PCI ",
+ .irq_mask = ar724x_pci_irq_mask,
+ .irq_unmask = ar724x_pci_irq_unmask,
+ .irq_mask_ack = ar724x_pci_irq_mask,
+};
+
+static void __init ar724x_pci_irq_init(int irq)
+{
+ void __iomem *base;
+ int i;
+
+ base = ar724x_pci_ctrl_base;
+
+ __raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
+ __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
+
+ BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
+
+ for (i = ATH79_PCI_IRQ_BASE;
+ i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++)
+ irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
+ handle_level_irq);
+
+ irq_set_chained_handler(irq, ar724x_pci_irq_handler);
+}
+
+int __init ar724x_pcibios_init(int irq)
+{
+ int ret;
+
+ ret = -ENOMEM;
+
+ ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
+ AR724X_PCI_CFG_SIZE);
+ if (ar724x_pci_devcfg_base == NULL)
+ goto err;
+
+ ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE,
+ AR724X_PCI_CTRL_SIZE);
+ if (ar724x_pci_ctrl_base == NULL)
+ goto err_unmap_devcfg;
+
+ ar724x_pci_irq_init(irq);
+ register_pci_controller(&ar724x_pci_controller);
+
+ return PCIBIOS_SUCCESSFUL;
+
+err_unmap_devcfg:
+ iounmap(ar724x_pci_devcfg_base);
+err:
+ return ret;
+}
diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c
deleted file mode 100644
index a4dd24a4130..00000000000
--- a/arch/mips/pci/pci-ath724x.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Atheros 724x PCI support
- *
- * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
- *
- * 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/pci.h>
-#include <asm/mach-ath79/pci-ath724x.h>
-
-#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys))
-#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val))
-
-#define ATH724X_PCI_DEV_BASE 0x14000000
-#define ATH724X_PCI_MEM_BASE 0x10000000
-#define ATH724X_PCI_MEM_SIZE 0x08000000
-
-static DEFINE_SPINLOCK(ath724x_pci_lock);
-static struct ath724x_pci_data *pci_data;
-static int pci_data_size;
-
-static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
- int size, uint32_t *value)
-{
- unsigned long flags, addr, tval, mask;
-
- if (devfn)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (where & (size - 1))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- spin_lock_irqsave(&ath724x_pci_lock, flags);
-
- switch (size) {
- case 1:
- addr = where & ~3;
- mask = 0xff000000 >> ((where % 4) * 8);
- tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
- tval = tval & ~mask;
- *value = (tval >> ((4 - (where % 4))*8));
- break;
- case 2:
- addr = where & ~3;
- mask = 0xffff0000 >> ((where % 4)*8);
- tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
- tval = tval & ~mask;
- *value = (tval >> ((4 - (where % 4))*8));
- break;
- case 4:
- *value = reg_read(ATH724X_PCI_DEV_BASE + where);
- break;
- default:
- spin_unlock_irqrestore(&ath724x_pci_lock, flags);
-
- return PCIBIOS_BAD_REGISTER_NUMBER;
- }
-
- spin_unlock_irqrestore(&ath724x_pci_lock, flags);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
- int size, uint32_t value)
-{
- unsigned long flags, tval, addr, mask;
-
- if (devfn)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (where & (size - 1))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- spin_lock_irqsave(&ath724x_pci_lock, flags);
-
- switch (size) {
- case 1:
- addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
- mask = 0xff000000 >> ((where % 4)*8);
- tval = reg_read(addr);
- tval = tval & ~mask;
- tval |= (value << ((4 - (where % 4))*8)) & mask;
- reg_write(addr, tval);
- break;
- case 2:
- addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
- mask = 0xffff0000 >> ((where % 4)*8);
- tval = reg_read(addr);
- tval = tval & ~mask;
- tval |= (value << ((4 - (where % 4))*8)) & mask;
- reg_write(addr, tval);
- break;
- case 4:
- reg_write((ATH724X_PCI_DEV_BASE + where), value);
- break;
- default:
- spin_unlock_irqrestore(&ath724x_pci_lock, flags);
-
- return PCIBIOS_BAD_REGISTER_NUMBER;
- }
-
- spin_unlock_irqrestore(&ath724x_pci_lock, flags);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops ath724x_pci_ops = {
- .read = ath724x_pci_read,
- .write = ath724x_pci_write,
-};
-
-static struct resource ath724x_io_resource = {
- .name = "PCI IO space",
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IO,
-};
-
-static struct resource ath724x_mem_resource = {
- .name = "PCI memory space",
- .start = ATH724X_PCI_MEM_BASE,
- .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct pci_controller ath724x_pci_controller = {
- .pci_ops = &ath724x_pci_ops,
- .io_resource = &ath724x_io_resource,
- .mem_resource = &ath724x_mem_resource,
-};
-
-void ath724x_pci_add_data(struct ath724x_pci_data *data, int size)
-{
- pci_data = data;
- pci_data_size = size;
-}
-
-int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
-{
- unsigned int devfn = dev->devfn;
- int irq = -1;
-
- if (devfn > pci_data_size - 1)
- return irq;
-
- irq = pci_data[devfn].irq;
-
- return irq;
-}
-
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- unsigned int devfn = dev->devfn;
-
- if (devfn > pci_data_size - 1)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- dev->dev.platform_data = pci_data[devfn].pdata;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int __init ath724x_pcibios_init(void)
-{
- register_pci_controller(&ath724x_pci_controller);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-arch_initcall(ath724x_pcibios_init);
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 0fbe4c0c170..fdc24440294 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -212,7 +212,7 @@ static inline void pci_enable_swapping(struct pci_dev *dev)
bridge->b_widget.w_tflush; /* Flush */
}
-static void __init pci_fixup_ioc3(struct pci_dev *d)
+static void __devinit pci_fixup_ioc3(struct pci_dev *d)
{
pci_disable_swapping(d);
}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 030c77e7926..075d87acd12 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -13,8 +13,12 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
#include <asm/pci.h>
#include <asm/gpio.h>
@@ -22,17 +26,9 @@
#include <lantiq_soc.h>
#include <lantiq_irq.h>
-#include <lantiq_platform.h>
#include "pci-lantiq.h"
-#define LTQ_PCI_CFG_BASE 0x17000000
-#define LTQ_PCI_CFG_SIZE 0x00008000
-#define LTQ_PCI_MEM_BASE 0x18000000
-#define LTQ_PCI_MEM_SIZE 0x02000000
-#define LTQ_PCI_IO_BASE 0x1AE00000
-#define LTQ_PCI_IO_SIZE 0x00200000
-
#define PCI_CR_FCI_ADDR_MAP0 0x00C0
#define PCI_CR_FCI_ADDR_MAP1 0x00C4
#define PCI_CR_FCI_ADDR_MAP2 0x00C8
@@ -68,79 +64,27 @@
#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y))
#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x))
-struct ltq_pci_gpio_map {
- int pin;
- int alt0;
- int alt1;
- int dir;
- char *name;
-};
-
-/* the pci core can make use of the following gpios */
-static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = {
- { 0, 1, 0, 0, "pci-exin0" },
- { 1, 1, 0, 0, "pci-exin1" },
- { 2, 1, 0, 0, "pci-exin2" },
- { 39, 1, 0, 0, "pci-exin3" },
- { 10, 1, 0, 0, "pci-exin4" },
- { 9, 1, 0, 0, "pci-exin5" },
- { 30, 1, 0, 1, "pci-gnt1" },
- { 23, 1, 0, 1, "pci-gnt2" },
- { 19, 1, 0, 1, "pci-gnt3" },
- { 38, 1, 0, 1, "pci-gnt4" },
- { 29, 1, 0, 0, "pci-req1" },
- { 31, 1, 0, 0, "pci-req2" },
- { 3, 1, 0, 0, "pci-req3" },
- { 37, 1, 0, 0, "pci-req4" },
-};
-
__iomem void *ltq_pci_mapped_cfg;
static __iomem void *ltq_pci_membase;
-int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
-
-/* Since the PCI REQ pins can be reused for other functionality, make it
- possible to exclude those from interpretation by the PCI controller */
-static int ltq_pci_req_mask = 0xf;
-
-static int *ltq_pci_irq_map;
-
-struct pci_ops ltq_pci_ops = {
+static int reset_gpio;
+static struct clk *clk_pci, *clk_external;
+static struct resource pci_io_resource;
+static struct resource pci_mem_resource;
+static struct pci_ops pci_ops = {
.read = ltq_pci_read_config_dword,
.write = ltq_pci_write_config_dword
};
-static struct resource pci_io_resource = {
- .name = "pci io space",
- .start = LTQ_PCI_IO_BASE,
- .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
- .flags = IORESOURCE_IO
-};
-
-static struct resource pci_mem_resource = {
- .name = "pci memory space",
- .start = LTQ_PCI_MEM_BASE,
- .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
- .flags = IORESOURCE_MEM
-};
-
-static struct pci_controller ltq_pci_controller = {
- .pci_ops = &ltq_pci_ops,
+static struct pci_controller pci_controller = {
+ .pci_ops = &pci_ops,
.mem_resource = &pci_mem_resource,
.mem_offset = 0x00000000UL,
.io_resource = &pci_io_resource,
.io_offset = 0x00000000UL,
};
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- if (ltqpci_plat_dev_init)
- return ltqpci_plat_dev_init(dev);
-
- return 0;
-}
-
-static u32 ltq_calc_bar11mask(void)
+static inline u32 ltq_calc_bar11mask(void)
{
u32 mem, bar11mask;
@@ -151,48 +95,42 @@ static u32 ltq_calc_bar11mask(void)
return bar11mask;
}
-static void ltq_pci_setup_gpio(int gpio)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) {
- if (gpio & (1 << i)) {
- ltq_gpio_request(ltq_pci_gpio_map[i].pin,
- ltq_pci_gpio_map[i].alt0,
- ltq_pci_gpio_map[i].alt1,
- ltq_pci_gpio_map[i].dir,
- ltq_pci_gpio_map[i].name);
- }
- }
- ltq_gpio_request(21, 0, 0, 1, "pci-reset");
- ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK;
-}
-
-static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
+static int __devinit ltq_pci_startup(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
+ const __be32 *req_mask, *bus_clk;
u32 temp_buffer;
- /* set clock to 33Mhz */
- if (ltq_is_ar9()) {
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR);
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR);
- } else {
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+ /* get our clocks */
+ clk_pci = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk_pci)) {
+ dev_err(&pdev->dev, "failed to get pci clock\n");
+ return PTR_ERR(clk_pci);
}
- /* external or internal clock ? */
- if (conf->clock) {
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
- LTQ_CGU_IFCCR);
- ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
- } else {
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
- LTQ_CGU_IFCCR);
- ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
+ clk_external = clk_get(&pdev->dev, "external");
+ if (IS_ERR(clk_external)) {
+ clk_put(clk_pci);
+ dev_err(&pdev->dev, "failed to get external pci clock\n");
+ return PTR_ERR(clk_external);
}
- /* setup pci clock and gpis used by pci */
- ltq_pci_setup_gpio(conf->gpio);
+ /* read the bus speed that we want */
+ bus_clk = of_get_property(node, "lantiq,bus-clock", NULL);
+ if (bus_clk)
+ clk_set_rate(clk_pci, *bus_clk);
+
+ /* and enable the clocks */
+ clk_enable(clk_pci);
+ if (of_find_property(node, "lantiq,external-clock", NULL))
+ clk_enable(clk_external);
+ else
+ clk_disable(clk_external);
+
+ /* setup reset gpio used by pci */
+ reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
+ if (gpio_is_valid(reset_gpio))
+ devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
/* enable auto-switching between PCI and EBU */
ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
@@ -205,7 +143,12 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
/* enable external 2 PCI masters */
temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
- temp_buffer &= (~(ltq_pci_req_mask << 16));
+ /* setup the request mask */
+ req_mask = of_get_property(node, "req-mask", NULL);
+ if (req_mask)
+ temp_buffer &= ~((*req_mask & 0xf) << 16);
+ else
+ temp_buffer &= ~0xf0000;
/* enable internal arbiter */
temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
/* enable internal PCI master reqest */
@@ -249,47 +192,55 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
/* toggle reset pin */
- __gpio_set_value(21, 0);
- wmb();
- mdelay(1);
- __gpio_set_value(21, 1);
- return 0;
-}
-
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- if (ltq_pci_irq_map[slot])
- return ltq_pci_irq_map[slot];
- printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n",
- slot);
-
+ if (gpio_is_valid(reset_gpio)) {
+ __gpio_set_value(reset_gpio, 0);
+ wmb();
+ mdelay(1);
+ __gpio_set_value(reset_gpio, 1);
+ }
return 0;
}
static int __devinit ltq_pci_probe(struct platform_device *pdev)
{
- struct ltq_pci_data *ltq_pci_data =
- (struct ltq_pci_data *) pdev->dev.platform_data;
+ struct resource *res_cfg, *res_bridge;
pci_clear_flags(PCI_PROBE_ONLY);
- ltq_pci_irq_map = ltq_pci_data->irq;
- ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
- ltq_pci_mapped_cfg =
- ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
- ltq_pci_controller.io_map_base =
- (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
- ltq_pci_startup(ltq_pci_data);
- register_pci_controller(&ltq_pci_controller);
+ res_cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res_bridge = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_cfg || !res_bridge) {
+ dev_err(&pdev->dev, "missing memory reources\n");
+ return -EINVAL;
+ }
+
+ ltq_pci_membase = devm_request_and_ioremap(&pdev->dev, res_bridge);
+ ltq_pci_mapped_cfg = devm_request_and_ioremap(&pdev->dev, res_cfg);
+
+ if (!ltq_pci_membase || !ltq_pci_mapped_cfg) {
+ dev_err(&pdev->dev, "failed to remap resources\n");
+ return -ENOMEM;
+ }
+
+ ltq_pci_startup(pdev);
+
+ pci_load_of_ranges(&pci_controller, pdev->dev.of_node);
+ register_pci_controller(&pci_controller);
return 0;
}
-static struct platform_driver
-ltq_pci_driver = {
+static const struct of_device_id ltq_pci_match[] = {
+ { .compatible = "lantiq,pci-xway" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ltq_pci_match);
+
+static struct platform_driver ltq_pci_driver = {
.probe = ltq_pci_probe,
.driver = {
- .name = "ltq_pci",
+ .name = "pci-xway",
.owner = THIS_MODULE,
+ .of_match_table = ltq_pci_match,
},
};
@@ -297,7 +248,7 @@ int __init pcibios_init(void)
{
int ret = platform_driver_register(&ltq_pci_driver);
if (ret)
- printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
+ pr_info("pci-xway: Error registering platform driver!");
return ret;
}
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
index 1644805a673..172af1cd586 100644
--- a/arch/mips/pci/pci-xlr.c
+++ b/arch/mips/pci/pci-xlr.c
@@ -41,6 +41,7 @@
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/console.h>
+#include <linux/pci_regs.h>
#include <asm/io.h>
@@ -156,35 +157,55 @@ struct pci_controller nlm_pci_controller = {
.io_offset = 0x00000000UL,
};
+/*
+ * The top level PCIe links on the XLS PCIe controller appear as
+ * bridges. Given a device, this function finds which link it is
+ * on.
+ */
+static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev)
+{
+ struct pci_bus *bus, *p;
+
+ /* Find the bridge on bus 0 */
+ bus = dev->bus;
+ for (p = bus->parent; p && p->number != 0; p = p->parent)
+ bus = p;
+
+ return p ? bus->self : NULL;
+}
+
static int get_irq_vector(const struct pci_dev *dev)
{
+ struct pci_dev *lnk;
+
if (!nlm_chip_is_xls())
- return PIC_PCIX_IRQ; /* for XLR just one IRQ*/
+ return PIC_PCIX_IRQ; /* for XLR just one IRQ */
/*
* For XLS PCIe, there is an IRQ per Link, find out which
* link the device is on to assign interrupts
- */
- if (dev->bus->self == NULL)
+ */
+ lnk = xls_get_pcie_link(dev);
+ if (lnk == NULL)
return 0;
- switch (dev->bus->self->devfn) {
- case 0x0:
+ switch (PCI_SLOT(lnk->devfn)) {
+ case 0:
return PIC_PCIE_LINK0_IRQ;
- case 0x8:
+ case 1:
return PIC_PCIE_LINK1_IRQ;
- case 0x10:
+ case 2:
if (nlm_chip_is_xls_b())
return PIC_PCIE_XLSB0_LINK2_IRQ;
else
return PIC_PCIE_LINK2_IRQ;
- case 0x18:
+ case 3:
if (nlm_chip_is_xls_b())
return PIC_PCIE_XLSB0_LINK3_IRQ;
else
return PIC_PCIE_LINK3_IRQ;
}
- WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+ WARN(1, "Unexpected devfn %d\n", lnk->devfn);
return 0;
}
@@ -202,7 +223,27 @@ void arch_teardown_msi_irq(unsigned int irq)
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
struct msi_msg msg;
+ struct pci_dev *lnk;
int irq, ret;
+ u16 val;
+
+ /* MSI not supported on XLR */
+ if (!nlm_chip_is_xls())
+ return 1;
+
+ /*
+ * Enable MSI on the XLS PCIe controller bridge which was disabled
+ * at enumeration, the bridge MSI capability is at 0x50
+ */
+ lnk = xls_get_pcie_link(dev);
+ if (lnk == NULL)
+ return 1;
+
+ pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val);
+ if ((val & PCI_MSI_FLAGS_ENABLE) == 0) {
+ val |= PCI_MSI_FLAGS_ENABLE;
+ pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val);
+ }
irq = get_irq_vector(dev);
if (irq <= 0)
@@ -327,7 +368,7 @@ static int __init pcibios_init(void)
}
} else {
/* XLR PCI controller ACK */
- irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+ irq_set_handler_data(PIC_PCIX_IRQ, xlr_pci_ack);
}
return 0;
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 0514866fa92..271e8c4a54c 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/of_address.h>
#include <asm/cpu-info.h>
@@ -114,9 +115,63 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
pci_bus_assign_resources(bus);
pci_enable_bridges(bus);
}
+ bus->dev.of_node = hose->of_node;
}
}
+#ifdef CONFIG_OF
+void __devinit pci_load_of_ranges(struct pci_controller *hose,
+ struct device_node *node)
+{
+ const __be32 *ranges;
+ int rlen;
+ int pna = of_n_addr_cells(node);
+ int np = pna + 5;
+
+ pr_info("PCI host bridge %s ranges:\n", node->full_name);
+ ranges = of_get_property(node, "ranges", &rlen);
+ if (ranges == NULL)
+ return;
+ hose->of_node = node;
+
+ while ((rlen -= np * 4) >= 0) {
+ u32 pci_space;
+ struct resource *res = NULL;
+ u64 addr, size;
+
+ pci_space = be32_to_cpup(&ranges[0]);
+ addr = of_translate_address(node, ranges + 3);
+ size = of_read_number(ranges + pna + 3, 2);
+ ranges += np;
+ switch ((pci_space >> 24) & 0x3) {
+ case 1: /* PCI IO space */
+ pr_info(" IO 0x%016llx..0x%016llx\n",
+ addr, addr + size - 1);
+ hose->io_map_base =
+ (unsigned long)ioremap(addr, size);
+ res = hose->io_resource;
+ res->flags = IORESOURCE_IO;
+ break;
+ case 2: /* PCI Memory space */
+ case 3: /* PCI 64 bits Memory space */
+ pr_info(" MEM 0x%016llx..0x%016llx\n",
+ addr, addr + size - 1);
+ res = hose->mem_resource;
+ res->flags = IORESOURCE_MEM;
+ break;
+ }
+ if (res != NULL) {
+ res->start = addr;
+ res->name = node->full_name;
+ res->end = res->start + size - 1;
+ res->parent = NULL;
+ res->sibling = NULL;
+ res->child = NULL;
+ }
+ }
+}
+#endif
+
static DEFINE_MUTEX(pci_scan_mutex);
void __devinit register_pci_controller(struct pci_controller *hose)