diff options
Diffstat (limited to 'drivers/clk/tegra/clk-tegra124.c')
-rw-r--r-- | drivers/clk/tegra/clk-tegra124.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e8cca3eac007..824d75883d2b 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -15,7 +15,6 @@ */ #include <linux/io.h> -#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/of.h> @@ -24,6 +23,7 @@ #include <linux/export.h> #include <linux/clk/tegra.h> #include <dt-bindings/clock/tegra124-car.h> +#include <dt-bindings/reset/tegra124-car.h> #include "clk.h" #include "clk-id.h" @@ -39,6 +39,9 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c +#define RST_DFLL_DVCO 0x2f4 +#define DVFS_DFLL_RESET_SHIFT 0 + #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 #define PLLC_MISC2 0x88 @@ -94,6 +97,8 @@ #define PMC_PLLM_WB0_OVERRIDE 0x1dc #define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 +#define CCLKG_BURST_POLICY 0x368 + #define UTMIP_PLL_CFG2 0x488 #define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) #define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) @@ -126,6 +131,8 @@ #ifdef CONFIG_PM_SLEEP static struct cpu_clk_suspend_context { u32 clk_csite_src; + u32 cclkg_burst; + u32 cclkg_divider; } tegra124_cpu_clk_sctx; #endif @@ -1319,12 +1326,22 @@ static void tegra124_cpu_clock_suspend(void) tegra124_cpu_clk_sctx.clk_csite_src = readl(clk_base + CLK_SOURCE_CSITE); writel(3 << 30, clk_base + CLK_SOURCE_CSITE); + + tegra124_cpu_clk_sctx.cclkg_burst = + readl(clk_base + CCLKG_BURST_POLICY); + tegra124_cpu_clk_sctx.cclkg_divider = + readl(clk_base + CCLKG_BURST_POLICY + 4); } static void tegra124_cpu_clock_resume(void) { writel(tegra124_cpu_clk_sctx.clk_csite_src, clk_base + CLK_SOURCE_CSITE); + + writel(tegra124_cpu_clk_sctx.cclkg_burst, + clk_base + CCLKG_BURST_POLICY); + writel(tegra124_cpu_clk_sctx.cclkg_divider, + clk_base + CCLKG_BURST_POLICY + 4); } #endif @@ -1415,6 +1432,68 @@ static void __init tegra124_clock_apply_init_table(void) } /** + * tegra124_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 tegra124_car_barrier(void) +{ + readl_relaxed(clk_base + RST_DFLL_DVCO); +} + +/** + * tegra124_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 tegra124_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); + tegra124_car_barrier(); +} + +/** + * tegra124_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 tegra124_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); + tegra124_car_barrier(); +} + +static int tegra124_reset_assert(unsigned long id) +{ + if (id == TEGRA124_RST_DFLL_DVCO) + tegra124_clock_assert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} + +static int tegra124_reset_deassert(unsigned long id) +{ + if (id == TEGRA124_RST_DFLL_DVCO) + tegra124_clock_deassert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} + +/** * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs * * Program an initial clock rate and enable or disable clocks needed @@ -1499,6 +1578,8 @@ static void __init tegra124_132_clock_init_post(struct device_node *np) { tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, &pll_x_params); + tegra_init_special_resets(1, tegra124_reset_assert, + tegra124_reset_deassert); tegra_add_of_provider(np); clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, |