@ -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,445 @@
@@ -0,0 +1,482 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
@ -67,11 +67,11 @@
+/*
+ * PCI Bus Interface Registers
+ */
+#define AR2315_PCI_1MS_REG (AR2315_PCI + 0x0008)
+#define AR2315_PCI_1MS_REG 0x0008
+
+#define AR2315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
+
+#define AR2315_PCI_MISC_CONFIG (AR2315_PCI + 0x000c)
+#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 */
@ -87,38 +87,38 @@
+#define AR2315_PCICACHE_DIS 0x00001000 /* PCI external access cache
+ * disable */
+
+#define AR2315_PCI_OUT_TSTAMP (AR2315_PCI + 0x0010)
+#define AR2315_PCI_OUT_TSTAMP 0x0010
+
+#define AR2315_PCI_UNCACHE_CFG (AR2315_PCI + 0x0014)
+#define AR2315_PCI_UNCACHE_CFG 0x0014
+
+#define AR2315_PCI_IN_EN (AR2315_PCI + 0x0100)
+#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 (AR2315_PCI + 0x0104)
+#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 (AR2315_PCI + 0x0200)
+#define AR2315_PCI_IN_PTR 0x0200
+
+#define AR2315_PCI_OUT_EN (AR2315_PCI + 0x0400)
+#define AR2315_PCI_OUT_EN 0x0400
+
+#define AR2315_PCI_OUT_EN0 0x01 /* Enable chain 0 */
+
+#define AR2315_PCI_OUT_DIS (AR2315_PCI + 0x0404)
+#define AR2315_PCI_OUT_DIS 0x0404
+
+#define AR2315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */
+
+#define AR2315_PCI_OUT_PTR (AR2315_PCI + 0x0408)
+#define AR2315_PCI_OUT_PTR 0x0408
+
+/* PCI interrupt status (write one to clear) */
+#define AR2315_PCI_ISR (AR2315_PCI + 0x0500)
+#define AR2315_PCI_ISR 0x0500
+
+#define AR2315_PCI_INT_TX 0x00000001 /* Desc In Completed */
+#define AR2315_PCI_INT_TXOK 0x00000002 /* Desc In OK */
@ -134,20 +134,20 @@
+#define AR2315_PCI_INT_ABORT 0x04000000 /* PCI bus abort event */
+
+/* PCI interrupt mask */
+#define AR2315_PCI_IMR (AR2315_PCI + 0x0504)
+#define AR2315_PCI_IMR 0x0504
+
+/* Global PCI interrupt enable */
+#define AR2315_PCI_IER (AR2315_PCI + 0x0508)
+#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 (AR2315_PCI + 0x0800)
+#define AR2315_PCI_HOST_IN_DIS (AR2315_PCI + 0x0804)
+#define AR2315_PCI_HOST_IN_PTR (AR2315_PCI + 0x0810)
+#define AR2315_PCI_HOST_OUT_EN (AR2315_PCI + 0x0900)
+#define AR2315_PCI_HOST_OUT_DIS (AR2315_PCI + 0x0904)
+#define AR2315_PCI_HOST_OUT_PTR (AR2315_PCI + 0x0908)
+#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
@ -174,6 +174,7 @@
+
+struct ar2315_pci_ctrl {
+ void __iomem *cfg_mem;
+ void __iomem *mmr_mem;
+ struct pci_controller pci_ctrl;
+ struct resource mem_res;
+ struct resource io_res;
@ -186,6 +187,27 @@
+ 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 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)
+{
@ -201,22 +223,24 @@
+ 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(apc->cfg_mem + addr);
+
+ isr = ar231x_read_reg(AR2315_PCI_ISR);
+ isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
+
+ if (isr & AR2315_PCI_INT_ABORT)
+ goto exit_err;
+
+ if (write) {
+ value = (value & ~(mask << sh)) | *ptr << sh;
+ __raw_writel(value, apc->cfg_mem + addr);
+ isr = ar231x_read_reg( AR2315_PCI_ISR);
+ isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR);
+ if (isr & AR2315_PCI_INT_ABORT)
+ goto exit_err;
+ } else {
@ -226,13 +250,14 @@
+ 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;
@ -308,8 +333,9 @@
+
+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);
@ -321,24 +347,27 @@
+
+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 = {
@ -348,28 +377,30 @@
+ .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_handler_data(AR2315_IRQ_LCBUS_PCI, 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)
@ -382,6 +413,10 @@
+ if (!apc)
+ return -ENOMEM;
+
+ apc->mmr_mem = devm_ioremap_nocache(dev, AR2315_PCI, AR2315_PCI_SIZE);
+ if (!apc->mmr_mem)
+ return -ENOMEM;
+
+ apc->mem_res.name = "AR2315 PCI mem space";
+ apc->mem_res.start = AR2315_PCIEXT;
+ apc->mem_res.end = AR2315_PCIEXT + AR2315_PCIEXT_SZ - 1;
@ -396,19 +431,21 @@
+ }
+
+ /* 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);
+
@ -416,7 +453,7 @@
+ if (err)
+ return err;
+
+ ar2315_pci_irq_init();
+ ar2315_pci_irq_init(apc );
+
+ /* PCI controller does not support I/O ports */
+ apc->io_res.name = "AR2315 IO space";