Blame view

drivers/cpufreq/pasemi-cpufreq.c 6.6 KB
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /*
   * Copyright (C) 2007 PA Semi, Inc
   *
   * Authors: Egor Martovetsky <egor@pasemi.com>
   *	    Olof Johansson <olof@lixom.net>
   *
   * Maintained by: Olof Johansson <olof@lixom.net>
   *
   * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c:
   * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   */
  
  #include <linux/cpufreq.h>
  #include <linux/timer.h>
7dfe293cf   Paul Gortmaker   powerpc: Fix up m...
30
  #include <linux/module.h>
5af507300   Rob Herring   drivers: clean-up...
31
  #include <linux/of_address.h>
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
32
33
34
35
  
  #include <asm/hw_irq.h>
  #include <asm/io.h>
  #include <asm/prom.h>
2abb7019e   Olof Johansson   [POWERPC] pasemi:...
36
  #include <asm/time.h>
8b32bc032   Olof Johansson   [POWERPC] pasemi:...
37
  #include <asm/smp.h>
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  #define SDCASR_REG		0x0100
  #define SDCASR_REG_STRIDE	0x1000
  #define SDCPWR_CFGA0_REG	0x0100
  #define SDCPWR_PWST0_REG	0x0000
  #define SDCPWR_GIZTIME_REG	0x0440
  
  /* SDCPWR_GIZTIME_REG fields */
  #define SDCPWR_GIZTIME_GR	0x80000000
  #define SDCPWR_GIZTIME_LONGLOCK	0x000000ff
  
  /* Offset of ASR registers from SDC base */
  #define SDCASR_OFFSET		0x120000
  
  static void __iomem *sdcpwr_mapbase;
  static void __iomem *sdcasr_mapbase;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
54
55
56
57
58
59
60
61
  /* Current astate, is used when waking up from power savings on
   * one core, in case the other core has switched states during
   * the idle time.
   */
  static int current_astate;
  
  /* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */
  static struct cpufreq_frequency_table pas_freqs[] = {
7f4b04614   Viresh Kumar   cpufreq: create a...
62
63
64
65
66
67
  	{0, 0,	0},
  	{0, 1,	0},
  	{0, 2,	0},
  	{0, 3,	0},
  	{0, 4,	0},
  	{0, 0,	CPUFREQ_TABLE_END},
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
68
  };
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  /*
   * hardware specific functions
   */
  
  static int get_astate_freq(int astate)
  {
  	u32 ret;
  	ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10));
  
  	return ret & 0x3f;
  }
  
  static int get_cur_astate(int cpu)
  {
  	u32 ret;
  
  	ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG);
  	ret = (ret >> (cpu * 4)) & 0x7;
  
  	return ret;
  }
  
  static int get_gizmo_latency(void)
  {
  	u32 giztime, ret;
  
  	giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG);
  
  	/* just provide the upper bound */
  	if (giztime & SDCPWR_GIZTIME_GR)
  		ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000;
  	else
  		ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000;
  
  	return ret;
  }
  
  static void set_astate(int cpu, unsigned int astate)
  {
ac3f6454d   Ingo Molnar   powerpc/pasemi: l...
108
  	unsigned long flags;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
109
110
111
112
113
114
115
116
117
118
119
  
  	/* Return if called before init has run */
  	if (unlikely(!sdcasr_mapbase))
  		return;
  
  	local_irq_save(flags);
  
  	out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate);
  
  	local_irq_restore(flags);
  }
8b32bc032   Olof Johansson   [POWERPC] pasemi:...
120
121
122
123
  int check_astate(void)
  {
  	return get_cur_astate(hard_smp_processor_id());
  }
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
124
125
126
127
128
129
130
131
132
133
134
  void restore_astate(int cpu)
  {
  	set_astate(cpu, current_astate);
  }
  
  /*
   * cpufreq functions
   */
  
  static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
  {
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
135
  	struct cpufreq_frequency_table *pos;
12d371a69   Stephen Rothwell   [POWERPC] get_pro...
136
137
  	const u32 *max_freqp;
  	u32 max_freq;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
138
  	int cur_astate;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
139
140
141
142
143
144
145
146
  	struct resource res;
  	struct device_node *cpu, *dn;
  	int err = -ENODEV;
  
  	cpu = of_get_cpu_node(policy->cpu, NULL);
  
  	if (!cpu)
  		goto out;
0d08a8477   Olof Johansson   [POWERPC] pasemi:...
147
148
149
150
  	dn = of_find_compatible_node(NULL, NULL, "1682m-sdc");
  	if (!dn)
  		dn = of_find_compatible_node(NULL, NULL,
  					     "pasemi,pwrficient-sdc");
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
151
152
153
154
155
156
157
158
159
160
161
  	if (!dn)
  		goto out;
  	err = of_address_to_resource(dn, 0, &res);
  	of_node_put(dn);
  	if (err)
  		goto out;
  	sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000);
  	if (!sdcasr_mapbase) {
  		err = -EINVAL;
  		goto out;
  	}
