diff mbox

[v5] clk: tegra: Initialize UTMIPLL when enabling PLLU

Message ID 1464280891-23036-1-git-send-email-rklein@nvidia.com
State Accepted
Delegated to: Thierry Reding
Headers show

Commit Message

Rhyland Klein May 26, 2016, 4:41 p.m. UTC
From: Andrew Bresticker <abrestic@chromium.org>

Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
clk-pll.c. UTMIPLL was being configured and set in HW control right
after registration. However, when the clock init_table is processed and
child clks of PLLU are enabled, it will call in and enable PLLU as
well, and initiate SW enabling sequence even though PLLU is already in
HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.

Doing the initialization once during pllu_enable means we configure it
properly into HW control.

A side effect of the commonization/localization of the UTMIPLL init
code, is that it corrects some errors that were present for earlier
generations. For instance, in clk-tegra124.c, it used to have:

define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)

when the correct shift to use is present in the new version:

define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)

which matches the Tegra124 TRM register definition.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>

[rklein: Merged in some later fixes for potential deadlocks]

Signed-off-by: Rhyland Klein <rklein@nvidia.com>
---
v5:
 - Initialized flags to 0 to avoid harmless spinlock warnings

v4:
 - Re-added examples in patch description

v3:
 - Flushed out description to describe this patch.

 drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-tegra114.c | 155 +------------
 drivers/clk/tegra/clk-tegra124.c | 156 +------------
 drivers/clk/tegra/clk-tegra210.c | 182 +--------------
 drivers/clk/tegra/clk-tegra30.c  | 113 +--------
 drivers/clk/tegra/clk.h          |  17 ++
 6 files changed, 510 insertions(+), 597 deletions(-)

Comments

Thierry Reding June 14, 2016, 11:33 a.m. UTC | #1
On Thu, May 26, 2016 at 12:41:31PM -0400, Rhyland Klein wrote:
> From: Andrew Bresticker <abrestic@chromium.org>
> 
> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
> clk-pll.c. UTMIPLL was being configured and set in HW control right
> after registration. However, when the clock init_table is processed and
> child clks of PLLU are enabled, it will call in and enable PLLU as
> well, and initiate SW enabling sequence even though PLLU is already in
> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> 
> Doing the initialization once during pllu_enable means we configure it
> properly into HW control.
> 
> A side effect of the commonization/localization of the UTMIPLL init
> code, is that it corrects some errors that were present for earlier
> generations. For instance, in clk-tegra124.c, it used to have:
> 
> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> 
> when the correct shift to use is present in the new version:
> 
> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> 
> which matches the Tegra124 TRM register definition.
> 
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> 
> [rklein: Merged in some later fixes for potential deadlocks]
> 
> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> ---
> v5:
>  - Initialized flags to 0 to avoid harmless spinlock warnings
> 
> v4:
>  - Re-added examples in patch description
> 
> v3:
>  - Flushed out description to describe this patch.
> 
>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
>  drivers/clk/tegra/clk.h          |  17 ++
>  6 files changed, 510 insertions(+), 597 deletions(-)

Applied, thanks.

Thierry
Jon Hunter June 17, 2016, 1:49 p.m. UTC | #2
Hi Thierry,

On 26/05/16 17:41, Rhyland Klein wrote:
> From: Andrew Bresticker <abrestic@chromium.org>
> 
> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
> clk-pll.c. UTMIPLL was being configured and set in HW control right
> after registration. However, when the clock init_table is processed and
> child clks of PLLU are enabled, it will call in and enable PLLU as
> well, and initiate SW enabling sequence even though PLLU is already in
> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> 
> Doing the initialization once during pllu_enable means we configure it
> properly into HW control.
> 
> A side effect of the commonization/localization of the UTMIPLL init
> code, is that it corrects some errors that were present for earlier
> generations. For instance, in clk-tegra124.c, it used to have:
> 
> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> 
> when the correct shift to use is present in the new version:
> 
> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> 
> which matches the Tegra124 TRM register definition.
> 
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> 
> [rklein: Merged in some later fixes for potential deadlocks]
> 
> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> ---
> v5:
>  - Initialized flags to 0 to avoid harmless spinlock warnings
> 
> v4:
>  - Re-added examples in patch description
> 
> v3:
>  - Flushed out description to describe this patch.
> 
>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
>  drivers/clk/tegra/clk.h          |  17 ++
>  6 files changed, 510 insertions(+), 597 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 4e194ecc8d5e..31e20110fae4 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c

...

> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
> +	unsigned long flags = 0, input_rate;
> +	unsigned int i;
> +	int ret = 0;
> +	u32 val;
> +
> +	if (!osc) {
> +		pr_err("%s: failed to get OSC clock\n", __func__);
> +		return -EINVAL;
> +	}
> +	input_rate = clk_hw_get_rate(osc);
> +
> +	if (pll->lock)
> +		spin_lock_irqsave(pll->lock, flags);
> +
> +	_clk_pll_enable(hw);
> +	ret = clk_pll_wait_for_lock(pll);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
> +		if (input_rate == utmi_parameters[i].osc_frequency)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(utmi_parameters)) {
> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	val = pll_readl_base(pll);
> +	val &= ~PLLU_BASE_OVERRIDE;
> +	pll_writel_base(val, pll);
> +
> +	/* Put PLLU under HW control */
> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> +
> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
> +	udelay(1);
> +
> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> +	udelay(1);
> +
> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
> +	val = pll_readl_base(pll);
> +	val &= ~PLLU_BASE_CLKENABLE_USB;
> +	pll_writel_base(val, pll);
> +
> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
> +		pr_debug("UTMIPLL already enabled\n");
> +		goto out;
> +	}
> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> +
> +	/* Program UTMIP PLL stable and active counts */
> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
> +			utmi_parameters[i].active_delay_count);
> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
> +
> +	/* Program UTMIP PLL delay and oscillator frequency counts */
> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
> +		utmi_parameters[i].enable_delay_count);
> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
> +		utmi_parameters[i].xtal_freq_count);
> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> +
> +	/* Remove power downs from UTMIP PLL control bits */
> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> +	udelay(100);

In next-20160617 I see that this udelay is now a usleep_range(100, 200)
and this is causing the following splat when the clock is enabled. I
don't think that we can use usleep here ...

[    0.224571] BUG: scheduling while atomic: swapper/0/1/0x00000003
[    0.224583] Modules linked in:
[    0.224597] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.7.0-rc3-next-20160617+ #277
[    0.224613] Hardware name: Google Pixel C (DT)
[    0.224623] Call trace:
[    0.224640] [<ffff0000080888b0>] dump_backtrace+0x0/0x1ac
[    0.224653] [<ffff000008088a70>] show_stack+0x14/0x1c
[    0.224669] [<ffff00000834a984>] dump_stack+0x8c/0xb0
[    0.224683] [<ffff00000814db30>] __schedule_bug+0x3c/0x50
[    0.224698] [<ffff0000087cd80c>] __schedule+0x470/0x56c
[    0.224708] [<ffff0000087cd948>] schedule+0x40/0xa4
[    0.224720] [<ffff0000087d0a14>] schedule_hrtimeout_range_clock+0x84/0xf0
[    0.224731] [<ffff0000087d0a90>] schedule_hrtimeout_range+0x10/0x18
[    0.224743] [<ffff0000087d05c8>] usleep_range+0x3c/0x44
[    0.224756] [<ffff0000086b25a4>] clk_pllu_tegra210_enable+0x200/0x2a8
[    0.224770] [<ffff000008698ef4>] clk_core_enable+0x5c/0x94
[    0.224780] [<ffff000008698edc>] clk_core_enable+0x44/0x94
[    0.224791] [<ffff000008698edc>] clk_core_enable+0x44/0x94
[    0.224801] [<ffff000008698edc>] clk_core_enable+0x44/0x94
[    0.224812] [<ffff0000086991b8>] clk_enable+0x24/0x40
[    0.224825] [<ffff00000842dd60>] tegra_powergate_enable_clocks.isra.6+0x90/0xd0
[    0.224840] [<ffff00000842e230>] tegra_powergate_power_up+0xa4/0x144
[    0.224851] [<ffff00000842ec40>] tegra_pmc_probe+0x6e0/0x8ec
[    0.224865] [<ffff0000084a72f4>] platform_drv_probe+0x50/0xbc
[    0.224879] [<ffff0000084a56fc>] driver_probe_device+0x1fc/0x29c
[    0.224890] [<ffff0000084a5840>] __driver_attach+0xa4/0xa8
[    0.224902] [<ffff0000084a3824>] bus_for_each_dev+0x58/0x98
[    0.224913] [<ffff0000084a5028>] driver_attach+0x20/0x28
[    0.224924] [<ffff0000084a4c48>] bus_add_driver+0x1c8/0x22c
[    0.224935] [<ffff0000084a60d8>] driver_register+0x68/0x108
[    0.224945] [<ffff0000084a7238>] __platform_driver_register+0x48/0x50
[    0.224960] [<ffff000008b37a30>] tegra_pmc_driver_init+0x18/0x20
[    0.224971] [<ffff000008081a54>] do_one_initcall+0x38/0x12c
[    0.224985] [<ffff000008b10ce0>] kernel_init_freeable+0x148/0x1ec
[    0.224997] [<ffff0000087caf98>] kernel_init+0x10/0x100
[    0.225008] [<ffff000008084e10>] ret_from_fork+0x10/0x40

Note the above is from some testing I am doing with adding power-domains for
XUSB in my local branch so you may not see the exact same dump in the mainline.

