Blame view

drivers/cpufreq/blackfin-cpufreq.c 5.01 KB
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
1
  /*
96f1050d3   Robin Getz   Blackfin: mass cl...
2
   * Blackfin core clock scaling
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
3
   *
8944b5a25   Michael Hennerich   Blackfin: cpufreq...
4
   * Copyright 2008-2011 Analog Devices Inc.
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
5
   *
96f1050d3   Robin Getz   Blackfin: mass cl...
6
   * Licensed under the GPL-2 or later.
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
7
8
9
   */
  
  #include <linux/kernel.h>
6a550b99a   Paul Gortmaker   blackfin: add mod...
10
  #include <linux/module.h>
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
11
12
  #include <linux/types.h>
  #include <linux/init.h>
969003152   Steven Miao   blackfin: bf60x: ...
13
  #include <linux/clk.h>
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
14
15
  #include <linux/cpufreq.h>
  #include <linux/fs.h>
7998a8787   Graf Yang   Blackfin: scale c...
16
  #include <linux/delay.h>
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
17
18
  #include <asm/blackfin.h>
  #include <asm/time.h>
761ec44ad   Mike Frysinger   Blackfin: pull in...
19
  #include <asm/dpmc.h>
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
20

969003152   Steven Miao   blackfin: bf60x: ...
21

e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
22
  /* this is the table of CCLK frequencies, in Hz */
507015880   Viresh Kumar   cpufreq: rename i...
23
  /* .driver_data is the entry in the auxiliary dpm_state_table[] */
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
24
25
26
  static struct cpufreq_frequency_table bfin_freq_table[] = {
  	{
  		.frequency = CPUFREQ_TABLE_END,
507015880   Viresh Kumar   cpufreq: rename i...
27
  		.driver_data = 0,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
28
29
30
  	},
  	{
  		.frequency = CPUFREQ_TABLE_END,
507015880   Viresh Kumar   cpufreq: rename i...
31
  		.driver_data = 1,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
32
33
34
  	},
  	{
  		.frequency = CPUFREQ_TABLE_END,
507015880   Viresh Kumar   cpufreq: rename i...
35
  		.driver_data = 2,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
36
37
38
  	},
  	{
  		.frequency = CPUFREQ_TABLE_END,
507015880   Viresh Kumar   cpufreq: rename i...
39
  		.driver_data = 0,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
40
41
42
43
44
45
46
  	},
  };
  
  static struct bfin_dpm_state {
  	unsigned int csel; /* system clock divider */
  	unsigned int tscale; /* change the divider on the core timer interrupt */
  } dpm_state_table[3];
6c2b7072a   Graf Yang   Blackfin: add sup...
47
  #if defined(CONFIG_CYCLES_CLOCKSOURCE)
1bfb4b21c   Vitja Makarov   [Blackfin] arch: ...
48
  /*
8944b5a25   Michael Hennerich   Blackfin: cpufreq...
49
   * normalized to maximum frequency offset for CYCLES,
6c2b7072a   Graf Yang   Blackfin: add sup...
50
51
   * used in time-ts cycles clock source, but could be used
   * somewhere also.
1bfb4b21c   Vitja Makarov   [Blackfin] arch: ...
52
53
54
   */
  unsigned long long __bfin_cycles_off;
  unsigned int __bfin_cycles_mod;
6c2b7072a   Graf Yang   Blackfin: add sup...
55
  #endif
1bfb4b21c   Vitja Makarov   [Blackfin] arch: ...
56

e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
57
  /**************************************************************************/
6c2b7072a   Graf Yang   Blackfin: add sup...
58
59
  static void __init bfin_init_tables(unsigned long cclk, unsigned long sclk)
  {
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
60

6c2b7072a   Graf Yang   Blackfin: add sup...
61
62
63
64
65
  	unsigned long csel, min_cclk;
  	int index;
  
  	/* Anomaly 273 seems to still exist on non-BF54x w/dcache turned on */
  #if ANOMALY_05000273 || ANOMALY_05000274 || \
7c7d02772   Sonic Zhang   bf60x: cpufreq: f...
66
67
  	(!(defined(CONFIG_BF54x) || defined(CONFIG_BF60x)) \
  	&& defined(CONFIG_BFIN_EXTMEM_DCACHEABLE))
6c2b7072a   Graf Yang   Blackfin: add sup...
68
69
70
71
  	min_cclk = sclk * 2;
  #else
  	min_cclk = sclk;
  #endif
969003152   Steven Miao   blackfin: bf60x: ...
72
73
  
  #ifndef CONFIG_BF60x
6c2b7072a   Graf Yang   Blackfin: add sup...
74
  	csel = ((bfin_read_PLL_DIV() & CSEL) >> 4);
969003152   Steven Miao   blackfin: bf60x: ...
75
76
77
  #else
  	csel = bfin_read32(CGU0_DIV) & 0x1F;
  #endif
6c2b7072a   Graf Yang   Blackfin: add sup...
78

810f1512d   James Cosin   Blackfin: cpufreq...
79
  	for (index = 0;  (cclk >> index) >= min_cclk && csel <= 3 && index < 3; index++, csel++) {
6c2b7072a   Graf Yang   Blackfin: add sup...
80
  		bfin_freq_table[index].frequency = cclk >> index;
969003152   Steven Miao   blackfin: bf60x: ...
81
  #ifndef CONFIG_BF60x
6c2b7072a   Graf Yang   Blackfin: add sup...
82
  		dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
969003152   Steven Miao   blackfin: bf60x: ...
83
84
  #else
  		dpm_state_table[index].csel = csel;
969003152   Steven Miao   blackfin: bf60x: ...
85
  #endif
810f1512d   James Cosin   Blackfin: cpufreq...
86
  		dpm_state_table[index].tscale =  (TIME_SCALE >> index) - 1;
6c2b7072a   Graf Yang   Blackfin: add sup...
87
88
89
90
91
92
93
94
95
96
97
  
  		pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d
  ",
  						 bfin_freq_table[index].frequency,
  						 dpm_state_table[index].csel,
  						 dpm_state_table[index].tscale);
  	}
  	return;
  }
  
  static void bfin_adjust_core_timer(void *info)
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
98
  {
6c2b7072a   Graf Yang   Blackfin: add sup...
99
100
101
102
103
104
105
106
  	unsigned int tscale;
  	unsigned int index = *(unsigned int *)info;
  
  	/* we have to adjust the core timer, because it is using cclk */
  	tscale = dpm_state_table[index].tscale;
  	bfin_write_TSCALE(tscale);
  	return;
  }
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
107

6c2b7072a   Graf Yang   Blackfin: add sup...
108
109
110
  static unsigned int bfin_getfreq_khz(unsigned int cpu)
  {
  	/* Both CoreA/B have the same core clock */
a10101d5f   Michael Hennerich   Blackfin arch: fi...
111
  	return get_cclk() / 1000;
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
112
  }
3a3cf0d7b   Bob Liu   blackfin: bf60x: ...
113
  #ifdef CONFIG_BF60x
d23f8cadf   Markus Elfring   blackfin-cpufreq:...
114
  static int cpu_set_cclk(int cpu, unsigned long new)
969003152   Steven Miao   blackfin: bf60x: ...
115
116
117
118
119
120
121
122
123
124
125
126
  {
  	struct clk *clk;
  	int ret;
  
  	clk = clk_get(NULL, "CCLK");
  	if (IS_ERR(clk))
  		return -ENODEV;
  
  	ret = clk_set_rate(clk, new);
  	clk_put(clk);
  	return ret;
  }
3a3cf0d7b   Bob Liu   blackfin: bf60x: ...
127
  #endif
969003152   Steven Miao   blackfin: bf60x: ...
128

9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
129
  static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
130
  {
3a3cf0d7b   Bob Liu   blackfin: bf60x: ...
131
132
133
  #ifndef CONFIG_BF60x
  	unsigned int plldiv;
  #endif
7998a8787   Graf Yang   Blackfin: scale c...
134
135
  	static unsigned long lpj_ref;
  	static unsigned int  lpj_ref_freq;
d4019f0a9   Viresh Kumar   cpufreq: move fre...
136
  	unsigned int old_freq, new_freq;
969003152   Steven Miao   blackfin: bf60x: ...
137
  	int ret = 0;
7998a8787   Graf Yang   Blackfin: scale c...
138

6c2b7072a   Graf Yang   Blackfin: add sup...
139
  #if defined(CONFIG_CYCLES_CLOCKSOURCE)
1bfb4b21c   Vitja Makarov   [Blackfin] arch: ...
140
  	cycles_t cycles;
6c2b7072a   Graf Yang   Blackfin: add sup...
141
  #endif
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
142

d4019f0a9   Viresh Kumar   cpufreq: move fre...
143
144
  	old_freq = bfin_getfreq_khz(0);
  	new_freq = bfin_freq_table[index].frequency;
6c2b7072a   Graf Yang   Blackfin: add sup...
145

969003152   Steven Miao   blackfin: bf60x: ...
146
  #ifndef CONFIG_BF60x
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
147
148
  	plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
  	bfin_write_PLL_DIV(plldiv);
969003152   Steven Miao   blackfin: bf60x: ...
149
  #else
d4019f0a9   Viresh Kumar   cpufreq: move fre...
150
  	ret = cpu_set_cclk(policy->cpu, new_freq * 1000);
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
151
152
153
154
155
  	if (ret != 0) {
  		WARN_ONCE(ret, "cpufreq set freq failed %d
  ", ret);
  		return ret;
  	}
969003152   Steven Miao   blackfin: bf60x: ...
156
  #endif
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
157
  	on_each_cpu(bfin_adjust_core_timer, &index, 1);
6c2b7072a   Graf Yang   Blackfin: add sup...
158
  #if defined(CONFIG_CYCLES_CLOCKSOURCE)
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
159
160
161
162
163
  	cycles = get_cycles();
  	SSYNC();
  	cycles += 10; /* ~10 cycles we lose after get_cycles() */
  	__bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
  	__bfin_cycles_mod = index;
6c2b7072a   Graf Yang   Blackfin: add sup...
164
  #endif
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
165
166
  	if (!lpj_ref_freq) {
  		lpj_ref = loops_per_jiffy;
d4019f0a9   Viresh Kumar   cpufreq: move fre...
167
  		lpj_ref_freq = old_freq;
6c2b7072a   Graf Yang   Blackfin: add sup...
168
  	}
d4019f0a9   Viresh Kumar   cpufreq: move fre...
169
  	if (new_freq != old_freq) {
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
170
  		loops_per_jiffy = cpufreq_scale(lpj_ref,
d4019f0a9   Viresh Kumar   cpufreq: move fre...
171
  				lpj_ref_freq, new_freq);
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
172
  	}
969003152   Steven Miao   blackfin: bf60x: ...
173
  	return ret;
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
174
  }
969003152   Steven Miao   blackfin: bf60x: ...
175
  static int __bfin_cpu_init(struct cpufreq_policy *policy)
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
176
  {
6c2b7072a   Graf Yang   Blackfin: add sup...
177
  	unsigned long cclk, sclk;
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
178

a10101d5f   Michael Hennerich   Blackfin arch: fi...
179
180
  	cclk = get_cclk() / 1000;
  	sclk = get_sclk() / 1000;
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
181

6c2b7072a   Graf Yang   Blackfin: add sup...
182
183
  	if (policy->cpu == CPUFREQ_CPU)
  		bfin_init_tables(cclk, sclk);
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
184

d887a1ce2   Michael Hennerich   Blackfin: cpufreq...
185
  	policy->cpuinfo.transition_latency = 50000; /* 50us assumed */
e2889e2cb   Viresh Kumar   cpufreq: blackfin...
186
  	return cpufreq_table_validate_and_show(policy, bfin_freq_table);
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
187
  }
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
188
  static struct cpufreq_driver bfin_driver = {
00ff424ca   Viresh Kumar   cpufreq: blackfin...
189
  	.verify = cpufreq_generic_frequency_table_verify,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
190
  	.target_index = bfin_target,
a10101d5f   Michael Hennerich   Blackfin arch: fi...
191
  	.get = bfin_getfreq_khz,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
192
193
  	.init = __bfin_cpu_init,
  	.name = "bfin cpufreq",
00ff424ca   Viresh Kumar   cpufreq: blackfin...
194
  	.attr = cpufreq_generic_attr,
e6c91b64d   Michael Hennerich   [Blackfin] arch: ...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  };
  
  static int __init bfin_cpu_init(void)
  {
  	return cpufreq_register_driver(&bfin_driver);
  }
  
  static void __exit bfin_cpu_exit(void)
  {
  	cpufreq_unregister_driver(&bfin_driver);
  }
  
  MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
  MODULE_DESCRIPTION("cpufreq driver for Blackfin");
  MODULE_LICENSE("GPL");
  
  module_init(bfin_cpu_init);
  module_exit(bfin_cpu_exit);