1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * hp6x0 Power Management Routines 4 * 5 * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com> 6 */ 7 #include <linux/init.h> 8 #include <linux/suspend.h> 9 #include <linux/errno.h> 10 #include <linux/time.h> 11 #include <linux/delay.h> 12 #include <linux/gfp.h> 13 #include <asm/io.h> 14 #include <asm/hd64461.h> 15 #include <asm/bl_bit.h> 16 #include <mach/hp6xx.h> 17 #include <cpu/dac.h> 18 #include <asm/freq.h> 19 #include <asm/watchdog.h> 20 21 #define INTR_OFFSET 0x600 22 23 #define STBCR 0xffffff82 24 #define STBCR2 0xffffff88 25 26 #define STBCR_STBY 0x80 27 #define STBCR_MSTP2 0x04 28 29 #define MCR 0xffffff68 30 #define RTCNT 0xffffff70 31 32 #define MCR_RMODE 2 33 #define MCR_RFSH 4 34 35 extern u8 wakeup_start; 36 extern u8 wakeup_end; 37 38 static void pm_enter(void) 39 { 40 u8 stbcr, csr; 41 u16 frqcr, mcr; 42 u32 vbr_new, vbr_old; 43 44 set_bl_bit(); 45 46 /* set wdt */ 47 csr = sh_wdt_read_csr(); 48 csr &= ~WTCSR_TME; 49 csr |= WTCSR_CKS_4096; 50 sh_wdt_write_csr(csr); 51 csr = sh_wdt_read_csr(); 52 sh_wdt_write_cnt(0); 53 54 /* disable PLL1 */ 55 frqcr = __raw_readw(FRQCR); 56 frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY); 57 __raw_writew(frqcr, FRQCR); 58 59 /* enable standby */ 60 stbcr = __raw_readb(STBCR); 61 __raw_writeb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); 62 63 /* set self-refresh */ 64 mcr = __raw_readw(MCR); 65 __raw_writew(mcr & ~MCR_RFSH, MCR); 66 67 /* set interrupt handler */ 68 asm volatile("stc vbr, %0" : "=r" (vbr_old)); 69 vbr_new = get_zeroed_page(GFP_ATOMIC); 70 udelay(50); 71 memcpy((void*)(vbr_new + INTR_OFFSET), 72 &wakeup_start, &wakeup_end - &wakeup_start); 73 asm volatile("ldc %0, vbr" : : "r" (vbr_new)); 74 75 __raw_writew(0, RTCNT); 76 __raw_writew(mcr | MCR_RFSH | MCR_RMODE, MCR); 77 78 cpu_sleep(); 79 80 asm volatile("ldc %0, vbr" : : "r" (vbr_old)); 81 82 free_page(vbr_new); 83 84 /* enable PLL1 */ 85 frqcr = __raw_readw(FRQCR); 86 frqcr |= FRQCR_PSTBY; 87 __raw_writew(frqcr, FRQCR); 88 udelay(50); 89 frqcr |= FRQCR_PLLEN; 90 __raw_writew(frqcr, FRQCR); 91 92 __raw_writeb(stbcr, STBCR); 93 94 clear_bl_bit(); 95 } 96 97 static int hp6x0_pm_enter(suspend_state_t state) 98 { 99 u8 stbcr, stbcr2; 100 #ifdef CONFIG_HD64461_ENABLER 101 u8 scr; 102 u16 hd64461_stbcr; 103 #endif 104 105 #ifdef CONFIG_HD64461_ENABLER 106 outb(0, HD64461_PCC1CSCIER); 107 108 scr = inb(HD64461_PCC1SCR); 109 scr |= HD64461_PCCSCR_VCC1; 110 outb(scr, HD64461_PCC1SCR); 111 112 hd64461_stbcr = inw(HD64461_STBCR); 113 hd64461_stbcr |= HD64461_STBCR_SPC1ST; 114 outw(hd64461_stbcr, HD64461_STBCR); 115 #endif 116 117 __raw_writeb(0x1f, DACR); 118 119 stbcr = __raw_readb(STBCR); 120 __raw_writeb(0x01, STBCR); 121 122 stbcr2 = __raw_readb(STBCR2); 123 __raw_writeb(0x7f , STBCR2); 124 125 outw(0xf07f, HD64461_SCPUCR); 126 127 pm_enter(); 128 129 outw(0, HD64461_SCPUCR); 130 __raw_writeb(stbcr, STBCR); 131 __raw_writeb(stbcr2, STBCR2); 132 133 #ifdef CONFIG_HD64461_ENABLER 134 hd64461_stbcr = inw(HD64461_STBCR); 135 hd64461_stbcr &= ~HD64461_STBCR_SPC1ST; 136 outw(hd64461_stbcr, HD64461_STBCR); 137 138 outb(0x4c, HD64461_PCC1CSCIER); 139 outb(0x00, HD64461_PCC1CSCR); 140 #endif 141 142 return 0; 143 } 144 145 static const struct platform_suspend_ops hp6x0_pm_ops = { 146 .enter = hp6x0_pm_enter, 147 .valid = suspend_valid_only_mem, 148 }; 149 150 static int __init hp6x0_pm_init(void) 151 { 152 suspend_set_ops(&hp6x0_pm_ops); 153 return 0; 154 } 155 156 late_initcall(hp6x0_pm_init); 157