atheros: v3.18: remap main SoC MMR memory
[openwrt/svn-archive/archive.git] / target / linux / atheros / patches-3.18 / 105-ar2315_pci.patch
index e5a8a52a8c50068118fdf73a46daaec80de2bbdb..6665a1138b41a87599aa8d76fdf08c29a4e3fc6a 100644 (file)
@@ -10,7 +10,7 @@
  obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o
 --- /dev/null
 +++ b/arch/mips/pci/pci-ar2315.c
-@@ -0,0 +1,345 @@
+@@ -0,0 +1,494 @@
 +/*
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +#include <linux/irq.h>
 +#include <linux/io.h>
 +#include <asm/paccess.h>
-+#include <ar231x_platform.h>
-+#include <ar231x.h>
-+#include <ar2315_regs.h>
++
++/*
++ * PCI Bus Interface Registers
++ */
++#define AR2315_PCI_1MS_REG            0x0008
++
++#define AR2315_PCI_1MS_MASK           0x3FFFF /* # of AHB clk cycles in 1ms */
++
++#define AR2315_PCI_MISC_CONFIG                0x000c
++
++#define AR2315_PCIMISC_TXD_EN 0x00000001      /* Enable TXD for fragments */
++#define AR2315_PCIMISC_CFG_SEL        0x00000002      /* Mem or Config cycles */
++#define AR2315_PCIMISC_GIG_MASK       0x0000000C      /* bits 31-30 for pci req */
++#define AR2315_PCIMISC_RST_MODE       0x00000030
++#define AR2315_PCIRST_INPUT   0x00000000      /* 4:5=0 rst is input */
++#define AR2315_PCIRST_LOW     0x00000010      /* 4:5=1 rst to GND */
++#define AR2315_PCIRST_HIGH    0x00000020      /* 4:5=2 rst to VDD */
++#define AR2315_PCIGRANT_EN    0x00000000      /* 6:7=0 early grant en */
++#define AR2315_PCIGRANT_FRAME 0x00000040      /* 6:7=1 grant waits 4 frame */
++#define AR2315_PCIGRANT_IDLE  0x00000080      /* 6:7=2 grant waits 4 idle */
++#define AR2315_PCIGRANT_GAP   0x00000000      /* 6:7=2 grant waits 4 idle */
++#define AR2315_PCICACHE_DIS   0x00001000      /* PCI external access cache
++                                               * disable */
++
++#define AR2315_PCI_OUT_TSTAMP         0x0010
++
++#define AR2315_PCI_UNCACHE_CFG                0x0014
++
++#define AR2315_PCI_IN_EN              0x0100
++
++#define AR2315_PCI_IN_EN0     0x01    /* Enable chain 0 */
++#define AR2315_PCI_IN_EN1     0x02    /* Enable chain 1 */
++#define AR2315_PCI_IN_EN2     0x04    /* Enable chain 2 */
++#define AR2315_PCI_IN_EN3     0x08    /* Enable chain 3 */
++
++#define AR2315_PCI_IN_DIS             0x0104
++
++#define AR2315_PCI_IN_DIS0    0x01    /* Disable chain 0 */
++#define AR2315_PCI_IN_DIS1    0x02    /* Disable chain 1 */
++#define AR2315_PCI_IN_DIS2    0x04    /* Disable chain 2 */
++#define AR2315_PCI_IN_DIS3    0x08    /* Disable chain 3 */
++
++#define AR2315_PCI_IN_PTR             0x0200
++
++#define AR2315_PCI_OUT_EN             0x0400
++
++#define AR2315_PCI_OUT_EN0    0x01    /* Enable chain 0 */
++
++#define AR2315_PCI_OUT_DIS            0x0404
++
++#define AR2315_PCI_OUT_DIS0   0x01    /* Disable chain 0 */
++
++#define AR2315_PCI_OUT_PTR            0x0408
++
++/* PCI interrupt status (write one to clear) */
++#define AR2315_PCI_ISR                        0x0500
++
++#define AR2315_PCI_INT_TX     0x00000001      /* Desc In Completed */
++#define AR2315_PCI_INT_TXOK   0x00000002      /* Desc In OK */
++#define AR2315_PCI_INT_TXERR  0x00000004      /* Desc In ERR */
++#define AR2315_PCI_INT_TXEOL  0x00000008      /* Desc In End-of-List */
++#define AR2315_PCI_INT_RX     0x00000010      /* Desc Out Completed */
++#define AR2315_PCI_INT_RXOK   0x00000020      /* Desc Out OK */
++#define AR2315_PCI_INT_RXERR  0x00000040      /* Desc Out ERR */
++#define AR2315_PCI_INT_RXEOL  0x00000080      /* Desc Out EOL */
++#define AR2315_PCI_INT_TXOOD  0x00000200      /* Desc In Out-of-Desc */
++#define AR2315_PCI_INT_DESCMASK       0x0000FFFF      /* Desc Mask */
++#define AR2315_PCI_INT_EXT    0x02000000      /* Extern PCI INTA */
++#define AR2315_PCI_INT_ABORT  0x04000000      /* PCI bus abort event */
++
++/* PCI interrupt mask */
++#define AR2315_PCI_IMR                        0x0504
++
++/* Global PCI interrupt enable */
++#define AR2315_PCI_IER                        0x0508
++
++#define AR2315_PCI_IER_DISABLE                0x00    /* disable pci interrupts */
++#define AR2315_PCI_IER_ENABLE         0x01    /* enable pci interrupts */
++
++#define AR2315_PCI_HOST_IN_EN         0x0800
++#define AR2315_PCI_HOST_IN_DIS                0x0804
++#define AR2315_PCI_HOST_IN_PTR                0x0810
++#define AR2315_PCI_HOST_OUT_EN                0x0900
++#define AR2315_PCI_HOST_OUT_DIS               0x0904
++#define AR2315_PCI_HOST_OUT_PTR               0x0908
++
++/*
++ * PCI interrupts, which share IP5
++ * Keep ordered according to AR2315_PCI_INT_XXX bits
++ */
++#define AR2315_PCI_IRQ_BASE           0x50
++#define AR2315_PCI_IRQ_EXT            (AR2315_PCI_IRQ_BASE+0)
++#define AR2315_PCI_IRQ_ABORT          (AR2315_PCI_IRQ_BASE+1)
++#define AR2315_PCI_IRQ_COUNT          2
++#define AR2315_PCI_IRQ_SHIFT          25      /* in AR2315_PCI_INT_STATUS */
 +
 +/* Arbitrary size of memory region to access the configuration space */
 +#define AR2315_PCI_CFG_SIZE   0x00100000
 +#define AR2315_PCI_HOST_SLOT  3
 +#define AR2315_PCI_HOST_DEVID ((0xff18 << 16) | PCI_VENDOR_ID_ATHEROS)
 +
-+static void __iomem *ar2315_pci_cfg_mem;
++/* ??? access BAR */
++#define AR2315_PCI_HOST_MBAR0         0x10000000
++/* RAM access BAR */
++#define AR2315_PCI_HOST_MBAR1         AR2315_PCI_HOST_SDRAM_BASEADDR
++/* ??? access BAR */
++#define AR2315_PCI_HOST_MBAR2         0x30000000
++
++struct ar2315_pci_ctrl {
++      void __iomem *cfg_mem;
++      void __iomem *mmr_mem;
++      unsigned irq;
++      struct pci_controller pci_ctrl;
++      struct resource mem_res;
++      struct resource io_res;
++};
++
++static inline struct ar2315_pci_ctrl *ar2315_pci_bus_to_apc(struct pci_bus *bus)
++{
++      struct pci_controller *hose = bus->sysdata;
++
++      return container_of(hose, struct ar2315_pci_ctrl, pci_ctrl);
++}
++
++static inline u32 ar2315_pci_reg_read(struct ar2315_pci_ctrl *apc, u32 reg)
++{
++      return __raw_readl(apc->mmr_mem + reg);
++}
++
++static inline void ar2315_pci_reg_write(struct ar2315_pci_ctrl *apc, u32 reg,
++                                      u32 val)
++{
++      __raw_writel(val, apc->mmr_mem + reg);
++}
 +
