[PATCH] MIPS: Loongson64: Add Loongson-2K1000 reset support

From: Qing Zhang
Date: Tue Apr 13 2021 - 21:26:38 EST


Add power management register operations to support reboot and poweroff.

Signed-off-by: Qing Zhang <zhangqing@xxxxxxxxxxx>
---
.../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