-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Thomas Bogendoerfer <[email protected]>
- Loading branch information
Showing
3 changed files
with
36 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |