Update devfreq for 5.9

Detailed description for this pull request:
 1. Update devfreq core
 - Add support delayed timer for polling mode. Until now, the devfreq supports
   only deferrable timer for reducing the unneeded CPU wakeup.
   But, it has a problem for Non-CPU device like DMC device with DMA operation.
   These Non-CPU device need to monitor continuously regardless of CPU state.
   Add support the delayed timer for polling mode to support the continuous
   monitoring.
 - Fix indentation of result of devfreq_summary debugfs node.
 - Fix the wrong end of code with semicolon instead of comma
 - Clean-up code to use the unified local variable name in sysfs-related
   internal funcitons.
 - Fix trivial spelling for devfreq-event.c.
 
 2. Update devfreq driver
 - Add the exception handling code to control when rockchip,pmu property is absent
   for rk3399_dmc.c.
 - Add missing 'rockchip,pmu' property to dt-binding document for rk3399_dmc.c.
 - Change the kind of timer of exynos5422-dmc.c from deferrable to delayed
   timer in order to monitor the DMC (Dynamic Memory Controller) status
   regardless of CPU idle state. And adjust the polling interval and upthreshold
   value in order to react faster and make better decisions when benchmarking
   testing for the memory behavior.
 - Add module parameter to either enable or disable the IRQ mode for DMC
   behavior monitoring. The exynos5422-dmc.c can operate in both polling
   and IRQ mode. The user can choose the monitoring mode by using module param.
   The default monitoring mode is polling mode with delayed timer.
 
  3. Add maintainer entry
 - Add Dmitry Osipenko <digetx@gmail.com> as maintainer for memory frequency
   scaling drivers for Nvidia Tegra. He have been developed and reviewed
   the tegra*-devfreq.c.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEsSpuqBtbWtRe4rLGnM3fLN7rz1MFAl8iiJ0WHGN3MDAuY2hv
 aUBzYW1zdW5nLmNvbQAKCRCczd8s3uvPU+WbD/0TkndmsnqXgzkLsyAUFgWsRy3N
 LL8xwtHXmM76ujT5m5UH5A+BHp3Ex9SsGA4xJ9cr7C3Reg2OmSKe8BZjkA52fwDE
 2qu0CHB4IP41EjS3skBqiEhSGdFPv7xd9z39dk6xgUNaQM3yEmcrtPI96jx2CYE9
 WYroUl8Lc1uU9fnV+1dyah7nK9p+pi27QqFQBdyOLikOpi2qq5loY6EsBjDq8bym
 Lv5VjgpI5cpBflolf1y5Zi6p+qFHNUroPz5iOnYJIUNqgKUHEhY8CdGVlLynQTo/
 IOLXvhuGQc7q2grFKUjHGTAps+YV2lbY8j8WZl+ujhLTkCxme/XILHXe7b2GHHZy
 TleViwsdhL0lYkGCOrla66qFn2kNIXMjEnRJ3GfL7wRUFliS6IlFrg50/TLws7Qe
 RogI+rM/LuBPM9H4IDy5WTglChnctOxc2sSmbWKy2u1LoDMxfR/SIEwjvdFq/enx
 U0fE/vpXrJkADPSk/4+W/AdnnV2JmIFKlHoy83cZYzp5KHq9voQOv575sMkvSYRl
 hRc9Y8zxYtPOS9cJGV/nxgyEfp/gkOpcwrvy/uPuOqVMLC//ZEK/gR78nfT1YvJ3
 c6ODnY8wpK+HZdqhWqc7SXWA9kK3BZrrDRkDBRPXthVOvyvKcifKn9AjVETqRGDu
 OPpZ19FZqIy3KMVMEg==
 =Iw2C
 -----END PGP SIGNATURE-----

Merge tag 'devfreq-next-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux

Pull devfreq updates for v5.9 from Chanwoo Choi:

