On Thu, May 02, 2019 at 02:38:15AM +0300, Dmitry Osipenko wrote:
> 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
> ---
> MAINTAINERS | 8 ++
> drivers/devfreq/Kconfig | 10 ++
> drivers/devfreq/Makefile | 1 +
> drivers/devfreq/tegra20-devfreq.c | 212 ++
> 4 files changed, 231 insertions(+)
> create mode 100644 drivers/devfreq/tegra20-devfreq.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 98edc38bfd7b..e7e434f74038 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10098,6 +10098,14 @@ F: include/linux/memblock.h
> F: mm/memblock.c
> F: Documentation/core-api/boot-time-mm.rst
>
> +MEMORY FREQUENCY SCALING DRIVER FOR NVIDIA TEGRA20
> +M: Dmitry Osipenko
> +L: linux...@vger.kernel.org
> +L: linux-te...@vger.kernel.org
> +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq.git
> +S: Maintained
> +F: drivers/devfreq/tegra20-devfreq.c
> +
> MEMORY MANAGEMENT
> L: linux...@kvack.org
> W: http://www.linux-mm.org
> diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
> index a6bba6e1e7d9..1530dbefa31f 100644
> --- a/drivers/devfreq/Kconfig
> +++ b/drivers/devfreq/Kconfig
> @@ -100,6 +100,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
Again, I'm not sure the COMPILE_TEST will work here unless you add a few
more dependencies.
Thierry
> + 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 ..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_COUNT0xb8
> +
> +#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 re