1d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo/*
2d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * PowerPC 4xx Clock and Power Management
3d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
4d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Copyright (C) 2010, Applied Micro Circuits Corporation
5d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Victor Gallardo (vgallardo@apm.com)
6d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
7d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Based on arch/powerpc/platforms/44x/idle.c:
8d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Jerone Young <jyoung5@us.ibm.com>
9d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Copyright 2008 IBM Corp.
10d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
11d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Based on arch/powerpc/sysdev/fsl_pmc.c:
12d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Anton Vorontsov <avorontsov@ru.mvista.com>
13d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Copyright 2009  MontaVista Software, Inc.
14d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
15d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * See file CREDITS for list of people who contributed to this
16d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * project.
17d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
18d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * This program is free software; you can redistribute it and/or
19d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * modify it under the terms of the GNU General Public License as
20d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * published by the Free Software Foundation; either version 2 of
21d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * the License, or (at your option) any later version.
22d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
23d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * This program is distributed in the hope that it will be useful,
24d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * but WITHOUT ANY WARRANTY; without even the implied warranty of
25d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * GNU General Public License for more details.
27d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo *
28d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * You should have received a copy of the GNU General Public License
29d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * along with this program; if not, write to the Free Software
30d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo * MA 02111-1307 USA
32d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo */
33d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
34d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <linux/kernel.h>
35d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <linux/of_platform.h>
36d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <linux/sysfs.h>
37d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <linux/cpu.h>
38d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <linux/suspend.h>
39d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <asm/dcr.h>
40d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <asm/dcr-native.h>
41d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#include <asm/machdep.h>
42d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
43d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#define CPM_ER	0
44d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#define CPM_FR	1
45d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#define CPM_SR	2
46d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
47d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#define CPM_IDLE_WAIT	0
48d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo#define CPM_IDLE_DOZE	1
49d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
50d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostruct cpm {
51d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	dcr_host_t	dcr_host;
52d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	dcr_offset[3];
53d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	powersave_off;
54d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	unused;
55d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	idle_doze;
56d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	standby;
57d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int	suspend;
58d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo};
59d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
60d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic struct cpm cpm;
61d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
62d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostruct cpm_idle_mode {
63d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int enabled;
64d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	const char  *name;
65d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo};
66d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
67d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic struct cpm_idle_mode idle_mode[] = {
68d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	[CPM_IDLE_WAIT] = { 1, "wait" }, /* default */
69d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	[CPM_IDLE_DOZE] = { 0, "doze" },
70d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo};
71d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
72d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic unsigned int cpm_set(unsigned int cpm_reg, unsigned int mask)
73d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
74d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int value;
75d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
76d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* CPM controller supports 3 different types of sleep interface
77d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * known as class 1, 2 and 3. For class 1 units, they are
78d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * unconditionally put to sleep when the corresponding CPM bit is
79d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * set. For class 2 and 3 units this is not case; if they can be
80d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * put to to sleep, they will. Here we do not verify, we just
81d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * set them and expect them to eventually go off when they can.
82d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 */
83d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	value = dcr_read(cpm.dcr_host, cpm.dcr_offset[cpm_reg]);
84d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	dcr_write(cpm.dcr_host, cpm.dcr_offset[cpm_reg], value | mask);
85d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
86d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* return old state, to restore later if needed */
87d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return value;
88d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
89d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
90d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle_wait(void)
91d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
92d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned long msr_save;
93d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
94d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* save off initial state */
95d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	msr_save = mfmsr();
96d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* sync required when CPM0_ER[CPU] is set */
97d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	mb();
98d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* set wait state MSR */
99d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE);
100d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	isync();
101d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* return to initial state */
102d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	mtmsr(msr_save);
103d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	isync();
104d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
105d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
106d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle_sleep(unsigned int mask)
107d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
108d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned int er_save;
109d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
110d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* update CPM_ER state */
111d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	er_save = cpm_set(CPM_ER, mask);
112d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
113d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* go to wait state so that CPM0_ER[CPU] can take effect */
114d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm_idle_wait();
115d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
116d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* restore CPM_ER state */
117d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	dcr_write(cpm.dcr_host, cpm.dcr_offset[CPM_ER], er_save);
118d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
119d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
120d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle_doze(void)
121d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
122d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm_idle_sleep(cpm.idle_doze);
123d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
124d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
125d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle_config(int mode)
126d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
127d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int i;
128d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
129d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (idle_mode[mode].enabled)
130d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		return;
131d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
132d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	for (i = 0; i < ARRAY_SIZE(idle_mode); i++)
133d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		idle_mode[i].enabled = 0;
134d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
135d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	idle_mode[mode].enabled = 1;
136d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
137d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
138d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic ssize_t cpm_idle_show(struct kobject *kobj,
139d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			     struct kobj_attribute *attr, char *buf)
140d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
141d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	char *s = buf;
142d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int i;
143d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
144d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
145d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		if (idle_mode[i].enabled)
146d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			s += sprintf(s, "[%s] ", idle_mode[i].name);
147d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		else
148d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			s += sprintf(s, "%s ", idle_mode[i].name);
149d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
150d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
151d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	*(s-1) = '\n'; /* convert the last space to a newline */
152d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
153d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return s - buf;
154d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
155d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
156d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic ssize_t cpm_idle_store(struct kobject *kobj,
157d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			      struct kobj_attribute *attr,
158d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			      const char *buf, size_t n)
159d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
160d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int i;
161d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	char *p;
162d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int len;
163d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
164d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	p = memchr(buf, '\n', n);
165d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	len = p ? p - buf : n;
166d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
167d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
168d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		if (strncmp(buf, idle_mode[i].name, len) == 0) {
169d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			cpm_idle_config(i);
170d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo			return n;
171d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		}
172d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
173d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
174d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return -EINVAL;
175d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
176d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
177d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic struct kobj_attribute cpm_idle_attr =
178d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	__ATTR(idle, 0644, cpm_idle_show, cpm_idle_store);
179d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
180d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle_config_sysfs(void)
181d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
1828a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers	struct device *dev;
183d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned long ret;
184d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
1858a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers	dev = get_cpu_device(0);
186d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
1878a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers	ret = sysfs_create_file(&dev->kobj,
188d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo				&cpm_idle_attr.attr);
189d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (ret)
190d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		printk(KERN_WARNING
191d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		       "cpm: failed to create idle sysfs entry\n");
192d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
193d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
194d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_idle(void)
195d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
196d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (idle_mode[CPM_IDLE_DOZE].enabled)
197d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_idle_doze();
198d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	else
199d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_idle_wait();
200d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
201d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
202d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic int cpm_suspend_valid(suspend_state_t state)
203d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
204d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	switch (state) {
205d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	case PM_SUSPEND_STANDBY:
206d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		return !!cpm.standby;
207d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	case PM_SUSPEND_MEM:
208d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		return !!cpm.suspend;
209d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	default:
210d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		return 0;
211d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
212d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
213d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
214d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic void cpm_suspend_standby(unsigned int mask)
215d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
216d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	unsigned long tcr_save;
217d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
218d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* disable decrement interrupt */
219d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	tcr_save = mfspr(SPRN_TCR);
220d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	mtspr(SPRN_TCR, tcr_save & ~TCR_DIE);
221d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
222d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* go to sleep state */
223d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm_idle_sleep(mask);
224d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
225d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* restore decrement interrupt */
226d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	mtspr(SPRN_TCR, tcr_save);
227d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
228d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
229d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic int cpm_suspend_enter(suspend_state_t state)
230d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
231d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	switch (state) {
232d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	case PM_SUSPEND_STANDBY:
233d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_suspend_standby(cpm.standby);
234d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		break;
235d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	case PM_SUSPEND_MEM:
236d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_suspend_standby(cpm.suspend);
237d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		break;
238d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
239d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
240d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return 0;
241d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
242d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
243d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic struct platform_suspend_ops cpm_suspend_ops = {
244d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	.valid		= cpm_suspend_valid,
245d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	.enter		= cpm_suspend_enter,
246d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo};
247d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
248d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic int cpm_get_uint_property(struct device_node *np,
249d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo				 const char *name)
250d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
251d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int len;
252d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	const unsigned int *prop = of_get_property(np, name, &len);
253d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
254d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (prop == NULL || len < sizeof(u32))
255d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		return 0;
256d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
257d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return *prop;
258d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
259d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
260d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic int __init cpm_init(void)
261d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
262d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	struct device_node *np;
263d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int dcr_base, dcr_len;
264d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	int ret = 0;
265d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
266d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (!cpm.powersave_off) {
267d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_idle_config(CPM_IDLE_WAIT);
268d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		ppc_md.power_save = &cpm_idle;
269d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
270d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
271d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	np = of_find_compatible_node(NULL, NULL, "ibm,cpm");
272d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (!np) {
273d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		ret = -EINVAL;
274d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		goto out;
275d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
276d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
277d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	dcr_base = dcr_resource_start(np, 0);
278d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	dcr_len = dcr_resource_len(np, 0);
279d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
280d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (dcr_base == 0 || dcr_len == 0) {
281d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		printk(KERN_ERR "cpm: could not parse dcr property for %s\n",
282d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		       np->full_name);
283d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		ret = -EINVAL;
284d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		goto out;
285d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
286d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
287d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.dcr_host = dcr_map(np, dcr_base, dcr_len);
288d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
289d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (!DCR_MAP_OK(cpm.dcr_host)) {
290d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		printk(KERN_ERR "cpm: failed to map dcr property for %s\n",
291d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		       np->full_name);
292d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		ret = -EINVAL;
293d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		goto out;
294d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
295d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
296d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* All 4xx SoCs with a CPM controller have one of two
297d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * different order for the CPM registers. Some have the
298d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * CPM registers in the following order (ER,FR,SR). The
299d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 * others have them in the following order (SR,ER,FR).
300d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	 */
301d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
302d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (cpm_get_uint_property(np, "er-offset") == 0) {
303d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_ER] = 0;
304d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_FR] = 1;
305d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_SR] = 2;
306d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	} else {
307d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_ER] = 1;
308d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_FR] = 2;
309d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm.dcr_offset[CPM_SR] = 0;
310d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
311d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
312d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* Now let's see what IPs to turn off for the following modes */
313d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
314d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.unused = cpm_get_uint_property(np, "unused-units");
315d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.idle_doze = cpm_get_uint_property(np, "idle-doze");
316d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.standby = cpm_get_uint_property(np, "standby");
317d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.suspend = cpm_get_uint_property(np, "suspend");
318d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
319d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* If some IPs are unused let's turn them off now */
320d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
321d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (cpm.unused) {
322d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_set(CPM_ER, cpm.unused);
323d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_set(CPM_FR, cpm.unused);
324d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	}
325d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
326d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	/* Now let's export interfaces */
327d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
328d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (!cpm.powersave_off && cpm.idle_doze)
329d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		cpm_idle_config_sysfs();
330d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
331d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (cpm.standby || cpm.suspend)
332d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		suspend_set_ops(&cpm_suspend_ops);
333d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardoout:
334d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	if (np)
335d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo		of_node_put(np);
336d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return ret;
337d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
338d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
339d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardolate_initcall(cpm_init);
340d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo
341d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardostatic int __init cpm_powersave_off(char *arg)
342d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo{
343d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	cpm.powersave_off = 1;
344d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo	return 0;
345d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo}
346d164f6d4f9108126f69ba2963cf6fb7ef4ba9232Victor Gallardo__setup("powersave=off", cpm_powersave_off);
347