diff mbox series

[v6,01/15] clk: tegra: Add PLLE HW power sequencer control

Message ID 20210119085546.725005-2-jckuo@nvidia.com
State Superseded
Headers show
Series [v6,01/15] clk: tegra: Add PLLE HW power sequencer control | expand

Commit Message

JC Kuo Jan. 19, 2021, 8:55 a.m. UTC
PLLE has a hardware power sequencer logic which is a state machine
that can power on/off PLLE without any software intervention. The
sequencer has two inputs, one from XUSB UPHY PLL and the other from
SATA UPHY PLL. PLLE provides reference clock to XUSB and SATA UPHY
PLLs. When both of the downstream PLLs are powered-off, PLLE hardware
power sequencer will automatically power off PLLE for power saving.

XUSB and SATA UPHY PLLs also have their own hardware power sequencer
logic. XUSB UPHY PLL is shared between XUSB SuperSpeed ports and PCIE
controllers. The XUSB UPHY PLL hardware power sequencer has inputs
from XUSB and PCIE. When all of the XUSB SuperSpeed ports and PCIE
controllers are in low power state, XUSB UPHY PLL hardware power
sequencer automatically power off PLL and flags idle to PLLE hardware
power sequencer. Similar applies to SATA UPHY PLL.

PLLE hardware power sequencer has to be enabled after both downstream
sequencers are enabled.

This commit adds two helper functions:
1. tegra210_plle_hw_sequence_start() for XUSB PADCTL driver to enable
   PLLE hardware sequencer at proper time.

2. tegra210_plle_hw_sequence_is_enabled() for XUSB PADCTL driver to
   check whether PLLE hardware sequencer has been enabled or not.

Signed-off-by: JC Kuo <jckuo@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
---
v6:
   no change
v5: no change
v4:
   update copyright strings
v3:
   rename 'val' with 'value

 drivers/clk/tegra/clk-tegra210.c | 53 +++++++++++++++++++++++++++++++-
 include/linux/clk/tegra.h        |  4 ++-
 2 files changed, 55 insertions(+), 2 deletions(-)

Comments

Thierry Reding Jan. 19, 2021, 2:11 p.m. UTC | #1
On Tue, Jan 19, 2021 at 04:55:32PM +0800, JC Kuo wrote:
> PLLE has a hardware power sequencer logic which is a state machine
> that can power on/off PLLE without any software intervention. The
> sequencer has two inputs, one from XUSB UPHY PLL and the other from
> SATA UPHY PLL. PLLE provides reference clock to XUSB and SATA UPHY
> PLLs. When both of the downstream PLLs are powered-off, PLLE hardware
> power sequencer will automatically power off PLLE for power saving.
> 
> XUSB and SATA UPHY PLLs also have their own hardware power sequencer
> logic. XUSB UPHY PLL is shared between XUSB SuperSpeed ports and PCIE
> controllers. The XUSB UPHY PLL hardware power sequencer has inputs
> from XUSB and PCIE. When all of the XUSB SuperSpeed ports and PCIE
> controllers are in low power state, XUSB UPHY PLL hardware power
> sequencer automatically power off PLL and flags idle to PLLE hardware
> power sequencer. Similar applies to SATA UPHY PLL.
> 
> PLLE hardware power sequencer has to be enabled after both downstream
> sequencers are enabled.
> 
> This commit adds two helper functions:
> 1. tegra210_plle_hw_sequence_start() for XUSB PADCTL driver to enable
>    PLLE hardware sequencer at proper time.
> 
> 2. tegra210_plle_hw_sequence_is_enabled() for XUSB PADCTL driver to
>    check whether PLLE hardware sequencer has been enabled or not.
> 
> Signed-off-by: JC Kuo <jckuo@nvidia.com>
> Acked-by: Thierry Reding <treding@nvidia.com>
> ---
> v6:
>    no change
> v5: no change
> v4:
>    update copyright strings
> v3:
>    rename 'val' with 'value
> 
>  drivers/clk/tegra/clk-tegra210.c | 53 +++++++++++++++++++++++++++++++-
>  include/linux/clk/tegra.h        |  4 ++-
>  2 files changed, 55 insertions(+), 2 deletions(-)

Michael, Stephen,

we need these custom APIs to pass control of the hardware PLL sequencer
to the UPHY driver. Do you have any objections to this? Subsequent
patches in this series depend on these symbols, so it'd be great if you
could give an Acked-by on this and patch 2 (I'll Cc you on that right
away) so that they can go in via either the PHY or USB trees.