-+static int ar2315_pci_cfg_access(int devfn, int where, int size, u32 *ptr,
-+                               bool write)
++static inline void ar2315_pci_reg_mask(struct ar2315_pci_ctrl *apc, u32 reg,
++                                     u32 mask, u32 val)
++{
++      u32 ret = ar2315_pci_reg_read(apc, reg);
++
++      ret &= ~mask;
++      ret |= val;
++      ar2315_pci_reg_write(apc, reg, ret);
++}
++
++static int ar2315_pci_cfg_access(struct ar2315_pci_ctrl *apc, unsigned devfn,
++                               int where, int size, u32 *ptr, bool write)
 +{
 +      int func = PCI_FUNC(devfn);
 +      int dev = PCI_SLOT(devfn);
 +              return PCIBIOS_DEVICE_NOT_FOUND;
 +
 +      /* Clear pending errors */
-+      ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
++      ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
 +      /* Select Configuration access */
-+      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, 0, AR2315_PCIMISC_CFG_SEL);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, 0,
++                          AR2315_PCIMISC_CFG_SEL);
 +
 +      mb();   /* PCI must see space change before we begin */
 +
-+      value = __raw_readl(ar2315_pci_cfg_mem + addr);
++      value = __raw_readl(apc->cfg_mem + addr);
++
++      isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
 +
-+      isr = ar231x_read_reg(AR2315_PCI_ISR);
 +      if (isr & AR2315_PCI_INT_ABORT)
 +              goto exit_err;
 +
 +      if (write) {
 +              value = (value & ~(mask << sh)) | *ptr << sh;
-+              __raw_writel(value, ar2315_pci_cfg_mem + addr);
-+              isr = ar231x_read_reg(AR2315_PCI_ISR);
++              __raw_writel(value, apc->cfg_mem + addr);
++              isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
 +              if (isr & AR2315_PCI_INT_ABORT)
 +                      goto exit_err;
 +      } else {
 +      goto exit;
 +
 +exit_err:
-+      ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
++      ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
 +      if (!write)
 +              *ptr = 0xffffffff;
 +
 +exit:
 +      /* Select Memory access */
-+      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL, 0);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL,
++                          0);
 +
 +      return isr & AR2315_PCI_INT_ABORT ? PCIBIOS_DEVICE_NOT_FOUND :
 +                                          PCIBIOS_SUCCESSFUL;
 +}
 +
-+static inline int ar2315_pci_local_cfg_rd(unsigned devfn, int where, u32 *val)
++static inline int ar2315_pci_local_cfg_rd(struct ar2315_pci_ctrl *apc,
++                                        unsigned devfn, int where, u32 *val)
 +{
-+      return ar2315_pci_cfg_access(devfn, where, sizeof(u32), val, false);
++      return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), val,
++                                   false);
 +}
 +
-+static inline int ar2315_pci_local_cfg_wr(unsigned devfn, int where, u32 val)
++static inline int ar2315_pci_local_cfg_wr(struct ar2315_pci_ctrl *apc,
++                                        unsigned devfn, int where, u32 val)
 +{
-+      return ar2315_pci_cfg_access(devfn, where, sizeof(u32), &val, true);
++      return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), &val,
++                                   true);
 +}
 +
-+static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned int devfn,
-+                             int where, int size, u32 *value)
++static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned devfn, int where,
++                             int size, u32 *value)
 +{
++      struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus);
++
 +      if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
 +              return PCIBIOS_DEVICE_NOT_FOUND;
 +
-+      return ar2315_pci_cfg_access(devfn, where, size, value, 0);
++      return ar2315_pci_cfg_access(apc, devfn, where, size, value, false);
 +}
 +
