Commit 6d5b988e authored by Stephen Warren's avatar Stephen Warren

clk: tegra: implement a reset driver

The Tegra CAR module implements both a clock and reset controller. So
far, the driver exposes the clock feature via the common clock API and
the reset feature using a custom API. This patch adds an implementation
of the common reset framework API (include/linux/reset*.h). The legacy
reset implementation will be removed once all drivers have been
converted.
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Reviewed-by: default avatarThierry Reding <treding@nvidia.com>
Acked-By: default avatarPeter De Schrijver <pdeschrijver@nvidia.com>
parent e0421468
...@@ -1460,7 +1460,8 @@ static void __init tegra114_clock_init(struct device_node *np) ...@@ -1460,7 +1460,8 @@ static void __init tegra114_clock_init(struct device_node *np)
return; return;
} }
clks = tegra_clk_init(TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_PERIPH_BANKS); clks = tegra_clk_init(clk_base, TEGRA114_CLK_CLK_MAX,
TEGRA114_CLK_PERIPH_BANKS);
if (!clks) if (!clks)
return; return;
......
...@@ -1398,7 +1398,7 @@ static void __init tegra124_clock_init(struct device_node *np) ...@@ -1398,7 +1398,7 @@ static void __init tegra124_clock_init(struct device_node *np)
return; return;
} }
clks = tegra_clk_init(TEGRA124_CLK_CLK_MAX, 6); clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6);
if (!clks) if (!clks)
return; return;
......
...@@ -1109,7 +1109,8 @@ static void __init tegra20_clock_init(struct device_node *np) ...@@ -1109,7 +1109,8 @@ static void __init tegra20_clock_init(struct device_node *np)
BUG(); BUG();
} }
clks = tegra_clk_init(TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_PERIPH_BANKS); clks = tegra_clk_init(clk_base, TEGRA20_CLK_CLK_MAX,
TEGRA20_CLK_PERIPH_BANKS);
if (!clks) if (!clks)
return; return;
......
...@@ -1427,7 +1427,8 @@ static void __init tegra30_clock_init(struct device_node *np) ...@@ -1427,7 +1427,8 @@ static void __init tegra30_clock_init(struct device_node *np)
BUG(); BUG();
} }
clks = tegra_clk_init(TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_PERIPH_BANKS); clks = tegra_clk_init(clk_base, TEGRA30_CLK_CLK_MAX,
TEGRA30_CLK_PERIPH_BANKS);
if (!clks) if (!clks)
return; return;
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/clk/tegra.h> #include <linux/clk/tegra.h>
#include <linux/reset-controller.h>
#include <linux/tegra-soc.h>
#include "clk.h" #include "clk.h"
...@@ -121,6 +123,35 @@ static struct tegra_clk_periph_regs periph_regs[] = { ...@@ -121,6 +123,35 @@ static struct tegra_clk_periph_regs periph_regs[] = {
}, },
}; };
static void __iomem *clk_base;
static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
/*
* If peripheral is on the APB bus then we must read the APB bus to
* flush the write operation in apb bus. This will avoid peripheral
* access after disabling clock. Since the reset driver has no
* knowledge of which reset IDs represent which devices, simply do
* this all the time.
*/
tegra_read_chipid();
writel_relaxed(BIT(id % 32),
clk_base + periph_regs[id / 32].rst_set_reg);
return 0;
}
static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
writel_relaxed(BIT(id % 32),
clk_base + periph_regs[id / 32].rst_clr_reg);
return 0;
}
struct tegra_clk_periph_regs *get_reg_bank(int clkid) struct tegra_clk_periph_regs *get_reg_bank(int clkid)
{ {
int reg_bank = clkid / 32; int reg_bank = clkid / 32;
...@@ -133,8 +164,10 @@ struct tegra_clk_periph_regs *get_reg_bank(int clkid) ...@@ -133,8 +164,10 @@ struct tegra_clk_periph_regs *get_reg_bank(int clkid)
} }
} }
struct clk ** __init tegra_clk_init(int num, int banks) struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
{ {
clk_base = regs;
if (WARN_ON(banks > ARRAY_SIZE(periph_regs))) if (WARN_ON(banks > ARRAY_SIZE(periph_regs)))
return NULL; return NULL;
...@@ -203,6 +236,17 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, ...@@ -203,6 +236,17 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
} }
} }
static struct reset_control_ops rst_ops = {
.assert = tegra_clk_rst_assert,
.deassert = tegra_clk_rst_deassert,
};
static struct reset_controller_dev rst_ctlr = {
.ops = &rst_ops,
.owner = THIS_MODULE,
.of_reset_n_cells = 1,
};
void __init tegra_add_of_provider(struct device_node *np) void __init tegra_add_of_provider(struct device_node *np)
{ {
int i; int i;
...@@ -220,6 +264,10 @@ void __init tegra_add_of_provider(struct device_node *np) ...@@ -220,6 +264,10 @@ void __init tegra_add_of_provider(struct device_node *np)
clk_data.clks = clks; clk_data.clks = clks;
clk_data.clk_num = clk_num; clk_data.clk_num = clk_num;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
rst_ctlr.of_node = np;
rst_ctlr.nr_resets = clk_num * 32;
reset_controller_register(&rst_ctlr);
} }
void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num) void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num)
......
...@@ -597,7 +597,7 @@ void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, ...@@ -597,7 +597,7 @@ void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
struct clk *clks[], int clk_max); struct clk *clks[], int clk_max);
struct tegra_clk_periph_regs *get_reg_bank(int clkid); struct tegra_clk_periph_regs *get_reg_bank(int clkid);
struct clk **tegra_clk_init(int num, int periph_banks); struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks);
struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk); struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment