All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw-KKrjLPT3xs0@public.gmane.org>
To: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Kevin Hilman <khilman-l0cyMroinI0@public.gmane.org>,
	Nishanth Menon <nm-l0cyMroinI0@public.gmane.org>,
	Mike Turquette
	<mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Russell King - ARM Linux
	<linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	Mark Brown
	<broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>,
	cpufreq-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Shilimkar Santosh
	<santosh.shilimkar-l0cyMroinI0@public.gmane.org>,
	Rob Herring <rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>,
	Richard Zhao
	<richard.zhao-KZfg59tc24xl57MIdRCFDg@public.gmane.org>,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: Re: [PATCH v3 3/3] cpufreq: Add a generic cpufreq-cpu0 driver
Date: Thu, 6 Sep 2012 21:59:01 +0200	[thread overview]
Message-ID: <201209062159.01788.rjw@sisk.pl> (raw)
In-Reply-To: <20120906072935.GB2362-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>

On Thursday, September 06, 2012, Shawn Guo wrote:
> On Wed, Sep 05, 2012 at 10:18:50PM +0200, Rafael J. Wysocki wrote:
> > On Wednesday, September 05, 2012, Shawn Guo wrote:
> > > On Wed, Sep 05, 2012 at 03:38:12PM +0200, Rafael J. Wysocki wrote:
> > > > Well, what about actually avoiding the code duplication?  That is,
> > > > can you make OMAP be a user of your new core function and drop the
> > > > OMAP-specific one, perhaps?
> > > > 
> > > I would expect that the driver will replace the omap-cpufreq driver
> > > completely at some point, where omap becomes a DT only platform.
> > 
> > That's fine, but why do we need two almost identical functions to start with?
> > 
> Probably because it does not worth the churn considering that any
> particular cpufreq driver having an identical .set_target as this
> generic one should eventually be replaced by this driver completely,
> IMO.
> 
> But anyway, it could be another patch which may need more discussion,
> so I just submitted the v4 with leaving this particular comment to be
> addressed in another patch.

It may be a different patch, I'm only concerned about the final outcome
(i.e. no added code duplication, please).

> I'm unsure this is what you are ordering.  But here is what I come up
> with to address your comment.  Please let me know if this is exactly
> what you are asking for, or you expect something different.

Yes, it is.

Thanks,
Rafael


