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 <pdeschrijver@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
Peter De Schrijver 2017-03-15 14:59:32 +02:00 committed by Thierry Reding
parent e745f992cf
commit 68d724cedc
2 changed files with 98 additions and 0 deletions

View File

@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/clk/tegra.h>
#include <dt-bindings/clock/tegra210-car.h>
#include <dt-bindings/reset/tegra210-car.h>
#include <linux/iopoll.h>
#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));

View File

@ -0,0 +1,13 @@
/*
* This header provides Tegra210-specific constants for binding
* nvidia,tegra210-car.
*/
#ifndef _DT_BINDINGS_RESET_TEGRA210_CAR_H
#define _DT_BINDINGS_RESET_TEGRA210_CAR_H
#define TEGRA210_RESET(x) (7 * 32 + (x))
#define TEGRA210_RST_DFLL_DVCO TEGRA210_RESET(0)
#define TEGRA210_RST_ADSP TEGRA210_RESET(1)
#endif /* _DT_BINDINGS_RESET_TEGRA210_CAR_H */