diff options
author | Peter De Schrijver <pdeschrijver@nvidia.com> | 2013-09-09 06:22:55 -0400 |
---|---|---|
committer | Peter De Schrijver <pdeschrijver@nvidia.com> | 2013-11-26 11:46:51 -0500 |
commit | 798e910bee3f9ad69a8b16d7e705086852d9f2de (patch) | |
tree | dedd66ad923319d1125350fcc7b6fb54711b41fb /drivers/clk/tegra | |
parent | 540fc26a02a950a523a62a16d75b87f0e2103584 (diff) |
clk: tegra: Add support for PLLSS
Tegra124 introduces a new PLL type, PLLSS. Add support for it.
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Diffstat (limited to 'drivers/clk/tegra')
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 123 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 5 |
2 files changed, 126 insertions, 2 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 3aa85bf2f425..689c468aca2f 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c | |||
@@ -137,6 +137,36 @@ | |||
137 | #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) | 137 | #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) |
138 | #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) | 138 | #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) |
139 | 139 | ||
140 | #define PLLSS_MISC_KCP 0 | ||
141 | #define PLLSS_MISC_KVCO 0 | ||
142 | #define PLLSS_MISC_SETUP 0 | ||
143 | #define PLLSS_EN_SDM 0 | ||
144 | #define PLLSS_EN_SSC 0 | ||
145 | #define PLLSS_EN_DITHER2 0 | ||
146 | #define PLLSS_EN_DITHER 1 | ||
147 | #define PLLSS_SDM_RESET 0 | ||
148 | #define PLLSS_CLAMP 0 | ||
149 | #define PLLSS_SDM_SSC_MAX 0 | ||
150 | #define PLLSS_SDM_SSC_MIN 0 | ||
151 | #define PLLSS_SDM_SSC_STEP 0 | ||
152 | #define PLLSS_SDM_DIN 0 | ||
153 | #define PLLSS_MISC_DEFAULT ((PLLSS_MISC_KCP << 25) | \ | ||
154 | (PLLSS_MISC_KVCO << 24) | \ | ||
155 | PLLSS_MISC_SETUP) | ||
156 | #define PLLSS_CFG_DEFAULT ((PLLSS_EN_SDM << 31) | \ | ||
157 | (PLLSS_EN_SSC << 30) | \ | ||
158 | (PLLSS_EN_DITHER2 << 29) | \ | ||
159 | (PLLSS_EN_DITHER << 28) | \ | ||
160 | (PLLSS_SDM_RESET) << 27 | \ | ||
161 | (PLLSS_CLAMP << 22)) | ||
162 | #define PLLSS_CTRL1_DEFAULT \ | ||
163 | ((PLLSS_SDM_SSC_MAX << 16) | PLLSS_SDM_SSC_MIN) | ||
164 | #define PLLSS_CTRL2_DEFAULT \ | ||
165 | ((PLLSS_SDM_SSC_STEP << 16) | PLLSS_SDM_DIN) | ||
166 | #define PLLSS_LOCK_OVERRIDE BIT(24) | ||
167 | #define PLLSS_REF_SRC_SEL_SHIFT 25 | ||
168 | #define PLLSS_REF_SRC_SEL_MASK (3 << PLLSS_REF_SRC_SEL_SHIFT) | ||
169 | |||
140 | #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) | 170 | #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) |
141 | #define pll_readl_base(p) pll_readl(p->params->base_reg, p) | 171 | #define pll_readl_base(p) pll_readl(p->params->base_reg, p) |
142 | #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) | 172 | #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) |
@@ -764,7 +794,7 @@ const struct clk_ops tegra_clk_plle_ops = { | |||
764 | .enable = clk_plle_enable, | 794 | .enable = clk_plle_enable, |
765 | }; | 795 | }; |
766 | 796 | ||
767 | #ifdef CONFIG_ARCH_TEGRA_114_SOC | 797 | #if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) |
768 | 798 | ||
769 | static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, | 799 | static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, |
770 | unsigned long parent_rate) | 800 | unsigned long parent_rate) |
@@ -1405,7 +1435,7 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | |||
1405 | return clk; | 1435 | return clk; |
1406 | } | 1436 | } |
1407 | 1437 | ||
1408 | #ifdef CONFIG_ARCH_TEGRA_114_SOC | 1438 | #if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) |
1409 | const struct clk_ops tegra_clk_pllxc_ops = { | 1439 | const struct clk_ops tegra_clk_pllxc_ops = { |
1410 | .is_enabled = clk_pll_is_enabled, | 1440 | .is_enabled = clk_pll_is_enabled, |
1411 | .enable = clk_pll_iddq_enable, | 1441 | .enable = clk_pll_iddq_enable, |
@@ -1702,3 +1732,92 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name, | |||
1702 | return clk; | 1732 | return clk; |
1703 | } | 1733 | } |
1704 | #endif | 1734 | #endif |
1735 | |||
1736 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
1737 | const struct clk_ops tegra_clk_pllss_ops = { | ||
1738 | .is_enabled = clk_pll_is_enabled, | ||
1739 | .enable = clk_pll_iddq_enable, | ||
1740 | .disable = clk_pll_iddq_disable, | ||
1741 | .recalc_rate = clk_pll_recalc_rate, | ||
1742 | .round_rate = clk_pll_ramp_round_rate, | ||
1743 | .set_rate = clk_pllxc_set_rate, | ||
1744 | }; | ||
1745 | |||
1746 | struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, | ||
1747 | void __iomem *clk_base, unsigned long flags, | ||
1748 | struct tegra_clk_pll_params *pll_params, | ||
1749 | spinlock_t *lock) | ||
1750 | { | ||
1751 | struct tegra_clk_pll *pll; | ||
1752 | struct clk *clk, *parent; | ||
1753 | struct tegra_clk_pll_freq_table cfg; | ||
1754 | unsigned long parent_rate; | ||
1755 | u32 val; | ||
1756 | int i; | ||
1757 | |||
1758 | if (!pll_params->div_nmp) | ||
1759 | return ERR_PTR(-EINVAL); | ||
1760 | |||
1761 | parent = __clk_lookup(parent_name); | ||
1762 | if (IS_ERR(parent)) { | ||
1763 | WARN(1, "parent clk %s of %s must be registered first\n", | ||
1764 | name, parent_name); | ||
1765 | return ERR_PTR(-EINVAL); | ||
1766 | } | ||
1767 | |||
1768 | pll_params->flags = TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_USE_LOCK; | ||
1769 | pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); | ||
1770 | if (IS_ERR(pll)) | ||
1771 | return ERR_CAST(pll); | ||
1772 | |||
1773 | val = pll_readl_base(pll); | ||
1774 | val &= ~PLLSS_REF_SRC_SEL_MASK; | ||
1775 | pll_writel_base(val, pll); | ||
1776 | |||
1777 | parent_rate = __clk_get_rate(parent); | ||
1778 | |||
1779 | pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); | ||
1780 | |||
1781 | /* initialize PLL to minimum rate */ | ||
1782 | |||
1783 | cfg.m = _pll_fixed_mdiv(pll_params, parent_rate); | ||
1784 | cfg.n = cfg.m * pll_params->vco_min / parent_rate; | ||
1785 | |||
1786 | for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++) | ||
1787 | ; | ||
1788 | if (!i) { | ||
1789 | kfree(pll); | ||
1790 | return ERR_PTR(-EINVAL); | ||
1791 | } | ||
1792 | |||
1793 | cfg.p = pll_params->pdiv_tohw[i-1].hw_val; | ||
1794 | |||
1795 | _update_pll_mnp(pll, &cfg); | ||
1796 | |||
1797 | pll_writel_misc(PLLSS_MISC_DEFAULT, pll); | ||
1798 | pll_writel(PLLSS_CFG_DEFAULT, pll_params->ext_misc_reg[0], pll); | ||
1799 | pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[1], pll); | ||
1800 | pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[2], pll); | ||
1801 | |||
1802 | val = pll_readl_base(pll); | ||
1803 | if (val & PLL_BASE_ENABLE) { | ||
1804 | if (val & BIT(pll_params->iddq_bit_idx)) { | ||
1805 | WARN(1, "%s is on but IDDQ set\n", name); | ||
1806 | kfree(pll); | ||
1807 | return ERR_PTR(-EINVAL); | ||
1808 | } | ||
1809 | } else | ||
1810 | val |= BIT(pll_params->iddq_bit_idx); | ||
1811 | |||
1812 | val &= ~PLLSS_LOCK_OVERRIDE; | ||
1813 | pll_writel_base(val, pll); | ||
1814 | |||
1815 | clk = _tegra_clk_register_pll(pll, name, parent_name, flags, | ||
1816 | &tegra_clk_pllss_ops); | ||
1817 | |||
1818 | if (IS_ERR(clk)) | ||
1819 | kfree(pll); | ||
1820 | |||
1821 | return clk; | ||
1822 | } | ||
1823 | #endif | ||
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 05abfc5fdff8..7f110acfe2a1 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h | |||
@@ -298,6 +298,11 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name, | |||
298 | struct tegra_clk_pll_params *pll_params, | 298 | struct tegra_clk_pll_params *pll_params, |
299 | spinlock_t *lock); | 299 | spinlock_t *lock); |
300 | 300 | ||
301 | struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, | ||
302 | void __iomem *clk_base, unsigned long flags, | ||
303 | struct tegra_clk_pll_params *pll_params, | ||
304 | spinlock_t *lock); | ||
305 | |||
301 | /** | 306 | /** |
302 | * struct tegra_clk_pll_out - PLL divider down clock | 307 | * struct tegra_clk_pll_out - PLL divider down clock |
303 | * | 308 | * |