diff mbox series

[v1,01/17] soc: tegra: pmc: Add helper functions for PLLM overrides

Message ID 1574146234-3871-2-git-send-email-skomatineni@nvidia.com (mailing list archive)
State Superseded, archived
Headers show
Series Remove direct Tegra PMC access in clock driver | expand

Commit Message

Sowjanya Komatineni Nov. 19, 2019, 6:50 a.m. UTC
Tegra PMC has an option to override the CAR PLLM configuration during
the warmboot.

PLLM dividers and enable overrides from Tegra PMC are applicable only
when PLLM_OVERRIDE bit in PMC_PLLP_WB0_OVERRIDE register is set by Tegra
the bootloader. During warmboot based on this override enable, PLLM
divider and enable configuration from overrides in PMC or from CAR
module are used.

Currently PLLM overrides in Tegra PMC are directly programmed by the Tegra
clock driver and with this when PMC is in secure mode, any direct PMC
register access from non-secure world will not go through.

This patch adds helper functions for use by the Tegra clock driver to
configure these PLLM overrides during PLLM clock rate and state changes.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++-
 include/soc/tegra/pmc.h |   5 ++
 2 files changed, 205 insertions(+), 4 deletions(-)

Comments

Dmitry Osipenko Nov. 19, 2019, 7:32 p.m. UTC | #1
19.11.2019 09:50, Sowjanya Komatineni пишет:
> Tegra PMC has an option to override the CAR PLLM configuration during
> the warmboot.
> 
> PLLM dividers and enable overrides from Tegra PMC are applicable only
> when PLLM_OVERRIDE bit in PMC_PLLP_WB0_OVERRIDE register is set by Tegra
> the bootloader. During warmboot based on this override enable, PLLM
> divider and enable configuration from overrides in PMC or from CAR
> module are used.
> 
> Currently PLLM overrides in Tegra PMC are directly programmed by the Tegra
> clock driver and with this when PMC is in secure mode, any direct PMC
> register access from non-secure world will not go through.
> 
> This patch adds helper functions for use by the Tegra clock driver to
> configure these PLLM overrides during PLLM clock rate and state changes.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++-
>  include/soc/tegra/pmc.h |   5 ++
>  2 files changed, 205 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index 8db63cfba833..224e7cf8dc00 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -79,6 +79,14 @@
>  
>  #define PMC_PWR_DET			0x48
>  
> +#define TEGRA186_PMC_PLLP_WB0_OVERRIDE	0x4c
> +#define PMC_PLLP_WB0_OVERRIDE		0xf8
> +#define  PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12)
> +#define  PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11)
> +
> +#define TEGRA186_PMC_PLLM_WB0_OVERRIDE_FREQ	0x50
> +#define TEGRA186_PMC_PLLM_WB0_OVERRIDE_2	0x54
> +
>  #define PMC_SCRATCH0_MODE_RECOVERY	BIT(31)
>  #define PMC_SCRATCH0_MODE_BOOTLOADER	BIT(30)
>  #define PMC_SCRATCH0_MODE_RCM		BIT(1)
> @@ -122,6 +130,9 @@
>  #define IO_DPD2_STATUS			0x1c4
>  #define SEL_DPD_TIM			0x1c8
>  
> +#define PMC_PLLM_WB0_OVERRIDE_FREQ	0x1dc
> +#define PMC_PLLM_WB0_OVERRIDE_2		0x2b0
> +
>  #define PMC_SCRATCH54			0x258
>  #define  PMC_SCRATCH54_DATA_SHIFT	8
>  #define  PMC_SCRATCH54_ADDR_SHIFT	0
> @@ -182,6 +193,15 @@ struct tegra_pmc_regs {
>  	unsigned int rst_source_mask;
>  	unsigned int rst_level_shift;
>  	unsigned int rst_level_mask;
> +	unsigned int pllp_wb0_override;
> +	unsigned int pllm_wb0_override_freq;
> +	unsigned int pllm_wb0_override_2;
> +	unsigned int override_divm_shift;
> +	unsigned int override_divm_mask;
> +	unsigned int override_divn_shift;
> +	unsigned int override_divn_mask;
> +	unsigned int override_divp_shift;
> +	unsigned int override_divp_mask;
>  };
>  
>  struct tegra_wake_event {
> @@ -227,6 +247,7 @@ struct tegra_pmc_soc {
>  	bool needs_mbist_war;
>  	bool has_impl_33v_pwr;
>  	bool maybe_tz_only;
> +	bool has_pllm_wb0_override;
>  
>  	const struct tegra_io_pad_soc *io_pads;
>  	unsigned int num_io_pads;
> @@ -1156,6 +1177,99 @@ static void tegra_powergate_remove_all(struct device_node *parent)
>  	of_node_put(np);
>  }
>  
> +bool tegra_pmc_is_pllm_wb0_override_enabled(void)
> +{
> +	u32 val;
> +
> +	if (pmc->soc->has_pllm_wb0_override) {
> +		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
> +		return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) ? 1 : 0;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(tegra_pmc_is_pllm_wb0_override_enabled);
> +
> +bool tegra_pmc_is_pllm_wb0_enabled(void)
> +{
> +	u32 val;
> +
> +	if (pmc->soc->has_pllm_wb0_override) {
> +		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
> +		return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE) ? 1 : 0;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(tegra_pmc_is_pllm_wb0_enabled);
> +
> +void tegra_pmc_set_pllm_wb0_enable(bool enable)
> +{
> +	u32 val;
> +
> +	if (pmc->soc->has_pllm_wb0_override) {
> +		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
> +		if (enable)
> +			val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
> +		else
> +			val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
> +		tegra_pmc_writel(pmc, val, pmc->soc->regs->pllp_wb0_override);
> +	}
> +}
> +EXPORT_SYMBOL(tegra_pmc_set_pllm_wb0_enable);
> +
> +void tegra_pmc_get_pllm_wb0_mnp_overrides(u32 *divm, u32 *divn, u8 *divp)
> +{
> +	u32 val;
> +	unsigned int divnm_reg, divp_reg;
> +
> +	if (pmc->soc->has_pllm_wb0_override) {
> +		divnm_reg = pmc->soc->regs->pllm_wb0_override_freq;
> +		divp_reg = pmc->soc->regs->pllm_wb0_override_2;
> +
> +		if (tegra_pmc_is_pllm_wb0_override_enabled()) {
> +			val = tegra_pmc_readl(pmc, divnm_reg);
> +			*divm = (val >> pmc->soc->regs->override_divm_shift) &
> +				pmc->soc->regs->override_divm_mask;
> +			*divn = (val >> pmc->soc->regs->override_divn_shift) &
> +				pmc->soc->regs->override_divn_mask;
> +			val = tegra_pmc_readl(pmc, divp_reg);
> +			*divp = (val >> pmc->soc->regs->override_divp_shift) &
> +				pmc->soc->regs->override_divp_mask;
> +		}
> +	}
> +}
> +EXPORT_SYMBOL(tegra_pmc_get_pllm_wb0_mnp_overrides);
> +
> +void tegra_pmc_set_pllm_wb0_mnp_overrides(u32 divm, u32 divn, u8 divp)
> +{
> +	u32 val;
> +	unsigned int divnm_reg, divp_reg;
> +
> +	if (pmc->soc->has_pllm_wb0_override) {
> +		divnm_reg = pmc->soc->regs->pllm_wb0_override_freq;
> +		divp_reg = pmc->soc->regs->pllm_wb0_override_2;
> +
> +		if (tegra_pmc_is_pllm_wb0_override_enabled()) {
> +			val = tegra_pmc_readl(pmc, divp_reg);
> +			val &= ~(pmc->soc->regs->override_divp_mask <<
> +				 pmc->soc->regs->override_divp_shift);
> +			val |= (divp << pmc->soc->regs->override_divp_shift);
> +			tegra_pmc_writel(pmc, val, divp_reg);
> +
> +			val = tegra_pmc_readl(pmc, divnm_reg);
> +			val &= ~(pmc->soc->regs->override_divm_mask <<
> +				 pmc->soc->regs->override_divm_shift);
> +			val |= divm << pmc->soc->regs->override_divm_shift;
> +			val &= ~(pmc->soc->regs->override_divn_mask <<
> +				 pmc->soc->regs->override_divn_shift);
> +			val |= divn << pmc->soc->regs->override_divn_shift;
> +			tegra_pmc_writel(pmc, val, divnm_reg);
> +		}
> +	}
> +}
> +EXPORT_SYMBOL(tegra_pmc_set_pllm_wb0_mnp_overrides);

Hello Sowjanya,

The exporting isn't needed because both PMC and CaR drivers are
built-in. Same for the other patches.

[snip]
diff mbox series

Patch

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 8db63cfba833..224e7cf8dc00 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -79,6 +79,14 @@ 
 
 #define PMC_PWR_DET			0x48
 
+#define TEGRA186_PMC_PLLP_WB0_OVERRIDE	0x4c
+#define PMC_PLLP_WB0_OVERRIDE		0xf8
+#define  PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12)
+#define  PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11)
+
+#define TEGRA186_PMC_PLLM_WB0_OVERRIDE_FREQ	0x50
+#define TEGRA186_PMC_PLLM_WB0_OVERRIDE_2	0x54
+
 #define PMC_SCRATCH0_MODE_RECOVERY	BIT(31)
 #define PMC_SCRATCH0_MODE_BOOTLOADER	BIT(30)
 #define PMC_SCRATCH0_MODE_RCM		BIT(1)
@@ -122,6 +130,9 @@ 
 #define IO_DPD2_STATUS			0x1c4
 #define SEL_DPD_TIM			0x1c8
 
+#define PMC_PLLM_WB0_OVERRIDE_FREQ	0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2		0x2b0
+
 #define PMC_SCRATCH54			0x258
 #define  PMC_SCRATCH54_DATA_SHIFT	8
 #define  PMC_SCRATCH54_ADDR_SHIFT	0
@@ -182,6 +193,15 @@  struct tegra_pmc_regs {
 	unsigned int rst_source_mask;
 	unsigned int rst_level_shift;
 	unsigned int rst_level_mask;
+	unsigned int pllp_wb0_override;
+	unsigned int pllm_wb0_override_freq;
+	unsigned int pllm_wb0_override_2;
+	unsigned int override_divm_shift;
+	unsigned int override_divm_mask;
+	unsigned int override_divn_shift;
+	unsigned int override_divn_mask;
+	unsigned int override_divp_shift;
+	unsigned int override_divp_mask;
 };
 
 struct tegra_wake_event {
@@ -227,6 +247,7 @@  struct tegra_pmc_soc {
 	bool needs_mbist_war;
 	bool has_impl_33v_pwr;
 	bool maybe_tz_only;
+	bool has_pllm_wb0_override;
 
 	const struct tegra_io_pad_soc *io_pads;
 	unsigned int num_io_pads;
@@ -1156,6 +1177,99 @@  static void tegra_powergate_remove_all(struct device_node *parent)
 	of_node_put(np);
 }
 
+bool tegra_pmc_is_pllm_wb0_override_enabled(void)
+{
+	u32 val;
+
+	if (pmc->soc->has_pllm_wb0_override) {
+		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
+		return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) ? 1 : 0;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_pmc_is_pllm_wb0_override_enabled);
+
+bool tegra_pmc_is_pllm_wb0_enabled(void)
+{
+	u32 val;
+
+	if (pmc->soc->has_pllm_wb0_override) {
+		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
+		return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE) ? 1 : 0;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_pmc_is_pllm_wb0_enabled);
+
+void tegra_pmc_set_pllm_wb0_enable(bool enable)
+{
+	u32 val;
+
+	if (pmc->soc->has_pllm_wb0_override) {
+		val = tegra_pmc_readl(pmc, pmc->soc->regs->pllp_wb0_override);
+		if (enable)
+			val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+		else
+			val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+		tegra_pmc_writel(pmc, val, pmc->soc->regs->pllp_wb0_override);
+	}
+}
+EXPORT_SYMBOL(tegra_pmc_set_pllm_wb0_enable);
+
+void tegra_pmc_get_pllm_wb0_mnp_overrides(u32 *divm, u32 *divn, u8 *divp)
+{
+	u32 val;
+	unsigned int divnm_reg, divp_reg;
+
+	if (pmc->soc->has_pllm_wb0_override) {
+		divnm_reg = pmc->soc->regs->pllm_wb0_override_freq;
+		divp_reg = pmc->soc->regs->pllm_wb0_override_2;
+
+		if (tegra_pmc_is_pllm_wb0_override_enabled()) {
+			val = tegra_pmc_readl(pmc, divnm_reg);
+			*divm = (val >> pmc->soc->regs->override_divm_shift) &
+				pmc->soc->regs->override_divm_mask;
+			*divn = (val >> pmc->soc->regs->override_divn_shift) &
+				pmc->soc->regs->override_divn_mask;
+			val = tegra_pmc_readl(pmc, divp_reg);
+			*divp = (val >> pmc->soc->regs->override_divp_shift) &
+				pmc->soc->regs->override_divp_mask;
+		}
+	}
+}
+EXPORT_SYMBOL(tegra_pmc_get_pllm_wb0_mnp_overrides);
+
+void tegra_pmc_set_pllm_wb0_mnp_overrides(u32 divm, u32 divn, u8 divp)
+{
+	u32 val;
+	unsigned int divnm_reg, divp_reg;
+
+	if (pmc->soc->has_pllm_wb0_override) {
+		divnm_reg = pmc->soc->regs->pllm_wb0_override_freq;
+		divp_reg = pmc->soc->regs->pllm_wb0_override_2;
+
+		if (tegra_pmc_is_pllm_wb0_override_enabled()) {
+			val = tegra_pmc_readl(pmc, divp_reg);
+			val &= ~(pmc->soc->regs->override_divp_mask <<
+				 pmc->soc->regs->override_divp_shift);
+			val |= (divp << pmc->soc->regs->override_divp_shift);
+			tegra_pmc_writel(pmc, val, divp_reg);
+
+			val = tegra_pmc_readl(pmc, divnm_reg);
+			val &= ~(pmc->soc->regs->override_divm_mask <<
+				 pmc->soc->regs->override_divm_shift);
+			val |= divm << pmc->soc->regs->override_divm_shift;
+			val &= ~(pmc->soc->regs->override_divn_mask <<
+				 pmc->soc->regs->override_divn_shift);
+			val |= divn << pmc->soc->regs->override_divn_shift;
+			tegra_pmc_writel(pmc, val, divnm_reg);
+		}
+	}
+}
+EXPORT_SYMBOL(tegra_pmc_set_pllm_wb0_mnp_overrides);
+
 static const struct tegra_io_pad_soc *
 tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
 {
@@ -2345,6 +2459,72 @@  static const struct tegra_pmc_regs tegra20_pmc_regs = {
 	.rst_level_mask = 0x0,
 };
 
+static const struct tegra_pmc_regs tegra30_pmc_regs = {
+	.scratch0 = 0x50,
+	.dpd_req = 0x1b8,
+	.dpd_status = 0x1bc,
+	.dpd2_req = 0x1c0,
+	.dpd2_status = 0x1c4,
+	.rst_status = 0x1b4,
+	.rst_source_shift = 0x0,
+	.rst_source_mask = 0x7,
+	.rst_level_shift = 0x0,
+	.rst_level_mask = 0x0,
+	.pllp_wb0_override = PMC_PLLP_WB0_OVERRIDE,
+	.pllm_wb0_override_freq = PMC_PLLM_WB0_OVERRIDE_FREQ,
+	.pllm_wb0_override_2 = PMC_PLLM_WB0_OVERRIDE_FREQ,
+	.override_divm_shift = 0,
+	.override_divm_mask = 0x1f,
+	.override_divn_shift = 5,
+	.override_divn_mask = 0x3ff,
+	.override_divp_shift = 15,
+	.override_divp_mask = 0x7,
+};
+
+static const struct tegra_pmc_regs tegra114_pmc_regs = {
+	.scratch0 = 0x50,
+	.dpd_req = 0x1b8,
+	.dpd_status = 0x1bc,
+	.dpd2_req = 0x1c0,
+	.dpd2_status = 0x1c4,
+	.rst_status = 0x1b4,
+	.rst_source_shift = 0x0,
+	.rst_source_mask = 0x7,
+	.rst_level_shift = 0x0,
+	.rst_level_mask = 0x0,
+	.pllp_wb0_override = PMC_PLLP_WB0_OVERRIDE,
+	.pllm_wb0_override_freq = PMC_PLLM_WB0_OVERRIDE_FREQ,
+	.pllm_wb0_override_2 = PMC_PLLM_WB0_OVERRIDE_2,
+	.override_divm_shift = 0,
+	.override_divm_mask = 0xff,
+	.override_divn_shift = 8,
+	.override_divn_mask = 0xff,
+	.override_divp_shift = 27,
+	.override_divp_mask = 0x1,
+};
+
+static const struct tegra_pmc_regs tegra210_pmc_regs = {
+	.scratch0 = 0x50,
+	.dpd_req = 0x1b8,
+	.dpd_status = 0x1bc,
+	.dpd2_req = 0x1c0,
+	.dpd2_status = 0x1c4,
+	.rst_status = 0x1b4,
+	.rst_source_shift = 0x0,
+	.rst_source_mask = 0x7,
+	.rst_level_shift = 0x0,
+	.rst_level_mask = 0x0,
+	.pllp_wb0_override = PMC_PLLP_WB0_OVERRIDE,
+	.pllm_wb0_override_freq = PMC_PLLM_WB0_OVERRIDE_FREQ,
+	.pllm_wb0_override_2 = PMC_PLLM_WB0_OVERRIDE_2,
+	.override_divm_shift = 0,
+	.override_divm_mask = 0xff,
+	.override_divn_shift = 8,
+	.override_divn_mask = 0xff,
+	.override_divp_shift = 27,
+	.override_divp_mask = 0x1f,
+};
+
 static void tegra20_pmc_init(struct tegra_pmc *pmc)
 {
 	u32 value, osc, pmu, off;
@@ -2411,6 +2591,7 @@  static const struct tegra_pmc_soc tegra20_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = false,
 	.num_io_pads = 0,
 	.io_pads = NULL,
 	.num_pin_descs = 0,
@@ -2458,11 +2639,12 @@  static const struct tegra_pmc_soc tegra30_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = true,
 	.num_io_pads = 0,
 	.io_pads = NULL,
 	.num_pin_descs = 0,
 	.pin_descs = NULL,
-	.regs = &tegra20_pmc_regs,
+	.regs = &tegra30_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
 	.reset_sources = tegra30_reset_sources,
@@ -2509,11 +2691,12 @@  static const struct tegra_pmc_soc tegra114_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = true,
 	.num_io_pads = 0,
 	.io_pads = NULL,
 	.num_pin_descs = 0,
 	.pin_descs = NULL,
-	.regs = &tegra20_pmc_regs,
+	.regs = &tegra114_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
 	.reset_sources = tegra30_reset_sources,
@@ -2620,11 +2803,12 @@  static const struct tegra_pmc_soc tegra124_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = true,
 	.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
 	.io_pads = tegra124_io_pads,
 	.num_pin_descs = ARRAY_SIZE(tegra124_pin_descs),
 	.pin_descs = tegra124_pin_descs,
-	.regs = &tegra20_pmc_regs,
+	.regs = &tegra114_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
 	.reset_sources = tegra30_reset_sources,
@@ -2730,11 +2914,12 @@  static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.needs_mbist_war = true,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = true,
+	.has_pllm_wb0_override = true,
 	.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
 	.io_pads = tegra210_io_pads,
 	.num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
 	.pin_descs = tegra210_pin_descs,
-	.regs = &tegra20_pmc_regs,
+	.regs = &tegra210_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
 	.irq_set_wake = tegra210_pmc_irq_set_wake,
@@ -2807,6 +2992,15 @@  static const struct tegra_pmc_regs tegra186_pmc_regs = {
 	.rst_source_mask = 0x3C,
 	.rst_level_shift = 0x0,
 	.rst_level_mask = 0x3,
+	.pllp_wb0_override = TEGRA186_PMC_PLLP_WB0_OVERRIDE,
+	.pllm_wb0_override_freq = TEGRA186_PMC_PLLM_WB0_OVERRIDE_FREQ,
+	.pllm_wb0_override_2 = TEGRA186_PMC_PLLM_WB0_OVERRIDE_2,
+	.override_divm_shift = 0,
+	.override_divm_mask = 0xff,
+	.override_divn_shift = 8,
+	.override_divn_mask = 0xff,
+	.override_divp_shift = 27,
+	.override_divp_mask = 0x1f,
 };
 
 static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
@@ -2859,6 +3053,7 @@  static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = true,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = true,
 	.num_io_pads = ARRAY_SIZE(tegra186_io_pads),
 	.io_pads = tegra186_io_pads,
 	.num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
@@ -2941,6 +3136,7 @@  static const struct tegra_pmc_soc tegra194_pmc_soc = {
 	.needs_mbist_war = false,
 	.has_impl_33v_pwr = false,
 	.maybe_tz_only = false,
+	.has_pllm_wb0_override = false,
 	.num_io_pads = ARRAY_SIZE(tegra194_io_pads),
 	.io_pads = tegra194_io_pads,
 	.regs = &tegra186_pmc_regs,
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index 57e58faf660b..cbf23e0d3c55 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -20,6 +20,11 @@  struct reset_control;
 bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
 int tegra_pmc_cpu_power_on(unsigned int cpuid);
 int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);
+bool tegra_pmc_is_pllm_wb0_override_enabled(void);
+bool tegra_pmc_is_pllm_wb0_enabled(void);
+void tegra_pmc_set_pllm_wb0_enable(bool enable);
+void tegra_pmc_get_pllm_wb0_mnp_overrides(u32 *divm, u32 *divn, u8 *divp);
+void tegra_pmc_set_pllm_wb0_mnp_overrides(u32 divm, u32 divn, u8 divp);
 
 /*
  * powergate and I/O rail APIs