summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/nvhost_acm.c
diff options
context:
space:
mode:
authorChris Johnson <cwj@nvidia.com>2011-08-12 09:04:09 +0300
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:21 -0800
commitb33dead2cc3e262000ba1915b19c27b6b0b87f41 (patch)
tree587b2f7261c8f1401e1aaa737d3f901eb8d3b49b /drivers/video/tegra/host/nvhost_acm.c
parent14dcbce77792e27a94adb242650c50809435af30 (diff)
video: tegra: nvhost: add submit timeout support
In this change, nvhost_cdma starts a timer (if a timeout is specified in the userctx), for the buffer at the head of the sync_queue that has not reached its syncpt threshold. If the timeout fires, nvhost_cdma initiates a channel / module reset. It then detects up to where in the sync_queue it stopped execution (based on the current HW syncpt value). For any remaining uncompleted buffers in the context, nvhost_cdma NOPs the entry and CPU incrs the syncpt to where it should be had it completed. If one of the sync_queue entries belongs to another context, it still does the syncpt incrs for this context, but via the PB as a GATHER opcode, At the end, CDMA is restarted, so buffers are refetched (either with NOP slots, or GATHERs to incr syncpts). This appears as though the buffer has completed (and the associated resources released). For testing, debugfs entries have been added under /d/tegra_nvhost force_timeout_val - set the timeout value, in ms force_timeout_channel - channel ID, were timeouts checks occur force_timeout_pid - process ID to set the userctx The idea is to set the timeout_val, then the timeout_channel (e.g. for 3D, the channel ID is 1) and then the process ID, gotten from running adb shell ps. Bug 625545 Original-Change-Id: I659e9255f1105f3439ce23e9169a19739b83ea52 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/42655 Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R89759c129e2db8f7dbf83a6066fc29947f95cc27
Diffstat (limited to 'drivers/video/tegra/host/nvhost_acm.c')
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c83
1 files changed, 67 insertions, 16 deletions
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 164617c7229d..9caaf4817257 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -26,6 +26,7 @@
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/device.h>
+#include <linux/delay.h>
#include <mach/powergate.h>
#include <mach/clk.h>
#include <mach/hardware.h>
@@ -34,6 +35,47 @@
#define ACM_POWERDOWN_HANDLER_DELAY_MSEC 25
#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ)
+#define POWERGATE_DELAY 10
+
+void nvhost_module_reset(struct nvhost_module *mod)
+{
+ struct nvhost_master *dev;
+ dev = container_of(mod, struct nvhost_channel, mod)->dev;
+
+ dev_dbg(&dev->pdev->dev,
+ "%s: asserting %s module reset (id %d, id2 %d)\n",
+ __func__, mod->name,
+ mod->powergate_id, mod->powergate_id2);
+
+ /* assert module and mc client reset */
+ if (mod->powergate_id != -1) {
+ tegra_powergate_mc_disable(mod->powergate_id);
+ tegra_periph_reset_assert(mod->clk[0]);
+ tegra_powergate_mc_flush(mod->powergate_id);
+ }
+ if (mod->powergate_id2 != -1) {
+ tegra_powergate_mc_disable(mod->powergate_id2);
+ tegra_periph_reset_assert(mod->clk[1]);
+ tegra_powergate_mc_flush(mod->powergate_id2);
+ }
+
+ udelay(POWERGATE_DELAY);
+
+ /* deassert reset */
+ if (mod->powergate_id != -1) {
+ tegra_powergate_mc_flush_done(mod->powergate_id);
+ tegra_periph_reset_deassert(mod->clk[0]);
+ tegra_powergate_mc_enable(mod->powergate_id);
+ }
+ if (mod->powergate_id2 != -1) {
+ tegra_powergate_mc_flush_done(mod->powergate_id2);
+ tegra_periph_reset_deassert(mod->clk[1]);
+ tegra_powergate_mc_enable(mod->powergate_id2);
+ }
+
+ dev_dbg(&dev->pdev->dev, "%s: module %s out of reset\n",
+ __func__, mod->name);
+}
void nvhost_module_busy(struct nvhost_module *mod)
{
@@ -43,13 +85,15 @@ void nvhost_module_busy(struct nvhost_module *mod)
int i = 0;
if (mod->parent)
nvhost_module_busy(mod->parent);
- if (mod->powergate_id != -1)
- tegra_unpowergate_partition(mod->powergate_id);
- if (mod->powergate_id2 != -1)
- tegra_unpowergate_partition(mod->powergate_id2);
+ if (mod->can_powergate) {
+ if (mod->powergate_id != -1)
+ tegra_unpowergate_partition(mod->powergate_id);
+ if (mod->powergate_id2 != -1)
+ tegra_unpowergate_partition(mod->powergate_id2);
+ }
while (i < mod->num_clks)
clk_enable(mod->clk[i++]);
- if (mod->func)
+ if (mod->can_powergate && mod->func)
mod->func(mod, NVHOST_POWER_ACTION_ON);
mod->powered = true;
}
@@ -68,12 +112,12 @@ static void powerdown_handler(struct work_struct *work)
mod->func(mod, NVHOST_POWER_ACTION_OFF);
for (i = 0; i < mod->num_clks; i++)
clk_disable(mod->clk[i]);
- if (mod->powergate_id != -1)
- tegra_powergate_partition(mod->powergate_id);
-
- if (mod->powergate_id2 != -1)
- tegra_powergate_partition(mod->powergate_id2);
-
+ if (mod->can_powergate) {
+ if (mod->powergate_id != -1)
+ tegra_powergate_partition(mod->powergate_id);
+ if (mod->powergate_id2 != -1)
+ tegra_powergate_partition(mod->powergate_id2);
+ }
mod->powered = false;
if (mod->parent)
nvhost_module_idle(mod->parent);
@@ -493,23 +537,30 @@ int nvhost_module_init(struct nvhost_module *mod, const char *name,
mod->num_clks = i;
mod->func = func;
mod->parent = parent;
+ mod->can_powergate = false;
mod->powered = false;
mod->powergate_id = -1;
mod->powergate_id2 = -1;
+ mod->powerdown_delay = ACM_POWERDOWN_HANDLER_DELAY_MSEC;
+
if (strcmp(name, "gr2d") == 0)
mod->powerdown_delay = 0;
- else
- mod->powerdown_delay = ACM_POWERDOWN_HANDLER_DELAY_MSEC;
-
- if (strcmp(name, "gr3d") == 0) {
+ else if (strcmp(name, "gr3d") == 0) {
+ mod->can_powergate = !_3d_powergating_disabled();
if (!scale3d.init)
scale3d_init(mod);
mod->powergate_id = TEGRA_POWERGATE_3D;
+ if (!mod->can_powergate)
+ tegra_unpowergate_partition(mod->powergate_id);
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
mod->powergate_id2 = TEGRA_POWERGATE_3D1;
+ if (!mod->can_powergate)
+ tegra_unpowergate_partition(mod->powergate_id2);
#endif
- } else if (strcmp(name, "mpe") == 0)
+ } else if (strcmp(name, "mpe") == 0) {
+ mod->can_powergate = true;
mod->powergate_id = TEGRA_POWERGATE_MPE;
+ }
if (mod->powergate_id == TEGRA_POWERGATE_MPE
&& _mpe_powergating_disabled()) {