-+static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned int devfn,
-+                              int where, int size, u32 value)
++static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned devfn, int where,
++                              int size, u32 value)
 +{
++      struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus);
++
 +      if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
 +              return PCIBIOS_DEVICE_NOT_FOUND;
 +
-+      return ar2315_pci_cfg_access(devfn, where, size, &value, 1);
++      return ar2315_pci_cfg_access(apc, devfn, where, size, &value, true);
 +}
 +
 +static struct pci_ops ar2315_pci_ops = {
 +      .write  = ar2315_pci_cfg_write,
 +};
 +
-+static struct resource ar2315_mem_resource = {
-+      .name   = "ar2315-pci-mem",
-+      .start  = AR2315_PCIEXT,
-+      .end    = AR2315_PCIEXT + AR2315_PCIEXT_SZ - 1,
-+      .flags  = IORESOURCE_MEM,
-+};
-+
-+/* PCI controller does not support I/O ports */
-+static struct resource ar2315_io_resource = {
-+      .name   = "ar2315-pci-io",
-+      .start  = 0,
-+      .end    = 0,
-+      .flags  = IORESOURCE_IO,
-+};
-+
-+static struct pci_controller ar2315_pci_controller = {
-+      .pci_ops        = &ar2315_pci_ops,
-+      .mem_resource   = &ar2315_mem_resource,
-+      .io_resource    = &ar2315_io_resource,
-+      .mem_offset     = 0x00000000UL,
-+      .io_offset      = 0x00000000UL,
-+};
-+
-+static int ar2315_pci_host_setup(void)
++static int ar2315_pci_host_setup(struct ar2315_pci_ctrl *apc)
 +{
 +      unsigned devfn = PCI_DEVFN(AR2315_PCI_HOST_SLOT, 0);
 +      int res;
 +      u32 id;
 +
-+      res = ar2315_pci_local_cfg_rd(devfn, PCI_VENDOR_ID, &id);
++      res = ar2315_pci_local_cfg_rd(apc, devfn, PCI_VENDOR_ID, &id);
 +      if (res != PCIBIOS_SUCCESSFUL || id != AR2315_PCI_HOST_DEVID)
 +              return -ENODEV;
 +
 +      /* Program MBARs */
-+      ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_0,
++      ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_0,
 +                              AR2315_PCI_HOST_MBAR0);
-+      ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_1,
++      ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_1,
 +                              AR2315_PCI_HOST_MBAR1);
-+      ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_2,
++      ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_2,
 +                              AR2315_PCI_HOST_MBAR2);
 +
 +      /* Run */
-+      ar2315_pci_local_cfg_wr(devfn, PCI_COMMAND, PCI_COMMAND_MEMORY |
++      ar2315_pci_local_cfg_wr(apc, devfn, PCI_COMMAND, PCI_COMMAND_MEMORY |
 +                              PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL |
 +                              PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
 +                              PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK);
 +
 +static void ar2315_pci_irq_handler(unsigned irq, struct irq_desc *desc)
 +{
-+      u32 pending = ar231x_read_reg(AR2315_PCI_ISR) &
-+                    ar231x_read_reg(AR2315_PCI_IMR);
++      struct ar2315_pci_ctrl *apc = irq_get_handler_data(irq);
++      u32 pending = ar2315_pci_reg_read(apc, AR2315_PCI_ISR) &
++                    ar2315_pci_reg_read(apc, AR2315_PCI_IMR);
 +
 +      if (pending & AR2315_PCI_INT_EXT)
 +              generic_handle_irq(AR2315_PCI_IRQ_EXT);
 +
 +static void ar2315_pci_irq_mask(struct irq_data *d)
 +{
++      struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
 +      u32 m = 1 << (d->irq - AR2315_PCI_IRQ_BASE + AR2315_PCI_IRQ_SHIFT);
 +
-+      ar231x_mask_reg(AR2315_PCI_IMR, m, 0);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, m, 0);
 +}
 +
 +static void ar2315_pci_irq_mask_ack(struct irq_data *d)
 +{
++      struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
 +      u32 m = 1 << (d->irq - AR2315_PCI_IRQ_BASE + AR2315_PCI_IRQ_SHIFT);
 +
-+      ar231x_mask_reg(AR2315_PCI_IMR, m, 0);
-+      ar231x_write_reg(AR2315_PCI_ISR, m);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, m, 0);
++      ar2315_pci_reg_write(apc, AR2315_PCI_ISR, m);
 +}
 +
 +static void ar2315_pci_irq_unmask(struct irq_data *d)
 +{
++      struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d);
 +      u32 m = 1 << (d->irq - AR2315_PCI_IRQ_BASE + AR2315_PCI_IRQ_SHIFT);
 +
