Commit 0f0cc168 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-devfreq'

* pm-devfreq:
  PM / devfreq: add relation of recommended frequency.
parents 62dc7c02 ab5f299f
...@@ -83,6 +83,7 @@ int update_devfreq(struct devfreq *devfreq) ...@@ -83,6 +83,7 @@ int update_devfreq(struct devfreq *devfreq)
{ {
unsigned long freq; unsigned long freq;
int err = 0; int err = 0;
u32 flags = 0;
if (!mutex_is_locked(&devfreq->lock)) { if (!mutex_is_locked(&devfreq->lock)) {
WARN(true, "devfreq->lock must be locked by the caller.\n"); WARN(true, "devfreq->lock must be locked by the caller.\n");
...@@ -94,7 +95,24 @@ int update_devfreq(struct devfreq *devfreq) ...@@ -94,7 +95,24 @@ int update_devfreq(struct devfreq *devfreq)
if (err) if (err)
return err; return err;
err = devfreq->profile->target(devfreq->dev.parent, &freq); /*
* Adjust the freuqency with user freq and QoS.
*
* List from the highest proiority
* max_freq (probably called by thermal when it's too hot)
* min_freq
*/
if (devfreq->min_freq && freq < devfreq->min_freq) {
freq = devfreq->min_freq;
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
}
if (devfreq->max_freq && freq > devfreq->max_freq) {
freq = devfreq->max_freq;
flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
}
err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
if (err) if (err)
return err; return err;
...@@ -625,14 +643,30 @@ module_exit(devfreq_exit); ...@@ -625,14 +643,30 @@ module_exit(devfreq_exit);
* freq value given to target callback. * freq value given to target callback.
* @dev The devfreq user device. (parent of devfreq) * @dev The devfreq user device. (parent of devfreq)
* @freq The frequency given to target function * @freq The frequency given to target function
* @flags Flags handed from devfreq framework.
* *
*/ */
struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq) struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
u32 flags)
{ {
struct opp *opp = opp_find_freq_ceil(dev, freq); struct opp *opp;
if (opp == ERR_PTR(-ENODEV)) if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
/* The freq is an upper bound. opp should be lower */
opp = opp_find_freq_floor(dev, freq); opp = opp_find_freq_floor(dev, freq);
/* If not available, use the closest opp */
if (opp == ERR_PTR(-ENODEV))
opp = opp_find_freq_ceil(dev, freq);
} else {
/* The freq is an lower bound. opp should be higher */
opp = opp_find_freq_ceil(dev, freq);
/* If not available, use the closest opp */
if (opp == ERR_PTR(-ENODEV))
opp = opp_find_freq_floor(dev, freq);
}
return opp; return opp;
} }
......
...@@ -619,13 +619,19 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp, ...@@ -619,13 +619,19 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
return err; return err;
} }
static int exynos4_bus_target(struct device *dev, unsigned long *_freq) static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
u32 flags)
{ {
int err = 0; int err = 0;
struct busfreq_data *data = dev_get_drvdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device,
struct opp *opp = devfreq_recommended_opp(dev, _freq); dev);
unsigned long old_freq = opp_get_freq(data->curr_opp); struct busfreq_data *data = platform_get_drvdata(pdev);
struct opp *opp = devfreq_recommended_opp(dev, _freq, flags);
unsigned long freq = opp_get_freq(opp); unsigned long freq = opp_get_freq(opp);
unsigned long old_freq = opp_get_freq(data->curr_opp);
if (IS_ERR(opp))
return PTR_ERR(opp);
if (old_freq == freq) if (old_freq == freq)
return 0; return 0;
......
...@@ -44,6 +44,14 @@ struct devfreq_dev_status { ...@@ -44,6 +44,14 @@ struct devfreq_dev_status {
void *private_data; void *private_data;
}; };
/*
* The resulting frequency should be at most this. (this bound is the
* least upper bound; thus, the resulting freq should be lower or same)
* If the flag is not set, the resulting frequency should be at most the
* bound (greatest lower bound)
*/
#define DEVFREQ_FLAG_LEAST_UPPER_BOUND 0x1
/** /**
* struct devfreq_dev_profile - Devfreq's user device profile * struct devfreq_dev_profile - Devfreq's user device profile
* @initial_freq The operating frequency when devfreq_add_device() is * @initial_freq The operating frequency when devfreq_add_device() is
...@@ -54,6 +62,8 @@ struct devfreq_dev_status { ...@@ -54,6 +62,8 @@ struct devfreq_dev_status {
* higher than any operable frequency, set maximum. * higher than any operable frequency, set maximum.
* Before returning, target function should set * Before returning, target function should set
* freq at the current frequency. * freq at the current frequency.
* The "flags" parameter's possible values are
* explained above with "DEVFREQ_FLAG_*" macros.
* @get_dev_status The device should provide the current performance * @get_dev_status The device should provide the current performance
* status to devfreq, which is used by governors. * status to devfreq, which is used by governors.
* @exit An optional callback that is called when devfreq * @exit An optional callback that is called when devfreq
...@@ -66,7 +76,7 @@ struct devfreq_dev_profile { ...@@ -66,7 +76,7 @@ struct devfreq_dev_profile {
unsigned long initial_freq; unsigned long initial_freq;
unsigned int polling_ms; unsigned int polling_ms;
int (*target)(struct device *dev, unsigned long *freq); int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev, int (*get_dev_status)(struct device *dev,
struct devfreq_dev_status *stat); struct devfreq_dev_status *stat);
void (*exit)(struct device *dev); void (*exit)(struct device *dev);
...@@ -165,7 +175,7 @@ extern int devfreq_remove_device(struct devfreq *devfreq); ...@@ -165,7 +175,7 @@ extern int devfreq_remove_device(struct devfreq *devfreq);
/* Helper functions for devfreq user device driver with OPP. */ /* Helper functions for devfreq user device driver with OPP. */
extern struct opp *devfreq_recommended_opp(struct device *dev, extern struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq); unsigned long *freq, u32 flags);
extern int devfreq_register_opp_notifier(struct device *dev, extern int devfreq_register_opp_notifier(struct device *dev,
struct devfreq *devfreq); struct devfreq *devfreq);
extern int devfreq_unregister_opp_notifier(struct device *dev, extern int devfreq_unregister_opp_notifier(struct device *dev,
...@@ -216,7 +226,7 @@ static int devfreq_remove_device(struct devfreq *devfreq) ...@@ -216,7 +226,7 @@ static int devfreq_remove_device(struct devfreq *devfreq)
} }
static struct opp *devfreq_recommended_opp(struct device *dev, static struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq) unsigned long *freq, u32 flags)
{ {
return -EINVAL; return -EINVAL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment