From 68d724cedcca8ab86eee824682f7da0af5e6e50d Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 15 Mar 2017 14:59:32 +0200 Subject: clk: tegra: Add Tegra210 special resets Tegra210 has 2 special resets which don't follow the normal pattern: DVCO and ADSP. Add them in this patch. Changelog: v2: add DT bindings file Signed-off-by: Peter De Schrijver Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra210.c | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'drivers/clk/tegra') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 1a8121abd427..6f29125ec439 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "clk.h" @@ -218,6 +219,12 @@ #define CLK_M_DIVISOR_SHIFT 2 #define CLK_M_DIVISOR_MASK 0x3 +#define RST_DFLL_DVCO 0x2f4 +#define DVFS_DFLL_RESET_SHIFT 0 + +#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8 +#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac + /* * SDM fractional divisor is 16-bit 2's complement signed number within * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned @@ -2982,6 +2989,81 @@ static void __init tegra210_clock_apply_init_table(void) tegra_init_from_table(init_table, clks, TEGRA210_CLK_CLK_MAX); } +/** + * tegra210_car_barrier - wait for pending writes to the CAR to complete + * + * Wait for any outstanding writes to the CAR MMIO space from this CPU + * to complete before continuing execution. No return value. + */ +static void tegra210_car_barrier(void) +{ + readl_relaxed(clk_base + RST_DFLL_DVCO); +} + +/** + * tegra210_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset + * + * Assert the reset line of the DFLL's DVCO. No return value. + */ +static void tegra210_clock_assert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v |= (1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra210_car_barrier(); +} + +/** + * tegra210_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset + * + * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to + * operate. No return value. + */ +static void tegra210_clock_deassert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v &= ~(1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra210_car_barrier(); +} + +static int tegra210_reset_assert(unsigned long id) +{ + if (id == TEGRA210_RST_DFLL_DVCO) + tegra210_clock_assert_dfll_dvco_reset(); + else if (id == TEGRA210_RST_ADSP) + writel(GENMASK(26, 21) | BIT(7), + clk_base + CLK_RST_CONTROLLER_RST_DEV_Y_SET); + else + return -EINVAL; + + return 0; +} + +static int tegra210_reset_deassert(unsigned long id) +{ + if (id == TEGRA210_RST_DFLL_DVCO) + tegra210_clock_deassert_dfll_dvco_reset(); + else if (id == TEGRA210_RST_ADSP) { + writel(BIT(21), clk_base + CLK_RST_CONTROLLER_RST_DEV_Y_CLR); + /* + * Considering adsp cpu clock (min: 12.5MHZ, max: 1GHz) + * a delay of 5us ensures that it's at least + * 6 * adsp_cpu_cycle_period long. + */ + udelay(5); + writel(GENMASK(26, 22) | BIT(7), + clk_base + CLK_RST_CONTROLLER_RST_DEV_Y_CLR); + } else + return -EINVAL; + + return 0; +} + /** * tegra210_clock_init - Tegra210-specific clock initialization * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -3046,6 +3128,9 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_super_clk_gen5_init(clk_base, pmc_base, tegra210_clks, &pll_x_params); + tegra_init_special_resets(2, tegra210_reset_assert, + tegra210_reset_deassert); + tegra_add_of_provider(np); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); -- cgit v1.2.3