summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorTalel Shenhar <tatias@codeaurora.org>2015-05-18 12:12:48 +0300
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-31 15:26:23 -0700
commitae479fa29fc8cc9fd3ab36dde46a0638da2a4fcc (patch)
tree24577d0ae0e0f274af20de06c28ca9e126a01c3a /include
parentcff87b3cda7f31e08f6c539661e3236889831a9e (diff)
mmc: core: devfreq: migrate to devfreq based clock scaling
This change adds the use of devfreq to MMC. Both eMMC and SD card will use it. For some workloads, such as video playback, it isn't necessary for these cards to run at high speed. Running at lower frequency, for example 52MHz, in such cases can still meet the deadlines for data transfers. Scaling down the clock frequency dynamically has power savings not only because the bus is running at lower frequency but also has an advantage of scaling down the system core voltage, if supported. Provide an ondemand clock scaling support similar to the cpufreq ondemand governor having two thresholds, up_threshold and down_threshold to decide whether to increase the frequency or scale it down respectively. The sampling interval is in the order of milliseconds. If sampling interval is too low, frequent switching of frequencies can lead to high power consumption and if sampling interval is too high, the clock scaling logic would take long time to realize that the underlying hardware (controller and card) is busy and scale up the clocks. Change-Id: I58ddbd93648ded82b304411956e035fb353cd97e Signed-off-by: Talel Shenhar <tatias@codeaurora.org> [subhashj@codeaurora.org: fixed trivial merge conflicts & compilation errors] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/mmc/card.h4
-rw-r--r--include/linux/mmc/host.h65
2 files changed, 53 insertions, 16 deletions
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 59ef4e717beb..ae943ccb331e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -275,6 +275,10 @@ struct mmc_card {
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
u32 ocr; /* the current OCR setting */
+ unsigned long clk_scaling_lowest; /* lowest scaleable
+ * frequency */
+ unsigned long clk_scaling_highest; /* highest scaleable
+ * frequency */
unsigned int rca; /* relative card address of device */
unsigned int type; /* card type */
#define MMC_TYPE_MMC 0 /* MMC card */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2ba8ba249e00..5afbac264ddd 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -15,6 +15,7 @@
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/device.h>
+#include <linux/devfreq.h>
#include <linux/fault-inject.h>
#include <linux/mmc/core.h>
@@ -224,9 +225,57 @@ enum dev_state {
DEV_RESUMED,
};
+/**
+ * struct mmc_devfeq_clk_scaling - main context for MMC clock scaling logic
+ *
+ * @lock: spinlock to protect statistics
+ * @devfreq: struct that represent mmc-host as a client for devfreq
+ * @devfreq_profile: MMC device profile, mostly polling interval and callbacks
+ * @ondemand_gov_data: struct supplied to ondemmand governor (thresholds)
+ * @state: load state, can be HIGH or LOW. used to notify mmc_host_ops callback
+ * @start_busy: timestamped armed once a data request is started
+ * @measure_interval_start: timestamped armed once a measure interval started
+ * @devfreq_abort: flag to sync between different contexts relevant to devfreq
+ * @skip_clk_scale_freq_update: flag that enable/disable frequency change
+ * @freq_table_sz: table size of frequencies supplied to devfreq
+ * @freq_table: frequencies table supplied to devfreq
+ * @curr_freq: current frequency
+ * @polling_delay_ms: polling interval for status collection used by devfreq
+ * @upthreshold: up-threshold supplied to ondemand governor
+ * @downthreshold: down-threshold supplied to ondemand governor
+ * @need_freq_change: flag indicating if a frequency change is required
+ * @clk_scaling_in_progress: flag indicating if there's ongoing frequency change
+ * @is_busy_started: flag indicating if a request is handled by the HW
+ * @enable: flag indicating if the clock scaling logic is enabled for this host
+ */
+struct mmc_devfeq_clk_scaling {
+ spinlock_t lock;
+ struct devfreq *devfreq;
+ struct devfreq_dev_profile devfreq_profile;
+ struct devfreq_simple_ondemand_data ondemand_gov_data;
+ enum mmc_load state;
+ ktime_t start_busy;
+ ktime_t measure_interval_start;
+ atomic_t devfreq_abort;
+ bool skip_clk_scale_freq_update;
+ int freq_table_sz;
+ u32 *freq_table;
+ unsigned long total_busy_time_us;
+ unsigned long target_freq;
+ unsigned long curr_freq;
+ unsigned long polling_delay_ms;
+ unsigned int upthreshold;
+ unsigned int downthreshold;
+ bool need_freq_change;
+ bool clk_scaling_in_progress;
+ bool is_busy_started;
+ bool enable;
+};
+
struct mmc_host {
struct device *parent;
struct device class_dev;
+ struct mmc_devfeq_clk_scaling clk_scaling;
int index;
const struct mmc_host_ops *ops;
struct mmc_pwrseq *pwrseq;
@@ -441,22 +490,6 @@ struct mmc_host {
} perf;
bool perf_enable;
#endif
- struct {
- unsigned long busy_time_us;
- unsigned long window_time;
- unsigned long curr_freq;
- unsigned long polling_delay_ms;
- unsigned int up_threshold;
- unsigned int down_threshold;
- ktime_t start_busy;
- bool enable;
- bool initialized;
- bool in_progress;
- /* freq. transitions are not allowed in invalid state */
- bool invalid_state;
- struct delayed_work work;
- enum mmc_load state;
- } clk_scaling;
enum dev_state dev_status;
bool wakeup_on_idle;
unsigned long private[0] ____cacheline_aligned;