]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branches 'pm-devfreq' and 'pm-domains'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 6 May 2019 08:55:49 +0000 (10:55 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 6 May 2019 08:55:49 +0000 (10:55 +0200)
* pm-devfreq:
  PM / devfreq: add tracing for scheduling work
  trace: events: add devfreq trace event file
  PM / devfreq: rk3399_dmc: Pass ODT and auto power down parameters to TF-A.
  PM / devfreq: rockchip-dfi: Move GRF definitions to a common place.
  PM / devfreq: exynos-bus: Suspend all devices on system shutdown
  PM / devfreq: Fix static checker warning in try_then_request_governor
  PM / devfreq: Restart previous governor if new governor fails to start
  PM / devfreq: tegra: remove unneeded variable
  PM / devfreq: rockchip-dfi: remove unneeded semicolon
  PM / devfreq: rk3399_dmc: remove unneeded semicolon
  PM / devfreq: consistent indentation
  PM / devfreq: fix missing check of return value in devfreq_add_device()
  PM / devfreq: fix mem leak in devfreq_add_device()
  PM / devfreq: Use of_node_name_eq for node name comparisons

* pm-domains:
  PM / Domains: Allow to attach a CPU via genpd_dev_pm_attach_by_id|name()
  PM / Domains: Search for the CPU device outside the genpd lock
  PM / Domains: Drop unused in-parameter to some genpd functions
  PM / Domains: Use the base device for driver_deferred_probe_check_state()
  PM / Domains: Enable genpd_dev_pm_attach_by_id|name() for single PM domain
  PM / Domains: Allow OF lookup for multi PM domain case from ->attach_dev()
  PM / Domains: Don't kfree() the virtual device in the error path
  PM / Domains: remove unnecessary unlikely()

13 files changed:
MAINTAINERS
drivers/base/power/domain.c
drivers/devfreq/devfreq-event.c
drivers/devfreq/devfreq.c
drivers/devfreq/event/exynos-ppmu.c
drivers/devfreq/event/rockchip-dfi.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/rk3399_dmc.c
drivers/devfreq/tegra-devfreq.c
include/linux/pm_domain.h
include/soc/rockchip/rk3399_grf.h [new file with mode: 0644]
include/soc/rockchip/rockchip_sip.h
include/trace/events/devfreq.h [new file with mode: 0644]

index 9a1d42e652da15ab36e39176769eb813245d68b2..dbb490f2b0a054ac6f332c2d4eb16cd500fa76bb 100644 (file)
@@ -4553,6 +4553,7 @@ S:        Maintained
 F:     drivers/devfreq/
 F:     include/linux/devfreq.h
 F:     Documentation/devicetree/bindings/devfreq/
+F:     include/trace/events/devfreq.h
 
 DEVICE FREQUENCY EVENT (DEVFREQ-EVENT)
 M:     Chanwoo Choi <cw00.choi@samsung.com>
index ecac03dcc9b268f0689b9bb3678117de76c3b88a..3d899e8abd585f09f49f8d5de7218a8d2357db55 100644 (file)
@@ -393,11 +393,9 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
        if (unlikely(!genpd->set_performance_state))
                return -EINVAL;
 
-       if (unlikely(!dev->power.subsys_data ||
-                    !dev->power.subsys_data->domain_data)) {
-               WARN_ON(1);
+       if (WARN_ON(!dev->power.subsys_data ||
+                    !dev->power.subsys_data->domain_data))
                return -EINVAL;
-       }
 
        genpd_lock(genpd);
 
@@ -1398,8 +1396,7 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
 
 #endif /* CONFIG_PM_SLEEP */
 
-static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
-                                       struct gpd_timing_data *td)
+static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
 {
        struct generic_pm_domain_data *gpd_data;
        int ret;
@@ -1414,9 +1411,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
                goto err_put;
        }
 
-       if (td)
-               gpd_data->td = *td;
-
        gpd_data->base.dev = dev;
        gpd_data->td.constraint_changed = true;
        gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
@@ -1456,8 +1450,8 @@ static void genpd_free_dev_data(struct device *dev,
        dev_pm_put_subsys_data(dev);
 }
 
-static void __genpd_update_cpumask(struct generic_pm_domain *genpd,
-                                  int cpu, bool set, unsigned int depth)
+static void genpd_update_cpumask(struct generic_pm_domain *genpd,
+                                int cpu, bool set, unsigned int depth)
 {
        struct gpd_link *link;
 
@@ -1468,7 +1462,7 @@ static void __genpd_update_cpumask(struct generic_pm_domain *genpd,
                struct generic_pm_domain *master = link->master;
 
                genpd_lock_nested(master, depth + 1);
-               __genpd_update_cpumask(master, cpu, set, depth + 1);
+               genpd_update_cpumask(master, cpu, set, depth + 1);
                genpd_unlock(master);
        }
 
@@ -1478,36 +1472,35 @@ static void __genpd_update_cpumask(struct generic_pm_domain *genpd,
                cpumask_clear_cpu(cpu, genpd->cpus);
 }
 
-static void genpd_update_cpumask(struct generic_pm_domain *genpd,
-                                struct device *dev, bool set)
+static void genpd_set_cpumask(struct generic_pm_domain *genpd, int cpu)
+{
+       if (cpu >= 0)
+               genpd_update_cpumask(genpd, cpu, true, 0);
+}
+
+static void genpd_clear_cpumask(struct generic_pm_domain *genpd, int cpu)
+{
+       if (cpu >= 0)
+               genpd_update_cpumask(genpd, cpu, false, 0);
+}
+
+static int genpd_get_cpu(struct generic_pm_domain *genpd, struct device *dev)
 {
        int cpu;
 
        if (!genpd_is_cpu_domain(genpd))
-               return;
+               return -1;
 
        for_each_possible_cpu(cpu) {
-               if (get_cpu_device(cpu) == dev) {
-                       __genpd_update_cpumask(genpd, cpu, set, 0);
-                       return;
-               }
+               if (get_cpu_device(cpu) == dev)
+                       return cpu;
        }
-}
 
-static void genpd_set_cpumask(struct generic_pm_domain *genpd,
-                             struct device *dev)
-{
-       genpd_update_cpumask(genpd, dev, true);
-}
-
-static void genpd_clear_cpumask(struct generic_pm_domain *genpd,
-                               struct device *dev)
-{
-       genpd_update_cpumask(genpd, dev, false);
+       return -1;
 }
 
 static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
-                           struct gpd_timing_data *td)
+                           struct device *base_dev)
 {
        struct generic_pm_domain_data *gpd_data;
        int ret;
@@ -1517,17 +1510,19 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
                return -EINVAL;
 
-       gpd_data = genpd_alloc_dev_data(dev, td);
+       gpd_data = genpd_alloc_dev_data(dev);
        if (IS_ERR(gpd_data))
                return PTR_ERR(gpd_data);
 
+       gpd_data->cpu = genpd_get_cpu(genpd, base_dev);
+
        ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
        if (ret)
                goto out;
 
        genpd_lock(genpd);
 
-       genpd_set_cpumask(genpd, dev);
+       genpd_set_cpumask(genpd, gpd_data->cpu);
        dev_pm_domain_set(dev, &genpd->domain);
 
        genpd->device_count++;
@@ -1555,7 +1550,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
        int ret;
 
        mutex_lock(&gpd_list_lock);
-       ret = genpd_add_device(genpd, dev, NULL);
+       ret = genpd_add_device(genpd, dev, dev);
        mutex_unlock(&gpd_list_lock);
 
        return ret;
@@ -1585,7 +1580,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
        genpd->device_count--;
        genpd->max_off_time_changed = true;
 
-       genpd_clear_cpumask(genpd, dev);
+       genpd_clear_cpumask(genpd, gpd_data->cpu);
        dev_pm_domain_set(dev, NULL);
 
        list_del_init(&pdd->list_node);
@@ -2261,7 +2256,7 @@ int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev)
                goto out;
        }
 
-       ret = genpd_add_device(genpd, dev, NULL);
+       ret = genpd_add_device(genpd, dev, dev);
 
 out:
        mutex_unlock(&gpd_list_lock);
@@ -2345,6 +2340,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_last);
 
 static void genpd_release_dev(struct device *dev)
 {
+       of_node_put(dev->of_node);
        kfree(dev);
 }
 
@@ -2406,14 +2402,14 @@ static void genpd_dev_pm_sync(struct device *dev)
        genpd_queue_power_off_work(pd);
 }
 
