X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fplatforms%2Fpmac_cpufreq.c;h=2c8cec2723ad810805911a044f68712b847cb7b0;hb=9c920a8402f2bb9bd931801d429b65f4eb6a262b;hp=5b2221a141847cf3665df4a6454525f527d9d7bd;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 5b2221a14..2c8cec272 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -1,8 +1,7 @@ /* * arch/ppc/platforms/pmac_cpufreq.c * - * Copyright (C) 2002 - 2004 Benjamin Herrenschmidt - * Copyright (C) 2004 John Steele Scott + * Copyright (C) 2002 - 2003 Benjamin Herrenschmidt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -48,7 +47,6 @@ #warning "WARNING, CPUFREQ not recommended on SMP kernels" #endif -extern void low_choose_7447a_dfs(int dfs); extern void low_choose_750fx_pll(int pll); extern void low_sleep_handler(void); extern void openpic_suspend(struct sys_device *sysdev, u32 state); @@ -56,27 +54,18 @@ extern void openpic_resume(struct sys_device *sysdev); extern void enable_kernel_altivec(void); extern void enable_kernel_fp(void); -/* - * Currently, PowerMac cpufreq supports only high & low frequencies - * that are set by the firmware - */ static unsigned int low_freq; static unsigned int hi_freq; static unsigned int cur_freq; -/* - * Different models uses different mecanisms to switch the frequency - */ -static int (*set_speed_proc)(int low_speed); +/* Clean that up some day ... use a func ptr or at least an enum... */ +static int cpufreq_uses_pmu; +static int cpufreq_uses_gpios; -/* - * Some definitions used by the various speedprocs - */ static u32 voltage_gpio; static u32 frequency_gpio; static u32 slew_done_gpio; - #define PMAC_CPU_LOW_SPEED 1 #define PMAC_CPU_HIGH_SPEED 0 @@ -134,39 +123,9 @@ static int __pmac cpu_750fx_cpu_speed(int low_speed) return 0; } -/* Switch CPU speed using DFS */ -static int __pmac dfs_set_cpu_speed(int low_speed) -{ - if (low_speed == 0) { - /* ramping up, set voltage first */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/1000); - } else { - /* ramping down, enable aack delay first */ - pmac_call_feature(PMAC_FTR_AACK_DELAY_ENABLE, NULL, 1, 0); - } - - /* set frequency */ - low_choose_7447a_dfs(low_speed); - - if (low_speed == 1) { - /* ramping down, set voltage last */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/1000); - } else { - /* ramping up, disable aack delay last */ - pmac_call_feature(PMAC_FTR_AACK_DELAY_ENABLE, NULL, 0, 0); - } - - return 0; -} - - /* Switch CPU speed using slewing GPIOs */ -static int __pmac gpios_set_cpu_speed(int low_speed) +static int __pmac gpios_set_cpu_speed(unsigned int low_speed) { int gpio; @@ -179,8 +138,7 @@ static int __pmac gpios_set_cpu_speed(int low_speed) } /* Set frequency */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, - low_speed ? 0x04 : 0x05); + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, low_speed ? 0x04 : 0x05); udelay(200); do { set_current_state(TASK_UNINTERRUPTIBLE); @@ -205,7 +163,7 @@ static int __pmac gpios_set_cpu_speed(int low_speed) /* Switch CPU speed under PMU control */ -static int __pmac pmu_set_cpu_speed(int low_speed) +static int __pmac pmu_set_cpu_speed(unsigned int low_speed) { struct adb_request req; unsigned long save_l2cr; @@ -311,7 +269,12 @@ static int __pmac do_set_cpu_speed(int speed_mode) return 0; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED); + if (cpufreq_uses_pmu) + rc = pmu_set_cpu_speed(speed_mode); + else if (cpufreq_uses_gpios) + rc = gpios_set_cpu_speed(speed_mode); + else + rc = cpu_750fx_cpu_speed(speed_mode); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; @@ -375,138 +338,20 @@ static struct cpufreq_driver pmac_cpufreq_driver = { }; -static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) -{ - struct device_node *volt_gpio_np = of_find_node_by_name(NULL, - "voltage-gpio"); - struct device_node *freq_gpio_np = of_find_node_by_name(NULL, - "frequency-gpio"); - struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, - "slewing-done"); - u32 *value; - - /* - * Check to see if it's GPIO driven or PMU only - * - * The way we extract the GPIO address is slightly hackish, but it - * works well enough for now. We need to abstract the whole GPIO - * stuff sooner or later anyway - */ - - if (volt_gpio_np) - voltage_gpio = read_gpio(volt_gpio_np); - if (freq_gpio_np) - frequency_gpio = read_gpio(freq_gpio_np); - if (slew_done_gpio_np) - slew_done_gpio = read_gpio(slew_done_gpio_np); - - /* If we use the frequency GPIOs, calculate the min/max speeds based - * on the bus frequencies - */ - if (frequency_gpio && slew_done_gpio) { - int lenp, rc; - u32 *freqs, *ratio; - - freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); - lenp /= sizeof(u32); - if (freqs == NULL || lenp != 2) { - printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); - return 1; - } - ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); - if (ratio == NULL) { - printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); - return 1; - } - - /* Get the min/max bus frequencies */ - low_freq = min(freqs[0], freqs[1]); - hi_freq = max(freqs[0], freqs[1]); - - /* Grrrr.. It _seems_ that the device-tree is lying on the low bus - * frequency, it claims it to be around 84Mhz on some models while - * it appears to be approx. 101Mhz on all. Let's hack around here... - * fortunately, we don't need to be too precise - */ - if (low_freq < 98000000) - low_freq = 101000000; - - /* Convert those to CPU core clocks */ - low_freq = (low_freq * (*ratio)) / 2000; - hi_freq = (hi_freq * (*ratio)) / 2000; - - /* Now we get the frequencies, we read the GPIO to see what is out current - * speed - */ - rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); - cur_freq = (rc & 0x01) ? hi_freq : low_freq; - - set_speed_proc = gpios_set_cpu_speed; - return 1; - } - - /* If we use the PMU, look for the min & max frequencies in the - * device-tree - */ - value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); - if (!value) - return 1; - low_freq = (*value) / 1000; - /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree - * here */ - if (low_freq < 100000) - low_freq *= 10; - - value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); - if (!value) - return 1; - hi_freq = (*value) / 1000; - set_speed_proc = pmu_set_cpu_speed; - - return 0; -} - -static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) -{ - struct device_node *volt_gpio_np; - u32 *reg; - - /* OF only reports the high frequency */ - hi_freq = cur_freq; - low_freq = cur_freq/2; - if (mfspr(HID1) & HID1_DFS) - cur_freq = low_freq; - else - cur_freq = hi_freq; - - volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); - if (!volt_gpio_np){ - printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); - return 1; - } - - reg = (u32 *)get_property(volt_gpio_np, "reg", NULL); - voltage_gpio = *reg; - set_speed_proc = dfs_set_cpu_speed; - - return 0; -} - /* Currently, we support the following machines: * * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) - * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) * - iBook2 500 (PMU based, 400Mhz & 500Mhz) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) - * - Recent MacRISC3 laptops - * - iBook G4s and PowerBook G4s with 7447A CPUs + * - Recent MacRISC3 machines */ static int __init pmac_cpufreq_setup(void) { struct device_node *cpunode; u32 *value; + int has_freq_ctl = 0; if (strstr(cmd_line, "nocpufreq")) return 0; @@ -522,36 +367,113 @@ static int __init pmac_cpufreq_setup(void) goto out; cur_freq = (*value) / 1000; - /* Check for 7447A based iBook G4 or PowerBook */ - if (machine_is_compatible("PowerBook6,5") || - machine_is_compatible("PowerBook6,4") || - machine_is_compatible("PowerBook5,5") || - machine_is_compatible("PowerBook5,4")) { - pmac_cpufreq_init_7447A(cpunode); - /* Check for other MacRISC3 machines */ - } else if (machine_is_compatible("PowerBook3,4") || - machine_is_compatible("PowerBook3,5") || - machine_is_compatible("MacRISC3")) { - pmac_cpufreq_init_MacRISC3(cpunode); + /* Check for newer machines */ + if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5") || + machine_is_compatible("MacRISC3")) { + struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio"); + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, "frequency-gpio"); + struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done"); + + /* + * Check to see if it's GPIO driven or PMU only + * + * The way we extract the GPIO address is slightly hackish, but it + * works well enough for now. We need to abstract the whole GPIO + * stuff sooner or later anyway + */ + + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (freq_gpio_np) + frequency_gpio = read_gpio(freq_gpio_np); + if (slew_done_gpio_np) + slew_done_gpio = read_gpio(slew_done_gpio_np); + + /* If we use the frequency GPIOs, calculate the min/max speeds based + * on the bus frequencies + */ + if (frequency_gpio && slew_done_gpio) { + int lenp, rc; + u32 *freqs, *ratio; + + freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); + lenp /= sizeof(u32); + if (freqs == NULL || lenp != 2) { + printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); + goto out; + } + ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); + if (ratio == NULL) { + printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); + goto out; + } + + /* Get the min/max bus frequencies */ + low_freq = min(freqs[0], freqs[1]); + hi_freq = max(freqs[0], freqs[1]); + + /* Grrrr.. It _seems_ that the device-tree is lying on the low bus + * frequency, it claims it to be around 84Mhz on some models while + * it appears to be approx. 101Mhz on all. Let's hack around here... + * fortunately, we don't need to be too precise + */ + if (low_freq < 98000000) + low_freq = 101000000; + + /* Convert those to CPU core clocks */ + low_freq = (low_freq * (*ratio)) / 2000; + hi_freq = (hi_freq * (*ratio)) / 2000; + + /* Now we get the frequencies, we read the GPIO to see what is out current + * speed + */ + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + cur_freq = (rc & 0x01) ? hi_freq : low_freq; + + has_freq_ctl = 1; + cpufreq_uses_gpios = 1; + goto out; + } + + /* If we use the PMU, look for the min & max frequencies in the + * device-tree + */ + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree + * here */ + if (low_freq < 100000) + low_freq *= 10; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + goto out; + hi_freq = (*value) / 1000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } /* Else check for iBook2 500 */ - } else if (machine_is_compatible("PowerBook4,1")) { + else if (machine_is_compatible("PowerBook4,1")) { /* We only know about 500Mhz model */ if (cur_freq < 450000 || cur_freq > 550000) goto out; hi_freq = cur_freq; low_freq = 400000; - set_speed_proc = pmu_set_cpu_speed; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; } - /* Else check for TiPb 400 & 500 */ + /* Else check for TiPb 500 */ else if (machine_is_compatible("PowerBook3,2")) { - /* We only know about the 400 MHz and the 500Mhz model - * they both have 300 MHz as low frequency - */ - if (cur_freq < 350000 || cur_freq > 550000) + /* We only know about 500Mhz model */ + if (cur_freq < 450000 || cur_freq > 550000) goto out; hi_freq = cur_freq; low_freq = 300000; - set_speed_proc = pmu_set_cpu_speed; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; } /* Else check for 750FX */ else if (PVR_VER(mfspr(PVR)) == 0x7000) { @@ -561,19 +483,21 @@ static int __init pmac_cpufreq_setup(void) value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); if (!value) goto out; - low_freq = (*value) / 1000; - set_speed_proc = cpu_750fx_cpu_speed; + low_freq = (*value) / 1000; + cpufreq_uses_pmu = 0; + has_freq_ctl = 1; } out: - if (set_speed_proc == NULL) + if (!has_freq_ctl) return -ENODEV; pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); - printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", - low_freq/1000, hi_freq/1000, cur_freq/1000); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz, switch method: %s\n", + low_freq/1000, hi_freq/1000, cur_freq/1000, + cpufreq_uses_pmu ? "PMU" : (cpufreq_uses_gpios ? "GPIOs" : "CPU")); return cpufreq_register_driver(&pmac_cpufreq_driver); }