• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/blackfin/mach-common/
1/*
2 * Blackfin power management
3 *
4 * Copyright 2006-2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2
7 * based on arm/mach-omap/pm.c
8 *    Copyright 2001, Cliff Brake <cbrake@accelent.com> and others
9 */
10
11#include <linux/suspend.h>
12#include <linux/sched.h>
13#include <linux/proc_fs.h>
14#include <linux/slab.h>
15#include <linux/io.h>
16#include <linux/irq.h>
17
18#include <asm/cplb.h>
19#include <asm/gpio.h>
20#include <asm/dma.h>
21#include <asm/dpmc.h>
22
23
24void bfin_pm_suspend_standby_enter(void)
25{
26	unsigned long flags;
27
28	local_irq_save_hw(flags);
29	bfin_pm_standby_setup();
30
31#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
32	sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
33#else
34	sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
35#endif
36
37	bfin_pm_standby_restore();
38
39#ifdef SIC_IWR0
40	bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
41# ifdef SIC_IWR1
42	/* BF52x system reset does not properly reset SIC_IWR1 which
43	 * will screw up the bootrom as it relies on MDMA0/1 waking it
44	 * up from IDLE instructions.  See this report for more info:
45	 * http://blackfin.uclinux.org/gf/tracker/4323
46	 */
47	if (ANOMALY_05000435)
48		bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
49	else
50		bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
51# endif
52# ifdef SIC_IWR2
53	bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
54# endif
55#else
56	bfin_write_SIC_IWR(IWR_DISABLE_ALL);
57#endif
58
59	local_irq_restore_hw(flags);
60}
61
62int bf53x_suspend_l1_mem(unsigned char *memptr)
63{
64	dma_memcpy_nocache(memptr, (const void *) L1_CODE_START,
65			L1_CODE_LENGTH);
66	dma_memcpy_nocache(memptr + L1_CODE_LENGTH,
67			(const void *) L1_DATA_A_START, L1_DATA_A_LENGTH);
68	dma_memcpy_nocache(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH,
69			(const void *) L1_DATA_B_START, L1_DATA_B_LENGTH);
70	memcpy(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH +
71			L1_DATA_B_LENGTH, (const void *) L1_SCRATCH_START,
72			L1_SCRATCH_LENGTH);
73
74	return 0;
75}
76
77int bf53x_resume_l1_mem(unsigned char *memptr)
78{
79	dma_memcpy_nocache((void *) L1_CODE_START, memptr, L1_CODE_LENGTH);
80	dma_memcpy_nocache((void *) L1_DATA_A_START, memptr + L1_CODE_LENGTH,
81			L1_DATA_A_LENGTH);
82	dma_memcpy_nocache((void *) L1_DATA_B_START, memptr + L1_CODE_LENGTH +
83			L1_DATA_A_LENGTH, L1_DATA_B_LENGTH);
84	memcpy((void *) L1_SCRATCH_START, memptr + L1_CODE_LENGTH +
85			L1_DATA_A_LENGTH + L1_DATA_B_LENGTH, L1_SCRATCH_LENGTH);
86
87	return 0;
88}
89
90#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
91static void flushinv_all_dcache(void)
92{
93	u32 way, bank, subbank, set;
94	u32 status, addr;
95	u32 dmem_ctl = bfin_read_DMEM_CONTROL();
96
97	for (bank = 0; bank < 2; ++bank) {
98		if (!(dmem_ctl & (1 << (DMC1_P - bank))))
99			continue;
100
101		for (way = 0; way < 2; ++way)
102			for (subbank = 0; subbank < 4; ++subbank)
103				for (set = 0; set < 64; ++set) {
104
105					bfin_write_DTEST_COMMAND(
106						way << 26 |
107						bank << 23 |
108						subbank << 16 |
109						set << 5
110					);
111					CSYNC();
112					status = bfin_read_DTEST_DATA0();
113
114					/* only worry about valid/dirty entries */
115					if ((status & 0x3) != 0x3)
116						continue;
117
118					/* construct the address using the tag */
119					addr = (status & 0xFFFFC800) | (subbank << 12) | (set << 5);
120
121					/* flush it */
122					__asm__ __volatile__("FLUSHINV[%0];" : : "a"(addr));
123				}
124	}
125}
126#endif
127
128int bfin_pm_suspend_mem_enter(void)
129{
130	unsigned long flags;
131	int wakeup, ret;
132
133	unsigned char *memptr = kmalloc(L1_CODE_LENGTH + L1_DATA_A_LENGTH
134					 + L1_DATA_B_LENGTH + L1_SCRATCH_LENGTH,
135					  GFP_KERNEL);
136
137	if (memptr == NULL) {
138		panic("bf53x_suspend_l1_mem malloc failed");
139		return -ENOMEM;
140	}
141
142	wakeup = bfin_read_VR_CTL() & ~FREQ;
143	wakeup |= SCKELOW;
144
145#ifdef CONFIG_PM_BFIN_WAKE_PH6
146	wakeup |= PHYWE;
147#endif
148#ifdef CONFIG_PM_BFIN_WAKE_GP
149	wakeup |= GPWE;
150#endif
151
152	local_irq_save_hw(flags);
153
154	ret = blackfin_dma_suspend();
155
156	if (ret) {
157		local_irq_restore_hw(flags);
158		kfree(memptr);
159		return ret;
160	}
161
162	bfin_gpio_pm_hibernate_suspend();
163
164#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
165	flushinv_all_dcache();
166#endif
167	_disable_dcplb();
168	_disable_icplb();
169	bf53x_suspend_l1_mem(memptr);
170
171	do_hibernate(wakeup | vr_wakeup);	/* See you later! */
172
173	bf53x_resume_l1_mem(memptr);
174
175	_enable_icplb();
176	_enable_dcplb();
177
178	bfin_gpio_pm_hibernate_restore();
179	blackfin_dma_resume();
180
181	local_irq_restore_hw(flags);
182	kfree(memptr);
183
184	return 0;
185}
186
187/*
188 *	bfin_pm_valid - Tell the PM core that we only support the standby sleep
189 *			state
190 *	@state:		suspend state we're checking.
191 *
192 */
193static int bfin_pm_valid(suspend_state_t state)
194{
195	return (state == PM_SUSPEND_STANDBY
196#if !(defined(BF533_FAMILY) || defined(CONFIG_BF561))
197	|| state == PM_SUSPEND_MEM
198#endif
199	);
200}
201
202/*
203 *	bfin_pm_enter - Actually enter a sleep state.
204 *	@state:		State we're entering.
205 *
206 */
207static int bfin_pm_enter(suspend_state_t state)
208{
209	switch (state) {
210	case PM_SUSPEND_STANDBY:
211		bfin_pm_suspend_standby_enter();
212		break;
213	case PM_SUSPEND_MEM:
214		bfin_pm_suspend_mem_enter();
215		break;
216	default:
217		return -EINVAL;
218	}
219
220	return 0;
221}
222
223struct platform_suspend_ops bfin_pm_ops = {
224	.enter = bfin_pm_enter,
225	.valid	= bfin_pm_valid,
226};
227
228static int __init bfin_pm_init(void)
229{
230	suspend_set_ops(&bfin_pm_ops);
231	return 0;
232}
233
234__initcall(bfin_pm_init);
235