-static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
+static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
                                 unsigned int index, bool power_on)
 {
        struct of_phandle_args pd_args;
        struct generic_pm_domain *pd;
        int ret;
 
-       ret = of_parse_phandle_with_args(np, "power-domains",
+       ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
                                "#power-domain-cells", index, &pd_args);
        if (ret < 0)
                return ret;
@@ -2425,12 +2421,12 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
                mutex_unlock(&gpd_list_lock);
                dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
                        __func__, PTR_ERR(pd));
-               return driver_deferred_probe_check_state(dev);
+               return driver_deferred_probe_check_state(base_dev);
        }
 
        dev_dbg(dev, "adding to PM domain %s\n", pd->name);
 
-       ret = genpd_add_device(pd, dev, NULL);
+       ret = genpd_add_device(pd, dev, base_dev);
        mutex_unlock(&gpd_list_lock);
 
        if (ret < 0) {
@@ -2481,7 +2477,7 @@ int genpd_dev_pm_attach(struct device *dev)
                                       "#power-domain-cells") != 1)
                return 0;
 
-       return __genpd_dev_pm_attach(dev, dev->of_node, 0, true);
+       return __genpd_dev_pm_attach(dev, dev, 0, true);
 }
 EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
 
@@ -2511,10 +2507,10 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
        if (!dev->of_node)
                return NULL;
 
-       /* Deal only with devices using multiple PM domains. */
+       /* Verify that the index is within a valid range. */
        num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
                                                 "#power-domain-cells");
-       if (num_domains < 2 || index >= num_domains)
+       if (index >= num_domains)
                return NULL;
 
        /* Allocate and register device on the genpd bus. */
@@ -2525,15 +2521,16 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
        dev_set_name(virt_dev, "genpd:%u:%s", index, dev_name(dev));
        virt_dev->bus = &genpd_bus_type;
        virt_dev->release = genpd_release_dev;
+       virt_dev->of_node = of_node_get(dev->of_node);
 
        ret = device_register(virt_dev);
        if (ret) {
-               kfree(virt_dev);
+               put_device(virt_dev);
                return ERR_PTR(ret);
        }
 
        /* Try to attach the device to the PM domain at the specified index. */
-       ret = __genpd_dev_pm_attach(virt_dev, dev->of_node, index, false);
+       ret = __genpd_dev_pm_attach(virt_dev, dev, index, false);
        if (ret < 1) {
                device_unregister(virt_dev);
                return ret ? ERR_PTR(ret) : NULL;
index d67242d87744330a96b2786d5bcd3267e8724c21..87e93406d7cd9eb18f0adca3b85e0a5c4d1cc966 100644 (file)
@@ -240,7 +240,7 @@ struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
        }
 
        list_for_each_entry(edev, &devfreq_event_list, node) {
-               if (!strcmp(edev->desc->name, node->name))
+               if (of_node_name_eq(node, edev->desc->name))
                        goto out;
        }
        edev = NULL;
index 0ae3de76833b7da0c16f01ca79e482ec66217594..6b6991f0e873f093c4cdac2fccfdd0534771043b 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/of.h>
 #include "governor.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/devfreq.h>
+
 static struct class *devfreq_class;
 
 /*
@@ -228,7 +231,7 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
  * if is not found. This can happen when both drivers (the governor driver
  * and the driver that call devfreq_add_device) are built as modules.
  * devfreq_list_lock should be held by the caller. Returns the matched
- * governor's pointer.
+ * governor's pointer or an error pointer.
  */
 static struct devfreq_governor *try_then_request_governor(const char *name)
 {
@@ -254,7 +257,7 @@ static struct devfreq_governor *try_then_request_governor(const char *name)
                /* Restore previous state before return */
                mutex_lock(&devfreq_list_lock);
                if (err)
-                       return NULL;
+                       return ERR_PTR(err);
 
                governor = find_devfreq_governor(name);
        }
@@ -394,6 +397,8 @@ static void devfreq_monitor(struct work_struct *work)
        queue_delayed_work(devfreq_wq, &devfreq->work,
                                msecs_to_jiffies(devfreq->profile->polling_ms));
        mutex_unlock(&devfreq->lock);
+
+       trace_devfreq_monitor(devfreq);
 }
 
 /**
@@ -528,7 +533,7 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
                mutex_lock(&devfreq->lock);
                if (!devfreq->stop_polling)
                        queue_delayed_work(devfreq_wq, &devfreq->work,
-                             msecs_to_jiffies(devfreq->profile->polling_ms));
+                               msecs_to_jiffies(devfreq->profile->polling_ms));
        }
 out:
        mutex_unlock(&devfreq->lock);
@@ -537,7 +542,7 @@ EXPORT_SYMBOL(devfreq_interval_update);
 
 /**
  * devfreq_notifier_call() - Notify that the device frequency requirements
- *                        has been changed out of devfreq framework.
+ *                          has been changed out of devfreq framework.
  * @nb:                the notifier_block (supposed to be devfreq->nb)
  * @type:      not used
  * @devp:      not used
@@ -651,7 +656,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
                mutex_unlock(&devfreq->lock);
                err = set_freq_table(devfreq);
                if (err < 0)
-                       goto err_out;
+                       goto err_dev;
                mutex_lock(&devfreq->lock);
        }
 
@@ -683,16 +688,27 @@ struct devfreq *devfreq_add_device(struct device *dev,
                goto err_out;
        }
 
-       devfreq->trans_table =
-               devm_kzalloc(&devfreq->dev,
-                            array3_size(sizeof(unsigned int),
-                                        devfreq->profile->max_state,
-                                        devfreq->profile->max_state),
-                            GFP_KERNEL);
+       devfreq->trans_table = devm_kzalloc(&devfreq->dev,
+                       array3_size(sizeof(unsigned int),
+                                   devfreq->profile->max_state,
+                                   devfreq->profile->max_state),
+                       GFP_KERNEL);
+       if (!devfreq->trans_table) {
+               mutex_unlock(&devfreq->lock);
+               err = -ENOMEM;
+               goto err_devfreq;
+       }
+
        devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
-                                               devfreq->profile->max_state,
-                                               sizeof(unsigned long),
-                                               GFP_KERNEL);
+                       devfreq->profile->max_state,
+                       sizeof(unsigned long),
+                       GFP_KERNEL);
+       if (!devfreq->time_in_state) {
+               mutex_unlock(&devfreq->lock);
+               err = -ENOMEM;
+               goto err_devfreq;
+       }
+
        devfreq->last_stat_updated = jiffies;
 
        srcu_init_notifier_head(&devfreq->transition_notifier_list);
@@ -726,7 +742,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 err_init:
        mutex_unlock(&devfreq_list_lock);
-
+err_devfreq:
        devfreq_remove_device(devfreq);
        devfreq = NULL;
 err_dev:
@@ -1113,7 +1129,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
        struct devfreq *df = to_devfreq(dev);
        int ret;
        char str_governor[DEVFREQ_NAME_LEN + 1];
-       struct devfreq_governor *governor;
+       const struct devfreq_governor *governor, *prev_governor;
 
        ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
        if (ret != 1)
@@ -1142,12 +1158,24 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
                        goto out;
                }
        }
+       prev_governor = df->governor;
        df->governor = governor;
        strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
        ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
-       if (ret)
+       if (ret) {
                dev_warn(dev, "%s: Governor %s not started(%d)\n",
                         __func__, df->governor->name, ret);
+               df->governor = prev_governor;
+               strncpy(df->governor_name, prev_governor->name,
+                       DEVFREQ_NAME_LEN);
+               ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
+               if (ret) {
+                       dev_err(dev,
+                               "%s: reverting to Governor %s failed (%d)\n",
+                               __func__, df->governor_name, ret);
+                       df->governor = NULL;
+               }
+       }
 out:
        mutex_unlock(&devfreq_list_lock);
 
@@ -1172,7 +1200,7 @@ static ssize_t available_governors_show(struct device *d,
         */
        if (df->governor->immutable) {
                count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
-                                  "%s ", df->governor_name);
+                                 "%s ", df->governor_name);
        /*
         * The devfreq device shows the registered governor except for
         * immutable governors such as passive governor .
@@ -1485,8 +1513,8 @@ EXPORT_SYMBOL(devfreq_recommended_opp);
 
 /**
  * devfreq_register_opp_notifier() - Helper function to get devfreq notified
- *                                for any changes in the OPP availability
- *                                changes
+ *                                  for any changes in the OPP availability
+ *                                  changes
  * @dev:       The devfreq user device. (parent of devfreq)
  * @devfreq:   The devfreq object.
  */
@@ -1498,8 +1526,8 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier);
 
 /**
  * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
- *                                  notified for any changes in the OPP
- *                                  availability changes anymore.
+ *                                    notified for any changes in the OPP
+ *                                    availability changes anymore.
  * @dev:       The devfreq user device. (parent of devfreq)
  * @devfreq:   The devfreq object.
  *
@@ -1518,8 +1546,8 @@ static void devm_devfreq_opp_release(struct device *dev, void *res)
 }
 
 /**
- * devm_ devfreq_register_opp_notifier()
- *             - Resource-managed devfreq_register_opp_notifier()
+ * devm_devfreq_register_opp_notifier() - Resource-managed
+ *                                       devfreq_register_opp_notifier()
  * @dev:       The devfreq user device. (parent of devfreq)
  * @devfreq:   The devfreq object.
  */
@@ -1547,8 +1575,8 @@ int devm_devfreq_register_opp_notifier(struct device *dev,
 EXPORT_SYMBOL(devm_devfreq_register_opp_notifier);
 
 /**
- * devm_devfreq_unregister_opp_notifier()
- *             - Resource-managed devfreq_unregister_opp_notifier()
+ * devm_devfreq_unregister_opp_notifier() - Resource-managed
+ *                                         devfreq_unregister_opp_notifier()
  * @dev:       The devfreq user device. (parent of devfreq)
  * @devfreq:   The devfreq object.
  */
@@ -1567,8 +1595,8 @@ EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
  * @list:      DEVFREQ_TRANSITION_NOTIFIER.
  */
 int devfreq_register_notifier(struct devfreq *devfreq,
-                               struct notifier_block *nb,
-                               unsigned int list)
+                             struct notifier_block *nb,
+                             unsigned int list)
 {
        int ret = 0;
 
@@ -1674,9 +1702,9 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier);
  * @list:      DEVFREQ_TRANSITION_NOTIFIER.
  */
 void devm_devfreq_unregister_notifier(struct device *dev,
-                               struct devfreq *devfreq,
-                               struct notifier_block *nb,
-                               unsigned int list)
+                                     struct devfreq *devfreq,
+                                     struct notifier_block *nb,
+                                     unsigned int list)
 {
        WARN_ON(devres_release(dev, devm_devfreq_notifier_release,
                               devm_devfreq_dev_match, devfreq));
index c61de0bdf053214bda01edb26a75abb64acc58f1..c2ea9495750157d2e7fdff63367868437fad3037 100644 (file)
@@ -529,7 +529,7 @@ static int of_get_devfreq_events(struct device_node *np,
                        if (!ppmu_events[i].name)
                                continue;
 
-                       if (!of_node_cmp(node->name, ppmu_events[i].name))
+                       if (of_node_name_eq(node, ppmu_events[i].name))
                                break;
                }
 
index 22b113363ffc62a6aa5281dec3da8005f6cf71e5..a436ec4901bbe5ac97985a8265a01ae16ae6b2c1 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/list.h>
 #include <linux/of.h>
 
+#include <soc/rockchip/rk3399_grf.h>
+
 #define RK3399_DMC_NUM_CH      2
 
 /* DDRMON_CTRL */
 #define DDRMON_CH1_COUNT_NUM           0x3c
 #define DDRMON_CH1_DFI_ACCESS_NUM      0x40
 
-/* pmu grf */
-#define PMUGRF_OS_REG2 0x308
-#define DDRTYPE_SHIFT  13
-#define DDRTYPE_MASK   7
-
-enum {
-       DDR3 = 3,
-       LPDDR3 = 6,
-       LPDDR4 = 7,
-       UNUSED = 0xFF
-};
-
 struct dmc_usage {
        u32 access;
        u32 total;
@@ -83,16 +73,17 @@ static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev)
        u32 ddr_type;
 
        /* get ddr type */
-       regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, &val);
-       ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK;
+       regmap_read(info->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
+       ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
+                   RK3399_PMUGRF_DDRTYPE_MASK;
 
        /* clear DDRMON_CTRL setting */
        writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL);
 
        /* set ddr type to dfi */
-       if (ddr_type == LPDDR3)
+       if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3)
                writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL);
-       else if (ddr_type == LPDDR4)
+       else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4)
                writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL);
 
        /* enable count, use software mode */
@@ -211,7 +202,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
        if (IS_ERR(data->clk)) {
                dev_err(dev, "Cannot get the clk dmc_clk\n");
                return PTR_ERR(data->clk);
-       };
+       }
 
        /* try to find the optional reference to the pmu syscon */
        node = of_parse_phandle(np, "rockchip,pmu", 0);
index c25658b265988b4fdd2a3f4304fdbfab83b7b9f3..486cc5b422f1d5076fd804179a12f81d5510070a 100644 (file)
@@ -514,6 +514,13 @@ static int exynos_bus_probe(struct platform_device *pdev)
        return ret;
 }
 
+static void exynos_bus_shutdown(struct platform_device *pdev)
+{
+       struct exynos_bus *bus = dev_get_drvdata(&pdev->dev);
+
+       devfreq_suspend_device(bus->devfreq);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int exynos_bus_resume(struct device *dev)
 {
@@ -556,6 +563,7 @@ MODULE_DEVICE_TABLE(of, exynos_bus_of_match);
 
 static struct platform_driver exynos_bus_platdrv = {
        .probe          = exynos_bus_probe,
+       .shutdown       = exynos_bus_shutdown,
        .driver = {
                .name   = "exynos-bus",
                .pm     = &exynos_bus_pm,
index e795ad2b3f6b86ef66194977f330428e240963d8..567c034d0301e5422c0a0d0e612afb2a163303a3 100644 (file)
 #include <linux/devfreq.h>
 #include <linux/devfreq-event.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/rwsem.h>
 #include <linux/suspend.h>
 
+#include <soc/rockchip/rk3399_grf.h>
 #include <soc/rockchip/rockchip_sip.h>
 
 struct dram_timing {
@@ -69,8 +72,11 @@ struct rk3399_dmcfreq {
        struct mutex lock;
        struct dram_timing timing;
        struct regulator *vdd_center;
+       struct regmap *regmap_pmu;
        unsigned long rate, target_rate;
        unsigned long volt, target_volt;
+       unsigned int odt_dis_freq;
+       int odt_pd_arg0, odt_pd_arg1;
 };
 
 static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
@@ -80,6 +86,8 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
        struct dev_pm_opp *opp;
        unsigned long old_clk_rate = dmcfreq->rate;
        unsigned long target_volt, target_rate;
+       struct arm_smccc_res res;
+       bool odt_enable = false;
        int err;
 
        opp = devfreq_recommended_opp(dev, freq, flags);
@@ -95,6 +103,19 @@ 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;
+
+       /*
+        * 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.
         * If frequency scaling from high to low, adjust frequency first.
@@ -294,11 +315,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 {
        struct arm_smccc_res res;
        struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = pdev->dev.of_node, *node;
        struct rk3399_dmcfreq *data;
        int ret, index, size;
        uint32_t *timing;
        struct dev_pm_opp *opp;
+       u32 ddr_type;
+       u32 val;
 
        data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
        if (!data)
@@ -322,7 +345,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 
                dev_err(dev, "Cannot get the clk dmc_clk\n");
                return PTR_ERR(data->dmc_clk);
-       };
+       }
 
        data->edev = devfreq_event_get_edev_by_phandle(dev, 0);
        if (IS_ERR(data->edev))
@@ -354,10 +377,56 @@ 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);
+               if (IS_ERR(data->regmap_pmu))
+                       return PTR_ERR(data->regmap_pmu);
+       }
+
+       regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
+       ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
+                   RK3399_PMUGRF_DDRTYPE_MASK;
+
+       switch (ddr_type) {
+       case RK3399_PMUGRF_DDRTYPE_DDR3:
+               data->odt_dis_freq = data->timing.ddr3_odt_dis_freq;
+               break;
+       case RK3399_PMUGRF_DDRTYPE_LPDDR3:
+               data->odt_dis_freq = data->timing.lpddr3_odt_dis_freq;
+               break;
+       case RK3399_PMUGRF_DDRTYPE_LPDDR4:
+               data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
+               break;
+       default:
+               return -EINVAL;
+       };
+
        arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
                      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
                      0, 0, 0, 0, &res);
 
+       /*
+        * In TF-A there is a platform SIP call to set the PD (power-down)
+        * timings and to enable or disable the ODT (on-die termination).
+        * This call needs three arguments as follows:
+        *
+        * arg0:
+        *     bit[0-7]   : sr_idle
+        *     bit[8-15]  : sr_mc_gate_idle
+        *     bit[16-31] : standby idle
+        * arg1:
+        *     bit[0-11]  : pd_idle
+        *     bit[16-27] : srpd_lite_idle
+        * arg2:
+        *     bit[0]     : odt enable
+        */
+       data->odt_pd_arg0 = (data->timing.sr_idle & 0xff) |
+                           ((data->timing.sr_mc_gate_idle & 0xff) << 8) |
+                           ((data->timing.standby_idle & 0xffff) << 16);
+       data->odt_pd_arg1 = (data->timing.pd_idle & 0xfff) |
+                           ((data->timing.srpd_lite_idle & 0xfff) << 16);
+
        /*
         * We add a devfreq driver to our parent since it has a device tree node
         * with operating points.
index c59d2eee5d3091ce0315092975a2692e1589ce34..c89ba7b834ffe164197abb179f29eb600f325399 100644 (file)
@@ -573,10 +573,7 @@ static int tegra_governor_get_target(struct devfreq *devfreq,
 static int tegra_governor_event_handler(struct devfreq *devfreq,
                                        unsigned int event, void *data)
 {
-       struct tegra_devfreq *tegra;
-       int ret = 0;
-
-       tegra = dev_get_drvdata(devfreq->dev.parent);
+       struct tegra_devfreq *tegra = dev_get_drvdata(devfreq->dev.parent);
 
        switch (event) {
        case DEVFREQ_GOV_START:
@@ -600,7 +597,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
                break;
        }
 
-       return ret;
+       return 0;
 }
 
 static struct devfreq_governor tegra_devfreq_governor = {
index bc82e74560ee2fdbf84a960fac826bf41e6e9bbe..0e8e356bed6a406725dbc55e5d0dae72e419105c 100644 (file)
@@ -175,6 +175,7 @@ struct generic_pm_domain_data {
        struct pm_domain_data base;
        struct gpd_timing_data td;
        struct notifier_block nb;
+       int cpu;
        unsigned int performance_state;
        void *data;
 };
diff --git a/include/soc/rockchip/rk3399_grf.h b/include/soc/rockchip/rk3399_grf.h
new file mode 100644 (file)
index 0000000..3eebabc
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Rockchip General Register Files definitions
+ *
+ * Copyright (c) 2018, Collabora Ltd.
+ * Author: Enric Balletbo i Serra <enric.balletbo@collabora.com>
+ */
+
+#ifndef __SOC_RK3399_GRF_H
+#define __SOC_RK3399_GRF_H
+
+/* PMU GRF Registers */
+#define RK3399_PMUGRF_OS_REG2          0x308
+#define RK3399_PMUGRF_DDRTYPE_SHIFT    13
+#define RK3399_PMUGRF_DDRTYPE_MASK     7
+#define RK3399_PMUGRF_DDRTYPE_DDR3     3
+#define RK3399_PMUGRF_DDRTYPE_LPDDR2   5
+#define RK3399_PMUGRF_DDRTYPE_LPDDR3   6
+#define RK3399_PMUGRF_DDRTYPE_LPDDR4   7
+
+#endif
index 7e28092c4d3dbd2fba7f434b034ca5dcf472c894..ad9482c56797f46f6053fc193afc338c99bc05f6 100644 (file)
@@ -23,5 +23,6 @@
 #define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE      0x05
 #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ       0x06
 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM     0x07
+#define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD    0x08
 
 #endif
diff --git a/include/trace/events/devfreq.h b/include/trace/events/devfreq.h
new file mode 100644 (file)
index 0000000..cf5b877
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM devfreq
+
+#if !defined(_TRACE_DEVFREQ_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_DEVFREQ_H
+
+#include <linux/devfreq.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(devfreq_monitor,
+       TP_PROTO(struct devfreq *devfreq),
+
+       TP_ARGS(devfreq),
+
+       TP_STRUCT__entry(
+               __field(unsigned long, freq)
+               __field(unsigned long, busy_time)
+               __field(unsigned long, total_time)
+               __field(unsigned int, polling_ms)
+               __string(dev_name, dev_name(&devfreq->dev))
+       ),
+
+       TP_fast_assign(
+               __entry->freq = devfreq->previous_freq;
+               __entry->busy_time = devfreq->last_status.busy_time;
+               __entry->total_time = devfreq->last_status.total_time;
+               __entry->polling_ms = devfreq->profile->polling_ms;
+               __assign_str(dev_name, dev_name(&devfreq->dev));
+       ),
+
+       TP_printk("dev_name=%s freq=%lu polling_ms=%u load=%lu",
+               __get_str(dev_name), __entry->freq, __entry->polling_ms,
+               __entry->total_time == 0 ? 0 :
+                       (100 * __entry->busy_time) / __entry->total_time)
+);
+#endif /* _TRACE_DEVFREQ_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>