0d08a8477   Olof Johansson   [POWERPC] pasemi:...
162
163
164
165
  	dn = of_find_compatible_node(NULL, NULL, "1682m-gizmo");
  	if (!dn)
  		dn = of_find_compatible_node(NULL, NULL,
  					     "pasemi,pwrficient-gizmo");
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  	if (!dn) {
  		err = -ENODEV;
  		goto out_unmap_sdcasr;
  	}
  	err = of_address_to_resource(dn, 0, &res);
  	of_node_put(dn);
  	if (err)
  		goto out_unmap_sdcasr;
  	sdcpwr_mapbase = ioremap(res.start, 0x1000);
  	if (!sdcpwr_mapbase) {
  		err = -EINVAL;
  		goto out_unmap_sdcasr;
  	}
  
  	pr_debug("init cpufreq on CPU %d
  ", policy->cpu);
12d371a69   Stephen Rothwell   [POWERPC] get_pro...
182
183
  	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
  	if (!max_freqp) {
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
184
185
186
187
188
  		err = -EINVAL;
  		goto out_unmap_sdcpwr;
  	}
  
  	/* we need the freq in kHz */
12d371a69   Stephen Rothwell   [POWERPC] get_pro...
189
  	max_freq = *max_freqp / 1000;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
190

12d371a69   Stephen Rothwell   [POWERPC] get_pro...
191
192
  	pr_debug("max clock-frequency is at %u kHz
  ", max_freq);
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
193
194
195
196
  	pr_debug("initializing frequency table
  ");
  
  	/* initialize frequency table */
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
197
198
199
200
  	cpufreq_for_each_entry(pos, pas_freqs) {
  		pos->frequency = get_astate_freq(pos->driver_data) * 100000;
  		pr_debug("%d: %d
  ", (int)(pos - pas_freqs), pos->frequency);
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
201
  	}
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
202
203
204
205
206
  	cur_astate = get_cur_astate(policy->cpu);
  	pr_debug("current astate is at %d
  ",cur_astate);
  
  	policy->cur = pas_freqs[cur_astate].frequency;
2abb7019e   Olof Johansson   [POWERPC] pasemi:...
207
  	ppc_proc_freq = policy->cur * 1000ul;
e315bb738   Viresh Kumar   cpufreq: pasemi: ...
208
  	return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
209
210
211
212
213
214
215
216
217
218
219
220
  
  out_unmap_sdcpwr:
  	iounmap(sdcpwr_mapbase);
  
  out_unmap_sdcasr:
  	iounmap(sdcasr_mapbase);
  out:
  	return err;
  }
  
  static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
  {
72640d880   Steven Rostedt   powerpc/pasemi: F...
221
222
223
224
  	/*
  	 * We don't support CPU hotplug. Don't unmap after the system
  	 * has already made it to a running state.
  	 */
d04e31a23   Thomas Gleixner   cpufreq/pasemi: A...
225
  	if (system_state >= SYSTEM_RUNNING)
72640d880   Steven Rostedt   powerpc/pasemi: F...
226
  		return 0;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
227
228
229
230
  	if (sdcasr_mapbase)
  		iounmap(sdcasr_mapbase);
  	if (sdcpwr_mapbase)
  		iounmap(sdcpwr_mapbase);
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
231
232
  	return 0;
  }
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
233
  static int pas_cpufreq_target(struct cpufreq_policy *policy,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
234
  			      unsigned int pas_astate_new)
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
235
  {
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
236
  	int i;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
237
238
239
240
  	pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency
  ",
  		 policy->cpu,
  		 pas_freqs[pas_astate_new].frequency,
507015880   Viresh Kumar   cpufreq: rename i...
241
  		 pas_freqs[pas_astate_new].driver_data);
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
242
243
244
245
246
  
  	current_astate = pas_astate_new;
  
  	for_each_online_cpu(i)
  		set_astate(i, pas_astate_new);
d4019f0a9   Viresh Kumar   cpufreq: move fre...
247
  	ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul;
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
248
249
250
251
252
  	return 0;
  }
  
  static struct cpufreq_driver pas_cpufreq_driver = {
  	.name		= "pas-cpufreq",
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
253
254
255
  	.flags		= CPUFREQ_CONST_LOOPS,
  	.init		= pas_cpufreq_cpu_init,
  	.exit		= pas_cpufreq_cpu_exit,
571743107   Viresh Kumar   cpufreq: pasemi: ...
256
  	.verify		= cpufreq_generic_frequency_table_verify,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
257
  	.target_index	= pas_cpufreq_target,
571743107   Viresh Kumar   cpufreq: pasemi: ...
258
  	.attr		= cpufreq_generic_attr,
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
259
260
261
262
263
264
265
266
  };
  
  /*
   * module init and destoy
   */
  
  static int __init pas_cpufreq_init(void)
  {
71a157e8e   Grant Likely   of: add 'of_' pre...
267
268
  	if (!of_machine_is_compatible("PA6T-1682M") &&
  	    !of_machine_is_compatible("pasemi,pwrficient"))
2e0c3370b   Olof Johansson   [POWERPC] pasemi:...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  		return -ENODEV;
  
  	return cpufreq_register_driver(&pas_cpufreq_driver);
  }
  
  static void __exit pas_cpufreq_exit(void)
  {
  	cpufreq_unregister_driver(&pas_cpufreq_driver);
  }
  
  module_init(pas_cpufreq_init);
  module_exit(pas_cpufreq_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");