]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: QoS triggers postscale
authorArto Merilainen <amerilainen@nvidia.com>
Sat, 1 Feb 2014 10:44:40 +0000 (12:44 +0200)
committerTerje Bergstrom <tbergstrom@nvidia.com>
Tue, 4 Feb 2014 13:46:13 +0000 (05:46 -0800)
For some devices we use QoS to define the minimum required frequency.
As this mechanism bypasses totally devfreq and the usual device profile,
we need to trigger postscale callback also in these cases to ensure that
i.e. EMC is scaled correctly at the same time.

Bug 1441874

Change-Id: I33545101157b015db240bfe9bb8a5c404469803c
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-on: http://git-master/r/362487
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
drivers/video/tegra/host/gk20a/gk20a_scale.c
drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c
drivers/video/tegra/host/nvhost_scale.c
drivers/video/tegra/host/nvhost_scale.h
include/linux/nvhost.h

index 92ee08144a16f58a0d85b48ceb29677084e6e713..c80b372a43dc1a069c8bd28eb4cb20f175374226 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/clk/tegra.h>
 #include <linux/tegra-soc.h>
 #include <linux/platform_data/tegra_edp.h>
+#include <linux/pm_qos.h>
 
 #include <governor.h>
 
@@ -79,6 +80,37 @@ void nvhost_gk20a_scale_callback(struct nvhost_device_profile *profile,
        nvhost_module_set_devfreq_rate(profile->pdev, 2, emc_target);
 }
 
+/*
+ * nvhost_scale_qos_notify()
+ *
+ * This function is called when the minimum QoS requirement for the device
+ * has changed. The function calls postscaling callback if it is defined.
+ */
+
+static int nvhost_scale_qos_notify(struct notifier_block *nb,
+                                  unsigned long n, void *p)
+{
+       struct nvhost_device_profile *profile =
+               container_of(nb, struct nvhost_device_profile,
+                            qos_notify_block);
+       struct nvhost_device_data *pdata = platform_get_drvdata(profile->pdev);
+       struct gk20a *g = get_gk20a(profile->pdev);
+       unsigned long freq;
+
+       if (!pdata->scaling_post_cb)
+               return NOTIFY_OK;
+
+       /* get the frequency requirement. if devfreq is enabled, check if it
+        * has higher demand than qos */
+       freq = gk20a_clk_round_rate(g, pm_qos_request(pdata->qos_id));
+       if (pdata->power_manager)
+               freq = max(pdata->power_manager->previous_freq, freq);
+
+       pdata->scaling_post_cb(profile, freq);
+
+       return NOTIFY_OK;
+}
+
 /*
  * nvhost_scale_make_freq_table(profile)
  *
@@ -302,6 +334,16 @@ void nvhost_gk20a_scale_init(struct platform_device *pdev)
 
                pdata->power_manager = devfreq;
        }
+
+       /* Should we register QoS callback for this device? */
+       if (pdata->qos_id < PM_QOS_NUM_CLASSES &&
+           pdata->qos_id != PM_QOS_RESERVED) {
+               profile->qos_notify_block.notifier_call =
+                       &nvhost_scale_qos_notify;
+               pm_qos_add_notifier(pdata->qos_id,
+                                   &profile->qos_notify_block);
+       }
+
        return;
 
 err_get_freqs:
index b5543e75417707fc7051601ae7dcc1af6821c151..8c0a2dd064b5c3fa667985d0beaf909c219e59de 100644 (file)
@@ -142,6 +142,7 @@ struct gk20a_platform gk20a_tegra_platform = {
                .devfreq_governor       = "nvhost_podgov",
                .scaling_post_cb        = nvhost_gk20a_scale_callback,
                .gpu_edp_device         = true,
+               .qos_id                 = PM_QOS_GPU_FREQ_MIN,
 #endif
        },
        .probe = gk20a_tegra_probe,
index 89792f019e6866b2a8a5cc9b1d13d38bfc4f7780..b916ac6ea0bd7e5e0e7dad6d132b1e5e15db9191 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/clk/tegra.h>
 #include <linux/platform_data/tegra_edp.h>
 #include <linux/tegra-soc.h>
+#include <linux/tegra-soc.h>
+#include <linux/platform_data/tegra_edp.h>
+#include <linux/pm_qos.h>
 
 #include <governor.h>
 
@@ -121,6 +124,37 @@ static int nvhost_scale_target(struct device *dev, unsigned long *freq,
        return 0;
 }
 
+/*
+ * nvhost_scale_qos_notify()
+ *
+ * This function is called when the minimum QoS requirement for the device
+ * has changed. The function calls postscaling callback if it is defined.
+ */
+
+static int nvhost_scale_qos_notify(struct notifier_block *nb,
+                                  unsigned long n, void *p)
+{
+       struct nvhost_device_profile *profile =
+               container_of(nb, struct nvhost_device_profile,
+                            qos_notify_block);
+       struct nvhost_device_data *pdata = platform_get_drvdata(profile->pdev);
+       unsigned long freq;
+
+       if (!pdata->scaling_post_cb)
+               return NOTIFY_OK;
+
+       /* get the frequency requirement. if devfreq is enabled, check if it
+        * has higher demand than qos */
+       freq = clk_round_rate(clk_get_parent(profile->clk),
+                             pm_qos_request(pdata->qos_id));
+       if (pdata->power_manager)
+               freq = max(pdata->power_manager->previous_freq, freq);
+
+       pdata->scaling_post_cb(profile, freq);
+
+       return NOTIFY_OK;
+}
+
 /*
  * update_load_estimate(profile)
  *
@@ -324,6 +358,15 @@ void nvhost_scale_init(struct platform_device *pdev)
                pdata->power_manager = devfreq;
        }
 
+       /* Should we register QoS callback for this device? */
+       if (pdata->qos_id < PM_QOS_NUM_CLASSES &&
+           pdata->qos_id != PM_QOS_RESERVED) {
+               profile->qos_notify_block.notifier_call =
+                       &nvhost_scale_qos_notify;
+               pm_qos_add_notifier(pdata->qos_id,
+                                   &profile->qos_notify_block);
+       }
+
        return;
 
 err_get_freqs:
index ce2e64e05a2e75fc9ee4b6bd0fc3b0842f81ee6e..5a74bd6c9b0fd92693a138c80aea7966597e38cf 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host 3D Clock Scaling
  *
- * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -46,6 +46,7 @@ struct nvhost_device_profile {
        struct nvhost_devfreq_ext_stat  ext_stat;
 
        void                            *private_data;
+       struct notifier_block           qos_notify_block;
 };
 
 /* Initialization and de-initialization for module */
index 7bf9e777d460ca14750e1cade8bcb68d8c4845df..933b72cca699351422b7678fa071dc0173e63b9f 100644 (file)
@@ -231,6 +231,8 @@ struct nvhost_device_data {
 
        u32 nvhost_timeout_default;
 
+       /* QoS id that denotes minimum frequency */
+       unsigned int                    qos_id;
        /* Data for devfreq usage */
        struct devfreq                  *power_manager;
        /* Private device profile data */