MIPS: ath79: Improve the DDR controller interface
authorAlban Bedel <albeu@free.fr>
Sun, 19 Apr 2015 12:30:03 +0000 (14:30 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Sun, 21 Jun 2015 19:53:51 +0000 (21:53 +0200)
The DDR controller need to be used by the IRQ controller to flush
the write buffer of some devices before running the IRQ handler.
It is also used by the PCI controller to setup the PCI memory windows.

The current interface used to access the DDR controller doesn't
provides any useful abstraction and simply rely on a shared global
pointer.

Replace this by a simple API to setup the PCI memory windows and use
the write buffer flush independently of the SoC type. That remove the
need for the shared global pointer, simplify the IRQ handler code.

[ralf@linux-mips.org: Folded in Alban Bedel's follup fix.]

Signed-off-by: Alban Bedel <albeu@free.fr>
Cc: linux-mips@linux-mips.org
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Wolfram Sang <wsa@the-dreams.de>
Cc: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Gabor Juhos <juhosg@openwrt.org>
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/9773/
Patchwork: http://patchwork.linux-mips.org/patch/10543/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/ath79/common.c
arch/mips/ath79/common.h
arch/mips/ath79/irq.c
arch/mips/ath79/setup.c
arch/mips/include/asm/mach-ath79/ath79.h
arch/mips/pci/pci-ar71xx.c

index eb3966cd8cfcbbf74d4ec0c6b650f334843b4039..3cedd1f95e0f0897cf3c1d47b6c27cb9182c4003 100644 (file)
@@ -38,11 +38,27 @@ unsigned int ath79_soc_rev;
 void __iomem *ath79_pll_base;
 void __iomem *ath79_reset_base;
 EXPORT_SYMBOL_GPL(ath79_reset_base);
-void __iomem *ath79_ddr_base;
+static void __iomem *ath79_ddr_base;
+static void __iomem *ath79_ddr_wb_flush_base;
+static void __iomem *ath79_ddr_pci_win_base;
+
+void ath79_ddr_ctrl_init(void)
+{
+       ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+                                        AR71XX_DDR_CTRL_SIZE);
+       if (soc_is_ar71xx() || soc_is_ar934x()) {
+               ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c;
+               ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c;
+       } else {
+               ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c;
+               ath79_ddr_pci_win_base = 0;
+       }
+}
+EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init);
 
 void ath79_ddr_wb_flush(u32 reg)
 {
-       void __iomem *flush_reg = ath79_ddr_base + reg;
+       void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg;
 
        /* Flush the DDR write buffer. */
        __raw_writel(0x1, flush_reg);
@@ -56,6 +72,21 @@ void ath79_ddr_wb_flush(u32 reg)
 }
 EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
 
+void ath79_ddr_set_pci_windows(void)
+{
+       BUG_ON(!ath79_ddr_pci_win_base);
+
+       __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0);
+       __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1);
+       __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2);
+       __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3);
+       __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4);
+       __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5);
+       __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6);
+       __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7);
+}
+EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows);
+
 void ath79_device_reset_set(u32 mask)
 {
        unsigned long flags;
index c39de61f9b36f6a0ec4cc327defa940c45e924f5..e5ea71277f0cf9fc19d3dd95e71afab2a8d84197 100644 (file)
@@ -22,6 +22,7 @@
 void ath79_clocks_init(void);
 unsigned long ath79_get_sys_clk_rate(const char *id);
 
+void ath79_ddr_ctrl_init(void);
 void ath79_ddr_wb_flush(unsigned int reg);
 
 void ath79_gpio_function_enable(u32 mask);
index 6adae366f11a9c4936a3546be33766871bf0b261..2c3991a4e512913467e722bacbf708ae524b1c90 100644 (file)
@@ -24,9 +24,6 @@
 #include <asm/mach-ath79/ar71xx_regs.h>
 #include "common.h"
 
-static void (*ath79_ip2_handler)(void);
-static void (*ath79_ip3_handler)(void);
-
 static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        void __iomem *base = ath79_reset_base;
@@ -129,10 +126,10 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
        status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS);
 
        if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) {
-               ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_PCIE);
+               ath79_ddr_wb_flush(3);
                generic_handle_irq(ATH79_IP2_IRQ(0));
        } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) {
-               ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_WMAC);
+               ath79_ddr_wb_flush(4);
                generic_handle_irq(ATH79_IP2_IRQ(1));
        } else {
                spurious_interrupt();
@@ -235,128 +232,50 @@ static void qca955x_irq_init(void)
        irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
 }
 
-asmlinkage void plat_irq_dispatch(void)
-{
-       unsigned long pending;
-
-       pending = read_c0_status() & read_c0_cause() & ST0_IM;
-
-       if (pending & STATUSF_IP7)
-               do_IRQ(ATH79_CPU_IRQ(7));
-
-       else if (pending & STATUSF_IP2)
-               ath79_ip2_handler();
-
-       else if (pending & STATUSF_IP4)
-               do_IRQ(ATH79_CPU_IRQ(4));
-
-       else if (pending & STATUSF_IP5)
-               do_IRQ(ATH79_CPU_IRQ(5));
-
-       else if (pending & STATUSF_IP3)
-               ath79_ip3_handler();
-
-       else if (pending & STATUSF_IP6)
-               do_IRQ(ATH79_CPU_IRQ(6));
-
-       else
-               spurious_interrupt();
-}
-
 /*
  * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
  * these devices typically allocate coherent DMA memory, however the
  * DMA controller may still have some unsynchronized data in the FIFO.
  * Issue a flush in the handlers to ensure that the driver sees
  * the update.
+ *
+ * This array map the interrupt lines to the DDR write buffer channels.
  */
 
