Skip to content

Commit

Permalink
memory: tegra124-emc: Make driver modular
Browse files Browse the repository at this point in the history
This patch adds modularization support to the Tegra124 EMC driver. Driver
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 this patch
adds prepare/complete callbacks, similar to what is done for Tegra20/30
EMC drivers.

Tested-by: Nicolas Chauvet <kwizart@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
  • Loading branch information
digetx authored and intel-lab-lkp committed Oct 25, 2020
1 parent 12cff92 commit d100fc4
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 48 deletions.
2 changes: 1 addition & 1 deletion drivers/clk/tegra/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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_ARCH_TEGRA_124_SOC) += 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
Expand Down
41 changes: 36 additions & 5 deletions drivers/clk/tegra/clk-tegra124-emc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -21,7 +23,6 @@
#include <linux/string.h>

#include <soc/tegra/fuse.h>
#include <soc/tegra/emc.h>

#include "clk.h"

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
27 changes: 24 additions & 3 deletions drivers/clk/tegra/clk-tegra124.c
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_audio4_mux] = { .dt_id = TEGRA124_CLK_AUDIO4_MUX, .present = true },
[tegra_clk_spdif_mux] = { .dt_id = TEGRA124_CLK_SPDIF_MUX, .present = true },
[tegra_clk_cec] = { .dt_id = TEGRA124_CLK_CEC, .present = true },
[tegra_clk_emc] = { .dt_id = TEGRA124_CLK_EMC, .present = false },
};

static struct tegra_devclk devclks[] __initdata = {
Expand Down Expand Up @@ -1500,6 +1501,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
Expand All @@ -1516,10 +1537,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));

Expand Down
16 changes: 4 additions & 12 deletions drivers/clk/tegra/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,18 +881,6 @@ 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);
#else
static inline struct clk *tegra_clk_register_emc(void __iomem *base,
struct device_node *np,
spinlock_t *lock)
{
return NULL;
}
#endif

void tegra114_clock_tune_cpu_trimmers_high(void);
void tegra114_clock_tune_cpu_trimmers_low(void);
void tegra114_clock_tune_cpu_trimmers_init(void);
Expand Down Expand Up @@ -922,6 +910,10 @@ void tegra_clk_periph_resume(void);
bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw);
struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter);

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);

struct clk *tegra210_clk_register_emc(struct device_node *np,
void __iomem *regs);

Expand Down
2 changes: 1 addition & 1 deletion drivers/memory/tegra/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ 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
help
Expand Down
31 changes: 21 additions & 10 deletions drivers/memory/tegra/tegra124-emc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1228,9 +1230,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;
};

Expand All @@ -1242,9 +1254,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");
9 changes: 9 additions & 0 deletions include/linux/clk/tegra.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ 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 device_node;
struct tegra_emc;

typedef long (tegra20_clk_emc_round_cb)(unsigned long rate,
unsigned long min_rate,
Expand All @@ -146,6 +148,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;
Expand Down
16 changes: 0 additions & 16 deletions include/soc/tegra/emc.h

This file was deleted.

0 comments on commit d100fc4

Please sign in to comment.