pm.c (3102B)
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 35extern u8 wakeup_start; 36extern u8 wakeup_end; 37 38static 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 97static 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 145static const struct platform_suspend_ops hp6x0_pm_ops = { 146 .enter = hp6x0_pm_enter, 147 .valid = suspend_valid_only_mem, 148}; 149 150static int __init hp6x0_pm_init(void) 151{ 152 suspend_set_ops(&hp6x0_pm_ops); 153 return 0; 154} 155 156late_initcall(hp6x0_pm_init);