mirror of https://gitee.com/openkylin/linux.git
Merge branch 'pm-devfreq'
* pm-devfreq: 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:
commit
9c8cc4d7c4
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue