Lines Matching +full:tegra210 +full:- +full:pmc

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
8 #include <linux/clk-provider.h>
17 #include <dt-bindings/clock/tegra210-car.h>
18 #include <dt-bindings/reset/tegra210-car.h>
20 #include <soc/tegra/pmc.h>
23 #include "clk-id.h"
27 * banks present in the Tegra210 CAR IP block. The banks are
264 * SDM fractional divisor is 16-bit 2's complement signed number within
265 * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned
266 * 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used to
275 #define sdin_get_n_eff(cfg) ((cfg)->n * PLL_SDM_COEFF + ((cfg)->sdm_data ? \
276 (PLL_SDM_COEFF/2 + sdin_data_to_din((cfg)->sdm_data)) : 0))
582 val = readl_relaxed(clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
583 writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
585 writel_relaxed(val, clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
691 u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]); in _pll_misc_chk_default()
699 params->defaults_set = false; in _pll_misc_chk_default()
732 pllcx->params->defaults_set = true; in tegra210_pllcx_set_defaults()
734 if (readl_relaxed(clk_base + pllcx->params->base_reg) & PLL_ENABLE) { in tegra210_pllcx_set_defaults()
736 pllcx_check_defaults(pllcx->params); in tegra210_pllcx_set_defaults()
737 if (!pllcx->params->defaults_set) in tegra210_pllcx_set_defaults()
745 clk_base + pllcx->params->ext_misc_reg[0]); in tegra210_pllcx_set_defaults()
747 clk_base + pllcx->params->ext_misc_reg[1]); in tegra210_pllcx_set_defaults()
749 clk_base + pllcx->params->ext_misc_reg[2]); in tegra210_pllcx_set_defaults()
751 clk_base + pllcx->params->ext_misc_reg[3]); in tegra210_pllcx_set_defaults()
783 u32 val = readl_relaxed(clk_base + plla->params->base_reg); in tegra210_plla_set_defaults()
785 plla->params->defaults_set = true; in tegra210_plla_set_defaults()
794 plla->params->defaults_set = false; in tegra210_plla_set_defaults()
801 _pll_misc_chk_default(clk_base, plla->params, 0, val, in tegra210_plla_set_defaults()
805 _pll_misc_chk_default(clk_base, plla->params, 2, val, in tegra210_plla_set_defaults()
809 val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
812 writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
820 writel_relaxed(val, clk_base + plla->params->base_reg); in tegra210_plla_set_defaults()
822 clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
824 clk_base + plla->params->ext_misc_reg[2]); in tegra210_plla_set_defaults()
837 plld->params->defaults_set = true; in tegra210_plld_set_defaults()
839 if (readl_relaxed(clk_base + plld->params->base_reg) & in tegra210_plld_set_defaults()
847 _pll_misc_chk_default(clk_base, plld->params, 1, in tegra210_plld_set_defaults()
854 _pll_misc_chk_default(clk_base, plld->params, 0, val, in tegra210_plld_set_defaults()
857 if (!plld->params->defaults_set) in tegra210_plld_set_defaults()
862 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
865 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
871 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
875 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
877 plld->params->ext_misc_reg[1]); in tegra210_plld_set_defaults()
889 u32 val = readl_relaxed(clk_base + plldss->params->base_reg); in plldss_defaults()
891 plldss->params->defaults_set = true; in plldss_defaults()
901 plldss->params->defaults_set = false; in plldss_defaults()
906 _pll_misc_chk_default(clk_base, plldss->params, 0, default_val, in plldss_defaults()
915 if (plldss->params->ssc_ctrl_en_mask) { in plldss_defaults()
917 _pll_misc_chk_default(clk_base, plldss->params, 1, in plldss_defaults()
920 _pll_misc_chk_default(clk_base, plldss->params, 2, in plldss_defaults()
923 _pll_misc_chk_default(clk_base, plldss->params, 3, in plldss_defaults()
925 } else if (plldss->params->ext_misc_reg[1]) { in plldss_defaults()
927 _pll_misc_chk_default(clk_base, plldss->params, 1, in plldss_defaults()
932 if (!plldss->params->defaults_set) in plldss_defaults()
940 plldss->params->base_reg); in plldss_defaults()
943 val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]); in plldss_defaults()
946 writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]); in plldss_defaults()
955 writel_relaxed(val, clk_base + plldss->params->base_reg); in plldss_defaults()
958 if (!plldss->params->ext_misc_reg[1]) { in plldss_defaults()
960 plldss->params->ext_misc_reg[0]); in plldss_defaults()
966 plldss->params->ext_misc_reg[0]); in plldss_defaults()
969 clk_base + plldss->params->ext_misc_reg[1]); in plldss_defaults()
970 writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]); in plldss_defaults()
971 writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]); in plldss_defaults()
1003 * VCO is exposed to the clock tree directly along with post-divider output
1008 u32 val = readl_relaxed(clk_base + pllre->params->base_reg); in tegra210_pllre_set_defaults()
1010 pllre->params->defaults_set = true; in tegra210_pllre_set_defaults()
1023 pllre->params->defaults_set = false; in tegra210_pllre_set_defaults()
1029 _pll_misc_chk_default(clk_base, pllre->params, 0, val, in tegra210_pllre_set_defaults()
1033 val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1040 writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1043 if (!pllre->params->defaults_set) in tegra210_pllre_set_defaults()
1052 writel_relaxed(val, clk_base + pllre->params->base_reg); in tegra210_pllre_set_defaults()
1054 clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1063 if (!IS_ERR_OR_NULL(hw->clk)) in pllx_get_dyn_steps()
1098 _pll_misc_chk_default(clk_base, pll->params, 0, default_val, in pllx_check_defaults()
1102 _pll_misc_chk_default(clk_base, pll->params, 1, default_val, in pllx_check_defaults()
1107 _pll_misc_chk_default(clk_base, pll->params, 2, in pllx_check_defaults()
1111 _pll_misc_chk_default(clk_base, pll->params, 3, default_val, in pllx_check_defaults()
1115 _pll_misc_chk_default(clk_base, pll->params, 4, default_val, in pllx_check_defaults()
1119 _pll_misc_chk_default(clk_base, pll->params, 5, default_val, in pllx_check_defaults()
1128 pllx->params->defaults_set = true; in tegra210_pllx_set_defaults()
1131 pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b); in tegra210_pllx_set_defaults()
1137 if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) { in tegra210_pllx_set_defaults()
1145 if (!pllx->params->defaults_set) in tegra210_pllx_set_defaults()
1148 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_set_defaults()
1151 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1154 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1162 pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1166 pllx->params->ext_misc_reg[1]); in tegra210_pllx_set_defaults()
1169 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_set_defaults()
1173 pllx->params->ext_misc_reg[3]); in tegra210_pllx_set_defaults()
1177 pllx->params->ext_misc_reg[4]); in tegra210_pllx_set_defaults()
1179 pllx->params->ext_misc_reg[5]); in tegra210_pllx_set_defaults()
1186 u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg); in tegra210_pllmb_set_defaults()
1188 pllmb->params->defaults_set = true; in tegra210_pllmb_set_defaults()
1198 _pll_misc_chk_default(clk_base, pllmb->params, 0, val, in tegra210_pllmb_set_defaults()
1201 if (!pllmb->params->defaults_set) in tegra210_pllmb_set_defaults()
1204 val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1207 writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1215 clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1221 * VCO is exposed to the clock tree directly along with post-divider output.
1222 * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz,
1234 _pll_misc_chk_default(clk_base, pll->params, 0, val, in pllp_check_defaults()
1240 _pll_misc_chk_default(clk_base, pll->params, 1, val, in pllp_check_defaults()
1247 u32 val = readl_relaxed(clk_base + pllp->params->base_reg); in tegra210_pllp_set_defaults()
1249 pllp->params->defaults_set = true; in tegra210_pllp_set_defaults()
1258 if (!pllp->params->defaults_set) in tegra210_pllp_set_defaults()
1262 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1266 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1274 clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1277 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]); in tegra210_pllp_set_defaults()
1281 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]); in tegra210_pllp_set_defaults()
1287 * VCO is exposed to the clock tree directly along with post-divider output.
1288 * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz,
1310 u32 val = readl_relaxed(clk_base + pllu->base_reg); in tegra210_pllu_set_defaults()
1312 pllu->defaults_set = true; in tegra210_pllu_set_defaults()
1321 if (!pllu->defaults_set) in tegra210_pllu_set_defaults()
1325 val = readl_relaxed(clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1328 writel_relaxed(val, clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1330 val = readl_relaxed(clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1333 writel_relaxed(val, clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1341 clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1343 clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1347 #define mask(w) ((1 << (w)) - 1)
1348 #define divm_mask(p) mask(p->params->div_nmp->divm_width)
1349 #define divn_mask(p) mask(p->params->div_nmp->divn_width)
1350 #define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
1351 mask(p->params->div_nmp->divp_width))
1353 #define divm_shift(p) ((p)->params->div_nmp->divm_shift)
1354 #define divn_shift(p) ((p)->params->div_nmp->divn_shift)
1355 #define divp_shift(p) ((p)->params->div_nmp->divp_shift)
1368 for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) { in tegra210_wait_for_mask()
1376 return -ETIMEDOUT; in tegra210_wait_for_mask()
1384 ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift) in tegra210_pllx_dyn_ramp()
1387 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1389 val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT; in tegra210_pllx_dyn_ramp()
1390 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1393 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1395 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1398 tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2], in tegra210_pllx_dyn_ramp()
1401 base = readl_relaxed(clk_base + pllx->params->base_reg) & in tegra210_pllx_dyn_ramp()
1403 base |= cfg->n << pllx->params->div_nmp->divn_shift; in tegra210_pllx_dyn_ramp()
1404 writel_relaxed(base, clk_base + pllx->params->base_reg); in tegra210_pllx_dyn_ramp()
1408 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1412 __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p, in tegra210_pllx_dyn_ramp()
1413 cfg->input_rate / cfg->m * cfg->n / in tegra210_pllx_dyn_ramp()
1414 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000); in tegra210_pllx_dyn_ramp()
1421 * - always set fixed M-value based on the reference rate
1422 * - always set P-value value 1:1 for output rates above VCO minimum, and
1423 * choose minimum necessary P-value for output rates below VCO maximum
1424 * - calculate N-value based on selected M and P
1425 * - calculate SDM_DIN fractional part
1432 struct tegra_clk_pll_params *params = pll->params; in tegra210_pll_fixed_mdiv_cfg()
1438 return -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1440 if (!(params->flags & TEGRA_PLL_VCO_OUT)) { in tegra210_pll_fixed_mdiv_cfg()
1441 p = DIV_ROUND_UP(params->vco_min, rate); in tegra210_pll_fixed_mdiv_cfg()
1442 p = params->round_p_to_pdiv(p, &pdiv); in tegra210_pll_fixed_mdiv_cfg()
1444 p = rate >= params->vco_min ? 1 : -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1448 return -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1450 cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate); in tegra210_pll_fixed_mdiv_cfg()
1451 cfg->p = p; in tegra210_pll_fixed_mdiv_cfg()
1454 cfg->p = tegra_pll_p_div_to_hw(pll, cfg->p); in tegra210_pll_fixed_mdiv_cfg()
1457 if (p_rate > params->vco_max) in tegra210_pll_fixed_mdiv_cfg()
1458 p_rate = params->vco_max; in tegra210_pll_fixed_mdiv_cfg()
1459 cf = input_rate / cfg->m; in tegra210_pll_fixed_mdiv_cfg()
1460 cfg->n = p_rate / cf; in tegra210_pll_fixed_mdiv_cfg()
1462 cfg->sdm_data = 0; in tegra210_pll_fixed_mdiv_cfg()
1463 cfg->output_rate = input_rate; in tegra210_pll_fixed_mdiv_cfg()
1464 if (params->sdm_ctrl_reg) { in tegra210_pll_fixed_mdiv_cfg()
1465 unsigned long rem = p_rate - cf * cfg->n; in tegra210_pll_fixed_mdiv_cfg()
1467 if (rem || params->ssc_ctrl_reg) { in tegra210_pll_fixed_mdiv_cfg()
1471 s -= PLL_SDM_COEFF / 2; in tegra210_pll_fixed_mdiv_cfg()
1472 cfg->sdm_data = sdin_din_to_data(s); in tegra210_pll_fixed_mdiv_cfg()
1474 cfg->output_rate *= sdin_get_n_eff(cfg); in tegra210_pll_fixed_mdiv_cfg()
1475 cfg->output_rate /= p * cfg->m * PLL_SDM_COEFF; in tegra210_pll_fixed_mdiv_cfg()
1477 cfg->output_rate *= cfg->n; in tegra210_pll_fixed_mdiv_cfg()
1478 cfg->output_rate /= p * cfg->m; in tegra210_pll_fixed_mdiv_cfg()
1481 cfg->input_rate = input_rate; in tegra210_pll_fixed_mdiv_cfg()
1487 * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
1499 cfg->n = sdin_get_n_eff(cfg); in tegra210_clk_pll_set_gain()
1500 cfg->m *= PLL_SDM_COEFF; in tegra210_clk_pll_set_gain()
1507 unsigned long vco_min = params->vco_min; in tegra210_clk_adjust_vco_min()
1509 params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF); in tegra210_clk_adjust_vco_min()
1510 vco_min = min(vco_min, params->vco_min); in tegra210_clk_adjust_vco_min()
1524 * PLL post divider maps - two types: quasi-linear and exponential
1562 return -EINVAL; in pll_qlin_p_to_pdiv()
1583 i--; in pll_expo_p_to_pdiv()
1591 return -EINVAL; in pll_expo_p_to_pdiv()
2165 /* disable spread-spectrum for pll_d2 */
2566 { .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
2699 return -EINVAL; in tegra210_clk_handle_mbist_war()
2703 if (!mbist_war->handle_lvl2_ovr) in tegra210_clk_handle_mbist_war()
2706 if (mbist_war->num_clks && !mbist_war->clks) in tegra210_clk_handle_mbist_war()
2707 return -ENODEV; in tegra210_clk_handle_mbist_war()
2709 err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks); in tegra210_clk_handle_mbist_war()
2715 mbist_war->handle_lvl2_ovr(mbist_war); in tegra210_clk_handle_mbist_war()
2719 clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks); in tegra210_clk_handle_mbist_war()
2775 /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ in tegra210_utmi_param_configure()
2848 for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) { in tegra210_enable_pllu()
2849 if (fentry->input_rate == pll_ref_freq) in tegra210_enable_pllu()
2853 if (!fentry->input_rate) { in tegra210_enable_pllu()
2855 return -EINVAL; in tegra210_enable_pllu()
2860 reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]); in tegra210_enable_pllu()
2861 reg &= ~BIT(pllu.params->iddq_bit_idx); in tegra210_enable_pllu()
2862 writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]); in tegra210_enable_pllu()
2867 reg |= fentry->m; in tegra210_enable_pllu()
2868 reg |= fentry->n << 8; in tegra210_enable_pllu()
2869 reg |= fentry->p << 16; in tegra210_enable_pllu()
2884 return -ETIMEDOUT; in tegra210_enable_pllu()
3009 * On Tegra210, the sor0 clock doesn't have a mux it bitfield 31:29,
3123 clkp = tegra_lookup_dt_id(init->clk_id, tegra210_clks); in tegra210_periph_clk_init()
3125 pr_warn("clock %u not found\n", init->clk_id); in tegra210_periph_clk_init()
3144 void __iomem *pmc) in tegra210_pll_init() argument
3150 pmc, 0, &pll_c_params, NULL); in tegra210_pll_init()
3173 pmc, 0, &pll_c2_params, NULL); in tegra210_pll_init()
3179 pmc, 0, &pll_c3_params, NULL); in tegra210_pll_init()
3184 clk = tegra_clk_register_pllm("pll_m", "osc", clk_base, pmc, in tegra210_pll_init()
3190 clk = tegra_clk_register_pllmb("pll_mb", "osc", clk_base, pmc, in tegra210_pll_init()
3271 clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, in tegra210_pll_init()
3284 clk_base, pmc, 0, in tegra210_pll_init()
3312 clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc, in tegra210_pll_init()
3372 /* Tegra210 CPU clock and reset control functions */
3492 { .compatible = "nvidia,tegra210-pmc" },
3527 /* TODO find a way to enable this on-demand */
3554 * tegra210_clock_apply_init_table - initialize clocks on Tegra210 SoCs
3557 * by the rest of the kernel, for Tegra210 SoCs. It is intended to be
3558 * called by assigning a pointer to it to tegra_clk_apply_init_table -
3567 * tegra210_car_barrier - wait for pending writes to the CAR to complete
3578 * tegra210_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
3593 * tegra210_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
3616 return -EINVAL; in tegra210_reset_assert()
3636 return -EINVAL; in tegra210_reset_deassert()
3673 * tegra210_clock_init - Tegra210-specific clock initialization
3676 * Register most SoC clocks for the Tegra210 system-on-chip. Intended
3678 * "nvidia,tegra210-car" string is encountered, and declared with
3688 pr_err("ioremap tegra210 CAR failed\n"); in tegra210_clock_init()
3694 pr_err("Failed to find pmc node\n"); in tegra210_clock_init()
3701 pr_err("Can't map pmc registers\n"); in tegra210_clock_init()
3708 pr_err("ioremap tegra210 APE failed\n"); in tegra210_clock_init()
3714 pr_err("ioremap tegra210 DISPA failed\n"); in tegra210_clock_init()
3720 pr_err("ioremap tegra210 VIC failed\n"); in tegra210_clock_init()
3744 /* For Tegra210, PLLD is the only source for DSIA & DSIB */ in tegra210_clock_init()
3765 CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);