1. Update devfreq core

 - Add delayed timer support for polling mode. Until now, devfreq supported
   only deferrable timer to avoid unneeded CPU wakeups. However, it has a
   problem for non-CPU devices, like DMC, doing DMA. Such devices need to
   monitor continuously regardless of the CPU state, so delayed timer support
   for the polling mode to facilitate the continuous monitoring.

 - Fix indentation of result of devfreq_summary debugfs node.

 - Fix the wrong end of code with a semicolon instead of a comma.

 - Clean-up code to use a unified local variable name in sysfs-related
   internal funcitons.

 - Fix trivial spelling mistake in devfreq-event.c.

2. Update devfreq drivers

 - Add the exception handling code to control when rockchip,pmu property is
   absent for rk3399_dmc.c.

 - Add missing 'rockchip,pmu' property to dt-binding document for rk3399_dmc.c.

 - Change the type of timer in exynos5422-dmc.c from deferrable to delayed
   in order to monitor the DMC (Dynamic Memory Controller) status regardless of
   the CPU idle state. Also adjust the polling interval and upthreshold
   value in order to react faster and make better decisions when benchmarking
   testing for the memory behavior.

 - Add module parameter to either enable or disable the IRQ mode for DMC
   behavior monitoring. exynos5422-dmc.c can operate in both the polling and
   the IRQ mode. The user can choose the monitoring mode via a module param.
   The default monitoring mode is the polling mode with a delayed timer.

 3. Add maintainer entry

 - Add Dmitry Osipenko <digetx@gmail.com> as maintainer for memory
   frequency scaling drivers for Nvidia Tegra. He has developed and
   reviewed tegra*-devfreq.c.

* tag 'devfreq-next-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux:
  PM / devfreq: Fix the wrong end with semicolon
  PM / devfreq: Fix indentaion of devfreq_summary debugfs node
  PM / devfreq: Clean up the devfreq instance name in sysfs attr
  memory: samsung: exynos5422-dmc: Add module param to control IRQ mode
  memory: samsung: exynos5422-dmc: Adjust polling interval and uptreshold
  memory: samsung: exynos5422-dmc: Use delayed timer as default
  PM / devfreq: Add support delayed timer for polling mode
  dt-bindings: devfreq: rk3399_dmc: Add rockchip,pmu phandle
  PM / devfreq: tegra: Add Dmitry as a maintainer
  PM / devfreq: event: Fix trivial spelling
  PM / devfreq: rk3399_dmc: Fix kernel oops when rockchip,pmu is absent
This commit is contained in:
Rafael J. Wysocki 2020-07-30 18:52:15 +02:00
commit a7ee88c3d3
8 changed files with 217 additions and 68 deletions

View File

@ -108,3 +108,15 @@ Description:
frequency requested by governors and min_freq.
The max_freq overrides min_freq because max_freq may be
used to throttle devices to avoid overheating.
What: /sys/class/devfreq/.../timer
Date: July 2020
Contact: Chanwoo Choi <cw00.choi@samsung.com>
Description:
This ABI shows and stores the kind of work timer by users.
This work timer is used by devfreq workqueue in order to
monitor the device status such as utilization. The user
can change the work timer on runtime according to their demand
as following:
echo deferrable > /sys/class/devfreq/.../timer
echo delayed > /sys/class/devfreq/.../timer

View File

@ -18,6 +18,8 @@ Optional properties:
format depends on the interrupt controller.
It should be a DCF interrupt. When DDR DVFS finishes
a DCF interrupt is triggered.
- rockchip,pmu: Phandle to the syscon managing the "PMU general register
files".
Following properties relate to DDR timing:

View File

@ -11097,6 +11097,15 @@ F: Documentation/core-api/boot-time-mm.rst
F: include/linux/memblock.h
F: mm/memblock.c
MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA
M: Dmitry Osipenko <digetx@gmail.com>
L: linux-pm@vger.kernel.org
L: linux-tegra@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
S: Maintained
F: drivers/devfreq/tegra20-devfreq.c
F: drivers/devfreq/tegra30-devfreq.c
MEMORY MANAGEMENT
M: Andrew Morton <akpm@linux-foundation.org>
L: linux-mm@kvack.org