Thanks,
Thierry

> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index 68cbb98af567..b9099012dc7b 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
> - * Copyright (c) 2012-2014 NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2012-2020 NVIDIA CORPORATION.  All rights reserved.
>   */
>  
>  #include <linux/io.h>
> @@ -403,6 +403,14 @@ static unsigned long tegra210_input_freq[] = {
>  #define PLLRE_BASE_DEFAULT_MASK		0x1c000000
>  #define PLLRE_MISC0_WRITE_MASK		0x67ffffff
>  
> +/* PLLE */
> +#define PLLE_MISC_IDDQ_SW_CTRL		(1 << 14)
> +#define PLLE_AUX_USE_LOCKDET		(1 << 3)
> +#define PLLE_AUX_SS_SEQ_INCLUDE		(1 << 31)
> +#define PLLE_AUX_ENABLE_SWCTL		(1 << 4)
> +#define PLLE_AUX_SS_SWCTL		(1 << 6)
> +#define PLLE_AUX_SEQ_ENABLE		(1 << 24)
> +
>  /* PLLX */
>  #define PLLX_USE_DYN_RAMP		1
>  #define PLLX_BASE_LOCK			(1 << 27)
> @@ -489,6 +497,49 @@ static unsigned long tegra210_input_freq[] = {
>  #define PLLU_MISC0_WRITE_MASK		0xbfffffff
>  #define PLLU_MISC1_WRITE_MASK		0x00000007
>  
> +bool tegra210_plle_hw_sequence_is_enabled(void)
> +{
> +	u32 value;
> +
> +	value = readl_relaxed(clk_base + PLLE_AUX);
> +	if (value & PLLE_AUX_SEQ_ENABLE)
> +		return true;
> +
> +	return false;
> +}
> +EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_is_enabled);
> +
> +int tegra210_plle_hw_sequence_start(void)
> +{
> +	u32 value;
> +
> +	if (tegra210_plle_hw_sequence_is_enabled())
> +		return 0;
> +
> +	/* skip if PLLE is not enabled yet */
> +	value = readl_relaxed(clk_base + PLLE_MISC0);
> +	if (!(value & PLLE_MISC_LOCK))
> +		return -EIO;
> +
> +	value &= ~PLLE_MISC_IDDQ_SW_CTRL;
> +	writel_relaxed(value, clk_base + PLLE_MISC0);
> +
> +	value = readl_relaxed(clk_base + PLLE_AUX);
> +	value |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE);
> +	value &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
> +	writel_relaxed(value, clk_base + PLLE_AUX);
> +
> +	fence_udelay(1, clk_base);
> +
> +	value |= PLLE_AUX_SEQ_ENABLE;
> +	writel_relaxed(value, clk_base + PLLE_AUX);
> +
> +	fence_udelay(1, clk_base);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_start);
> +
>  void tegra210_xusb_pll_hw_control_enable(void)
>  {
>  	u32 val;
> diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
> index eb016fc9cc0b..f7ff722a03dd 100644
> --- a/include/linux/clk/tegra.h
> +++ b/include/linux/clk/tegra.h
> @@ -1,6 +1,6 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
>  /*
> - * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2012-2020, NVIDIA CORPORATION.  All rights reserved.
>   */
>  
>  #ifndef __LINUX_CLK_TEGRA_H_
> @@ -123,6 +123,8 @@ static inline void tegra_cpu_clock_resume(void)
>  }
>  #endif
>  
> +extern int tegra210_plle_hw_sequence_start(void);
> +extern bool tegra210_plle_hw_sequence_is_enabled(void);
>  extern void tegra210_xusb_pll_hw_control_enable(void);
>  extern void tegra210_xusb_pll_hw_sequence_start(void);
>  extern void tegra210_sata_pll_hw_control_enable(void);
> -- 
> 2.25.1
>
Stephen Boyd Feb. 11, 2021, 3:06 a.m. UTC | #2
Quoting JC Kuo (2021-01-19 00:55:32)
> PLLE has a hardware power sequencer logic which is a state machine
> that can power on/off PLLE without any software intervention. The
> sequencer has two inputs, one from XUSB UPHY PLL and the other from
> SATA UPHY PLL. PLLE provides reference clock to XUSB and SATA UPHY
> PLLs. When both of the downstream PLLs are powered-off, PLLE hardware
> power sequencer will automatically power off PLLE for power saving.
> 
> XUSB and SATA UPHY PLLs also have their own hardware power sequencer
> logic. XUSB UPHY PLL is shared between XUSB SuperSpeed ports and PCIE
> controllers. The XUSB UPHY PLL hardware power sequencer has inputs
> from XUSB and PCIE. When all of the XUSB SuperSpeed ports and PCIE
> controllers are in low power state, XUSB UPHY PLL hardware power
> sequencer automatically power off PLL and flags idle to PLLE hardware
> power sequencer. Similar applies to SATA UPHY PLL.
> 
> PLLE hardware power sequencer has to be enabled after both downstream
> sequencers are enabled.
> 
> This commit adds two helper functions:
> 1. tegra210_plle_hw_sequence_start() for XUSB PADCTL driver to enable
>    PLLE hardware sequencer at proper time.
> 
> 2. tegra210_plle_hw_sequence_is_enabled() for XUSB PADCTL driver to
>    check whether PLLE hardware sequencer has been enabled or not.
> 
> Signed-off-by: JC Kuo <jckuo@nvidia.com>
> Acked-by: Thierry Reding <treding@nvidia.com>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>
diff mbox series

