1*aaf9128aSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2da2014a2SPaul Mundt /*
3da2014a2SPaul Mundt * hp6x0 Power Management Routines
4da2014a2SPaul Mundt *
5da2014a2SPaul Mundt * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
6da2014a2SPaul Mundt */
7da2014a2SPaul Mundt #include <linux/init.h>
8da2014a2SPaul Mundt #include <linux/suspend.h>
9da2014a2SPaul Mundt #include <linux/errno.h>
10da2014a2SPaul Mundt #include <linux/time.h>
113e517627SMagnus Damm #include <linux/delay.h>
123e517627SMagnus Damm #include <linux/gfp.h>
13da2014a2SPaul Mundt #include <asm/io.h>
14da2014a2SPaul Mundt #include <asm/hd64461.h>
15f03c4866SPaul Mundt #include <asm/bl_bit.h>
167639a454SPaul Mundt #include <mach/hp6xx.h>
17da2014a2SPaul Mundt #include <cpu/dac.h>
183e517627SMagnus Damm #include <asm/freq.h>
193e517627SMagnus Damm #include <asm/watchdog.h>
203e517627SMagnus Damm
213e517627SMagnus Damm #define INTR_OFFSET 0x600
22da2014a2SPaul Mundt
23da2014a2SPaul Mundt #define STBCR 0xffffff82
24da2014a2SPaul Mundt #define STBCR2 0xffffff88
25da2014a2SPaul Mundt
263e517627SMagnus Damm #define STBCR_STBY 0x80
273e517627SMagnus Damm #define STBCR_MSTP2 0x04
283e517627SMagnus Damm
293e517627SMagnus Damm #define MCR 0xffffff68
303e517627SMagnus Damm #define RTCNT 0xffffff70
313e517627SMagnus Damm
323e517627SMagnus Damm #define MCR_RMODE 2
333e517627SMagnus Damm #define MCR_RFSH 4
343e517627SMagnus Damm
353e517627SMagnus Damm extern u8 wakeup_start;
363e517627SMagnus Damm extern u8 wakeup_end;
373e517627SMagnus Damm
pm_enter(void)383e517627SMagnus Damm static void pm_enter(void)
393e517627SMagnus Damm {
403e517627SMagnus Damm u8 stbcr, csr;
413e517627SMagnus Damm u16 frqcr, mcr;
423e517627SMagnus Damm u32 vbr_new, vbr_old;
433e517627SMagnus Damm
443e517627SMagnus Damm set_bl_bit();
453e517627SMagnus Damm
463e517627SMagnus Damm /* set wdt */
473e517627SMagnus Damm csr = sh_wdt_read_csr();
483e517627SMagnus Damm csr &= ~WTCSR_TME;
493e517627SMagnus Damm csr |= WTCSR_CKS_4096;
503e517627SMagnus Damm sh_wdt_write_csr(csr);
513e517627SMagnus Damm csr = sh_wdt_read_csr();
523e517627SMagnus Damm sh_wdt_write_cnt(0);
533e517627SMagnus Damm
543e517627SMagnus Damm /* disable PLL1 */
559d56dd3bSPaul Mundt frqcr = __raw_readw(FRQCR);
563e517627SMagnus Damm frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
579d56dd3bSPaul Mundt __raw_writew(frqcr, FRQCR);
583e517627SMagnus Damm
593e517627SMagnus Damm /* enable standby */
609d56dd3bSPaul Mundt stbcr = __raw_readb(STBCR);
619d56dd3bSPaul Mundt __raw_writeb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
623e517627SMagnus Damm
633e517627SMagnus Damm /* set self-refresh */
649d56dd3bSPaul Mundt mcr = __raw_readw(MCR);
659d56dd3bSPaul Mundt __raw_writew(mcr & ~MCR_RFSH, MCR);
663e517627SMagnus Damm
673e517627SMagnus Damm /* set interrupt handler */
683e517627SMagnus Damm asm volatile("stc vbr, %0" : "=r" (vbr_old));
693e517627SMagnus Damm vbr_new = get_zeroed_page(GFP_ATOMIC);
703e517627SMagnus Damm udelay(50);
713e517627SMagnus Damm memcpy((void*)(vbr_new + INTR_OFFSET),
723e517627SMagnus Damm &wakeup_start, &wakeup_end - &wakeup_start);
733e517627SMagnus Damm asm volatile("ldc %0, vbr" : : "r" (vbr_new));
743e517627SMagnus Damm
759d56dd3bSPaul Mundt __raw_writew(0, RTCNT);
769d56dd3bSPaul Mundt __raw_writew(mcr | MCR_RFSH | MCR_RMODE, MCR);
773e517627SMagnus Damm
783e517627SMagnus Damm cpu_sleep();
793e517627SMagnus Damm
803e517627SMagnus Damm asm volatile("ldc %0, vbr" : : "r" (vbr_old));
813e517627SMagnus Damm
823e517627SMagnus Damm free_page(vbr_new);
833e517627SMagnus Damm
843e517627SMagnus Damm /* enable PLL1 */
859d56dd3bSPaul Mundt frqcr = __raw_readw(FRQCR);
863e517627SMagnus Damm frqcr |= FRQCR_PSTBY;
879d56dd3bSPaul Mundt __raw_writew(frqcr, FRQCR);
883e517627SMagnus Damm udelay(50);
893e517627SMagnus Damm frqcr |= FRQCR_PLLEN;
909d56dd3bSPaul Mundt __raw_writew(frqcr, FRQCR);
913e517627SMagnus Damm
929d56dd3bSPaul Mundt __raw_writeb(stbcr, STBCR);
933e517627SMagnus Damm
943e517627SMagnus Damm clear_bl_bit();
953e517627SMagnus Damm }
963e517627SMagnus Damm
hp6x0_pm_enter(suspend_state_t state)97da2014a2SPaul Mundt static int hp6x0_pm_enter(suspend_state_t state)
98da2014a2SPaul Mundt {
99da2014a2SPaul Mundt u8 stbcr, stbcr2;
100da2014a2SPaul Mundt #ifdef CONFIG_HD64461_ENABLER
101da2014a2SPaul Mundt u8 scr;
102da2014a2SPaul Mundt u16 hd64461_stbcr;
103da2014a2SPaul Mundt #endif
104da2014a2SPaul Mundt
105da2014a2SPaul Mundt #ifdef CONFIG_HD64461_ENABLER
106da2014a2SPaul Mundt outb(0, HD64461_PCC1CSCIER);
107da2014a2SPaul Mundt
108da2014a2SPaul Mundt scr = inb(HD64461_PCC1SCR);
109da2014a2SPaul Mundt scr |= HD64461_PCCSCR_VCC1;
110da2014a2SPaul Mundt outb(scr, HD64461_PCC1SCR);
111da2014a2SPaul Mundt
112da2014a2SPaul Mundt hd64461_stbcr = inw(HD64461_STBCR);
113da2014a2SPaul Mundt hd64461_stbcr |= HD64461_STBCR_SPC1ST;
114da2014a2SPaul Mundt outw(hd64461_stbcr, HD64461_STBCR);
115da2014a2SPaul Mundt #endif
116da2014a2SPaul Mundt
1179d56dd3bSPaul Mundt __raw_writeb(0x1f, DACR);
118da2014a2SPaul Mundt
1199d56dd3bSPaul Mundt stbcr = __raw_readb(STBCR);
1209d56dd3bSPaul Mundt __raw_writeb(0x01, STBCR);
121da2014a2SPaul Mundt
1229d56dd3bSPaul Mundt stbcr2 = __raw_readb(STBCR2);
1239d56dd3bSPaul Mundt __raw_writeb(0x7f , STBCR2);
124da2014a2SPaul Mundt
125da2014a2SPaul Mundt outw(0xf07f, HD64461_SCPUCR);
126da2014a2SPaul Mundt
127da2014a2SPaul Mundt pm_enter();
128da2014a2SPaul Mundt
129da2014a2SPaul Mundt outw(0, HD64461_SCPUCR);
1309d56dd3bSPaul Mundt __raw_writeb(stbcr, STBCR);
1319d56dd3bSPaul Mundt __raw_writeb(stbcr2, STBCR2);
132da2014a2SPaul Mundt
133da2014a2SPaul Mundt #ifdef CONFIG_HD64461_ENABLER
134da2014a2SPaul Mundt hd64461_stbcr = inw(HD64461_STBCR);
135da2014a2SPaul Mundt hd64461_stbcr &= ~HD64461_STBCR_SPC1ST;
136da2014a2SPaul Mundt outw(hd64461_stbcr, HD64461_STBCR);
137da2014a2SPaul Mundt
138da2014a2SPaul Mundt outb(0x4c, HD64461_PCC1CSCIER);
139da2014a2SPaul Mundt outb(0x00, HD64461_PCC1CSCR);
140da2014a2SPaul Mundt #endif
141da2014a2SPaul Mundt
142da2014a2SPaul Mundt return 0;
143da2014a2SPaul Mundt }
144da2014a2SPaul Mundt
1452f55ac07SLionel Debroux static const struct platform_suspend_ops hp6x0_pm_ops = {
146da2014a2SPaul Mundt .enter = hp6x0_pm_enter,
147da2014a2SPaul Mundt .valid = suspend_valid_only_mem,
148da2014a2SPaul Mundt };
149da2014a2SPaul Mundt
hp6x0_pm_init(void)150da2014a2SPaul Mundt static int __init hp6x0_pm_init(void)
151da2014a2SPaul Mundt {
152da2014a2SPaul Mundt suspend_set_ops(&hp6x0_pm_ops);
153da2014a2SPaul Mundt return 0;
154da2014a2SPaul Mundt }
155da2014a2SPaul Mundt
156da2014a2SPaul Mundt late_initcall(hp6x0_pm_init);
157