18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * BRIEF MODULE DESCRIPTION
38c2ecf20Sopenharmony_ci *	Au1xx0 Power Management routines.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2001, 2008 MontaVista Software Inc.
68c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc. <source@mvista.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Some of the routines are right out of init/main.c, whose
98c2ecf20Sopenharmony_ci *  copyrights apply here.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  This program is free software; you can redistribute	 it and/or modify it
128c2ecf20Sopenharmony_ci *  under  the terms of	 the GNU General  Public License as published by the
138c2ecf20Sopenharmony_ci *  Free Software Foundation;  either version 2 of the	License, or (at your
148c2ecf20Sopenharmony_ci *  option) any later version.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
178c2ecf20Sopenharmony_ci *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
188c2ecf20Sopenharmony_ci *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
198c2ecf20Sopenharmony_ci *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
208c2ecf20Sopenharmony_ci *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
218c2ecf20Sopenharmony_ci *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
228c2ecf20Sopenharmony_ci *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
238c2ecf20Sopenharmony_ci *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
248c2ecf20Sopenharmony_ci *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
258c2ecf20Sopenharmony_ci *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *  You should have received a copy of the  GNU General Public License along
288c2ecf20Sopenharmony_ci *  with this program; if not, write  to the Free Software Foundation, Inc.,
298c2ecf20Sopenharmony_ci *  675 Mass Ave, Cambridge, MA 02139, USA.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <linux/pm.h>
338c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
348c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
378c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1000.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * We need to save/restore a bunch of core registers that are
418c2ecf20Sopenharmony_ci * either volatile or reset to some state across a processor sleep.
428c2ecf20Sopenharmony_ci * If reading a register doesn't provide a proper result for a
438c2ecf20Sopenharmony_ci * later restore, we have to provide a function for loading that
448c2ecf20Sopenharmony_ci * register and save a copy.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * We only have to save/restore registers that aren't otherwise
478c2ecf20Sopenharmony_ci * done as part of a driver pm_* function.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_cistatic unsigned int sleep_sys_clocks[5];
508c2ecf20Sopenharmony_cistatic unsigned int sleep_sys_pinfunc;
518c2ecf20Sopenharmony_cistatic unsigned int sleep_static_memctlr[4][3];
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void save_core_regs(void)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	/* Clocks and PLLs. */
578c2ecf20Sopenharmony_ci	sleep_sys_clocks[0] = alchemy_rdsys(AU1000_SYS_FREQCTRL0);
588c2ecf20Sopenharmony_ci	sleep_sys_clocks[1] = alchemy_rdsys(AU1000_SYS_FREQCTRL1);
598c2ecf20Sopenharmony_ci	sleep_sys_clocks[2] = alchemy_rdsys(AU1000_SYS_CLKSRC);
608c2ecf20Sopenharmony_ci	sleep_sys_clocks[3] = alchemy_rdsys(AU1000_SYS_CPUPLL);
618c2ecf20Sopenharmony_ci	sleep_sys_clocks[4] = alchemy_rdsys(AU1000_SYS_AUXPLL);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* pin mux config */
648c2ecf20Sopenharmony_ci	sleep_sys_pinfunc = alchemy_rdsys(AU1000_SYS_PINFUNC);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* Save the static memory controller configuration. */
678c2ecf20Sopenharmony_ci	sleep_static_memctlr[0][0] = alchemy_rdsmem(AU1000_MEM_STCFG0);
688c2ecf20Sopenharmony_ci	sleep_static_memctlr[0][1] = alchemy_rdsmem(AU1000_MEM_STTIME0);
698c2ecf20Sopenharmony_ci	sleep_static_memctlr[0][2] = alchemy_rdsmem(AU1000_MEM_STADDR0);
708c2ecf20Sopenharmony_ci	sleep_static_memctlr[1][0] = alchemy_rdsmem(AU1000_MEM_STCFG1);
718c2ecf20Sopenharmony_ci	sleep_static_memctlr[1][1] = alchemy_rdsmem(AU1000_MEM_STTIME1);
728c2ecf20Sopenharmony_ci	sleep_static_memctlr[1][2] = alchemy_rdsmem(AU1000_MEM_STADDR1);
738c2ecf20Sopenharmony_ci	sleep_static_memctlr[2][0] = alchemy_rdsmem(AU1000_MEM_STCFG2);
748c2ecf20Sopenharmony_ci	sleep_static_memctlr[2][1] = alchemy_rdsmem(AU1000_MEM_STTIME2);
758c2ecf20Sopenharmony_ci	sleep_static_memctlr[2][2] = alchemy_rdsmem(AU1000_MEM_STADDR2);
768c2ecf20Sopenharmony_ci	sleep_static_memctlr[3][0] = alchemy_rdsmem(AU1000_MEM_STCFG3);
778c2ecf20Sopenharmony_ci	sleep_static_memctlr[3][1] = alchemy_rdsmem(AU1000_MEM_STTIME3);
788c2ecf20Sopenharmony_ci	sleep_static_memctlr[3][2] = alchemy_rdsmem(AU1000_MEM_STADDR3);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void restore_core_regs(void)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	/* restore clock configuration.  Writing CPUPLL last will
848c2ecf20Sopenharmony_ci	 * stall a bit and stabilize other clocks (unless this is
858c2ecf20Sopenharmony_ci	 * one of those Au1000 with a write-only PLL, where we dont
868c2ecf20Sopenharmony_ci	 * have a valid value)
878c2ecf20Sopenharmony_ci	 */
888c2ecf20Sopenharmony_ci	alchemy_wrsys(sleep_sys_clocks[0], AU1000_SYS_FREQCTRL0);
898c2ecf20Sopenharmony_ci	alchemy_wrsys(sleep_sys_clocks[1], AU1000_SYS_FREQCTRL1);
908c2ecf20Sopenharmony_ci	alchemy_wrsys(sleep_sys_clocks[2], AU1000_SYS_CLKSRC);
918c2ecf20Sopenharmony_ci	alchemy_wrsys(sleep_sys_clocks[4], AU1000_SYS_AUXPLL);
928c2ecf20Sopenharmony_ci	if (!au1xxx_cpu_has_pll_wo())
938c2ecf20Sopenharmony_ci		alchemy_wrsys(sleep_sys_clocks[3], AU1000_SYS_CPUPLL);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	alchemy_wrsys(sleep_sys_pinfunc, AU1000_SYS_PINFUNC);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* Restore the static memory controller configuration. */
988c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[0][0], AU1000_MEM_STCFG0);
998c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[0][1], AU1000_MEM_STTIME0);
1008c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[0][2], AU1000_MEM_STADDR0);
1018c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[1][0], AU1000_MEM_STCFG1);
1028c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[1][1], AU1000_MEM_STTIME1);
1038c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[1][2], AU1000_MEM_STADDR1);
1048c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[2][0], AU1000_MEM_STCFG2);
1058c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[2][1], AU1000_MEM_STTIME2);
1068c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[2][2], AU1000_MEM_STADDR2);
1078c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[3][0], AU1000_MEM_STCFG3);
1088c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[3][1], AU1000_MEM_STTIME3);
1098c2ecf20Sopenharmony_ci	alchemy_wrsmem(sleep_static_memctlr[3][2], AU1000_MEM_STADDR3);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_civoid au_sleep(void)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	save_core_regs();
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	switch (alchemy_get_cputype()) {
1178c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1000:
1188c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1500:
1198c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1100:
1208c2ecf20Sopenharmony_ci		alchemy_sleep_au1000();
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1550:
1238c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1200:
1248c2ecf20Sopenharmony_ci		alchemy_sleep_au1550();
1258c2ecf20Sopenharmony_ci		break;
1268c2ecf20Sopenharmony_ci	case ALCHEMY_CPU_AU1300:
1278c2ecf20Sopenharmony_ci		alchemy_sleep_au1300();
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	restore_core_regs();
1328c2ecf20Sopenharmony_ci}
133