-static void ath79_default_ip2_handler(void)
-{
-       do_IRQ(ATH79_CPU_IRQ(2));
-}
-
-static void ath79_default_ip3_handler(void)
-{
-       do_IRQ(ATH79_CPU_IRQ(3));
-}
-
-static void ar71xx_ip2_handler(void)
-{
-       ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI);
-       do_IRQ(ATH79_CPU_IRQ(2));
-}
-
-static void ar724x_ip2_handler(void)
-{
-       ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE);
-       do_IRQ(ATH79_CPU_IRQ(2));
-}
-
-static void ar913x_ip2_handler(void)
-{
-       ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC);
-       do_IRQ(ATH79_CPU_IRQ(2));
-}
-
-static void ar933x_ip2_handler(void)
-{
-       ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC);
-       do_IRQ(ATH79_CPU_IRQ(2));
-}
-
-static void ar71xx_ip3_handler(void)
-{
-       ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB);
-       do_IRQ(ATH79_CPU_IRQ(3));
-}
+static unsigned irq_wb_chan[8] = {
+       -1, -1, -1, -1, -1, -1, -1, -1,
+};
 
-static void ar724x_ip3_handler(void)
+asmlinkage void plat_irq_dispatch(void)
 {
-       ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB);
-       do_IRQ(ATH79_CPU_IRQ(3));
-}
+       unsigned long pending;
+       int irq;
 
-static void ar913x_ip3_handler(void)
-{
-       ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB);
-       do_IRQ(ATH79_CPU_IRQ(3));
-}
+       pending = read_c0_status() & read_c0_cause() & ST0_IM;
 
-static void ar933x_ip3_handler(void)
-{
-       ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB);
-       do_IRQ(ATH79_CPU_IRQ(3));
-}
+       if (!pending) {
+               spurious_interrupt();
+               return;
+       }
 
-static void ar934x_ip3_handler(void)
-{
-       ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB);
-       do_IRQ(ATH79_CPU_IRQ(3));
+       pending >>= CAUSEB_IP;
+       while (pending) {
+               irq = fls(pending) - 1;
+               if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)
+                       ath79_ddr_wb_flush(irq_wb_chan[irq]);
+               do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+               pending &= ~BIT(irq);
+       }
 }
 
 void __init arch_init_irq(void)
 {
-       if (soc_is_ar71xx()) {
-               ath79_ip2_handler = ar71xx_ip2_handler;
-               ath79_ip3_handler = ar71xx_ip3_handler;
-       } else if (soc_is_ar724x()) {
-               ath79_ip2_handler = ar724x_ip2_handler;
-               ath79_ip3_handler = ar724x_ip3_handler;
-       } else if (soc_is_ar913x()) {
-               ath79_ip2_handler = ar913x_ip2_handler;
-               ath79_ip3_handler = ar913x_ip3_handler;
-       } else if (soc_is_ar933x()) {
-               ath79_ip2_handler = ar933x_ip2_handler;
-               ath79_ip3_handler = ar933x_ip3_handler;
+       if (soc_is_ar71xx() || soc_is_ar724x() ||
+           soc_is_ar913x() || soc_is_ar933x()) {
+               irq_wb_chan[2] = 3;
+               irq_wb_chan[3] = 2;
        } else if (soc_is_ar934x()) {
-               ath79_ip2_handler = ath79_default_ip2_handler;
-               ath79_ip3_handler = ar934x_ip3_handler;
-       } else if (soc_is_qca955x()) {
-               ath79_ip2_handler = ath79_default_ip2_handler;
-               ath79_ip3_handler = ath79_default_ip3_handler;
-       } else {
-               BUG();
+               irq_wb_chan[3] = 2;
        }
 
        mips_cpu_irq_init();
index 7fc8397d16f21d713ad3e073308f69c75dd88692..74f1af7eeefccb27a7c8af12a234cbae85c02bcb 100644 (file)
@@ -200,8 +200,7 @@ void __init plat_mem_setup(void)
                                           AR71XX_RESET_SIZE);
        ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
                                         AR71XX_PLL_SIZE);
-       ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
-                                        AR71XX_DDR_CTRL_SIZE);
+       ath79_ddr_ctrl_init();
 
        ath79_detect_sys_type();
        detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
index 1557934aaca973d25e4a0d2bcc97e5e1d39f926a..4eee221b0cf0bce93fa7adb7b634c9feebcdf21d 100644 (file)
@@ -115,7 +115,8 @@ static inline int soc_is_qca955x(void)
        return soc_is_qca9556() || soc_is_qca9558();
 }
 
-extern void __iomem *ath79_ddr_base;
+void ath79_ddr_set_pci_windows(void);
+
 extern void __iomem *ath79_pll_base;
 extern void __iomem *ath79_reset_base;
 
index dac6a07c45bf955d9f773d3af79b568983e1ebd8..283157f8dc64794a3a02936ef11974538c8950eb 100644 (file)
@@ -318,23 +318,13 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
 
 static 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);
-
+       ath79_ddr_set_pci_windows();
        mdelay(100);
 }