Commit 281462e5 authored by Dmitry Osipenko's avatar Dmitry Osipenko Committed by Krzysztof Kozlowski
Browse files

memory: tegra124-emc: Make driver modular



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: default avatarNicolas Chauvet <kwizart@gmail.com>
Signed-off-by: default avatarDmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20201228154920.18846-2-digetx@gmail.com


Signed-off-by: default avatarKrzysztof Kozlowski <krzk@kernel.org>
parent 5c8fe583
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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
+36 −5
Original line number Diff line number Diff line
@@ -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,7 +480,7 @@ 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,
struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np,
				      spinlock_t *lock)
{
	struct tegra_clk_emc *tegra;
@@ -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;
}
+23 −3
Original line number Diff line number Diff line
@@ -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,9 +1536,9 @@ 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,
	clks[TEGRA124_CLK_EMC] = tegra124_clk_register_emc(clk_base, np,
							   &emc_lock);

	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+12 −6
Original line number Diff line number Diff line
@@ -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,
#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,
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);
Loading