diff options
-rw-r--r-- | drivers/cpufreq/powernow-k6.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 1332b72f373a..16359ab2c459 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c | |||
@@ -26,6 +26,14 @@ | |||
26 | static unsigned int busfreq; /* FSB, in 10 kHz */ | 26 | static unsigned int busfreq; /* FSB, in 10 kHz */ |
27 | static unsigned int max_multiplier; | 27 | static unsigned int max_multiplier; |
28 | 28 | ||
29 | static unsigned int param_busfreq = 0; | ||
30 | static unsigned int param_max_multiplier = 0; | ||
31 | |||
32 | module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO); | ||
33 | MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)"); | ||
34 | |||
35 | module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO); | ||
36 | MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz"); | ||
29 | 37 | ||
30 | /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ | 38 | /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ |
31 | static struct cpufreq_frequency_table clock_ratio[] = { | 39 | static struct cpufreq_frequency_table clock_ratio[] = { |
@@ -40,6 +48,27 @@ static struct cpufreq_frequency_table clock_ratio[] = { | |||
40 | {0, CPUFREQ_TABLE_END} | 48 | {0, CPUFREQ_TABLE_END} |
41 | }; | 49 | }; |
42 | 50 | ||
51 | static const struct { | ||
52 | unsigned freq; | ||
53 | unsigned mult; | ||
54 | } usual_frequency_table[] = { | ||
55 | { 400000, 40 }, // 100 * 4 | ||
56 | { 450000, 45 }, // 100 * 4.5 | ||
57 | { 475000, 50 }, // 95 * 5 | ||
58 | { 500000, 50 }, // 100 * 5 | ||
59 | { 506250, 45 }, // 112.5 * 4.5 | ||
60 | { 533500, 55 }, // 97 * 5.5 | ||
61 | { 550000, 55 }, // 100 * 5.5 | ||
62 | { 562500, 50 }, // 112.5 * 5 | ||
63 | { 570000, 60 }, // 95 * 6 | ||
64 | { 600000, 60 }, // 100 * 6 | ||
65 | { 618750, 55 }, // 112.5 * 5.5 | ||
66 | { 660000, 55 }, // 120 * 5.5 | ||
67 | { 675000, 60 }, // 112.5 * 6 | ||
68 | { 720000, 60 }, // 120 * 6 | ||
69 | }; | ||
70 | |||
71 | #define FREQ_RANGE 3000 | ||
43 | 72 | ||
44 | /** | 73 | /** |
45 | * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier | 74 | * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier |
@@ -125,17 +154,56 @@ static int powernow_k6_target(struct cpufreq_policy *policy, | |||
125 | return 0; | 154 | return 0; |
126 | } | 155 | } |
127 | 156 | ||
128 | |||
129 | static int powernow_k6_cpu_init(struct cpufreq_policy *policy) | 157 | static int powernow_k6_cpu_init(struct cpufreq_policy *policy) |
130 | { | 158 | { |
131 | unsigned int i, f; | 159 | unsigned int i, f; |
160 | unsigned khz; | ||
132 | 161 | ||
133 | if (policy->cpu != 0) | 162 | if (policy->cpu != 0) |
134 | return -ENODEV; | 163 | return -ENODEV; |
135 | 164 | ||
136 | /* get frequencies */ | 165 | max_multiplier = 0; |
137 | max_multiplier = powernow_k6_get_cpu_multiplier(); | 166 | khz = cpu_khz; |
138 | busfreq = cpu_khz / max_multiplier; | 167 | for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) { |
168 | if (khz >= usual_frequency_table[i].freq - FREQ_RANGE && | ||
169 | khz <= usual_frequency_table[i].freq + FREQ_RANGE) { | ||
170 | khz = usual_frequency_table[i].freq; | ||
171 | max_multiplier = usual_frequency_table[i].mult; | ||
172 | break; | ||
173 | } | ||
174 | } | ||
175 | if (param_max_multiplier) { | ||
176 | for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { | ||
177 | if (clock_ratio[i].driver_data == param_max_multiplier) { | ||
178 | max_multiplier = param_max_multiplier; | ||
179 | goto have_max_multiplier; | ||
180 | } | ||
181 | } | ||
182 | printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n"); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | if (!max_multiplier) { | ||
187 | printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz); | ||
188 | printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n"); | ||
189 | return -EOPNOTSUPP; | ||
190 | } | ||
191 | |||
192 | have_max_multiplier: | ||
193 | param_max_multiplier = max_multiplier; | ||
194 | |||
195 | if (param_busfreq) { | ||
196 | if (param_busfreq >= 50000 && param_busfreq <= 150000) { | ||
197 | busfreq = param_busfreq / 10; | ||
198 | goto have_busfreq; | ||
199 | } | ||
200 | printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | busfreq = khz / max_multiplier; | ||
205 | have_busfreq: | ||
206 | param_busfreq = busfreq * 10; | ||
139 | 207 | ||
140 | /* table init */ | 208 | /* table init */ |
141 | for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { | 209 | for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { |