From 1043a4036b2e8ca7dc12da3a7018fb3271699c1b Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 16 Sep 2013 16:04:06 +0200 Subject: WIP: move clock and regulator handling into a3xx_gpu Signed-off-by: Lucas Stach --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 67 ++++++++--- drivers/gpu/drm/msm/adreno/a3xx_gpu.h | 17 +++ drivers/gpu/drm/msm/adreno/a3xx_pm.c | 203 +++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_gpu.c | 219 +--------------------------------- drivers/gpu/drm/msm/msm_gpu.h | 9 -- 6 files changed, 273 insertions(+), 243 deletions(-) create mode 100644 drivers/gpu/drm/msm/adreno/a3xx_pm.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index e24eb5ed1952..cea5b55eebcf 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -7,6 +7,7 @@ msm-y := \ adreno/adreno_gpu.o \ adreno/adreno_ringbuffer.o \ adreno/a3xx_gpu.o \ + adreno/a3xx_pm.o \ hdmi/hdmi.o \ hdmi/hdmi_bridge.o \ hdmi/hdmi_connector.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index a31360a7ec46..c97f8f41b159 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -254,9 +254,12 @@ static int a3xx_hw_init(struct adreno_gpu *gpu) static void a3xx_destroy(struct adreno_gpu *gpu) { + struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(gpu); DBG("%s", adreno_get_name(gpu)); + a3xx_bs_fini(a3xx_gpu); + adreno_gpu_cleanup(gpu); put_device(&gpu->pdev->dev); kfree(gpu); @@ -365,8 +368,8 @@ static void a3xx_show(struct adreno_gpu *gpu, struct seq_file *m) static const struct adreno_gpu_funcs funcs = { .get_param = adreno_get_param, .hw_init = a3xx_hw_init, - .pm_suspend = msm_gpu_pm_suspend, - .pm_resume = msm_gpu_pm_resume, + .pm_suspend = a3xx_gpu_pm_suspend, + .pm_resume = a3xx_gpu_pm_resume, .recover = adreno_recover, .last_fence = adreno_last_fence, .submit = adreno_submit, @@ -379,14 +382,18 @@ static const struct adreno_gpu_funcs funcs = { #endif }; +static const char *clk_names[] = { + "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", +}; + struct msm_gpu *a3xx_gpu_init(struct drm_device *dev, struct adreno_gem *gem, struct workqueue_struct *wq, int reglog) { - struct adreno_gpu *adreno_gpu = NULL; + struct a3xx_gpu *a3xx_gpu = NULL; struct msm_gpu *gpu; struct platform_device *pdev = a3xx_pdev; struct adreno_platform_config *config; - int ret; + int i, ret; if (!pdev) { dev_err(dev->dev, "no a3xx device\n"); @@ -395,35 +402,63 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev, struct adreno_gem *gem, config = pdev->dev.platform_data; - adreno_gpu = kzalloc(sizeof(*adreno_gpu), GFP_KERNEL); - if (!adreno_gpu) { + a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL); + if (!a3xx_gpu) { ret = -ENOMEM; goto fail; } - gpu = &adreno_gpu->base; + gpu = &a3xx_gpu->base.base; get_device(&pdev->dev); - adreno_gpu->pdev = pdev; + a3xx_gpu->base.pdev = pdev; - gpu->fast_rate = config->fast_rate; - gpu->slow_rate = config->slow_rate; - gpu->bus_freq = config->bus_freq; + a3xx_gpu->fast_rate = config->fast_rate; + a3xx_gpu->slow_rate = config->slow_rate; + a3xx_gpu->bus_freq = config->bus_freq; DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u", - gpu->fast_rate, gpu->slow_rate, gpu->bus_freq); + a3xx_gpu->fast_rate, a3xx_gpu->slow_rate, a3xx_gpu->bus_freq); + + /* Acquire clocks: */ + BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(a3xx_gpu->grp_clks)); + + for (i = 0; i < ARRAY_SIZE(clk_names); i++) { + a3xx_gpu->grp_clks[i] = devm_clk_get(&pdev->dev, clk_names[i]); + DBG("grp_clks[%s]: %p", clk_names[i], a3xx_gpu->grp_clks[i]); + if (IS_ERR(a3xx_gpu->grp_clks[i])) + a3xx_gpu->grp_clks[i] = NULL; + } + + a3xx_gpu->ebi1_clk = devm_clk_get(&pdev->dev, "bus_clk"); + DBG("ebi1_clk: %p", a3xx_gpu->ebi1_clk); + if (IS_ERR(a3xx_gpu->ebi1_clk)) + a3xx_gpu->ebi1_clk = NULL; + + /* Acquire regulators: */ + a3xx_gpu->gpu_reg = devm_regulator_get(&pdev->dev, "vdd"); + DBG("gpu_reg: %p", a3xx_gpu->gpu_reg); + if (IS_ERR(a3xx_gpu->gpu_reg)) + a3xx_gpu->gpu_reg = NULL; + + a3xx_gpu->gpu_cx = devm_regulator_get(&pdev->dev, "vddcx"); + DBG("gpu_cx: %p", a3xx_gpu->gpu_cx); + if (IS_ERR(a3xx_gpu->gpu_cx)) + a3xx_gpu->gpu_cx = NULL; + + a3xx_bs_init(a3xx_gpu, pdev); adreno_reglog = reglog; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, + ret = adreno_gpu_init(dev, pdev, &a3xx_gpu->base, &funcs, gem, wq, config->rev); if (ret) goto fail; - return &adreno_gpu->base; + return &a3xx_gpu->base.base; fail: - if (adreno_gpu) - a3xx_destroy(adreno_gpu); + if (a3xx_gpu) + a3xx_destroy(&a3xx_gpu->base); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h index 00384e9a439c..0070c54ff2d6 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h @@ -21,4 +21,21 @@ #include "adreno_gpu.h" #include "a3xx.xml.h" +struct a3xx_gpu { + struct adreno_gpu base; + + /* Power Control: */ + struct regulator *gpu_reg, *gpu_cx; + struct clk *ebi1_clk, *grp_clks[5]; + uint32_t fast_rate, slow_rate, bus_freq; + uint32_t bsc; +}; +#define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base) + +int a3xx_gpu_pm_suspend(struct adreno_gpu *gpu); +int a3xx_gpu_pm_resume(struct adreno_gpu *gpu); + +void a3xx_bs_init(struct a3xx_gpu *gpu, struct platform_device *pdev); +void a3xx_bs_fini(struct a3xx_gpu *gpu); + #endif /* __A3XX_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_pm.c b/drivers/gpu/drm/msm/adreno/a3xx_pm.c new file mode 100644 index 000000000000..f11ef116bcea --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a3xx_pm.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 Pengutronix + * Author: Lucas Stach + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include + +/* + * Power Management: + */ + +#ifdef CONFIG_MSM_BUS_SCALING +#include +#include +void a3xx_bs_init(struct a3xx_gpu *gpu, struct platform_device *pdev) +{ + struct drm_device *dev = gpu->dev; + struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; + + if (!pdev) { + dev_err(dev->dev, "could not find dtv pdata\n"); + return; + } + + if (pdata->bus_scale_table) { + gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table); + DBG("bus scale client: %08x", gpu->bsc); + } +} + +void a3xx_bs_fini(struct a3xx_gpu *gpu) +{ + if (gpu->bsc) { + msm_bus_scale_unregister_client(gpu->bsc); + gpu->bsc = 0; + } +} + +static void a3xx_bs_set(struct a3xx_gpu *gpu, int idx) +{ + if (gpu->bsc) { + DBG("set bus scaling: %d", idx); + msm_bus_scale_client_update_request(gpu->bsc, idx); + } +} +#else +void a3xx_bs_init(struct a3xx_gpu *gpu, struct platform_device *pdev) {} +void a3xx_bs_fini(struct a3xx_gpu *gpu) {} +static void a3xx_bs_set(struct a3xx_gpu *gpu, int idx) {} +#endif + +static int enable_pwrrail(struct a3xx_gpu *gpu) +{ + struct drm_device *dev = gpu->base.drm; + int ret = 0; + + if (gpu->gpu_reg) { + ret = regulator_enable(gpu->gpu_reg); + if (ret) { + dev_err(dev->dev, "failed to enable 'gpu_reg': %d\n", ret); + return ret; + } + } + + if (gpu->gpu_cx) { + ret = regulator_enable(gpu->gpu_cx); + if (ret) { + dev_err(dev->dev, "failed to enable 'gpu_cx': %d\n", ret); + return ret; + } + } + + return 0; +} + +static int disable_pwrrail(struct a3xx_gpu *gpu) +{ + if (gpu->gpu_cx) + regulator_disable(gpu->gpu_cx); + if (gpu->gpu_reg) + regulator_disable(gpu->gpu_reg); + return 0; +} + +static int enable_clk(struct a3xx_gpu *gpu) +{ + struct clk *rate_clk = NULL; + int i; + + /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ + for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { + if (gpu->grp_clks[i]) { + clk_prepare(gpu->grp_clks[i]); + rate_clk = gpu->grp_clks[i]; + } + } + + if (rate_clk && gpu->fast_rate) + clk_set_rate(rate_clk, gpu->fast_rate); + + for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) + if (gpu->grp_clks[i]) + clk_enable(gpu->grp_clks[i]); + + return 0; +} + +static int disable_clk(struct a3xx_gpu *gpu) +{ + struct clk *rate_clk = NULL; + int i; + + /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ + for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { + if (gpu->grp_clks[i]) { + clk_disable(gpu->grp_clks[i]); + rate_clk = gpu->grp_clks[i]; + } + } + + if (rate_clk && gpu->slow_rate) + clk_set_rate(rate_clk, gpu->slow_rate); + + for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) + if (gpu->grp_clks[i]) + clk_unprepare(gpu->grp_clks[i]); + + return 0; +} + +static int enable_axi(struct a3xx_gpu *gpu) +{ + if (gpu->ebi1_clk) + clk_prepare_enable(gpu->ebi1_clk); + if (gpu->bus_freq) + a3xx_bs_set(gpu, gpu->bus_freq); + return 0; +} + +static int disable_axi(struct a3xx_gpu *gpu) +{ + if (gpu->ebi1_clk) + clk_disable_unprepare(gpu->ebi1_clk); + if (gpu->bus_freq) + a3xx_bs_set(gpu, 0); + return 0; +} + +int a3xx_gpu_pm_resume(struct adreno_gpu *gpu) +{ + struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(gpu); + int ret; + + DBG("%s", adreno_get_name(gpu)); + + ret = enable_pwrrail(a3xx_gpu); + if (ret) + return ret; + + ret = enable_clk(a3xx_gpu); + if (ret) + return ret; + + ret = enable_axi(a3xx_gpu); + if (ret) + return ret; + + return 0; +} + +int a3xx_gpu_pm_suspend(struct adreno_gpu *gpu) +{ + struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(gpu); + int ret; + + DBG("%s", adreno_get_name(gpu)); + + ret = disable_axi(a3xx_gpu); + if (ret) + return ret; + + ret = disable_clk(a3xx_gpu); + if (ret) + return ret; + + ret = disable_pwrrail(a3xx_gpu); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index a319dc1f302b..f8152472ab91 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -19,189 +19,6 @@ #include "msm_gem.h" #include "adreno/adreno_gpu.h" -/* - * Power Management: - */ - -#ifdef CONFIG_MSM_BUS_SCALING -#include -#include -static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) -{ - struct drm_device *dev = gpu->dev; - struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; - - if (!pdev) { - dev_err(dev->dev, "could not find dtv pdata\n"); - return; - } - - if (pdata->bus_scale_table) { - gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table); - DBG("bus scale client: %08x", gpu->bsc); - } -} - -static void bs_fini(struct msm_gpu *gpu) -{ - if (gpu->bsc) { - msm_bus_scale_unregister_client(gpu->bsc); - gpu->bsc = 0; - } -} - -static void bs_set(struct msm_gpu *gpu, int idx) -{ - if (gpu->bsc) { - DBG("set bus scaling: %d", idx); - msm_bus_scale_client_update_request(gpu->bsc, idx); - } -} -#else -static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) {} -static void bs_fini(struct msm_gpu *gpu) {} -static void bs_set(struct msm_gpu *gpu, int idx) {} -#endif - -static int enable_pwrrail(struct msm_gpu *gpu) -{ - struct drm_device *dev = gpu->dev; - int ret = 0; - - if (gpu->gpu_reg) { - ret = regulator_enable(gpu->gpu_reg); - if (ret) { - dev_err(dev->dev, "failed to enable 'gpu_reg': %d\n", ret); - return ret; - } - } - - if (gpu->gpu_cx) { - ret = regulator_enable(gpu->gpu_cx); - if (ret) { - dev_err(dev->dev, "failed to enable 'gpu_cx': %d\n", ret); - return ret; - } - } - - return 0; -} - -static int disable_pwrrail(struct msm_gpu *gpu) -{ - if (gpu->gpu_cx) - regulator_disable(gpu->gpu_cx); - if (gpu->gpu_reg) - regulator_disable(gpu->gpu_reg); - return 0; -} - -static int enable_clk(struct msm_gpu *gpu) -{ - struct clk *rate_clk = NULL; - int i; - - /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { - if (gpu->grp_clks[i]) { - clk_prepare(gpu->grp_clks[i]); - rate_clk = gpu->grp_clks[i]; - } - } - - if (rate_clk && gpu->fast_rate) - clk_set_rate(rate_clk, gpu->fast_rate); - - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) - if (gpu->grp_clks[i]) - clk_enable(gpu->grp_clks[i]); - - return 0; -} - -static int disable_clk(struct msm_gpu *gpu) -{ - struct clk *rate_clk = NULL; - int i; - - /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */ - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) { - if (gpu->grp_clks[i]) { - clk_disable(gpu->grp_clks[i]); - rate_clk = gpu->grp_clks[i]; - } - } - - if (rate_clk && gpu->slow_rate) - clk_set_rate(rate_clk, gpu->slow_rate); - - for (i = ARRAY_SIZE(gpu->grp_clks) - 1; i > 0; i--) - if (gpu->grp_clks[i]) - clk_unprepare(gpu->grp_clks[i]); - - return 0; -} - -static int enable_axi(struct msm_gpu *gpu) -{ - if (gpu->ebi1_clk) - clk_prepare_enable(gpu->ebi1_clk); - if (gpu->bus_freq) - bs_set(gpu, gpu->bus_freq); - return 0; -} - -static int disable_axi(struct msm_gpu *gpu) -{ - if (gpu->ebi1_clk) - clk_disable_unprepare(gpu->ebi1_clk); - if (gpu->bus_freq) - bs_set(gpu, 0); - return 0; -} - -int msm_gpu_pm_resume(struct adreno_gpu *gpu) -{ - int ret; - - DBG("%s", adreno_get_name(gpu)); - - ret = enable_pwrrail(&gpu->base); - if (ret) - return ret; - - ret = enable_clk(&gpu->base); - if (ret) - return ret; - - ret = enable_axi(&gpu->base); - if (ret) - return ret; - - return 0; -} - -int msm_gpu_pm_suspend(struct adreno_gpu *gpu) -{ - int ret; - - DBG("%s", adreno_get_name(gpu)); - - ret = disable_axi(&gpu->base); - if (ret) - return ret; - - ret = disable_clk(&gpu->base); - if (ret) - return ret; - - ret = disable_pwrrail(&gpu->base); - if (ret) - return ret; - - return 0; -} - /* * Cmdstream submission/retirement: */ @@ -285,15 +102,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, * Init/Cleanup: */ -static const char *clk_names[] = { - "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", -}; - int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct adreno_gpu_funcs *funcs, const char *ioname, const char *irqname, int ringsz) { - int i, ret; + int ret; gpu->dev = drm; gpu->funcs = funcs; @@ -301,32 +114,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, INIT_LIST_HEAD(&gpu->active_list); INIT_WORK(&gpu->retire_work, retire_worker); - BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks)); - - /* Acquire clocks: */ - for (i = 0; i < ARRAY_SIZE(clk_names); i++) { - gpu->grp_clks[i] = devm_clk_get(&pdev->dev, clk_names[i]); - DBG("grp_clks[%s]: %p", clk_names[i], gpu->grp_clks[i]); - if (IS_ERR(gpu->grp_clks[i])) - gpu->grp_clks[i] = NULL; - } - - gpu->ebi1_clk = devm_clk_get(&pdev->dev, "bus_clk"); - DBG("ebi1_clk: %p", gpu->ebi1_clk); - if (IS_ERR(gpu->ebi1_clk)) - gpu->ebi1_clk = NULL; - - /* Acquire regulators: */ - gpu->gpu_reg = devm_regulator_get(&pdev->dev, "vdd"); - DBG("gpu_reg: %p", gpu->gpu_reg); - if (IS_ERR(gpu->gpu_reg)) - gpu->gpu_reg = NULL; - - gpu->gpu_cx = devm_regulator_get(&pdev->dev, "vddcx"); - DBG("gpu_cx: %p", gpu->gpu_cx); - if (IS_ERR(gpu->gpu_cx)) - gpu->gpu_cx = NULL; - /* Setup IOMMU.. eventually we will (I think) do this once per context * and have separate page tables per context. For now, to keep things * simple and to get something working, just use a single address space: @@ -339,8 +126,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, } gpu->id = msm_register_iommu(drm, gpu->iommu); - bs_init(gpu, pdev); - return 0; fail: @@ -353,8 +138,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) WARN_ON(!list_empty(&gpu->active_list)); - bs_fini(gpu); - if (gpu->iommu) iommu_domain_free(gpu->iommu); } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 4d5ccba14853..4487e18ec526 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -51,17 +51,8 @@ struct msm_gpu { struct iommu_domain *iommu; int id; - - /* Power Control: */ - struct regulator *gpu_reg, *gpu_cx; - struct clk *ebi1_clk, *grp_clks[5]; - uint32_t fast_rate, slow_rate, bus_freq; - uint32_t bsc; }; -int msm_gpu_pm_suspend(struct adreno_gpu *gpu); -int msm_gpu_pm_resume(struct adreno_gpu *gpu); - void msm_gpu_retire(struct msm_gpu *gpu); struct msm_gem_submit; int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, -- cgit v1.2.3