Commit 68d724ce authored by Peter De Schrijver's avatar Peter De Schrijver Committed by Thierry Reding
Browse files

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: default avatarPeter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent e745f992
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -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));

+13 −0
Original line number Diff line number Diff line
/*
 * 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 */