Skip to content

Commit

Permalink
MIPS: Loongson64: Implement PM suspend for LEFI firmware
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Thomas Bogendoerfer <[email protected]>
  • Loading branch information
FlyGoat authored and opsiff committed Dec 25, 2024
1 parent 9d22d8e commit 5557efc
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 71 deletions.
2 changes: 1 addition & 1 deletion arch/mips/loongson64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,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
88 changes: 18 additions & 70 deletions arch/mips/loongson64/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,98 +6,46 @@
* Author: Wu Zhangjin <[email protected]>
*/
#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;
}
Expand Down
17 changes: 17 additions & 0 deletions arch/mips/loongson64/sleeper.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2024, Jiaxun Yang <[email protected]>
* 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)

0 comments on commit 5557efc

Please sign in to comment.