| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 1 | /* linux/arch/arm/mach-exynos4/pm.c | 
 | 2 |  * | 
 | 3 |  * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 
 | 4 |  *		http://www.samsung.com | 
 | 5 |  * | 
 | 6 |  * EXYNOS4210 - Power Management support | 
 | 7 |  * | 
 | 8 |  * Based on arch/arm/mach-s3c2410/pm.c | 
 | 9 |  * Copyright (c) 2006 Simtec Electronics | 
 | 10 |  *	Ben Dooks <ben@simtec.co.uk> | 
 | 11 |  * | 
 | 12 |  * This program is free software; you can redistribute it and/or modify | 
 | 13 |  * it under the terms of the GNU General Public License version 2 as | 
 | 14 |  * published by the Free Software Foundation. | 
 | 15 | */ | 
 | 16 |  | 
 | 17 | #include <linux/init.h> | 
 | 18 | #include <linux/suspend.h> | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 19 | #include <linux/syscore_ops.h> | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 20 | #include <linux/io.h> | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 21 | #include <linux/err.h> | 
 | 22 | #include <linux/clk.h> | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 23 |  | 
 | 24 | #include <asm/cacheflush.h> | 
 | 25 | #include <asm/hardware/cache-l2x0.h> | 
| Shawn Guo | 63b870f | 2011-11-17 01:19:11 +0900 | [diff] [blame] | 26 | #include <asm/smp_scu.h> | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 27 |  | 
 | 28 | #include <plat/cpu.h> | 
 | 29 | #include <plat/pm.h> | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 30 | #include <plat/pll.h> | 
| MyungJoo Ham | b93cb91 | 2011-07-21 11:25:23 +0900 | [diff] [blame] | 31 | #include <plat/regs-srom.h> | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 32 |  | 
 | 33 | #include <mach/regs-irq.h> | 
 | 34 | #include <mach/regs-gpio.h> | 
 | 35 | #include <mach/regs-clock.h> | 
 | 36 | #include <mach/regs-pmu.h> | 
 | 37 | #include <mach/pm-core.h> | 
| Jaecheol Lee | e4cf2d1 | 2011-07-18 19:21:27 +0900 | [diff] [blame] | 38 | #include <mach/pmu.h> | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 39 |  | 
 | 40 | static struct sleep_save exynos4_set_clksrc[] = { | 
 | 41 | 	{ .reg = S5P_CLKSRC_MASK_TOP			, .val = 0x00000001, }, | 
 | 42 | 	{ .reg = S5P_CLKSRC_MASK_CAM			, .val = 0x11111111, }, | 
 | 43 | 	{ .reg = S5P_CLKSRC_MASK_TV			, .val = 0x00000111, }, | 
 | 44 | 	{ .reg = S5P_CLKSRC_MASK_LCD0			, .val = 0x00001111, }, | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 45 | 	{ .reg = S5P_CLKSRC_MASK_MAUDIO			, .val = 0x00000001, }, | 
 | 46 | 	{ .reg = S5P_CLKSRC_MASK_FSYS			, .val = 0x01011111, }, | 
 | 47 | 	{ .reg = S5P_CLKSRC_MASK_PERIL0			, .val = 0x01111111, }, | 
 | 48 | 	{ .reg = S5P_CLKSRC_MASK_PERIL1			, .val = 0x01110111, }, | 
 | 49 | 	{ .reg = S5P_CLKSRC_MASK_DMC			, .val = 0x00010000, }, | 
 | 50 | }; | 
 | 51 |  | 
