diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2014-04-11 14:42:29 +0530 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2014-04-13 20:09:36 -0700 |
commit | 974da74574f3d36f8957db6353ee8a419c4e1670 (patch) | |
tree | 1008fa38c906843d49e1347598c91cbfb52e39e4 /drivers/platform | |
parent | dc7cbe176efe641ff27c4ef63568816d8b45d732 (diff) |
platform: tegra: move pm_domain to drivers
Change-Id: I30baee4084399b8078232f31296c4d891a903d47
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/395123
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/Kconfig | 4 | ||||
-rw-r--r-- | drivers/platform/tegra/Kconfig | 23 | ||||
-rw-r--r-- | drivers/platform/tegra/Makefile | 6 | ||||
-rw-r--r-- | drivers/platform/tegra/pm_domains.c | 272 |
4 files changed, 300 insertions, 5 deletions
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616aeaa966..6d36c5e4f3ef 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -4,4 +4,6 @@ endif if GOLDFISH source "drivers/platform/goldfish/Kconfig" endif - +if ARCH_TEGRA +source "drivers/platform/tegra/Kconfig" +endif diff --git a/drivers/platform/tegra/Kconfig b/drivers/platform/tegra/Kconfig new file mode 100644 index 000000000000..25916fd9c38e --- /dev/null +++ b/drivers/platform/tegra/Kconfig @@ -0,0 +1,23 @@ + +# Copyright (c) 2012-2014, 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, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope 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 <http://www.gnu.org/licenses/>. + +comment "NVIDIA Tegra options" + +config TEGRA_MC_DOMAINS + bool "Enable Tegra MC PM domain" + depends on PM_GENERIC_DOMAINS + default n + help + When enabled, clock gates MC when it's not needed. diff --git a/drivers/platform/tegra/Makefile b/drivers/platform/tegra/Makefile index c82cc3403b4b..918e2af246b6 100644 --- a/drivers/platform/tegra/Makefile +++ b/drivers/platform/tegra/Makefile @@ -16,6 +16,8 @@ obj-y += mc/ obj-$(CONFIG_PM_SLEEP) += pm-irq.o obj-y += pmc.o +obj-$(CONFIG_TEGRA_MC_DOMAINS) += pm_domains.o + ifneq ($(CONFIG_ARM64),) ccflags-y += -I$(srctree)/arch/arm/mach-tegra/include \ @@ -48,8 +50,6 @@ obj-y += powergate-ops-txx.o obj-y += powergate-ops-t1xx.o obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += powergate-t12x.o -obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o - obj-y += dvfs.o obj-$(CONFIG_ARCH_TEGRA_13x_SOC) += tegra13_dvfs.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o @@ -77,6 +77,8 @@ obj-y += tegra_emc.o obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += tegra12_emc.o obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += tegra_emc_dt_parse.o +obj-$(CONFIG_TEGRA_MC_DOMAINS) += pm_domains.o + obj-y += flowctrl.o obj-y += reset.o obj-$(CONFIG_DEBUG_ICEDCC) += sysfs-dcc.o diff --git a/drivers/platform/tegra/pm_domains.c b/drivers/platform/tegra/pm_domains.c index 19d305704a7d..d98999562b95 100644 --- a/drivers/platform/tegra/pm_domains.c +++ b/drivers/platform/tegra/pm_domains.c @@ -1,2 +1,270 @@ -/* Automatically generated file; DO NOT EDIT. */ -#include "../../../arch/arm/mach-tegra/pm_domains.c" +/* + * drivers/platform/tegra/pm_domains.c + * + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. + * + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/pm_domain.h> +#include <linux/tegra_pm_domains.h> + +#ifdef CONFIG_TEGRA_MC_DOMAINS +#define TEGRA_PD_DEV_CALLBACK(callback, dev) \ +({ \ + int (*__routine)(struct device *__d); \ + int __ret = 0; \ + \ + if (dev->type && dev->type->pm) \ + __routine = dev->type->pm->callback; \ + else if (dev->class && dev->class->pm) \ + __routine = dev->class->pm->callback; \ + else if (dev->bus && dev->bus->pm) \ + __routine = dev->bus->pm->callback; \ + else \ + __routine = NULL; \ + \ + if (!__routine && dev->driver && dev->driver->pm) \ + __routine = dev->driver->pm->callback; \ + \ + if (__routine) \ + __ret = __routine(dev); \ + __ret; \ +}) + +struct domain_client { + const char *name; + struct generic_pm_domain *domain; +}; + +#ifdef CONFIG_PM_SLEEP + +static int tegra_pd_suspend_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(suspend, dev); +} + +static int tegra_pd_suspend_late(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(suspend_late, dev); +} + +static int tegra_pd_resume_early(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(resume_early, dev); +} + +static int tegra_pd_resume_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(resume, dev); +} + +static int tegra_pd_freeze_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(freeze, dev); +} + +static int tegra_pd_freeze_late(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(freeze_late, dev); +} + +static int tegra_pd_thaw_early(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(thaw_early, dev); +} + +static int tegra_pd_thaw_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(thaw, dev); +} +#else /* !CONFIG_PM_SLEEP */ + +#define tegra_pd_suspend_dev NULL +#define tegra_pd_suspend_late NULL +#define tegra_pd_resume_early NULL +#define tegra_pd_resume_dev NULL +#define tegra_pd_freeze_dev NULL +#define tegra_pd_freeze_late NULL +#define tegra_pd_thaw_early NULL +#define tegra_pd_thaw_dev NULL + +#endif /* !CONFIG_PM_SLEEP */ + +static bool tegra_pd_active_wakeup(struct device *dev) +{ + return device_may_wakeup(dev); +} + +static int tegra_pd_save_dev(struct device *dev) +{ + return 0; +} + +static int tegra_pd_restore_dev(struct device *dev) +{ + return 0; +} + +static int tegra_pd_stop_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(runtime_suspend, dev); +} + +static int tegra_pd_start_dev(struct device *dev) +{ + return TEGRA_PD_DEV_CALLBACK(runtime_resume, dev); +} + +struct gpd_dev_ops tegra_pd_ops = { + .active_wakeup = tegra_pd_active_wakeup, + .save_state = tegra_pd_save_dev, + .restore_state = tegra_pd_restore_dev, + .stop = tegra_pd_stop_dev, + .start = tegra_pd_start_dev, + .suspend = tegra_pd_suspend_dev, + .suspend_late = tegra_pd_suspend_late, + .resume_early = tegra_pd_resume_early, + .resume = tegra_pd_resume_dev, + .freeze = tegra_pd_freeze_dev, + .freeze_late = tegra_pd_freeze_late, + .thaw_early = tegra_pd_thaw_early, + .thaw = tegra_pd_thaw_dev, +}; + +static int tegra_mc_clk_power_off(struct generic_pm_domain *genpd) +{ + struct tegra_pm_domain *pd = to_tegra_pd(genpd); + + if (!pd) + return -EINVAL; + + if (IS_ERR_OR_NULL(pd->clk)) + return 0; + + clk_disable_unprepare(pd->clk); + + return 0; +} + +static int tegra_mc_clk_power_on(struct generic_pm_domain *genpd) +{ + struct tegra_pm_domain *pd = to_tegra_pd(genpd); + + if (!pd) + return -EINVAL; + + if (IS_ERR_OR_NULL(pd->clk)) + return 0; + + clk_prepare_enable(pd->clk); + + return 0; +} + +static struct tegra_pm_domain tegra_nvavp = { + .gpd.name = "tegra_nvavp", +}; + +static struct tegra_pm_domain tegra_mc_clk = { + .gpd.name = "tegra_mc_clk", + .gpd.power_off = tegra_mc_clk_power_off, + .gpd.power_on = tegra_mc_clk_power_on, +}; + +static struct domain_client client_list[] = { + { .name = "tegradc", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra30-hda", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-apbdma", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-otg", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-ehci", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-xhci", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-host1x", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra_nvavp", .domain = &tegra_mc_clk.gpd }, + { .name = "nvavp", .domain = &tegra_nvavp.gpd }, + { .name = "sdhci-tegra", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra11-se", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra12-se", .domain = &tegra_mc_clk.gpd }, + { .name = "tegra-pcie", .domain = &tegra_mc_clk.gpd }, + { .name = "gpu", .domain = &tegra_mc_clk.gpd }, + {}, +}; + +static int __init tegra_init_pm_domain(void) +{ + pm_genpd_init(&tegra_mc_clk.gpd, &simple_qos_governor, false); + + pm_genpd_init(&tegra_nvavp.gpd, &simple_qos_governor, false); + tegra_pd_add_sd(&tegra_nvavp.gpd); + + return 0; +} +core_initcall(tegra_init_pm_domain); + +static struct generic_pm_domain *tegra_pd_get_domain(const char *client) +{ + const char *s; + struct domain_client *clients = client_list; + + while ((s = clients->name) != NULL) { + if (!strncmp(s, client, strlen(s))) + return clients->domain; + + clients++; + } + return NULL; +} + +void tegra_pd_add_device(struct device *dev) +{ + struct generic_pm_domain *master = tegra_pd_get_domain(dev_name(dev)); + + if (!master) + return; + + device_set_wakeup_capable(dev, 1); + pm_genpd_add_device(master, dev); + pm_genpd_dev_need_save(dev, false); + pm_genpd_add_callbacks(dev, &tegra_pd_ops, NULL); +} +EXPORT_SYMBOL(tegra_pd_add_device); + +void tegra_pd_remove_device(struct device *dev) +{ + struct generic_pm_domain *genpd = dev_to_genpd(dev); + + if (!IS_ERR_OR_NULL(genpd)) + pm_genpd_remove_device(genpd, dev); +} +EXPORT_SYMBOL(tegra_pd_remove_device); + +void tegra_pd_add_sd(struct generic_pm_domain *sd) +{ + struct generic_pm_domain *master = tegra_pd_get_domain(sd->name); + + if (!master) + return; + + pm_genpd_add_subdomain(master, sd); +} +EXPORT_SYMBOL(tegra_pd_add_sd); +#else +struct tegra_pm_domain tegra_mc_clk; +EXPORT_SYMBOL(tegra_mc_clk); +struct tegra_pm_domain tegra_mc_chain_a; +EXPORT_SYMBOL(tegra_mc_chain_a); +struct tegra_pm_domain tegra_mc_chain_b; +EXPORT_SYMBOL(tegra_mc_chain_b); +#endif |