Patch

diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 68cbb98af567..b9099012dc7b 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -1,6 +1,6 @@ 
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2014 NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2012-2020 NVIDIA CORPORATION.  All rights reserved.
  */
 
 #include <linux/io.h>
@@ -403,6 +403,14 @@  static unsigned long tegra210_input_freq[] = {
 #define PLLRE_BASE_DEFAULT_MASK		0x1c000000
 #define PLLRE_MISC0_WRITE_MASK		0x67ffffff
 
+/* PLLE */
+#define PLLE_MISC_IDDQ_SW_CTRL		(1 << 14)
+#define PLLE_AUX_USE_LOCKDET		(1 << 3)
+#define PLLE_AUX_SS_SEQ_INCLUDE		(1 << 31)
+#define PLLE_AUX_ENABLE_SWCTL		(1 << 4)
+#define PLLE_AUX_SS_SWCTL		(1 << 6)
+#define PLLE_AUX_SEQ_ENABLE		(1 << 24)
+
 /* PLLX */
 #define PLLX_USE_DYN_RAMP		1
 #define PLLX_BASE_LOCK			(1 << 27)
@@ -489,6 +497,49 @@  static unsigned long tegra210_input_freq[] = {
 #define PLLU_MISC0_WRITE_MASK		0xbfffffff
 #define PLLU_MISC1_WRITE_MASK		0x00000007
 
+bool tegra210_plle_hw_sequence_is_enabled(void)
+{
+	u32 value;
+
+	value = readl_relaxed(clk_base + PLLE_AUX);
+	if (value & PLLE_AUX_SEQ_ENABLE)
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_is_enabled);
+
+int tegra210_plle_hw_sequence_start(void)
+{
+	u32 value;
+
+	if (tegra210_plle_hw_sequence_is_enabled())
+		return 0;
+
+	/* skip if PLLE is not enabled yet */
+	value = readl_relaxed(clk_base + PLLE_MISC0);
+	if (!(value & PLLE_MISC_LOCK))
+		return -EIO;
+
+	value &= ~PLLE_MISC_IDDQ_SW_CTRL;
+	writel_relaxed(value, clk_base + PLLE_MISC0);
+
+	value = readl_relaxed(clk_base + PLLE_AUX);
+	value |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE);
+	value &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+	writel_relaxed(value, clk_base + PLLE_AUX);
+
+	fence_udelay(1, clk_base);
+
+	value |= PLLE_AUX_SEQ_ENABLE;
+	writel_relaxed(value, clk_base + PLLE_AUX);
+
+	fence_udelay(1, clk_base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra210_plle_hw_sequence_start);
+
 void tegra210_xusb_pll_hw_control_enable(void)
 {
 	u32 val;
diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
index eb016fc9cc0b..f7ff722a03dd 100644
--- a/include/linux/clk/tegra.h
+++ b/include/linux/clk/tegra.h
@@ -1,6 +1,6 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2012-2020, NVIDIA CORPORATION.  All rights reserved.
  */
 
 #ifndef __LINUX_CLK_TEGRA_H_
@@ -123,6 +123,8 @@  static inline void tegra_cpu_clock_resume(void)
 }
 #endif
 
+extern int tegra210_plle_hw_sequence_start(void);
+extern bool tegra210_plle_hw_sequence_is_enabled(void);
 extern void tegra210_xusb_pll_hw_control_enable(void);
 extern void tegra210_xusb_pll_hw_sequence_start(void);
 extern void tegra210_sata_pll_hw_control_enable(void);