15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/errno.h>
18 #include <linux/kernel.h>
20 #include <linux/sched.h>
26 #include <asm/machdep.h>
28 #include <asm/sections.h>
29 #include <asm/cputable.h>
34 #define DBG(fmt...) pr_debug(fmt)
38 #define SCOM_PCR 0x0aa001
40 #define PCR_HILO_SELECT 0x80000000U
41 #define PCR_SPEED_FULL 0x00000000U
42 #define PCR_SPEED_HALF 0x00020000U
43 #define PCR_SPEED_QUARTER 0x00040000U
44 #define PCR_SPEED_MASK 0x000e0000U
45 #define PCR_SPEED_SHIFT 17
46 #define PCR_FREQ_REQ_VALID 0x00010000U
47 #define PCR_VOLT_REQ_VALID 0x00008000U
48 #define PCR_TARGET_TIME_MASK 0x00006000U
49 #define PCR_STATLAT_MASK 0x00001f00U
50 #define PCR_SNOOPLAT_MASK 0x000000f0U
51 #define PCR_SNOOPACC_MASK 0x0000000fU
53 #define SCOM_PSR 0x408001
55 #define PSR_CMD_RECEIVED 0x2000000000000000U
56 #define PSR_CMD_COMPLETED 0x1000000000000000U
57 #define PSR_CUR_SPEED_MASK 0x0300000000000000U
58 #define PSR_CUR_SPEED_SHIFT (56)
63 #define CPUFREQ_HIGH 0
72 static struct freq_attr* g5_cpu_freqs_attr[] = {
80 static int g5_pmode_cur;
82 static void (*g5_switch_volt)(
int speed_mode);
83 static int (*g5_switch_freq)(
int speed_mode);
84 static int (*g5_query_freq)(
void);
88 static unsigned long transition_latency;
90 #ifdef CONFIG_PMAC_SMU
92 static const u32 *g5_pmode_data;
93 static int g5_pmode_max;
96 static int g5_fvt_count;
97 static int g5_fvt_cur;
103 static void g5_smu_switch_volt(
int speed_mode)
105 struct smu_simple_cmd
cmd;
109 &comp,
'V',
'S',
'L',
'E',
'W',
110 0xff, g5_fvt_cur+1, speed_mode);
121 static void g5_vdnap_switch_volt(
int speed_mode)
154 static int g5_scom_switch_freq(
int speed_mode)
160 if (speed_mode < g5_pmode_cur)
161 g5_switch_volt(speed_mode);
171 g5_pmode_data[speed_mode]);
174 for (to = 0; to < 10; to++) {
190 if (speed_mode > g5_pmode_cur)
191 g5_switch_volt(speed_mode);
193 g5_pmode_cur = speed_mode;
199 static int g5_scom_query_freq(
void)
201 unsigned long psr = scom970_read(
SCOM_PSR);
204 for (i = 0; i <= g5_pmode_max; i++)
215 static void g5_dummy_switch_volt(
int speed_mode)
230 static void g5_pfunc_switch_volt(
int speed_mode)
233 if (pfunc_cpu0_volt_high)
235 if (pfunc_cpu1_volt_high)
238 if (pfunc_cpu0_volt_low)
240 if (pfunc_cpu1_volt_low)
255 static int g5_pfunc_switch_freq(
int speed_mode)
259 unsigned long timeout;
262 DBG(
"g5_pfunc_switch_freq(%d)\n", speed_mode);
265 if (speed_mode < g5_pmode_cur)
266 g5_switch_volt(speed_mode);
294 if (speed_mode > g5_pmode_cur)
295 g5_switch_volt(speed_mode);
297 g5_pmode_cur = speed_mode;
303 static int g5_pfunc_query_freq(
void)
325 unsigned int target_freq,
unsigned int relation)
327 unsigned int newstate = 0;
332 target_freq, relation, &newstate))
335 if (g5_pmode_cur == newstate)
340 freqs.old = g5_cpu_freqs[g5_pmode_cur].
frequency;
341 freqs.new = g5_cpu_freqs[newstate].
frequency;
345 rc = g5_switch_freq(newstate);
353 static unsigned int g5_cpufreq_get_speed(
unsigned int cpu)
355 return g5_cpu_freqs[g5_pmode_cur].
frequency;
360 policy->
cpuinfo.transition_latency = transition_latency;
365 cpumask_copy(policy->
cpus, cpu_online_mask);
377 .init = g5_cpufreq_cpu_init,
378 .verify = g5_cpufreq_verify,
379 .target = g5_cpufreq_target,
380 .get = g5_cpufreq_get_speed,
381 .attr = g5_cpu_freqs_attr,
385 #ifdef CONFIG_PMAC_SMU
390 unsigned int psize, ssize;
391 unsigned long max_freq;
392 char *freq_method, *volt_method;
395 int use_volts_vdnap = 0;
396 int use_volts_smu = 0;
413 if (reg ==
NULL || (*reg) != 0)
418 if (cpunode ==
NULL) {
426 DBG(
"No cpu-version property !\n");
429 pvr_hi = (*valp) >> 16;
430 if (pvr_hi != 0x3c && pvr_hi != 0x44) {
437 if (!g5_pmode_data) {
438 DBG(
"No power-mode-data !\n");
441 g5_pmode_max = psize /
sizeof(
u32) - 1;
451 ssize = (shdr->
len *
sizeof(
u32)) -
457 if (g5_fvt_count < 1 || g5_pmode_max < 1)
460 g5_switch_volt = g5_smu_switch_volt;
462 }
else if (use_volts_vdnap) {
472 pfunc_vdnap0_complete =
474 if (pfunc_set_vdnap0 ==
NULL ||
475 pfunc_vdnap0_complete ==
NULL) {
477 "platform function\n");
481 g5_switch_volt = g5_vdnap_switch_volt;
482 volt_method =
"GPIO";
484 g5_switch_volt = g5_dummy_switch_volt;
485 volt_method =
"none";
498 max_freq = (*valp)/1000;
503 transition_latency = 12000;
504 g5_switch_freq = g5_scom_switch_freq;
505 g5_query_freq = g5_scom_query_freq;
506 freq_method =
"SCOM";
515 g5_switch_freq(g5_query_freq());
519 freq_method, volt_method);
523 g5_cpu_freqs[g5_pmode_cur].
frequency/1000);
533 of_node_put(cpunode);
546 u64 max_freq, min_freq, ih, il;
547 int has_volt = 1, rc = 0;
549 DBG(
"cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
555 if (!
strcmp(cpunode->type,
"cpu"))
558 if (cpunode ==
NULL) {
567 if (eeprom ==
NULL) {
577 "hwctrl-location",
NULL);
580 if (
strcmp(loc,
"CPU CLOCK"))
586 if (hwclock ==
NULL) {
592 DBG(
"cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
597 pfunc_cpu_setfreq_high =
599 pfunc_cpu_setfreq_low =
603 pfunc_cpu0_volt_high =
605 pfunc_cpu0_volt_low =
607 pfunc_cpu1_volt_high =
609 pfunc_cpu1_volt_low =
613 if (pfunc_cpu_getfreq ==
NULL || pfunc_cpu_setfreq_high ==
NULL ||
614 pfunc_cpu_setfreq_low ==
NULL || pfunc_slewing_done ==
NULL) {
621 if (pfunc_cpu0_volt_high ==
NULL || pfunc_cpu0_volt_low ==
NULL) {
624 pfunc_cpu0_volt_high = pfunc_cpu0_volt_low =
NULL;
628 pfunc_cpu1_volt_high ==
NULL || pfunc_cpu1_volt_low ==
NULL) {
631 pfunc_cpu1_volt_high = pfunc_cpu1_volt_low =
NULL;
648 max_freq = (*valp)/1000;
654 ih = *((
u32 *)(eeprom + 0x10));
655 il = *((
u32 *)(eeprom + 0x20));
660 " on this model !\n");
666 if (ih != 0 && il != 0)
667 min_freq = (max_freq * il) / ih;
670 if (min_freq >= max_freq || min_freq < 1000) {
680 g5_switch_volt = g5_pfunc_switch_volt;
681 g5_switch_freq = g5_pfunc_switch_freq;
682 g5_query_freq = g5_pfunc_query_freq;
691 g5_switch_freq(g5_query_freq());
695 "Voltage method: %s\n", has_volt ?
"i2c/pfunc" :
"none");
699 g5_cpu_freqs[g5_pmode_cur].
frequency/1000);
713 of_node_put(hwclock);
715 of_node_put(cpunode);
720 static int __init g5_cpufreq_init(
void)
727 DBG(
"No /cpus node !\n");
734 rc = g5_pm72_cpufreq_init(cpus);
735 #ifdef CONFIG_PMAC_SMU
737 rc = g5_neo2_cpufreq_init(cpus);