* [PATCH] [2.6.22] pasemi: cpufreq driver @ 2007-04-25 20:46 Olof Johansson 2007-04-25 23:47 ` Arnd Bergmann 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson 0 siblings, 2 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-25 20:46 UTC (permalink / raw) To: paulus; +Cc: linuxppc-dev, egor, cpufreq Cpufreq driver for PA Semi PWRficient processors. Signed-off-by: Egor Martovetsky <egor@pasemi.com> Signed-off-by: Olof Johansson <olof@lixom.net> Index: powerpc/arch/powerpc/platforms/pasemi/Makefile =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/Makefile +++ powerpc/arch/powerpc/platforms/pasemi/Makefile @@ -1,2 +1,3 @@ obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o gpio_mdio.o +obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o Index: powerpc/arch/powerpc/platforms/pasemi/cpufreq.c =================================================================== --- /dev/null +++ powerpc/arch/powerpc/platforms/pasemi/cpufreq.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2007 PA Semi, Inc + * + * Author: Egor Martovetsky <egor@pasemi.com> + * + * Maintained by: Olof Johansson <olof@lixom.net> + * + * 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 + * published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/cpufreq.h> +#include <linux/timer.h> + +#include <asm/hw_irq.h> +#include <asm/io.h> +#include <asm/prom.h> + +#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 + +/* This should eventually come out of the device tree */ +#define SDCPWR_BASE 0xfc104000 +#define SDCPWR_SIZE 0x1000 + +#define SDCASR_BASE 0xfc120000 +#define SDCASR_SIZE 0x2000 + +static void __iomem *sdcpwr_mapbase; +static void __iomem *sdcasr_mapbase; + + +static DEFINE_MUTEX(pas_switch_mutex); + +/* 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[] = { + {0, 0}, + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static struct freq_attr *pas_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +/* + * hardware specific functions + */ + +static int get_astate_freq(int astate) +{ + u32 ret; + ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10)) & 0x3f; + + return ret; +} + +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 */ + ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * ((giztime & SDCPWR_GIZTIME_GR) ? 128 : 1) * 1000; + return ret; +} + +static void set_astate(int cpu, unsigned int astate) +{ + u64 flags; + + /* 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); +} + +void restore_astate(int cpu) +{ + set_astate(cpu, current_astate); +} + +/* + * cpufreq functions + */ + +static int pas_cpufreq_cpu_init (struct cpufreq_policy *policy) +{ + u32 *max_freq; + int i, cur_astate; + struct device_node *cpu; + + cpu = of_get_cpu_node(policy->cpu, NULL); + + if(!cpu) + return -ENODEV; + + sdcpwr_mapbase = ioremap(SDCPWR_BASE, SDCPWR_SIZE); + sdcasr_mapbase = ioremap(SDCASR_BASE, SDCASR_SIZE); + if (!sdcpwr_mapbase || !sdcasr_mapbase) + panic("SDCMAP: Cannot map registers!"); + + pr_debug("init cpufreq on CPU %d\n", policy->cpu); + + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); + + if(!max_freq) + return -EINVAL; + + // we need the freq in kHz + *max_freq /= 1000; + + pr_debug("max clock-frequency is at %u kHz\n", *max_freq); + pr_debug("initializing frequency table\n"); + + // initialize frequency table + for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { + pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000; + pr_debug("%d: %d\n", i, pas_freqs[i].frequency); + } + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.transition_latency = get_gizmo_latency(); + + cur_astate = get_cur_astate(policy->cpu); + pr_debug("current astate is at %d\n",cur_astate); + + policy->cur = pas_freqs[cur_astate].frequency; + policy->cpus = cpu_possible_map; + + cpufreq_frequency_table_get_attr (pas_freqs, policy->cpu); + + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ + return cpufreq_frequency_table_cpuinfo (policy, pas_freqs); +} + +static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static int pas_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, pas_freqs); +} + +static int pas_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + int pas_astate_new; + int i; + + cpufreq_frequency_table_target(policy, + pas_freqs, + target_freq, + relation, + &pas_astate_new); + + freqs.old = policy->cur; + freqs.new = pas_freqs[pas_astate_new].frequency; + freqs.cpu = policy->cpu; + + mutex_lock (&pas_switch_mutex); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", + policy->cpu, + pas_freqs[pas_astate_new].frequency, + pas_freqs[pas_astate_new].index); + + current_astate = pas_astate_new; + + for_each_online_cpu(i) { + set_astate(i, pas_astate_new); + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + mutex_unlock(&pas_switch_mutex); + + return 0; +} + +static struct cpufreq_driver pas_cpufreq_driver = { + .name = "pas-cpufreq", + .owner = THIS_MODULE, + .flags = CPUFREQ_CONST_LOOPS, + .init = pas_cpufreq_cpu_init, + .exit = pas_cpufreq_cpu_exit, + .verify = pas_cpufreq_verify, + .target = pas_cpufreq_target, + .attr = pas_cpu_freqs_attr, +}; + +/* + * module init and destoy + */ + +static int __init pas_cpufreq_init(void) +{ + 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>"); Index: powerpc/arch/powerpc/platforms/pasemi/idle.c =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/idle.c +++ powerpc/arch/powerpc/platforms/pasemi/idle.c @@ -61,6 +61,10 @@ static int pasemi_system_reset_exception /* do system reset */ return 0; } + + /* Set higher astate since we come out of power savings at 0 */ + restore_astate(hard_smp_processor_id()); + /* everything handled */ regs->msr |= MSR_RI; return 1; @@ -68,6 +72,11 @@ static int pasemi_system_reset_exception void __init pasemi_idle_init(void) { +#ifndef CONFIG_PPC_PASEMI_CPUFREQ + printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); + current_mode = 0; +#endif + ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); Index: powerpc/arch/powerpc/platforms/pasemi/pasemi.h =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/pasemi.h +++ powerpc/arch/powerpc/platforms/pasemi/pasemi.h @@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void extern void idle_spin(void); extern void idle_doze(void); +/* Restore astate to last set */ +#ifdef CONFIG_PPC_PASEMI_CPUFREQ +extern void restore_astate(int cpu); +#else +static inline void restore_astate(int cpu) +{ +} +#endif #endif /* _PASEMI_PASEMI_H */ Index: powerpc/arch/powerpc/platforms/Kconfig =================================================================== --- powerpc.orig/arch/powerpc/platforms/Kconfig +++ powerpc/arch/powerpc/platforms/Kconfig @@ -155,7 +155,7 @@ source "drivers/cpufreq/Kconfig" config CPU_FREQ_PMAC bool "Support for Apple PowerBooks" - depends on CPU_FREQ && ADB_PMU && PPC32 + depends on ADB_PMU && PPC32 select CPU_FREQ_TABLE help This adds support for frequency switching on Apple PowerBooks, @@ -164,11 +164,21 @@ config CPU_FREQ_PMAC config CPU_FREQ_PMAC64 bool "Support for some Apple G5s" - depends on CPU_FREQ && PPC64 + depends on PPC64 select CPU_FREQ_TABLE help This adds support for frequency switching on Apple iMac G5, and some of the more recent desktop G5 machines as well. + +config PPC_PASEMI_CPUFREQ + bool "Support for PA Semi PWRficient" + depends on PPC_PASEMI + default y + select CPU_FREQ_TABLE + help + This adds the support for frequency switching on PA Semi + PWRficient processors. + endmenu config PPC601_SYNC_FIX ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH] [2.6.22] pasemi: cpufreq driver 2007-04-25 20:46 [PATCH] [2.6.22] pasemi: cpufreq driver Olof Johansson @ 2007-04-25 23:47 ` Arnd Bergmann 2007-04-25 23:57 ` Olof Johansson 2007-04-26 6:56 ` cbe_cpufreq crashes my machine Olof Johansson 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson 1 sibling, 2 replies; 29+ messages in thread From: Arnd Bergmann @ 2007-04-25 23:47 UTC (permalink / raw) To: linuxppc-dev; +Cc: Olof Johansson, egor, paulus, cpufreq On Wednesday 25 April 2007, Olof Johansson wrote: > +/* This should eventually come out of the device tree */ > +#define SDCPWR_BASE 0xfc104000 > +#define SDCPWR_SIZE 0x1000 > + > +#define SDCASR_BASE 0xfc120000 > +#define SDCASR_SIZE 0x2000 the comment is right. Why don't you do it then? ;-) > +static int pas_cpufreq_cpu_init (struct cpufreq_policy *policy) > +{ > + u32 *max_freq; > + int i, cur_astate; > + struct device_node *cpu; > + > + cpu = of_get_cpu_node(policy->cpu, NULL); > + > + if(!cpu) > + return -ENODEV; > + > + sdcpwr_mapbase = ioremap(SDCPWR_BASE, SDCPWR_SIZE); > + sdcasr_mapbase = ioremap(SDCASR_BASE, SDCASR_SIZE); > + if (!sdcpwr_mapbase || !sdcasr_mapbase) > + panic("SDCMAP: Cannot map registers!"); I can't see any check in here that finds out if you are actually running on the right hardware. The proper way to implement this driver would be to register an of_platform_driver for the cpufreq device and then get the register addresses from there, > @@ -155,7 +155,7 @@ source "drivers/cpufreq/Kconfig" > > config CPU_FREQ_PMAC > bool "Support for Apple PowerBooks" > - depends on CPU_FREQ && ADB_PMU && PPC32 > + depends on ADB_PMU && PPC32 > select CPU_FREQ_TABLE > help > This adds support for frequency switching on Apple PowerBooks, > @@ -164,11 +164,21 @@ config CPU_FREQ_PMAC > > config CPU_FREQ_PMAC64 > bool "Support for some Apple G5s" > - depends on CPU_FREQ && PPC64 > + depends on PPC64 > select CPU_FREQ_TABLE > help > This adds support for frequency switching on Apple iMac G5, > and some of the more recent desktop G5 machines as well. Why this change? > +config PPC_PASEMI_CPUFREQ > + bool "Support for PA Semi PWRficient" > + depends on PPC_PASEMI > + default y > + select CPU_FREQ_TABLE > + help > + This adds the support for frequency switching on PA Semi > + PWRficient processors. > + > endmenu Why bool and not tristate? Arnd <>< ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH] [2.6.22] pasemi: cpufreq driver 2007-04-25 23:47 ` Arnd Bergmann @ 2007-04-25 23:57 ` Olof Johansson 2007-04-26 1:57 ` Olof Johansson 2007-04-26 6:56 ` cbe_cpufreq crashes my machine Olof Johansson 1 sibling, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-25 23:57 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, egor, paulus, cpufreq On Thu, Apr 26, 2007 at 01:47:35AM +0200, Arnd Bergmann wrote: > On Wednesday 25 April 2007, Olof Johansson wrote: > > > +/* This should eventually come out of the device tree */ > > +#define SDCPWR_BASE 0xfc104000 > > +#define SDCPWR_SIZE 0x1000 > > + > > +#define SDCASR_BASE 0xfc120000 > > +#define SDCASR_SIZE 0x2000 > > the comment is right. Why don't you do it then? ;-) Leftovers from when it was a regular platform driver. > > +static int pas_cpufreq_cpu_init (struct cpufreq_policy *policy) > > +{ > > + u32 *max_freq; > > + int i, cur_astate; > > + struct device_node *cpu; > > + > > + cpu = of_get_cpu_node(policy->cpu, NULL); > > + > > + if(!cpu) > > + return -ENODEV; > > + > > + sdcpwr_mapbase = ioremap(SDCPWR_BASE, SDCPWR_SIZE); > > + sdcasr_mapbase = ioremap(SDCASR_BASE, SDCASR_SIZE); > > + if (!sdcpwr_mapbase || !sdcasr_mapbase) > > + panic("SDCMAP: Cannot map registers!"); > > I can't see any check in here that finds out if you are actually running on > the right hardware. > The proper way to implement this driver would be to register an > of_platform_driver for the cpufreq device and then get the register > addresses from there, Yup. > > @@ -155,7 +155,7 @@ source "drivers/cpufreq/Kconfig" > > > > config CPU_FREQ_PMAC > > bool "Support for Apple PowerBooks" > > - depends on CPU_FREQ && ADB_PMU && PPC32 > > + depends on ADB_PMU && PPC32 > > select CPU_FREQ_TABLE > > help > > This adds support for frequency switching on Apple PowerBooks, > > @@ -164,11 +164,21 @@ config CPU_FREQ_PMAC > > > > config CPU_FREQ_PMAC64 > > bool "Support for some Apple G5s" > > - depends on CPU_FREQ && PPC64 > > + depends on PPC64 > > select CPU_FREQ_TABLE > > help > > This adds support for frequency switching on Apple iMac G5, > > and some of the more recent desktop G5 machines as well. > > Why this change? They're redundant, but they should have been in a separate patch. I forgot to revert them before rediffing. > > +config PPC_PASEMI_CPUFREQ > > + bool "Support for PA Semi PWRficient" > > + depends on PPC_PASEMI > > + default y > > + select CPU_FREQ_TABLE > > + help > > + This adds the support for frequency switching on PA Semi > > + PWRficient processors. > > + > > endmenu > > Why bool and not tristate? 1) The other cpufreq drivers are bool 2) See the idle loop interaction: It can go tristate once we have runtime selection of idle loop, but until then we need it for idle=doze. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH] [2.6.22] pasemi: cpufreq driver 2007-04-25 23:57 ` Olof Johansson @ 2007-04-26 1:57 ` Olof Johansson 0 siblings, 0 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-26 1:57 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, egor, paulus, cpufreq On Wed, Apr 25, 2007 at 06:57:57PM -0500, olof wrote: > 2) See the idle loop interaction: It can go tristate once we have runtime > selection of idle loop, but until then we need it for idle=doze. Grmbl. Looks like I posted a stale patch that actually won't build with PPC_PASEMI_CPUFREQ=n. I'll repost with the correct version. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* cbe_cpufreq crashes my machine 2007-04-25 23:47 ` Arnd Bergmann 2007-04-25 23:57 ` Olof Johansson @ 2007-04-26 6:56 ` Olof Johansson 2007-04-26 8:39 ` Benjamin Herrenschmidt 2007-04-26 23:07 ` [PATCH] cell: cbe_cpufreq cleanup and crash fix Olof Johansson 1 sibling, 2 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-26 6:56 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, Christian Krafft On Thu, Apr 26, 2007 at 01:47:35AM +0200, Arnd Bergmann wrote: > I can't see any check in here that finds out if you are actually running on > the right hardware. Seems like this came along with our use of cbe_cpufreq.c as a basis. You don't do it either! :-) Enabling CONFIG_CBE_CPUFREQ makes my machine die a horrible death, see below. I'd post a patch if I knew what machine compatible fields to compare with, but I have no clue what's considered approprate to check for on cell. Unable to handle kernel paging request for data at address 0x00000888 Faulting instruction address: 0xc000000000036b14 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2 Modules linked in: NIP: C000000000036B14 LR: C000000000036B08 CTR: C000000000036A60 REGS: c00000007fd83830 TRAP: 0300 Not tainted (2.6.20) MSR: 9000000000009032 <EE,ME,IR,DR> CR: 82000022 XER: 20000000 DAR: 0000000000000888, DSISR: 0000000040000000 TASK = c00000000ffc5820[1] 'swapper' THREAD: c00000007fd80000 CPU: 0 GPR00: C00000000093F940 C00000007FD83AB0 C000000000916EC0 0000000000000000 GPR04: C00000000068343F C0000000009C1208 C00000007F8FAE00 0000000000000000 GPR08: C000000000859720 0000000000000888 C0000000009C3DE0 0000000000000000 GPR12: 0000000000000000 C000000000779600 0000000000000000 C000000000684808 GPR16: 4000000000000000 C0000000006834E0 0000000000000000 0000000000000000 GPR20: 0000000000764880 C000000000764880 C000000000764AF0 0000000000764AF0 GPR24: C000000000684308 C00000000085FAE8 C0000000025DD028 0000000000000000 GPR28: FFFFFFFFFFFFFFF4 C00000007F8FAC38 C000000000784B58 C00000007F8FAC00 NIP [C000000000036B14] .cbe_cpufreq_cpu_init+0xb4/0x12c LR [C000000000036B08] .cbe_cpufreq_cpu_init+0xa8/0x12c Call Trace: [C00000007FD83AB0] [C000000000036AA8] .cbe_cpufreq_cpu_init+0x48/0x12c (unreliable) [C00000007FD83B40] [C0000000004831FC] .cpufreq_add_dev+0x158/0x4f4 [C00000007FD83D00] [C00000000033A5E4] .sysdev_driver_register+0xbc/0x158 [C00000007FD83D90] [C000000000482FF0] .cpufreq_register_driver+0xd0/0x184 [C00000007FD83E40] [C0000000007421B4] .cbe_cpufreq_init+0x1c/0x34 [C00000007FD83EC0] [C0000000000093B4] .init+0x1c4/0x39c [C00000007FD83F90] [C000000000022E10] .kernel_thread+0x4c/0x68 Instruction dump: 800b0000 2f80fffe 409effe4 e93e8038 380061a8 e87f000e 901f0018 f93f0030 4bffe239 60000000 39230888 7c0004ac <e9230888> 0c090000 4c00012c ebbe8008 -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: cbe_cpufreq crashes my machine 2007-04-26 6:56 ` cbe_cpufreq crashes my machine Olof Johansson @ 2007-04-26 8:39 ` Benjamin Herrenschmidt 2007-04-26 23:07 ` [PATCH] cell: cbe_cpufreq cleanup and crash fix Olof Johansson 1 sibling, 0 replies; 29+ messages in thread From: Benjamin Herrenschmidt @ 2007-04-26 8:39 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, Arnd Bergmann, Christian Krafft On Thu, 2007-04-26 at 01:56 -0500, Olof Johansson wrote: > On Thu, Apr 26, 2007 at 01:47:35AM +0200, Arnd Bergmann wrote: > > I can't see any check in here that finds out if you are actually running on > > the right hardware. > > Seems like this came along with our use of cbe_cpufreq.c as a basis. You > don't do it either! :-) > > Enabling CONFIG_CBE_CPUFREQ makes my machine die a horrible death, > see below. I'd post a patch if I knew what machine compatible fields to > compare with, but I have no clue what's considered approprate to check > for on cell. Or machine_is(cell) Ben. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH] cell: cbe_cpufreq cleanup and crash fix 2007-04-26 6:56 ` cbe_cpufreq crashes my machine Olof Johansson 2007-04-26 8:39 ` Benjamin Herrenschmidt @ 2007-04-26 23:07 ` Olof Johansson 2007-04-27 5:22 ` [Cbe-oss-dev] " Akinobu Mita 2007-04-27 5:33 ` [PATCH v2] " Olof Johansson 1 sibling, 2 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-26 23:07 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev, Christian Krafft cbe_cpufreq cleanups: * comment format * whitespace * don't init on non-cell platforms Signed-off-by: Olof Johansson <olof@lixom.net> Index: powerpc/arch/powerpc/platforms/cell/cbe_cpufreq.c =================================================================== --- powerpc.orig/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ powerpc/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -155,7 +155,7 @@ static int set_pmode_reg(int cpu, unsign } static int set_pmode(int cpu, unsigned int slow_mode) { - if(pmi_dev) + if (pmi_dev) return set_pmode_pmi(cpu, slow_mode); else return set_pmode_reg(cpu, slow_mode); @@ -167,7 +167,7 @@ static void cbe_cpufreq_handle_pmi(struc u8 cpu; u8 cbe_pmode_new; - BUG_ON (pmi_msg.type != PMI_TYPE_FREQ_CHANGE); + BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); cpu = cbe_node_to_cpu(pmi_msg.data1); cbe_pmode_new = pmi_msg.data2; @@ -191,7 +191,7 @@ static struct pmi_handler cbe_pmi_handle * cpufreq functions */ -static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy) +static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) { const u32 *max_freqp; u32 max_freq; @@ -200,7 +200,7 @@ static int cbe_cpufreq_cpu_init (struct cpu = of_get_cpu_node(policy->cpu, NULL); - if(!cpu) + if (!cpu) return -ENODEV; pr_debug("init cpufreq on CPU %d\n", policy->cpu); @@ -210,13 +210,13 @@ static int cbe_cpufreq_cpu_init (struct if (!max_freqp) return -EINVAL; - // we need the freq in kHz + /* we need the freq in kHz */ max_freq = *max_freqp / 1000; pr_debug("max clock-frequency is at %u kHz\n", max_freq); pr_debug("initializing frequency table\n"); - // initialize frequency table + /* initialize frequency table */ for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index; pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); @@ -235,10 +235,10 @@ static int cbe_cpufreq_cpu_init (struct policy->cpus = cpu_sibling_map[policy->cpu]; #endif - cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu); + cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ - return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs); + return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) @@ -270,7 +270,7 @@ static int cbe_cpufreq_target(struct cpu freqs.new = cbe_freqs[cbe_pmode_new].frequency; freqs.cpu = policy->cpu; - mutex_lock (&cbe_switch_mutex); + mutex_lock(&cbe_switch_mutex); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", @@ -303,6 +303,9 @@ static int __init cbe_cpufreq_init(void) { struct device_node *np; + if (!machine_is(cell)) + return 0; + np = of_find_node_by_type(NULL, "ibm,pmi"); pmi_dev = of_find_device_by_node(np); @@ -315,7 +318,7 @@ static int __init cbe_cpufreq_init(void) static void __exit cbe_cpufreq_exit(void) { - if(pmi_dev) + if (pmi_dev) pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); cpufreq_unregister_driver(&cbe_cpufreq_driver); ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Cbe-oss-dev] [PATCH] cell: cbe_cpufreq cleanup and crash fix 2007-04-26 23:07 ` [PATCH] cell: cbe_cpufreq cleanup and crash fix Olof Johansson @ 2007-04-27 5:22 ` Akinobu Mita 2007-04-27 5:32 ` Olof Johansson 2007-04-27 5:33 ` [PATCH v2] " Olof Johansson 1 sibling, 1 reply; 29+ messages in thread From: Akinobu Mita @ 2007-04-27 5:22 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann On Thu, Apr 26, 2007 at 06:07:54PM -0500, Olof Johansson wrote: > @@ -303,6 +303,9 @@ static int __init cbe_cpufreq_init(void) > { > struct device_node *np; > > + if (!machine_is(cell)) > + return 0; > + Please return -ENODEV to prevent loading module. Otherwise it will cause crash when unloading the module because of cpufreq_unregister_driver() with unregistered driver. > @@ -315,7 +318,7 @@ static int __init cbe_cpufreq_init(void) > > static void __exit cbe_cpufreq_exit(void) > { > - if(pmi_dev) > + if (pmi_dev) > pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); > > cpufreq_unregister_driver(&cbe_cpufreq_driver); ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Cbe-oss-dev] [PATCH] cell: cbe_cpufreq cleanup and crash fix 2007-04-27 5:22 ` [Cbe-oss-dev] " Akinobu Mita @ 2007-04-27 5:32 ` Olof Johansson 0 siblings, 0 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-27 5:32 UTC (permalink / raw) To: Akinobu Mita; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann On Fri, Apr 27, 2007 at 02:22:06PM +0900, Akinobu Mita wrote: > On Thu, Apr 26, 2007 at 06:07:54PM -0500, Olof Johansson wrote: > > @@ -303,6 +303,9 @@ static int __init cbe_cpufreq_init(void) > > { > > struct device_node *np; > > > > + if (!machine_is(cell)) > > + return 0; > > + > > Please return -ENODEV to prevent loading module. > > Otherwise it will cause crash when unloading the module > because of cpufreq_unregister_driver() with unregistered driver. It won't crash due to the checks in cpufreq_unregister_driver(), but it's still better to return failure. Thanks, -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v2] cell: cbe_cpufreq cleanup and crash fix 2007-04-26 23:07 ` [PATCH] cell: cbe_cpufreq cleanup and crash fix Olof Johansson 2007-04-27 5:22 ` [Cbe-oss-dev] " Akinobu Mita @ 2007-04-27 5:33 ` Olof Johansson 2007-04-27 7:55 ` Christian Krafft 1 sibling, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-27 5:33 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev, Christian Krafft cbe_cpufreq cleanups: * comment format * whitespace * don't init on non-cell platforms Signed-off-by: Olof Johansson <olof@lixom.net> Index: powerpc/arch/powerpc/platforms/cell/cbe_cpufreq.c =================================================================== --- powerpc.orig/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ powerpc/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -155,7 +155,7 @@ static int set_pmode_reg(int cpu, unsign } static int set_pmode(int cpu, unsigned int slow_mode) { - if(pmi_dev) + if (pmi_dev) return set_pmode_pmi(cpu, slow_mode); else return set_pmode_reg(cpu, slow_mode); @@ -167,7 +167,7 @@ static void cbe_cpufreq_handle_pmi(struc u8 cpu; u8 cbe_pmode_new; - BUG_ON (pmi_msg.type != PMI_TYPE_FREQ_CHANGE); + BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); cpu = cbe_node_to_cpu(pmi_msg.data1); cbe_pmode_new = pmi_msg.data2; @@ -191,7 +191,7 @@ static struct pmi_handler cbe_pmi_handle * cpufreq functions */ -static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy) +static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) { const u32 *max_freqp; u32 max_freq; @@ -200,7 +200,7 @@ static int cbe_cpufreq_cpu_init (struct cpu = of_get_cpu_node(policy->cpu, NULL); - if(!cpu) + if (!cpu) return -ENODEV; pr_debug("init cpufreq on CPU %d\n", policy->cpu); @@ -210,13 +210,13 @@ static int cbe_cpufreq_cpu_init (struct if (!max_freqp) return -EINVAL; - // we need the freq in kHz + /* we need the freq in kHz */ max_freq = *max_freqp / 1000; pr_debug("max clock-frequency is at %u kHz\n", max_freq); pr_debug("initializing frequency table\n"); - // initialize frequency table + /* initialize frequency table */ for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index; pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); @@ -235,10 +235,10 @@ static int cbe_cpufreq_cpu_init (struct policy->cpus = cpu_sibling_map[policy->cpu]; #endif - cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu); + cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ - return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs); + return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) @@ -270,7 +270,7 @@ static int cbe_cpufreq_target(struct cpu freqs.new = cbe_freqs[cbe_pmode_new].frequency; freqs.cpu = policy->cpu; - mutex_lock (&cbe_switch_mutex); + mutex_lock(&cbe_switch_mutex); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", @@ -303,6 +303,9 @@ static int __init cbe_cpufreq_init(void) { struct device_node *np; + if (!machine_is(cell)) + return -ENODEV; + np = of_find_node_by_type(NULL, "ibm,pmi"); pmi_dev = of_find_device_by_node(np); @@ -315,7 +318,7 @@ static int __init cbe_cpufreq_init(void) static void __exit cbe_cpufreq_exit(void) { - if(pmi_dev) + if (pmi_dev) pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); cpufreq_unregister_driver(&cbe_cpufreq_driver); ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] cell: cbe_cpufreq cleanup and crash fix 2007-04-27 5:33 ` [PATCH v2] " Olof Johansson @ 2007-04-27 7:55 ` Christian Krafft 0 siblings, 0 replies; 29+ messages in thread From: Christian Krafft @ 2007-04-27 7:55 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann [-- Attachment #1: Type: text/plain, Size: 633 bytes --] On Fri, 27 Apr 2007 00:33:47 -0500 olof@lixom.net (Olof Johansson) wrote: > cbe_cpufreq cleanups: > > * comment format > * whitespace > * don't init on non-cell platforms > > Signed-off-by: Olof Johansson <olof@lixom.net> Acked-by: Christian Krafft <krafft@de.ibm.com> Thx for fixing ;-) -- Mit freundlichen Gruessen, kind regards, Christian Krafft IBM Systems & Technology Group, Linux Kernel Development IT Specialist Vorsitzender des Aufsichtsrats: Johann Weihen Geschaeftsfuehrung: Herbert Kircher Sitz der Gesellschaft: Boeblingen Registriergericht: Amtsgericht Stuttgart, HRB 243294 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-25 20:46 [PATCH] [2.6.22] pasemi: cpufreq driver Olof Johansson 2007-04-25 23:47 ` Arnd Bergmann @ 2007-04-26 5:37 ` Olof Johansson 2007-04-26 8:55 ` Arnd Bergmann ` (2 more replies) 1 sibling, 3 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-26 5:37 UTC (permalink / raw) To: paulus; +Cc: linuxppc-dev, egor, arnd, cpufreq Cpufreq driver for PA Semi PWRficient processors. Signed-off-by: Egor Martovetsky <egor@pasemi.com> Signed-off-by: Olof Johansson <olof@lixom.net> --- Changes since last version: * Attributed copyright correctly to cbe_cpufreq.c and adjust license to match (this was my mistake) * Lookup the SDC and Gizmo device nodes to get register bases * machine_is_compatible checks * Cleanups as suggested by Arnd + misc whitespace * Rebased on top of MDIO config patch I chose not to do this as an of_platform driver since it doesn't fit that well with the cpufreq driver model; having 3 levels of init/probe functions is excessive. Index: powerpc/arch/powerpc/platforms/pasemi/Makefile =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/Makefile +++ powerpc/arch/powerpc/platforms/pasemi/Makefile @@ -1,2 +1,3 @@ obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o +obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o Index: powerpc/arch/powerpc/platforms/pasemi/cpufreq.c =================================================================== --- /dev/null +++ powerpc/arch/powerpc/platforms/pasemi/cpufreq.c @@ -0,0 +1,307 @@ +/* + * 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> + +#include <asm/hw_irq.h> +#include <asm/io.h> +#include <asm/prom.h> + +#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; + +static DEFINE_MUTEX(pas_switch_mutex); + +/* 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[] = { + {0, 0}, + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static struct freq_attr *pas_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +/* + * 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) +{ + u64 flags; + + /* 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); +} + +void restore_astate(int cpu) +{ + set_astate(cpu, current_astate); +} + +/* + * cpufreq functions + */ + +static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + u32 *max_freq; + int i, cur_astate; + struct resource res; + struct device_node *cpu, *dn; + int err = -ENODEV; + + cpu = of_get_cpu_node(policy->cpu, NULL); + + if (!cpu) + goto out; + + dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); + 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; + } + + dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); + 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\n", policy->cpu); + + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); + if (!max_freq) { + err = -EINVAL; + goto out_unmap_sdcpwr; + } + + /* we need the freq in kHz */ + *max_freq /= 1000; + + pr_debug("max clock-frequency is at %u kHz\n", *max_freq); + pr_debug("initializing frequency table\n"); + + /* initialize frequency table */ + for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { + pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000; + pr_debug("%d: %d\n", i, pas_freqs[i].frequency); + } + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.transition_latency = get_gizmo_latency(); + + cur_astate = get_cur_astate(policy->cpu); + pr_debug("current astate is at %d\n",cur_astate); + + policy->cur = pas_freqs[cur_astate].frequency; + policy->cpus = cpu_possible_map; + + cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu); + + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max + * are set correctly + */ + return cpufreq_frequency_table_cpuinfo(policy, pas_freqs); + +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) +{ + if (sdcasr_mapbase) + iounmap(sdcasr_mapbase); + if (sdcpwr_mapbase) + iounmap(sdcpwr_mapbase); + + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static int pas_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, pas_freqs); +} + +static int pas_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + int pas_astate_new; + int i; + + cpufreq_frequency_table_target(policy, + pas_freqs, + target_freq, + relation, + &pas_astate_new); + + freqs.old = policy->cur; + freqs.new = pas_freqs[pas_astate_new].frequency; + freqs.cpu = policy->cpu; + + mutex_lock(&pas_switch_mutex); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", + policy->cpu, + pas_freqs[pas_astate_new].frequency, + pas_freqs[pas_astate_new].index); + + current_astate = pas_astate_new; + + for_each_online_cpu(i) + set_astate(i, pas_astate_new); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + mutex_unlock(&pas_switch_mutex); + + return 0; +} + +static struct cpufreq_driver pas_cpufreq_driver = { + .name = "pas-cpufreq", + .owner = THIS_MODULE, + .flags = CPUFREQ_CONST_LOOPS, + .init = pas_cpufreq_cpu_init, + .exit = pas_cpufreq_cpu_exit, + .verify = pas_cpufreq_verify, + .target = pas_cpufreq_target, + .attr = pas_cpu_freqs_attr, +}; + +/* + * module init and destoy + */ + +static int __init pas_cpufreq_init(void) +{ + if (!machine_is_compatible("PA6T-1682M")) + return 0; + + 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>"); Index: powerpc/arch/powerpc/platforms/pasemi/idle.c =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/idle.c +++ powerpc/arch/powerpc/platforms/pasemi/idle.c @@ -61,6 +61,10 @@ static int pasemi_system_reset_exception /* do system reset */ return 0; } + + /* Set higher astate since we come out of power savings at 0 */ + restore_astate(hard_smp_processor_id()); + /* everything handled */ regs->msr |= MSR_RI; return 1; @@ -68,6 +72,11 @@ static int pasemi_system_reset_exception void __init pasemi_idle_init(void) { +#ifndef CONFIG_PPC_PASEMI_CPUFREQ + printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); + current_mode = 0; +#endif + ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); Index: powerpc/arch/powerpc/platforms/pasemi/pasemi.h =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/pasemi.h +++ powerpc/arch/powerpc/platforms/pasemi/pasemi.h @@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void extern void idle_spin(void); extern void idle_doze(void); +/* Restore astate to last set */ +#ifdef CONFIG_PPC_PASEMI_CPUFREQ +extern void restore_astate(int cpu); +#else +static inline void restore_astate(int cpu) +{ +} +#endif #endif /* _PASEMI_PASEMI_H */ Index: powerpc/arch/powerpc/platforms/Kconfig =================================================================== --- powerpc.orig/arch/powerpc/platforms/Kconfig +++ powerpc/arch/powerpc/platforms/Kconfig @@ -169,6 +169,16 @@ config CPU_FREQ_PMAC64 help This adds support for frequency switching on Apple iMac G5, and some of the more recent desktop G5 machines as well. + +config PPC_PASEMI_CPUFREQ + bool "Support for PA Semi PWRficient" + depends on PPC_PASEMI + default y + select CPU_FREQ_TABLE + help + This adds the support for frequency switching on PA Semi + PWRficient processors. + endmenu config PPC601_SYNC_FIX ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson @ 2007-04-26 8:55 ` Arnd Bergmann 2007-04-26 16:48 ` Olof Johansson 2007-04-26 10:26 ` Johannes Berg 2007-04-27 5:46 ` [PATCH v3] " Olof Johansson 2 siblings, 1 reply; 29+ messages in thread From: Arnd Bergmann @ 2007-04-26 8:55 UTC (permalink / raw) To: linuxppc-dev; +Cc: Olof Johansson, egor, paulus, cpufreq On Thursday 26 April 2007, Olof Johansson wrote: > I chose not to do this as an of_platform driver since it doesn't fit > that well with the cpufreq driver model; having 3 levels of init/probe > functions is excessive. <snip> > + dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); > + 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; > + } > + > + dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); > + 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; > + } What are sdc and gizmo anyway? If they are both only used for cpufreq, maybe the easiest way to do this with an of_platform_driver would be to have a single node that has two register ranges. Arnd <>< ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 8:55 ` Arnd Bergmann @ 2007-04-26 16:48 ` Olof Johansson 2007-04-26 17:11 ` Arnd Bergmann 0 siblings, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-26 16:48 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, egor, paulus, cpufreq On Thu, Apr 26, 2007 at 10:55:33AM +0200, Arnd Bergmann wrote: > On Thursday 26 April 2007, Olof Johansson wrote: > > > I chose not to do this as an of_platform driver since it doesn't fit > > that well with the cpufreq driver model; having 3 levels of init/probe > > functions is excessive. > > <snip> > > > + dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); > > + 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; > > + } > > + > > + dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); > > + 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; > > + } > > What are sdc and gizmo anyway? If they are both only used for cpufreq, maybe the > easiest way to do this with an of_platform_driver would be to have a single > node that has two register ranges. SDC is the system and debug controller, it contains a number of smaller devices such as the PIC, the PMU (Gizmo), RNG, and various debug features. Some already have drivers submitted, others will later on. Unfortunately the setting of the current active state is done to an SDC register, while information of the states is in the PMU, so access to both is needed in the driver. That doesn't change the fact that making this an of_platform driver is excessive: * module_init to register an of_platform driver * of_platform walks the tree, calls probes * of_platform driver probe code to register the cpufreq driver * cpufreq calls it's registered drivers * the cpufreq driver in turn will do the inits Compare to: * module_init registers cpufreq driver if machine_is_compatible() * cpufreq calls it's registered drivers * the cpufreq driver in turn will do the inits Don't get me wrong, of_platform drivers are often convenient, but I don't see it being a benefit to use them in this case. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 16:48 ` Olof Johansson @ 2007-04-26 17:11 ` Arnd Bergmann 2007-04-26 19:05 ` Segher Boessenkool 2007-04-26 20:26 ` Olof Johansson 0 siblings, 2 replies; 29+ messages in thread From: Arnd Bergmann @ 2007-04-26 17:11 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, egor, paulus, cpufreq On Thursday 26 April 2007, Olof Johansson wrote: > SDC is the system and debug controller, it contains a number of smaller > devices such as the PIC, the PMU (Gizmo), RNG, and various debug > features. Some already have drivers submitted, others will later on. Oh well, these chips all seem to be the same. On cell, we have solved the problem by introducing the 'cbe_regs' helper library that gives access to all those miscellaneous registers to the individual device drivers, so that not all of them need to scan the device tree for the same registers and map them individually. The problem with an of_platform_driver for this would be that you can only have _one_ driver attached to the registers. > Unfortunately the setting of the current active state is done to an SDC > register, while information of the states is in the PMU, so access to > both is needed in the driver. One thing that you could do is to list only this one register of the SDC in the reg property, not all of the SDC. Arnd <>< ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 17:11 ` Arnd Bergmann @ 2007-04-26 19:05 ` Segher Boessenkool 2007-04-26 20:38 ` Olof Johansson 2007-04-26 20:26 ` Olof Johansson 1 sibling, 1 reply; 29+ messages in thread From: Segher Boessenkool @ 2007-04-26 19:05 UTC (permalink / raw) To: Arnd Bergmann; +Cc: Olof Johansson, linuxppc-dev, egor, paulus, cpufreq >> Unfortunately the setting of the current active state is done to an >> SDC >> register, while information of the states is in the PMU, so access to >> both is needed in the driver. > > One thing that you could do is to list only this one register of the > SDC in the reg property, not all of the SDC. The system-controller node should really describe all of the system controller. If the Linux driver needs to access two separate devices, it should really just do that. Don't try to make things "simpler" in the device tree. You probably should map the SDC registers in the platform startop code, and then have the various platform drivers use that. Maybe even do an abstraction ;-) Segher ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 19:05 ` Segher Boessenkool @ 2007-04-26 20:38 ` Olof Johansson 2007-04-27 0:10 ` Segher Boessenkool 0 siblings, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-26 20:38 UTC (permalink / raw) To: Segher Boessenkool; +Cc: linuxppc-dev, paulus, egor, Arnd Bergmann, cpufreq On Thu, Apr 26, 2007 at 09:05:59PM +0200, Segher Boessenkool wrote: > >>Unfortunately the setting of the current active state is done to an > >>SDC > >>register, while information of the states is in the PMU, so access to > >>both is needed in the driver. > > > >One thing that you could do is to list only this one register of the > >SDC in the reg property, not all of the SDC. > > The system-controller node should really describe > all of the system controller. If the Linux driver > needs to access two separate devices, it should > really just do that. Don't try to make things > "simpler" in the device tree. > > You probably should map the SDC registers in the > platform startop code, and then have the various > platform drivers use that. Maybe even do an > abstraction ;-) Yep, it's a good idea to do and I'll look at it for 2.6.23 time frame. Thanks, -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 20:38 ` Olof Johansson @ 2007-04-27 0:10 ` Segher Boessenkool 0 siblings, 0 replies; 29+ messages in thread From: Segher Boessenkool @ 2007-04-27 0:10 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, paulus, egor, Arnd Bergmann, cpufreq >> You probably should map the SDC registers in the >> platform startop code, and then have the various >> platform drivers use that. Maybe even do an >> abstraction ;-) > > Yep, it's a good idea to do and I'll look at it for 2.6.23 time frame. Oh I'm sure you can get that done in time for .22 still ;-) Segher ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 17:11 ` Arnd Bergmann 2007-04-26 19:05 ` Segher Boessenkool @ 2007-04-26 20:26 ` Olof Johansson 2007-04-26 20:43 ` Arnd Bergmann 1 sibling, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-26 20:26 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linuxppc-dev, egor, paulus, cpufreq On Thu, Apr 26, 2007 at 07:11:21PM +0200, Arnd Bergmann wrote: > On Thursday 26 April 2007, Olof Johansson wrote: > > SDC is the system and debug controller, it contains a number of smaller > > devices such as the PIC, the PMU (Gizmo), RNG, and various debug > > features. Some already have drivers submitted, others will later on. > > Oh well, these chips all seem to be the same. On cell, we have solved > the problem by introducing the 'cbe_regs' helper library that gives > access to all those miscellaneous registers to the individual device > drivers, so that not all of them need to scan the device tree for > the same registers and map them individually. Not a bad idea, I'll consider it for the future. Most of our devices are on a pseudo-PCI bus, so it's only a handful that need special register access. The stuff in the SDC is the biggest exception. > The problem with an of_platform_driver for this would be that you > can only have _one_ driver attached to the registers. > > > Unfortunately the setting of the current active state is done to an SDC > > register, while information of the states is in the PMU, so access to > > both is needed in the driver. > > One thing that you could do is to list only this one register of the > SDC in the reg property, not all of the SDC. That doesn't make much sense in this case. The register isn't in the Gizmo. Having a driver/library for the SDC that the gizmo driver can use is a good idea, similar to what you've done on cell. I'll try to have that ready for 2.6.23, but that shouldn't stop this base driver from going in now. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 20:26 ` Olof Johansson @ 2007-04-26 20:43 ` Arnd Bergmann 0 siblings, 0 replies; 29+ messages in thread From: Arnd Bergmann @ 2007-04-26 20:43 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, egor, paulus, cpufreq On Thursday 26 April 2007, Olof Johansson wrote: > Having a driver/library for the SDC that the gizmo driver can use is a > good idea, similar to what you've done on cell. I'll try to have that > ready for 2.6.23, but that shouldn't stop this base driver from going > in now. Yes, agreed. Arnd <>< ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson 2007-04-26 8:55 ` Arnd Bergmann @ 2007-04-26 10:26 ` Johannes Berg 2007-04-26 20:37 ` Olof Johansson 2007-04-27 5:46 ` [PATCH v3] " Olof Johansson 2 siblings, 1 reply; 29+ messages in thread From: Johannes Berg @ 2007-04-26 10:26 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, egor, paulus, arnd, cpufreq [-- Attachment #1: Type: text/plain, Size: 942 bytes --] On Thu, 2007-04-26 at 00:37 -0500, Olof Johansson wrote: > > + policy->cur = pas_freqs[cur_astate].frequency; > + policy->cpus = cpu_possible_map; That doesn't seem right. Either, all your processors scale along each other in which case you should use cpu_online_map here, or they scale each on their own in which case you just set a single bit here. The generic code works like this: CPU 0 is brought online and cpufreq initialised for it CPU 1 is brought online and cpufreq initialised for it. if cpus includes more than a single bit, cpufreq is linked to the first other CPU in policy->cpus and then cpufreq for CPU1 is deinitialised again. We have the same bug on powermac but for some reason the patch to fix it that I posted a long time ago (look for "powermac: fix G5-cpufreq for cpu on/offline") wasn't applied yet. Look at it though, it includes a comment on what needs to be done. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 190 bytes --] ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 10:26 ` Johannes Berg @ 2007-04-26 20:37 ` Olof Johansson 2007-04-27 9:40 ` Johannes Berg 0 siblings, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-26 20:37 UTC (permalink / raw) To: Johannes Berg; +Cc: linuxppc-dev, egor, paulus, arnd, cpufreq On Thu, Apr 26, 2007 at 12:26:00PM +0200, Johannes Berg wrote: > On Thu, 2007-04-26 at 00:37 -0500, Olof Johansson wrote: > > > > + policy->cur = pas_freqs[cur_astate].frequency; > > + policy->cpus = cpu_possible_map; > > That doesn't seem right. > > Either, all your processors scale along each other in which case you > should use cpu_online_map here, or they scale each on their own in which > case you just set a single bit here. You can set the requested speed per-processor, but the actual speed will be the max of them. Because of this, it's less surprising to set it on both at the same time since then you'll at least know what you're running at. So yes, I'll change it to online_map instead of possible_map. > The generic code works like this: > CPU 0 is brought online and cpufreq initialised for it > CPU 1 is brought online and cpufreq initialised for it. if cpus includes > more than a single bit, cpufreq is linked to the first other CPU in > policy->cpus and then cpufreq for CPU1 is deinitialised again. > > We have the same bug on powermac but for some reason the patch to fix it > that I posted a long time ago (look for "powermac: fix G5-cpufreq for > cpu on/offline") wasn't applied yet. Look at it though, it includes a > comment on what needs to be done. Hmm, I just tried adding debugging to the cpu_init code, and I'm not seeing it called more than once (i.e. only for cpu 0). Mind you, I don't have cpu hotplug support at this time. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-26 20:37 ` Olof Johansson @ 2007-04-27 9:40 ` Johannes Berg 2007-04-27 18:09 ` Olof Johansson 0 siblings, 1 reply; 29+ messages in thread From: Johannes Berg @ 2007-04-27 9:40 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, egor, paulus, arnd, cpufreq [-- Attachment #1: Type: text/plain, Size: 899 bytes --] On Thu, 2007-04-26 at 15:37 -0500, Olof Johansson wrote: > You can set the requested speed per-processor, but the actual speed > will be the max of them. Because of this, it's less surprising to set > it on both at the same time since then you'll at least know what you're > running at. > > So yes, I'll change it to online_map instead of possible_map. Ok, yeah, so effectively they all just go together (that additional complication of running at the max probably should be hidden as you note) > Hmm, I just tried adding debugging to the cpu_init code, and I'm not > seeing it called more than once (i.e. only for cpu 0). Mind you, I don't > have cpu hotplug support at this time. Oh right, you need cpu hotplug support for the bug to show up. What happens then is you unplug and replug a CPU and the sysfs cpufreq stuff for the CPU you just replugged is gone. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 190 bytes --] ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2] [2.6.22] pasemi: cpufreq driver 2007-04-27 9:40 ` Johannes Berg @ 2007-04-27 18:09 ` Olof Johansson 0 siblings, 0 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-27 18:09 UTC (permalink / raw) To: Johannes Berg; +Cc: linuxppc-dev, egor, paulus, arnd, cpufreq On Fri, Apr 27, 2007 at 11:40:03AM +0200, Johannes Berg wrote: > > Hmm, I just tried adding debugging to the cpu_init code, and I'm not > > seeing it called more than once (i.e. only for cpu 0). Mind you, I don't > > have cpu hotplug support at this time. > > Oh right, you need cpu hotplug support for the bug to show up. What > happens then is you unplug and replug a CPU and the sysfs cpufreq stuff > for the CPU you just replugged is gone. Ok. Nothing for me to worry about right now then, but it's good to keep in mind for when the time comes. Thanks, -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3] [2.6.22] pasemi: cpufreq driver 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson 2007-04-26 8:55 ` Arnd Bergmann 2007-04-26 10:26 ` Johannes Berg @ 2007-04-27 5:46 ` Olof Johansson 2007-04-29 2:50 ` Dominik Brodowski 2 siblings, 1 reply; 29+ messages in thread From: Olof Johansson @ 2007-04-27 5:46 UTC (permalink / raw) To: paulus; +Cc: linuxppc-dev, egor, arnd, cpufreq Cpufreq driver for PA Semi PWRficient processors. Signed-off-by: Egor Martovetsky <egor@pasemi.com> Signed-off-by: Olof Johansson <olof@lixom.net> --- v3: * use cpu_online_map instead of possible_map * fix CPU_FREQ dependency * return -ENODEV instead of 0 on unsupported platforms v2: * Attributed copyright correctly to cbe_cpufreq.c and adjust license to match (this was my mistake) * Lookup the SDC and Gizmo device nodes to get register bases * machine_is_compatible checks * Cleanups as suggested by Arnd + misc whitespace I chose not to do this as an of_platform driver since it doesn't fit that well with the cpufreq driver model; having 3 levels of init/probe functions is excessive. Index: powerpc/arch/powerpc/platforms/pasemi/Makefile =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/Makefile +++ powerpc/arch/powerpc/platforms/pasemi/Makefile @@ -1,2 +1,3 @@ obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o +obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o Index: powerpc/arch/powerpc/platforms/pasemi/cpufreq.c =================================================================== --- /dev/null +++ powerpc/arch/powerpc/platforms/pasemi/cpufreq.c @@ -0,0 +1,307 @@ +/* + * 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> + +#include <asm/hw_irq.h> +#include <asm/io.h> +#include <asm/prom.h> + +#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; + +static DEFINE_MUTEX(pas_switch_mutex); + +/* 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[] = { + {0, 0}, + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static struct freq_attr *pas_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +/* + * 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) +{ + u64 flags; + + /* 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); +} + +void restore_astate(int cpu) +{ + set_astate(cpu, current_astate); +} + +/* + * cpufreq functions + */ + +static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + u32 *max_freq; + int i, cur_astate; + struct resource res; + struct device_node *cpu, *dn; + int err = -ENODEV; + + cpu = of_get_cpu_node(policy->cpu, NULL); + + if (!cpu) + goto out; + + dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); + 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; + } + + dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); + 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\n", policy->cpu); + + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); + if (!max_freq) { + err = -EINVAL; + goto out_unmap_sdcpwr; + } + + /* we need the freq in kHz */ + *max_freq /= 1000; + + pr_debug("max clock-frequency is at %u kHz\n", *max_freq); + pr_debug("initializing frequency table\n"); + + /* initialize frequency table */ + for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { + pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000; + pr_debug("%d: %d\n", i, pas_freqs[i].frequency); + } + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.transition_latency = get_gizmo_latency(); + + cur_astate = get_cur_astate(policy->cpu); + pr_debug("current astate is at %d\n",cur_astate); + + policy->cur = pas_freqs[cur_astate].frequency; + policy->cpus = cpu_online_map; + + cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu); + + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max + * are set correctly + */ + return cpufreq_frequency_table_cpuinfo(policy, pas_freqs); + +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) +{ + if (sdcasr_mapbase) + iounmap(sdcasr_mapbase); + if (sdcpwr_mapbase) + iounmap(sdcpwr_mapbase); + + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static int pas_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, pas_freqs); +} + +static int pas_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + int pas_astate_new; + int i; + + cpufreq_frequency_table_target(policy, + pas_freqs, + target_freq, + relation, + &pas_astate_new); + + freqs.old = policy->cur; + freqs.new = pas_freqs[pas_astate_new].frequency; + freqs.cpu = policy->cpu; + + mutex_lock(&pas_switch_mutex); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", + policy->cpu, + pas_freqs[pas_astate_new].frequency, + pas_freqs[pas_astate_new].index); + + current_astate = pas_astate_new; + + for_each_online_cpu(i) + set_astate(i, pas_astate_new); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + mutex_unlock(&pas_switch_mutex); + + return 0; +} + +static struct cpufreq_driver pas_cpufreq_driver = { + .name = "pas-cpufreq", + .owner = THIS_MODULE, + .flags = CPUFREQ_CONST_LOOPS, + .init = pas_cpufreq_cpu_init, + .exit = pas_cpufreq_cpu_exit, + .verify = pas_cpufreq_verify, + .target = pas_cpufreq_target, + .attr = pas_cpu_freqs_attr, +}; + +/* + * module init and destoy + */ + +static int __init pas_cpufreq_init(void) +{ + if (!machine_is_compatible("PA6T-1682M")) + 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>"); Index: powerpc/arch/powerpc/platforms/pasemi/idle.c =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/idle.c +++ powerpc/arch/powerpc/platforms/pasemi/idle.c @@ -61,6 +61,10 @@ static int pasemi_system_reset_exception /* do system reset */ return 0; } + + /* Set higher astate since we come out of power savings at 0 */ + restore_astate(hard_smp_processor_id()); + /* everything handled */ regs->msr |= MSR_RI; return 1; @@ -68,6 +72,11 @@ static int pasemi_system_reset_exception void __init pasemi_idle_init(void) { +#ifndef CONFIG_PPC_PASEMI_CPUFREQ + printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); + current_mode = 0; +#endif + ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); Index: powerpc/arch/powerpc/platforms/pasemi/pasemi.h =================================================================== --- powerpc.orig/arch/powerpc/platforms/pasemi/pasemi.h +++ powerpc/arch/powerpc/platforms/pasemi/pasemi.h @@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void extern void idle_spin(void); extern void idle_doze(void); +/* Restore astate to last set */ +#ifdef CONFIG_PPC_PASEMI_CPUFREQ +extern void restore_astate(int cpu); +#else +static inline void restore_astate(int cpu) +{ +} +#endif #endif /* _PASEMI_PASEMI_H */ Index: powerpc/arch/powerpc/platforms/Kconfig =================================================================== --- powerpc.orig/arch/powerpc/platforms/Kconfig +++ powerpc/arch/powerpc/platforms/Kconfig @@ -169,6 +169,16 @@ config CPU_FREQ_PMAC64 help This adds support for frequency switching on Apple iMac G5, and some of the more recent desktop G5 machines as well. + +config PPC_PASEMI_CPUFREQ + bool "Support for PA Semi PWRficient" + depends on CPU_FREQ && PPC_PASEMI + default y + select CPU_FREQ_TABLE + help + This adds the support for frequency switching on PA Semi + PWRficient processors. + endmenu config PPC601_SYNC_FIX ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3] [2.6.22] pasemi: cpufreq driver 2007-04-27 5:46 ` [PATCH v3] " Olof Johansson @ 2007-04-29 2:50 ` Dominik Brodowski 2007-04-29 3:40 ` Stephen Rothwell 2007-04-29 4:42 ` Olof Johansson 0 siblings, 2 replies; 29+ messages in thread From: Dominik Brodowski @ 2007-04-29 2:50 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, egor, paulus, arnd, cpufreq Hi, On Fri, Apr 27, 2007 at 12:46:01AM -0500, Olof Johansson wrote: > + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); (u32) or (32*) ? > + cur_astate = get_cur_astate(policy->cpu); May the different cores have different settings at initalization? e.g. core 0: freq A core 1: freq B with (freq B > freq A)? If so, cur_astate is set wrongly, as the _effective_ frequency would be freq B, right? > +#ifndef CONFIG_PPC_PASEMI_CPUFREQ > + printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); > + current_mode = 0; > +#endif > + This confuses me a bit -- does something else than cpufreq not work if cpufreq is disabled? Overall, the patch looks good to me. Dominik ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3] [2.6.22] pasemi: cpufreq driver 2007-04-29 2:50 ` Dominik Brodowski @ 2007-04-29 3:40 ` Stephen Rothwell 2007-04-29 4:39 ` Olof Johansson 2007-04-29 4:42 ` Olof Johansson 1 sibling, 1 reply; 29+ messages in thread From: Stephen Rothwell @ 2007-04-29 3:40 UTC (permalink / raw) To: Dominik Brodowski Cc: arnd, cpufreq, linuxppc-dev, egor, Olof Johansson, paulus On Sat, 28 Apr 2007 22:50:21 -0400 Dominik Brodowski <linux@dominikbrodowski.net> wrote: > > Hi, > > On Fri, Apr 27, 2007 at 12:46:01AM -0500, Olof Johansson wrote: > > + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); > > (u32) or (32*) ? Neither, get_property now returns (void *) so casting is not needed or wanted. Also, later in the patch, you modify the property value in place. Do not do this. To help you remember, if you had not done the cast, gcc would have complained because get_property return a const void *. Also, get_property is now called of_get_property. -- Cheers, Stephen Rothwell sfr@canb.auug.org.au http://www.canb.auug.org.au/~sfr/ ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3] [2.6.22] pasemi: cpufreq driver 2007-04-29 3:40 ` Stephen Rothwell @ 2007-04-29 4:39 ` Olof Johansson 0 siblings, 0 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-29 4:39 UTC (permalink / raw) To: Stephen Rothwell Cc: arnd, cpufreq, Dominik Brodowski, linuxppc-dev, paulus, egor On Sun, Apr 29, 2007 at 01:40:59PM +1000, Stephen Rothwell wrote: > On Sat, 28 Apr 2007 22:50:21 -0400 Dominik Brodowski <linux@dominikbrodowski.net> wrote: > > > > Hi, > > > > On Fri, Apr 27, 2007 at 12:46:01AM -0500, Olof Johansson wrote: > > > + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); > > > > (u32) or (32*) ? > > Neither, get_property now returns (void *) so casting is not needed or > wanted. > > Also, later in the patch, you modify the property value in place. Do not do this. To help you remember, if you had not done the cast, gcc would have complained because get_property return a const void *. Yep. It came along over from the cbe_cpufreq driver, which also does it. I'll post a patch tomorrow or Monday unless someone else beats me to it (the driver has already been merged). > Also, get_property is now called of_get_property. Sure, but keeping up with the API churn during other patch merging is a mess. It's easier to make one final pass over all new code and fix it up once more later during the merge window. -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3] [2.6.22] pasemi: cpufreq driver 2007-04-29 2:50 ` Dominik Brodowski 2007-04-29 3:40 ` Stephen Rothwell @ 2007-04-29 4:42 ` Olof Johansson 1 sibling, 0 replies; 29+ messages in thread From: Olof Johansson @ 2007-04-29 4:42 UTC (permalink / raw) To: paulus, linuxppc-dev, egor, arnd, cpufreq On Sat, Apr 28, 2007 at 10:50:21PM -0400, Dominik Brodowski wrote: > Hi, > > On Fri, Apr 27, 2007 at 12:46:01AM -0500, Olof Johansson wrote: > > + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); > > (u32) or (32*) ? > > > + cur_astate = get_cur_astate(policy->cpu); > > May the different cores have different settings at initalization? e.g. > > core 0: freq A > core 1: freq B > > with (freq B > freq A)? If so, cur_astate is set wrongly, as the _effective_ > frequency would be freq B, right? Firmware normally sets only cpu 0 (since cpu 1 isn't started until after linux is loaded and started). So it'll works well by default. > > +#ifndef CONFIG_PPC_PASEMI_CPUFREQ > > + printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); > > + current_mode = 0; > > +#endif > > + > > This confuses me a bit -- does something else than cpufreq not work if > cpufreq is disabled? After doze, we come back out in astate 0, so we need to raise it back up. We do so by calling the restore_astate() function. If we don't have it, and use idle=doze, we'll end up with a cpu running at astate 0 and no way to raise it. > Overall, the patch looks good to me. Thanks, -Olof ^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2007-04-29 4:41 UTC | newest] Thread overview: 29+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-04-25 20:46 [PATCH] [2.6.22] pasemi: cpufreq driver Olof Johansson 2007-04-25 23:47 ` Arnd Bergmann 2007-04-25 23:57 ` Olof Johansson 2007-04-26 1:57 ` Olof Johansson 2007-04-26 6:56 ` cbe_cpufreq crashes my machine Olof Johansson 2007-04-26 8:39 ` Benjamin Herrenschmidt 2007-04-26 23:07 ` [PATCH] cell: cbe_cpufreq cleanup and crash fix Olof Johansson 2007-04-27 5:22 ` [Cbe-oss-dev] " Akinobu Mita 2007-04-27 5:32 ` Olof Johansson 2007-04-27 5:33 ` [PATCH v2] " Olof Johansson 2007-04-27 7:55 ` Christian Krafft 2007-04-26 5:37 ` [PATCH v2] [2.6.22] pasemi: cpufreq driver Olof Johansson 2007-04-26 8:55 ` Arnd Bergmann 2007-04-26 16:48 ` Olof Johansson 2007-04-26 17:11 ` Arnd Bergmann 2007-04-26 19:05 ` Segher Boessenkool 2007-04-26 20:38 ` Olof Johansson 2007-04-27 0:10 ` Segher Boessenkool 2007-04-26 20:26 ` Olof Johansson 2007-04-26 20:43 ` Arnd Bergmann 2007-04-26 10:26 ` Johannes Berg 2007-04-26 20:37 ` Olof Johansson 2007-04-27 9:40 ` Johannes Berg 2007-04-27 18:09 ` Olof Johansson 2007-04-27 5:46 ` [PATCH v3] " Olof Johansson 2007-04-29 2:50 ` Dominik Brodowski 2007-04-29 3:40 ` Stephen Rothwell 2007-04-29 4:39 ` Olof Johansson 2007-04-29 4:42 ` Olof Johansson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).