aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorManuel Lauss <manuel.lauss@googlemail.com>2010-04-13 14:49:14 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-05-21 16:31:15 -0400
commit0f0d85bcc332ec8f0957378ea5fa3e553f80ae4b (patch)
treebcf184569aa20ee21aaf392ec3164c4487d7b68c /arch
parent7b5fcd694dffd1db294dd4ef9f90911852e422f5 (diff)
MIPS: Alchemy: add sysdev for IRQ PM.
Use a sysdev to implement PM methods for the Au1000 interrupt controllers. Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com> To: Linux-MIPS <linux-mips@linux-mips.org> Patchwork: http://patchwork.linux-mips.org/patch/1114/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/alchemy/common/irq.c174
-rw-r--r--arch/mips/alchemy/common/power.c5
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000.h34
3 files changed, 122 insertions, 91 deletions
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index b2821ace4d00..9f78ada83b3c 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -29,6 +29,8 @@
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/interrupt.h> 30#include <linux/interrupt.h>
31#include <linux/irq.h> 31#include <linux/irq.h>
32#include <linux/slab.h>
33#include <linux/sysdev.h>
32 34
33#include <asm/irq_cpu.h> 35#include <asm/irq_cpu.h>
34#include <asm/mipsregs.h> 36#include <asm/mipsregs.h>
@@ -216,90 +218,6 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = {
216}; 218};
217 219
218 220
219#ifdef CONFIG_PM
220
221/*
222 * Save/restore the interrupt controller state.
223 * Called from the save/restore core registers as part of the
224 * au_sleep function in power.c.....maybe I should just pm_register()
225 * them instead?
226 */
227static unsigned int sleep_intctl_config0[2];
228static unsigned int sleep_intctl_config1[2];
229static unsigned int sleep_intctl_config2[2];
230static unsigned int sleep_intctl_src[2];
231static unsigned int sleep_intctl_assign[2];
232static unsigned int sleep_intctl_wake[2];
233static unsigned int sleep_intctl_mask[2];
234
235void save_au1xxx_intctl(void)
236{
237 sleep_intctl_config0[0] = au_readl(IC0_CFG0RD);
238 sleep_intctl_config1[0] = au_readl(IC0_CFG1RD);
239 sleep_intctl_config2[0] = au_readl(IC0_CFG2RD);
240 sleep_intctl_src[0] = au_readl(IC0_SRCRD);
241 sleep_intctl_assign[0] = au_readl(IC0_ASSIGNRD);
242 sleep_intctl_wake[0] = au_readl(IC0_WAKERD);
243 sleep_intctl_mask[0] = au_readl(IC0_MASKRD);
244
245 sleep_intctl_config0[1] = au_readl(IC1_CFG0RD);
246 sleep_intctl_config1[1] = au_readl(IC1_CFG1RD);
247 sleep_intctl_config2[1] = au_readl(IC1_CFG2RD);
248 sleep_intctl_src[1] = au_readl(IC1_SRCRD);
249 sleep_intctl_assign[1] = au_readl(IC1_ASSIGNRD);
250 sleep_intctl_wake[1] = au_readl(IC1_WAKERD);
251 sleep_intctl_mask[1] = au_readl(IC1_MASKRD);
252}
253
254/*
255 * For most restore operations, we clear the entire register and
256 * then set the bits we found during the save.
257 */
258void restore_au1xxx_intctl(void)
259{
260 au_writel(0xffffffff, IC0_MASKCLR); au_sync();
261
262 au_writel(0xffffffff, IC0_CFG0CLR); au_sync();
263 au_writel(sleep_intctl_config0[0], IC0_CFG0SET); au_sync();
264 au_writel(0xffffffff, IC0_CFG1CLR); au_sync();
265 au_writel(sleep_intctl_config1[0], IC0_CFG1SET); au_sync();
266 au_writel(0xffffffff, IC0_CFG2CLR); au_sync();
267 au_writel(sleep_intctl_config2[0], IC0_CFG2SET); au_sync();
268 au_writel(0xffffffff, IC0_SRCCLR); au_sync();
269 au_writel(sleep_intctl_src[0], IC0_SRCSET); au_sync();
270 au_writel(0xffffffff, IC0_ASSIGNCLR); au_sync();
271 au_writel(sleep_intctl_assign[0], IC0_ASSIGNSET); au_sync();
272 au_writel(0xffffffff, IC0_WAKECLR); au_sync();
273 au_writel(sleep_intctl_wake[0], IC0_WAKESET); au_sync();
274 au_writel(0xffffffff, IC0_RISINGCLR); au_sync();
275 au_writel(0xffffffff, IC0_FALLINGCLR); au_sync();
276 au_writel(0x00000000, IC0_TESTBIT); au_sync();
277
278 au_writel(0xffffffff, IC1_MASKCLR); au_sync();
279
280 au_writel(0xffffffff, IC1_CFG0CLR); au_sync();
281 au_writel(sleep_intctl_config0[1], IC1_CFG0SET); au_sync();
282 au_writel(0xffffffff, IC1_CFG1CLR); au_sync();
283 au_writel(sleep_intctl_config1[1], IC1_CFG1SET); au_sync();
284 au_writel(0xffffffff, IC1_CFG2CLR); au_sync();
285 au_writel(sleep_intctl_config2[1], IC1_CFG2SET); au_sync();
286 au_writel(0xffffffff, IC1_SRCCLR); au_sync();
287 au_writel(sleep_intctl_src[1], IC1_SRCSET); au_sync();
288 au_writel(0xffffffff, IC1_ASSIGNCLR); au_sync();
289 au_writel(sleep_intctl_assign[1], IC1_ASSIGNSET); au_sync();
290 au_writel(0xffffffff, IC1_WAKECLR); au_sync();
291 au_writel(sleep_intctl_wake[1], IC1_WAKESET); au_sync();
292 au_writel(0xffffffff, IC1_RISINGCLR); au_sync();
293 au_writel(0xffffffff, IC1_FALLINGCLR); au_sync();
294 au_writel(0x00000000, IC1_TESTBIT); au_sync();
295
296 au_writel(sleep_intctl_mask[1], IC1_MASKSET); au_sync();
297
298 au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync();
299}
300#endif /* CONFIG_PM */
301
302
303static void au1x_ic0_unmask(unsigned int irq_nr) 221static void au1x_ic0_unmask(unsigned int irq_nr)
304{ 222{
305 unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; 223 unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
@@ -635,3 +553,91 @@ void __init arch_init_irq(void)
635 break; 553 break;
636 } 554 }
637} 555}
556
557struct alchemy_ic_sysdev {
558 struct sys_device sysdev;
559 void __iomem *base;
560 unsigned long pmdata[7];
561};
562
563static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state)
564{
565 struct alchemy_ic_sysdev *icdev =
566 container_of(dev, struct alchemy_ic_sysdev, sysdev);
567
568 icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD);
569 icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD);
570 icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD);
571 icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD);
572 icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD);
573 icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD);
574 icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD);
575
576 return 0;
577}
578
579static int alchemy_ic_resume(struct sys_device *dev)
580{
581 struct alchemy_ic_sysdev *icdev =
582 container_of(dev, struct alchemy_ic_sysdev, sysdev);
583
584 __raw_writel(0xffffffff, icdev->base + IC_MASKCLR);
585 __raw_writel(0xffffffff, icdev->base + IC_CFG0CLR);
586 __raw_writel(0xffffffff, icdev->base + IC_CFG1CLR);
587 __raw_writel(0xffffffff, icdev->base + IC_CFG2CLR);
588 __raw_writel(0xffffffff, icdev->base + IC_SRCCLR);
589 __raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR);
590 __raw_writel(0xffffffff, icdev->base + IC_WAKECLR);
591 __raw_writel(0xffffffff, icdev->base + IC_RISINGCLR);
592 __raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR);
593 __raw_writel(0x00000000, icdev->base + IC_TESTBIT);
594 wmb();
595 __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET);
596 __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET);
597 __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET);
598 __raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET);
599 __raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET);
600 __raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET);
601 wmb();
602
603 __raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET);
604 wmb();
605
606 return 0;
607}
608
609static struct sysdev_class alchemy_ic_sysdev_class = {
610 .name = "ic",
611 .suspend = alchemy_ic_suspend,
612 .resume = alchemy_ic_resume,
613};
614
615static int __init alchemy_ic_sysdev_init(void)
616{
617 struct alchemy_ic_sysdev *icdev;
618 unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR };
619 int err, i;
620
621 err = sysdev_class_register(&alchemy_ic_sysdev_class);
622 if (err)
623 return err;
624
625 for (i = 0; i < 2; i++) {
626 icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL);
627 if (!icdev)
628 return -ENOMEM;
629
630 icdev->base = ioremap(icbase[i], 0x1000);
631
632 icdev->sysdev.id = i;
633 icdev->sysdev.cls = &alchemy_ic_sysdev_class;
634 err = sysdev_register(&icdev->sysdev);
635 if (err) {
636 kfree(icdev);
637 return err;
638 }
639 }
640
641 return 0;
642}
643device_initcall(alchemy_ic_sysdev_init);
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index 6ab7b42aa1be..11e5ec748414 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -106,9 +106,6 @@ static void save_core_regs(void)
106 sleep_usb[1] = au_readl(0xb4020024); /* OTG_MUX */ 106 sleep_usb[1] = au_readl(0xb4020024); /* OTG_MUX */
107#endif 107#endif
108 108
109 /* Save interrupt controller state. */
110 save_au1xxx_intctl();
111
112 /* Clocks and PLLs. */ 109 /* Clocks and PLLs. */
113 sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0); 110 sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0);
114 sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1); 111 sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1);
@@ -200,8 +197,6 @@ static void restore_core_regs(void)
200 au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync(); 197 au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync();
201 } 198 }
202 199
203 restore_au1xxx_intctl();
204
205#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) 200#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
206 au1xxx_dbdma_resume(); 201 au1xxx_dbdma_resume();
207#endif 202#endif
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index ae07423e6e82..e76941db2312 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -190,8 +190,6 @@ extern unsigned long au1xxx_calc_clock(void);
190/* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */ 190/* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
191void au1xxx_save_and_sleep(void); 191void au1xxx_save_and_sleep(void);
192void au_sleep(void); 192void au_sleep(void);
193void save_au1xxx_intctl(void);
194void restore_au1xxx_intctl(void);
195 193
196 194
197/* SOC Interrupt numbers */ 195/* SOC Interrupt numbers */
@@ -835,6 +833,38 @@ enum soc_au1200_ints {
835#define MEM_STNAND_DATA 0x20 833#define MEM_STNAND_DATA 0x20
836#endif 834#endif
837 835
836
837/* Interrupt Controller register offsets */
838#define IC_CFG0RD 0x40
839#define IC_CFG0SET 0x40
840#define IC_CFG0CLR 0x44
841#define IC_CFG1RD 0x48
842#define IC_CFG1SET 0x48
843#define IC_CFG1CLR 0x4C
844#define IC_CFG2RD 0x50
845#define IC_CFG2SET 0x50
846#define IC_CFG2CLR 0x54
847#define IC_REQ0INT 0x54
848#define IC_SRCRD 0x58
849#define IC_SRCSET 0x58
850#define IC_SRCCLR 0x5C
851#define IC_REQ1INT 0x5C
852#define IC_ASSIGNRD 0x60
853#define IC_ASSIGNSET 0x60
854#define IC_ASSIGNCLR 0x64
855#define IC_WAKERD 0x68
856#define IC_WAKESET 0x68
857#define IC_WAKECLR 0x6C
858#define IC_MASKRD 0x70
859#define IC_MASKSET 0x70
860#define IC_MASKCLR 0x74
861#define IC_RISINGRD 0x78
862#define IC_RISINGCLR 0x78
863#define IC_FALLINGRD 0x7C
864#define IC_FALLINGCLR 0x7C
865#define IC_TESTBIT 0x80
866
867
838/* Interrupt Controller 0 */ 868/* Interrupt Controller 0 */
839#define IC0_CFG0RD 0xB0400040 869#define IC0_CFG0RD 0xB0400040
840#define IC0_CFG0SET 0xB0400040 870#define IC0_CFG0SET 0xB0400040