Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alban Bedel and committed by
Ralf Baechle
24b0e3e8 626a0695

+66 -125
+33 -2
arch/mips/ath79/common.c
··· 38 38 void __iomem *ath79_pll_base; 39 39 void __iomem *ath79_reset_base; 40 40 EXPORT_SYMBOL_GPL(ath79_reset_base); 41 - void __iomem *ath79_ddr_base; 41 + static void __iomem *ath79_ddr_base; 42 + static void __iomem *ath79_ddr_wb_flush_base; 43 + static void __iomem *ath79_ddr_pci_win_base; 44 + 45 + void ath79_ddr_ctrl_init(void) 46 + { 47 + ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, 48 + AR71XX_DDR_CTRL_SIZE); 49 + if (soc_is_ar71xx() || soc_is_ar934x()) { 50 + ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c; 51 + ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c; 52 + } else { 53 + ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c; 54 + ath79_ddr_pci_win_base = 0; 55 + } 56 + } 57 + EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init); 42 58 43 59 void ath79_ddr_wb_flush(u32 reg) 44 60 { 45 - void __iomem *flush_reg = ath79_ddr_base + reg; 61 + void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg; 46 62 47 63 /* Flush the DDR write buffer. */ 48 64 __raw_writel(0x1, flush_reg); ··· 71 55 ; 72 56 } 73 57 EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush); 58 + 59 + void ath79_ddr_set_pci_windows(void) 60 + { 61 + BUG_ON(!ath79_ddr_pci_win_base); 62 + 63 + __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0); 64 + __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1); 65 + __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2); 66 + __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3); 67 + __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4); 68 + __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5); 69 + __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6); 70 + __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7); 71 + } 72 + EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows); 74 73 75 74 void ath79_device_reset_set(u32 mask) 76 75 {
+1
arch/mips/ath79/common.h
··· 22 22 void ath79_clocks_init(void); 23 23 unsigned long ath79_get_sys_clk_rate(const char *id); 24 24 25 + void ath79_ddr_ctrl_init(void); 25 26 void ath79_ddr_wb_flush(unsigned int reg); 26 27 27 28 void ath79_gpio_function_enable(u32 mask);
+28 -109
arch/mips/ath79/irq.c
··· 24 24 #include <asm/mach-ath79/ar71xx_regs.h> 25 25 #include "common.h" 26 26 27 - static void (*ath79_ip2_handler)(void); 28 - static void (*ath79_ip3_handler)(void); 29 - 30 27 static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) 31 28 { 32 29 void __iomem *base = ath79_reset_base; ··· 126 129 status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); 127 130 128 131 if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { 129 - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_PCIE); 132 + ath79_ddr_wb_flush(3); 130 133 generic_handle_irq(ATH79_IP2_IRQ(0)); 131 134 } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) { 132 - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_WMAC); 135 + ath79_ddr_wb_flush(4); 133 136 generic_handle_irq(ATH79_IP2_IRQ(1)); 134 137 } else { 135 138 spurious_interrupt(); ··· 232 235 irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch); 233 236 } 234 237 235 - asmlinkage void plat_irq_dispatch(void) 236 - { 237 - unsigned long pending; 238 - 239 - pending = read_c0_status() & read_c0_cause() & ST0_IM; 240 - 241 - if (pending & STATUSF_IP7) 242 - do_IRQ(ATH79_CPU_IRQ(7)); 243 - 244 - else if (pending & STATUSF_IP2) 245 - ath79_ip2_handler(); 246 - 247 - else if (pending & STATUSF_IP4) 248 - do_IRQ(ATH79_CPU_IRQ(4)); 249 - 250 - else if (pending & STATUSF_IP5) 251 - do_IRQ(ATH79_CPU_IRQ(5)); 252 - 253 - else if (pending & STATUSF_IP3) 254 - ath79_ip3_handler(); 255 - 256 - else if (pending & STATUSF_IP6) 257 - do_IRQ(ATH79_CPU_IRQ(6)); 258 - 259 - else 260 - spurious_interrupt(); 261 - } 262 - 263 238 /* 264 239 * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for 265 240 * these devices typically allocate coherent DMA memory, however the 266 241 * DMA controller may still have some unsynchronized data in the FIFO. 267 242 * Issue a flush in the handlers to ensure that the driver sees 268 243 * the update. 244 + * 245 + * This array map the interrupt lines to the DDR write buffer channels. 269 246 */ 270 247 271 - static void ath79_default_ip2_handler(void) 272 - { 273 - do_IRQ(ATH79_CPU_IRQ(2)); 274 - } 248 + static unsigned irq_wb_chan[8] = { 249 + -1, -1, -1, -1, -1, -1, -1, -1, 250 + }; 275 251 276 - static void ath79_default_ip3_handler(void) 252 + asmlinkage void plat_irq_dispatch(void) 277 253 { 278 - do_IRQ(ATH79_CPU_IRQ(3)); 279 - } 254 + unsigned long pending; 255 + int irq; 280 256 281 - static void ar71xx_ip2_handler(void) 282 - { 283 - ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI); 284 - do_IRQ(ATH79_CPU_IRQ(2)); 285 - } 257 + pending = read_c0_status() & read_c0_cause() & ST0_IM; 286 258 287 - static void ar724x_ip2_handler(void) 288 - { 289 - ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE); 290 - do_IRQ(ATH79_CPU_IRQ(2)); 291 - } 259 + if (!pending) { 260 + spurious_interrupt(); 261 + return; 262 + } 292 263 293 - static void ar913x_ip2_handler(void) 294 - { 295 - ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC); 296 - do_IRQ(ATH79_CPU_IRQ(2)); 297 - } 298 - 299 - static void ar933x_ip2_handler(void) 300 - { 301 - ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC); 302 - do_IRQ(ATH79_CPU_IRQ(2)); 303 - } 304 - 305 - static void ar71xx_ip3_handler(void) 306 - { 307 - ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); 308 - do_IRQ(ATH79_CPU_IRQ(3)); 309 - } 310 - 311 - static void ar724x_ip3_handler(void) 312 - { 313 - ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB); 314 - do_IRQ(ATH79_CPU_IRQ(3)); 315 - } 316 - 317 - static void ar913x_ip3_handler(void) 318 - { 319 - ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB); 320 - do_IRQ(ATH79_CPU_IRQ(3)); 321 - } 322 - 323 - static void ar933x_ip3_handler(void) 324 - { 325 - ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB); 326 - do_IRQ(ATH79_CPU_IRQ(3)); 327 - } 328 - 329 - static void ar934x_ip3_handler(void) 330 - { 331 - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB); 332 - do_IRQ(ATH79_CPU_IRQ(3)); 264 + pending >>= CAUSEB_IP; 265 + while (pending) { 266 + irq = fls(pending) - 1; 267 + if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1) 268 + ath79_ddr_wb_flush(irq_wb_chan[irq]); 269 + do_IRQ(MIPS_CPU_IRQ_BASE + irq); 270 + pending &= ~BIT(irq); 271 + } 333 272 } 334 273 335 274 void __init arch_init_irq(void) 336 275 { 337 - if (soc_is_ar71xx()) { 338 - ath79_ip2_handler = ar71xx_ip2_handler; 339 - ath79_ip3_handler = ar71xx_ip3_handler; 340 - } else if (soc_is_ar724x()) { 341 - ath79_ip2_handler = ar724x_ip2_handler; 342 - ath79_ip3_handler = ar724x_ip3_handler; 343 - } else if (soc_is_ar913x()) { 344 - ath79_ip2_handler = ar913x_ip2_handler; 345 - ath79_ip3_handler = ar913x_ip3_handler; 346 - } else if (soc_is_ar933x()) { 347 - ath79_ip2_handler = ar933x_ip2_handler; 348 - ath79_ip3_handler = ar933x_ip3_handler; 276 + if (soc_is_ar71xx() || soc_is_ar724x() || 277 + soc_is_ar913x() || soc_is_ar933x()) { 278 + irq_wb_chan[2] = 3; 279 + irq_wb_chan[3] = 2; 349 280 } else if (soc_is_ar934x()) { 350 - ath79_ip2_handler = ath79_default_ip2_handler; 351 - ath79_ip3_handler = ar934x_ip3_handler; 352 - } else if (soc_is_qca955x()) { 353 - ath79_ip2_handler = ath79_default_ip2_handler; 354 - ath79_ip3_handler = ath79_default_ip3_handler; 355 - } else { 356 - BUG(); 281 + irq_wb_chan[3] = 2; 357 282 } 358 283 359 284 mips_cpu_irq_init();
+1 -2
arch/mips/ath79/setup.c
··· 200 200 AR71XX_RESET_SIZE); 201 201 ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, 202 202 AR71XX_PLL_SIZE); 203 - ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, 204 - AR71XX_DDR_CTRL_SIZE); 203 + ath79_ddr_ctrl_init(); 205 204 206 205 ath79_detect_sys_type(); 207 206 detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
+2 -1
arch/mips/include/asm/mach-ath79/ath79.h
··· 115 115 return soc_is_qca9556() || soc_is_qca9558(); 116 116 } 117 117 118 - extern void __iomem *ath79_ddr_base; 118 + void ath79_ddr_set_pci_windows(void); 119 + 119 120 extern void __iomem *ath79_pll_base; 120 121 extern void __iomem *ath79_reset_base; 121 122
+1 -11
arch/mips/pci/pci-ar71xx.c
··· 318 318 319 319 static void ar71xx_pci_reset(void) 320 320 { 321 - void __iomem *ddr_base = ath79_ddr_base; 322 - 323 321 ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); 324 322 mdelay(100); 325 323 326 324 ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); 327 325 mdelay(100); 328 326 329 - __raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0); 330 - __raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1); 331 - __raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2); 332 - __raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3); 333 - __raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4); 334 - __raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5); 335 - __raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6); 336 - __raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7); 337 - 327 + ath79_ddr_set_pci_windows(); 338 328 mdelay(100); 339 329 } 340 330