summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt3
-rw-r--r--drivers/devfreq/bimc-bwmon.c40
-rw-r--r--drivers/devfreq/governor_bw_hwmon.c42
-rw-r--r--drivers/devfreq/governor_bw_hwmon.h4
4 files changed, 84 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
index 6bed78506108..d96c174d2581 100644
--- a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
+++ b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
@@ -5,7 +5,8 @@ can be used to measure the bandwidth of read/write traffic from the BIMC
master ports. For example, the CPU subsystem sits on one BIMC master port.
Required properties:
-- compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2"
+- compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" or
+ "qcom,bimc-bwmon3"
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
- reg-names: Names of the bases for the above registers. Expected
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index d4a56c98cb4c..2b0bacdb5f6a 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -43,6 +43,7 @@
struct bwmon_spec {
bool wrap_on_thres;
bool overflow;
+ bool throt_adj;
};
struct bwmon {
@@ -53,19 +54,24 @@ struct bwmon {
const struct bwmon_spec *spec;
struct device *dev;
struct bw_hwmon hw;
+ u32 throttle_adj;
};
#define to_bwmon(ptr) container_of(ptr, struct bwmon, hw)
+#define ENABLE_MASK BIT(0)
+#define THROTTLE_MASK 0x1F
+#define THROTTLE_SHIFT 16
+
static DEFINE_SPINLOCK(glb_lock);
static void mon_enable(struct bwmon *m)
{
- writel_relaxed(0x1, MON_EN(m));
+ writel_relaxed((ENABLE_MASK | m->throttle_adj), MON_EN(m));
}
static void mon_disable(struct bwmon *m)
{
- writel_relaxed(0x0, MON_EN(m));
+ writel_relaxed(m->throttle_adj, MON_EN(m));
/*
* mon_disable() and mon_irq_clear(),
* If latter goes first and count happen to trigger irq, we would
@@ -145,6 +151,26 @@ static void mon_irq_clear(struct bwmon *m)
mb();
}
+static int mon_set_throttle_adj(struct bw_hwmon *hw, uint adj)
+{
+ struct bwmon *m = to_bwmon(hw);
+
+ if (adj > THROTTLE_MASK)
+ return -EINVAL;
+
+ adj = (adj & THROTTLE_MASK) << THROTTLE_SHIFT;
+ m->throttle_adj = adj;
+
+ return 0;
+}
+
+static u32 mon_get_throttle_adj(struct bw_hwmon *hw)
+{
+ struct bwmon *m = to_bwmon(hw);
+
+ return m->throttle_adj >> THROTTLE_SHIFT;
+}
+
static void mon_set_limit(struct bwmon *m, u32 count)
{
writel_relaxed(count, MON_THRES(m));
@@ -324,13 +350,15 @@ static int resume_bw_hwmon(struct bw_hwmon *hw)
/*************************************************************************/
static const struct bwmon_spec spec[] = {
- { .wrap_on_thres = true, .overflow = false },
- { .wrap_on_thres = false, .overflow = true },
+ { .wrap_on_thres = true, .overflow = false, .throt_adj = false},
+ { .wrap_on_thres = false, .overflow = true, .throt_adj = false},
+ { .wrap_on_thres = false, .overflow = true, .throt_adj = true},
};
static struct of_device_id match_table[] = {
{ .compatible = "qcom,bimc-bwmon", .data = &spec[0] },
{ .compatible = "qcom,bimc-bwmon2", .data = &spec[1] },
+ { .compatible = "qcom,bimc-bwmon3", .data = &spec[2] },
{}
};
@@ -399,6 +427,10 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
m->hw.resume_hwmon = &resume_bw_hwmon;
m->hw.get_bytes_and_clear = &get_bytes_and_clear;
m->hw.set_thres = &set_thres;
+ if (m->spec->throt_adj) {
+ m->hw.set_throttle_adj = &mon_set_throttle_adj;
+ m->hw.get_throttle_adj = &mon_get_throttle_adj;
+ }
ret = register_bw_hwmon(dev, &m->hw);
if (ret) {
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index b369fed1a821..05198a17ad5f 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -673,6 +673,47 @@ static int devfreq_bw_hwmon_get_freq(struct devfreq *df,
return 0;
}
+static ssize_t store_throttle_adj(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct devfreq *df = to_devfreq(dev);
+ struct hwmon_node *node = df->data;
+ int ret;
+ unsigned int val;
+
+ if (!node->hw->set_throttle_adj)
+ return -ENOSYS;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = node->hw->set_throttle_adj(node->hw, val);
+
+ if (!ret)
+ return count;
+ else
+ return ret;
+}
+
+static ssize_t show_throttle_adj(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct devfreq *df = to_devfreq(dev);
+ struct hwmon_node *node = df->data;
+ unsigned int val;
+
+ if (!node->hw->get_throttle_adj)
+ val = 0;
+ else
+ val = node->hw->get_throttle_adj(node->hw);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static DEVICE_ATTR(throttle_adj, 0644, show_throttle_adj,
+ store_throttle_adj);
+
gov_attr(guard_band_mbps, 0U, 2000U);
gov_attr(decay_rate, 0U, 100U);
gov_attr(io_percent, 1U, 100U);
@@ -709,6 +750,7 @@ static struct attribute *dev_attr[] = {
&dev_attr_low_power_io_percent.attr,
&dev_attr_low_power_delay.attr,
&dev_attr_mbps_zones.attr,
+ &dev_attr_throttle_adj.attr,
NULL,
};
diff --git a/drivers/devfreq/governor_bw_hwmon.h b/drivers/devfreq/governor_bw_hwmon.h
index 8e60f9aeceb0..dcae1d6cbeb2 100644
--- a/drivers/devfreq/governor_bw_hwmon.h
+++ b/drivers/devfreq/governor_bw_hwmon.h
@@ -24,6 +24,8 @@
* @set_thres: Set the count threshold to generate an IRQ
* @get_bytes_and_clear: Get the bytes transferred since the last call
* and reset the counter to start over.
+ * @set_throttle_adj: Set throttle adjust field to the given value
+ * @get_throttle_adj: Get the value written to throttle adjust field
* @dev: Pointer to device that this HW monitor can
* monitor.
* @of_node: OF node of device that this HW monitor can
@@ -47,6 +49,8 @@ struct bw_hwmon {
int (*resume_hwmon)(struct bw_hwmon *hw);
unsigned long (*set_thres)(struct bw_hwmon *hw, unsigned long bytes);
unsigned long (*get_bytes_and_clear)(struct bw_hwmon *hw);
+ int (*set_throttle_adj)(struct bw_hwmon *hw, uint adj);
+ u32 (*get_throttle_adj)(struct bw_hwmon *hw);
struct device *dev;
struct device_node *of_node;
struct devfreq_governor *gov;