Cheers
Jon
Thierry Reding June 17, 2016, 3:23 p.m. UTC | #3
On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
> Hi Thierry,
> 
> On 26/05/16 17:41, Rhyland Klein wrote:
> > From: Andrew Bresticker <abrestic@chromium.org>
> > 
> > Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
> > clk-pll.c. UTMIPLL was being configured and set in HW control right
> > after registration. However, when the clock init_table is processed and
> > child clks of PLLU are enabled, it will call in and enable PLLU as
> > well, and initiate SW enabling sequence even though PLLU is already in
> > HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> > 
> > Doing the initialization once during pllu_enable means we configure it
> > properly into HW control.
> > 
> > A side effect of the commonization/localization of the UTMIPLL init
> > code, is that it corrects some errors that were present for earlier
> > generations. For instance, in clk-tegra124.c, it used to have:
> > 
> > define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> > 
> > when the correct shift to use is present in the new version:
> > 
> > define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> > 
> > which matches the Tegra124 TRM register definition.
> > 
> > Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> > 
> > [rklein: Merged in some later fixes for potential deadlocks]
> > 
> > Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> > ---
> > v5:
> >  - Initialized flags to 0 to avoid harmless spinlock warnings
> > 
> > v4:
> >  - Re-added examples in patch description
> > 
> > v3:
> >  - Flushed out description to describe this patch.
> > 
> >  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
> >  drivers/clk/tegra/clk-tegra114.c | 155 +------------
> >  drivers/clk/tegra/clk-tegra124.c | 156 +------------
> >  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
> >  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
> >  drivers/clk/tegra/clk.h          |  17 ++
> >  6 files changed, 510 insertions(+), 597 deletions(-)
> > 
> > diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> > index 4e194ecc8d5e..31e20110fae4 100644
> > --- a/drivers/clk/tegra/clk-pll.c
> > +++ b/drivers/clk/tegra/clk-pll.c
> 
> ...
> 
> > +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
> > +{
> > +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> > +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
> > +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
> > +	unsigned long flags = 0, input_rate;
> > +	unsigned int i;
> > +	int ret = 0;
> > +	u32 val;
> > +
> > +	if (!osc) {
> > +		pr_err("%s: failed to get OSC clock\n", __func__);
> > +		return -EINVAL;
> > +	}
> > +	input_rate = clk_hw_get_rate(osc);
> > +
> > +	if (pll->lock)
> > +		spin_lock_irqsave(pll->lock, flags);
> > +
> > +	_clk_pll_enable(hw);
> > +	ret = clk_pll_wait_for_lock(pll);
> > +	if (ret < 0)
> > +		goto out;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
> > +		if (input_rate == utmi_parameters[i].osc_frequency)
> > +			break;
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(utmi_parameters)) {
> > +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
> > +		ret = -EINVAL;
> > +		goto out;
> > +	}
> > +
> > +	val = pll_readl_base(pll);
> > +	val &= ~PLLU_BASE_OVERRIDE;
> > +	pll_writel_base(val, pll);
> > +
> > +	/* Put PLLU under HW control */
> > +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
> > +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
> > +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
> > +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
> > +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
> > +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +
> > +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
> > +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
> > +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
> > +	udelay(1);
> > +
> > +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> > +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	udelay(1);
> > +
> > +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
> > +	val = pll_readl_base(pll);
> > +	val &= ~PLLU_BASE_CLKENABLE_USB;
> > +	pll_writel_base(val, pll);
> > +
> > +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> > +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
> > +		pr_debug("UTMIPLL already enabled\n");
> > +		goto out;
> > +	}
> > +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
> > +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> > +
> > +	/* Program UTMIP PLL stable and active counts */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
> > +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
> > +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
> > +			utmi_parameters[i].active_delay_count);
> > +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
> > +
> > +	/* Program UTMIP PLL delay and oscillator frequency counts */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> > +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
> > +		utmi_parameters[i].enable_delay_count);
> > +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
> > +		utmi_parameters[i].xtal_freq_count);
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> > +
> > +	/* Remove power downs from UTMIP PLL control bits */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> > +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
> > +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> > +	udelay(100);
> 
> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
> and this is causing the following splat when the clock is enabled. I
> don't think that we can use usleep here ...

Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
for 100 microseconds here, so can we please find another way to do this?

Thierry
Rhyland Klein June 20, 2016, 5:24 p.m. UTC | #4
On 6/17/2016 11:23 AM, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
>> Hi Thierry,
>>
>> On 26/05/16 17:41, Rhyland Klein wrote:
>>> From: Andrew Bresticker <abrestic@chromium.org>
>>>
>>> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
>>> clk-pll.c. UTMIPLL was being configured and set in HW control right
>>> after registration. However, when the clock init_table is processed and
>>> child clks of PLLU are enabled, it will call in and enable PLLU as
>>> well, and initiate SW enabling sequence even though PLLU is already in
>>> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
>>>
>>> Doing the initialization once during pllu_enable means we configure it
>>> properly into HW control.
>>>
>>> A side effect of the commonization/localization of the UTMIPLL init
>>> code, is that it corrects some errors that were present for earlier
>>> generations. For instance, in clk-tegra124.c, it used to have:
>>>
>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
>>>
>>> when the correct shift to use is present in the new version:
>>>
>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
>>>
>>> which matches the Tegra124 TRM register definition.
>>>
>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>>>
>>> [rklein: Merged in some later fixes for potential deadlocks]
>>>
>>> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
>>> ---
>>> v5:
>>>  - Initialized flags to 0 to avoid harmless spinlock warnings
>>>
>>> v4:
>>>  - Re-added examples in patch description
>>>
>>> v3:
>>>  - Flushed out description to describe this patch.
>>>
>>>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
>>>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
>>>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
>>>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
>>>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
>>>  drivers/clk/tegra/clk.h          |  17 ++
>>>  6 files changed, 510 insertions(+), 597 deletions(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>>> index 4e194ecc8d5e..31e20110fae4 100644
>>> --- a/drivers/clk/tegra/clk-pll.c
>>> +++ b/drivers/clk/tegra/clk-pll.c
>>
>> ...
>>
>>> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
>>> +{
>>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>>> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
>>> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
>>> +	unsigned long flags = 0, input_rate;
>>> +	unsigned int i;
>>> +	int ret = 0;
>>> +	u32 val;
>>> +
>>> +	if (!osc) {
>>> +		pr_err("%s: failed to get OSC clock\n", __func__);
>>> +		return -EINVAL;
>>> +	}
>>> +	input_rate = clk_hw_get_rate(osc);
>>> +
>>> +	if (pll->lock)
>>> +		spin_lock_irqsave(pll->lock, flags);
>>> +
>>> +	_clk_pll_enable(hw);
>>> +	ret = clk_pll_wait_for_lock(pll);
>>> +	if (ret < 0)
>>> +		goto out;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
>>> +		if (input_rate == utmi_parameters[i].osc_frequency)
>>> +			break;
>>> +	}
>>> +
>>> +	if (i == ARRAY_SIZE(utmi_parameters)) {
>>> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
>>> +		ret = -EINVAL;
>>> +		goto out;
>>> +	}
>>> +
>>> +	val = pll_readl_base(pll);
>>> +	val &= ~PLLU_BASE_OVERRIDE;
>>> +	pll_writel_base(val, pll);
>>> +
>>> +	/* Put PLLU under HW control */
>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
>>> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
>>> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
>>> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
>>> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
>>> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
>>> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
>>> +	udelay(1);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	udelay(1);
>>> +
>>> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
>>> +	val = pll_readl_base(pll);
>>> +	val &= ~PLLU_BASE_CLKENABLE_USB;
>>> +	pll_writel_base(val, pll);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
>>> +		pr_debug("UTMIPLL already enabled\n");
>>> +		goto out;
>>> +	}
>>> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
>>> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>> +
>>> +	/* Program UTMIP PLL stable and active counts */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
>>> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
>>> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
>>> +			utmi_parameters[i].active_delay_count);
>>> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
>>> +
>>> +	/* Program UTMIP PLL delay and oscillator frequency counts */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
>>> +		utmi_parameters[i].enable_delay_count);
>>> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
>>> +		utmi_parameters[i].xtal_freq_count);
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>> +
>>> +	/* Remove power downs from UTMIP PLL control bits */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
>>> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>> +	udelay(100);
>>
>> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
>> and this is causing the following splat when the clock is enabled. I
>> don't think that we can use usleep here ...
> 
> Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
> for 100 microseconds here, so can we please find another way to do this?
> 

I discussed this with some people downstream, and they said we should
never need to wait 100 microseconds, and should never need more then
1-2us for delays to take effect.

Therefore I would think changing this to a udelay(2) should be alright.
I simply enabled the clock, and it seemed to be fine. I'll send a new
version with that change if you want.

-rhyland
Rhyland Klein June 27, 2016, 6:11 p.m. UTC | #5
Jonathan, can you confirm replacing usleep_range(100, 200) with udelay(2) works for you?

-rhyland

-----Original Message-----
From: Thierry Reding [mailto:thierry.reding@gmail.com] 
Sent: Friday, June 17, 2016 11:24 AM
To: Jonathan Hunter
Cc: Rhyland Klein; Peter De Schrijver; Mike Turquette; Stephen Warren; Stephen Boyd; Alexandre Courbot; linux-clk@vger.kernel.org; linux-tegra@vger.kernel.org; linux-kernel@vger.kernel.org; Andrew Bresticker
Subject: Re: [PATCH v5] clk: tegra: Initialize UTMIPLL when enabling PLLU

* PGP Signed by an unknown key

On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
> Hi Thierry,
> 
> On 26/05/16 17:41, Rhyland Klein wrote:
> > From: Andrew Bresticker <abrestic@chromium.org>
> > 
> > Move the UTMIPLL initialization code form clk-tegra<chip>.c files 
> > into clk-pll.c. UTMIPLL was being configured and set in HW control 
> > right after registration. However, when the clock init_table is 
> > processed and child clks of PLLU are enabled, it will call in and 
> > enable PLLU as well, and initiate SW enabling sequence even though 
> > PLLU is already in HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> > 
> > Doing the initialization once during pllu_enable means we configure 
> > it properly into HW control.
> > 
> > A side effect of the commonization/localization of the UTMIPLL init 
> > code, is that it corrects some errors that were present for earlier 
> > generations. For instance, in clk-tegra124.c, it used to have:
> > 
> > define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> > 
> > when the correct shift to use is present in the new version:
> > 
> > define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> > 
> > which matches the Tegra124 TRM register definition.
> > 
> > Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> > 
> > [rklein: Merged in some later fixes for potential deadlocks]
> > 
> > Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> > ---
> > v5:
> >  - Initialized flags to 0 to avoid harmless spinlock warnings
> > 
> > v4:
> >  - Re-added examples in patch description
> > 
> > v3:
> >  - Flushed out description to describe this patch.
> > 
> >  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
> >  drivers/clk/tegra/clk-tegra114.c | 155 +------------  
> > drivers/clk/tegra/clk-tegra124.c | 156 +------------  
> > drivers/clk/tegra/clk-tegra210.c | 182 +--------------  
> > drivers/clk/tegra/clk-tegra30.c  | 113 +--------
> >  drivers/clk/tegra/clk.h          |  17 ++
> >  6 files changed, 510 insertions(+), 597 deletions(-)
> > 
> > diff --git a/drivers/clk/tegra/clk-pll.c 
> > b/drivers/clk/tegra/clk-pll.c index 4e194ecc8d5e..31e20110fae4 
> > 100644
> > --- a/drivers/clk/tegra/clk-pll.c
> > +++ b/drivers/clk/tegra/clk-pll.c
> 
> ...
> 
> > +static int clk_pllu_tegra210_enable(struct clk_hw *hw) {
> > +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> > +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
> > +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
> > +	unsigned long flags = 0, input_rate;
> > +	unsigned int i;
> > +	int ret = 0;
> > +	u32 val;
> > +
> > +	if (!osc) {
> > +		pr_err("%s: failed to get OSC clock\n", __func__);
> > +		return -EINVAL;
> > +	}
> > +	input_rate = clk_hw_get_rate(osc);
> > +
> > +	if (pll->lock)
> > +		spin_lock_irqsave(pll->lock, flags);
> > +
> > +	_clk_pll_enable(hw);
> > +	ret = clk_pll_wait_for_lock(pll);
> > +	if (ret < 0)
> > +		goto out;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
> > +		if (input_rate == utmi_parameters[i].osc_frequency)
> > +			break;
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(utmi_parameters)) {
> > +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
> > +		ret = -EINVAL;
> > +		goto out;
> > +	}
> > +
> > +	val = pll_readl_base(pll);
> > +	val &= ~PLLU_BASE_OVERRIDE;
> > +	pll_writel_base(val, pll);
> > +
> > +	/* Put PLLU under HW control */
> > +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
> > +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
> > +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
> > +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
> > +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
> > +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +
> > +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
> > +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
> > +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
> > +	udelay(1);
> > +
> > +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> > +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> > +	udelay(1);
> > +
> > +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
> > +	val = pll_readl_base(pll);
> > +	val &= ~PLLU_BASE_CLKENABLE_USB;
> > +	pll_writel_base(val, pll);
> > +
> > +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> > +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
> > +		pr_debug("UTMIPLL already enabled\n");
> > +		goto out;
> > +	}
> > +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
> > +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> > +
> > +	/* Program UTMIP PLL stable and active counts */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
> > +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
> > +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
> > +			utmi_parameters[i].active_delay_count);
> > +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
> > +
> > +	/* Program UTMIP PLL delay and oscillator frequency counts */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> > +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
> > +		utmi_parameters[i].enable_delay_count);
> > +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
> > +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
> > +		utmi_parameters[i].xtal_freq_count);
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> > +
> > +	/* Remove power downs from UTMIP PLL control bits */
> > +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> > +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
> > +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
> > +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> > +	udelay(100);
> 
> In next-20160617 I see that this udelay is now a usleep_range(100, 
> 200) and this is causing the following splat when the clock is 
> enabled. I don't think that we can use usleep here ...

Okay, I'll back out the patch. I'd really prefer to avoid busy-looping for 100 microseconds here, so can we please find another way to do this?

Thierry

* Unknown Key
* 0x7F3EB3A1
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jon Hunter June 28, 2016, 4:30 p.m. UTC | #6
Hi Rhyland,

On 27/06/16 19:11, Rhyland Klein wrote:
> Jonathan, can you confirm replacing usleep_range(100, 200) with udelay(2) works for you?

Yes for me, using a udelay(2) does seem to work. I have made sure that a
usb device is still detected on the Jetson TX1. However, I am not sure
the best way to test this thoroughly.

If we do make this change it would be good to propagate downstream as
well to get wider testing.

Cheers
Jon
Rhyland Klein June 30, 2016, 3:32 p.m. UTC | #7
On 6/17/2016 11:23 AM, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
>> Hi Thierry,
>>
>> On 26/05/16 17:41, Rhyland Klein wrote:
>>> From: Andrew Bresticker <abrestic@chromium.org>
>>>
>>> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
>>> clk-pll.c. UTMIPLL was being configured and set in HW control right
>>> after registration. However, when the clock init_table is processed and
>>> child clks of PLLU are enabled, it will call in and enable PLLU as
>>> well, and initiate SW enabling sequence even though PLLU is already in
>>> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
>>>
>>> Doing the initialization once during pllu_enable means we configure it
>>> properly into HW control.
>>>
>>> A side effect of the commonization/localization of the UTMIPLL init
>>> code, is that it corrects some errors that were present for earlier
>>> generations. For instance, in clk-tegra124.c, it used to have:
>>>
>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
>>>
>>> when the correct shift to use is present in the new version:
>>>
>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
>>>
>>> which matches the Tegra124 TRM register definition.
>>>
>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>>>
>>> [rklein: Merged in some later fixes for potential deadlocks]
>>>
>>> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
>>> ---
>>> v5:
>>>  - Initialized flags to 0 to avoid harmless spinlock warnings
>>>
>>> v4:
>>>  - Re-added examples in patch description
>>>
>>> v3:
>>>  - Flushed out description to describe this patch.
>>>
>>>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
>>>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
>>>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
>>>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
>>>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
>>>  drivers/clk/tegra/clk.h          |  17 ++
>>>  6 files changed, 510 insertions(+), 597 deletions(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>>> index 4e194ecc8d5e..31e20110fae4 100644
>>> --- a/drivers/clk/tegra/clk-pll.c
>>> +++ b/drivers/clk/tegra/clk-pll.c
>>
>> ...
>>
>>> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
>>> +{
>>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>>> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
>>> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
>>> +	unsigned long flags = 0, input_rate;
>>> +	unsigned int i;
>>> +	int ret = 0;
>>> +	u32 val;
>>> +
>>> +	if (!osc) {
>>> +		pr_err("%s: failed to get OSC clock\n", __func__);
>>> +		return -EINVAL;
>>> +	}
>>> +	input_rate = clk_hw_get_rate(osc);
>>> +
>>> +	if (pll->lock)
>>> +		spin_lock_irqsave(pll->lock, flags);
>>> +
>>> +	_clk_pll_enable(hw);
>>> +	ret = clk_pll_wait_for_lock(pll);
>>> +	if (ret < 0)
>>> +		goto out;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
>>> +		if (input_rate == utmi_parameters[i].osc_frequency)
>>> +			break;
>>> +	}
>>> +
>>> +	if (i == ARRAY_SIZE(utmi_parameters)) {
>>> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
>>> +		ret = -EINVAL;
>>> +		goto out;
>>> +	}
>>> +
>>> +	val = pll_readl_base(pll);
>>> +	val &= ~PLLU_BASE_OVERRIDE;
>>> +	pll_writel_base(val, pll);
>>> +
>>> +	/* Put PLLU under HW control */
>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
>>> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
>>> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
>>> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
>>> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
>>> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
>>> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
>>> +	udelay(1);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>> +	udelay(1);
>>> +
>>> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
>>> +	val = pll_readl_base(pll);
>>> +	val &= ~PLLU_BASE_CLKENABLE_USB;
>>> +	pll_writel_base(val, pll);
>>> +
>>> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
>>> +		pr_debug("UTMIPLL already enabled\n");
>>> +		goto out;
>>> +	}
>>> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
>>> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>> +
>>> +	/* Program UTMIP PLL stable and active counts */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
>>> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
>>> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
>>> +			utmi_parameters[i].active_delay_count);
>>> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
>>> +
>>> +	/* Program UTMIP PLL delay and oscillator frequency counts */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
>>> +		utmi_parameters[i].enable_delay_count);
>>> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
>>> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
>>> +		utmi_parameters[i].xtal_freq_count);
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>> +
>>> +	/* Remove power downs from UTMIP PLL control bits */
>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
>>> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>> +	udelay(100);
>>
>> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
>> and this is causing the following splat when the clock is enabled. I
>> don't think that we can use usleep here ...
> 
> Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
> for 100 microseconds here, so can we please find another way to do this?
> 

It looks like we should be able to use a short udelay of 1-2us. I
believe the original code had udelay(1) and I know Jon and I tested
udelay(2) and it was ok.

Do you want me to send another patch rev with just the udelay change or
are you going to just modify it locally yourself?

-rhyland
Thierry Reding June 30, 2016, 3:37 p.m. UTC | #8
On Thu, Jun 30, 2016 at 11:32:14AM -0400, Rhyland Klein wrote:
> On 6/17/2016 11:23 AM, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
> >> Hi Thierry,
> >>
> >> On 26/05/16 17:41, Rhyland Klein wrote:
> >>> From: Andrew Bresticker <abrestic@chromium.org>
> >>>
> >>> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
> >>> clk-pll.c. UTMIPLL was being configured and set in HW control right
> >>> after registration. However, when the clock init_table is processed and
> >>> child clks of PLLU are enabled, it will call in and enable PLLU as
> >>> well, and initiate SW enabling sequence even though PLLU is already in
> >>> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> >>>
> >>> Doing the initialization once during pllu_enable means we configure it
> >>> properly into HW control.
> >>>
> >>> A side effect of the commonization/localization of the UTMIPLL init
> >>> code, is that it corrects some errors that were present for earlier
> >>> generations. For instance, in clk-tegra124.c, it used to have:
> >>>
> >>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> >>>
> >>> when the correct shift to use is present in the new version:
> >>>
> >>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> >>>
> >>> which matches the Tegra124 TRM register definition.
> >>>
> >>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> >>>
> >>> [rklein: Merged in some later fixes for potential deadlocks]
> >>>
> >>> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> >>> ---
> >>> v5:
> >>>  - Initialized flags to 0 to avoid harmless spinlock warnings
> >>>
> >>> v4:
> >>>  - Re-added examples in patch description
> >>>
> >>> v3:
> >>>  - Flushed out description to describe this patch.
> >>>
> >>>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
> >>>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
> >>>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
> >>>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
> >>>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
> >>>  drivers/clk/tegra/clk.h          |  17 ++
> >>>  6 files changed, 510 insertions(+), 597 deletions(-)
> >>>
> >>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> >>> index 4e194ecc8d5e..31e20110fae4 100644
> >>> --- a/drivers/clk/tegra/clk-pll.c
> >>> +++ b/drivers/clk/tegra/clk-pll.c
> >>
> >> ...
> >>
> >>> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
> >>> +{
> >>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> >>> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
> >>> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
> >>> +	unsigned long flags = 0, input_rate;
> >>> +	unsigned int i;
> >>> +	int ret = 0;
> >>> +	u32 val;
> >>> +
> >>> +	if (!osc) {
> >>> +		pr_err("%s: failed to get OSC clock\n", __func__);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +	input_rate = clk_hw_get_rate(osc);
> >>> +
> >>> +	if (pll->lock)
> >>> +		spin_lock_irqsave(pll->lock, flags);
> >>> +
> >>> +	_clk_pll_enable(hw);
> >>> +	ret = clk_pll_wait_for_lock(pll);
> >>> +	if (ret < 0)
> >>> +		goto out;
> >>> +
> >>> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
> >>> +		if (input_rate == utmi_parameters[i].osc_frequency)
> >>> +			break;
> >>> +	}
> >>> +
> >>> +	if (i == ARRAY_SIZE(utmi_parameters)) {
> >>> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
> >>> +		ret = -EINVAL;
> >>> +		goto out;
> >>> +	}
> >>> +
> >>> +	val = pll_readl_base(pll);
> >>> +	val &= ~PLLU_BASE_OVERRIDE;
> >>> +	pll_writel_base(val, pll);
> >>> +
> >>> +	/* Put PLLU under HW control */
> >>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
> >>> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
> >>> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
> >>> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
> >>> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
> >>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>> +
> >>> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
> >>> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
> >>> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
> >>> +	udelay(1);
> >>> +
> >>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> >>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>> +	udelay(1);
> >>> +
> >>> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
> >>> +	val = pll_readl_base(pll);
> >>> +	val &= ~PLLU_BASE_CLKENABLE_USB;
> >>> +	pll_writel_base(val, pll);
> >>> +
> >>> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> >>> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
> >>> +		pr_debug("UTMIPLL already enabled\n");
> >>> +		goto out;
> >>> +	}
> >>> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
> >>> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> >>> +
> >>> +	/* Program UTMIP PLL stable and active counts */
> >>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
> >>> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
> >>> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
> >>> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
> >>> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
> >>> +			utmi_parameters[i].active_delay_count);
> >>> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
> >>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
> >>> +
> >>> +	/* Program UTMIP PLL delay and oscillator frequency counts */
> >>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> >>> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
> >>> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
> >>> +		utmi_parameters[i].enable_delay_count);
> >>> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
> >>> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
> >>> +		utmi_parameters[i].xtal_freq_count);
> >>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> >>> +
> >>> +	/* Remove power downs from UTMIP PLL control bits */
> >>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> >>> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
> >>> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
> >>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> >>> +	udelay(100);
> >>
> >> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
> >> and this is causing the following splat when the clock is enabled. I
> >> don't think that we can use usleep here ...
> > 
> > Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
> > for 100 microseconds here, so can we please find another way to do this?
> > 
> 
> It looks like we should be able to use a short udelay of 1-2us. I
> believe the original code had udelay(1) and I know Jon and I tested
> udelay(2) and it was ok.

What original code? The downstream driver? If so I'd be leaning towards
simply adopting that. Everything else in this functions seems to want to
wait for 1 us, seems natural for this to do as well.

> Do you want me to send another patch rev with just the udelay change or
> are you going to just modify it locally yourself?

No need to resend, I'll cherry-pick the patch from next-20160617 and
make this into udelay(1).

Thierry
Rhyland Klein June 30, 2016, 3:40 p.m. UTC | #9
On 6/30/2016 11:37 AM, Thierry Reding wrote:
> * PGP Signed by an unknown key
> 
> On Thu, Jun 30, 2016 at 11:32:14AM -0400, Rhyland Klein wrote:
>> On 6/17/2016 11:23 AM, Thierry Reding wrote:
>>>> Old Signed by an unknown key
>>>
>>> On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
>>>> Hi Thierry,
>>>>
>>>> On 26/05/16 17:41, Rhyland Klein wrote:
>>>>> From: Andrew Bresticker <abrestic@chromium.org>
>>>>>
>>>>> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
>>>>> clk-pll.c. UTMIPLL was being configured and set in HW control right
>>>>> after registration. However, when the clock init_table is processed and
>>>>> child clks of PLLU are enabled, it will call in and enable PLLU as
>>>>> well, and initiate SW enabling sequence even though PLLU is already in
>>>>> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
>>>>>
>>>>> Doing the initialization once during pllu_enable means we configure it
>>>>> properly into HW control.
>>>>>
>>>>> A side effect of the commonization/localization of the UTMIPLL init
>>>>> code, is that it corrects some errors that were present for earlier
>>>>> generations. For instance, in clk-tegra124.c, it used to have:
>>>>>
>>>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
>>>>>
>>>>> when the correct shift to use is present in the new version:
>>>>>
>>>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
>>>>>
>>>>> which matches the Tegra124 TRM register definition.
>>>>>
>>>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>>>>>
>>>>> [rklein: Merged in some later fixes for potential deadlocks]
>>>>>
>>>>> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
>>>>> ---
>>>>> v5:
>>>>>  - Initialized flags to 0 to avoid harmless spinlock warnings
>>>>>
>>>>> v4:
>>>>>  - Re-added examples in patch description
>>>>>
>>>>> v3:
>>>>>  - Flushed out description to describe this patch.
>>>>>
>>>>>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
>>>>>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
>>>>>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
>>>>>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
>>>>>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
>>>>>  drivers/clk/tegra/clk.h          |  17 ++
>>>>>  6 files changed, 510 insertions(+), 597 deletions(-)
>>>>>
>>>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>>>>> index 4e194ecc8d5e..31e20110fae4 100644
>>>>> --- a/drivers/clk/tegra/clk-pll.c
>>>>> +++ b/drivers/clk/tegra/clk-pll.c
>>>>
>>>> ...
>>>>
>>>>> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
>>>>> +{
>>>>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>>>>> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
>>>>> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
>>>>> +	unsigned long flags = 0, input_rate;
>>>>> +	unsigned int i;
>>>>> +	int ret = 0;
>>>>> +	u32 val;
>>>>> +
>>>>> +	if (!osc) {
>>>>> +		pr_err("%s: failed to get OSC clock\n", __func__);
>>>>> +		return -EINVAL;
>>>>> +	}
>>>>> +	input_rate = clk_hw_get_rate(osc);
>>>>> +
>>>>> +	if (pll->lock)
>>>>> +		spin_lock_irqsave(pll->lock, flags);
>>>>> +
>>>>> +	_clk_pll_enable(hw);
>>>>> +	ret = clk_pll_wait_for_lock(pll);
>>>>> +	if (ret < 0)
>>>>> +		goto out;
>>>>> +
>>>>> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
>>>>> +		if (input_rate == utmi_parameters[i].osc_frequency)
>>>>> +			break;
>>>>> +	}
>>>>> +
>>>>> +	if (i == ARRAY_SIZE(utmi_parameters)) {
>>>>> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
>>>>> +		ret = -EINVAL;
>>>>> +		goto out;
>>>>> +	}
>>>>> +
>>>>> +	val = pll_readl_base(pll);
>>>>> +	val &= ~PLLU_BASE_OVERRIDE;
>>>>> +	pll_writel_base(val, pll);
>>>>> +
>>>>> +	/* Put PLLU under HW control */
>>>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>>>> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
>>>>> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
>>>>> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
>>>>> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
>>>>> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
>>>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>>>> +
>>>>> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
>>>>> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
>>>>> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
>>>>> +	udelay(1);
>>>>> +
>>>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>>>> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
>>>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
>>>>> +	udelay(1);
>>>>> +
>>>>> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
>>>>> +	val = pll_readl_base(pll);
>>>>> +	val &= ~PLLU_BASE_CLKENABLE_USB;
>>>>> +	pll_writel_base(val, pll);
>>>>> +
>>>>> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>>>> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
>>>>> +		pr_debug("UTMIPLL already enabled\n");
>>>>> +		goto out;
>>>>> +	}
>>>>> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
>>>>> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
>>>>> +
>>>>> +	/* Program UTMIP PLL stable and active counts */
>>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
>>>>> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
>>>>> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
>>>>> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
>>>>> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
>>>>> +			utmi_parameters[i].active_delay_count);
>>>>> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
>>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
>>>>> +
>>>>> +	/* Program UTMIP PLL delay and oscillator frequency counts */
>>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>>>> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
>>>>> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
>>>>> +		utmi_parameters[i].enable_delay_count);
>>>>> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
>>>>> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
>>>>> +		utmi_parameters[i].xtal_freq_count);
>>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>>>> +
>>>>> +	/* Remove power downs from UTMIP PLL control bits */
>>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
>>>>> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
>>>>> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
>>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
>>>>> +	udelay(100);
>>>>
>>>> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
>>>> and this is causing the following splat when the clock is enabled. I
>>>> don't think that we can use usleep here ...
>>>
>>> Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
>>> for 100 microseconds here, so can we please find another way to do this?
>>>
>>
>> It looks like we should be able to use a short udelay of 1-2us. I
>> believe the original code had udelay(1) and I know Jon and I tested
>> udelay(2) and it was ok.
> 
> What original code? The downstream driver? If so I'd be leaning towards
> simply adopting that. Everything else in this functions seems to want to
> wait for 1 us, seems natural for this to do as well.

