^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * pmu.c, Power Management Unit routines for NEC VR4100 series.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2003-2007 Yoichi Yuasa <yuasa@linux-mips.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/idle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define PMU_TYPE1_BASE 0x0b0000a0UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define PMU_TYPE1_SIZE 0x0eUL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define PMU_TYPE2_BASE 0x0f0000c0UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define PMU_TYPE2_SIZE 0x10UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define PMUCNT2REG 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define SOFTRST 0x0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static void __iomem *pmu_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define pmu_read(offset) readw(pmu_base + (offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define pmu_write(offset, value) writew((value), pmu_base + (offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void __cpuidle vr41xx_cpu_wait(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) local_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!need_resched())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * "standby" sets IE bit of the CP0_STATUS to 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) __asm__("standby;\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static inline void software_reset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) uint16_t pmucnt2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) case CPU_VR4122:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) case CPU_VR4131:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) case CPU_VR4133:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) pmucnt2 = pmu_read(PMUCNT2REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pmucnt2 |= SOFTRST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) pmu_write(PMUCNT2REG, pmucnt2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) set_c0_status(ST0_BEV | ST0_ERL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __flush_cache_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) write_c0_wired(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) __asm__("jr %0"::"r"(0xbfc00000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void vr41xx_restart(char *command)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) local_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) software_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) while (1) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static void vr41xx_halt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) local_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) printk(KERN_NOTICE "\nYou can turn off the power supply\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) __asm__("hibernate;\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int __init vr41xx_pmu_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned long start, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case CPU_VR4111:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case CPU_VR4121:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) start = PMU_TYPE1_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) size = PMU_TYPE1_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case CPU_VR4122:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case CPU_VR4131:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case CPU_VR4133:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) start = PMU_TYPE2_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) size = PMU_TYPE2_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) printk("Unexpected CPU of NEC VR4100 series\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (request_mem_region(start, size, "PMU") == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) pmu_base = ioremap(start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (pmu_base == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) release_mem_region(start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) cpu_wait = vr41xx_cpu_wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) _machine_restart = vr41xx_restart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) _machine_halt = vr41xx_halt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pm_power_off = vr41xx_halt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) core_initcall(vr41xx_pmu_init);