]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
MIPS: Loongson64: Implement PM suspend for LEFI firmware
authorJiaxun Yang <jiaxun.yang@flygoat.com>
Tue, 7 May 2024 15:22:01 +0000 (16:22 +0100)
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>
Tue, 11 Jun 2024 11:03:50 +0000 (13:03 +0200)
Implement PM suspend for LEFI firmware.
Entering STR (Suspend to RAM) is as simple as save our context
then go to a firmware vector.
Wake is a little bit treaky as we need to setup some CP0 status
first, which can be done with smp_slave_setup.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
arch/mips/loongson64/Makefile
arch/mips/loongson64/pm.c
arch/mips/loongson64/sleeper.S [new file with mode: 0644]

index e806280bbb850ca0cdc9a1b2107e72006c489de7..cbba30dfddf5d0fd413f37ca91df27db7290fec4 100644 (file)
@@ -8,7 +8,7 @@ obj-$(CONFIG_MACH_LOONGSON64) += cop2-ex.o dma.o \
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_NUMA)     += numa.o
 obj-$(CONFIG_RS780_HPET) += hpet.o
-obj-$(CONFIG_SUSPEND) += pm.o
+obj-$(CONFIG_SUSPEND) += pm.o sleeper.o
 obj-$(CONFIG_PCI_QUIRKS) += vbios_quirk.o
 obj-$(CONFIG_CPU_LOONGSON3_CPUCFG_EMULATION) += cpucfg-emul.o
 obj-$(CONFIG_SYSFS) += boardinfo.o
index 7c8556f097812da6122037f95b113eeb1b09ec34..5f0604af8f13647b25d871eefaff64440f49f6d4 100644 (file)
@@ -6,98 +6,46 @@
  *  Author: Wu Zhangjin <wuzhangjin@gmail.com>
  */
 #include <linux/suspend.h>
-#include <linux/interrupt.h>
 #include <linux/pm.h>
 
-#include <asm/i8259.h>
 #include <asm/mipsregs.h>
 
 #include <loongson.h>
 
-static unsigned int __maybe_unused cached_master_mask; /* i8259A */
-static unsigned int __maybe_unused cached_slave_mask;
-static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */
+asmlinkage void loongson_lefi_sleep(unsigned long sleep_addr);
 
-void arch_suspend_disable_irqs(void)
+static int lefi_pm_enter(suspend_state_t state)
 {
-       /* disable all mips events */
-       local_irq_disable();
-
-#ifdef CONFIG_I8259
-       /* disable all events of i8259A */
-       cached_slave_mask = inb(PIC_SLAVE_IMR);
-       cached_master_mask = inb(PIC_MASTER_IMR);
-
-       outb(0xff, PIC_SLAVE_IMR);
-       inb(PIC_SLAVE_IMR);
-       outb(0xff, PIC_MASTER_IMR);
-       inb(PIC_MASTER_IMR);
-#endif
-       /* disable all events of bonito */
-       cached_bonito_irq_mask = LOONGSON_INTEN;
-       LOONGSON_INTENCLR = 0xffff;
-       (void)LOONGSON_INTENCLR;
-}
-
-void arch_suspend_enable_irqs(void)
-{
-       /* enable all mips events */
-       local_irq_enable();
-#ifdef CONFIG_I8259
-       /* only enable the cached events of i8259A */
-       outb(cached_slave_mask, PIC_SLAVE_IMR);
-       outb(cached_master_mask, PIC_MASTER_IMR);
-#endif
-       /* enable all cached events of bonito */
-       LOONGSON_INTENSET = cached_bonito_irq_mask;
-       (void)LOONGSON_INTENSET;
-}
-
-/*
- * Setup the board-specific events for waking up loongson from wait mode
- */
-void __weak setup_wakeup_events(void)
-{
-}
-
-void __weak mach_suspend(void)
-{
-}
-
-void __weak mach_resume(void)
-{
-}
-
-static int loongson_pm_enter(suspend_state_t state)
-{
-       mach_suspend();
-
-       mach_resume();
-
-       return 0;
+       switch (state) {
+       case PM_SUSPEND_MEM:
+               pm_set_suspend_via_firmware();
+               loongson_lefi_sleep(loongson_sysconf.suspend_addr);
+               pm_set_resume_via_firmware();
+               return 0;
+       default:
+               return -EINVAL;
+       }
 }
 
-static int loongson_pm_valid_state(suspend_state_t state)
+static int lefi_pm_valid_state(suspend_state_t state)
 {
        switch (state) {
-       case PM_SUSPEND_ON:
-       case PM_SUSPEND_STANDBY:
        case PM_SUSPEND_MEM:
-               return 1;
-
+               return !!loongson_sysconf.suspend_addr;
        default:
                return 0;
        }
 }
 
-static const struct platform_suspend_ops loongson_pm_ops = {
-       .valid  = loongson_pm_valid_state,
-       .enter  = loongson_pm_enter,
+static const struct platform_suspend_ops lefi_pm_ops = {
+       .valid  = lefi_pm_valid_state,
+       .enter  = lefi_pm_enter,
 };
 
 static int __init loongson_pm_init(void)
 {
-       suspend_set_ops(&loongson_pm_ops);
+       if (loongson_sysconf.fw_interface == LOONGSON_LEFI)
+               suspend_set_ops(&lefi_pm_ops);
 
        return 0;
 }
diff --git a/arch/mips/loongson64/sleeper.S b/arch/mips/loongson64/sleeper.S
new file mode 100644 (file)
index 0000000..04874b9
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  Copyright (C) 2024, Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *  Loongson EFI firmware sleeper routine
+ */
+
+#include <asm/asm.h>
+#include <asm/pm.h>
+
+#include <kernel-entry-init.h>
+
+LEAF(loongson_lefi_sleep)
+       SUSPEND_SAVE
+       jalr    a0
+    smp_slave_setup
+       RESUME_RESTORE_REGS_RETURN
+END(loongson_lefi_sleep)