From d0ce4807d0f190be8fd4221bb48d543bf20473f6 Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Mon, 28 Jul 2014 16:21:10 +0530 Subject: gpu: nvgpu: poweron host1x explicitly Currently gk20a gets reference of host1x via phandle in Device Tree. But runtime PM does not seem to be handling power dependencies too well in this case and hence some times host1x is off when we need it. To fix this, exlicitly power on host1x while powering gpu up. Do this via "busy" and "idle" callbacks from gk20a_platform Bug 1534272 Bug 200022536 Change-Id: Ia562ee19722cfc8edc5626a5a058ab8edfe3d206 Signed-off-by: Deepak Nibade --- drivers/gpu/nvgpu/gk20a/gk20a.c | 20 +++++++++++++++++- drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 6 ++++++ drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | 28 ++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 355b2039..fa6e0cce 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -1604,16 +1604,30 @@ int gk20a_busy(struct platform_device *pdev) { int ret = 0; struct gk20a *g = get_gk20a(pdev); + struct gk20a_platform *platform = gk20a_get_platform(pdev); down_read(&g->busy_lock); #ifdef CONFIG_PM_RUNTIME + if (platform->busy) { + ret = platform->busy(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "%s: failed to poweron platform dependency\n", + __func__); + goto fail; + } + } + ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) + if (ret < 0) { pm_runtime_put_noidle(&pdev->dev); + if (platform->idle) + platform->idle(pdev); + } #endif gk20a_scale_notify_busy(pdev); +fail: up_read(&g->busy_lock); return ret < 0 ? ret : 0; @@ -1621,11 +1635,15 @@ int gk20a_busy(struct platform_device *pdev) void gk20a_idle(struct platform_device *pdev) { + struct gk20a_platform *platform = gk20a_get_platform(pdev); #ifdef CONFIG_PM_RUNTIME if (atomic_read(&pdev->dev.power.usage_count) == 1) gk20a_scale_notify_idle(pdev); pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_sync_autosuspend(&pdev->dev); + + if (platform->idle) + platform->idle(pdev); #else gk20a_scale_notify_idle(pdev); #endif diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h index 76e9cf6c..6dd0c0db 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h @@ -94,6 +94,12 @@ struct gk20a_platform { */ int (*late_probe)(struct platform_device *dev); + /* Poweron platform dependencies */ + int (*busy)(struct platform_device *dev); + + /* Powerdown platform dependencies */ + void (*idle)(struct platform_device *dev); + /* This function is called to allocate secure memory (memory that the * CPU cannot see). The function should fill the context buffer * descriptor (especially fields destroy, sgt, size). diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c index 148496dd..f234fdec 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c @@ -449,6 +449,25 @@ static void gk20a_tegra_debug_dump(struct platform_device *pdev) nvhost_debug_dump_device(g->host1x_dev); } +static int gk20a_tegra_busy(struct platform_device *dev) +{ + struct gk20a_platform *platform = gk20a_get_platform(dev); + struct gk20a *g = platform->g; + + if (g->host1x_dev) + return nvhost_module_busy_ext(g->host1x_dev); + return 0; +} + +static void gk20a_tegra_idle(struct platform_device *dev) +{ + struct gk20a_platform *platform = gk20a_get_platform(dev); + struct gk20a *g = platform->g; + + if (g->host1x_dev) + nvhost_module_idle_ext(g->host1x_dev); +} + static int gk20a_tegra_probe(struct platform_device *dev) { struct gk20a_platform *platform = gk20a_get_platform(dev); @@ -554,6 +573,9 @@ struct gk20a_platform t132_gk20a_tegra_platform = { .unrailgate = gk20a_tegra_unrailgate, .is_railgated = gk20a_tegra_is_railgated, + .busy = gk20a_tegra_busy, + .idle = gk20a_tegra_idle, + /* frequency scaling configuration */ .prescale = gk20a_tegra_prescale, .postscale = gk20a_tegra_postscale, @@ -587,6 +609,9 @@ struct gk20a_platform gk20a_tegra_platform = { .unrailgate = gk20a_tegra_unrailgate, .is_railgated = gk20a_tegra_is_railgated, + .busy = gk20a_tegra_busy, + .idle = gk20a_tegra_idle, + /* frequency scaling configuration */ .prescale = gk20a_tegra_prescale, .postscale = gk20a_tegra_postscale, @@ -618,6 +643,9 @@ struct gk20a_platform gm20b_tegra_platform = { /* power management callbacks */ .suspend = gk20a_tegra_suspend, + .busy = gk20a_tegra_busy, + .idle = gk20a_tegra_idle, + /* frequency scaling configuration */ .prescale = gk20a_tegra_prescale, .postscale = gk20a_tegra_postscale, -- cgit v1.2.2