| Jonghwan Choi | acd3561 | 2011-08-24 21:52:45 +0900 | [diff] [blame] | 52 | static struct sleep_save exynos4210_set_clksrc[] = { | 
 | 53 | 	{ .reg = S5P_CLKSRC_MASK_LCD1			, .val = 0x00001111, }, | 
 | 54 | }; | 
 | 55 |  | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 56 | static struct sleep_save exynos4_epll_save[] = { | 
 | 57 | 	SAVE_ITEM(S5P_EPLL_CON0), | 
 | 58 | 	SAVE_ITEM(S5P_EPLL_CON1), | 
 | 59 | }; | 
 | 60 |  | 
 | 61 | static struct sleep_save exynos4_vpll_save[] = { | 
 | 62 | 	SAVE_ITEM(S5P_VPLL_CON0), | 
 | 63 | 	SAVE_ITEM(S5P_VPLL_CON1), | 
 | 64 | }; | 
 | 65 |  | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 66 | static struct sleep_save exynos4_core_save[] = { | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 67 | 	/* GIC side */ | 
 | 68 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x000), | 
 | 69 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x004), | 
 | 70 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x008), | 
 | 71 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x00C), | 
 | 72 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x014), | 
 | 73 | 	SAVE_ITEM(S5P_VA_GIC_CPU + 0x018), | 
 | 74 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x000), | 
 | 75 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x004), | 
 | 76 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x100), | 
 | 77 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x104), | 
 | 78 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x108), | 
 | 79 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x300), | 
 | 80 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x304), | 
 | 81 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x308), | 
 | 82 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x400), | 
 | 83 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x404), | 
 | 84 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x408), | 
 | 85 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C), | 
 | 86 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x410), | 
 | 87 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x414), | 
 | 88 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x418), | 
 | 89 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C), | 
 | 90 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x420), | 
 | 91 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x424), | 
 | 92 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x428), | 
 | 93 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C), | 
 | 94 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x430), | 
 | 95 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x434), | 
 | 96 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x438), | 
 | 97 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C), | 
 | 98 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x440), | 
 | 99 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x444), | 
 | 100 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x448), | 
 | 101 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C), | 
 | 102 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x450), | 
 | 103 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x454), | 
 | 104 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x458), | 
 | 105 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C), | 
 | 106 |  | 
 | 107 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x800), | 
 | 108 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x804), | 
 | 109 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x808), | 
 | 110 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C), | 
 | 111 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x810), | 
 | 112 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x814), | 
 | 113 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x818), | 
 | 114 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C), | 
 | 115 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x820), | 
 | 116 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x824), | 
 | 117 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x828), | 
 | 118 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C), | 
 | 119 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x830), | 
 | 120 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x834), | 
 | 121 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x838), | 
 | 122 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C), | 
 | 123 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x840), | 
 | 124 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x844), | 
 | 125 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x848), | 
 | 126 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C), | 
 | 127 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x850), | 
 | 128 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x854), | 
 | 129 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x858), | 
 | 130 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C), | 
 | 131 |  | 
 | 132 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00), | 
 | 133 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04), | 
 | 134 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08), | 
 | 135 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C), | 
 | 136 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10), | 
 | 137 | 	SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14), | 
 | 138 |  | 
 | 139 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000), | 
 | 140 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010), | 
 | 141 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020), | 
 | 142 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030), | 
 | 143 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040), | 
 | 144 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050), | 
 | 145 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060), | 
 | 146 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070), | 
 | 147 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080), | 
 | 148 | 	SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090), | 
| MyungJoo Ham | b93cb91 | 2011-07-21 11:25:23 +0900 | [diff] [blame] | 149 |  | 
 | 150 | 	/* SROM side */ | 
 | 151 | 	SAVE_ITEM(S5P_SROM_BW), | 
 | 152 | 	SAVE_ITEM(S5P_SROM_BC0), | 
 | 153 | 	SAVE_ITEM(S5P_SROM_BC1), | 
 | 154 | 	SAVE_ITEM(S5P_SROM_BC2), | 
 | 155 | 	SAVE_ITEM(S5P_SROM_BC3), | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 156 | }; | 
 | 157 |  | 
 | 158 | static struct sleep_save exynos4_l2cc_save[] = { | 
 | 159 | 	SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL), | 
 | 160 | 	SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL), | 
 | 161 | 	SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL), | 
 | 162 | 	SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL), | 
 | 163 | 	SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), | 
 | 164 | }; | 
 | 165 |  | 
| Jaecheol Lee | f4ba4b0 | 2011-07-18 19:25:03 +0900 | [diff] [blame] | 166 | /* For Cortex-A9 Diagnostic and Power control register */ | 
 | 167 | static unsigned int save_arm_register[2]; | 
 | 168 |  | 
| Russell King | 29cb3cd | 2011-07-02 09:54:01 +0100 | [diff] [blame] | 169 | static int exynos4_cpu_suspend(unsigned long arg) | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 170 | { | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 171 | 	outer_flush_all(); | 
 | 172 |  | 
 | 173 | 	/* issue the standby signal into the pm unit. */ | 
 | 174 | 	cpu_do_idle(); | 
 | 175 |  | 
 | 176 | 	/* we should never get past here */ | 
 | 177 | 	panic("sleep resumed to originator?"); | 
 | 178 | } | 
 | 179 |  | 
 | 180 | static void exynos4_pm_prepare(void) | 
 | 181 | { | 
 | 182 | 	u32 tmp; | 
 | 183 |  | 
 | 184 | 	s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); | 
 | 185 | 	s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save)); | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 186 | 	s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); | 
 | 187 | 	s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 188 |  | 
 | 189 | 	tmp = __raw_readl(S5P_INFORM1); | 
 | 190 |  | 
 | 191 | 	/* Set value of power down register for sleep mode */ | 
 | 192 |  | 