Sorry I wasn't clear. The code in the clk-tegraXX specific drivers was
using udelay(1) as you pointed out, thats what I meant.

> 
>> Do you want me to send another patch rev with just the udelay change or
>> are you going to just modify it locally yourself?
> 
> No need to resend, I'll cherry-pick the patch from next-20160617 and
> make this into udelay(1).

Thanks!

-rhyland
Thierry Reding June 30, 2016, 3:43 p.m. UTC | #10
On Thu, Jun 30, 2016 at 11:40:19AM -0400, Rhyland Klein wrote:
> On 6/30/2016 11:37 AM, Thierry Reding wrote:
> > * PGP Signed by an unknown key
> > 
> > On Thu, Jun 30, 2016 at 11:32:14AM -0400, Rhyland Klein wrote:
> >> On 6/17/2016 11:23 AM, Thierry Reding wrote:
> >>>> Old Signed by an unknown key
> >>>
> >>> On Fri, Jun 17, 2016 at 02:49:41PM +0100, Jon Hunter wrote:
> >>>> Hi Thierry,
> >>>>
> >>>> On 26/05/16 17:41, Rhyland Klein wrote:
> >>>>> From: Andrew Bresticker <abrestic@chromium.org>
> >>>>>
> >>>>> Move the UTMIPLL initialization code form clk-tegra<chip>.c files into
> >>>>> clk-pll.c. UTMIPLL was being configured and set in HW control right
> >>>>> after registration. However, when the clock init_table is processed and
> >>>>> child clks of PLLU are enabled, it will call in and enable PLLU as
> >>>>> well, and initiate SW enabling sequence even though PLLU is already in
> >>>>> HW control. This leads to getting UTMIPLL stuck with a SEQ_BUSY status.
> >>>>>
> >>>>> Doing the initialization once during pllu_enable means we configure it
> >>>>> properly into HW control.
> >>>>>
> >>>>> A side effect of the commonization/localization of the UTMIPLL init
> >>>>> code, is that it corrects some errors that were present for earlier
> >>>>> generations. For instance, in clk-tegra124.c, it used to have:
> >>>>>
> >>>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
> >>>>>
> >>>>> when the correct shift to use is present in the new version:
> >>>>>
> >>>>> define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
> >>>>>
> >>>>> which matches the Tegra124 TRM register definition.
> >>>>>
> >>>>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> >>>>>
> >>>>> [rklein: Merged in some later fixes for potential deadlocks]
> >>>>>
> >>>>> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
> >>>>> ---
> >>>>> v5:
> >>>>>  - Initialized flags to 0 to avoid harmless spinlock warnings
> >>>>>
> >>>>> v4:
> >>>>>  - Re-added examples in patch description
> >>>>>
> >>>>> v3:
> >>>>>  - Flushed out description to describe this patch.
> >>>>>
> >>>>>  drivers/clk/tegra/clk-pll.c      | 484 +++++++++++++++++++++++++++++++++++++++
> >>>>>  drivers/clk/tegra/clk-tegra114.c | 155 +------------
> >>>>>  drivers/clk/tegra/clk-tegra124.c | 156 +------------
> >>>>>  drivers/clk/tegra/clk-tegra210.c | 182 +--------------
> >>>>>  drivers/clk/tegra/clk-tegra30.c  | 113 +--------
> >>>>>  drivers/clk/tegra/clk.h          |  17 ++
> >>>>>  6 files changed, 510 insertions(+), 597 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> >>>>> index 4e194ecc8d5e..31e20110fae4 100644
> >>>>> --- a/drivers/clk/tegra/clk-pll.c
> >>>>> +++ b/drivers/clk/tegra/clk-pll.c
> >>>>
> >>>> ...
> >>>>
> >>>>> +static int clk_pllu_tegra210_enable(struct clk_hw *hw)
> >>>>> +{
> >>>>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> >>>>> +	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
> >>>>> +	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
> >>>>> +	unsigned long flags = 0, input_rate;
> >>>>> +	unsigned int i;
> >>>>> +	int ret = 0;
> >>>>> +	u32 val;
> >>>>> +
> >>>>> +	if (!osc) {
> >>>>> +		pr_err("%s: failed to get OSC clock\n", __func__);
> >>>>> +		return -EINVAL;
> >>>>> +	}
> >>>>> +	input_rate = clk_hw_get_rate(osc);
> >>>>> +
> >>>>> +	if (pll->lock)
> >>>>> +		spin_lock_irqsave(pll->lock, flags);
> >>>>> +
> >>>>> +	_clk_pll_enable(hw);
> >>>>> +	ret = clk_pll_wait_for_lock(pll);
> >>>>> +	if (ret < 0)
> >>>>> +		goto out;
> >>>>> +
> >>>>> +	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
> >>>>> +		if (input_rate == utmi_parameters[i].osc_frequency)
> >>>>> +			break;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (i == ARRAY_SIZE(utmi_parameters)) {
> >>>>> +		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
> >>>>> +		ret = -EINVAL;
> >>>>> +		goto out;
> >>>>> +	}
> >>>>> +
> >>>>> +	val = pll_readl_base(pll);
> >>>>> +	val &= ~PLLU_BASE_OVERRIDE;
> >>>>> +	pll_writel_base(val, pll);
> >>>>> +
> >>>>> +	/* Put PLLU under HW control */
> >>>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>>>> +	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
> >>>>> +	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
> >>>>> +	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
> >>>>> +	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
> >>>>> +		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
> >>>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>>>> +
> >>>>> +	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
> >>>>> +	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
> >>>>> +	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
> >>>>> +	udelay(1);
> >>>>> +
> >>>>> +	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>>>> +	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
> >>>>> +	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
> >>>>> +	udelay(1);
> >>>>> +
> >>>>> +	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
> >>>>> +	val = pll_readl_base(pll);
> >>>>> +	val &= ~PLLU_BASE_CLKENABLE_USB;
> >>>>> +	pll_writel_base(val, pll);
> >>>>> +
> >>>>> +	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> >>>>> +	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
> >>>>> +		pr_debug("UTMIPLL already enabled\n");
> >>>>> +		goto out;
> >>>>> +	}
> >>>>> +	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
> >>>>> +	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
> >>>>> +
> >>>>> +	/* Program UTMIP PLL stable and active counts */
> >>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
> >>>>> +	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
> >>>>> +	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
> >>>>> +	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
> >>>>> +	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
> >>>>> +			utmi_parameters[i].active_delay_count);
> >>>>> +	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
> >>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
> >>>>> +
> >>>>> +	/* Program UTMIP PLL delay and oscillator frequency counts */
> >>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> >>>>> +	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
> >>>>> +	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
> >>>>> +		utmi_parameters[i].enable_delay_count);
> >>>>> +	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
> >>>>> +	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
> >>>>> +		utmi_parameters[i].xtal_freq_count);
> >>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> >>>>> +
> >>>>> +	/* Remove power downs from UTMIP PLL control bits */
> >>>>> +	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
> >>>>> +	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
> >>>>> +	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
> >>>>> +	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
> >>>>> +	udelay(100);
> >>>>
> >>>> In next-20160617 I see that this udelay is now a usleep_range(100, 200)
> >>>> and this is causing the following splat when the clock is enabled. I
> >>>> don't think that we can use usleep here ...
> >>>
> >>> Okay, I'll back out the patch. I'd really prefer to avoid busy-looping
> >>> for 100 microseconds here, so can we please find another way to do this?
> >>>
> >>
> >> It looks like we should be able to use a short udelay of 1-2us. I
> >> believe the original code had udelay(1) and I know Jon and I tested
> >> udelay(2) and it was ok.
> > 
> > What original code? The downstream driver? If so I'd be leaning towards
> > simply adopting that. Everything else in this functions seems to want to
> > wait for 1 us, seems natural for this to do as well.
> 
> Sorry I wasn't clear. The code in the clk-tegraXX specific drivers was
> using udelay(1) as you pointed out, thats what I meant.

On further looking at the downstream code, the write before the udelay()
above should probably also use the non-relaxed version because the code
in our downstream kernel uses a dsb() after the write (which makes it
equivalent to a plain writel()).

Thierry
diff mbox

Patch

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 4e194ecc8d5e..31e20110fae4 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -191,6 +191,53 @@ 
 #define PLLSS_REF_SRC_SEL_SHIFT	25
 #define PLLSS_REF_SRC_SEL_MASK	(3 << PLLSS_REF_SRC_SEL_SHIFT)
 
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP BIT(1)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP BIT(3)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERUP BIT(5)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN BIT(24)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP BIT(25)
+#define UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN BIT(30)
+
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25)
+
+#define PLLU_HW_PWRDN_CFG0 0x530
+#define PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL BIT(0)
+#define PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define PLLU_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT BIT(7)
+#define PLLU_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE BIT(28)
+
+#define XUSB_PLL_CFG0 0x534
+#define XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY 0x3ff
+#define XUSB_PLL_CFG0_PLLU_LOCK_DLY (0x3ff << 14)
+
+#define PLLU_BASE_CLKENABLE_USB BIT(21)
+#define PLLU_BASE_OVERRIDE BIT(24)
+
 #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
 #define pll_readl_base(p) pll_readl(p->params->base_reg, p)
 #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
@@ -973,6 +1020,123 @@  const struct clk_ops tegra_clk_plle_ops = {
 	.enable = clk_plle_enable,
 };
 
