From: Dmitry Osipenko <digetx@gmail.com> To: Thierry Reding <thierry.reding@gmail.com>, Jonathan Hunter <jonathanh@nvidia.com>, Georgi Djakov <georgi.djakov@linaro.org>, Rob Herring <robh+dt@kernel.org>, Michael Turquette <mturquette@baylibre.com>, Stephen Boyd <sboyd@kernel.org>, Peter De Schrijver <pdeschrijver@nvidia.com>, MyungJoo Ham <myungjoo.ham@samsung.com>, Kyungmin Park <kyungmin.park@samsung.com>, Chanwoo Choi <cw00.choi@samsung.com>, Mikko Perttunen <cyndis@kapsi.fi>, Viresh Kumar <vireshk@kernel.org>, Peter Geis <pgwipeout@gmail.com>, Nicolas Chauvet <kwizart@gmail.com>, Krzysztof Kozlowski <krzk@kernel.org> Cc: linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org Subject: [PATCH v11 04/10] memory: tegra124-emc: Make driver modular Date: Thu, 3 Dec 2020 22:24:33 +0300 [thread overview] Message-ID: <20201203192439.16177-5-digetx@gmail.com> (raw) In-Reply-To: <20201203192439.16177-1-digetx@gmail.com> Add modularization support to the Tegra124 EMC driver, which now can be compiled as a loadable kernel module. Note that EMC clock must be registered at clk-init time, otherwise PLLM will be disabled as unused clock at boot time if EMC driver is compiled as a module. Hence add a prepare/complete callbacks. similarly to what is done for the Tegra20/30 EMC drivers. Tested-by: Nicolas Chauvet <kwizart@gmail.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> --- drivers/clk/tegra/Kconfig | 3 ++ drivers/clk/tegra/Makefile | 2 +- drivers/clk/tegra/clk-tegra124-emc.c | 41 ++++++++++++++++++++++++---- drivers/clk/tegra/clk-tegra124.c | 26 ++++++++++++++++-- drivers/clk/tegra/clk.h | 18 ++++++++---- drivers/memory/tegra/Kconfig | 3 +- drivers/memory/tegra/tegra124-emc.c | 31 ++++++++++++++------- include/linux/clk/tegra.h | 8 ++++++ include/soc/tegra/emc.h | 16 ----------- 9 files changed, 106 insertions(+), 42 deletions(-) delete mode 100644 include/soc/tegra/emc.h diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig index deaa4605824c..90df619dc087 100644 --- a/drivers/clk/tegra/Kconfig +++ b/drivers/clk/tegra/Kconfig @@ -7,3 +7,6 @@ config TEGRA_CLK_DFLL depends on ARCH_TEGRA_124_SOC || ARCH_TEGRA_210_SOC select PM_OPP def_bool y + +config TEGRA124_CLK_EMC + bool diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index eec2313fd37e..7b1816856eb5 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra20-emc.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o obj-$(CONFIG_TEGRA_CLK_DFLL) += clk-tegra124-dfll-fcpu.o -obj-$(CONFIG_TEGRA124_EMC) += clk-tegra124-emc.o +obj-$(CONFIG_TEGRA124_CLK_EMC) += clk-tegra124-emc.o obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o obj-y += cvb.o obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c index 745f9faa98d8..bdf6f4a51617 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -11,7 +11,9 @@ #include <linux/clk-provider.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clk/tegra.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of_address.h> @@ -21,7 +23,6 @@ #include <linux/string.h> #include <soc/tegra/fuse.h> -#include <soc/tegra/emc.h> #include "clk.h" @@ -80,6 +81,9 @@ struct tegra_clk_emc { int num_timings; struct emc_timing *timings; spinlock_t *lock; + + tegra124_emc_prepare_timing_change_cb *prepare_timing_change; + tegra124_emc_complete_timing_change_cb *complete_timing_change; }; /* Common clock framework callback implementations */ @@ -176,6 +180,9 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) if (tegra->emc) return tegra->emc; + if (!tegra->prepare_timing_change || !tegra->complete_timing_change) + return NULL; + if (!tegra->emc_node) return NULL; @@ -241,7 +248,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, div = timing->parent_rate / (timing->rate / 2) - 2; - err = tegra_emc_prepare_timing_change(emc, timing->rate); + err = tegra->prepare_timing_change(emc, timing->rate); if (err) return err; @@ -259,7 +266,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, spin_unlock_irqrestore(tegra->lock, flags); - tegra_emc_complete_timing_change(emc, timing->rate); + tegra->complete_timing_change(emc, timing->rate); clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent)); clk_disable_unprepare(tegra->prev_parent); @@ -473,8 +480,8 @@ static const struct clk_ops tegra_clk_emc_ops = { .get_parent = emc_get_parent, }; -struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, - spinlock_t *lock) +struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock) { struct tegra_clk_emc *tegra; struct clk_init_data init; @@ -538,3 +545,27 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, return clk; }; + +void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb, + tegra124_emc_complete_timing_change_cb *complete_cb) +{ + struct clk *clk = __clk_lookup("emc"); + struct tegra_clk_emc *tegra; + struct clk_hw *hw; + + if (clk) { + hw = __clk_get_hw(clk); + tegra = container_of(hw, struct tegra_clk_emc, hw); + + tegra->prepare_timing_change = prep_cb; + tegra->complete_timing_change = complete_cb; + } +} +EXPORT_SYMBOL_GPL(tegra124_clk_set_emc_callbacks); + +bool tegra124_clk_emc_driver_available(struct clk_hw *hw) +{ + struct tegra_clk_emc *tegra = container_of(hw, struct tegra_clk_emc, hw); + + return tegra->prepare_timing_change && tegra->complete_timing_change; +} diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e931319dcc9d..934520aab6e3 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1500,6 +1500,26 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) writel(plld_base, clk_base + PLLD_BASE); } +static struct clk *tegra124_clk_src_onecell_get(struct of_phandle_args *clkspec, + void *data) +{ + struct clk_hw *hw; + struct clk *clk; + + clk = of_clk_src_onecell_get(clkspec, data); + if (IS_ERR(clk)) + return clk; + + hw = __clk_get_hw(clk); + + if (clkspec->args[0] == TEGRA124_CLK_EMC) { + if (!tegra124_clk_emc_driver_available(hw)) + return ERR_PTR(-EPROBE_DEFER); + } + + return clk; +} + /** * tegra124_132_clock_init_post - clock initialization postamble for T124/T132 * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -1516,10 +1536,10 @@ static void __init tegra124_132_clock_init_post(struct device_node *np) &pll_x_params); tegra_init_special_resets(1, tegra124_reset_assert, tegra124_reset_deassert); - tegra_add_of_provider(np, of_clk_src_onecell_get); + tegra_add_of_provider(np, tegra124_clk_src_onecell_get); - clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, - &emc_lock); + clks[TEGRA124_CLK_EMC] = tegra124_clk_register_emc(clk_base, np, + &emc_lock); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 6b565f6b5f66..c3e36b5dcc75 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -881,16 +881,22 @@ void tegra_super_clk_gen5_init(void __iomem *clk_base, void __iomem *pmc_base, struct tegra_clk *tegra_clks, struct tegra_clk_pll_params *pll_params); -#ifdef CONFIG_TEGRA124_EMC -struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, - spinlock_t *lock); +#ifdef CONFIG_TEGRA124_CLK_EMC +struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock); +bool tegra124_clk_emc_driver_available(struct clk_hw *emc_hw); #else -static inline struct clk *tegra_clk_register_emc(void __iomem *base, - struct device_node *np, - spinlock_t *lock) +static inline struct clk * +tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock) { return NULL; } + +static inline bool tegra124_clk_emc_driver_available(struct clk_hw *emc_hw) +{ + return false; +} #endif void tegra114_clock_tune_cpu_trimmers_high(void); diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index ca7077a06f4c..f5b451403c58 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -32,9 +32,10 @@ config TEGRA30_EMC external memory. config TEGRA124_EMC - bool "NVIDIA Tegra124 External Memory Controller driver" + tristate "NVIDIA Tegra124 External Memory Controller driver" default y depends on TEGRA_MC && ARCH_TEGRA_124_SOC + select TEGRA124_CLK_EMC help This driver is for the External Memory Controller (EMC) found on Tegra124 chips. The EMC controls the external DRAM on the board. diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index ee8ee39e98ed..edfbf6d6d357 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -9,16 +9,17 @@ #include <linux/clk-provider.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clk/tegra.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/sort.h> #include <linux/string.h> -#include <soc/tegra/emc.h> #include <soc/tegra/fuse.h> #include <soc/tegra/mc.h> @@ -562,8 +563,8 @@ static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, return timing; } -int tegra_emc_prepare_timing_change(struct tegra_emc *emc, - unsigned long rate) +static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = tegra_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; @@ -790,8 +791,8 @@ int tegra_emc_prepare_timing_change(struct tegra_emc *emc, return 0; } -void tegra_emc_complete_timing_change(struct tegra_emc *emc, - unsigned long rate) +static void tegra_emc_complete_timing_change(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = tegra_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; @@ -987,6 +988,7 @@ static const struct of_device_id tegra_emc_of_match[] = { { .compatible = "nvidia,tegra132-emc" }, {} }; +MODULE_DEVICE_TABLE(of, tegra_emc_of_match); static struct device_node * tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) @@ -1226,9 +1228,19 @@ static int tegra_emc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, emc); + tegra124_clk_set_emc_callbacks(tegra_emc_prepare_timing_change, + tegra_emc_complete_timing_change); + if (IS_ENABLED(CONFIG_DEBUG_FS)) emc_debugfs_init(&pdev->dev, emc); + /* + * Don't allow the kernel module to be unloaded. Unloading adds some + * extra complexity which doesn't really worth the effort in a case of + * this driver. + */ + try_module_get(THIS_MODULE); + return 0; }; @@ -1240,9 +1252,8 @@ static struct platform_driver tegra_emc_driver = { .suppress_bind_attrs = true, }, }; +module_platform_driver(tegra_emc_driver); -static int tegra_emc_init(void) -{ - return platform_driver_register(&tegra_emc_driver); -} -subsys_initcall(tegra_emc_init); +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); +MODULE_DESCRIPTION("NVIDIA Tegra124 EMC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 3f01d43f0598..eb016fc9cc0b 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -136,6 +136,7 @@ extern void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value); extern void tegra210_clk_emc_update_setting(u32 emc_src_value); struct clk; +struct tegra_emc; typedef long (tegra20_clk_emc_round_cb)(unsigned long rate, unsigned long min_rate, @@ -146,6 +147,13 @@ void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb, void *cb_arg); int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same); +typedef int (tegra124_emc_prepare_timing_change_cb)(struct tegra_emc *emc, + unsigned long rate); +typedef void (tegra124_emc_complete_timing_change_cb)(struct tegra_emc *emc, + unsigned long rate); +void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb, + tegra124_emc_complete_timing_change_cb *complete_cb); + struct tegra210_clk_emc_config { unsigned long rate; bool same_freq; diff --git a/include/soc/tegra/emc.h b/include/soc/tegra/emc.h deleted file mode 100644 index 05199a97ccf4..000000000000 --- a/include/soc/tegra/emc.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2014 NVIDIA Corporation. All rights reserved. - */ - -#ifndef __SOC_TEGRA_EMC_H__ -#define __SOC_TEGRA_EMC_H__ - -struct tegra_emc; - -int tegra_emc_prepare_timing_change(struct tegra_emc *emc, - unsigned long rate); -void tegra_emc_complete_timing_change(struct tegra_emc *emc, - unsigned long rate); - -#endif /* __SOC_TEGRA_EMC_H__ */ -- 2.29.2
WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Osipenko <digetx@gmail.com> To: Thierry Reding <thierry.reding@gmail.com>, Jonathan Hunter <jonathanh@nvidia.com>, Georgi Djakov <georgi.djakov@linaro.org>, Rob Herring <robh+dt@kernel.org>, Michael Turquette <mturquette@baylibre.com>, Stephen Boyd <sboyd@kernel.org>, Peter De Schrijver <pdeschrijver@nvidia.com>, MyungJoo Ham <myungjoo.ham@samsung.com>, Kyungmin Park <kyungmin.park@samsung.com>, Chanwoo Choi <cw00.choi@samsung.com>, Mikko Perttunen <cyndis@kapsi.fi>, Viresh Kumar <vireshk@kernel.org>, Peter Geis <pgwipeout@gmail.com>, Nicolas Chauvet <kwizart@gmail.com>, Krzysztof Kozlowski <krzk@kernel.org> Cc: linux-tegra@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org Subject: [PATCH v11 04/10] memory: tegra124-emc: Make driver modular Date: Thu, 3 Dec 2020 22:24:33 +0300 [thread overview] Message-ID: <20201203192439.16177-5-digetx@gmail.com> (raw) In-Reply-To: <20201203192439.16177-1-digetx@gmail.com> Add modularization support to the Tegra124 EMC driver, which now can be compiled as a loadable kernel module. Note that EMC clock must be registered at clk-init time, otherwise PLLM will be disabled as unused clock at boot time if EMC driver is compiled as a module. Hence add a prepare/complete callbacks. similarly to what is done for the Tegra20/30 EMC drivers. Tested-by: Nicolas Chauvet <kwizart@gmail.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> --- drivers/clk/tegra/Kconfig | 3 ++ drivers/clk/tegra/Makefile | 2 +- drivers/clk/tegra/clk-tegra124-emc.c | 41 ++++++++++++++++++++++++---- drivers/clk/tegra/clk-tegra124.c | 26 ++++++++++++++++-- drivers/clk/tegra/clk.h | 18 ++++++++---- drivers/memory/tegra/Kconfig | 3 +- drivers/memory/tegra/tegra124-emc.c | 31 ++++++++++++++------- include/linux/clk/tegra.h | 8 ++++++ include/soc/tegra/emc.h | 16 ----------- 9 files changed, 106 insertions(+), 42 deletions(-) delete mode 100644 include/soc/tegra/emc.h diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig index deaa4605824c..90df619dc087 100644 --- a/drivers/clk/tegra/Kconfig +++ b/drivers/clk/tegra/Kconfig @@ -7,3 +7,6 @@ config TEGRA_CLK_DFLL depends on ARCH_TEGRA_124_SOC || ARCH_TEGRA_210_SOC select PM_OPP def_bool y + +config TEGRA124_CLK_EMC + bool diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index eec2313fd37e..7b1816856eb5 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra20-emc.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o obj-$(CONFIG_TEGRA_CLK_DFLL) += clk-tegra124-dfll-fcpu.o -obj-$(CONFIG_TEGRA124_EMC) += clk-tegra124-emc.o +obj-$(CONFIG_TEGRA124_CLK_EMC) += clk-tegra124-emc.o obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o obj-y += cvb.o obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c index 745f9faa98d8..bdf6f4a51617 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -11,7 +11,9 @@ #include <linux/clk-provider.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clk/tegra.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of_address.h> @@ -21,7 +23,6 @@ #include <linux/string.h> #include <soc/tegra/fuse.h> -#include <soc/tegra/emc.h> #include "clk.h" @@ -80,6 +81,9 @@ struct tegra_clk_emc { int num_timings; struct emc_timing *timings; spinlock_t *lock; + + tegra124_emc_prepare_timing_change_cb *prepare_timing_change; + tegra124_emc_complete_timing_change_cb *complete_timing_change; }; /* Common clock framework callback implementations */ @@ -176,6 +180,9 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) if (tegra->emc) return tegra->emc; + if (!tegra->prepare_timing_change || !tegra->complete_timing_change) + return NULL; + if (!tegra->emc_node) return NULL; @@ -241,7 +248,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, div = timing->parent_rate / (timing->rate / 2) - 2; - err = tegra_emc_prepare_timing_change(emc, timing->rate); + err = tegra->prepare_timing_change(emc, timing->rate); if (err) return err; @@ -259,7 +266,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra, spin_unlock_irqrestore(tegra->lock, flags); - tegra_emc_complete_timing_change(emc, timing->rate); + tegra->complete_timing_change(emc, timing->rate); clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent)); clk_disable_unprepare(tegra->prev_parent); @@ -473,8 +480,8 @@ static const struct clk_ops tegra_clk_emc_ops = { .get_parent = emc_get_parent, }; -struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, - spinlock_t *lock) +struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock) { struct tegra_clk_emc *tegra; struct clk_init_data init; @@ -538,3 +545,27 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, return clk; }; + +void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb, + tegra124_emc_complete_timing_change_cb *complete_cb) +{ + struct clk *clk = __clk_lookup("emc"); + struct tegra_clk_emc *tegra; + struct clk_hw *hw; + + if (clk) { + hw = __clk_get_hw(clk); + tegra = container_of(hw, struct tegra_clk_emc, hw); + + tegra->prepare_timing_change = prep_cb; + tegra->complete_timing_change = complete_cb; + } +} +EXPORT_SYMBOL_GPL(tegra124_clk_set_emc_callbacks); + +bool tegra124_clk_emc_driver_available(struct clk_hw *hw) +{ + struct tegra_clk_emc *tegra = container_of(hw, struct tegra_clk_emc, hw); + + return tegra->prepare_timing_change && tegra->complete_timing_change; +} diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e931319dcc9d..934520aab6e3 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1500,6 +1500,26 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) writel(plld_base, clk_base + PLLD_BASE); } +static struct clk *tegra124_clk_src_onecell_get(struct of_phandle_args *clkspec, + void *data) +{ + struct clk_hw *hw; + struct clk *clk; + + clk = of_clk_src_onecell_get(clkspec, data); + if (IS_ERR(clk)) + return clk; + + hw = __clk_get_hw(clk); + + if (clkspec->args[0] == TEGRA124_CLK_EMC) { + if (!tegra124_clk_emc_driver_available(hw)) + return ERR_PTR(-EPROBE_DEFER); + } + + return clk; +} + /** * tegra124_132_clock_init_post - clock initialization postamble for T124/T132 * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -1516,10 +1536,10 @@ static void __init tegra124_132_clock_init_post(struct device_node *np) &pll_x_params); tegra_init_special_resets(1, tegra124_reset_assert, tegra124_reset_deassert); - tegra_add_of_provider(np, of_clk_src_onecell_get); + tegra_add_of_provider(np, tegra124_clk_src_onecell_get); - clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, - &emc_lock); + clks[TEGRA124_CLK_EMC] = tegra124_clk_register_emc(clk_base, np, + &emc_lock); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 6b565f6b5f66..c3e36b5dcc75 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -881,16 +881,22 @@ void tegra_super_clk_gen5_init(void __iomem *clk_base, void __iomem *pmc_base, struct tegra_clk *tegra_clks, struct tegra_clk_pll_params *pll_params); -#ifdef CONFIG_TEGRA124_EMC -struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, - spinlock_t *lock); +#ifdef CONFIG_TEGRA124_CLK_EMC +struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock); +bool tegra124_clk_emc_driver_available(struct clk_hw *emc_hw); #else -static inline struct clk *tegra_clk_register_emc(void __iomem *base, - struct device_node *np, - spinlock_t *lock) +static inline struct clk * +tegra124_clk_register_emc(void __iomem *base, struct device_node *np, + spinlock_t *lock) { return NULL; } + +static inline bool tegra124_clk_emc_driver_available(struct clk_hw *emc_hw) +{ + return false; +} #endif void tegra114_clock_tune_cpu_trimmers_high(void); diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index ca7077a06f4c..f5b451403c58 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -32,9 +32,10 @@ config TEGRA30_EMC external memory. config TEGRA124_EMC - bool "NVIDIA Tegra124 External Memory Controller driver" + tristate "NVIDIA Tegra124 External Memory Controller driver" default y depends on TEGRA_MC && ARCH_TEGRA_124_SOC + select TEGRA124_CLK_EMC help This driver is for the External Memory Controller (EMC) found on Tegra124 chips. The EMC controls the external DRAM on the board. diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index ee8ee39e98ed..edfbf6d6d357 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -9,16 +9,17 @@ #include <linux/clk-provider.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clk/tegra.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/sort.h> #include <linux/string.h> -#include <soc/tegra/emc.h> #include <soc/tegra/fuse.h> #include <soc/tegra/mc.h> @@ -562,8 +563,8 @@ static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, return timing; } -int tegra_emc_prepare_timing_change(struct tegra_emc *emc, - unsigned long rate) +static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = tegra_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; @@ -790,8 +791,8 @@ int tegra_emc_prepare_timing_change(struct tegra_emc *emc, return 0; } -void tegra_emc_complete_timing_change(struct tegra_emc *emc, - unsigned long rate) +static void tegra_emc_complete_timing_change(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = tegra_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; @@ -987,6 +988,7 @@ static const struct of_device_id tegra_emc_of_match[] = { { .compatible = "nvidia,tegra132-emc" }, {} }; +MODULE_DEVICE_TABLE(of, tegra_emc_of_match); static struct device_node * tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) @@ -1226,9 +1228,19 @@ static int tegra_emc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, emc); + tegra124_clk_set_emc_callbacks(tegra_emc_prepare_timing_change, + tegra_emc_complete_timing_change); + if (IS_ENABLED(CONFIG_DEBUG_FS)) emc_debugfs_init(&pdev->dev, emc); + /* + * Don't allow the kernel module to be unloaded. Unloading adds some + * extra complexity which doesn't really worth the effort in a case of + * this driver. + */ + try_module_get(THIS_MODULE); + return 0; }; @@ -1240,9 +1252,8 @@ static struct platform_driver tegra_emc_driver = { .suppress_bind_attrs = true, }, }; +module_platform_driver(tegra_emc_driver); -static int tegra_emc_init(void) -{ - return platform_driver_register(&tegra_emc_driver); -} -subsys_initcall(tegra_emc_init); +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); +MODULE_DESCRIPTION("NVIDIA Tegra124 EMC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 3f01d43f0598..eb016fc9cc0b 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -136,6 +136,7 @@ extern void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value); extern void tegra210_clk_emc_update_setting(u32 emc_src_value); struct clk; +struct tegra_emc; typedef long (tegra20_clk_emc_round_cb)(unsigned long rate, unsigned long min_rate, @@ -146,6 +147,13 @@ void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb, void *cb_arg); int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same); +typedef int (tegra124_emc_prepare_timing_change_cb)(struct tegra_emc *emc, + unsigned long rate); +typedef void (tegra124_emc_complete_timing_change_cb)(struct tegra_emc *emc, + unsigned long rate); +void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb, + tegra124_emc_complete_timing_change_cb *complete_cb); + struct tegra210_clk_emc_config { unsigned long rate; bool same_freq; diff --git a/include/soc/tegra/emc.h b/include/soc/tegra/emc.h deleted file mode 100644 index 05199a97ccf4..000000000000 --- a/include/soc/tegra/emc.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2014 NVIDIA Corporation. All rights reserved. - */ - -#ifndef __SOC_TEGRA_EMC_H__ -#define __SOC_TEGRA_EMC_H__ - -struct tegra_emc; - -int tegra_emc_prepare_timing_change(struct tegra_emc *emc, - unsigned long rate); -void tegra_emc_complete_timing_change(struct tegra_emc *emc, - unsigned long rate); - -#endif /* __SOC_TEGRA_EMC_H__ */ -- 2.29.2 _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2020-12-03 19:25 UTC|newest] Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-12-03 19:24 [PATCH v11 00/10] Introduce memory interconnect for NVIDIA Tegra SoCs Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 01/10] dt-bindings: memory: tegra20: emc: Document opp-supported-hw property Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-04 15:46 ` Thierry Reding 2020-12-04 15:46 ` Thierry Reding 2020-12-09 20:17 ` Rob Herring 2020-12-09 20:17 ` Rob Herring 2020-12-03 19:24 ` [PATCH v11 02/10] memory: tegra20: Support hardware versioning and clean up OPP table initialization Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-04 16:20 ` Thierry Reding 2020-12-04 16:20 ` Thierry Reding 2020-12-03 19:24 ` [PATCH v11 03/10] memory: tegra30: Support interconnect framework Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-04 16:27 ` Thierry Reding 2020-12-04 16:27 ` Thierry Reding 2020-12-03 19:24 ` Dmitry Osipenko [this message] 2020-12-03 19:24 ` [PATCH v11 04/10] memory: tegra124-emc: Make driver modular Dmitry Osipenko 2020-12-04 16:41 ` Thierry Reding 2020-12-04 16:41 ` Thierry Reding 2020-12-05 19:52 ` Dmitry Osipenko 2020-12-05 19:52 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 05/10] memory: tegra124-emc: Continue probing if timings are missing in device-tree Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 06/10] memory: tegra124: Support interconnect framework Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 07/10] drm/tegra: dc: Support memory bandwidth management Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 08/10] drm/tegra: dc: Extend debug stats with total number of events Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 09/10] PM / devfreq: tegra30: Support interconnect and OPPs from device-tree Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-07 1:32 ` Chanwoo Choi 2020-12-07 1:32 ` Chanwoo Choi 2020-12-07 22:11 ` Dmitry Osipenko 2020-12-07 22:11 ` Dmitry Osipenko 2020-12-03 19:24 ` [PATCH v11 10/10] PM / devfreq: tegra30: Separate configurations per-SoC generation Dmitry Osipenko 2020-12-03 19:24 ` Dmitry Osipenko 2020-12-07 1:33 ` Chanwoo Choi 2020-12-07 1:33 ` Chanwoo Choi 2020-12-05 14:09 ` [PATCH v11 00/10] Introduce memory interconnect for NVIDIA Tegra SoCs Krzysztof Kozlowski 2020-12-05 14:09 ` Krzysztof Kozlowski 2020-12-07 22:11 ` Dmitry Osipenko 2020-12-07 22:11 ` Dmitry Osipenko
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20201203192439.16177-5-digetx@gmail.com \ --to=digetx@gmail.com \ --cc=cw00.choi@samsung.com \ --cc=cyndis@kapsi.fi \ --cc=devicetree@vger.kernel.org \ --cc=dri-devel@lists.freedesktop.org \ --cc=georgi.djakov@linaro.org \ --cc=jonathanh@nvidia.com \ --cc=krzk@kernel.org \ --cc=kwizart@gmail.com \ --cc=kyungmin.park@samsung.com \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-pm@vger.kernel.org \ --cc=linux-tegra@vger.kernel.org \ --cc=mturquette@baylibre.com \ --cc=myungjoo.ham@samsung.com \ --cc=pdeschrijver@nvidia.com \ --cc=pgwipeout@gmail.com \ --cc=robh+dt@kernel.org \ --cc=sboyd@kernel.org \ --cc=thierry.reding@gmail.com \ --cc=vireshk@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.