-+      ar231x_mask_reg(AR2315_PCI_IMR, 0, m);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, 0, m);
 +}
 +
 +static struct irq_chip ar2315_pci_irq_chip = {
 +      .irq_unmask = ar2315_pci_irq_unmask,
 +};
 +
-+static void ar2315_pci_irq_init(void)
++static void ar2315_pci_irq_init(struct ar2315_pci_ctrl *apc)
 +{
 +      int i;
 +
-+      ar231x_mask_reg(AR2315_PCI_IER, AR2315_PCI_IER_ENABLE, 0);
-+      ar231x_mask_reg(AR2315_PCI_IMR, (AR2315_PCI_INT_ABORT |
-+                       AR2315_PCI_INT_EXT), 0);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IER, AR2315_PCI_IER_ENABLE, 0);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, (AR2315_PCI_INT_ABORT |
++                          AR2315_PCI_INT_EXT), 0);
 +
 +      for (i = 0; i < AR2315_PCI_IRQ_COUNT; ++i) {
 +              int irq = AR2315_PCI_IRQ_BASE + i;
 +
 +              irq_set_chip_and_handler(irq, &ar2315_pci_irq_chip,
 +                                       handle_level_irq);
++              irq_set_chip_data(irq, apc);
 +      }
 +
-+      irq_set_chained_handler(AR2315_IRQ_LCBUS_PCI, ar2315_pci_irq_handler);
++      irq_set_chained_handler(apc->irq, ar2315_pci_irq_handler);
++      irq_set_handler_data(apc->irq, apc);
 +
 +      /* Clear any pending Abort or external Interrupts
 +       * and enable interrupt processing */
-+      ar231x_write_reg(AR2315_PCI_ISR, (AR2315_PCI_INT_ABORT |
-+                       AR2315_PCI_INT_EXT));
-+      ar231x_mask_reg(AR2315_PCI_IER, 0, AR2315_PCI_IER_ENABLE);
++      ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT |
++                                                AR2315_PCI_INT_EXT);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_IER, 0, AR2315_PCI_IER_ENABLE);
 +}
 +
 +static int ar2315_pci_probe(struct platform_device *pdev)
 +{
++      struct ar2315_pci_ctrl *apc;
 +      struct device *dev = &pdev->dev;
-+      u32 reg;
-+      int res;
++      struct resource *res;
++      int irq, err;
 +
-+      /* Remap PCI config space */
-+      ar2315_pci_cfg_mem = devm_ioremap_nocache(dev, AR2315_PCIEXT,
-+                                                AR2315_PCI_CFG_SIZE);
-+      if (!ar2315_pci_cfg_mem) {
-+              dev_err(dev, "failed to remap PCI config space\n");
++      apc = devm_kzalloc(dev, sizeof(*apc), GFP_KERNEL);
++      if (!apc)
 +              return -ENOMEM;
-+      }
 +
-+      /* Reset PCI DMA logic */
-+      reg = ar231x_mask_reg(AR2315_RESET, 0, AR2315_RESET_PCIDMA);
-+      msleep(20);
-+      reg &= ~AR2315_RESET_PCIDMA;
-+      ar231x_write_reg(AR2315_RESET, reg);
-+      msleep(20);
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return -EINVAL;
++      apc->irq = irq;
 +
-+      ar231x_mask_reg(AR2315_ENDIAN_CTL, 0,
-+                      AR2315_CONFIG_PCIAHB | AR2315_CONFIG_PCIAHB_BRIDGE);
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                         "ar2315-pci-ctrl");
++      apc->mmr_mem = devm_ioremap_resource(dev, res);
++      if (IS_ERR(apc->mmr_mem))
++              return PTR_ERR(apc->mmr_mem);
 +
