linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sowjanya Komatineni <skomatineni@nvidia.com>
To: <thierry.reding@gmail.com>, <jonathanh@nvidia.com>,
	<tglx@linutronix.de>, <jason@lakedaemon.net>,
	<marc.zyngier@arm.com>, <linus.walleij@linaro.org>,
	<stefan@agner.ch>, <mark.rutland@arm.com>
Cc: <pdeschrijver@nvidia.com>, <pgaikwad@nvidia.com>,
	<sboyd@kernel.org>, <linux-clk@vger.kernel.org>,
	<linux-gpio@vger.kernel.org>, <jckuo@nvidia.com>,
	<josephl@nvidia.com>, <talho@nvidia.com>,
	<skomatineni@nvidia.com>, <linux-tegra@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <mperttunen@nvidia.com>,
	<spatra@nvidia.com>, <robh+dt@kernel.org>, <digetx@gmail.com>,
	<devicetree@vger.kernel.org>
Subject: [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support
Date: Sun, 21 Jul 2019 12:40:47 -0700	[thread overview]
Message-ID: <1563738060-30213-9-git-send-email-skomatineni@nvidia.com> (raw)
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>

This patch implements save and restore context for peripheral fixed
clock ops, peripheral gate clock ops, sdmmc mux clock ops, and
peripheral clock ops.

During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.

So during suspend entry clock and reset state of peripherals is saved
and on resume they are restored to have clocks back to same rate and
state as before suspend.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/clk-periph-fixed.c | 33 +++++++++++++++++++++++++++
 drivers/clk/tegra/clk-periph-gate.c  | 34 ++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-periph.c       | 43 ++++++++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-sdmmc-mux.c    | 30 +++++++++++++++++++++++++
 drivers/clk/tegra/clk.h              |  8 +++++++
 5 files changed, 148 insertions(+)

diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
index c088e7a280df..21b24530fa00 100644
--- a/drivers/clk/tegra/clk-periph-fixed.c
+++ b/drivers/clk/tegra/clk-periph-fixed.c
@@ -60,11 +60,44 @@ tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
 	return (unsigned long)rate;
 }
 
+static int tegra_clk_periph_fixed_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	fixed->enb_ctx = readl_relaxed(fixed->base + fixed->regs->enb_reg) &
+			 mask;
+	fixed->rst_ctx = readl_relaxed(fixed->base + fixed->regs->rst_reg) &
+			 mask;
+
+	return 0;
+}
+
+static void tegra_clk_periph_fixed_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
+	u32 mask = 1 << (fixed->num % 32);
+
+	if (fixed->enb_ctx)
+		writel_relaxed(mask, fixed->base + fixed->regs->enb_set_reg);
+	else
+		writel_relaxed(mask, fixed->base + fixed->regs->enb_clr_reg);
+
+	udelay(2);
+
+	if (!fixed->rst_ctx) {
+		udelay(5); /* reset propogation delay */
+		writel_relaxed(mask, fixed->base + fixed->regs->rst_reg);
+	}
+}
+
 static const struct clk_ops tegra_clk_periph_fixed_ops = {
 	.is_enabled = tegra_clk_periph_fixed_is_enabled,
 	.enable = tegra_clk_periph_fixed_enable,
 	.disable = tegra_clk_periph_fixed_disable,
 	.recalc_rate = tegra_clk_periph_fixed_recalc_rate,
+	.save_context = tegra_clk_periph_fixed_save_context,
+	.restore_context = tegra_clk_periph_fixed_restore_context,
 };
 
 struct clk *tegra_clk_register_periph_fixed(const char *name,
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index 4b31beefc9fc..6ba5b08e0787 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(periph_ref_lock);
 
 #define read_rst(gate) \
 	readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
+#define write_rst_set(val, gate) \
+	writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
 #define write_rst_clr(val, gate) \
 	writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
 
@@ -110,10 +112,42 @@ static void clk_periph_disable(struct clk_hw *hw)
 	spin_unlock_irqrestore(&periph_ref_lock, flags);
 }
 
