1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * loongson-specific suspend support |
4 | * |
5 | * Copyright (C) 2009 Lemote Inc. |
6 | * Author: Wu Zhangjin <wuzhangjin@gmail.com> |
7 | */ |
8 | #include <linux/suspend.h> |
9 | #include <linux/interrupt.h> |
10 | #include <linux/pm.h> |
11 | |
12 | #include <asm/i8259.h> |
13 | #include <asm/mipsregs.h> |
14 | |
15 | #include <loongson.h> |
16 | |
17 | static unsigned int __maybe_unused cached_master_mask; /* i8259A */ |
18 | static unsigned int __maybe_unused cached_slave_mask; |
19 | static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */ |
20 | |
21 | void arch_suspend_disable_irqs(void) |
22 | { |
23 | /* disable all mips events */ |
24 | local_irq_disable(); |
25 | |
26 | #ifdef CONFIG_I8259 |
27 | /* disable all events of i8259A */ |
28 | cached_slave_mask = inb(PIC_SLAVE_IMR); |
29 | cached_master_mask = inb(PIC_MASTER_IMR); |
30 | |
31 | outb(0xff, PIC_SLAVE_IMR); |
32 | inb(PIC_SLAVE_IMR); |
33 | outb(0xff, PIC_MASTER_IMR); |
34 | inb(PIC_MASTER_IMR); |
35 | #endif |
36 | /* disable all events of bonito */ |
37 | cached_bonito_irq_mask = LOONGSON_INTEN; |
38 | LOONGSON_INTENCLR = 0xffff; |
39 | (void)LOONGSON_INTENCLR; |
40 | } |
41 | |
42 | void arch_suspend_enable_irqs(void) |
43 | { |
44 | /* enable all mips events */ |
45 | local_irq_enable(); |
46 | #ifdef CONFIG_I8259 |
47 | /* only enable the cached events of i8259A */ |
48 | outb(cached_slave_mask, PIC_SLAVE_IMR); |
49 | outb(cached_master_mask, PIC_MASTER_IMR); |
50 | #endif |
51 | /* enable all cached events of bonito */ |
52 | LOONGSON_INTENSET = cached_bonito_irq_mask; |
53 | (void)LOONGSON_INTENSET; |
54 | } |
55 | |
56 | /* |
57 | * Setup the board-specific events for waking up loongson from wait mode |
58 | */ |
59 | void __weak setup_wakeup_events(void) |
60 | { |
61 | } |
62 | |
63 | void __weak mach_suspend(void) |
64 | { |
65 | } |
66 | |
67 | void __weak mach_resume(void) |
68 | { |
69 | } |
70 | |
71 | static int loongson_pm_enter(suspend_state_t state) |
72 | { |
73 | mach_suspend(); |
74 | |
75 | mach_resume(); |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int loongson_pm_valid_state(suspend_state_t state) |
81 | { |
82 | switch (state) { |
83 | case PM_SUSPEND_ON: |
84 | case PM_SUSPEND_STANDBY: |
85 | case PM_SUSPEND_MEM: |
86 | return 1; |
87 | |
88 | default: |
89 | return 0; |
90 | } |
91 | } |
92 | |
93 | static const struct platform_suspend_ops loongson_pm_ops = { |
94 | .valid = loongson_pm_valid_state, |
95 | .enter = loongson_pm_enter, |
96 | }; |
97 | |
98 | static int __init loongson_pm_init(void) |
99 | { |
100 | suspend_set_ops(ops: &loongson_pm_ops); |
101 | |
102 | return 0; |
103 | } |
104 | arch_initcall(loongson_pm_init); |
105 | |