MIPS: ath79: Improve the DDR controller interface
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>
This commit is contained in:
parent
626a0695a6
commit
24b0e3e84f
|
@ -38,11 +38,27 @@ unsigned int ath79_soc_rev;
|
||||||
void __iomem *ath79_pll_base;
|
void __iomem *ath79_pll_base;
|
||||||
void __iomem *ath79_reset_base;
|
void __iomem *ath79_reset_base;
|
||||||
EXPORT_SYMBOL_GPL(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 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. */
|
/* Flush the DDR write buffer. */
|
||||||
__raw_writel(0x1, flush_reg);
|
__raw_writel(0x1, flush_reg);
|
||||||
|
@ -56,6 +72,21 @@ void ath79_ddr_wb_flush(u32 reg)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
|
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)
|
void ath79_device_reset_set(u32 mask)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
void ath79_clocks_init(void);
|
void ath79_clocks_init(void);
|
||||||
unsigned long ath79_get_sys_clk_rate(const char *id);
|
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_ddr_wb_flush(unsigned int reg);
|
||||||
|
|
||||||
void ath79_gpio_function_enable(u32 mask);
|
void ath79_gpio_function_enable(u32 mask);
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||||
#include "common.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)
|
static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
void __iomem *base = ath79_reset_base;
|
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);
|
status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS);
|
||||||
|
|
||||||
if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) {
|
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));
|
generic_handle_irq(ATH79_IP2_IRQ(0));
|
||||||
} else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) {
|
} 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));
|
generic_handle_irq(ATH79_IP2_IRQ(1));
|
||||||
} else {
|
} else {
|
||||||
spurious_interrupt();
|
spurious_interrupt();
|
||||||
|
@ -235,128 +232,50 @@ static void qca955x_irq_init(void)
|
||||||
irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
|
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
|
* The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
|
||||||
* these devices typically allocate coherent DMA memory, however the
|
* these devices typically allocate coherent DMA memory, however the
|
||||||
* DMA controller may still have some unsynchronized data in the FIFO.
|
* DMA controller may still have some unsynchronized data in the FIFO.
|
||||||
* Issue a flush in the handlers to ensure that the driver sees
|
* Issue a flush in the handlers to ensure that the driver sees
|
||||||
* the update.
|
* the update.
|
||||||
|
*
|
||||||
|
* This array map the interrupt lines to the DDR write buffer channels.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void ath79_default_ip2_handler(void)
|
static unsigned irq_wb_chan[8] = {
|
||||||
{
|
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
do_IRQ(ATH79_CPU_IRQ(2));
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static void ath79_default_ip3_handler(void)
|
asmlinkage void plat_irq_dispatch(void)
|
||||||
{
|
{
|
||||||
do_IRQ(ATH79_CPU_IRQ(3));
|
unsigned long pending;
|
||||||
}
|
int irq;
|
||||||
|
|
||||||
static void ar71xx_ip2_handler(void)
|
pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
||||||
{
|
|
||||||
ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI);
|
|
||||||
do_IRQ(ATH79_CPU_IRQ(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ar724x_ip2_handler(void)
|
if (!pending) {
|
||||||
{
|
spurious_interrupt();
|
||||||
ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE);
|
return;
|
||||||
do_IRQ(ATH79_CPU_IRQ(2));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void ar913x_ip2_handler(void)
|
pending >>= CAUSEB_IP;
|
||||||
{
|
while (pending) {
|
||||||
ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC);
|
irq = fls(pending) - 1;
|
||||||
do_IRQ(ATH79_CPU_IRQ(2));
|
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);
|
||||||
static void ar933x_ip2_handler(void)
|
pending &= ~BIT(irq);
|
||||||
{
|
}
|
||||||
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 void ar724x_ip3_handler(void)
|
|
||||||
{
|
|
||||||
ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB);
|
|
||||||
do_IRQ(ATH79_CPU_IRQ(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ar913x_ip3_handler(void)
|
|
||||||
{
|
|
||||||
ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB);
|
|
||||||
do_IRQ(ATH79_CPU_IRQ(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ar933x_ip3_handler(void)
|
|
||||||
{
|
|
||||||
ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB);
|
|
||||||
do_IRQ(ATH79_CPU_IRQ(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ar934x_ip3_handler(void)
|
|
||||||
{
|
|
||||||
ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB);
|
|
||||||
do_IRQ(ATH79_CPU_IRQ(3));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init arch_init_irq(void)
|
void __init arch_init_irq(void)
|
||||||
{
|
{
|
||||||
if (soc_is_ar71xx()) {
|
if (soc_is_ar71xx() || soc_is_ar724x() ||
|
||||||
ath79_ip2_handler = ar71xx_ip2_handler;
|
soc_is_ar913x() || soc_is_ar933x()) {
|
||||||
ath79_ip3_handler = ar71xx_ip3_handler;
|
irq_wb_chan[2] = 3;
|
||||||
} else if (soc_is_ar724x()) {
|
irq_wb_chan[3] = 2;
|
||||||
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;
|
|
||||||
} else if (soc_is_ar934x()) {
|
} else if (soc_is_ar934x()) {
|
||||||
ath79_ip2_handler = ath79_default_ip2_handler;
|
irq_wb_chan[3] = 2;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mips_cpu_irq_init();
|
mips_cpu_irq_init();
|
||||||
|
|
|
@ -200,8 +200,7 @@ void __init plat_mem_setup(void)
|
||||||
AR71XX_RESET_SIZE);
|
AR71XX_RESET_SIZE);
|
||||||
ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
|
ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
|
||||||
AR71XX_PLL_SIZE);
|
AR71XX_PLL_SIZE);
|
||||||
ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
|
ath79_ddr_ctrl_init();
|
||||||
AR71XX_DDR_CTRL_SIZE);
|
|
||||||
|
|
||||||
ath79_detect_sys_type();
|
ath79_detect_sys_type();
|
||||||
detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
|
detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
|
||||||
|
|
|
@ -115,7 +115,8 @@ static inline int soc_is_qca955x(void)
|
||||||
return soc_is_qca9556() || soc_is_qca9558();
|
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_pll_base;
|
||||||
extern void __iomem *ath79_reset_base;
|
extern void __iomem *ath79_reset_base;
|
||||||
|
|
||||||
|
|
|
@ -318,23 +318,13 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
|
||||||
|
|
||||||
static void ar71xx_pci_reset(void)
|
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);
|
ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
|
||||||
mdelay(100);
|
mdelay(100);
|
||||||
|
|
||||||
ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
|
ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
|
||||||
mdelay(100);
|
mdelay(100);
|
||||||
|
|
||||||
__raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0);
|
ath79_ddr_set_pci_windows();
|
||||||
__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);
|
mdelay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue