MIPS: ath25: add AR2315 PCI host controller driver
authorSergey Ryazanov <ryazanov.s.a@gmail.com>
Tue, 28 Oct 2014 23:18:47 +0000 (03:18 +0400)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 24 Nov 2014 06:45:28 +0000 (07:45 +0100)
Add PCI host controller driver and DMA address calculation hook.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Linux MIPS <linux-mips@linux-mips.org>
Patchwork: https://patchwork.linux-mips.org/patch/8246/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/ath25/Kconfig
arch/mips/ath25/ar2315.c
arch/mips/include/asm/mach-ath25/dma-coherence.h
arch/mips/pci/Makefile
arch/mips/pci/pci-ar2315.c [new file with mode: 0644]

index ca3dde4..fc19dd5 100644 (file)
@@ -7,3 +7,10 @@ config SOC_AR2315
        bool "Atheros AR2315+ SoC support"
        depends on ATH25
        default y
+
+config PCI_AR2315
+       bool "Atheros AR2315 PCI controller support"
+       depends on SOC_AR2315
+       select HW_HAS_PCI
+       select PCI
+       default y
index 52805b7..f024789 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/bitops.h>
 #include <linux/irqdomain.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 #include <linux/reboot.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
@@ -133,6 +134,10 @@ static void ar2315_irq_dispatch(void)
 
        if (pending & CAUSEF_IP3)
                do_IRQ(AR2315_IRQ_WLAN0);
+#ifdef CONFIG_PCI_AR2315
+       else if (pending & CAUSEF_IP5)
+               do_IRQ(AR2315_IRQ_LCBUS_PCI);
+#endif
        else if (pending & CAUSEF_IP2)
                do_IRQ(AR2315_IRQ_MISC);
        else if (pending & CAUSEF_IP7)
@@ -296,10 +301,62 @@ void __init ar2315_plat_mem_setup(void)
        _machine_restart = ar2315_restart;
 }
 
+#ifdef CONFIG_PCI_AR2315
+static struct resource ar2315_pci_res[] = {
+       {
+               .name = "ar2315-pci-ctrl",
+               .flags = IORESOURCE_MEM,
+               .start = AR2315_PCI_BASE,
+               .end = AR2315_PCI_BASE + AR2315_PCI_SIZE - 1,
+       },
+       {
+               .name = "ar2315-pci-ext",
+               .flags = IORESOURCE_MEM,
+               .start = AR2315_PCI_EXT_BASE,
+               .end = AR2315_PCI_EXT_BASE + AR2315_PCI_EXT_SIZE - 1,
+       },
+       {
+               .name = "ar2315-pci",
+               .flags = IORESOURCE_IRQ,
+               .start = AR2315_IRQ_LCBUS_PCI,
+               .end = AR2315_IRQ_LCBUS_PCI,
+       },
+};
+#endif
+
 void __init ar2315_arch_init(void)
 {
        unsigned irq = irq_create_mapping(ar2315_misc_irq_domain,
                                          AR2315_MISC_IRQ_UART0);
 
        ath25_serial_setup(AR2315_UART0_BASE, irq, ar2315_apb_frequency());
+
+#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
 }
index 8b3d0cc..d8009c9 100644 (file)
 
 #include <linux/device.h>
 
+/*
+ * We need some arbitrary non-zero value to be programmed to the BAR1 register
+ * of PCI host controller to enable DMA. The same value should be used as the
+ * offset to calculate the physical address of DMA buffer for PCI devices.
+ */
+#define AR2315_PCI_HOST_SDRAM_BASEADDR 0x20000000
+
+static inline dma_addr_t ath25_dev_offset(struct device *dev)
+{
+#ifdef CONFIG_PCI
+       extern struct bus_type pci_bus_type;
+
+       if (dev && dev->bus == &pci_bus_type)
+               return AR2315_PCI_HOST_SDRAM_BASEADDR;
+#endif
+       return 0;
+}
+
 static inline dma_addr_t
 plat_map_dma_mem(struct device *dev, void *addr, size_t size)
 {
-       return virt_to_phys(addr);
+       return virt_to_phys(addr) + ath25_dev_offset(dev);
 }
 
 static inline dma_addr_t
 plat_map_dma_mem_page(struct device *dev, struct page *page)
 {
-       return page_to_phys(page);
+       return page_to_phys(page) + ath25_dev_offset(dev);
 }
 
 static inline unsigned long
 plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
 {
-       return dma_addr;
+       return dma_addr - ath25_dev_offset(dev);
 }
 
 static inline void
Simple merge
Simple merge