+/*
+ * Structure defining the fields for USB UTMI clocks Parameters.
+ */
+struct utmi_clk_param {
+	/* Oscillator Frequency in Hz */
+	u32 osc_frequency;
+	/* UTMIP PLL Enable Delay Count  */
+	u8 enable_delay_count;
+	/* UTMIP PLL Stable count */
+	u8 stable_count;
+	/*  UTMIP PLL Active delay count */
+	u8 active_delay_count;
+	/* UTMIP PLL Xtal frequency count */
+	u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+	{ .osc_frequency = 13000000, .enable_delay_count = 0x02,
+	  .stable_count = 0x33, .active_delay_count = 0x05,
+	  .xtal_freq_count = 0x7f },
+	{ .osc_frequency = 19200000, .enable_delay_count = 0x03,
+	  .stable_count = 0x4b, .active_delay_count = 0x06,
+	  .xtal_freq_count = 0xbb },
+	{ .osc_frequency = 12000000, .enable_delay_count = 0x02,
+	  .stable_count = 0x2f, .active_delay_count = 0x04,
+	  .xtal_freq_count = 0x76 },
+	{ .osc_frequency = 26000000, .enable_delay_count = 0x04,
+	  .stable_count = 0x66, .active_delay_count = 0x09,
+	  .xtal_freq_count = 0xfe },
+	{ .osc_frequency = 16800000, .enable_delay_count = 0x03,
+	  .stable_count = 0x41, .active_delay_count = 0x0a,
+	  .xtal_freq_count = 0xa4 },
+	{ .osc_frequency = 38400000, .enable_delay_count = 0x0,
+	  .stable_count = 0x0, .active_delay_count = 0x6,
+	  .xtal_freq_count = 0x80 },
+};
+
+static int clk_pllu_enable(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
+	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
+	unsigned long flags = 0, input_rate;
+	unsigned int i;
+	int ret = 0;
+	u32 val;
+
+	if (!osc) {
+		pr_err("%s: failed to get OSC clock\n", __func__);
+		return -EINVAL;
+	}
+	input_rate = clk_hw_get_rate(osc);
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	_clk_pll_enable(hw);
+	ret = clk_pll_wait_for_lock(pll);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+		if (input_rate == utmi_parameters[i].osc_frequency)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(utmi_parameters)) {
+		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = pll_readl_base(pll);
+	val &= ~PLLU_BASE_OVERRIDE;
+	pll_writel_base(val, pll);
+
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+	/* Program UTMIP PLL stable and active counts */
+	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+			utmi_parameters[i].active_delay_count);
+	/* Remove power downs from UTMIP PLL control bits */
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
+
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	/* Program UTMIP PLL delay and oscillator frequency counts */
+	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+		utmi_parameters[i].enable_delay_count);
+	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+		utmi_parameters[i].xtal_freq_count);
+	/* Remove power downs from UTMIP PLL control bits */
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+
+out:
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return ret;
+}
+
+static const struct clk_ops tegra_clk_pllu_ops = {
+	.is_enabled = clk_pll_is_enabled,
+	.enable = clk_pllu_enable,
+	.disable = clk_pll_disable,
+	.recalc_rate = clk_pll_recalc_rate,
+};
+
 static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
 			   unsigned long parent_rate)
 {
@@ -1505,6 +1669,109 @@  static void clk_plle_tegra114_disable(struct clk_hw *hw)
 	if (pll->lock)
 		spin_unlock_irqrestore(pll->lock, flags);
 }
+
+static int clk_pllu_tegra114_enable(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct clk *osc = __clk_lookup("osc");
+	unsigned long flags = 0, input_rate;
+	unsigned int i;
+	int ret = 0;
+	u32 val;
+
+	if (!osc) {
+		pr_err("%s: failed to get OSC clock\n", __func__);
+		return -EINVAL;
+		}
+	input_rate = clk_hw_get_rate(__clk_get_hw(osc));
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	_clk_pll_enable(hw);
+	ret = clk_pll_wait_for_lock(pll);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+		if (input_rate == utmi_parameters[i].osc_frequency)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(utmi_parameters)) {
+		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = pll_readl_base(pll);
+	val &= ~PLLU_BASE_OVERRIDE;
+	pll_writel_base(val, pll);
+
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+	/* Program UTMIP PLL stable and active counts */
+	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+			utmi_parameters[i].active_delay_count);
+	/* Remove power downs from UTMIP PLL control bits */
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
+
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	/* Program UTMIP PLL delay and oscillator frequency counts */
+	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+		utmi_parameters[i].enable_delay_count);
+	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+		utmi_parameters[i].xtal_freq_count);
+	/* Remove power downs from UTMIP PLL control bits */
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+
+	/* Setup HW control of UTMIPLL */
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	val |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+	val &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+	val |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+
+	udelay(1);
+
+	/*
+	 * Setup SW override of UTMIPLL assuming USB2.0 ports are assigned
+	 * to USB2
+	 */
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	val |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
+	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	udelay(1);
+
+	/* Enable HW control of UTMIPLL */
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	val |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+out:
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return ret;
+}
 #endif
 
 static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
@@ -1614,6 +1881,27 @@  struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
 	return clk;
 }
 
+struct clk *tegra_clk_register_pllu(const char *name, const char *parent_name,
+		void __iomem *clk_base, unsigned long flags,
+		struct tegra_clk_pll_params *pll_params, spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk;
+
+	pll_params->flags |= TEGRA_PLLU;
+
+	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pllu_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
 #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
 	defined(CONFIG_ARCH_TEGRA_124_SOC) || \
 	defined(CONFIG_ARCH_TEGRA_132_SOC) || \
@@ -1652,6 +1940,12 @@  static const struct clk_ops tegra_clk_plle_tegra114_ops = {
 	.recalc_rate = clk_pll_recalc_rate,
 };
 
+static const struct clk_ops tegra_clk_pllu_tegra114_ops = {
+	.is_enabled =  clk_pll_is_enabled,
+	.enable = clk_pllu_tegra114_enable,
+	.disable = clk_pll_disable,
+	.recalc_rate = clk_pll_recalc_rate,
+};
 
 struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
 			  void __iomem *clk_base, void __iomem *pmc,
@@ -1919,6 +2213,28 @@  struct clk *tegra_clk_register_plle_tegra114(const char *name,
 
 	return clk;
 }
+
+struct clk *tegra_clk_register_pllu_tegra114(const char *name,
+		const char *parent_name, void __iomem *clk_base,
+		unsigned long flags, struct tegra_clk_pll_params *pll_params,
+		spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk;
+
+	pll_params->flags |= TEGRA_PLLU;
+
+	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pllu_tegra114_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
 #endif
 
 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
@@ -2187,6 +2503,145 @@  static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
 	return val & PLLE_BASE_ENABLE ? 1 : 0;
 }
 
+static int clk_pllu_tegra210_enable(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
+	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
+	unsigned long flags = 0, input_rate;
+	unsigned int i;
+	int ret = 0;
+	u32 val;
+
+	if (!osc) {
+		pr_err("%s: failed to get OSC clock\n", __func__);
+		return -EINVAL;
+	}
+	input_rate = clk_hw_get_rate(osc);
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	_clk_pll_enable(hw);
+	ret = clk_pll_wait_for_lock(pll);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+		if (input_rate == utmi_parameters[i].osc_frequency)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(utmi_parameters)) {
+		pr_err("%s: Unexpected input rate %lu\n", __func__, input_rate);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = pll_readl_base(pll);
+	val &= ~PLLU_BASE_OVERRIDE;
+	pll_writel_base(val, pll);
+
+	/* Put PLLU under HW control */
+	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
+	val |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
+	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
+	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
+	val &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
+		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
+	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
+
+	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
+	val &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
+	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
+	udelay(1);
+
+	val = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
+	val |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
+	writel_relaxed(val, pll->clk_base + PLLU_HW_PWRDN_CFG0);
+	udelay(1);
+
+	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
+	val = pll_readl_base(pll);
+	val &= ~PLLU_BASE_CLKENABLE_USB;
+	pll_writel_base(val, pll);
+
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	if (val & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
+		pr_debug("UTMIPLL already enabled\n");
+		goto out;
+	}
+	val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	/* Program UTMIP PLL stable and active counts */
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+	val &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+	val &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+			utmi_parameters[i].active_delay_count);
+	val |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
+
+	/* Program UTMIP PLL delay and oscillator frequency counts */
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	val &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+		utmi_parameters[i].enable_delay_count);
+	val &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+	val |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+		utmi_parameters[i].xtal_freq_count);
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+
+	/* Remove power downs from UTMIP PLL control bits */
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	val |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+	udelay(100);
+
+	/* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+	val |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
+	val |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
+	val |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+	val &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG2);
+
+	/* Setup HW control of UTMIPLL */
+	val = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+	val &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	writel_relaxed(val, pll->clk_base + UTMIP_PLL_CFG1);
+
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	val |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+	val &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	udelay(1);
+
+	val = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
+	val &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
+	writel_relaxed(val, pll->clk_base + XUSB_PLL_CFG0);
+
+	udelay(1);
+
+	/* Enable HW control of UTMIPLL */
+	val = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	val |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+	writel_relaxed(val, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+out:
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return ret;
+}
+
 static const struct clk_ops tegra_clk_plle_tegra210_ops = {
 	.is_enabled =  clk_plle_tegra210_is_enabled,
 	.enable = clk_plle_tegra210_enable,
@@ -2194,6 +2649,13 @@  static const struct clk_ops tegra_clk_plle_tegra210_ops = {
 	.recalc_rate = clk_pll_recalc_rate,
 };
 
+static const struct clk_ops tegra_clk_pllu_tegra210_ops = {
+	.is_enabled =  clk_pll_is_enabled,
+	.enable = clk_pllu_tegra210_enable,
+	.disable = clk_pll_disable,
+	.recalc_rate = clk_pllre_recalc_rate,
+};
+
 struct clk *tegra_clk_register_plle_tegra210(const char *name,
 				const char *parent_name,
 				void __iomem *clk_base, unsigned long flags,
@@ -2434,4 +2896,26 @@  struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
 
 	return clk;
 }
+
+struct clk *tegra_clk_register_pllu_tegra210(const char *name,
+		const char *parent_name, void __iomem *clk_base,
+		unsigned long flags, struct tegra_clk_pll_params *pll_params,
+		spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk;
+
+	pll_params->flags |= TEGRA_PLLU;
+
+	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pllu_tegra210_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
 #endif
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index b78054fac0a8..ff202eb9a716 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -113,32 +113,6 @@ 
 
 #define CCLKG_BURST_POLICY 0x368
 
-#define UTMIP_PLL_CFG2 0x488
-#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
-#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
-
-#define UTMIP_PLL_CFG1 0x484
-#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
-#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
-
-#define UTMIPLL_HW_PWRDN_CFG0			0x52c
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE	BIT(25)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE	BIT(24)
-#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET	BIT(6)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE	BIT(5)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL	BIT(4)
-#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL	BIT(2)
-#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE	BIT(1)
-#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL	BIT(0)
-
 #define CLK_SOURCE_CSITE 0x1d4
 #define CLK_SOURCE_EMC 0x19c
 
@@ -649,43 +623,6 @@  static unsigned long tegra114_input_freq[] = {
 
 #define MASK(x) (BIT(x) - 1)
 
-struct utmi_clk_param {
-	/* Oscillator Frequency in KHz */
-	u32 osc_frequency;
-	/* UTMIP PLL Enable Delay Count  */
-	u8 enable_delay_count;
-	/* UTMIP PLL Stable count */
-	u8 stable_count;
-	/*  UTMIP PLL Active delay count */
-	u8 active_delay_count;
-	/* UTMIP PLL Xtal frequency count */
-	u8 xtal_freq_count;
-};
-
-static const struct utmi_clk_param utmi_parameters[] = {
-	{
-		.osc_frequency = 13000000, .enable_delay_count = 0x02,
-		.stable_count = 0x33, .active_delay_count = 0x05,
-		.xtal_freq_count = 0x7f
-	}, {
-		.osc_frequency = 19200000, .enable_delay_count = 0x03,
-		.stable_count = 0x4b, .active_delay_count = 0x06,
-		.xtal_freq_count = 0xbb
-	}, {
-		.osc_frequency = 12000000, .enable_delay_count = 0x02,
-		.stable_count = 0x2f, .active_delay_count = 0x04,
-		.xtal_freq_count = 0x76
-	}, {
-		.osc_frequency = 26000000, .enable_delay_count = 0x04,
-		.stable_count = 0x66, .active_delay_count = 0x09,
-		.xtal_freq_count = 0xfe
-	}, {
-		.osc_frequency = 16800000, .enable_delay_count = 0x03,
-		.stable_count = 0x41, .active_delay_count = 0x0a,
-		.xtal_freq_count = 0xa4
-	},
-};
-
 /* peripheral mux definitions */
 
 static const char *mux_plld_out0_plld2_out0[] = {
@@ -986,88 +923,6 @@  static void __init tegra114_fixed_clk_init(void __iomem *clk_base)
 
 }
 
-static __init void tegra114_utmi_param_configure(void __iomem *clk_base)
-{
-	unsigned int i;
-	u32 reg;
-
-	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
-		if (osc_freq == utmi_parameters[i].osc_frequency)
-			break;
-	}
-
-	if (i >= ARRAY_SIZE(utmi_parameters)) {
-		pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
-		       osc_freq);
-		return;
-	}
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL stable and active counts */
-	/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
-	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
-	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
-
-	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
-					    active_delay_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
-
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL delay and oscillator frequency counts */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
-					    enable_delay_count);
-
-	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
-	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
-					   xtal_freq_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	/* Setup HW control of UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
-	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	udelay(1);
-
-	/* Setup SW override of UTMIPLL assuming USB2.0
-	   ports are assigned to USB2 */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	udelay(1);
-
-	/* Enable HW control UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-}
-
 static void __init tegra114_pll_init(void __iomem *clk_base,
 				     void __iomem *pmc)
 {
@@ -1118,16 +973,10 @@  static void __init tegra114_pll_init(void __iomem *clk_base,
 					CLK_SET_RATE_PARENT, 1, 1);
 
 	/* PLLU */
-	val = readl(clk_base + pll_u_params.base_reg);
-	val &= ~BIT(24); /* disable PLLU_OVERRIDE */
-	writel(val, clk_base + pll_u_params.base_reg);
-
-	clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0,
-			    &pll_u_params, &pll_u_lock);
+	clk = tegra_clk_register_pllu_tegra114("pll_u", "pll_ref", clk_base, 0,
+					       &pll_u_params, &pll_u_lock);
 	clks[TEGRA114_CLK_PLL_U] = clk;
 