-+      ar231x_write_reg(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM |
-+                       (AR2315_PCICLK_IN_FREQ_DIV_6 << AR2315_PCICLK_DIV_S));
-+      ar231x_mask_reg(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI);
-+      ar231x_mask_reg(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK | AR2315_IF_MASK,
-+                      AR2315_IF_PCI | AR2315_IF_PCI_HOST |
-+                      AR2315_IF_PCI_INTR | (AR2315_IF_PCI_CLK_OUTPUT_CLK <<
-+                                            AR2315_IF_PCI_CLK_SHIFT));
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                         "ar2315-pci-ext");
++      if (!res)
++              return -EINVAL;
++
++      apc->mem_res.name = "AR2315 PCI mem space";
++      apc->mem_res.parent = res;
++      apc->mem_res.start = res->start;
++      apc->mem_res.end = res->end;
++      apc->mem_res.flags = IORESOURCE_MEM;
++
++      /* Remap PCI config space */
++      apc->cfg_mem = devm_ioremap_nocache(dev, res->start,
++                                          AR2315_PCI_CFG_SIZE);
++      if (!apc->cfg_mem) {
++              dev_err(dev, "failed to remap PCI config space\n");
++              return -ENOMEM;
++      }
 +
 +      /* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
-+      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE,
-+                      AR2315_PCIRST_LOW);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG,
++                          AR2315_PCIMISC_RST_MODE,
++                          AR2315_PCIRST_LOW);
 +      msleep(100);
 +
 +      /* Bring the PCI out of reset */
-+      ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE,
-+                      AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8);
++      ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG,
++                          AR2315_PCIMISC_RST_MODE,
++                          AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8);
 +
-+      ar231x_write_reg(AR2315_PCI_UNCACHE_CFG,
-+                       0x1E | /* 1GB uncached */
-+                       (1 << 5) | /* Enable uncached */
-+                       (0x2 << 30) /* Base: 0x80000000 */);
-+      ar231x_read_reg(AR2315_PCI_UNCACHE_CFG);
++      ar2315_pci_reg_write(apc, AR2315_PCI_UNCACHE_CFG,
++                           0x1E | /* 1GB uncached */
++                           (1 << 5) | /* Enable uncached */
++                           (0x2 << 30) /* Base: 0x80000000 */);
++      ar2315_pci_reg_read(apc, AR2315_PCI_UNCACHE_CFG);
 +
 +      msleep(500);
 +
-+      res = ar2315_pci_host_setup();
-+      if (res)
-+              return res;
++      err = ar2315_pci_host_setup(apc);
++      if (err)
++              return err;
++
++      ar2315_pci_irq_init(apc);
++
++      /* PCI controller does not support I/O ports */
++      apc->io_res.name = "AR2315 IO space";
++      apc->io_res.start = 0;
++      apc->io_res.end = 0;
++      apc->io_res.flags = IORESOURCE_IO,
 +
-+      ar2315_pci_irq_init();
++      apc->pci_ctrl.pci_ops = &ar2315_pci_ops;
++      apc->pci_ctrl.mem_resource = &apc->mem_res,
++      apc->pci_ctrl.io_resource = &apc->io_res,
 +
-+      register_pci_controller(&ar2315_pci_controller);
++      register_pci_controller(&apc->pci_ctrl);
 +
 +      return 0;
 +}
 +      default y
 --- a/arch/mips/ath25/ar2315.c
 +++ b/arch/mips/ath25/ar2315.c