+static int clk_periph_gate_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+
+	gate->clk_state_ctx = read_enb(gate) & periph_clk_to_bit(gate);
+	gate->rst_state_ctx = read_rst(gate) & periph_clk_to_bit(gate);
+
+	return 0;
+}
+
+static void clk_periph_gate_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+
+	if (gate->clk_state_ctx)
+		write_enb_set(periph_clk_to_bit(gate), gate);
+	else
+		write_enb_clr(periph_clk_to_bit(gate), gate);
+
+	udelay(5);
+
+	if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
+	    !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
+		if (gate->rst_state_ctx)
+			write_rst_set(periph_clk_to_bit(gate), gate);
+		else
+			write_rst_clr(periph_clk_to_bit(gate), gate);
+	}
+}
+
 const struct clk_ops tegra_clk_periph_gate_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_gate_save_context,
+	.restore_context = clk_periph_gate_restore_context,
 };
 
 struct clk *tegra_clk_register_periph_gate(const char *name,
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 58437da25156..b29a1ed2ec08 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -5,6 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/export.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 
@@ -99,6 +100,42 @@ static void clk_periph_disable(struct clk_hw *hw)
 	gate_ops->disable(gate_hw);
 }
 
+static int clk_periph_save_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph *periph = to_clk_periph(hw);
+	const struct clk_ops *gate_ops = periph->gate_ops;
+	struct clk_hw *gate_hw = &periph->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
+		gate_ops->save_context(gate_hw);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
+		periph->rate_ctx = clk_periph_recalc_rate(hw, parent_rate);
+
+	periph->parent_ctx = clk_periph_get_parent(hw);
+
+	return 0;
+}
+
+static void clk_periph_restore_context(struct clk_hw *hw)
+{
+	struct tegra_clk_periph *periph = to_clk_periph(hw);
+	const struct clk_ops *gate_ops = periph->gate_ops;
+	struct clk_hw *gate_hw = &periph->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	clk_periph_set_parent(hw, periph->parent_ctx);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
+		clk_periph_set_rate(hw, periph->rate_ctx, parent_rate);
+
+	if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
+		gate_ops->restore_context(gate_hw);
+}
+
 const struct clk_ops tegra_clk_periph_ops = {
 	.get_parent = clk_periph_get_parent,
 	.set_parent = clk_periph_set_parent,
@@ -108,6 +145,8 @@ const struct clk_ops tegra_clk_periph_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static const struct clk_ops tegra_clk_periph_nodiv_ops = {
@@ -116,6 +155,8 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
 	.is_enabled = clk_periph_is_enabled,
 	.enable = clk_periph_enable,
 	.disable = clk_periph_disable,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static const struct clk_ops tegra_clk_periph_no_gate_ops = {
@@ -124,6 +165,8 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
 	.recalc_rate = clk_periph_recalc_rate,
 	.round_rate = clk_periph_round_rate,
 	.set_rate = clk_periph_set_rate,
+	.save_context = clk_periph_save_context,
+	.restore_context = clk_periph_restore_context,
 };
 
 static struct clk *_tegra_clk_register_periph(const char *name,
diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c
index a5cd3e31dbae..fffe08e02c10 100644
--- a/drivers/clk/tegra/clk-sdmmc-mux.c
+++ b/drivers/clk/tegra/clk-sdmmc-mux.c
@@ -194,6 +194,34 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
 	gate_ops->disable(gate_hw);
 }
 
+static int clk_sdmmc_mux_save_context(struct clk_hw *hw)
+{
+	struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
+	const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
+	struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	sdmmc_mux->rate_ctx = clk_sdmmc_mux_recalc_rate(hw, parent_rate);
+	sdmmc_mux->parent_ctx = clk_sdmmc_mux_get_parent(hw);
+	gate_ops->save_context(gate_hw);
+
+	return 0;
+}
+
+static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
+{
+	struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
+	const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
+	struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = clk_hw_get_rate(parent);
+
+	clk_sdmmc_mux_set_parent(hw, sdmmc_mux->parent_ctx);
+	clk_sdmmc_mux_set_rate(hw, sdmmc_mux->rate_ctx, parent_rate);
+	gate_ops->restore_context(gate_hw);
+}
+
 static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
 	.get_parent = clk_sdmmc_mux_get_parent,
 	.set_parent = clk_sdmmc_mux_set_parent,
@@ -203,6 +231,8 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
 	.is_enabled = clk_sdmmc_mux_is_enabled,
 	.enable = clk_sdmmc_mux_enable,
 	.disable = clk_sdmmc_mux_disable,
+	.save_context = clk_sdmmc_mux_save_context,
+	.restore_context = clk_sdmmc_mux_restore_context,
 };
 
 struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 3cd003b7512a..ac6de3a0b91f 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -523,6 +523,8 @@ struct tegra_clk_periph_gate {
 	int			clk_num;
 	int			*enable_refcnt;
 	const struct tegra_clk_periph_regs *regs;
+	bool			clk_state_ctx;
+	bool			rst_state_ctx;
 };
 
 #define to_clk_periph_gate(_hw)					\
@@ -549,6 +551,8 @@ struct tegra_clk_periph_fixed {
 	unsigned int mul;
 	unsigned int div;
 	unsigned int num;
+	bool enb_ctx;
+	bool rst_ctx;
 };
 
 struct clk *tegra_clk_register_periph_fixed(const char *name,
@@ -581,6 +585,8 @@ struct tegra_clk_periph {
 	const struct clk_ops	*mux_ops;
 	const struct clk_ops	*div_ops;
 	const struct clk_ops	*gate_ops;
+	unsigned long		rate_ctx;
+	u8			parent_ctx;
 };
 
 #define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
@@ -732,6 +738,8 @@ struct tegra_sdmmc_mux {
 	const struct clk_ops	*gate_ops;
 	struct tegra_clk_periph_gate	gate;
 	u8			div_flags;
+	unsigned long		rate_ctx;
+	u8			parent_ctx;
 };
 
 #define to_clk_sdmmc_mux(_hw) container_of(_hw, struct tegra_sdmmc_mux, hw)
-- 
2.7.4


  parent reply	other threads:[~2019-07-21 19:41 UTC|newest]

Thread overview: 84+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-21 19:40 [PATCH V6 00/21] SC7 entry and exit support for Tegra210 Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 01/21] irqchip: tegra: Do not disable COP IRQ during suspend Sowjanya Komatineni
2019-07-21 20:24   ` Marc Zyngier
2019-07-22  9:54   ` Dmitry Osipenko
2019-07-22 10:13     ` Marc Zyngier
2019-07-22 10:57       ` Dmitry Osipenko
2019-07-22 16:21         ` Sowjanya Komatineni
2019-07-22 18:38           ` Marc Zyngier
2019-07-22 23:35             ` Dmitry Osipenko
2019-07-24 23:09               ` Sowjanya Komatineni
2019-07-26  4:48                 ` Dmitry Osipenko
2019-07-25  9:55     ` Peter De Schrijver
2019-07-25 10:05       ` Dmitry Osipenko
2019-07-25 10:33         ` Peter De Schrijver
2019-07-25 10:38           ` Peter De Schrijver
2019-07-25 10:59             ` Dmitry Osipenko
2019-08-02 13:05               ` Peter De Schrijver
2019-08-02 17:35                 ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support Sowjanya Komatineni
2019-07-21 22:03   ` Dmitry Osipenko
2019-07-21 22:09     ` Dmitry Osipenko
2019-07-21 22:48       ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 03/21] pinctrl: tegra210: Add Tegra210 pinctrl pm ops Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 04/21] clk: tegra: Save and restore divider rate Sowjanya Komatineni
2019-07-21 22:14   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context Sowjanya Komatineni
2019-07-21 22:18   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context Sowjanya Komatineni
2019-07-21 21:44   ` Dmitry Osipenko
2019-07-21 22:47     ` Sowjanya Komatineni
2019-07-21 22:21   ` Dmitry Osipenko
2019-07-22  3:22     ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore Sowjanya Komatineni
2019-07-22 10:12   ` Dmitry Osipenko
2019-07-21 19:40 ` Sowjanya Komatineni [this message]
2019-07-21 19:40 ` [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU Sowjanya Komatineni
2019-07-21 21:16   ` Dmitry Osipenko
2019-07-21 22:39     ` Sowjanya Komatineni
2019-07-22  3:17       ` Sowjanya Komatineni
2019-07-22  6:32         ` Dmitry Osipenko
2019-07-22  7:12           ` Sowjanya Komatineni
2019-07-22  7:17             ` Dmitry Osipenko
2019-07-22  7:24               ` Sowjanya Komatineni
2019-07-22  7:30                 ` Dmitry Osipenko
2019-07-22  7:36                   ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support Sowjanya Komatineni
2019-07-21 21:32   ` Dmitry Osipenko
2019-07-21 22:42     ` Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 12/21] cpufreq: tegra124: " Sowjanya Komatineni
2019-07-21 21:04   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 14/21] clk: tegra210: Add suspend and resume support Sowjanya Komatineni
2019-07-21 21:38   ` Dmitry Osipenko
2019-07-21 22:45     ` Sowjanya Komatineni
2019-07-22  6:10       ` Dmitry Osipenko
2019-07-22  6:52         ` Sowjanya Komatineni
2019-07-22  7:09           ` Dmitry Osipenko
2019-07-22  7:12             ` Dmitry Osipenko
2019-08-02 17:51               ` Stephen Boyd
2019-08-02 20:39                 ` Sowjanya Komatineni
2019-08-07 21:22                   ` Stephen Boyd
2019-07-21 19:40 ` [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210 Sowjanya Komatineni
2019-07-23  0:58   ` Dmitry Osipenko
2019-07-23  1:08     ` Dmitry Osipenko
2019-07-23  1:41       ` Dmitry Osipenko
2019-07-23  1:52         ` Dmitry Osipenko
2019-07-23  2:10           ` Dmitry Osipenko
     [not found]         ` <71a88a9c-a542-557a-0eaa-3c90112dee0e@nvidia.com>
2019-07-23  3:03           ` Dmitry Osipenko
2019-07-23  3:09             ` Sowjanya Komatineni
2019-07-23  3:25               ` Dmitry Osipenko
2019-07-23  3:31                 ` Sowjanya Komatineni
2019-07-23  3:43                   ` Dmitry Osipenko
2019-07-23 14:27                     ` Dmitry Osipenko
2019-07-23 23:39                       ` Sowjanya Komatineni
2019-07-24  9:31                         ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm Sowjanya Komatineni
2019-07-26  6:30   ` Dmitry Osipenko
2019-07-21 19:40 ` [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings Sowjanya Komatineni
2019-07-21 19:40 ` [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings Sowjanya Komatineni
2019-07-21 19:41 ` [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano " Sowjanya Komatineni
2019-07-21 22:25   ` Dmitry Osipenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1563738060-30213-9-git-send-email-skomatineni@nvidia.com \
    --to=skomatineni@nvidia.com \
    --cc=devicetree@vger.kernel.org \
    --cc=digetx@gmail.com \
    --cc=jason@lakedaemon.net \
    --cc=jckuo@nvidia.com \
    --cc=jonathanh@nvidia.com \
    --cc=josephl@nvidia.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=marc.zyngier@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=mperttunen@nvidia.com \
    --cc=pdeschrijver@nvidia.com \
    --cc=pgaikwad@nvidia.com \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=spatra@nvidia.com \
    --cc=stefan@agner.ch \
    --cc=talho@nvidia.com \
    --cc=tglx@linutronix.de \
    --cc=thierry.reding@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).