-	tegra114_utmi_param_configure(clk_base);
-
 	/* PLLU_480M */
 	clk = clk_register_gate(NULL, "pll_u_480M", "pll_u",
 				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index f4fbbf16a056..a112d3d2bff1 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -99,32 +99,6 @@ 
 
 #define CCLKG_BURST_POLICY 0x368
 
-#define UTMIP_PLL_CFG2 0x488
-#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
-#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
-
-#define UTMIP_PLL_CFG1 0x484
-#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
-#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
-
-#define UTMIPLL_HW_PWRDN_CFG0			0x52c
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE	BIT(25)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE	BIT(24)
-#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET	BIT(6)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE	BIT(5)
-#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL	BIT(4)
-#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL	BIT(2)
-#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE	BIT(1)
-#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL	BIT(0)
-
 /* Tegra CPU clock and reset control regs */
 #define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS	0x470
 
@@ -764,43 +738,6 @@  static struct tegra_clk_pll_params pll_u_params = {
 		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
-struct utmi_clk_param {
-	/* Oscillator Frequency in KHz */
-	u32 osc_frequency;
-	/* UTMIP PLL Enable Delay Count  */
-	u8 enable_delay_count;
-	/* UTMIP PLL Stable count */
-	u8 stable_count;
-	/*  UTMIP PLL Active delay count */
-	u8 active_delay_count;
-	/* UTMIP PLL Xtal frequency count */
-	u8 xtal_freq_count;
-};
-
-static const struct utmi_clk_param utmi_parameters[] = {
-	{
-		.osc_frequency = 13000000, .enable_delay_count = 0x02,
-		.stable_count = 0x33, .active_delay_count = 0x05,
-		.xtal_freq_count = 0x7f
-	}, {
-		.osc_frequency = 19200000, .enable_delay_count = 0x03,
-		.stable_count = 0x4b, .active_delay_count = 0x06,
-		.xtal_freq_count = 0xbb
-	}, {
-		.osc_frequency = 12000000, .enable_delay_count = 0x02,
-		.stable_count = 0x2f, .active_delay_count = 0x04,
-		.xtal_freq_count = 0x76
-	}, {
-		.osc_frequency = 26000000, .enable_delay_count = 0x04,
-		.stable_count = 0x66, .active_delay_count = 0x09,
-		.xtal_freq_count = 0xfe
-	}, {
-		.osc_frequency = 16800000, .enable_delay_count = 0x03,
-		.stable_count = 0x41, .active_delay_count = 0x0a,
-		.xtal_freq_count = 0xa4
-	},
-};
-
 static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_ispb] = { .dt_id = TEGRA124_CLK_ISPB, .present = true },
 	[tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
@@ -1063,88 +1000,6 @@  static struct tegra_devclk devclks[] __initdata = {
 
 static struct clk **clks;
 
-static void tegra124_utmi_param_configure(void __iomem *clk_base)
-{
-	unsigned int i;
-	u32 reg;
-
-	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
-		if (osc_freq == utmi_parameters[i].osc_frequency)
-			break;
-	}
-
-	if (i >= ARRAY_SIZE(utmi_parameters)) {
-		pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
-		       osc_freq);
-		return;
-	}
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL stable and active counts */
-	/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
-	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
-	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
-
-	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
-					    active_delay_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
-
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL delay and oscillator frequency counts */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
-					    enable_delay_count);
-
-	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
-	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
-					   xtal_freq_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	/* Setup HW control of UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
-	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	udelay(1);
-
-	/* Setup SW override of UTMIPLL assuming USB2.0
-	   ports are assigned to USB2 */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	udelay(1);
-
-	/* Enable HW control UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-}
-
 static __init void tegra124_periph_clk_init(void __iomem *clk_base,
 					    void __iomem *pmc_base)
 {
@@ -1195,7 +1050,6 @@  static __init void tegra124_periph_clk_init(void __iomem *clk_base,
 static void __init tegra124_pll_init(void __iomem *clk_base,
 				     void __iomem *pmc)
 {
-	u32 val;
 	struct clk *clk;
 
 	/* PLLC */
@@ -1256,17 +1110,11 @@  static void __init tegra124_pll_init(void __iomem *clk_base,
 	clks[TEGRA124_CLK_PLL_M_UD] = clk;
 
 	/* PLLU */
-	val = readl(clk_base + pll_u_params.base_reg);
-	val &= ~BIT(24); /* disable PLLU_OVERRIDE */
-	writel(val, clk_base + pll_u_params.base_reg);
-
-	clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0,
-			    &pll_u_params, &pll_u_lock);
+	clk = tegra_clk_register_pllu_tegra114("pll_u", "pll_ref", clk_base, 0,
+					       &pll_u_params, &pll_u_lock);
 	clk_register_clkdev(clk, "pll_u", NULL);
 	clks[TEGRA124_CLK_PLL_U] = clk;
 
-	tegra124_utmi_param_configure(clk_base);
-
 	/* PLLU_480M */
 	clk = clk_register_gate(NULL, "pll_u_480M", "pll_u",
 				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index b8551813ec43..cc60322bb116 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -155,27 +155,6 @@ 
 #define PMC_PLLM_WB0_OVERRIDE 0x1dc
 #define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
 
-#define UTMIP_PLL_CFG2 0x488
-#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
-#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP BIT(1)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP BIT(3)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERUP BIT(5)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN BIT(24)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP BIT(25)
-
-#define UTMIP_PLL_CFG1 0x484
-#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
-#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
-
 #define SATA_PLL_CFG0				0x490
 #define SATA_PLL_CFG0_PADPLL_RESET_SWCTL	BIT(0)
 #define SATA_PLL_CFG0_PADPLL_USE_LOCKDET	BIT(2)
@@ -2037,47 +2016,6 @@  static struct tegra_clk_pll_params pll_u_vco_params = {
 	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
 
-struct utmi_clk_param {
-	/* Oscillator Frequency in KHz */
-	u32 osc_frequency;
-	/* UTMIP PLL Enable Delay Count  */
-	u8 enable_delay_count;
-	/* UTMIP PLL Stable count */
-	u16 stable_count;
-	/*  UTMIP PLL Active delay count */
-	u8 active_delay_count;
-	/* UTMIP PLL Xtal frequency count */
-	u16 xtal_freq_count;
-};
-
-static const struct utmi_clk_param utmi_parameters[] = {
-	{
-		.osc_frequency = 38400000, .enable_delay_count = 0x0,
-		.stable_count = 0x0, .active_delay_count = 0x6,
-		.xtal_freq_count = 0x80
-	}, {
-		.osc_frequency = 13000000, .enable_delay_count = 0x02,
-		.stable_count = 0x33, .active_delay_count = 0x05,
-		.xtal_freq_count = 0x7f
-	}, {
-		.osc_frequency = 19200000, .enable_delay_count = 0x03,
-		.stable_count = 0x4b, .active_delay_count = 0x06,
-		.xtal_freq_count = 0xbb
-	}, {
-		.osc_frequency = 12000000, .enable_delay_count = 0x02,
-		.stable_count = 0x2f, .active_delay_count = 0x08,
-		.xtal_freq_count = 0x76
-	}, {
-		.osc_frequency = 26000000, .enable_delay_count = 0x04,
-		.stable_count = 0x66, .active_delay_count = 0x09,
-		.xtal_freq_count = 0xfe
-	}, {
-		.osc_frequency = 16800000, .enable_delay_count = 0x03,
-		.stable_count = 0x41, .active_delay_count = 0x0a,
-		.xtal_freq_count = 0xa4
-	},
-};
-
 static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_ispb] = { .dt_id = TEGRA210_CLK_ISPB, .present = true },
 	[tegra_clk_rtc] = { .dt_id = TEGRA210_CLK_RTC, .present = true },
@@ -2345,114 +2283,6 @@  static struct tegra_audio_clk_info tegra210_audio_plls[] = {
 
 static struct clk **clks;
 
-static void tegra210_utmi_param_configure(void __iomem *clk_base)
-{
-	u32 reg;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
-		if (osc_freq == utmi_parameters[i].osc_frequency)
-			break;
-	}
-
-	if (i >= ARRAY_SIZE(utmi_parameters)) {
-		pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
-		       osc_freq);
-		return;
-	}
-
-	reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
-	reg |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
-	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
-	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
-	reg &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
-		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
-	writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
-
-	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);
-
-	reg = readl_relaxed(clk_base + PLLU_BASE);
-	reg &= ~PLLU_BASE_CLKENABLE_USB;
-	writel_relaxed(reg, clk_base + PLLU_BASE);
-
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	udelay(10);
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL stable and active counts */
-	/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
-	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
-	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
-
-	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
-					    active_delay_count);
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL delay and oscillator frequency counts */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
-					    enable_delay_count);
-
-	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
-	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
-					   xtal_freq_count);
-
-	reg |= UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	reg |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-	udelay(1);
-
-	/* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
-	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
-	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
-	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
-
-	/* Setup HW control of UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
-	reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-
-	udelay(1);
-
-	reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
-	reg &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
-	writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
-
-	udelay(1);
-
-	/* Enable HW control UTMIPLL */
-	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
-	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
-	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
-}
-
 static __init void tegra210_periph_clk_init(void __iomem *clk_base,
 					    void __iomem *pmc_base)
 {
@@ -2520,7 +2350,6 @@  static __init void tegra210_periph_clk_init(void __iomem *clk_base,
 static void __init tegra210_pll_init(void __iomem *clk_base,
 				     void __iomem *pmc)
 {
-	u32 val;
 	struct clk *clk;
 
 	/* PLLC */
@@ -2580,12 +2409,9 @@  static void __init tegra210_pll_init(void __iomem *clk_base,
 	clks[TEGRA210_CLK_PLL_M_UD] = clk;
 
 	/* PLLU_VCO */
-	val = readl(clk_base + pll_u_vco_params.base_reg);
-	val &= ~PLLU_BASE_OVERRIDE; /* disable PLLU_OVERRIDE */
-	writel(val, clk_base + pll_u_vco_params.base_reg);
-
-	clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
-			    0, &pll_u_vco_params, &pll_u_lock, pll_ref_freq);
+	clk = tegra_clk_register_pllu_tegra210("pll_u_vco", "pll_ref",
+					       clk_base, 0, &pll_u_vco_params,
+					       &pll_u_lock);
 	clk_register_clkdev(clk, "pll_u_vco", NULL);
 	clks[TEGRA210_CLK_PLL_U] = clk;
 
@@ -2618,8 +2444,6 @@  static void __init tegra210_pll_init(void __iomem *clk_base,
 	clk_register_clkdev(clk, "pll_u_out2", NULL);
 	clks[TEGRA210_CLK_PLL_U_OUT2] = clk;
 
-	tegra210_utmi_param_configure(clk_base);
-
 	/* PLLU_480M */
 	clk = clk_register_gate(NULL, "pll_u_480M", "pll_u_vco",
 				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 9396f4930da7..8e2db5ead8da 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -118,20 +118,6 @@ 
 
 #define AUDIO_SYNC_DOUBLER 0x49c
 
-#define UTMIP_PLL_CFG2 0x488
-#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
-#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
-
-#define UTMIP_PLL_CFG1 0x484
-#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
-#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
-
 /* Tegra CPU clock and reset control regs */
 #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX		0x4c
 #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET	0x340
@@ -207,46 +193,6 @@  static DEFINE_SPINLOCK(emc_lock);
 
 static struct clk **clks;
 
-/*
- * Structure defining the fields for USB UTMI clocks Parameters.
- */
-struct utmi_clk_param {
-	/* Oscillator Frequency in KHz */
-	u32 osc_frequency;
-	/* UTMIP PLL Enable Delay Count  */
-	u8 enable_delay_count;
-	/* UTMIP PLL Stable count */
-	u8 stable_count;
-	/*  UTMIP PLL Active delay count */
-	u8 active_delay_count;
-	/* UTMIP PLL Xtal frequency count */
-	u8 xtal_freq_count;
-};
-
-static const struct utmi_clk_param utmi_parameters[] = {
-	{
-		.osc_frequency = 13000000, .enable_delay_count = 0x02,
-		.stable_count = 0x33, .active_delay_count = 0x05,
-		.xtal_freq_count = 0x7f
-	}, {
-		.osc_frequency = 19200000, .enable_delay_count = 0x03,
-		.stable_count = 0x4b, .active_delay_count = 0x06,
-		.xtal_freq_count = 0xbb
-	}, {
-		.osc_frequency = 12000000, .enable_delay_count = 0x02,
-		.stable_count = 0x2f, .active_delay_count = 0x04,
-		.xtal_freq_count = 0x76
-	}, {
-		.osc_frequency = 26000000, .enable_delay_count = 0x04,
-		.stable_count = 0x66, .active_delay_count = 0x09,
-		.xtal_freq_count = 0xfe
-	}, {
-		.osc_frequency = 16800000, .enable_delay_count = 0x03,
-		.stable_count = 0x41, .active_delay_count = 0x0a,
-		.xtal_freq_count = 0xa4
-	},
-};
-
 static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
 	{ 12000000, 1040000000, 520,  6, 1, 8 },
 	{ 13000000, 1040000000, 480,  6, 1, 8 },
@@ -873,59 +819,6 @@  static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true },
 };
 
-static void tegra30_utmi_param_configure(void)
-{
-	unsigned int i;
-	u32 reg;
-
-	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
-		if (input_freq == utmi_parameters[i].osc_frequency)
-			break;
-	}
-
-	if (i >= ARRAY_SIZE(utmi_parameters)) {
-		pr_err("%s: Unexpected input rate %lu\n", __func__, input_freq);
-		return;
-	}
-
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL stable and active counts */
-	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
-	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
-			utmi_parameters[i].stable_count);
-
-	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
-			utmi_parameters[i].active_delay_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
-
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
-
-	/* Program UTMIP PLL delay and oscillator frequency counts */
-	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
-	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
-
-	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
-		utmi_parameters[i].enable_delay_count);
-
-	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
-	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
-		utmi_parameters[i].xtal_freq_count);
-
-	/* Remove power downs from UTMIP PLL control bits */
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
-	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
-
-	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
-}
-
 static const char *pll_e_parents[] = { "pll_ref", "pll_p" };
 
 static void __init tegra30_pll_init(void)
@@ -972,12 +865,10 @@  static void __init tegra30_pll_init(void)
 	clks[TEGRA30_CLK_PLL_X_OUT0] = clk;
 
 	/* PLLU */
-	clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0,
-			    &pll_u_params, NULL);
+	clk = tegra_clk_register_pllu("pll_u", "pll_ref", clk_base, 0,
+				      &pll_u_params, NULL);
 	clks[TEGRA30_CLK_PLL_U] = clk;
 
-	tegra30_utmi_param_configure();
-
 	/* PLLD */
 	clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0,
 			    &pll_d_params, &pll_d_lock);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 9421f0310999..6ba82ecffd4d 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -427,6 +427,23 @@  struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
 			   struct tegra_clk_pll_params *pll_params,
 			   spinlock_t *lock);
 
+struct clk *tegra_clk_register_pllu(const char *name, const char *parent_name,
+				void __iomem *clk_base, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllu_tegra114(const char *name,
+				const char *parent_name,
+				void __iomem *clk_base, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllu_tegra210(const char *name,
+				const char *parent_name,
+				void __iomem *clk_base, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
 /**
  * struct tegra_clk_pll_out - PLL divider down clock
  *