diff options
| author | Manuel Lauss <manuel.lauss@googlemail.com> | 2010-04-13 14:49:14 -0400 | 
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2010-05-21 16:31:15 -0400 | 
| commit | 0f0d85bcc332ec8f0957378ea5fa3e553f80ae4b (patch) | |
| tree | bcf184569aa20ee21aaf392ec3164c4487d7b68c | |
| parent | 7b5fcd694dffd1db294dd4ef9f90911852e422f5 (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>
| -rw-r--r-- | arch/mips/alchemy/common/irq.c | 174 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/power.c | 5 | ||||
| -rw-r--r-- | arch/mips/include/asm/mach-au1x00/au1000.h | 34 | 
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 | */ | ||
| 227 | static unsigned int sleep_intctl_config0[2]; | ||
| 228 | static unsigned int sleep_intctl_config1[2]; | ||
| 229 | static unsigned int sleep_intctl_config2[2]; | ||
| 230 | static unsigned int sleep_intctl_src[2]; | ||
| 231 | static unsigned int sleep_intctl_assign[2]; | ||
| 232 | static unsigned int sleep_intctl_wake[2]; | ||
| 233 | static unsigned int sleep_intctl_mask[2]; | ||
| 234 | |||
| 235 | void 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 | */ | ||
| 258 | void 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 | |||
| 303 | static void au1x_ic0_unmask(unsigned int irq_nr) | 221 | static 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 | |||
| 557 | struct alchemy_ic_sysdev { | ||
| 558 | struct sys_device sysdev; | ||
| 559 | void __iomem *base; | ||
| 560 | unsigned long pmdata[7]; | ||
| 561 | }; | ||
| 562 | |||
| 563 | static 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 | |||
| 579 | static 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 | |||
| 609 | static struct sysdev_class alchemy_ic_sysdev_class = { | ||
| 610 | .name = "ic", | ||
| 611 | .suspend = alchemy_ic_suspend, | ||
| 612 | .resume = alchemy_ic_resume, | ||
| 613 | }; | ||
| 614 | |||
| 615 | static 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 | } | ||
| 643 | device_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 */ | 
| 191 | void au1xxx_save_and_sleep(void); | 191 | void au1xxx_save_and_sleep(void); | 
| 192 | void au_sleep(void); | 192 | void au_sleep(void); | 
| 193 | void save_au1xxx_intctl(void); | ||
| 194 | void 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 | 
