Commit 68557c59 authored by Jiaxun Yang's avatar Jiaxun Yang Committed by Thomas Bogendoerfer
Browse files

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: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
parent 2226d454
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+18 −70
Original line number Diff line number Diff line
@@ -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();

	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;
}
+17 −0
Original line number Diff line number Diff line
/* 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)