| Jaecheol Lee | e4cf2d1 | 2011-07-18 19:21:27 +0900 | [diff] [blame] | 193 | 	exynos4_sys_powerdown_conf(SYS_SLEEP); | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 194 | 	__raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); | 
 | 195 |  | 
 | 196 | 	/* ensure at least INFORM0 has the resume address */ | 
 | 197 |  | 
 | 198 | 	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); | 
 | 199 |  | 
 | 200 | 	/* Before enter central sequence mode, clock src register have to set */ | 
 | 201 |  | 
 | 202 | 	s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); | 
 | 203 |  | 
| Jonghwan Choi | acd3561 | 2011-08-24 21:52:45 +0900 | [diff] [blame] | 204 | 	if (soc_is_exynos4210()) | 
 | 205 | 		s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); | 
 | 206 |  | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 207 | } | 
 | 208 |  | 
| Kay Sievers | 4a858cf | 2011-12-21 16:01:38 -0800 | [diff] [blame] | 209 | static int exynos4_pm_add(struct device *dev) | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 210 | { | 
 | 211 | 	pm_cpu_prep = exynos4_pm_prepare; | 
 | 212 | 	pm_cpu_sleep = exynos4_cpu_suspend; | 
 | 213 |  | 
 | 214 | 	return 0; | 
 | 215 | } | 
 | 216 |  | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 217 | static unsigned long pll_base_rate; | 
 | 218 |  | 
 | 219 | static void exynos4_restore_pll(void) | 
 | 220 | { | 
 | 221 | 	unsigned long pll_con, locktime, lockcnt; | 
 | 222 | 	unsigned long pll_in_rate; | 
 | 223 | 	unsigned int p_div, epll_wait = 0, vpll_wait = 0; | 
 | 224 |  | 
 | 225 | 	if (pll_base_rate == 0) | 
 | 226 | 		return; | 
 | 227 |  | 
 | 228 | 	pll_in_rate = pll_base_rate; | 
 | 229 |  | 
 | 230 | 	/* EPLL */ | 
 | 231 | 	pll_con = exynos4_epll_save[0].val; | 
 | 232 |  | 
 | 233 | 	if (pll_con & (1 << 31)) { | 
 | 234 | 		pll_con &= (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT); | 
 | 235 | 		p_div = (pll_con >> PLL46XX_PDIV_SHIFT); | 
 | 236 |  | 
 | 237 | 		pll_in_rate /= 1000000; | 
 | 238 |  | 
 | 239 | 		locktime = (3000 / pll_in_rate) * p_div; | 
 | 240 | 		lockcnt = locktime * 10000 / (10000 / pll_in_rate); | 
 | 241 |  | 
 | 242 | 		__raw_writel(lockcnt, S5P_EPLL_LOCK); | 
 | 243 |  | 
 | 244 | 		s3c_pm_do_restore_core(exynos4_epll_save, | 
 | 245 | 					ARRAY_SIZE(exynos4_epll_save)); | 
 | 246 | 		epll_wait = 1; | 
 | 247 | 	} | 
 | 248 |  | 
 | 249 | 	pll_in_rate = pll_base_rate; | 
 | 250 |  | 
 | 251 | 	/* VPLL */ | 
 | 252 | 	pll_con = exynos4_vpll_save[0].val; | 
 | 253 |  | 
 | 254 | 	if (pll_con & (1 << 31)) { | 
 | 255 | 		pll_in_rate /= 1000000; | 
 | 256 | 		/* 750us */ | 
 | 257 | 		locktime = 750; | 
 | 258 | 		lockcnt = locktime * 10000 / (10000 / pll_in_rate); | 
 | 259 |  | 
 | 260 | 		__raw_writel(lockcnt, S5P_VPLL_LOCK); | 
 | 261 |  | 
 | 262 | 		s3c_pm_do_restore_core(exynos4_vpll_save, | 
 | 263 | 					ARRAY_SIZE(exynos4_vpll_save)); | 
 | 264 | 		vpll_wait = 1; | 
 | 265 | 	} | 
 | 266 |  | 
 | 267 | 	/* Wait PLL locking */ | 
 | 268 |  | 
 | 269 | 	do { | 
 | 270 | 		if (epll_wait) { | 
 | 271 | 			pll_con = __raw_readl(S5P_EPLL_CON0); | 
 | 272 | 			if (pll_con & (1 << S5P_EPLLCON0_LOCKED_SHIFT)) | 
 | 273 | 				epll_wait = 0; | 
 | 274 | 		} | 
 | 275 |  | 
 | 276 | 		if (vpll_wait) { | 
 | 277 | 			pll_con = __raw_readl(S5P_VPLL_CON0); | 
 | 278 | 			if (pll_con & (1 << S5P_VPLLCON0_LOCKED_SHIFT)) | 
 | 279 | 				vpll_wait = 0; | 
 | 280 | 		} | 
 | 281 | 	} while (epll_wait || vpll_wait); | 
 | 282 | } | 
 | 283 |  | 