> 8<---
>  drivers/cpufreq/Kconfig          |    4 ++
>  drivers/cpufreq/Kconfig.arm      |    1 +
>  drivers/cpufreq/Makefile         |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c   |   94 +++++-----------------------------
>  drivers/cpufreq/cpufreq.h        |   31 +++++++++++
>  drivers/cpufreq/cpufreq_target.c |   99 +++++++++++++++++++++++++++++++++++
>  drivers/cpufreq/omap-cpufreq.c   |  105 +++++---------------------------------
>  7 files changed, 163 insertions(+), 172 deletions(-)
>  create mode 100644 drivers/cpufreq/cpufreq.h
>  create mode 100644 drivers/cpufreq/cpufreq_target.c
> 
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index ea512f4..206eec9 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -20,6 +20,9 @@ if CPU_FREQ
>  config CPU_FREQ_TABLE
>  	tristate
>  
> +config CPU_FREQ_TARGET
> +	tristate
> +
>  config CPU_FREQ_STAT
>  	tristate "CPU frequency translation statistics"
>  	select CPU_FREQ_TABLE
> @@ -183,6 +186,7 @@ config GENERIC_CPUFREQ_CPU0
>  	bool "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && PM_OPP && OF
>  	select CPU_FREQ_TABLE
> +	select CPU_FREQ_TARGET
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency management.
>  	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 5961e64..60d81d0 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -7,6 +7,7 @@ config ARM_OMAP2PLUS_CPUFREQ
>  	depends on ARCH_OMAP2PLUS
>  	default ARCH_OMAP2PLUS
>  	select CPU_FREQ_TABLE
> +	select CPU_FREQ_TARGET
>  
>  config ARM_S3C2416_CPUFREQ
>  	bool "S3C2416 CPU Frequency scaling support"
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index a378ed2..f7d19d1 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
>  
>  # CPUfreq cross-arch helpers
>  obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
> +obj-$(CONFIG_CPU_FREQ_TARGET)		+= cpufreq_target.o
>  
>  obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)	+= cpufreq-cpu0.o
>  
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index e915827..51096e8 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -1,9 +1,6 @@
>  /*
>   * Copyright (C) 2012 Freescale Semiconductor, Inc.
>   *
> - * The OPP code in function cpu0_set_target() is reused from
> - * drivers/cpufreq/omap-cpufreq.c
> - *
>   * 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.
> @@ -20,6 +17,7 @@
>  #include <linux/opp.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/slab.h>
> +#include "cpufreq.h"
>  
>  static unsigned int transition_latency;
>  static unsigned int voltage_tolerance; /* in percentage */
> @@ -42,84 +40,18 @@ static unsigned int cpu0_get_speed(unsigned int cpu)
>  static int cpu0_set_target(struct cpufreq_policy *policy,
>  			   unsigned int target_freq, unsigned int relation)
>  {
> -	struct cpufreq_freqs freqs;
> -	struct opp *opp;
> -	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
> -	unsigned int index, cpu;
> -	int ret;
> -
> -	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
> -					     relation, &index);
> -	if (ret) {
> -		pr_err("failed to match target freqency %d: %d\n",
> -		       target_freq, ret);
> -		return ret;
> -	}
> -
> -	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
> -	if (freq_Hz < 0)
> -		freq_Hz = freq_table[index].frequency * 1000;
> -	freqs.new = freq_Hz / 1000;
> -	freqs.old = clk_get_rate(cpu_clk) / 1000;
> -
> -	if (freqs.old == freqs.new)
> -		return 0;
> -
> -	for_each_online_cpu(cpu) {
> -		freqs.cpu = cpu;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> -	}
> -
> -	if (cpu_reg) {
> -		opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
> -		if (IS_ERR(opp)) {
> -			pr_err("failed to find OPP for %ld\n", freq_Hz);
> -			return PTR_ERR(opp);
> -		}
> -		volt = opp_get_voltage(opp);
> -		tol = volt * voltage_tolerance / 100;
> -		volt_old = regulator_get_voltage(cpu_reg);
> -	}
> -
> -	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> -		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> -		 freqs.new / 1000, volt ? volt / 1000 : -1);
> -
> -	/* scaling up?  scale voltage before frequency */
> -	if (cpu_reg && freqs.new > freqs.old) {
> -		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
> -		if (ret) {
> -			pr_err("failed to scale voltage up: %d\n", ret);
> -			freqs.new = freqs.old;
> -			return ret;
> -		}
> -	}
> -
> -	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
> -	if (ret) {
> -		pr_err("failed to set clock rate: %d\n", ret);
> -		if (cpu_reg)
> -			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
> -		return ret;
> -	}
> -
> -	/* scaling down?  scale voltage after frequency */
> -	if (cpu_reg && freqs.new < freqs.old) {
> -		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
> -		if (ret) {
> -			pr_err("failed to scale voltage down: %d\n", ret);
> -			clk_set_rate(cpu_clk, freqs.old * 1000);
> -			freqs.new = freqs.old;
> -			return ret;
> -		}
> -	}
> -
> -	for_each_online_cpu(cpu) {
> -		freqs.cpu = cpu;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> -	}
> -
> -	return 0;
> +	struct cpufreq_target_data data;
> +
> +	data.dev = cpu_dev;
> +	data.clk = cpu_clk;
> +	data.reg = cpu_reg;
> +	data.tol = voltage_tolerance;
> +	data.freq_table = freq_table;
> +	data.policy = policy;
> +	data.target_freq = target_freq;
> +	data.relation = relation;
> +
> +	return cpufreq_set_target(&data);
>  }
>  
>  static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
> diff --git a/drivers/cpufreq/cpufreq.h b/drivers/cpufreq/cpufreq.h
> new file mode 100644
> index 0000000..ae380b3
> --- /dev/null
> +++ b/drivers/cpufreq/cpufreq.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + */
> +
> +#ifndef _DRIVERS_CPUFREQ_H
> +#define _DRIVERS_CPUFREQ_H
> +
> +struct device;
> +struct clk;
> +struct regulator;
> +struct cpufreq_frequency_table;
> +struct cpufreq_policy;
> +
> +struct cpufreq_target_data {
> +	struct device *dev;
> +	struct clk *clk;
> +	struct regulator *reg;
> +	unsigned int tol;
> +	struct cpufreq_frequency_table *freq_table;
> +	struct cpufreq_policy *policy;
> +	unsigned int target_freq;
> +	unsigned int relation;
> +};
> +
> +int cpufreq_set_target(struct cpufreq_target_data *data);
> +
> +#endif /* _DRIVERS_CPUFREQ_H */
> diff --git a/drivers/cpufreq/cpufreq_target.c b/drivers/cpufreq/cpufreq_target.c
> new file mode 100644
> index 0000000..02a5584
> --- /dev/null
> +++ b/drivers/cpufreq/cpufreq_target.c
> @@ -0,0 +1,99 @@
> +/*
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + *
> + * Based on function omap_target() from drivers/cpufreq/omap-cpufreq.c
> + *
> + * 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.
> + */
> +#include <linux/clk.h>
> +#include <linux/cpufreq.h>
> +#include <linux/module.h>
> +#include <linux/opp.h>
> +#include <linux/regulator/consumer.h>
> +#include "cpufreq.h"
> +
> +int cpufreq_set_target(struct cpufreq_target_data *d)
> +{
> +	struct cpufreq_freqs freqs;
> +	struct opp *opp;
> +	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
> +	unsigned int index, cpu;
> +	int ret;
> +
> +	ret = cpufreq_frequency_table_target(d->policy, d->freq_table,
> +					     d->target_freq, d->relation,
> +					     &index);
> +	if (ret) {
> +		pr_err("failed to match target freqency %d: %d\n",
> +		       d->target_freq, ret);
> +		return ret;
> +	}
> +
> +	freq_Hz = clk_round_rate(d->clk, d->freq_table[index].frequency * 1000);
> +	if (freq_Hz < 0)
> +		freq_Hz = d->freq_table[index].frequency * 1000;
> +	freqs.new = freq_Hz / 1000;
> +	freqs.old = clk_get_rate(d->clk) / 1000;
> +
> +	if (freqs.old == freqs.new)
> +		return 0;
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +	}
> +
> +	if (d->reg) {
> +		opp = opp_find_freq_ceil(d->dev, &freq_Hz);
> +		if (IS_ERR(opp)) {
> +			pr_err("failed to find OPP for %ld\n", freq_Hz);
> +			return PTR_ERR(opp);
> +		}
> +		volt = opp_get_voltage(opp);
> +		tol = volt * d->tol / 100;
> +		volt_old = regulator_get_voltage(d->reg);
> +	}
> +
> +	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> +		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> +		 freqs.new / 1000, volt ? volt / 1000 : -1);
> +
> +	/* scaling up?  scale voltage before frequency */
> +	if (d->reg && freqs.new > freqs.old) {
> +		ret = regulator_set_voltage_tol(d->reg, volt, tol);
> +		if (ret) {
> +			pr_err("failed to scale voltage up: %d\n", ret);
> +			freqs.new = freqs.old;
> +			return ret;
> +		}
> +	}
> +
> +	ret = clk_set_rate(d->clk, freqs.new * 1000);
> +	if (ret) {
> +		pr_err("failed to set clock rate: %d\n", ret);
> +		if (d->reg)
> +			regulator_set_voltage_tol(d->reg, volt_old, tol);
> +		return ret;
> +	}
> +
> +	/* scaling down?  scale voltage after frequency */
> +	if (d->reg && freqs.new < freqs.old) {
> +		ret = regulator_set_voltage_tol(d->reg, volt, tol);
> +		if (ret) {
> +			pr_err("failed to scale voltage down: %d\n", ret);
> +			clk_set_rate(d->clk, freqs.old * 1000);
> +			freqs.new = freqs.old;
> +			return ret;
> +		}
> +	}
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_set_target);
> diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
> index 83a78ad..0772df5 100644
> --- a/drivers/cpufreq/omap-cpufreq.c
> +++ b/drivers/cpufreq/omap-cpufreq.c
> @@ -37,6 +37,8 @@
>  
>  #include <mach/hardware.h>
>  
> +#include "cpufreq.h"
> +
>  /* OPP tolerance in percentage */
>  #define	OPP_TOLERANCE	4
>  
> @@ -69,97 +71,18 @@ static int omap_target(struct cpufreq_policy *policy,
>  		       unsigned int target_freq,
>  		       unsigned int relation)
>  {
> -	unsigned int i;
> -	int r, ret = 0;
> -	struct cpufreq_freqs freqs;
> -	struct opp *opp;
> -	unsigned long freq, volt = 0, volt_old = 0, tol = 0;
> -
> -	if (!freq_table) {
> -		dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
> -				policy->cpu);
> -		return -EINVAL;
> -	}
> -
> -	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
> -			relation, &i);
> -	if (ret) {
> -		dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
> -			__func__, policy->cpu, target_freq, ret);
> -		return ret;
> -	}
> -	freqs.new = freq_table[i].frequency;
> -	if (!freqs.new) {
> -		dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
> -			policy->cpu, target_freq);
> -		return -EINVAL;
> -	}
> -
> -	freqs.old = omap_getspeed(policy->cpu);
> -	freqs.cpu = policy->cpu;
> -
> -	if (freqs.old == freqs.new && policy->cur == freqs.new)
> -		return ret;
> -
> -	/* notifiers */
> -	for_each_cpu(i, policy->cpus) {
> -		freqs.cpu = i;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> -	}
> -
> -	freq = freqs.new * 1000;
> -
> -	if (mpu_reg) {
> -		opp = opp_find_freq_ceil(mpu_dev, &freq);
> -		if (IS_ERR(opp)) {
> -			dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
> -				__func__, freqs.new);
> -			return -EINVAL;
> -		}
> -		volt = opp_get_voltage(opp);
> -		tol = volt * OPP_TOLERANCE / 100;
> -		volt_old = regulator_get_voltage(mpu_reg);
> -	}
> -
> -	dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
> -		freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> -		freqs.new / 1000, volt ? volt / 1000 : -1);
> -
> -	/* scaling up?  scale voltage before frequency */
> -	if (mpu_reg && (freqs.new > freqs.old)) {
> -		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
> -		if (r < 0) {
> -			dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
> -				 __func__);
> -			freqs.new = freqs.old;
> -			goto done;
> -		}
> -	}
> -
> -	ret = clk_set_rate(mpu_clk, freqs.new * 1000);
> -
> -	/* scaling down?  scale voltage after frequency */
> -	if (mpu_reg && (freqs.new < freqs.old)) {
> -		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
> -		if (r < 0) {
> -			dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
> -				 __func__);
> -			ret = clk_set_rate(mpu_clk, freqs.old * 1000);
> -			freqs.new = freqs.old;
> -			goto done;
> -		}
> -	}
> -
> -	freqs.new = omap_getspeed(policy->cpu);
> -
> -done:
> -	/* notifiers */
> -	for_each_cpu(i, policy->cpus) {
> -		freqs.cpu = i;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> -	}
> -
> -	return ret;
> +	struct cpufreq_target_data data;
> +
> +	data.dev = mpu_dev;
> +	data.clk = mpu_clk;
> +	data.reg = mpu_reg;
> +	data.tol = OPP_TOLERANCE;
> +	data.freq_table = freq_table;
> +	data.policy = policy;
> +	data.target_freq = target_freq;
> +	data.relation = relation;
> +
> +	return cpufreq_set_target(&data);
>  }
>  
>  static inline void freq_table_free(void)
> 

WARNING: multiple messages have this Message-ID (diff)
From: rjw@sisk.pl (Rafael J. Wysocki)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 3/3] cpufreq: Add a generic cpufreq-cpu0 driver
Date: Thu, 6 Sep 2012 21:59:01 +0200	[thread overview]
Message-ID: <201209062159.01788.rjw@sisk.pl> (raw)
In-Reply-To: <20120906072935.GB2362@S2101-09.ap.freescale.net>

On Thursday, September 06, 2012, Shawn Guo wrote:
> On Wed, Sep 05, 2012 at 10:18:50PM +0200, Rafael J. Wysocki wrote:
> > On Wednesday, September 05, 2012, Shawn Guo wrote:
> > > On Wed, Sep 05, 2012 at 03:38:12PM +0200, Rafael J. Wysocki wrote:
> > > > Well, what about actually avoiding the code duplication?  That is,
> > > > can you make OMAP be a user of your new core function and drop the
> > > > OMAP-specific one, perhaps?
> > > > 
> > > I would expect that the driver will replace the omap-cpufreq driver
> > > completely at some point, where omap becomes a DT only platform.
> > 
> > That's fine, but why do we need two almost identical functions to start with?
> > 
> Probably because it does not worth the churn considering that any
> particular cpufreq driver having an identical .set_target as this
> generic one should eventually be replaced by this driver completely,
> IMO.
> 
> But anyway, it could be another patch which may need more discussion,
> so I just submitted the v4 with leaving this particular comment to be
> addressed in another patch.

