video: tegra: host: host1x clock scaling for vi
Terje Bergstrom [Mon, 11 Feb 2013 20:47:04 +0000 (22:47 +0200)]
Implement host1x clock scaling for vi driver. As actmon relies on
host1x clocks, we need to readjust the actmon history when host1x
clock is changed.

Bug 1278248

Change-Id: Ibcd3104c5fb674268d5bd54684874c2bd534a4b1
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/223066
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

drivers/video/tegra/host/host1x/host1x.c
drivers/video/tegra/host/host1x/host1x.h
drivers/video/tegra/host/host1x/host1x_actmon.c
drivers/video/tegra/host/nvhost_acm.c
drivers/video/tegra/host/t114/t114.c
include/linux/nvhost.h

index c16c1f3..d8d7f29 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host Driver Entrypoint
  *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2013, 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,
@@ -395,6 +395,13 @@ static int __devinit nvhost_alloc_resources(struct nvhost_master *host)
        return 0;
 }
 
+void nvhost_host1x_update_clk(struct platform_device *pdev)
+{
+       struct nvhost_master *host = nvhost_get_host(pdev);
+
+       actmon_op().update_sample_period(host);
+}
+
 static int __devinit nvhost_probe(struct platform_device *dev)
 {
        struct nvhost_master *host;
index 9010fb0..a734da6 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host Driver Entrypoint
  *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2013, 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,
@@ -103,4 +103,6 @@ static inline struct platform_device *nvhost_get_parent(
        return _dev->dev.parent ? to_platform_device(_dev->dev.parent) : NULL;
 }
 
+void nvhost_host1x_update_clk(struct platform_device *pdev);
+
 #endif
index a0f768d..f953b18 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host Actmon support
  *
- * Copyright (c) 2012, NVIDIA Corporation.
+ * Copyright (c) 2012-2013, 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,
@@ -86,7 +86,6 @@ static void host1x_actmon_update_sample_period_safe(struct nvhost_master *host)
                | host1x_sync_actmon_status_status_source_f(
                host1x_sync_actmon_status_status_source_usec_v()),
                sync_regs + host1x_sync_actmon_status_r());
-
 }
 
 static int host1x_actmon_init(struct nvhost_master *host)
@@ -221,12 +220,46 @@ static int host1x_actmon_below_wmark_count(struct nvhost_master *host)
 
 static void host1x_actmon_update_sample_period(struct nvhost_master *host)
 {
+       void __iomem *sync_regs = host->sync_aperture;
+       long old_clks_per_sample;
+       long ratio, avg;
+       u32 val;
+       unsigned long timeout = jiffies + msecs_to_jiffies(25);
+
        /* No sense to update actmon if actmon is inactive */
        if (actmon_status.init != ACTMON_READY)
                return;
 
        nvhost_module_busy(host->dev);
+
+       /* Disable actmon */
+       val = readl(sync_regs + host1x_sync_actmon_ctrl_r());
+       val &= ~host1x_sync_actmon_ctrl_enb_m();
+       val &= ~host1x_sync_actmon_ctrl_enb_periodic_m();
+       writel(val, sync_regs + host1x_sync_actmon_ctrl_r());
+
+       /* Calculate ratio between old and new clks_per_sample */
+       old_clks_per_sample = actmon_status.clks_per_sample;
        host1x_actmon_update_sample_period_safe(host);
+       ratio = (actmon_status.clks_per_sample * 1000) / old_clks_per_sample;
+
+       /* Scale the avg to match new clock */
+       avg = readl(sync_regs + host1x_sync_actmon_avg_count_r());
+       avg *= ratio;
+       avg /= 1000;
+       writel(avg, sync_regs + host1x_sync_actmon_init_avg_r());
+
+       /* Wait for actmon to be disabled */
+       do {
+               val = readl(sync_regs + host1x_sync_actmon_status_r());
+       } while (!time_after(jiffies, timeout) &&
+                       val & host1x_sync_actmon_status_gr3d_mon_act_f(1));
+
+       /* Re-enable actmon - this will latch the init value to avg reg */
+       val |= host1x_sync_actmon_ctrl_enb_m();
+       val |= host1x_sync_actmon_ctrl_enb_periodic_m();
+       writel(val, sync_regs + host1x_sync_actmon_ctrl_r());
+
        nvhost_module_idle(host->dev);
 }
 
index 25c55ea..b058a11 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host Automatic Clock Management
  *
- * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010-2013, 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,
@@ -356,6 +356,7 @@ static int nvhost_module_update_rate(struct platform_device *dev, int index)
        struct nvhost_module_client *m;
        unsigned long devfreq_rate, default_rate;
        struct nvhost_device_data *pdata = platform_get_drvdata(dev);
+       int ret;
 
        if (!pdata->clk[index])
                return -EINVAL;
@@ -378,7 +379,13 @@ static int nvhost_module_update_rate(struct platform_device *dev, int index)
        trace_nvhost_module_update_rate(dev->name,
                        pdata->clocks[index].name, rate);
 
-       return clk_set_rate(pdata->clk[index], rate);
+       ret = clk_set_rate(pdata->clk[index], rate);
+
+       if (pdata->update_clk)
+               pdata->update_clk(dev);
+
+       return ret;
+
 }
 
 int nvhost_module_set_rate(struct platform_device *dev, void *priv,
index d9745c5..39f3ffc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Init for Tegra11 Architecture Chips
  *
- * Copyright (c) 2011-2012, NVIDIA Corporation.
+ * Copyright (c) 2011-2013, 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,
@@ -210,10 +210,12 @@ static struct nvhost_device_data tegra_vi01_info = {
                          BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
                          BIT(NVSYNCPT_VI_ISP_4),
        .modulemutexes  = BIT(NVMODMUTEX_VI),
+       .clocks         = { {"host1x", 136000000, 6} },
        .exclusive      = true,
        NVHOST_MODULE_NO_POWERGATE_IDS,
        NVHOST_DEFAULT_CLOCKGATE_DELAY,
        .moduleid       = NVHOST_MODULE_VI,
+       .update_clk     = nvhost_host1x_update_clk,
 };
 
 static struct platform_device tegra_vi01_device = {
index c1b60ac..c07445e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra graphics host driver
  *
- * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2009-2013, NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -166,6 +166,9 @@ struct nvhost_device_data {
                        struct nvhost_hwctx *hwctx,
                        u32 offset,
                        u32 *value);
+
+       /* Callback when a clock is changed */
+       void (*update_clk)(struct platform_device *dev);
 };
 
 struct nvhost_devfreq_ext_stat {