| Kay Sievers | 4a858cf | 2011-12-21 16:01:38 -0800 | [diff] [blame] | 284 | static struct subsys_interface exynos4_pm_interface = { | 
 | 285 | 	.name		= "exynos4_pm", | 
 | 286 | 	.subsys		= &exynos4_subsys, | 
 | 287 | 	.add_dev	= exynos4_pm_add, | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 288 | }; | 
 | 289 |  | 
 | 290 | static __init int exynos4_pm_drvinit(void) | 
 | 291 | { | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 292 | 	struct clk *pll_base; | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 293 | 	unsigned int tmp; | 
 | 294 |  | 
 | 295 | 	s3c_pm_init(); | 
 | 296 |  | 
 | 297 | 	/* All wakeup disable */ | 
 | 298 |  | 
 | 299 | 	tmp = __raw_readl(S5P_WAKEUP_MASK); | 
 | 300 | 	tmp |= ((0xFF << 8) | (0x1F << 1)); | 
 | 301 | 	__raw_writel(tmp, S5P_WAKEUP_MASK); | 
 | 302 |  | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 303 | 	pll_base = clk_get(NULL, "xtal"); | 
 | 304 |  | 
 | 305 | 	if (!IS_ERR(pll_base)) { | 
 | 306 | 		pll_base_rate = clk_get_rate(pll_base); | 
 | 307 | 		clk_put(pll_base); | 
 | 308 | 	} | 
 | 309 |  | 
| Kay Sievers | 4a858cf | 2011-12-21 16:01:38 -0800 | [diff] [blame] | 310 | 	return subsys_interface_register(&exynos4_pm_interface); | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 311 | } | 
 | 312 | arch_initcall(exynos4_pm_drvinit); | 
 | 313 |  | 
| Jaecheol Lee | 12974e9 | 2011-07-18 19:21:41 +0900 | [diff] [blame] | 314 | static int exynos4_pm_suspend(void) | 
 | 315 | { | 
 | 316 | 	unsigned long tmp; | 
 | 317 |  | 
 | 318 | 	/* Setting Central Sequence Register for power down mode */ | 
 | 319 |  | 
 | 320 | 	tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); | 
 | 321 | 	tmp &= ~S5P_CENTRAL_LOWPWR_CFG; | 
 | 322 | 	__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); | 
 | 323 |  | 
| Jongpill Lee | 00a351f | 2011-09-27 07:26:04 +0900 | [diff] [blame] | 324 | 	if (soc_is_exynos4212()) { | 
 | 325 | 		tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION); | 
 | 326 | 		tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM | | 
 | 327 | 			 S5P_USE_STANDBYWFE_ISP_ARM); | 
 | 328 | 		__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); | 
 | 329 | 	} | 
 | 330 |  | 
| Jaecheol Lee | f4ba4b0 | 2011-07-18 19:25:03 +0900 | [diff] [blame] | 331 | 	/* Save Power control register */ | 
 | 332 | 	asm ("mrc p15, 0, %0, c15, c0, 0" | 
 | 333 | 	     : "=r" (tmp) : : "cc"); | 
 | 334 | 	save_arm_register[0] = tmp; | 
 | 335 |  | 
 | 336 | 	/* Save Diagnostic register */ | 
 | 337 | 	asm ("mrc p15, 0, %0, c15, c0, 1" | 
 | 338 | 	     : "=r" (tmp) : : "cc"); | 
 | 339 | 	save_arm_register[1] = tmp; | 
 | 340 |  | 
