From c727848bb4f0b841b6ade4eced73e03a7887af87 Mon Sep 17 00:00:00 2001 From: Rama Aparna Mallavarapu Date: Tue, 23 Apr 2019 11:51:53 +0530 Subject: [PATCH] devfreq: detect ddr type and add frequency table accordingly Some targets support different DDR types. Detect the DDR type and populate the frequency table accordingly. OPP framework supports opp-supported-hw bit map which allows the selected frequencies to be added to the opp table based on the hardware version check. Implement the same in the bandwidth monitor device so that the right frequencies would be added to the opp table. This patch also adds checks for the latency based device to detect the DDR type at runtime and add the corresponding frequency map. Change-Id: Ice5a0b14da67b3f2f07e98bc7349220da7d4efdb Signed-off-by: Santosh Mardi Signed-off-by: Rama Aparna Mallavarapu [avajid@codeaurora.org: resolved minor conflicts and made minor styling changes] Signed-off-by: Amir Vajid --- drivers/devfreq/arm-memlat-mon.c | 23 +++++++++++++++++++++++ drivers/devfreq/devfreq_icc.c | 15 +++++++++++++++ drivers/devfreq/governor_memlat.c | 23 ++++++++++++++++++----- drivers/devfreq/governor_memlat.h | 1 + 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 4c79111cf89d..f1d2f3d38fa9 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "governor.h" #include "governor_memlat.h" #include @@ -252,6 +253,26 @@ static int get_mask_from_dev_handle(struct platform_device *pdev, return ret; } +static struct device_node *parse_child_nodes(struct device *dev) +{ + struct device_node *of_child; + int ddr_type_of = -1; + int ddr_type = of_fdt_get_ddrtype(); + int ret; + + for_each_child_of_node(dev->of_node, of_child) { + ret = of_property_read_u32(of_child, "qcom,ddr-type", + &ddr_type_of); + if (!ret && (ddr_type == ddr_type_of)) { + dev_dbg(dev, + "ddr-type = %d, is matching DT entry\n", + ddr_type_of); + return of_child; + } + } + return NULL; +} + static int arm_memlat_mon_driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -297,6 +318,8 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) hw->start_hwmon = &start_hwmon; hw->stop_hwmon = &stop_hwmon; hw->get_cnt = &get_cnt; + if (of_get_child_count(dev->of_node)) + hw->get_child_of_node = &parse_child_nodes; spec = of_device_get_match_data(dev); if (spec && spec->is_compute) { diff --git a/drivers/devfreq/devfreq_icc.c b/drivers/devfreq/devfreq_icc.c index d1f1c396b432..a9888faedacc 100644 --- a/drivers/devfreq/devfreq_icc.c +++ b/drivers/devfreq/devfreq_icc.c @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -87,6 +89,8 @@ int devfreq_add_icc(struct device *dev) struct devfreq_dev_profile *p; const char *gov_name; int ret; + struct opp_table *opp_table; + u32 version; d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); if (!d) @@ -98,6 +102,15 @@ int devfreq_add_icc(struct device *dev) p->target = icc_target; p->get_dev_status = icc_get_dev_status; + if (of_device_is_compatible(dev->of_node, "qcom,devfreq-icc-ddr")) { + version = (1 << of_fdt_get_ddrtype()); + opp_table = dev_pm_opp_set_supported_hw(dev, &version, 1); + if (IS_ERR(opp_table)) { + dev_err(dev, "Failed to set supported hardware\n"); + return PTR_ERR(opp_table); + } + } + ret = dev_pm_opp_of_add_table(dev); if (ret < 0) dev_err(dev, "Couldn't parse OPP table:%d\n", ret); @@ -159,6 +172,8 @@ static int devfreq_icc_remove(struct platform_device *pdev) } static const struct of_device_id devfreq_icc_match_table[] = { + { .compatible = "qcom,devfreq-icc-llcc" }, + { .compatible = "qcom,devfreq-icc-ddr" }, { .compatible = "qcom,devfreq-icc" }, {} }; diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index 8997d0f11f53..04ff9abdefb9 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "governor.h" @@ -418,14 +419,18 @@ static struct devfreq_governor devfreq_gov_compute = { #define NUM_COLS 2 static struct core_dev_map *init_core_dev_map(struct device *dev, - char *prop_name) + struct device_node *of_node, + char *prop_name) { int len, nf, i, j; u32 data; struct core_dev_map *tbl; int ret; - if (!of_find_property(dev->of_node, prop_name, &len)) + if (!of_node) + of_node = dev->of_node; + + if (!of_find_property(of_node, prop_name, &len)) return NULL; len /= sizeof(data); @@ -439,13 +444,13 @@ static struct core_dev_map *init_core_dev_map(struct device *dev, return NULL; for (i = 0, j = 0; i < nf; i++, j += 2) { - ret = of_property_read_u32_index(dev->of_node, prop_name, j, + ret = of_property_read_u32_index(of_node, prop_name, j, &data); if (ret < 0) return NULL; tbl[i].core_mhz = data / 1000; - ret = of_property_read_u32_index(dev->of_node, prop_name, j + 1, + ret = of_property_read_u32_index(of_node, prop_name, j + 1, &data); if (ret < 0) return NULL; @@ -462,6 +467,7 @@ static struct memlat_node *register_common(struct device *dev, struct memlat_hwmon *hw) { struct memlat_node *node; + struct device_node *of_child; if (!hw->dev && !hw->of_node) return ERR_PTR(-EINVAL); @@ -473,7 +479,14 @@ static struct memlat_node *register_common(struct device *dev, node->ratio_ceil = 10; node->hw = hw; - hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); + if (hw->get_child_of_node) { + of_child = hw->get_child_of_node(dev); + hw->freq_map = init_core_dev_map(dev, of_child, + "qcom,core-dev-table"); + } else { + hw->freq_map = init_core_dev_map(dev, NULL, + "qcom,core-dev-table"); + } if (!hw->freq_map) { dev_err(dev, "Couldn't find the core-dev freq table!\n"); return ERR_PTR(-EINVAL); diff --git a/drivers/devfreq/governor_memlat.h b/drivers/devfreq/governor_memlat.h index c43edddb2695..b1c334018f16 100644 --- a/drivers/devfreq/governor_memlat.h +++ b/drivers/devfreq/governor_memlat.h @@ -54,6 +54,7 @@ struct memlat_hwmon { int (*start_hwmon)(struct memlat_hwmon *hw); void (*stop_hwmon)(struct memlat_hwmon *hw); unsigned long (*get_cnt)(struct memlat_hwmon *hw); + struct device_node *(*get_child_of_node)(struct device *dev); struct device *dev; struct device_node *of_node;