clk: tegra: Add Tegra210 special resets
authorPeter De Schrijver <pdeschrijver@nvidia.com>
Wed, 15 Mar 2017 12:59:32 +0000 (14:59 +0200)
committerThierry Reding <treding@nvidia.com>
Mon, 20 Mar 2017 13:20:42 +0000 (14:20 +0100)
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>
drivers/clk/tegra/clk-tegra210.c
include/dt-bindings/reset/tegra210-car.h [new file with mode: 0644]

index 1a8121abd4275b8524b747f61dbd116ee4e71958..6f29125ec4391460f61a1fa3b1b9f037ff3909be 100644 (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"
 #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));
 
diff --git a/include/dt-bindings/reset/tegra210-car.h b/include/dt-bindings/reset/tegra210-car.h
new file mode 100644 (file)
index 0000000..296ec6e
--- /dev/null
@@ -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 */