View File

@ -293,7 +293,7 @@ static void devfreq_event_release_edev(struct device *dev)
/**
* devfreq_event_add_edev() - Add new devfreq-event device.
* @dev : the device owning the devfreq-event device being created
* @desc : the devfreq-event device's decriptor which include essential
* @desc : the devfreq-event device's descriptor which include essential
* data for devfreq-event device.
*
* Note that this function add new devfreq-event device to devfreq-event class
@ -385,7 +385,7 @@ static void devm_devfreq_event_release(struct device *dev, void *res)
/**
* devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev()
* @dev : the device owning the devfreq-event device being created
* @desc : the devfreq-event device's decriptor which include essential
* @desc : the devfreq-event device's descriptor which include essential
* data for devfreq-event device.
*
* Note that this function manages automatically the memory of devfreq-event

View File

@ -49,6 +49,11 @@ static LIST_HEAD(devfreq_governor_list);
static LIST_HEAD(devfreq_list);
static DEFINE_MUTEX(devfreq_list_lock);
static const char timer_name[][DEVFREQ_NAME_LEN] = {
[DEVFREQ_TIMER_DEFERRABLE] = { "deferrable" },
[DEVFREQ_TIMER_DELAYED] = { "delayed" },
};
/**
* find_device_devfreq() - find devfreq struct using device pointer
* @dev: device pointer used to lookup device devfreq.
@ -454,7 +459,17 @@ void devfreq_monitor_start(struct devfreq *devfreq)
if (devfreq->governor->interrupt_driven)
return;
INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
switch (devfreq->profile->timer) {
case DEVFREQ_TIMER_DEFERRABLE:
INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
break;
case DEVFREQ_TIMER_DELAYED:
INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor);
break;
default:
return;
}
if (devfreq->profile->polling_ms)
queue_delayed_work(devfreq_wq, &devfreq->work,
msecs_to_jiffies(devfreq->profile->polling_ms));
@ -771,6 +786,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;
if (devfreq->profile->timer < 0
|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
goto err_out;
}
if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
mutex_unlock(&devfreq->lock);
err = set_freq_table(devfreq);
@ -1260,18 +1280,20 @@ EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent));
struct devfreq *df = to_devfreq(dev);
return sprintf(buf, "%s\n", dev_name(df->dev.parent));
}
static DEVICE_ATTR_RO(name);
static ssize_t governor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (!to_devfreq(dev)->governor)
struct devfreq *df = to_devfreq(dev);
if (!df->governor)
return -EINVAL;
return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
return sprintf(buf, "%s\n", df->governor->name);
}
static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
@ -1282,6 +1304,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
char str_governor[DEVFREQ_NAME_LEN + 1];
const struct devfreq_governor *governor, *prev_governor;
if (!df->governor)
return -EINVAL;
ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
if (ret != 1)
return -EINVAL;
@ -1295,20 +1320,18 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
if (df->governor == governor) {
ret = 0;
goto out;
} else if ((df->governor && df->governor->immutable) ||
governor->immutable) {
} else if (df->governor->immutable || governor->immutable) {
ret = -EINVAL;
goto out;
}
if (df->governor) {
ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
if (ret) {
dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
__func__, df->governor->name, ret);
goto out;
}
ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
if (ret) {
dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
__func__, df->governor->name, ret);
goto out;
}
prev_governor = df->governor;
df->governor = governor;
strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
@ -1343,13 +1366,16 @@ static ssize_t available_governors_show(struct device *d,
struct devfreq *df = to_devfreq(d);
ssize_t count = 0;
if (!df->governor)
return -EINVAL;
mutex_lock(&devfreq_list_lock);
/*
* The devfreq with immutable governor (e.g., passive) shows
* only own governor.
*/
if (df->governor && df->governor->immutable) {
if (df->governor->immutable) {
count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
"%s ", df->governor_name);
/*
@ -1383,27 +1409,37 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
unsigned long freq;
struct devfreq *devfreq = to_devfreq(dev);
struct devfreq *df = to_devfreq(dev);
if (devfreq->profile->get_cur_freq &&
!devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
if (!df->profile)
return -EINVAL;
if (df->profile->get_cur_freq &&
!df->profile->get_cur_freq(df->dev.parent, &freq))
return sprintf(buf, "%lu\n", freq);
return sprintf(buf, "%lu\n", devfreq->previous_freq);
return sprintf(buf, "%lu\n", df->previous_freq);
}
static DEVICE_ATTR_RO(cur_freq);
static ssize_t target_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
struct devfreq *df = to_devfreq(dev);
return sprintf(buf, "%lu\n", df->previous_freq);
}
static DEVICE_ATTR_RO(target_freq);
static ssize_t polling_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
struct devfreq *df = to_devfreq(dev);
if (!df->profile)
return -EINVAL;
return sprintf(buf, "%d\n", df->profile->polling_ms);
}
static ssize_t polling_interval_store(struct device *dev,
@ -1531,6 +1567,9 @@ static ssize_t available_frequencies_show(struct device *d,
ssize_t count = 0;
int i;
if (!df->profile)
return -EINVAL;
mutex_lock(&df->lock);
for (i = 0; i < df->profile->max_state; i++)
@ -1551,49 +1590,53 @@ static DEVICE_ATTR_RO(available_frequencies);
static ssize_t trans_stat_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
struct devfreq *df = to_devfreq(dev);
ssize_t len;
int i, j;
unsigned int max_state = devfreq->profile->max_state;
unsigned int max_state;
if (!df->profile)
return -EINVAL;
max_state = df->profile->max_state;
if (max_state == 0)
return sprintf(buf, "Not Supported.\n");
mutex_lock(&devfreq->lock);
if (!devfreq->stop_polling &&
devfreq_update_status(devfreq, devfreq->previous_freq)) {
mutex_unlock(&devfreq->lock);
mutex_lock(&df->lock);
if (!df->stop_polling &&
devfreq_update_status(df, df->previous_freq)) {
mutex_unlock(&df->lock);
return 0;
}
mutex_unlock(&devfreq->lock);
mutex_unlock(&df->lock);
len = sprintf(buf, " From : To\n");
len += sprintf(buf + len, " :");
for (i = 0; i < max_state; i++)
len += sprintf(buf + len, "%10lu",
devfreq->profile->freq_table[i]);
df->profile->freq_table[i]);
len += sprintf(buf + len, " time(ms)\n");
for (i = 0; i < max_state; i++) {
if (devfreq->profile->freq_table[i]
== devfreq->previous_freq) {
if (df->profile->freq_table[i]
== df->previous_freq) {
len += sprintf(buf + len, "*");
} else {
len += sprintf(buf + len, " ");
}
len += sprintf(buf + len, "%10lu:",
devfreq->profile->freq_table[i]);
df->profile->freq_table[i]);
for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%10u",
devfreq->stats.trans_table[(i * max_state) + j]);
df->stats.trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10llu\n", (u64)
jiffies64_to_msecs(devfreq->stats.time_in_state[i]));
jiffies64_to_msecs(df->stats.time_in_state[i]));
}
len += sprintf(buf + len, "Total transition : %u\n",
devfreq->stats.total_trans);
df->stats.total_trans);
return len;
}
@ -1604,6 +1647,9 @@ static ssize_t trans_stat_store(struct device *dev,
struct devfreq *df = to_devfreq(dev);
int err, value;
if (!df->profile)
return -EINVAL;
if (df->profile->max_state == 0)
return count;
@ -1625,6 +1671,69 @@ static ssize_t trans_stat_store(struct device *dev,
}
static DEVICE_ATTR_RW(trans_stat);
static ssize_t timer_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *df = to_devfreq(dev);
if (!df->profile)
return -EINVAL;
return sprintf(buf, "%s\n", timer_name[df->profile->timer]);
}
static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
char str_timer[DEVFREQ_NAME_LEN + 1];
int timer = -1;
int ret = 0, i;
if (!df->governor || !df->profile)
return -EINVAL;
ret = sscanf(buf, "%16s", str_timer);
if (ret != 1)
return -EINVAL;
for (i = 0; i < DEVFREQ_TIMER_NUM; i++) {
if (!strncmp(timer_name[i], str_timer, DEVFREQ_NAME_LEN)) {
timer = i;
break;
}
}
if (timer < 0) {
ret = -EINVAL;
goto out;
}
if (df->profile->timer == timer) {
ret = 0;
goto out;
}
mutex_lock(&df->lock);
df->profile->timer = timer;
mutex_unlock(&df->lock);
ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
if (ret) {
dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
__func__, df->governor->name, ret);
goto out;
}
ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
if (ret)
dev_warn(dev, "%s: Governor %s not started(%d)\n",
__func__, df->governor->name, ret);
out:
return ret ? ret : count;
}
static DEVICE_ATTR_RW(timer);
static struct attribute *devfreq_attrs[] = {
&dev_attr_name.attr,
&dev_attr_governor.attr,
@ -1636,6 +1745,7 @@ static struct attribute *devfreq_attrs[] = {
&dev_attr_min_freq.attr,
&dev_attr_max_freq.attr,
&dev_attr_trans_stat.attr,
&dev_attr_timer.attr,
NULL,
};
ATTRIBUTE_GROUPS(devfreq);
@ -1657,8 +1767,7 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
unsigned long cur_freq, min_freq, max_freq;
unsigned int polling_ms;
seq_printf(s, "%-30s %-10s %-10s %-15s %10s %12s %12s %12s\n",
"dev_name",
seq_printf(s, "%-30s %-30s %-15s %10s %12s %12s %12s\n",
"dev",
"parent_dev",
"governor",
@ -1666,10 +1775,9 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
"cur_freq_Hz",
"min_freq_Hz",
"max_freq_Hz");
seq_printf(s, "%30s %10s %10s %15s %10s %12s %12s %12s\n",
seq_printf(s, "%30s %30s %15s %10s %12s %12s %12s\n",
"------------------------------",
"------------------------------",
"----------",
"----------",
"---------------",
"----------",
"------------",
@ -1692,14 +1800,13 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
#endif
mutex_lock(&devfreq->lock);
cur_freq = devfreq->previous_freq,
cur_freq = devfreq->previous_freq;
get_freq_range(devfreq, &min_freq, &max_freq);
polling_ms = devfreq->profile->polling_ms,
polling_ms = devfreq->profile->polling_ms;
mutex_unlock(&devfreq->lock);
seq_printf(s,
"%-30s %-10s %-10s %-15s %10d %12ld %12ld %12ld\n",
dev_name(devfreq->dev.parent),
"%-30s %-30s %-15s %10d %12ld %12ld %12ld\n",
dev_name(&devfreq->dev),
p_devfreq ? dev_name(&p_devfreq->dev) : "null",
devfreq->governor_name,

View File

@ -95,18 +95,20 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
mutex_lock(&dmcfreq->lock);
if (target_rate >= dmcfreq->odt_dis_freq)
odt_enable = true;
if (dmcfreq->regmap_pmu) {
if (target_rate >= dmcfreq->odt_dis_freq)
odt_enable = true;
/*
* This makes a SMC call to the TF-A to set the DDR PD (power-down)
* timings and to enable or disable the ODT (on-die termination)
* resistors.
*/
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
dmcfreq->odt_pd_arg1,
ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
odt_enable, 0, 0, 0, &res);
/*
* This makes a SMC call to the TF-A to set the DDR PD
* (power-down) timings and to enable or disable the
* ODT (on-die termination) resistors.
*/
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
dmcfreq->odt_pd_arg1,
ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
odt_enable, 0, 0, 0, &res);
}
/*
* If frequency scaling from low to high, adjust voltage first.
@ -371,13 +373,14 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
}
node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) {
data->regmap_pmu = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(data->regmap_pmu)) {
ret = PTR_ERR(data->regmap_pmu);
goto err_edev;
}
if (!node)
goto no_pmu;
data->regmap_pmu = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(data->regmap_pmu)) {
ret = PTR_ERR(data->regmap_pmu);
goto err_edev;
}
regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
@ -399,6 +402,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
goto err_edev;
};
no_pmu:
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
ROCKCHIP_SIP_CONFIG_DRAM_INIT,
0, 0, 0, 0, &res);

View File

@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of_device.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
@ -21,6 +22,10 @@
#include "../jedec_ddr.h"
#include "../of_memory.h"
static int irqmode;
module_param(irqmode, int, 0644);
MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)");
#define EXYNOS5_DREXI_TIMINGAREF (0x0030)
#define EXYNOS5_DREXI_TIMINGROW0 (0x0034)
#define EXYNOS5_DREXI_TIMINGDATA0 (0x0038)
@ -945,6 +950,7 @@ static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
* It provides to the devfreq framework needed functions and polling period.
*/
static struct devfreq_dev_profile exynos5_dmc_df_profile = {
.timer = DEVFREQ_TIMER_DELAYED,
.target = exynos5_dmc_target,
.get_dev_status = exynos5_dmc_get_status,
.get_cur_freq = exynos5_dmc_get_cur_freq,
@ -1427,7 +1433,7 @@ static int exynos5_dmc_probe(struct platform_device *pdev)
/* There is two modes in which the driver works: polling or IRQ */
irq[0] = platform_get_irq_byname(pdev, "drex_0");
irq[1] = platform_get_irq_byname(pdev, "drex_1");
if (irq[0] > 0 && irq[1] > 0) {
if (irq[0] > 0 && irq[1] > 0 && irqmode) {
ret = devm_request_threaded_irq(dev, irq[0], NULL,
dmc_irq_thread, IRQF_ONESHOT,
dev_name(dev), dmc);
@ -1465,10 +1471,10 @@ static int exynos5_dmc_probe(struct platform_device *pdev)
* Setup default thresholds for the devfreq governor.
* The values are chosen based on experiments.
*/
dmc->gov_data.upthreshold = 30;
dmc->gov_data.upthreshold = 10;
dmc->gov_data.downdifferential = 5;
exynos5_dmc_df_profile.polling_ms = 500;
exynos5_dmc_df_profile.polling_ms = 100;
}
@ -1484,7 +1490,7 @@ static int exynos5_dmc_probe(struct platform_device *pdev)
if (dmc->in_irq_mode)
exynos5_dmc_start_perf_events(dmc, PERF_COUNTER_START_VALUE);
dev_info(dev, "DMC initialized\n");
dev_info(dev, "DMC initialized, in irq mode: %d\n", dmc->in_irq_mode);
return 0;

View File

@ -31,6 +31,13 @@
#define DEVFREQ_PRECHANGE (0)
#define DEVFREQ_POSTCHANGE (1)
/* DEVFREQ work timers */
enum devfreq_timer {
DEVFREQ_TIMER_DEFERRABLE = 0,
DEVFREQ_TIMER_DELAYED,
DEVFREQ_TIMER_NUM,
};
struct devfreq;
struct devfreq_governor;
@ -70,6 +77,7 @@ struct devfreq_dev_status {
* @initial_freq: The operating frequency when devfreq_add_device() is
* called.
* @polling_ms: The polling interval in ms. 0 disables polling.
* @timer: Timer type is either deferrable or delayed timer.
* @target: The device should set its operating frequency at
* freq or lowest-upper-than-freq value. If freq is
* higher than any operable frequency, set maximum.
@ -96,6 +104,7 @@ struct devfreq_dev_status {
struct devfreq_dev_profile {
unsigned long initial_freq;
unsigned int polling_ms;
enum devfreq_timer timer;
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev,