From ae1f9efe299b2f24680b04e429c76dec3240b60d Mon Sep 17 00:00:00 2001 From: Simone Willett Date: Wed, 15 Feb 2012 14:22:37 -0800 Subject: Revert "video: tegra: host: use runtime pm for clock management" This reverts commit 961c60fe7213d92793d6072abc16f58721a33fed Change-Id: I8ef0fbaee30e94c78b8df609f729953fee6d1583 Reviewed-on: http://git-master/r/84135 Reviewed-by: Terje Bergstrom Reviewed-by: Mayuresh Kulkarni Tested-by: Lokesh Pathak Reviewed-by: Lokesh Pathak --- drivers/video/tegra/host/nvhost_acm.c | 228 ++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 108 deletions(-) (limited to 'drivers/video/tegra/host/nvhost_acm.c') diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c index 351b70e0b6fb..a2386a257c8f 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -29,14 +29,13 @@ #include #include #include -#include #include #include #include -#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ) -#define POWERGATE_DELAY 10 -#define MAX_DEVID_LENGTH 16 +#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ) +#define POWERGATE_DELAY 10 +#define MAX_DEVID_LENGTH 16 DEFINE_MUTEX(client_list_lock); @@ -99,113 +98,139 @@ void nvhost_module_reset(struct nvhost_device *dev) __func__, dev->name); } +static void to_state_clockgated_locked(struct nvhost_device *dev) +{ + if (dev->powerstate == NVHOST_POWER_STATE_RUNNING) { + int i; + for (i = 0; i < dev->num_clks; i++) + clk_disable(dev->clk[i]); + if (dev->dev.parent) + nvhost_module_idle(to_nvhost_device(dev->dev.parent)); + } else if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED + && dev->can_powergate) { + do_unpowergate_locked(dev->powergate_ids[0]); + do_unpowergate_locked(dev->powergate_ids[1]); + } + dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED; +} + +static void to_state_running_locked(struct nvhost_device *dev) +{ + int prev_state = dev->powerstate; + if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED) + to_state_clockgated_locked(dev); + if (dev->powerstate == NVHOST_POWER_STATE_CLOCKGATED) { + int i; + + if (dev->dev.parent) + nvhost_module_busy(to_nvhost_device(dev->dev.parent)); + + for (i = 0; i < dev->num_clks; i++) { + int err = clk_enable(dev->clk[i]); + BUG_ON(err); + } + + if (prev_state == NVHOST_POWER_STATE_POWERGATED + && dev->finalize_poweron) + dev->finalize_poweron(dev); + } + dev->powerstate = NVHOST_POWER_STATE_RUNNING; +} + /* This gets called from powergate_handler() and from module suspend. * Module suspend is done for all modules, runtime power gating only * for modules with can_powergate set. */ -static int to_state_powergated_locked(struct nvhost_device *dev, - bool system_suspend) +static int to_state_powergated_locked(struct nvhost_device *dev) { - int err = 0, i = 0; - - if (dev->prepare_poweroff && dev->powered) { - struct nvhost_device *device; - struct device *parent = dev->dev.parent; - if (parent) - device = to_nvhost_device(parent); - - if (system_suspend) { - /* enable parent clock - * host1x does not have parent */ - if (parent) { - for (i = 0; i < device->num_clks; i++) - clk_enable(device->clk[i]); - } - - /* enable module clock */ - for (i = 0; i < dev->num_clks; i++) - clk_enable(dev->clk[i]); - } else - pm_runtime_get_sync(&dev->dev); + int err = 0; + if (dev->prepare_poweroff + && dev->powerstate != NVHOST_POWER_STATE_POWERGATED) { + /* Clock needs to be on in prepare_poweroff */ + to_state_running_locked(dev); err = dev->prepare_poweroff(dev); if (err) return err; - - if (system_suspend) { - /* disable module clock */ - for (i = 0; i < dev->num_clks; i++) - clk_disable(dev->clk[i]); - - /* disable parent clock - * host1x does not have parent */ - if (parent) { - for (i = 0; i < device->num_clks; i++) - clk_disable(device->clk[i]); - } - } else - pm_runtime_put_sync_suspend(&dev->dev); } + if (dev->powerstate == NVHOST_POWER_STATE_RUNNING) + to_state_clockgated_locked(dev); + if (dev->can_powergate) { do_powergate_locked(dev->powergate_ids[0]); do_powergate_locked(dev->powergate_ids[1]); - dev->powered = false; } + dev->powerstate = NVHOST_POWER_STATE_POWERGATED; return 0; } +static void schedule_powergating_locked(struct nvhost_device *dev) +{ + if (dev->can_powergate) + schedule_delayed_work(&dev->powerstate_down, + msecs_to_jiffies(dev->powergate_delay)); +} + +static void schedule_clockgating_locked(struct nvhost_device *dev) +{ + schedule_delayed_work(&dev->powerstate_down, + msecs_to_jiffies(dev->clockgate_delay)); +} + void nvhost_module_busy(struct nvhost_device *dev) { if (dev->busy) dev->busy(dev); mutex_lock(&dev->lock); + cancel_delayed_work(&dev->powerstate_down); - if (dev->can_powergate) { - /* cancel power-gate handler */ - cancel_delayed_work_sync(&dev->powerstate_down); - - /* unpowergate the module if it was power gated */ - if (!dev->powered) { - do_unpowergate_locked(dev->powergate_ids[0]); - do_unpowergate_locked(dev->powergate_ids[1]); - dev->powered = true; - } - } - - pm_runtime_get_sync(&dev->dev); - + dev->refcount++; + if (dev->refcount > 0 && !nvhost_module_powered(dev)) + to_state_running_locked(dev); mutex_unlock(&dev->lock); } -static bool is_module_idle(struct nvhost_device *dev, bool system_suspend) +static void powerstate_down_handler(struct work_struct *work) { - /* for system suspend, pm core holds a reference on runtime pm. - * this is for kernels >= 3.x, it is not there for kernels < 3.x. - * for more details refer the LKML thread: - * https://lkml.org/lkml/2011/6/25/93 - * https://lkml.org/lkml/2011/6/25/94 - * https://lkml.org/lkml/2011/6/25/95 */ - if (system_suspend) - return atomic_read(&dev->dev.power.usage_count) == 1; - else - return atomic_read(&dev->dev.power.usage_count) == 0; + struct nvhost_device *dev; + + dev = container_of(to_delayed_work(work), + struct nvhost_device, + powerstate_down); + + mutex_lock(&dev->lock); + if (dev->refcount == 0) { + switch (dev->powerstate) { + case NVHOST_POWER_STATE_RUNNING: + to_state_clockgated_locked(dev); + schedule_powergating_locked(dev); + break; + case NVHOST_POWER_STATE_CLOCKGATED: + if (to_state_powergated_locked(dev)) + schedule_powergating_locked(dev); + break; + default: + break; + } + } + mutex_unlock(&dev->lock); } + void nvhost_module_idle_mult(struct nvhost_device *dev, int refs) { bool kick = false; - int i; mutex_lock(&dev->lock); - for (i = 0; i < refs; i++) - pm_runtime_put_sync(&dev->dev); - - if (is_module_idle(dev, false)) + dev->refcount -= refs; + if (dev->refcount == 0) { + if (nvhost_module_powered(dev)) + schedule_clockgating_locked(dev); kick = true; - + } mutex_unlock(&dev->lock); if (kick) { @@ -216,19 +241,6 @@ void nvhost_module_idle_mult(struct nvhost_device *dev, int refs) } } -static void powerstate_down_handler(struct work_struct *work) -{ - struct nvhost_device *dev; - - dev = container_of(to_delayed_work(work), struct nvhost_device, - powerstate_down); - - mutex_lock(&dev->lock); - if (dev->can_powergate) - to_state_powergated_locked(dev, false); - mutex_unlock(&dev->lock); -} - int nvhost_module_get_rate(struct nvhost_device *dev, unsigned long *rate, int index) { @@ -243,6 +255,7 @@ int nvhost_module_get_rate(struct nvhost_device *dev, unsigned long *rate, *rate = clk_get_rate(c); nvhost_module_idle(dev); return 0; + } static int nvhost_module_update_rate(struct nvhost_device *dev, int index) @@ -280,6 +293,7 @@ int nvhost_module_set_rate(struct nvhost_device *dev, void *priv, ret = nvhost_module_update_rate(dev, index); mutex_unlock(&client_list_lock); return ret; + } int nvhost_module_add_client(struct nvhost_device *dev, void *priv) @@ -352,25 +366,31 @@ int nvhost_module_init(struct nvhost_device *dev) mutex_init(&dev->lock); init_waitqueue_head(&dev->idle_wq); + INIT_DELAYED_WORK(&dev->powerstate_down, powerstate_down_handler); /* power gate units that we can power gate */ if (dev->can_powergate) { do_powergate_locked(dev->powergate_ids[0]); do_powergate_locked(dev->powergate_ids[1]); - INIT_DELAYED_WORK(&dev->powerstate_down, powerstate_down_handler); - dev->powered = false; + dev->powerstate = NVHOST_POWER_STATE_POWERGATED; } else { do_unpowergate_locked(dev->powergate_ids[0]); do_unpowergate_locked(dev->powergate_ids[1]); - dev->powered = true; + dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED; } - /* enable runtime pm */ - nvhost_module_resume(dev); - return 0; } +static int is_module_idle(struct nvhost_device *dev) +{ + int count; + mutex_lock(&dev->lock); + count = dev->refcount; + mutex_unlock(&dev->lock); + return (count == 0); +} + static void debug_not_idle(struct nvhost_master *host) { int i; @@ -381,8 +401,8 @@ static void debug_not_idle(struct nvhost_master *host) mutex_lock(&dev->lock); if (dev->name) dev_warn(&host->pdev->dev, - "tegra_grhost: %s: refcnt %d\n", dev->name, - atomic_read(&dev->dev.power.usage_count)); + "tegra_grhost: %s: refcnt %d\n", + dev->name, dev->refcount); mutex_unlock(&dev->lock); } @@ -404,10 +424,10 @@ int nvhost_module_suspend(struct nvhost_device *dev, bool system_suspend) int ret; struct nvhost_master *host = nvhost_get_host(dev); - if (system_suspend && !is_module_idle(dev, system_suspend)) + if (system_suspend && !is_module_idle(dev)) debug_not_idle(host); - ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev, system_suspend), + ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev), ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT); if (ret == 0) { dev_info(&dev->dev, "%s prevented suspend\n", @@ -416,20 +436,16 @@ int nvhost_module_suspend(struct nvhost_device *dev, bool system_suspend) } if (system_suspend) - dev_info(&dev->dev, "tegra_grhost: entered idle\n"); + dev_dbg(&dev->dev, "tegra_grhost: entered idle\n"); mutex_lock(&dev->lock); - if (dev->can_powergate) - cancel_delayed_work_sync(&dev->powerstate_down); - to_state_powergated_locked(dev, system_suspend); + cancel_delayed_work(&dev->powerstate_down); + to_state_powergated_locked(dev); mutex_unlock(&dev->lock); if (dev->suspend) dev->suspend(dev); - if (system_suspend) - pm_runtime_set_suspended(&dev->dev); - return 0; } @@ -443,10 +459,6 @@ void nvhost_module_deinit(struct nvhost_device *dev) nvhost_module_suspend(dev, false); for (i = 0; i < dev->num_clks; i++) clk_put(dev->clk[i]); + dev->powerstate = NVHOST_POWER_STATE_DEINIT; } -void nvhost_module_resume(struct nvhost_device *dev) -{ - pm_runtime_set_autosuspend_delay(&dev->dev, dev->clockgate_delay); - pm_runtime_use_autosuspend(&dev->dev); -} -- cgit v1.2.3