aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/tegra/clk-pll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/tegra/clk-pll.c')
-rw-r--r--drivers/clk/tegra/clk-pll.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 4e194ecc8d5e..b3855360d6bc 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,133 @@ 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);
+ const struct utmi_clk_param *params = NULL;
+ unsigned long flags = 0, input_rate;
+ unsigned int i;
+ int ret = 0;
+ u32 value;
+
+ 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) {
+ params = &utmi_parameters[i];
+ break;
+ }
+ }
+
+ if (!params) {
+ pr_err("%s: unexpected input rate %lu Hz\n", __func__,
+ input_rate);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ value = pll_readl_base(pll);
+ value &= ~PLLU_BASE_OVERRIDE;
+ pll_writel_base(value, pll);
+
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+ /* Program UTMIP PLL stable and active counts */
+ value &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_STABLE_COUNT(params->stable_count);
+ value &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(params->active_delay_count);
+ /* Remove power downs from UTMIP PLL control bits */
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);
+
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ value &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(params->enable_delay_count);
+ value &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(params->xtal_freq_count);
+ /* Remove power downs from UTMIP PLL control bits */
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ writel_relaxed(value, 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 +1679,112 @@ 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);
+ const struct utmi_clk_param *params = NULL;
+ struct clk *osc = __clk_lookup("osc");
+ unsigned long flags = 0, input_rate;
+ unsigned int i;
+ int ret = 0;
+ u32 value;
+
+ 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) {
+ params = &utmi_parameters[i];
+ break;
+ }
+ }
+
+ if (!params) {
+ pr_err("%s: unexpected input rate %lu Hz\n", __func__,
+ input_rate);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ value = pll_readl_base(pll);
+ value &= ~PLLU_BASE_OVERRIDE;
+ pll_writel_base(value, pll);
+
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+ /* Program UTMIP PLL stable and active counts */
+ value &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_STABLE_COUNT(params->stable_count);
+ value &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(params->active_delay_count);
+ /* Remove power downs from UTMIP PLL control bits */
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);
+
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ value &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(params->enable_delay_count);
+ value &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(params->xtal_freq_count);
+ /* Remove power downs from UTMIP PLL control bits */
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);
+
+ /* Setup HW control of UTMIPLL */
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ value |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ value &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ value |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
+ writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);
+
+ udelay(1);
+
+ /*
+ * Setup SW override of UTMIPLL assuming USB2.0 ports are assigned
+ * to USB2
+ */
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ value |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
+ value &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ /* Enable HW control of UTMIPLL */
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ value |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(value, 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 +1894,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 +1953,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 +2226,29 @@ 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 +2517,152 @@ 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);
+ const struct utmi_clk_param *params = NULL;
+ unsigned long flags = 0, input_rate;
+ unsigned int i;
+ int ret = 0;
+ u32 value;
+
+ 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) {
+ params = &utmi_parameters[i];
+ break;
+ }
+ }
+
+ if (!params) {
+ pr_err("%s: unexpected input rate %lu Hz\n", __func__,
+ input_rate);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ value = pll_readl_base(pll);
+ value &= ~PLLU_BASE_OVERRIDE;
+ pll_writel_base(value, pll);
+
+ /* Put PLLU under HW control */
+ value = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
+ value |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
+ PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
+ PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
+ value &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
+ PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
+ writel_relaxed(value, pll->clk_base + PLLU_HW_PWRDN_CFG0);
+
+ value = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
+ value &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
+ writel_relaxed(value, pll->clk_base + XUSB_PLL_CFG0);
+
+ udelay(1);
+
+ value = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
+ value |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(value, pll->clk_base + PLLU_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ /* Disable PLLU clock branch to UTMIPLL since it uses OSC */
+ value = pll_readl_base(pll);
+ value &= ~PLLU_BASE_CLKENABLE_USB;
+ pll_writel_base(value, pll);
+
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ if (value & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
+ pr_debug("UTMIPLL already enabled\n");
+ goto out;
+ }
+
+ value &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ /* Program UTMIP PLL stable and active counts */
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+ value &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_STABLE_COUNT(params->stable_count);
+ value &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(params->active_delay_count);
+ value |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ value &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(params->enable_delay_count);
+ value &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ value |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(params->xtal_freq_count);
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ value |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ writel(value, pll->clk_base + UTMIP_PLL_CFG1);
+
+ udelay(1);
+
+ /* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
+ value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
+ value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
+ value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);
+
+ /* Setup HW control of UTMIPLL */
+ value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);
+
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ value |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ value &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ value = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
+ value &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
+ writel_relaxed(value, pll->clk_base + XUSB_PLL_CFG0);
+
+ udelay(1);
+
+ /* Enable HW control of UTMIPLL */
+ value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ value |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(value, 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 +2670,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 +2917,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