| Jaecheol Lee | 12974e9 | 2011-07-18 19:21:41 +0900 | [diff] [blame] | 341 | 	return 0; | 
 | 342 | } | 
 | 343 |  | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 344 | static void exynos4_pm_resume(void) | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 345 | { | 
| Jaecheol Lee | e240ab1 | 2011-07-18 19:21:34 +0900 | [diff] [blame] | 346 | 	unsigned long tmp; | 
 | 347 |  | 
 | 348 | 	/* | 
 | 349 | 	 * If PMU failed while entering sleep mode, WFI will be | 
 | 350 | 	 * ignored by PMU and then exiting cpu_do_idle(). | 
 | 351 | 	 * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically | 
 | 352 | 	 * in this situation. | 
 | 353 | 	 */ | 
 | 354 | 	tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); | 
 | 355 | 	if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) { | 
 | 356 | 		tmp |= S5P_CENTRAL_LOWPWR_CFG; | 
 | 357 | 		__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); | 
 | 358 | 		/* No need to perform below restore code */ | 
 | 359 | 		goto early_wakeup; | 
 | 360 | 	} | 
| Jaecheol Lee | f4ba4b0 | 2011-07-18 19:25:03 +0900 | [diff] [blame] | 361 | 	/* Restore Power control register */ | 
 | 362 | 	tmp = save_arm_register[0]; | 
 | 363 | 	asm volatile ("mcr p15, 0, %0, c15, c0, 0" | 
 | 364 | 		      : : "r" (tmp) | 
 | 365 | 		      : "cc"); | 
 | 366 |  | 
 | 367 | 	/* Restore Diagnostic register */ | 
 | 368 | 	tmp = save_arm_register[1]; | 
 | 369 | 	asm volatile ("mcr p15, 0, %0, c15, c0, 1" | 
 | 370 | 		      : : "r" (tmp) | 
 | 371 | 		      : "cc"); | 
| Jaecheol Lee | e240ab1 | 2011-07-18 19:21:34 +0900 | [diff] [blame] | 372 |  | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 373 | 	/* For release retention */ | 
 | 374 |  | 
 | 375 | 	__raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); | 
 | 376 | 	__raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION); | 
 | 377 | 	__raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION); | 
 | 378 | 	__raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION); | 
 | 379 | 	__raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION); | 
 | 380 | 	__raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); | 
 | 381 | 	__raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); | 
 | 382 |  | 
 | 383 | 	s3c_pm_do_restore_core(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); | 
 | 384 |  | 
| Jaecheol Lee | 56c03d9 | 2011-07-18 19:25:13 +0900 | [diff] [blame] | 385 | 	exynos4_restore_pll(); | 
 | 386 |  | 
| Shawn Guo | 63b870f | 2011-11-17 01:19:11 +0900 | [diff] [blame] | 387 | 	scu_enable(S5P_VA_SCU); | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 388 |  | 
 | 389 | #ifdef CONFIG_CACHE_L2X0 | 
 | 390 | 	s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save)); | 
 | 391 | 	outer_inv_all(); | 
 | 392 | 	/* enable L2X0*/ | 
 | 393 | 	writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL); | 
 | 394 | #endif | 
| Jaecheol Lee | e240ab1 | 2011-07-18 19:21:34 +0900 | [diff] [blame] | 395 |  | 
 | 396 | early_wakeup: | 
 | 397 | 	return; | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 398 | } | 
 | 399 |  | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 400 | static struct syscore_ops exynos4_pm_syscore_ops = { | 
| Jaecheol Lee | 12974e9 | 2011-07-18 19:21:41 +0900 | [diff] [blame] | 401 | 	.suspend	= exynos4_pm_suspend, | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 402 | 	.resume		= exynos4_pm_resume, | 
 | 403 | }; | 
 | 404 |  | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 405 | static __init int exynos4_pm_syscore_init(void) | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 406 | { | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 407 | 	register_syscore_ops(&exynos4_pm_syscore_ops); | 
 | 408 | 	return 0; | 
| Jaecheol Lee | 1663895 | 2011-03-10 13:33:59 +0900 | [diff] [blame] | 409 | } | 
| Rafael J. Wysocki | bb072c3 | 2011-04-22 22:03:21 +0200 | [diff] [blame] | 410 | arch_initcall(exynos4_pm_syscore_init); |