.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms and conditions of the GNU General Public License, |
---|
6 | | - * version 2, as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
11 | | - * more details. |
---|
12 | | - * |
---|
13 | | - * You should have received a copy of the GNU General Public License |
---|
14 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
15 | 4 | */ |
---|
16 | 5 | |
---|
17 | 6 | #include <linux/slab.h> |
---|
.. | .. |
---|
338 | 327 | return clk_pll_wait_for_lock(pll); |
---|
339 | 328 | } |
---|
340 | 329 | |
---|
| 330 | +static bool pllm_clk_is_gated_by_pmc(struct tegra_clk_pll *pll) |
---|
| 331 | +{ |
---|
| 332 | + u32 val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); |
---|
| 333 | + |
---|
| 334 | + return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) && |
---|
| 335 | + !(val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE); |
---|
| 336 | +} |
---|
| 337 | + |
---|
341 | 338 | static int clk_pll_is_enabled(struct clk_hw *hw) |
---|
342 | 339 | { |
---|
343 | 340 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
344 | 341 | u32 val; |
---|
345 | 342 | |
---|
346 | | - if (pll->params->flags & TEGRA_PLLM) { |
---|
347 | | - val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); |
---|
348 | | - if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) |
---|
349 | | - return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; |
---|
350 | | - } |
---|
| 343 | + /* |
---|
| 344 | + * Power Management Controller (PMC) can override the PLLM clock |
---|
| 345 | + * settings, including the enable-state. The PLLM is enabled when |
---|
| 346 | + * PLLM's CaR state is ON and when PLLM isn't gated by PMC. |
---|
| 347 | + */ |
---|
| 348 | + if ((pll->params->flags & TEGRA_PLLM) && pllm_clk_is_gated_by_pmc(pll)) |
---|
| 349 | + return 0; |
---|
351 | 350 | |
---|
352 | 351 | val = pll_readl_base(pll); |
---|
353 | 352 | |
---|
.. | .. |
---|
443 | 442 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
444 | 443 | unsigned long flags = 0; |
---|
445 | 444 | int ret; |
---|
| 445 | + |
---|
| 446 | + if (clk_pll_is_enabled(hw)) |
---|
| 447 | + return 0; |
---|
446 | 448 | |
---|
447 | 449 | if (pll->lock) |
---|
448 | 450 | spin_lock_irqsave(pll->lock, flags); |
---|
.. | .. |
---|
590 | 592 | cfg->n = cfg->output_rate / cfreq; |
---|
591 | 593 | cfg->cpcon = OUT_OF_TABLE_CPCON; |
---|
592 | 594 | |
---|
593 | | - if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || |
---|
594 | | - (1 << p_div) > divp_max(pll) |
---|
595 | | - || cfg->output_rate > pll->params->vco_max) { |
---|
| 595 | + if (cfg->m == 0 || cfg->m > divm_max(pll) || |
---|
| 596 | + cfg->n > divn_max(pll) || (1 << p_div) > divp_max(pll) || |
---|
| 597 | + cfg->output_rate > pll->params->vco_max) { |
---|
596 | 598 | return -EINVAL; |
---|
597 | 599 | } |
---|
598 | 600 | |
---|
| 601 | + cfg->output_rate = cfg->n * DIV_ROUND_UP(parent_rate, cfg->m); |
---|
599 | 602 | cfg->output_rate >>= p_div; |
---|
600 | 603 | |
---|
601 | 604 | if (pll->params->pdiv_tohw) { |
---|
.. | .. |
---|
751 | 754 | |
---|
752 | 755 | state = clk_pll_is_enabled(hw); |
---|
753 | 756 | |
---|
| 757 | + if (state && pll->params->pre_rate_change) { |
---|
| 758 | + ret = pll->params->pre_rate_change(); |
---|
| 759 | + if (WARN_ON(ret)) |
---|
| 760 | + return ret; |
---|
| 761 | + } |
---|
| 762 | + |
---|
754 | 763 | _get_pll_mnp(pll, &old_cfg); |
---|
755 | 764 | |
---|
756 | 765 | if (state && pll->params->defaults_set && pll->params->dyn_ramp && |
---|
757 | 766 | (cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) { |
---|
758 | 767 | ret = pll->params->dyn_ramp(pll, cfg); |
---|
759 | 768 | if (!ret) |
---|
760 | | - return 0; |
---|
| 769 | + goto done; |
---|
761 | 770 | } |
---|
762 | 771 | |
---|
763 | 772 | if (state) { |
---|
.. | .. |
---|
778 | 787 | ret = clk_pll_wait_for_lock(pll); |
---|
779 | 788 | pll_clk_start_ss(pll); |
---|
780 | 789 | } |
---|
| 790 | + |
---|
| 791 | +done: |
---|
| 792 | + if (state && pll->params->post_rate_change) |
---|
| 793 | + pll->params->post_rate_change(); |
---|
781 | 794 | |
---|
782 | 795 | return ret; |
---|
783 | 796 | } |
---|
.. | .. |
---|
939 | 952 | static int clk_plle_enable(struct clk_hw *hw) |
---|
940 | 953 | { |
---|
941 | 954 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
942 | | - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
943 | 955 | struct tegra_clk_pll_freq_table sel; |
---|
| 956 | + unsigned long input_rate; |
---|
944 | 957 | u32 val; |
---|
945 | 958 | int err; |
---|
| 959 | + |
---|
| 960 | + if (clk_pll_is_enabled(hw)) |
---|
| 961 | + return 0; |
---|
| 962 | + |
---|
| 963 | + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
946 | 964 | |
---|
947 | 965 | if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) |
---|
948 | 966 | return -EINVAL; |
---|
.. | .. |
---|
1010 | 1028 | return rate; |
---|
1011 | 1029 | } |
---|
1012 | 1030 | |
---|
| 1031 | +static void tegra_clk_pll_restore_context(struct clk_hw *hw) |
---|
| 1032 | +{ |
---|
| 1033 | + struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
| 1034 | + struct clk_hw *parent = clk_hw_get_parent(hw); |
---|
| 1035 | + unsigned long parent_rate = clk_hw_get_rate(parent); |
---|
| 1036 | + unsigned long rate = clk_hw_get_rate(hw); |
---|
| 1037 | + |
---|
| 1038 | + if (clk_pll_is_enabled(hw)) |
---|
| 1039 | + return; |
---|
| 1040 | + |
---|
| 1041 | + if (pll->params->set_defaults) |
---|
| 1042 | + pll->params->set_defaults(pll); |
---|
| 1043 | + |
---|
| 1044 | + clk_pll_set_rate(hw, rate, parent_rate); |
---|
| 1045 | + |
---|
| 1046 | + if (!__clk_get_enable_count(hw->clk)) |
---|
| 1047 | + clk_pll_disable(hw); |
---|
| 1048 | + else |
---|
| 1049 | + clk_pll_enable(hw); |
---|
| 1050 | +} |
---|
| 1051 | + |
---|
1013 | 1052 | const struct clk_ops tegra_clk_pll_ops = { |
---|
1014 | 1053 | .is_enabled = clk_pll_is_enabled, |
---|
1015 | 1054 | .enable = clk_pll_enable, |
---|
.. | .. |
---|
1017 | 1056 | .recalc_rate = clk_pll_recalc_rate, |
---|
1018 | 1057 | .round_rate = clk_pll_round_rate, |
---|
1019 | 1058 | .set_rate = clk_pll_set_rate, |
---|
| 1059 | + .restore_context = tegra_clk_pll_restore_context, |
---|
1020 | 1060 | }; |
---|
1021 | 1061 | |
---|
1022 | 1062 | const struct clk_ops tegra_clk_plle_ops = { |
---|
.. | .. |
---|
1355 | 1395 | int ret; |
---|
1356 | 1396 | unsigned long flags = 0; |
---|
1357 | 1397 | |
---|
| 1398 | + if (clk_pll_is_enabled(hw)) |
---|
| 1399 | + return 0; |
---|
| 1400 | + |
---|
1358 | 1401 | if (pll->lock) |
---|
1359 | 1402 | spin_lock_irqsave(pll->lock, flags); |
---|
1360 | 1403 | |
---|
.. | .. |
---|
1567 | 1610 | u32 val; |
---|
1568 | 1611 | int ret; |
---|
1569 | 1612 | unsigned long flags = 0; |
---|
1570 | | - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
| 1613 | + unsigned long input_rate; |
---|
| 1614 | + |
---|
| 1615 | + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
1571 | 1616 | |
---|
1572 | 1617 | if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) |
---|
1573 | 1618 | return -EINVAL; |
---|
.. | .. |
---|
1626 | 1671 | pll_writel(val, PLLE_SS_CTRL, pll); |
---|
1627 | 1672 | udelay(1); |
---|
1628 | 1673 | |
---|
1629 | | - /* Enable hw control of xusb brick pll */ |
---|
| 1674 | + /* Enable HW control of XUSB brick PLL */ |
---|
1630 | 1675 | val = pll_readl_misc(pll); |
---|
1631 | 1676 | val &= ~PLLE_MISC_IDDQ_SW_CTRL; |
---|
1632 | 1677 | pll_writel_misc(val, pll); |
---|
.. | .. |
---|
1649 | 1694 | val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; |
---|
1650 | 1695 | pll_writel(val, XUSBIO_PLL_CFG0, pll); |
---|
1651 | 1696 | |
---|
1652 | | - /* Enable hw control of SATA pll */ |
---|
| 1697 | + /* Enable HW control of SATA PLL */ |
---|
1653 | 1698 | val = pll_readl(SATA_PLL_CFG0, pll); |
---|
1654 | 1699 | val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; |
---|
1655 | 1700 | val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET; |
---|
.. | .. |
---|
1795 | 1840 | |
---|
1796 | 1841 | return ret; |
---|
1797 | 1842 | } |
---|
| 1843 | + |
---|
| 1844 | +static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll) |
---|
| 1845 | +{ |
---|
| 1846 | + u32 val, val_aux; |
---|
| 1847 | + |
---|
| 1848 | + /* ensure parent is set to pll_ref */ |
---|
| 1849 | + val = pll_readl_base(pll); |
---|
| 1850 | + val_aux = pll_readl(pll->params->aux_reg, pll); |
---|
| 1851 | + |
---|
| 1852 | + if (val & PLL_BASE_ENABLE) { |
---|
| 1853 | + if ((val_aux & PLLE_AUX_PLLRE_SEL) || |
---|
| 1854 | + (val_aux & PLLE_AUX_PLLP_SEL)) |
---|
| 1855 | + WARN(1, "pll_e enabled with unsupported parent %s\n", |
---|
| 1856 | + (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : |
---|
| 1857 | + "pll_re_vco"); |
---|
| 1858 | + } else { |
---|
| 1859 | + val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); |
---|
| 1860 | + pll_writel(val_aux, pll->params->aux_reg, pll); |
---|
| 1861 | + fence_udelay(1, pll->clk_base); |
---|
| 1862 | + } |
---|
| 1863 | +} |
---|
1798 | 1864 | #endif |
---|
1799 | 1865 | |
---|
1800 | 1866 | static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, |
---|
.. | .. |
---|
1823 | 1889 | const char *name, const char *parent_name, unsigned long flags, |
---|
1824 | 1890 | const struct clk_ops *ops) |
---|
1825 | 1891 | { |
---|
1826 | | - struct clk_init_data init = {}; |
---|
| 1892 | + struct clk_init_data init; |
---|
1827 | 1893 | |
---|
1828 | 1894 | init.name = name; |
---|
1829 | 1895 | init.ops = ops; |
---|
.. | .. |
---|
2207 | 2273 | { |
---|
2208 | 2274 | struct tegra_clk_pll *pll; |
---|
2209 | 2275 | struct clk *clk; |
---|
2210 | | - u32 val, val_aux; |
---|
2211 | 2276 | |
---|
2212 | 2277 | pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); |
---|
2213 | 2278 | if (IS_ERR(pll)) |
---|
2214 | 2279 | return ERR_CAST(pll); |
---|
2215 | 2280 | |
---|
2216 | | - /* ensure parent is set to pll_re_vco */ |
---|
2217 | | - |
---|
2218 | | - val = pll_readl_base(pll); |
---|
2219 | | - val_aux = pll_readl(pll_params->aux_reg, pll); |
---|
2220 | | - |
---|
2221 | | - if (val & PLL_BASE_ENABLE) { |
---|
2222 | | - if ((val_aux & PLLE_AUX_PLLRE_SEL) || |
---|
2223 | | - (val_aux & PLLE_AUX_PLLP_SEL)) |
---|
2224 | | - WARN(1, "pll_e enabled with unsupported parent %s\n", |
---|
2225 | | - (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : |
---|
2226 | | - "pll_re_vco"); |
---|
2227 | | - } else { |
---|
2228 | | - val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); |
---|
2229 | | - pll_writel(val_aux, pll_params->aux_reg, pll); |
---|
2230 | | - } |
---|
| 2281 | + _clk_plle_tegra_init_parent(pll); |
---|
2231 | 2282 | |
---|
2232 | 2283 | clk = _tegra_clk_register_pll(pll, name, parent_name, flags, |
---|
2233 | 2284 | &tegra_clk_plle_tegra114_ops); |
---|
.. | .. |
---|
2269 | 2320 | .recalc_rate = clk_pll_recalc_rate, |
---|
2270 | 2321 | .round_rate = clk_pll_ramp_round_rate, |
---|
2271 | 2322 | .set_rate = clk_pllxc_set_rate, |
---|
| 2323 | + .restore_context = tegra_clk_pll_restore_context, |
---|
2272 | 2324 | }; |
---|
2273 | 2325 | |
---|
2274 | 2326 | struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, |
---|
.. | .. |
---|
2380 | 2432 | return clk; |
---|
2381 | 2433 | } |
---|
2382 | 2434 | |
---|
| 2435 | +static int clk_plle_tegra210_is_enabled(struct clk_hw *hw) |
---|
| 2436 | +{ |
---|
| 2437 | + struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
| 2438 | + u32 val; |
---|
| 2439 | + |
---|
| 2440 | + val = pll_readl_base(pll); |
---|
| 2441 | + |
---|
| 2442 | + return val & PLLE_BASE_ENABLE ? 1 : 0; |
---|
| 2443 | +} |
---|
| 2444 | + |
---|
2383 | 2445 | static int clk_plle_tegra210_enable(struct clk_hw *hw) |
---|
2384 | 2446 | { |
---|
2385 | 2447 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
.. | .. |
---|
2387 | 2449 | u32 val; |
---|
2388 | 2450 | int ret = 0; |
---|
2389 | 2451 | unsigned long flags = 0; |
---|
2390 | | - unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
| 2452 | + unsigned long input_rate; |
---|
| 2453 | + |
---|
| 2454 | + if (clk_plle_tegra210_is_enabled(hw)) |
---|
| 2455 | + return 0; |
---|
| 2456 | + |
---|
| 2457 | + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); |
---|
2391 | 2458 | |
---|
2392 | 2459 | if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) |
---|
2393 | 2460 | return -EINVAL; |
---|
.. | .. |
---|
2498 | 2565 | spin_unlock_irqrestore(pll->lock, flags); |
---|
2499 | 2566 | } |
---|
2500 | 2567 | |
---|
2501 | | -static int clk_plle_tegra210_is_enabled(struct clk_hw *hw) |
---|
| 2568 | +static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw) |
---|
2502 | 2569 | { |
---|
2503 | 2570 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
---|
2504 | | - u32 val; |
---|
2505 | 2571 | |
---|
2506 | | - val = pll_readl_base(pll); |
---|
2507 | | - |
---|
2508 | | - return val & PLLE_BASE_ENABLE ? 1 : 0; |
---|
| 2572 | + _clk_plle_tegra_init_parent(pll); |
---|
2509 | 2573 | } |
---|
2510 | 2574 | |
---|
2511 | 2575 | static const struct clk_ops tegra_clk_plle_tegra210_ops = { |
---|
.. | .. |
---|
2513 | 2577 | .enable = clk_plle_tegra210_enable, |
---|
2514 | 2578 | .disable = clk_plle_tegra210_disable, |
---|
2515 | 2579 | .recalc_rate = clk_pll_recalc_rate, |
---|
| 2580 | + .restore_context = tegra_clk_plle_t210_restore_context, |
---|
2516 | 2581 | }; |
---|
2517 | 2582 | |
---|
2518 | 2583 | struct clk *tegra_clk_register_plle_tegra210(const char *name, |
---|
.. | .. |
---|
2523 | 2588 | { |
---|
2524 | 2589 | struct tegra_clk_pll *pll; |
---|
2525 | 2590 | struct clk *clk; |
---|
2526 | | - u32 val, val_aux; |
---|
2527 | 2591 | |
---|
2528 | 2592 | pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); |
---|
2529 | 2593 | if (IS_ERR(pll)) |
---|
2530 | 2594 | return ERR_CAST(pll); |
---|
2531 | 2595 | |
---|
2532 | | - /* ensure parent is set to pll_re_vco */ |
---|
2533 | | - |
---|
2534 | | - val = pll_readl_base(pll); |
---|
2535 | | - val_aux = pll_readl(pll_params->aux_reg, pll); |
---|
2536 | | - |
---|
2537 | | - if (val & PLLE_BASE_ENABLE) { |
---|
2538 | | - if ((val_aux & PLLE_AUX_PLLRE_SEL) || |
---|
2539 | | - (val_aux & PLLE_AUX_PLLP_SEL)) |
---|
2540 | | - WARN(1, "pll_e enabled with unsupported parent %s\n", |
---|
2541 | | - (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : |
---|
2542 | | - "pll_re_vco"); |
---|
2543 | | - } else { |
---|
2544 | | - val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); |
---|
2545 | | - pll_writel(val_aux, pll_params->aux_reg, pll); |
---|
2546 | | - } |
---|
| 2596 | + _clk_plle_tegra_init_parent(pll); |
---|
2547 | 2597 | |
---|
2548 | 2598 | clk = _tegra_clk_register_pll(pll, name, parent_name, flags, |
---|
2549 | 2599 | &tegra_clk_plle_tegra210_ops); |
---|