* [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch implements save and restore of pllout context.
During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.
So during suspend entry the state of pllout is saved and on resume
it is restored back to have pllout in same state as before suspend.
pllout rate is saved and restore in clock divider so it will be at
same rate as before suspend when pllout state is restored.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-pll-out.c | 28 ++++++++++++++++++++++++++++
drivers/clk/tegra/clk-tegra210.c | 3 ++-
drivers/clk/tegra/clk.h | 9 +++++++++
3 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
index 35f2bf00e1e6..8f26a7e3e579 100644
--- a/drivers/clk/tegra/clk-pll-out.c
+++ b/drivers/clk/tegra/clk-pll-out.c
@@ -69,10 +69,38 @@ static void clk_pll_out_disable(struct clk_hw *hw)
spin_unlock_irqrestore(pll_out->lock, flags);
}
+static int tegra_clk_pll_out_save_context(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+
+ if (pll_out->flags & TEGRA_PLLRE_OUT)
+ pll_out->pllout_ctx = readl_relaxed(pll_out->reg);
+ else
+ pll_out->pllout_ctx = clk_hw_get_rate(hw);
+
+ return 0;
+}
+
+static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+
+ if (pll_out->flags & TEGRA_PLLRE_OUT) {
+ writel_relaxed(pll_out->pllout_ctx, pll_out->reg);
+ } else {
+ if (!__clk_get_enable_count(hw->clk))
+ clk_pll_out_disable(hw);
+ else
+ clk_pll_out_enable(hw);
+ }
+}
+
const struct clk_ops tegra_clk_pll_out_ops = {
.is_enabled = clk_pll_out_is_enabled,
.enable = clk_pll_out_enable,
.disable = clk_pll_out_disable,
+ .save_context = tegra_clk_pll_out_save_context,
+ .restore_context = tegra_clk_pll_out_restore_context,
};
struct clk *tegra_clk_register_pll_out(const char *name,
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index df172d5772d7..4721ee030d1c 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -3200,7 +3200,8 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
8, 8, 1, NULL);
clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div",
clk_base + PLLRE_OUT1, 1, 0,
- CLK_SET_RATE_PARENT, 0, NULL);
+ CLK_SET_RATE_PARENT, TEGRA_PLLRE_OUT,
+ NULL);
clks[TEGRA210_CLK_PLL_RE_OUT1] = clk;
/* PLLE */
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 83623f5f55f3..fb29a8c27873 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -439,6 +439,12 @@ struct clk *tegra_clk_register_pllu_tegra210(const char *name,
* @rst_bit_idx: bit to reset PLL divider
* @lock: register lock
* @flags: hardware-specific flags
+ * @pllout_ctx: pllout context to save and restore during suspend
+ * and resume
+ *
+ * Flags:
+ * TEGRA_PLLRE_OUT - This flag indicates that it is PLLRE_OUT and is used to
+ * identify PLLRE_OUT during clk_pll_out save and restore.
*/
struct tegra_clk_pll_out {
struct clk_hw hw;
@@ -447,8 +453,11 @@ struct tegra_clk_pll_out {
u8 rst_bit_idx;
spinlock_t *lock;
u8 flags;
+ unsigned int pllout_ctx;
};
+#define TEGRA_PLLRE_OUT BIT(0)
+
#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
extern const struct clk_ops tegra_clk_pll_out_ops;
--
2.7.4
^ permalink raw reply related
* [PATCH V6 07/21] clk: tegra: Support for OSC context save and restore
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
X-NVConfidentiality: public
This patch adds support for saving OSC clock frequency and the
drive-strength during OSC clock init and creates an API to restore
OSC control register value from the saved context.
This API is invoked by Tegra210 clock driver during system resume
to restore the OSC clock settings.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-tegra-fixed.c | 15 +++++++++++++++
drivers/clk/tegra/clk.h | 1 +
2 files changed, 16 insertions(+)
diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index 8d91b2b191cf..7c6c8abfcde6 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -17,6 +17,10 @@
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_SHIFT 28
#define OSC_CTRL_PLL_REF_DIV_SHIFT 26
+#define OSC_CTRL_MASK (0x3f2 | \
+ (0xf << OSC_CTRL_OSC_FREQ_SHIFT))
+
+static u32 osc_ctrl_ctx;
int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
unsigned long *input_freqs, unsigned int num,
@@ -29,6 +33,7 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
unsigned osc_idx;
val = readl_relaxed(clk_base + OSC_CTRL);
+ osc_ctrl_ctx = val & OSC_CTRL_MASK;
osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
if (osc_idx < num)
@@ -96,3 +101,13 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)
*dt_clk = clk;
}
}
+
+void tegra_clk_osc_resume(void __iomem *clk_base)
+{
+ u32 val;
+
+ val = readl_relaxed(clk_base + OSC_CTRL) & ~OSC_CTRL_MASK;
+ val |= osc_ctrl_ctx;
+ writel_relaxed(val, clk_base + OSC_CTRL);
+ fence_udelay(2, clk_base);
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 8532f5150091..3cd003b7512a 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -849,6 +849,7 @@ int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
u8 frac_width, u8 flags);
void tegra_clk_sync_state_pll(struct clk_hw *hw);
+void tegra_clk_osc_resume(void __iomem *clk_base);
/* Combined read fence with delay */
#define fence_udelay(delay, reg) \
--
2.7.4
^ permalink raw reply related
* [PATCH V6 08/21] clk: tegra: clk-periph: Add save and restore support
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
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
^ permalink raw reply related
* [PATCH V6 10/21] clk: tegra: clk-super: Add save and restore support
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch implements save and restore context for clk_super_mux
and clk_super.
During system supend, core power goes off the and context of Tegra
CAR registers is lost.
So during suspend entry, context of super clock registers are saved
through save_context clk_ops and are restored through restore_context
clk_ops to have them in same state as before suspend.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-super.c | 40 ++++++++++++++++++++++++++++++++++++++++
drivers/clk/tegra/clk.h | 1 +
2 files changed, 41 insertions(+)
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index d73c587e4853..84492afd3f1d 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -121,9 +121,27 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
return err;
}
+static int clk_super_mux_save_context(struct clk_hw *hw)
+{
+ struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+
+ mux->parent_index_ctx = clk_super_get_parent(hw);
+
+ return 0;
+}
+
+static void clk_super_mux_restore_context(struct clk_hw *hw)
+{
+ struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+
+ clk_super_set_parent(hw, mux->parent_index_ctx);
+}
+
static const struct clk_ops tegra_clk_super_mux_ops = {
.get_parent = clk_super_get_parent,
.set_parent = clk_super_set_parent,
+ .save_context = clk_super_mux_save_context,
+ .restore_context = clk_super_mux_restore_context,
};
static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -159,12 +177,34 @@ static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,
return super->div_ops->set_rate(div_hw, rate, parent_rate);
}
+static int clk_super_save_context(struct clk_hw *hw)
+{
+ struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
+ struct clk_hw *div_hw = &super->frac_div.hw;
+
+ super->parent_index_ctx = clk_super_get_parent(hw);
+
+ return super->div_ops->save_context(div_hw);
+}
+
+static void clk_super_restore_context(struct clk_hw *hw)
+{
+ struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
+ struct clk_hw *div_hw = &super->frac_div.hw;
+
+ clk_super_set_parent(hw, super->parent_index_ctx);
+
+ super->div_ops->restore_context(div_hw);
+}
+
const struct clk_ops tegra_clk_super_ops = {
.get_parent = clk_super_get_parent,
.set_parent = clk_super_set_parent,
.set_rate = clk_super_set_rate,
.round_rate = clk_super_round_rate,
.recalc_rate = clk_super_recalc_rate,
+ .save_context = clk_super_save_context,
+ .restore_context = clk_super_restore_context,
};
struct clk *tegra_clk_register_super_mux(const char *name,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index c357b49e49b0..562a3ee2d537 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -708,6 +708,7 @@ struct tegra_clk_super_mux {
u8 div2_index;
u8 pllx_index;
spinlock_t *lock;
+ u8 parent_index_ctx;
};
#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
--
2.7.4
^ permalink raw reply related
* [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch has a fix to enable PLLP branches to CPU before changing
the CPU clusters clock source to PLLP for Gen5 Super clock.
During system suspend entry and exit, CPU source will be switched
to PLLP and this needs PLLP branches to be enabled to CPU prior to
the switch.
On system resume, warmboot code enables PLLP branches to CPU and
powers up the CPU with PLLP clock source.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-super.c | 11 +++++++++++
drivers/clk/tegra/clk-tegra-super-gen4.c | 4 ++--
drivers/clk/tegra/clk.h | 4 ++++
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index 39ef31b46df5..d73c587e4853 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -28,6 +28,9 @@
#define super_state_to_src_shift(m, s) ((m->width * s))
#define super_state_to_src_mask(m) (((1 << m->width) - 1))
+#define CCLK_SRC_PLLP_OUT0 4
+#define CCLK_SRC_PLLP_OUT4 5
+
static u8 clk_super_get_parent(struct clk_hw *hw)
{
struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
@@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
if (index == mux->div2_index)
index = mux->pllx_index;
}
+
+ /*
+ * Enable PLLP branches to CPU before selecting PLLP source
+ */
+ if ((mux->flags & TEGRA_CPU_CLK) &&
+ ((index == CCLK_SRC_PLLP_OUT0) || (index == CCLK_SRC_PLLP_OUT4)))
+ tegra_clk_set_pllp_out_cpu(true);
+
val &= ~((super_state_to_src_mask(mux)) << shift);
val |= (index & (super_state_to_src_mask(mux))) << shift;
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index cdfe7c9697e1..cd208d0eca2a 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
gen_info->num_cclk_g_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKG_BURST_POLICY,
- 0, 4, 8, 0, NULL);
+ TEGRA_CPU_CLK, 4, 8, 0, NULL);
} else {
clk = tegra_clk_register_super_mux("cclk_g",
gen_info->cclk_g_parents,
@@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
gen_info->num_cclk_lp_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
- 0, 4, 8, 0, NULL);
+ TEGRA_CPU_CLK, 4, 8, 0, NULL);
} else {
clk = tegra_clk_register_super_mux("cclk_lp",
gen_info->cclk_lp_parents,
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index ac6de3a0b91f..c357b49e49b0 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
* Flags:
* TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
* that this is LP cluster clock.
+ * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. To use PLLP
+ * for CPU clock source, need to enable PLLP branches to CPU by setting the
+ * additional bit PLLP_OUT_CPU for gen5 super clock.
*/
struct tegra_clk_super_mux {
struct clk_hw hw;
@@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
#define TEGRA_DIVIDER_2 BIT(0)
+#define TEGRA_CPU_CLK BIT(1)
extern const struct clk_ops tegra_clk_super_ops;
struct clk *tegra_clk_register_super_mux(const char *name,
--
2.7.4
^ permalink raw reply related
* [PATCH V6 12/21] cpufreq: tegra124: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch adds suspend and resume pm ops for cpufreq driver.
PLLP is the safe clock source for CPU during system suspend and
resume as PLLP rate is below the CPU Fmax at Vmin.
CPUFreq driver suspend switches the CPU clock source to PLLP and
disables the DFLL clock.
During system resume, warmboot code powers up the CPU with PLLP
clock source. So CPUFreq driver resume enabled DFLL clock and
switches CPU back to DFLL clock source.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/cpufreq/tegra124-cpufreq.c | 46 ++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
index 4f0c637b3b49..4eff63379b0f 100644
--- a/drivers/cpufreq/tegra124-cpufreq.c
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -128,8 +129,53 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
return ret;
}
+static int tegra124_cpufreq_suspend(struct device *dev)
+{
+ struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
+
+ /*
+ * PLLP rate 408Mhz is below the CPU Fmax at Vmin and is safe to
+ * use during suspend and resume. So, switch the CPU clock source
+ * to PLLP and disable DFLL.
+ */
+ clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+
+ /* disable DFLL clock */
+ clk_disable_unprepare(priv->dfll_clk);
+
+ return 0;
+}
+
+static int tegra124_cpufreq_resume(struct device *dev)
+{
+ struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
+ int ret = 0;
+
+ /*
+ * Warmboot code powers up the CPU with PLLP clock source.
+ * Enable DFLL clock and switch CPU clock source back to DFLL.
+ */
+ ret = clk_prepare_enable(priv->dfll_clk);
+ if (ret) {
+ dev_warn(dev, "failed to enable DFLL clock for CPU\n");
+ clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+ disable_cpufreq();
+ return ret;
+ }
+
+ clk_set_parent(priv->cpu_clk, priv->dfll_clk);
+
+ return ret;
+}
+
+static const struct dev_pm_ops tegra124_cpufreq_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra124_cpufreq_suspend,
+ tegra124_cpufreq_resume)
+};
+
static struct platform_driver tegra124_cpufreq_platdrv = {
.driver.name = "cpufreq-tegra124",
+ .driver.pm = &tegra124_cpufreq_pm_ops,
.probe = tegra124_cpufreq_probe,
};
--
2.7.4
^ permalink raw reply related
* [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch implements DFLL suspend and resume operation.
During system suspend entry, CPU clock will switch CPU to safe
clock source of PLLP and disables DFLL clock output.
DFLL driver suspend confirms DFLL disable state and errors out on
being active.
DFLL is re-initialized during the DFLL driver resume as it goes
through complete reset during suspend entry.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-dfll.c | 44 ++++++++++++++++++++++++++++++
drivers/clk/tegra/clk-dfll.h | 2 ++
drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 1 +
3 files changed, 47 insertions(+)
diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
index f8688c2ddf1a..7dcad4ccd0ae 100644
--- a/drivers/clk/tegra/clk-dfll.c
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -1513,6 +1513,50 @@ static int dfll_init(struct tegra_dfll *td)
return ret;
}
+/**
+ * tegra_dfll_suspend - check DFLL is disabled
+ * @dev: DFLL device *
+ *
+ * DFLL clock should be disabled by the CPUFreq driver. So, make
+ * sure it is disabled and disable all clocks needed by the DFLL.
+ */
+int tegra_dfll_suspend(struct device *dev)
+{
+ struct tegra_dfll *td = dev_get_drvdata(dev);
+
+ if (dfll_is_running(td)) {
+ dev_warn(td->dev, "failed disabling the dfll\n");
+ return -EBUSY;
+ }
+
+ pm_runtime_disable(dev);
+
+ clk_unprepare(td->ref_clk);
+ clk_unprepare(td->soc_clk);
+ clk_unprepare(td->i2c_clk);
+
+ reset_control_assert(td->dvco_rst);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dfll_suspend);
+
+/**
+ * tegra_dfll_resume - reinitialize DFLL on resume
+ * @pdev: DFLL instance
+ *
+ * Re-initialize DFLL on resume as it gets disabled and reset during
+ * suspend entry. DFLL clock is enabled in closed loop mode later
+ * and CPU frequency will be switched to DFLL output.
+ */
+int tegra_dfll_resume(struct device *dev)
+{
+ struct tegra_dfll *td = dev_get_drvdata(dev);
+
+ return dfll_init(td);
+}
+EXPORT_SYMBOL(tegra_dfll_resume);
+
/*
* DT data fetch
*/
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
index 1b14ebe7268b..fb209eb5f365 100644
--- a/drivers/clk/tegra/clk-dfll.h
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
int tegra_dfll_runtime_suspend(struct device *dev);
int tegra_dfll_runtime_resume(struct device *dev);
+int tegra_dfll_suspend(struct device *dev);
+int tegra_dfll_resume(struct device *dev);
#endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
index e84b6d52cbbd..2ac2679d696d 100644
--- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
static const struct dev_pm_ops tegra124_dfll_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
tegra_dfll_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
};
static struct platform_driver tegra124_dfll_fcpu_driver = {
--
2.7.4
^ permalink raw reply related
* [PATCH V6 13/21] clk: tegra210: Use fence_udelay during PLLU init
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch uses fence_udelay rather than udelay during PLLU
initialization to ensure writes to clock registers happens before
waiting for specified delay.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-tegra210.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 58397f93166c..55a88c0824a5 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -2841,7 +2841,7 @@ static int tegra210_enable_pllu(void)
reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
reg &= ~BIT(pllu.params->iddq_bit_idx);
writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
- udelay(5);
+ fence_udelay(5, clk_base);
reg = readl_relaxed(clk_base + PLLU_BASE);
reg &= ~GENMASK(20, 0);
@@ -2849,7 +2849,7 @@ static int tegra210_enable_pllu(void)
reg |= fentry->n << 8;
reg |= fentry->p << 16;
writel(reg, clk_base + PLLU_BASE);
- udelay(1);
+ fence_udelay(1, clk_base);
reg |= PLL_ENABLE;
writel(reg, clk_base + PLLU_BASE);
@@ -2895,12 +2895,12 @@ static int tegra210_init_pllu(void)
reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK;
writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
- udelay(1);
+ fence_udelay(1, clk_base);
reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
- udelay(1);
+ fence_udelay(1, clk_base);
reg = readl_relaxed(clk_base + PLLU_BASE);
reg &= ~PLLU_BASE_CLKENABLE_USB;
--
2.7.4
^ permalink raw reply related
* [PATCH V6 15/21] soc/tegra: pmc: Allow to support more tegras wake
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch allows to create separate irq_set_wake and irq_set_type
implementations for different tegra designs PMC that has different
wake models which require difference wake registers and different
programming sequence.
AOWAKE model support is available for Tegra186 and Tegra194 only
and it resides within PMC and supports tiered wake architecture.
Tegra210 and prior tegra designs uses PMC directly to receive wake
events and coordinate the wake sequence.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/soc/tegra/pmc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 9f9c1c677cf4..91c84d0e66ae 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -226,6 +226,8 @@ struct tegra_pmc_soc {
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
struct device_node *np,
bool invert);
+ int (*irq_set_wake)(struct irq_data *data, unsigned int on);
+ int (*irq_set_type)(struct irq_data *data, unsigned int type);
const char * const *reset_sources;
unsigned int num_reset_sources;
@@ -1920,7 +1922,7 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
.alloc = tegra_pmc_irq_alloc,
};
-static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
unsigned int offset, bit;
@@ -1952,7 +1954,7 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
-static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
u32 value;
@@ -2006,8 +2008,8 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
pmc->irq.irq_unmask = irq_chip_unmask_parent;
pmc->irq.irq_eoi = irq_chip_eoi_parent;
pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
- pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
- pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
+ pmc->irq.irq_set_type = pmc->soc->irq_set_type;
+ pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
&tegra_pmc_irq_domain_ops, pmc);
@@ -2680,6 +2682,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.regs = &tegra186_pmc_regs,
.init = NULL,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .irq_set_wake = tegra186_pmc_irq_set_wake,
+ .irq_set_type = tegra186_pmc_irq_set_type,
.reset_sources = tegra186_reset_sources,
.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
.reset_levels = tegra186_reset_levels,
--
2.7.4
^ permalink raw reply related
* [PATCH V6 17/21] arm64: tegra: Enable wake from deep sleep on RTC alarm.
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch updates device tree for RTC and PMC to allow system wake
from deep sleep on RTC alarm.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 659753118e96..30a7c48385a2 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -768,7 +768,8 @@
rtc@7000e000 {
compatible = "nvidia,tegra210-rtc", "nvidia,tegra20-rtc";
reg = <0x0 0x7000e000 0x0 0x100>;
- interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&pmc>;
clocks = <&tegra_car TEGRA210_CLK_RTC>;
clock-names = "rtc";
};
@@ -778,6 +779,8 @@
reg = <0x0 0x7000e400 0x0 0x400>;
clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
clock-names = "pclk", "clk32k_in";
+ #interrupt-cells = <2>;
+ interrupt-controller;
powergates {
pd_audio: aud {
--
2.7.4
^ permalink raw reply related
* [PATCH V6 18/21] soc/tegra: pmc: Configure core power request polarity
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch configures polarity of the core power request signal
in PMC control register based on the device tree property.
PMC asserts and de-asserts power request signal based on it polarity
when it need to power-up and power-down the core rail during SC7.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/soc/tegra/pmc.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index c556f38874e1..7521394b94ab 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -56,6 +56,7 @@
#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */
#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */
#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */
+#define PMC_CNTRL_PWRREQ_POLARITY BIT(8)
#define PMC_CNTRL_MAIN_RST BIT(4)
#define PMC_CNTRL_LATCH_WAKEUPS BIT(5)
@@ -2303,6 +2304,11 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
else
value |= PMC_CNTRL_SYSCLK_POLARITY;
+ if (pmc->corereq_high)
+ value &= ~PMC_CNTRL_PWRREQ_POLARITY;
+ else
+ value |= PMC_CNTRL_PWRREQ_POLARITY;
+
/* configure the output polarity while the request is tristated */
tegra_pmc_writel(pmc, value, PMC_CNTRL);
--
2.7.4
^ permalink raw reply related
* [PATCH V6 19/21] soc/tegra: pmc: Configure deep sleep control settings
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
Tegra210 and prior Tegra chips have deep sleep entry and wakeup related
timings which are platform specific that should be configured before
entering into deep sleep.
Below are the timing specific configurations for deep sleep entry and
wakeup.
- Core rail power-on stabilization timer
- OSC clock stabilization timer after SOC rail power is stabilized.
- Core power off time is the minimum wake delay to keep the system
in deep sleep state irrespective of any quick wake event.
These values depends on the discharge time of regulators and turn OFF
time of the PMIC to allow the complete system to finish entering into
deep sleep state.
These values vary based on the platform design and are specified
through the device tree.
This patch has implementation to configure these timings which are must
to have for proper deep sleep and wakeup operations.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/soc/tegra/pmc.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 7521394b94ab..16df35bdbd4b 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -89,6 +89,8 @@
#define PMC_CPUPWRGOOD_TIMER 0xc8
#define PMC_CPUPWROFF_TIMER 0xcc
+#define PMC_COREPWRGOOD_TIMER 0x3c
+#define PMC_COREPWROFF_TIMER 0xe0
#define PMC_PWR_DET_VALUE 0xe4
@@ -2290,7 +2292,7 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
static void tegra20_pmc_init(struct tegra_pmc *pmc)
{
- u32 value;
+ u32 value, osc, pmu, off;
/* Always enable CPU power request */
value = tegra_pmc_readl(pmc, PMC_CNTRL);
@@ -2316,6 +2318,15 @@ static void tegra20_pmc_init(struct tegra_pmc *pmc)
value = tegra_pmc_readl(pmc, PMC_CNTRL);
value |= PMC_CNTRL_SYSCLK_OE;
tegra_pmc_writel(pmc, value, PMC_CNTRL);
+
+ osc = DIV_ROUND_UP(pmc->core_osc_time * 8192, 1000000);
+ pmu = DIV_ROUND_UP(pmc->core_pmu_time * 32768, 1000000);
+ off = DIV_ROUND_UP(pmc->core_off_time * 32768, 1000000);
+ if (osc && pmu)
+ tegra_pmc_writel(pmc, ((osc << 8) & 0xff00) | (pmu & 0xff),
+ PMC_COREPWRGOOD_TIMER);
+ if (off)
+ tegra_pmc_writel(pmc, off, PMC_COREPWROFF_TIMER);
}
static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
--
2.7.4
^ permalink raw reply related
* [PATCH V6 20/21] arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch has Jetson TX1 platform specific SC7 timing configuration
in device tree.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
index 27723829d033..cb58f79deb48 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
@@ -279,6 +279,13 @@
pmc@7000e400 {
nvidia,invert-interrupt;
+ nvidia,suspend-mode = <0>;
+ nvidia,cpu-pwr-good-time = <0>;
+ nvidia,cpu-pwr-off-time = <0>;
+ nvidia,core-pwr-good-time = <4587 3876>;
+ nvidia,core-pwr-off-time = <39065>;
+ nvidia,core-power-req-active-high;
+ nvidia,sys-clock-req-active-high;
};
/* eMMC */
--
2.7.4
^ permalink raw reply related
* [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano SC7 timings
From: Sowjanya Komatineni @ 2019-07-21 19:41 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch adds Jetson nano platform specific SC7 timing configuration
in the device tree.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 9d17ec707bce..b525e69c172a 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -382,6 +382,13 @@
pmc@7000e400 {
nvidia,invert-interrupt;
+ nvidia,suspend-mode = <0>;
+ nvidia,cpu-pwr-good-time = <0>;
+ nvidia,cpu-pwr-off-time = <0>;
+ nvidia,core-pwr-good-time = <4587 3876>;
+ nvidia,core-pwr-off-time = <39065>;
+ nvidia,core-power-req-active-high;
+ nvidia,sys-clock-req-active-high;
};
hda@70030000 {
--
2.7.4
^ permalink raw reply related
* [PATCH V6 16/21] soc/tegra: pmc: Add pmc wake support for tegra210
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch implements PMC wakeup sequence for Tegra210 and defines
common used RTC alarm wake event.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/soc/tegra/pmc.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 91c84d0e66ae..c556f38874e1 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -57,6 +57,12 @@
#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */
#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */
#define PMC_CNTRL_MAIN_RST BIT(4)
+#define PMC_CNTRL_LATCH_WAKEUPS BIT(5)
+
+#define PMC_WAKE_MASK 0x0c
+#define PMC_WAKE_LEVEL 0x10
+#define PMC_WAKE_STATUS 0x14
+#define PMC_SW_WAKE_STATUS 0x18
#define DPD_SAMPLE 0x020
#define DPD_SAMPLE_ENABLE BIT(0)
@@ -87,6 +93,11 @@
#define PMC_SCRATCH41 0x140
+#define PMC_WAKE2_MASK 0x160
+#define PMC_WAKE2_LEVEL 0x164
+#define PMC_WAKE2_STATUS 0x168
+#define PMC_SW_WAKE2_STATUS 0x16c
+
#define PMC_SENSOR_CTRL 0x1b0
#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
@@ -1922,6 +1933,55 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
.alloc = tegra_pmc_irq_alloc,
};
+static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+ struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+ unsigned int offset, bit;
+ u32 value;
+
+ if (data->hwirq == ULONG_MAX)
+ return 0;
+
+ offset = data->hwirq / 32;
+ bit = data->hwirq % 32;
+
+ /*
+ * Latch wakeups to SW_WAKE_STATUS register to capture events
+ * that would not make it into wakeup event register during LP0 exit.
+ */
+ value = tegra_pmc_readl(pmc, PMC_CNTRL);
+ value |= PMC_CNTRL_LATCH_WAKEUPS;
+ tegra_pmc_writel(pmc, value, PMC_CNTRL);
+ udelay(120);
+
+ value &= ~PMC_CNTRL_LATCH_WAKEUPS;
+ tegra_pmc_writel(pmc, value, PMC_CNTRL);
+ udelay(120);
+
+ tegra_pmc_writel(pmc, 0, PMC_SW_WAKE_STATUS);
+ tegra_pmc_writel(pmc, 0, PMC_SW_WAKE2_STATUS);
+
+ tegra_pmc_writel(pmc, 0, PMC_WAKE_STATUS);
+ tegra_pmc_writel(pmc, 0, PMC_WAKE2_STATUS);
+
+ /* enable PMC wake */
+ if (data->hwirq >= 32)
+ offset = PMC_WAKE2_MASK;
+ else
+ offset = PMC_WAKE_MASK;
+
+ value = tegra_pmc_readl(pmc, offset);
+
+ if (on)
+ value |= 1 << bit;
+ else
+ value &= ~(1 << bit);
+
+ tegra_pmc_writel(pmc, value, offset);
+
+ return 0;
+}
+
static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
@@ -1954,6 +2014,49 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
+static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
+ unsigned int offset, bit;
+ u32 value;
+
+ if (data->hwirq == ULONG_MAX)
+ return 0;
+
+ offset = data->hwirq / 32;
+ bit = data->hwirq % 32;
+
+ if (data->hwirq >= 32)
+ offset = PMC_WAKE2_LEVEL;
+ else
+ offset = PMC_WAKE_LEVEL;
+
+ value = tegra_pmc_readl(pmc, offset);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_LEVEL_HIGH:
+ value |= 1 << bit;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_LEVEL_LOW:
+ value &= ~(1 << bit);
+ break;
+
+ case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
+ value ^= 1 << bit;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ tegra_pmc_writel(pmc, value, offset);
+
+ return 0;
+}
+
static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
@@ -2540,6 +2643,10 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
};
+static const struct tegra_wake_event tegra210_wake_events[] = {
+ TEGRA_WAKE_IRQ("rtc", 16, 2),
+};
+
static const struct tegra_pmc_soc tegra210_pmc_soc = {
.num_powergates = ARRAY_SIZE(tegra210_powergates),
.powergates = tegra210_powergates,
@@ -2557,10 +2664,14 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
+ .irq_set_wake = tegra210_pmc_irq_set_wake,
+ .irq_set_type = tegra210_pmc_irq_set_type,
.reset_sources = tegra210_reset_sources,
.num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
.reset_levels = NULL,
.num_reset_levels = 0,
+ .num_wake_events = ARRAY_SIZE(tegra210_wake_events),
+ .wake_events = tegra210_wake_events,
};
#define TEGRA186_IO_PAD_TABLE(_pad) \
--
2.7.4
^ permalink raw reply related
* [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 19:40 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree
In-Reply-To: <1563738060-30213-1-git-send-email-skomatineni@nvidia.com>
This patch adds support for clk: tegra210: suspend-resume.
All the CAR controller settings are lost on suspend when core
power goes off.
This patch has implementation for saving and restoring all PLLs
and clocks context during system suspend and resume to have the
clocks back to same state for normal operation.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-tegra210.c | 68 ++++++++++++++++++++++++++++++++++++++--
drivers/clk/tegra/clk.c | 14 +++++++++
drivers/clk/tegra/clk.h | 1 +
3 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 55a88c0824a5..68271873acc1 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -9,6 +9,7 @@
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/mutex.h>
@@ -220,11 +221,15 @@
#define CLK_M_DIVISOR_SHIFT 2
#define CLK_M_DIVISOR_MASK 0x3
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
+
#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
+#define CPU_SOFTRST_CTRL 0x380
#define LVL2_CLK_GATE_OVRA 0xf8
#define LVL2_CLK_GATE_OVRC 0x3a0
@@ -2825,6 +2830,7 @@ static int tegra210_enable_pllu(void)
struct tegra_clk_pll_freq_table *fentry;
struct tegra_clk_pll pllu;
u32 reg;
+ int ret;
for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
if (fentry->input_rate == pll_ref_freq)
@@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
reg |= PLL_ENABLE;
writel(reg, clk_base + PLLU_BASE);
- readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
- reg & PLL_BASE_LOCK, 2, 1000);
- if (!(reg & PLL_BASE_LOCK)) {
+ ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
+ if (ret) {
pr_err("Timed out waiting for PLL_U to lock\n");
return -ETIMEDOUT;
}
@@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
}
#ifdef CONFIG_PM_SLEEP
+#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
+#define car_writel(_val, _base, _off) \
+ writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
+
+static u32 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
+static u32 cpu_softrst_ctx[3];
+
+static int tegra210_clk_suspend(void)
+{
+ unsigned int i;
+
+ clk_save_context();
+
+ /*
+ * save the bootloader configured clock registers SPARE_REG0,
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
+ */
+ spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
+ misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
+ clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
+
+ for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+ cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
+
+ return 0;
+}
+
+static void tegra210_clk_resume(void)
+{
+ unsigned int i;
+
+ tegra_clk_osc_resume(clk_base);
+
+ /*
+ * restore the bootloader configured clock registers SPARE_REG0,
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
+ */
+ writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
+ writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
+ writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
+
+ for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+ car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
+
+ fence_udelay(5, clk_base);
+
+ tegra210_init_pllu();
+ clk_restore_context();
+}
+
static void tegra210_cpu_clock_suspend(void)
{
/* switch coresite to clk_m, save off original source */
@@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
}
#endif
+static struct syscore_ops tegra_clk_syscore_ops = {
+ .suspend = tegra210_clk_suspend,
+ .resume = tegra210_clk_resume,
+};
+
static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
.wait_for_reset = tegra210_wait_cpu_in_reset,
.disable_clock = tegra210_disable_cpu_clock,
@@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct device_node *np)
tegra210_mbist_clk_init();
tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+
+ register_syscore_ops(&tegra_clk_syscore_ops);
}
CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 573e3c967ae1..eb08047fd02f 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -23,6 +23,7 @@
#define CLK_OUT_ENB_W 0x364
#define CLK_OUT_ENB_X 0x280
#define CLK_OUT_ENB_Y 0x298
+#define CLK_ENB_PLLP_OUT_CPU BIT(31)
#define CLK_OUT_ENB_SET_L 0x320
#define CLK_OUT_ENB_CLR_L 0x324
#define CLK_OUT_ENB_SET_H 0x328
@@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
}
}
+void tegra_clk_set_pllp_out_cpu(bool enable)
+{
+ u32 val;
+
+ val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
+ if (enable)
+ val |= CLK_ENB_PLLP_OUT_CPU;
+ else
+ val &= ~CLK_ENB_PLLP_OUT_CPU;
+
+ writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
+}
+
struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
{
clk_base = regs;
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 562a3ee2d537..0ffa763c755b 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -863,6 +863,7 @@ int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
u8 frac_width, u8 flags);
void tegra_clk_sync_state_pll(struct clk_hw *hw);
void tegra_clk_osc_resume(void __iomem *clk_base);
+void tegra_clk_set_pllp_out_cpu(bool enable);
/* Combined read fence with delay */
#define fence_udelay(delay, reg) \
--
2.7.4
^ permalink raw reply related
* [PATCH 1/2] [PATCH] gpio: Replace usage of bare 'unsigned' with 'unsigned int'
From: Hennie Muller @ 2019-07-21 12:52 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, linux-gpio, linux-kernel
Cc: Hennie Muller
Fixes a couple of warnings by checkpatch and sparse.
Signed-off-by: Hennie Muller <hm@bitlabs.co.za>
---
drivers/gpio/gpio-viperboard.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index 9b604f13e302..c301c1d56dd2 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -79,7 +79,7 @@ MODULE_PARM_DESC(gpioa_freq,
/* ----- begin of gipo a chip -------------------------------------------- */
static int vprbrd_gpioa_get(struct gpio_chip *chip,
- unsigned offset)
+ unsigned int offset)
{
int ret, answer, error = 0;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -129,7 +129,7 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip,
}
static void vprbrd_gpioa_set(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -170,7 +170,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
}
static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
- unsigned offset)
+ unsigned int offset)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -207,7 +207,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
}
static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -251,8 +251,8 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
/* ----- begin of gipo b chip -------------------------------------------- */
-static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
- unsigned dir)
+static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
+ unsigned int dir)
{
struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
int ret;
@@ -273,7 +273,7 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
}
static int vprbrd_gpiob_get(struct gpio_chip *chip,
- unsigned offset)
+ unsigned int offset)
{
int ret;
u16 val;
@@ -305,7 +305,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip,
}
static void vprbrd_gpiob_set(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -338,7 +338,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
}
static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
- unsigned offset)
+ unsigned int offset)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -359,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
}
static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
int ret;
struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
--
2.22.0
^ permalink raw reply related
* [PATCH 2/2] [PATCH] gpio: Explicitly cast from __be16 to unsigned short
From: Hennie Muller @ 2019-07-21 12:52 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, linux-gpio, linux-kernel
Cc: Hennie Muller
In-Reply-To: <20190721125259.13990-1-hm@bitlabs.co.za>
cpu_to_be16 returns a __be16 value. This does not break anything
but does cause sparse to generate unnecessary warnings.
Signed-off-by: Hennie Muller <hm@bitlabs.co.za>
---
drivers/gpio/gpio-viperboard.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index c301c1d56dd2..7ff80d18bb70 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -258,8 +258,8 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
int ret;
gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR;
- gbmsg->val = cpu_to_be16(dir << offset);
- gbmsg->mask = cpu_to_be16(0x0001 << offset);
+ gbmsg->val = (__force u16)cpu_to_be16(dir << offset);
+ gbmsg->mask = (__force u16)cpu_to_be16(0x0001 << offset);
ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000,
@@ -321,8 +321,8 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
mutex_lock(&vb->lock);
gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL;
- gbmsg->val = cpu_to_be16(value << offset);
- gbmsg->mask = cpu_to_be16(0x0001 << offset);
+ gbmsg->val = (__force u16)cpu_to_be16(value << offset);
+ gbmsg->mask = (__force u16)cpu_to_be16(0x0001 << offset);
ret = usb_control_msg(vb->usb_dev,
usb_sndctrlpipe(vb->usb_dev, 0),
--
2.22.0
^ permalink raw reply related
* Re: [PATCH] gpio: don't WARN() on NULL descs if gpiolib is disabled
From: Linus Walleij @ 2019-07-20 19:44 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bartosz Golaszewski, open list:GPIO SUBSYSTEM,
linux-kernel@vger.kernel.org, Claus H . Stovgaard
In-Reply-To: <CAMpxmJWDTkhuWhfSJ-fkJ6r+7a3kErXafQ_sJLVgMf=cA=1+aQ@mail.gmail.com>
On Sat, Jul 20, 2019 at 8:03 PM Bartosz Golaszewski
<bgolaszewski@baylibre.com> wrote:
> I'll apply it to my local tree and send it for v5.3-rc2.
OK! Do you see it as bug fix so it should go in the rcs?
It pretty much needs to be a regression to go in there,
because this stub stuff blew up in my face before :/
Thanks,
Linus
^ permalink raw reply
* Re: [PATCH] Record interrupt status when an IRQ is masked
From: Linus Walleij @ 2019-07-20 19:42 UTC (permalink / raw)
To: Tomasz Kazimierz Motyl, Geert Uytterhoeven, Andy Shevchenko,
Thomas Petazzoni, Marek Vasut
Cc: Bartosz Golaszewski, open list:GPIO SUBSYSTEM, butterfly_tm666,
Tomasz Kazimierz Motyl
In-Reply-To: <20190720113155.12276-1-tomasz.motyl@se.com>
Looping in some experts on PCA953xx by top posting, sorry.
Linus Walleij
On Sat, Jul 20, 2019 at 1:32 PM Tomasz Kazimierz Motyl
<tomasz.motyl666@gmail.com> wrote:
>
> When one changes the state of any input pins of a PCA9555 chip before
> setting up the IRQ mask through i.e. SysFS e.g. echo "both" >
> /sys/class/gpio/gpioXYZ/edge the epoll_wait shall not exit on the subsequent
> change of the GPIO state. The reason behind it is that the IRQ status is not
> being saved when the IRQ is masked.
>
> ---
> drivers/gpio/gpio-pca953x.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
> index 7e76830b3368..088bef902156 100644
> --- a/drivers/gpio/gpio-pca953x.c
> +++ b/drivers/gpio/gpio-pca953x.c
> @@ -716,13 +716,16 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
> trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
> if (trigger[i])
> trigger_seen = true;
> +
> + /* We want the current status recorded in the chip->irq stat regardless the
> + * chip->irq_mask setting in order to have a change detected when the interrupt
> + * mask gets changed i.e. echo "both" > /sys/class/gpioXYZ/edge */
> + chip->irq_stat[i] = cur_stat[i];
> }
>
> if (!trigger_seen)
> return false;
>
> - memcpy(chip->irq_stat, cur_stat, NBANK(chip));
> -
> for (i = 0; i < NBANK(chip); i++) {
> pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
> (cur_stat[i] & chip->irq_trig_raise[i]);
> --
> 2.17.1
>
^ permalink raw reply
* Re: [PATCH] gpio: don't WARN() on NULL descs if gpiolib is disabled
From: Bartosz Golaszewski @ 2019-07-20 18:03 UTC (permalink / raw)
To: Linus Walleij
Cc: Bartosz Golaszewski, open list:GPIO SUBSYSTEM,
linux-kernel@vger.kernel.org, Claus H . Stovgaard
In-Reply-To: <CACRpkdaiZgK1EoaUxDtbm_GJHVjZU56e_qBQ-OF0mmwb5W8+tg@mail.gmail.com>
wt., 16 lip 2019 o 23:46 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> On Tue, Jul 9, 2019 at 4:20 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > wt., 9 lip 2019 o 15:30 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> > > I was thinking something like this in the stubs:
> > >
> > > gpiod_get[_index]() {
> > > return POISON;
> > > }
> > >
> > > gpiod_get[_index]_optional() {
> > > return NULL;
> > > }
> >
> > This is already being done.
>
> Ah it is.
>
> > > This way all gpiod_get() and optional calls are properly
> > > handled and the semantic that only _optional calls
> > > can return NULL is preserved. (Your patch would
> > > violate this.)
> > >
> >
> > Maybe I'm missing something, but I don't quite see how my patch
> > violates this behavior. :(
>
> I missed that we actually do pass a poison from the strict
> *get functions, mea culpa.
>
> Let's apply this, will you send me a pull request or shall I
> just try to apply it?
>
> Yours,
> Linus Walleij
I'll apply it to my local tree and send it for v5.3-rc2.
Bart
^ permalink raw reply
* [PATCH] pinctrl: pinctrl-single: add header include guard
From: Masahiro Yamada @ 2019-07-20 11:58 UTC (permalink / raw)
To: linux-gpio, Linus Walleij; +Cc: Masahiro Yamada, linux-kernel
Add a header include guard just in case.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
include/linux/platform_data/pinctrl-single.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/platform_data/pinctrl-single.h b/include/linux/platform_data/pinctrl-single.h
index 1cf36fdf9510..7473d3c4cabf 100644
--- a/include/linux/platform_data/pinctrl-single.h
+++ b/include/linux/platform_data/pinctrl-single.h
@@ -1,4 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _PINCTRL_SINGLE_H
+#define _PINCTRL_SINGLE_H
+
/**
* irq: optional wake-up interrupt
* rearm: optional soc specific rearm function
@@ -11,3 +15,5 @@ struct pcs_pdata {
int irq;
void (*rearm)(void);
};
+
+#endif /* _PINCTRL_SINGLE_H */
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v4 7/8] dt-bindings: arm: sunxi: add binding for Lichee Zero Plus core board
From: Icenowy Zheng @ 2019-07-20 11:39 UTC (permalink / raw)
To: linux-arm-kernel, Maxime Ripard
Cc: devicetree, Linus Walleij, linux-sunxi, linux-kernel, linux-gpio,
Chen-Yu Tsai, Rob Herring, linux-clk
In-Reply-To: <20190720101318.cwrvv5r42wxx5k4r@flea>
于 2019年7月20日 GMT+08:00 下午6:13:18, Maxime Ripard <maxime.ripard@bootlin.com> 写到:
>On Sat, Jul 13, 2019 at 11:46:33AM +0800, Icenowy Zheng wrote:
>> The Lichee Zero Plus is a core board made by Sipeed, with a microUSB
>> connector on it, TF slot or WSON8 SD chip, optional eMMC or SPI
>Flash.
>> It has a gold finger connector for expansion, and UART is available
>from
>> reserved pins w/ 2.54mm pitch. The board can use either SoChip S3 or
>> Allwinner V3L SoCs.
>>
>> Add the device tree binding of the basic version of the core board --
>> w/o eMMC or SPI Flash, w/ TF slot or WSON8 SD, and use S3 SoC.
>>
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> No changes since v3.
>>
>> Patch introduced in v2.
>>
>> Documentation/devicetree/bindings/arm/sunxi.yaml | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml
>b/Documentation/devicetree/bindings/arm/sunxi.yaml
>> index 000a00d12d6a..48c126a7a848 100644
>> --- a/Documentation/devicetree/bindings/arm/sunxi.yaml
>> +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
>> @@ -353,6 +353,11 @@ properties:
>> - const: licheepi,licheepi-zero
>> - const: allwinner,sun8i-v3s
>>
>> + - description: Lichee Zero Plus (with S3, without eMMC/SPI
>Flash)
>> + items:
>> + - const: sipeed,lichee-zero-plus
>> + - const: allwinner,sun8i-s3
>
>If the S3 is just a rebranded V3, then we should have the v3 compatile
>in that list too.
S3 is V3 with copackaged DDR3 DRAM.
It's pin incompatible w/ V3.
>
>Maxime
>
>--
>Maxime Ripard, Bootlin
>Embedded Linux and Kernel engineering
>https://bootlin.com
--
使用 K-9 Mail 发送自我的Android设备。
^ permalink raw reply
* [PATCH] Record interrupt status when an IRQ is masked
From: Tomasz Kazimierz Motyl @ 2019-07-20 11:31 UTC (permalink / raw)
To: linus.walleij, bgolaszewski, linux-gpio
Cc: butterfly_tm666, Tomasz Kazimierz Motyl
When one changes the state of any input pins of a PCA9555 chip before
setting up the IRQ mask through i.e. SysFS e.g. echo "both" >
/sys/class/gpio/gpioXYZ/edge the epoll_wait shall not exit on the subsequent
change of the GPIO state. The reason behind it is that the IRQ status is not
being saved when the IRQ is masked.
---
drivers/gpio/gpio-pca953x.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 7e76830b3368..088bef902156 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -716,13 +716,16 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
if (trigger[i])
trigger_seen = true;
+
+ /* We want the current status recorded in the chip->irq stat regardless the
+ * chip->irq_mask setting in order to have a change detected when the interrupt
+ * mask gets changed i.e. echo "both" > /sys/class/gpioXYZ/edge */
+ chip->irq_stat[i] = cur_stat[i];
}
if (!trigger_seen)
return false;
- memcpy(chip->irq_stat, cur_stat, NBANK(chip));
-
for (i = 0; i < NBANK(chip); i++) {
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
(cur_stat[i] & chip->irq_trig_raise[i]);
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v4 7/8] dt-bindings: arm: sunxi: add binding for Lichee Zero Plus core board
From: Maxime Ripard @ 2019-07-20 10:13 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Rob Herring, Chen-Yu Tsai, Linus Walleij, devicetree,
linux-arm-kernel, linux-kernel, linux-clk, linux-gpio,
linux-sunxi
In-Reply-To: <20190713034634.44585-8-icenowy@aosc.io>
[-- Attachment #1: Type: text/plain, Size: 1481 bytes --]
On Sat, Jul 13, 2019 at 11:46:33AM +0800, Icenowy Zheng wrote:
> The Lichee Zero Plus is a core board made by Sipeed, with a microUSB
> connector on it, TF slot or WSON8 SD chip, optional eMMC or SPI Flash.
> It has a gold finger connector for expansion, and UART is available from
> reserved pins w/ 2.54mm pitch. The board can use either SoChip S3 or
> Allwinner V3L SoCs.
>
> Add the device tree binding of the basic version of the core board --
> w/o eMMC or SPI Flash, w/ TF slot or WSON8 SD, and use S3 SoC.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> No changes since v3.
>
> Patch introduced in v2.
>
> Documentation/devicetree/bindings/arm/sunxi.yaml | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
> index 000a00d12d6a..48c126a7a848 100644
> --- a/Documentation/devicetree/bindings/arm/sunxi.yaml
> +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
> @@ -353,6 +353,11 @@ properties:
> - const: licheepi,licheepi-zero
> - const: allwinner,sun8i-v3s
>
> + - description: Lichee Zero Plus (with S3, without eMMC/SPI Flash)
> + items:
> + - const: sipeed,lichee-zero-plus
> + - const: allwinner,sun8i-s3
If the S3 is just a rebranded V3, then we should have the v3 compatile
in that list too.
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox