Add power management register operations to support reboot and poweroff.

Signed-off-by: Qing Zhang <[email protected]>
---
 .../include/asm/mach-loongson64/loongson.h    |  8 ++++++
 arch/mips/loongson64/reset.c                  | 28 ++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/arch/mips/include/asm/mach-loongson64/loongson.h 
b/arch/mips/include/asm/mach-loongson64/loongson.h
index f7c3ab6d724e..9d254a7b438a 100644
--- a/arch/mips/include/asm/mach-loongson64/loongson.h
+++ b/arch/mips/include/asm/mach-loongson64/loongson.h
@@ -263,4 +263,12 @@ extern u64 loongson_freqctrl[MAX_PACKAGES];
 #define LOONGSON_PCIMAP_WIN(WIN, ADDR) \
        ((((ADDR)>>26) & LOONGSON_PCIMAP_PCIMAP_LO0) << ((WIN)*6))
 
+/* Loongson-2K1000 Power management related registers */
+#define        PM1_STS         0x0C /* Power Management1 Status Register */
+#define        PM1_CNT         0x14 /* Power Management 1 Control Register */
+#define        RST_CNT         0x30 /* Reset Control Register */
+#define        SLP_TYP         GENMASK(12, 10) /* Sleep Enable */
+#define        SLP_EN          BIT(13) /* Soft Off */
+#define        ACPI_OFF        0x7000
+
 #endif /* __ASM_MACH_LOONGSON64_LOONGSON_H */
diff --git a/arch/mips/loongson64/reset.c b/arch/mips/loongson64/reset.c
index 3bb8a1ed9348..b4348bf50538 100644
--- a/arch/mips/loongson64/reset.c
+++ b/arch/mips/loongson64/reset.c
@@ -18,9 +18,16 @@
 static void loongson_restart(char *command)
 {
 
-       void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
+       if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) {
+               unsigned long base;
 
-       fw_restart();
+               base = CKSEG1ADDR(LOONGSON_REG_BASE) + ACPI_OFF;
+               writel(1, (void *)(base + RST_CNT));
+       } else {
+               void (*fw_restart)(void) = (void 
*)loongson_sysconf.restart_addr;
+
+               fw_restart();
+       }
        while (1) {
                if (cpu_wait)
                        cpu_wait();
@@ -29,9 +36,22 @@ static void loongson_restart(char *command)
 
 static void loongson_poweroff(void)
 {
-       void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
 
-       fw_poweroff();
+       if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) {
+               unsigned long base;
+               unsigned int acpi_ctrl;
+
+               base = CKSEG1ADDR(LOONGSON_REG_BASE) + ACPI_OFF;
+               acpi_ctrl = readl((void *)(base + PM1_STS));
+               acpi_ctrl &= 0xffffffff;
+               writel(acpi_ctrl, (void *)(base + PM1_STS));
+               acpi_ctrl = SLP_EN | SLP_TYP;
+               writel(acpi_ctrl, (void *)(base + PM1_CNT));
+       } else {
+               void (*fw_poweroff)(void) = (void 
*)loongson_sysconf.poweroff_addr;
+
+               fw_poweroff();
+       }
        while (1) {
                if (cpu_wait)
                        cpu_wait();
-- 
2.31.0

Reply via email to