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