MIPS: Loongson64: Implement PM suspend for LEFI firmware
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>
This commit is contained in:
parent
2226d454db
commit
68557c59a5
@ -8,7 +8,7 @@ obj-$(CONFIG_MACH_LOONGSON64) += cop2-ex.o dma.o \
|
|||||||
obj-$(CONFIG_SMP) += smp.o
|
obj-$(CONFIG_SMP) += smp.o
|
||||||
obj-$(CONFIG_NUMA) += numa.o
|
obj-$(CONFIG_NUMA) += numa.o
|
||||||
obj-$(CONFIG_RS780_HPET) += hpet.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_PCI_QUIRKS) += vbios_quirk.o
|
||||||
obj-$(CONFIG_CPU_LOONGSON3_CPUCFG_EMULATION) += cpucfg-emul.o
|
obj-$(CONFIG_CPU_LOONGSON3_CPUCFG_EMULATION) += cpucfg-emul.o
|
||||||
obj-$(CONFIG_SYSFS) += boardinfo.o
|
obj-$(CONFIG_SYSFS) += boardinfo.o
|
||||||
|
@ -6,98 +6,46 @@
|
|||||||
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
|
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
|
||||||
*/
|
*/
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
|
|
||||||
#include <asm/i8259.h>
|
|
||||||
#include <asm/mipsregs.h>
|
#include <asm/mipsregs.h>
|
||||||
|
|
||||||
#include <loongson.h>
|
#include <loongson.h>
|
||||||
|
|
||||||
static unsigned int __maybe_unused cached_master_mask; /* i8259A */
|
asmlinkage void loongson_lefi_sleep(unsigned long sleep_addr);
|
||||||
static unsigned int __maybe_unused cached_slave_mask;
|
|
||||||
static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int loongson_pm_valid_state(suspend_state_t state)
|
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case PM_SUSPEND_ON:
|
|
||||||
case PM_SUSPEND_STANDBY:
|
|
||||||
case PM_SUSPEND_MEM:
|
case PM_SUSPEND_MEM:
|
||||||
return 1;
|
pm_set_suspend_via_firmware();
|
||||||
|
loongson_lefi_sleep(loongson_sysconf.suspend_addr);
|
||||||
|
pm_set_resume_via_firmware();
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lefi_pm_valid_state(suspend_state_t state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case PM_SUSPEND_MEM:
|
||||||
|
return !!loongson_sysconf.suspend_addr;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct platform_suspend_ops loongson_pm_ops = {
|
static const struct platform_suspend_ops lefi_pm_ops = {
|
||||||
.valid = loongson_pm_valid_state,
|
.valid = lefi_pm_valid_state,
|
||||||
.enter = loongson_pm_enter,
|
.enter = lefi_pm_enter,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init loongson_pm_init(void)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
17
arch/mips/loongson64/sleeper.S
Normal file
17
arch/mips/loongson64/sleeper.S
Normal file
@ -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)
|
Loading…
x
Reference in New Issue
Block a user