It may be a different patch, I'm only concerned about the final outcome
(i.e. no added code duplication, please).

> I'm unsure this is what you are ordering.  But here is what I come up
> with to address your comment.  Please let me know if this is exactly
> what you are asking for, or you expect something different.

Yes, it is.

Thanks,
Rafael


> 8<---
>  drivers/cpufreq/Kconfig          |    4 ++
>  drivers/cpufreq/Kconfig.arm      |    1 +
>  drivers/cpufreq/Makefile         |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c   |   94 +++++-----------------------------
>  drivers/cpufreq/cpufreq.h        |   31 +++++++++++
>  drivers/cpufreq/cpufreq_target.c |   99 +++++++++++++++++++++++++++++++++++
>  drivers/cpufreq/omap-cpufreq.c   |  105 +++++---------------------------------
>  7 files changed, 163 insertions(+), 172 deletions(-)
>  create mode 100644 drivers/cpufreq/cpufreq.h
>  create mode 100644 drivers/cpufreq/cpufreq_target.c
> 
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index ea512f4..206eec9 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -20,6 +20,9 @@ if CPU_FREQ
>  config CPU_FREQ_TABLE
>  	tristate
>  
> +config CPU_FREQ_TARGET
> +	tristate
> +
>  config CPU_FREQ_STAT
>  	tristate "CPU frequency translation statistics"
>  	select CPU_FREQ_TABLE
> @@ -183,6 +186,7 @@ config GENERIC_CPUFREQ_CPU0
>  	bool "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && PM_OPP && OF
>  	select CPU_FREQ_TABLE
> +	select CPU_FREQ_TARGET
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency management.
>  	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 5961e64..60d81d0 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -7,6 +7,7 @@ config ARM_OMAP2PLUS_CPUFREQ
>  	depends on ARCH_OMAP2PLUS
>  	default ARCH_OMAP2PLUS
>  	select CPU_FREQ_TABLE
> +	select CPU_FREQ_TARGET
>  
>  config ARM_S3C2416_CPUFREQ
>  	bool "S3C2416 CPU Frequency scaling support"
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index a378ed2..f7d19d1 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
>  
>  # CPUfreq cross-arch helpers
>  obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
> +obj-$(CONFIG_CPU_FREQ_TARGET)		+= cpufreq_target.o
>  
>  obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)	+= cpufreq-cpu0.o
>  
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index e915827..51096e8 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -1,9 +1,6 @@
>  /*
>   * Copyright (C) 2012 Freescale Semiconductor, Inc.
>   *
> - * The OPP code in function cpu0_set_target() is reused from
> - * drivers/cpufreq/omap-cpufreq.c
> - *
>   * 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.
> @@ -20,6 +17,7 @@
>  #include <linux/opp.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/slab.h>
> +#include "cpufreq.h"
>  
>  static unsigned int transition_latency;
>  static unsigned int voltage_tolerance; /* in percentage */
> @@ -42,84 +40,18 @@ static unsigned int cpu0_get_speed(unsigned int cpu)
>  static int cpu0_set_target(struct cpufreq_policy *policy,
>  			   unsigned int target_freq, unsigned int relation)
>  {
> -	struct cpufreq_freqs freqs;
> -	struct opp *opp;
> -	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
> -	unsigned int index, cpu;
> -	int ret;
> -
> -	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
> -					     relation, &index);
> -	if (ret) {
> -		pr_err("failed to match target freqency %d: %d\n",
> -		       target_freq, ret);
> -		return ret;
> -	}
> -
> -	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
> -	if (freq_Hz < 0)
> -		freq_Hz = freq_table[index].frequency * 1000;
> -	freqs.new = freq_Hz / 1000;
> -	freqs.old = clk_get_rate(cpu_clk) / 1000;
> -
> -	if (freqs.old == freqs.new)
> -		return 0;
> -
> -	for_each_online_cpu(cpu) {
> -		freqs.cpu = cpu;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> -	}
> -
> -	if (cpu_reg) {
> -		opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
> -		if (IS_ERR(opp)) {
> -			pr_err("failed to find OPP for %ld\n", freq_Hz);
> -			return PTR_ERR(opp);
> -		}
> -		volt = opp_get_voltage(opp);
> -		tol = volt * voltage_tolerance / 100;
> -		volt_old = regulator_get_voltage(cpu_reg);
> -	}
> -
> -	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> -		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> -		 freqs.new / 1000, volt ? volt / 1000 : -1);
> -
> -	/* scaling up?  scale voltage before frequency */
> -	if (cpu_reg && freqs.new > freqs.old) {
> -		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
> -		if (ret) {
> -			pr_err("failed to scale voltage up: %d\n", ret);
> -			freqs.new = freqs.old;
> -			return ret;
> -		}
> -	}
> -
> -	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
> -	if (ret) {
> -		pr_err("failed to set clock rate: %d\n", ret);
> -		if (cpu_reg)
> -			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
> -		return ret;
> -	}
> -
> -	/* scaling down?  scale voltage after frequency */
> -	if (cpu_reg && freqs.new < freqs.old) {
> -		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
> -		if (ret) {
> -			pr_err("failed to scale voltage down: %d\n", ret);
> -			clk_set_rate(cpu_clk, freqs.old * 1000);
> -			freqs.new = freqs.old;
> -			return ret;
> -		}
> -	}
> -
> -	for_each_online_cpu(cpu) {
> -		freqs.cpu = cpu;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> -	}
> -
> -	return 0;
> +	struct cpufreq_target_data data;
> +
> +	data.dev = cpu_dev;
> +	data.clk = cpu_clk;
> +	data.reg = cpu_reg;
> +	data.tol = voltage_tolerance;
> +	data.freq_table = freq_table;
> +	data.policy = policy;
> +	data.target_freq = target_freq;
> +	data.relation = relation;
> +
> +	return cpufreq_set_target(&data);
>  }
>  
>  static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
> diff --git a/drivers/cpufreq/cpufreq.h b/drivers/cpufreq/cpufreq.h
> new file mode 100644
> index 0000000..ae380b3
> --- /dev/null
> +++ b/drivers/cpufreq/cpufreq.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + */
> +
> +#ifndef _DRIVERS_CPUFREQ_H
> +#define _DRIVERS_CPUFREQ_H
> +
> +struct device;
> +struct clk;
> +struct regulator;
> +struct cpufreq_frequency_table;
> +struct cpufreq_policy;
> +
> +struct cpufreq_target_data {
> +	struct device *dev;
> +	struct clk *clk;
> +	struct regulator *reg;
> +	unsigned int tol;
> +	struct cpufreq_frequency_table *freq_table;
> +	struct cpufreq_policy *policy;
> +	unsigned int target_freq;
> +	unsigned int relation;
> +};
> +
> +int cpufreq_set_target(struct cpufreq_target_data *data);
> +
> +#endif /* _DRIVERS_CPUFREQ_H */
> diff --git a/drivers/cpufreq/cpufreq_target.c b/drivers/cpufreq/cpufreq_target.c
> new file mode 100644
> index 0000000..02a5584
> --- /dev/null
> +++ b/drivers/cpufreq/cpufreq_target.c
> @@ -0,0 +1,99 @@
> +/*
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + *
> + * Based on function omap_target() from drivers/cpufreq/omap-cpufreq.c
> + *
> + * 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.
> + */
> +#include <linux/clk.h>
> +#include <linux/cpufreq.h>
> +#include <linux/module.h>
> +#include <linux/opp.h>
> +#include <linux/regulator/consumer.h>
> +#include "cpufreq.h"
> +
> +int cpufreq_set_target(struct cpufreq_target_data *d)
> +{
> +	struct cpufreq_freqs freqs;
> +	struct opp *opp;
> +	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
> +	unsigned int index, cpu;
> +	int ret;
> +
> +	ret = cpufreq_frequency_table_target(d->policy, d->freq_table,
> +					     d->target_freq, d->relation,
> +					     &index);
> +	if (ret) {
> +		pr_err("failed to match target freqency %d: %d\n",
> +		       d->target_freq, ret);
> +		return ret;
> +	}
> +
> +	freq_Hz = clk_round_rate(d->clk, d->freq_table[index].frequency * 1000);
> +	if (freq_Hz < 0)
> +		freq_Hz = d->freq_table[index].frequency * 1000;
> +	freqs.new = freq_Hz / 1000;
> +	freqs.old = clk_get_rate(d->clk) / 1000;
> +
> +	if (freqs.old == freqs.new)
> +		return 0;
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +	}
> +
> +	if (d->reg) {
> +		opp = opp_find_freq_ceil(d->dev, &freq_Hz);
> +		if (IS_ERR(opp)) {
> +			pr_err("failed to find OPP for %ld\n", freq_Hz);
> +			return PTR_ERR(opp);
> +		}
> +		volt = opp_get_voltage(opp);
> +		tol = volt * d->tol / 100;
> +		volt_old = regulator_get_voltage(d->reg);
> +	}
> +
> +	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> +		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> +		 freqs.new / 1000, volt ? volt / 1000 : -1);
> +
> +	/* scaling up?  scale voltage before frequency */
> +	if (d->reg && freqs.new > freqs.old) {
> +		ret = regulator_set_voltage_tol(d->reg, volt, tol);
> +		if (ret) {
> +			pr_err("failed to scale voltage up: %d\n", ret);
> +			freqs.new = freqs.old;
> +			return ret;
> +		}
> +	}
> +
> +	ret = clk_set_rate(d->clk, freqs.new * 1000);
> +	if (ret) {
> +		pr_err("failed to set clock rate: %d\n", ret);
> +		if (d->reg)
> +			regulator_set_voltage_tol(d->reg, volt_old, tol);
> +		return ret;
> +	}
> +
> +	/* scaling down?  scale voltage after frequency */
> +	if (d->reg && freqs.new < freqs.old) {
> +		ret = regulator_set_voltage_tol(d->reg, volt, tol);
> +		if (ret) {
> +			pr_err("failed to scale voltage down: %d\n", ret);
> +			clk_set_rate(d->clk, freqs.old * 1000);
> +			freqs.new = freqs.old;
> +			return ret;
> +		}
> +	}
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_set_target);
> diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
> index 83a78ad..0772df5 100644
> --- a/drivers/cpufreq/omap-cpufreq.c
> +++ b/drivers/cpufreq/omap-cpufreq.c
> @@ -37,6 +37,8 @@
>  
>  #include <mach/hardware.h>
>  
> +#include "cpufreq.h"
> +
>  /* OPP tolerance in percentage */
>  #define	OPP_TOLERANCE	4
>  
> @@ -69,97 +71,18 @@ static int omap_target(struct cpufreq_policy *policy,
>  		       unsigned int target_freq,
>  		       unsigned int relation)
>  {
> -	unsigned int i;
> -	int r, ret = 0;
> -	struct cpufreq_freqs freqs;
> -	struct opp *opp;
> -	unsigned long freq, volt = 0, volt_old = 0, tol = 0;
> -
> -	if (!freq_table) {
> -		dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
> -				policy->cpu);
> -		return -EINVAL;
> -	}
> -
> -	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
> -			relation, &i);
> -	if (ret) {
> -		dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
> -			__func__, policy->cpu, target_freq, ret);
> -		return ret;
> -	}
> -	freqs.new = freq_table[i].frequency;
> -	if (!freqs.new) {
> -		dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
> -			policy->cpu, target_freq);
> -		return -EINVAL;
> -	}
> -
> -	freqs.old = omap_getspeed(policy->cpu);
> -	freqs.cpu = policy->cpu;
> -
> -	if (freqs.old == freqs.new && policy->cur == freqs.new)
> -		return ret;
> -
> -	/* notifiers */
> -	for_each_cpu(i, policy->cpus) {
> -		freqs.cpu = i;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> -	}
> -
> -	freq = freqs.new * 1000;
> -
> -	if (mpu_reg) {
> -		opp = opp_find_freq_ceil(mpu_dev, &freq);
> -		if (IS_ERR(opp)) {
> -			dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
> -				__func__, freqs.new);
> -			return -EINVAL;
> -		}
> -		volt = opp_get_voltage(opp);
> -		tol = volt * OPP_TOLERANCE / 100;
> -		volt_old = regulator_get_voltage(mpu_reg);
> -	}
> -
> -	dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
> -		freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
> -		freqs.new / 1000, volt ? volt / 1000 : -1);
> -
> -	/* scaling up?  scale voltage before frequency */
> -	if (mpu_reg && (freqs.new > freqs.old)) {
> -		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
> -		if (r < 0) {
> -			dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
> -				 __func__);
> -			freqs.new = freqs.old;
> -			goto done;
> -		}
> -	}
> -
> -	ret = clk_set_rate(mpu_clk, freqs.new * 1000);
> -
> -	/* scaling down?  scale voltage after frequency */
> -	if (mpu_reg && (freqs.new < freqs.old)) {
> -		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
> -		if (r < 0) {
> -			dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
> -				 __func__);
> -			ret = clk_set_rate(mpu_clk, freqs.old * 1000);
> -			freqs.new = freqs.old;
> -			goto done;
> -		}
> -	}
> -
> -	freqs.new = omap_getspeed(policy->cpu);
> -
> -done:
> -	/* notifiers */
> -	for_each_cpu(i, policy->cpus) {
> -		freqs.cpu = i;
> -		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> -	}
> -
> -	return ret;
> +	struct cpufreq_target_data data;
> +
> +	data.dev = mpu_dev;
> +	data.clk = mpu_clk;
> +	data.reg = mpu_reg;
> +	data.tol = OPP_TOLERANCE;
> +	data.freq_table = freq_table;
> +	data.policy = policy;
> +	data.target_freq = target_freq;
> +	data.relation = relation;
> +
> +	return cpufreq_set_target(&data);
>  }
>  
>  static inline void freq_table_free(void)
> 

  parent reply	other threads:[~2012-09-06 19:59 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-10  5:37 [PATCH v3 0/3] Add a generic cpufreq-cpu0 driver Shawn Guo
2012-08-10  5:37 ` Shawn Guo
2012-08-10  5:37 ` [PATCH v3 1/3] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp Shawn Guo
2012-08-10  5:37   ` Shawn Guo
2012-09-04 23:27   ` Rafael J. Wysocki
2012-09-04 23:27     ` Rafael J. Wysocki
     [not found]   ` <1344577046-14847-2-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2012-09-06 22:35     ` Stephen Warren
2012-09-06 22:35       ` Stephen Warren
     [not found]       ` <5049252D.9000802-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2012-09-07  2:58         ` Shawn Guo
2012-09-07  2:58           ` Shawn Guo
     [not found]           ` <20120907025847.GI26709-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-09-07 16:55             ` Stephen Warren
2012-09-07 16:55               ` Stephen Warren
2012-09-10  1:17               ` Shawn Guo
2012-09-10  1:17                 ` Shawn Guo
     [not found]                 ` <20120910011741.GP26709-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-09-10 17:17                   ` Stephen Warren
2012-09-10 17:17                     ` Stephen Warren
     [not found]                     ` <504E20BE.8050107-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2012-09-11 11:59                       ` Prashant Gaikwad
2012-09-11 11:59                         ` Prashant Gaikwad
     [not found]                         ` <504F2789.1070006-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2012-09-11 15:16                           ` Stephen Warren
2012-09-11 15:16                             ` Stephen Warren
2012-08-10  5:37 ` [PATCH v3 2/3] PM / OPP: Initialize OPP table from device tree Shawn Guo
2012-08-10  5:37   ` Shawn Guo
2012-08-16 21:05   ` Rafael J. Wysocki
2012-08-16 21:05     ` Rafael J. Wysocki
     [not found]     ` <201208162305.55114.rjw-KKrjLPT3xs0@public.gmane.org>
2012-08-17  0:52       ` Shawn Guo
2012-08-17  0:52         ` Shawn Guo
2012-08-17  1:53         ` Rob Herring
2012-08-17  1:53           ` Rob Herring
2012-09-04 23:27           ` Rafael J. Wysocki
2012-09-04 23:27             ` Rafael J. Wysocki
2012-08-10  5:37 ` [PATCH v3 3/3] cpufreq: Add a generic cpufreq-cpu0 driver Shawn Guo
2012-08-10  5:37   ` Shawn Guo
2012-09-04 23:18   ` Rafael J. Wysocki
2012-09-04 23:18     ` Rafael J. Wysocki
     [not found]     ` <201209050118.39045.rjw-KKrjLPT3xs0@public.gmane.org>
2012-09-05  1:12       ` Shawn Guo
2012-09-05  1:12         ` Shawn Guo
2012-09-05  4:53         ` AnilKumar, Chimata
2012-09-05  4:53           ` AnilKumar, Chimata
2012-09-05  5:02         ` Shilimkar, Santosh
2012-09-05  5:02           ` Shilimkar, Santosh
2012-09-05 13:38         ` Rafael J. Wysocki
2012-09-05 13:38           ` Rafael J. Wysocki
2012-09-05 13:59           ` Shawn Guo
2012-09-05 13:59             ` Shawn Guo
2012-09-05 20:18             ` Rafael J. Wysocki
2012-09-05 20:18               ` Rafael J. Wysocki
2012-09-06  7:29               ` Shawn Guo
2012-09-06  7:29                 ` Shawn Guo
     [not found]                 ` <20120906072935.GB2362-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-09-06 19:59                   ` Rafael J. Wysocki [this message]
2012-09-06 19:59                     ` Rafael J. Wysocki
2012-08-31  6:42 ` [PATCH v3 0/3] " Shawn Guo
2012-08-31  6:42   ` Shawn Guo
2012-09-01  5:53   ` Rafael J. Wysocki
2012-09-01  5:53     ` Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=201209062159.01788.rjw@sisk.pl \
    --to=rjw-kkrjlpt3xs0@public.gmane.org \
    --cc=broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org \
    --cc=cpufreq-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org \
    --cc=khilman-l0cyMroinI0@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org \
    --cc=linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=nm-l0cyMroinI0@public.gmane.org \
    --cc=richard.zhao-KZfg59tc24xl57MIdRCFDg@public.gmane.org \
    --cc=rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org \
    --cc=santosh.shilimkar-l0cyMroinI0@public.gmane.org \
    --cc=shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.