Messages in this thread | | | Subject | Re: [PATCH v2 3/3] soc: loongson2_pm: add power management support | From | zhuyinbo <> | Date | Mon, 12 Jun 2023 15:54:41 +0800 |
| |
在 2023/6/12 下午12:36, Huacai Chen 写道: > Hi, Yinbo, > > On Mon, May 22, 2023 at 5:33 PM Yinbo Zhu <zhuyinbo@loongson.cn> wrote: >> >> The Loongson-2's Power Management Controller was ACPI, supports ACPI >> S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To >> Disk), ACPI S5 (Soft Shutdown) and supports multiple wake-up methods >> (USB, GMAC, PWRBTN, etc.). This driver was to add Power Management >> Controller support that base on dts for Loongson-2 series SoCs. >> >> Signed-off-by: Liu Yun <liuyun@loongson.cn> >> Signed-off-by: Liu Peibao <liupeibao@loongson.cn> >> Signed-off-by: Yinbo Zhu <zhuyinbo@loongson.cn> >> --- >> MAINTAINERS | 1 + >> drivers/soc/loongson/Kconfig | 10 ++ >> drivers/soc/loongson/Makefile | 1 + >> drivers/soc/loongson/loongson2_pm.c | 235 ++++++++++++++++++++++++++++ >> 4 files changed, 247 insertions(+) >> create mode 100644 drivers/soc/loongson/loongson2_pm.c >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index bcd05f1fa5c1..7c4ad0cbaeff 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -12195,6 +12195,7 @@ M: Yinbo Zhu <zhuyinbo@loongson.cn> >> L: linux-pm@vger.kernel.org >> S: Maintained >> F: Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml >> +F: drivers/soc/loongson/loongson2_pm.c >> >> LOONGSON-2 SOC SERIES PINCTRL DRIVER >> M: zhanghongchen <zhanghongchen@loongson.cn> >> diff --git a/drivers/soc/loongson/Kconfig b/drivers/soc/loongson/Kconfig >> index 707f56358dc4..2431a0bcbd84 100644 >> --- a/drivers/soc/loongson/Kconfig >> +++ b/drivers/soc/loongson/Kconfig >> @@ -16,3 +16,13 @@ config LOONGSON2_GUTS >> SoCs. Initially only reading SVR and registering soc device are >> supported. Other guts accesses, such as reading firmware configuration >> by default, should eventually be added into this driver as well. >> + >> +config LOONGSON2_PM >> + bool "Loongson-2 SoC Power Management Controller Driver" >> + depends on LOONGARCH && OF >> + help >> + The Loongson-2's Power Management Controller was ACPI, supports ACPI >> + S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To >> + Disk), ACPI S5 (Soft Shutdown) and supports multiple wake-up methods >> + (USB, GMAC, PWRBTN, etc.). This driver was to add Power Management >> + Controller support that base on dts for Loongson-2 series SoCs. >> diff --git a/drivers/soc/loongson/Makefile b/drivers/soc/loongson/Makefile >> index 263c486df638..4118f50f55e2 100644 >> --- a/drivers/soc/loongson/Makefile >> +++ b/drivers/soc/loongson/Makefile >> @@ -4,3 +4,4 @@ >> # >> >> obj-$(CONFIG_LOONGSON2_GUTS) += loongson2_guts.o >> +obj-$(CONFIG_LOONGSON2_PM) += loongson2_pm.o >> diff --git a/drivers/soc/loongson/loongson2_pm.c b/drivers/soc/loongson/loongson2_pm.c >> new file mode 100644 >> index 000000000000..cd96a1ebbb6c >> --- /dev/null >> +++ b/drivers/soc/loongson/loongson2_pm.c >> @@ -0,0 +1,235 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Loongson-2 PM Support >> + * >> + * Copyright (C) 2023 Loongson Technology Corporation Limited >> + */ >> + >> +#include <linux/io.h> >> +#include <linux/of.h> >> +#include <linux/init.h> >> +#include <linux/input.h> >> +#include <linux/suspend.h> >> +#include <linux/interrupt.h> >> +#include <linux/pm_wakeirq.h> >> +#include <linux/platform_device.h> >> +#include <asm/bootinfo.h> >> +#include <asm/suspend.h> >> + >> +#define LOONGSON2_PM1_CNT_REG 0x14 >> +#define LOONGSON2_PM1_STS_REG 0x0c >> +#define LOONGSON2_PM1_ENA_REG 0x10 >> +#define LOONGSON2_GPE0_STS_REG 0x28 >> +#define LOONGSON2_GPE0_ENA_REG 0x2c >> + >> +#define LOONGSON2_PM1_PWRBTN_STS BIT(8) >> +#define LOONGSON2_PM1_PCIEXP_WAKE_STS BIT(14) >> +#define LOONGSON2_PM1_WAKE_STS BIT(15) >> +#define LOONGSON2_PM1_CNT_INT_EN BIT(0) >> +#define LOONGSON2_PM1_PWRBTN_EN LOONGSON2_PM1_PWRBTN_STS >> + >> +static struct loongson2_pm { >> + void __iomem *base; >> + struct input_dev *dev; >> + bool suspended; >> +} loongson2_pm; >> + >> +#define loongson2_pm_readw(reg) readw(loongson2_pm.base + reg) >> +#define loongson2_pm_readl(reg) readl(loongson2_pm.base + reg) >> +#define loongson2_pm_writew(val, reg) writew(val, loongson2_pm.base + reg) >> +#define loongson2_pm_writel(val, reg) writel(val, loongson2_pm.base + reg) >> + >> +static void loongson2_pm_status_clear(void) >> +{ >> + u16 value; >> + >> + value = loongson2_pm_readw(LOONGSON2_PM1_STS_REG); >> + value |= (LOONGSON2_PM1_PWRBTN_STS | LOONGSON2_PM1_PCIEXP_WAKE_STS | >> + LOONGSON2_PM1_WAKE_STS); >> + loongson2_pm_writew(value, LOONGSON2_PM1_STS_REG); >> + loongson2_pm_writel(loongson2_pm_readl(LOONGSON2_GPE0_STS_REG), >> + LOONGSON2_GPE0_STS_REG); >> +} >> + >> +static void loongson2_pm_irq_enable(void) >> +{ >> + u16 value; >> + >> + value = loongson2_pm_readw(LOONGSON2_PM1_CNT_REG); >> + value |= LOONGSON2_PM1_CNT_INT_EN; >> + loongson2_pm_writew(value, LOONGSON2_PM1_CNT_REG); >> +} >> + >> +static void loongson2_pm_pwrbtn_irq_enable(void) >> +{ >> + u16 value; >> + >> + loongson2_pm_irq_enable(); >> + >> + value = loongson2_pm_readw(LOONGSON2_PM1_ENA_REG); >> + value |= LOONGSON2_PM1_PWRBTN_EN; >> + loongson2_pm_writew(value, LOONGSON2_PM1_ENA_REG); >> +} > You can combine these two functions as loongson2_power_button_irq_enable().
okay, I got it.
> >> + >> +static void loongson2_pm_mach_resume(void) >> +{ >> + loongson_common_resume(); >> + loongson2_pm_irq_enable(); >> +} >> + >> +static void loongson2_pm_mach_suspend(void) >> +{ >> + loongson2_pm_status_clear(); >> + loongson_common_suspend(); >> +} >> + >> +static int loongson2_suspend_enter(suspend_state_t state) >> +{ >> + loongson2_pm_mach_suspend(); >> + loongson_suspend_enter(); >> + pm_set_resume_via_firmware(); >> + loongson2_pm_mach_resume(); >> + >> + return 0; >> +} > After some thinkings, I found these three simple function can be combined as: > static int loongson2_suspend_enter(suspend_state_t state) > { > loongson2_pm_status_clear(); > loongson_common_suspend(); > loongson_suspend_enter(); > loongson_common_resume(); > loongson2_pm_irq_enable(); > pm_set_resume_via_firmware(); > > return 0; > } > > After this combining, > loongson_common_suspend()/loongson_suspend_enter()/loongson_common_resume() > can be still use the old naming > loongarch_common_suspend()/loongarch_suspend_enter()/loongarch_common_resume(). >
okay, I got it.
>> + >> +static int loongson2_suspend_begin(suspend_state_t state) >> +{ >> + pm_set_suspend_via_firmware(); >> + >> + return 0; >> +} >> + >> +static int loongson2_suspend_valid_state(suspend_state_t state) >> +{ >> + if (state == PM_SUSPEND_MEM) >> + return !!loongson_sysconf.suspend_addr; >> + >> + return 0; >> +} >> + >> +static const struct platform_suspend_ops loongson2_suspend_ops = { >> + .valid = loongson2_suspend_valid_state, >> + .begin = loongson2_suspend_begin, >> + .enter = loongson2_suspend_enter, >> +}; >> + >> +static int loongson2_pm_pwrbtn_init(struct device *dev, int irq) >> +{ >> + int ret; >> + struct input_dev *pwrbt; > Rename loongson2_pm_pwrbtn_init() to loongson2_power_button_init() > and rename 'pwrbt' to 'pwrbtn' or just 'button' is better.
okay, I got it.
Thanks, Yinbo
| |