From 386789ebbdd3a204ebe16b7a6277f7a45823549d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 2 May 2019 02:38:09 +0300 Subject: PM / devfreq: tegra: Mark ACTMON's governor as immutable The ACTMON's governor supports only the Tegra's devfreq device and there is no need to use any other governor, hence let's mark Tegra governor as immutable to permanently stick it with Tegra's devfreq device. Reviewed-by: Chanwoo Choi Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/devfreq/Kconfig') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index ba98a4e3ad33..7dd46d44579d 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -95,7 +95,6 @@ config ARM_EXYNOS_BUS_DEVFREQ config ARM_TEGRA_DEVFREQ tristate "Tegra DEVFREQ Driver" depends on ARCH_TEGRA_124_SOC - select DEVFREQ_GOV_SIMPLE_ONDEMAND select PM_OPP help This adds the DEVFREQ driver for the Tegra family of SoCs. -- cgit v1.2.3 From 1ac347488529939d74f5e2d17948825b5bc6f5e6 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 2 May 2019 02:38:12 +0300 Subject: PM / devfreq: tegra: Support Tegra30 The devfreq driver can be used on Tegra30 without any code change and it works perfectly fine, the default Tegra124 parameters are good enough for Tegra30. Signed-off-by: Dmitry Osipenko Reviewed-by: Chanwoo Choi [Modified by MyungJoo to depends on Tegra30/114/124/210 only] Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 6 ++++-- drivers/devfreq/tegra-devfreq.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/devfreq/Kconfig') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 7dd46d44579d..8f3f0ed17d85 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -93,8 +93,10 @@ config ARM_EXYNOS_BUS_DEVFREQ This does not yet operate with optimal voltages. config ARM_TEGRA_DEVFREQ - tristate "Tegra DEVFREQ Driver" - depends on ARCH_TEGRA_124_SOC + tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver" + depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \ + ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \ + ARCH_TEGRA_210_SOC select PM_OPP help This adds the DEVFREQ driver for the Tegra family of SoCs. diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c index 5cddf2199c4e..a6ba75f4106d 100644 --- a/drivers/devfreq/tegra-devfreq.c +++ b/drivers/devfreq/tegra-devfreq.c @@ -726,6 +726,7 @@ static int tegra_devfreq_remove(struct platform_device *pdev) } static const struct of_device_id tegra_devfreq_of_match[] = { + { .compatible = "nvidia,tegra30-actmon" }, { .compatible = "nvidia,tegra124-actmon" }, { }, }; -- cgit v1.2.3 From 35f8dbc727212bc5a49b90961d98f9ef596e2072 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 2 May 2019 02:38:13 +0300 Subject: PM / devfreq: tegra: Enable COMPILE_TEST for the driver The driver's compilation doesn't have any specific dependencies, hence the COMPILE_TEST option can be supported in Kconfig. Signed-off-by: Dmitry Osipenko Reviewed-by: Chanwoo Choi Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/devfreq/Kconfig') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 8f3f0ed17d85..1091119c1d0a 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -96,7 +96,8 @@ config ARM_TEGRA_DEVFREQ tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver" depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \ ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \ - ARCH_TEGRA_210_SOC + ARCH_TEGRA_210_SOC || \ + COMPILE_TEST select PM_OPP help This adds the DEVFREQ driver for the Tegra family of SoCs. -- cgit v1.2.3 From d196175ed8f45248b54bf5c2e7c05ac0e1e97d70 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 2 May 2019 02:38:15 +0300 Subject: PM / devfreq: Introduce driver for NVIDIA Tegra20 Add devfreq driver for NVIDIA Tegra20 SoC's. The driver periodically reads out Memory Controller counters and adjusts memory frequency based on the memory clients activity. Reviewed-by: Chanwoo Choi Signed-off-by: Dmitry Osipenko [Removed MAINTAINERS updates by MyungJoo so that it can be sent elsewhere.] Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 10 ++ drivers/devfreq/Makefile | 1 + drivers/devfreq/tegra20-devfreq.c | 212 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 drivers/devfreq/tegra20-devfreq.c (limited to 'drivers/devfreq/Kconfig') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 1091119c1d0a..f3b242987fd9 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -104,6 +104,16 @@ config ARM_TEGRA_DEVFREQ It reads ACTMON counters of memory controllers and adjusts the operating frequencies and voltages with OPP support. +config ARM_TEGRA20_DEVFREQ + tristate "NVIDIA Tegra20 DEVFREQ Driver" + depends on (TEGRA_MC && TEGRA20_EMC) || COMPILE_TEST + select DEVFREQ_GOV_SIMPLE_ONDEMAND + select PM_OPP + help + This adds the DEVFREQ driver for the Tegra20 family of SoCs. + It reads Memory Controller counters and adjusts the operating + frequencies and voltages with OPP support. + config ARM_RK3399_DMC_DEVFREQ tristate "ARM RK3399 DMC DEVFREQ Driver" depends on ARCH_ROCKCHIP diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 47e5aeeebfd1..338ae8440db6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o +obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/tegra20-devfreq.c b/drivers/devfreq/tegra20-devfreq.c new file mode 100644 index 000000000000..ff82bac9ee4e --- /dev/null +++ b/drivers/devfreq/tegra20-devfreq.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVIDIA Tegra20 devfreq driver + * + * Copyright (C) 2019 GRATE-DRIVER project + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "governor.h" + +#define MC_STAT_CONTROL 0x90 +#define MC_STAT_EMC_CLOCK_LIMIT 0xa0 +#define MC_STAT_EMC_CLOCKS 0xa4 +#define MC_STAT_EMC_CONTROL 0xa8 +#define MC_STAT_EMC_COUNT 0xb8 + +#define EMC_GATHER_CLEAR (1 << 8) +#define EMC_GATHER_ENABLE (3 << 8) + +struct tegra_devfreq { + struct devfreq *devfreq; + struct clk *emc_clock; + void __iomem *regs; +}; + +static int tegra_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct tegra_devfreq *tegra = dev_get_drvdata(dev); + struct devfreq *devfreq = tegra->devfreq; + struct dev_pm_opp *opp; + unsigned long rate; + int err; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + err = clk_set_min_rate(tegra->emc_clock, rate); + if (err) + return err; + + err = clk_set_rate(tegra->emc_clock, 0); + if (err) + goto restore_min_rate; + + return 0; + +restore_min_rate: + clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq); + + return err; +} + +static int tegra_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *stat) +{ + struct tegra_devfreq *tegra = dev_get_drvdata(dev); + + /* + * EMC_COUNT returns number of memory events, that number is lower + * than the number of clocks. Conversion ratio of 1/8 results in a + * bit higher bandwidth than actually needed, it is good enough for + * the time being because drivers don't support requesting minimum + * needed memory bandwidth yet. + * + * TODO: adjust the ratio value once relevant drivers will support + * memory bandwidth management. + */ + stat->busy_time = readl_relaxed(tegra->regs + MC_STAT_EMC_COUNT); + stat->total_time = readl_relaxed(tegra->regs + MC_STAT_EMC_CLOCKS) / 8; + stat->current_frequency = clk_get_rate(tegra->emc_clock); + + writel_relaxed(EMC_GATHER_CLEAR, tegra->regs + MC_STAT_CONTROL); + writel_relaxed(EMC_GATHER_ENABLE, tegra->regs + MC_STAT_CONTROL); + + return 0; +} + +static struct devfreq_dev_profile tegra_devfreq_profile = { + .polling_ms = 500, + .target = tegra_devfreq_target, + .get_dev_status = tegra_devfreq_get_dev_status, +}; + +static struct tegra_mc *tegra_get_memory_controller(void) +{ + struct platform_device *pdev; + struct device_node *np; + struct tegra_mc *mc; + + np = of_find_compatible_node(NULL, NULL, "nvidia,tegra20-mc-gart"); + if (!np) + return ERR_PTR(-ENOENT); + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return ERR_PTR(-ENODEV); + + mc = platform_get_drvdata(pdev); + if (!mc) + return ERR_PTR(-EPROBE_DEFER); + + return mc; +} + +static int tegra_devfreq_probe(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra; + struct tegra_mc *mc; + unsigned long max_rate; + unsigned long rate; + int err; + + mc = tegra_get_memory_controller(); + if (IS_ERR(mc)) { + err = PTR_ERR(mc); + dev_err(&pdev->dev, "failed to get memory controller: %d\n", + err); + return err; + } + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + /* EMC is a system-critical clock that is always enabled */ + tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(tegra->emc_clock)) { + err = PTR_ERR(tegra->emc_clock); + dev_err(&pdev->dev, "failed to get emc clock: %d\n", err); + return err; + } + + tegra->regs = mc->regs; + + max_rate = clk_round_rate(tegra->emc_clock, ULONG_MAX); + + for (rate = 0; rate <= max_rate; rate++) { + rate = clk_round_rate(tegra->emc_clock, rate); + + err = dev_pm_opp_add(&pdev->dev, rate, 0); + if (err) { + dev_err(&pdev->dev, "failed to add opp: %d\n", err); + goto remove_opps; + } + } + + /* + * Reset statistic gathers state, select global bandwidth for the + * statistics collection mode and set clocks counter saturation + * limit to maximum. + */ + writel_relaxed(0x00000000, tegra->regs + MC_STAT_CONTROL); + writel_relaxed(0x00000000, tegra->regs + MC_STAT_EMC_CONTROL); + writel_relaxed(0xffffffff, tegra->regs + MC_STAT_EMC_CLOCK_LIMIT); + + platform_set_drvdata(pdev, tegra); + + tegra->devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, + DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); + if (IS_ERR(tegra->devfreq)) { + err = PTR_ERR(tegra->devfreq); + goto remove_opps; + } + + return 0; + +remove_opps: + dev_pm_opp_remove_all_dynamic(&pdev->dev); + + return err; +} + +static int tegra_devfreq_remove(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra = platform_get_drvdata(pdev); + + devfreq_remove_device(tegra->devfreq); + dev_pm_opp_remove_all_dynamic(&pdev->dev); + + return 0; +} + +static struct platform_driver tegra_devfreq_driver = { + .probe = tegra_devfreq_probe, + .remove = tegra_devfreq_remove, + .driver = { + .name = "tegra20-devfreq", + }, +}; +module_platform_driver(tegra_devfreq_driver); + +MODULE_ALIAS("platform:tegra20-devfreq"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_DESCRIPTION("NVIDIA Tegra20 devfreq driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 23ca7d2503d895c80b65e4321fc6cc678c7642f2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 28 Jun 2019 12:32:20 +0200 Subject: PM / devfreq: tegra20: add COMMON_CLK dependency Compile-testing the new driver on platforms without CONFIG_COMMON_CLK leads to a link error: drivers/devfreq/tegra20-devfreq.o: In function `tegra_devfreq_target': tegra20-devfreq.c:(.text+0x288): undefined reference to `clk_set_min_rate' Add a dependency on COMMON_CLK to avoid this. Fixes: 1d39ee8dad6d ("PM / devfreq: Introduce driver for NVIDIA Tegra20") Signed-off-by: Arnd Bergmann Reviewed-by: Dmitry Osipenko Reviewed-by: Chanwoo Choi Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/devfreq/Kconfig') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index f3b242987fd9..defe1d438710 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -107,6 +107,7 @@ config ARM_TEGRA_DEVFREQ config ARM_TEGRA20_DEVFREQ tristate "NVIDIA Tegra20 DEVFREQ Driver" depends on (TEGRA_MC && TEGRA20_EMC) || COMPILE_TEST + depends on COMMON_CLK select DEVFREQ_GOV_SIMPLE_ONDEMAND select PM_OPP help -- cgit v1.2.3