-@@ -77,6 +77,10 @@ ar2315_irq_dispatch(void)
+@@ -137,6 +137,10 @@ static void ar2315_irq_dispatch(void)
                do_IRQ(AR2315_IRQ_WLAN0_INTRS);
        else if (pending & CAUSEF_IP4)
                do_IRQ(AR2315_IRQ_ENET0_INTRS);
        else if (pending & CAUSEF_IP2)
                do_IRQ(AR2315_IRQ_MISC_INTRS);
        else if (pending & CAUSEF_IP7)
-@@ -458,3 +462,18 @@ ar2315_plat_setup(void)
-       ar231x_serial_setup(AR2315_UART0, AR2315_MISC_IRQ_UART0,
-                           ar2315_apb_frequency());
+@@ -450,8 +454,60 @@ void __init ar2315_plat_mem_setup(void)
+       _machine_restart = ar2315_restart;
  }
-+
 +#ifdef CONFIG_PCI_AR2315
-+static int __init ar2315_pci_init(void)
-+{
-+      struct platform_device *pdev;
-+
-+      if (!is_2315() || ar231x_devtype != DEV_TYPE_AR2315)
-+              return -ENODEV;
++static struct resource ar2315_pci_res[] = {
++      {
++              .name = "ar2315-pci-ctrl",
++              .flags = IORESOURCE_MEM,
++              .start = AR2315_PCI,
++              .end = AR2315_PCI + AR2315_PCI_SIZE - 1,
++      },
++      {
++              .name = "ar2315-pci-ext",
++              .flags = IORESOURCE_MEM,
++              .start = AR2315_PCIEXT,
++              .end = AR2315_PCIEXT + AR2315_PCIEXT_SZ - 1,
++      },
++      {
++              .name = "ar2315-pci",
++              .flags = IORESOURCE_IRQ,
++              .start = AR2315_IRQ_LCBUS_PCI,
++              .end = AR2315_IRQ_LCBUS_PCI,
++      },
++};
++#endif
 +
-+      pdev = platform_device_register_simple("ar2315-pci", -1, NULL, 0);
+ void __init ar2315_arch_init(void)
+ {
+       ath25_serial_setup(AR2315_UART0, AR2315_MISC_IRQ_UART0,
+                          ar2315_apb_frequency());
 +
-+      return pdev ? 0 : -ENODEV;
-+}
-+arch_initcall(ar2315_pci_init);
++#ifdef CONFIG_PCI_AR2315
++      if (ath25_soc == ATH25_SOC_AR2315) {
++              /* Reset PCI DMA logic */
++              ar2315_rst_reg_mask(AR2315_RESET, 0, AR2315_RESET_PCIDMA);
++              msleep(20);
++              ar2315_rst_reg_mask(AR2315_RESET, AR2315_RESET_PCIDMA, 0);
++              msleep(20);
++
++              /* Configure endians */
++              ar2315_rst_reg_mask(AR2315_ENDIAN_CTL, 0, AR2315_CONFIG_PCIAHB |
++                                  AR2315_CONFIG_PCIAHB_BRIDGE);
++
++              /* Configure as PCI host with DMA */
++              ar2315_rst_reg_write(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM |
++                                (AR2315_PCICLK_IN_FREQ_DIV_6 <<
++                                 AR2315_PCICLK_DIV_S));
++              ar2315_rst_reg_mask(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI);
++              ar2315_rst_reg_mask(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK |
++                                  AR2315_IF_MASK, AR2315_IF_PCI |
++                                  AR2315_IF_PCI_HOST | AR2315_IF_PCI_INTR |
++                                  (AR2315_IF_PCI_CLK_OUTPUT_CLK <<
++                                   AR2315_IF_PCI_CLK_SHIFT));
++
++              platform_device_register_simple("ar2315-pci", -1,
++                                              ar2315_pci_res,
++                                              ARRAY_SIZE(ar2315_pci_res));
++      }
 +#endif
+ }