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

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012-2020 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))
522 return -EIO; in tegra210_plle_hw_sequence_start()
633 val = readl_relaxed(clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
634 writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
636 writel_relaxed(val, clk_base + mbist->lvl2_offset); in tegra210_generic_mbist_war()
742 u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]); in _pll_misc_chk_default()
750 params->defaults_set = false; in _pll_misc_chk_default()
783 pllcx->params->defaults_set = true; in tegra210_pllcx_set_defaults()
785 if (readl_relaxed(clk_base + pllcx->params->base_reg) & PLL_ENABLE) { in tegra210_pllcx_set_defaults()
787 pllcx_check_defaults(pllcx->params); in tegra210_pllcx_set_defaults()
788 if (!pllcx->params->defaults_set) in tegra210_pllcx_set_defaults()
796 clk_base + pllcx->params->ext_misc_reg[0]); in tegra210_pllcx_set_defaults()
798 clk_base + pllcx->params->ext_misc_reg[1]); in tegra210_pllcx_set_defaults()
800 clk_base + pllcx->params->ext_misc_reg[2]); in tegra210_pllcx_set_defaults()
802 clk_base + pllcx->params->ext_misc_reg[3]); in tegra210_pllcx_set_defaults()
834 u32 val = readl_relaxed(clk_base + plla->params->base_reg); in tegra210_plla_set_defaults()
836 plla->params->defaults_set = true; in tegra210_plla_set_defaults()
845 plla->params->defaults_set = false; in tegra210_plla_set_defaults()
852 _pll_misc_chk_default(clk_base, plla->params, 0, val, in tegra210_plla_set_defaults()
856 _pll_misc_chk_default(clk_base, plla->params, 2, val, in tegra210_plla_set_defaults()
860 val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
863 writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
871 writel_relaxed(val, clk_base + plla->params->base_reg); in tegra210_plla_set_defaults()
873 clk_base + plla->params->ext_misc_reg[0]); in tegra210_plla_set_defaults()
875 clk_base + plla->params->ext_misc_reg[2]); in tegra210_plla_set_defaults()
888 plld->params->defaults_set = true; in tegra210_plld_set_defaults()
890 if (readl_relaxed(clk_base + plld->params->base_reg) & in tegra210_plld_set_defaults()
898 _pll_misc_chk_default(clk_base, plld->params, 1, in tegra210_plld_set_defaults()
905 _pll_misc_chk_default(clk_base, plld->params, 0, val, in tegra210_plld_set_defaults()
908 if (!plld->params->defaults_set) in tegra210_plld_set_defaults()
913 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
916 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
922 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
926 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); in tegra210_plld_set_defaults()
928 plld->params->ext_misc_reg[1]); in tegra210_plld_set_defaults()
940 u32 val = readl_relaxed(clk_base + plldss->params->base_reg); in plldss_defaults()
942 plldss->params->defaults_set = true; in plldss_defaults()
952 plldss->params->defaults_set = false; in plldss_defaults()
957 _pll_misc_chk_default(clk_base, plldss->params, 0, default_val, in plldss_defaults()
966 if (plldss->params->ssc_ctrl_en_mask) { in plldss_defaults()
968 _pll_misc_chk_default(clk_base, plldss->params, 1, in plldss_defaults()
971 _pll_misc_chk_default(clk_base, plldss->params, 2, in plldss_defaults()
974 _pll_misc_chk_default(clk_base, plldss->params, 3, in plldss_defaults()
976 } else if (plldss->params->ext_misc_reg[1]) { in plldss_defaults()
978 _pll_misc_chk_default(clk_base, plldss->params, 1, in plldss_defaults()
983 if (!plldss->params->defaults_set) in plldss_defaults()
991 plldss->params->base_reg); in plldss_defaults()
994 val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]); in plldss_defaults()
997 writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]); in plldss_defaults()
1006 writel_relaxed(val, clk_base + plldss->params->base_reg); in plldss_defaults()
1009 if (!plldss->params->ext_misc_reg[1]) { in plldss_defaults()
1011 plldss->params->ext_misc_reg[0]); in plldss_defaults()
1017 plldss->params->ext_misc_reg[0]); in plldss_defaults()
1020 clk_base + plldss->params->ext_misc_reg[1]); in plldss_defaults()
1021 writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]); in plldss_defaults()
1022 writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]); in plldss_defaults()
1054 * VCO is exposed to the clock tree directly along with post-divider output
1059 u32 val = readl_relaxed(clk_base + pllre->params->base_reg); in tegra210_pllre_set_defaults()
1061 pllre->params->defaults_set = true; in tegra210_pllre_set_defaults()
1074 pllre->params->defaults_set = false; in tegra210_pllre_set_defaults()
1080 _pll_misc_chk_default(clk_base, pllre->params, 0, val, in tegra210_pllre_set_defaults()
1084 val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1091 writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1094 if (!pllre->params->defaults_set) in tegra210_pllre_set_defaults()
1103 writel_relaxed(val, clk_base + pllre->params->base_reg); in tegra210_pllre_set_defaults()
1105 clk_base + pllre->params->ext_misc_reg[0]); in tegra210_pllre_set_defaults()
1114 if (!IS_ERR_OR_NULL(hw->clk)) in pllx_get_dyn_steps()
1149 _pll_misc_chk_default(clk_base, pll->params, 0, default_val, in pllx_check_defaults()
1153 _pll_misc_chk_default(clk_base, pll->params, 1, default_val, in pllx_check_defaults()
1158 _pll_misc_chk_default(clk_base, pll->params, 2, in pllx_check_defaults()
1162 _pll_misc_chk_default(clk_base, pll->params, 3, default_val, in pllx_check_defaults()
1166 _pll_misc_chk_default(clk_base, pll->params, 4, default_val, in pllx_check_defaults()
1170 _pll_misc_chk_default(clk_base, pll->params, 5, default_val, in pllx_check_defaults()
1179 pllx->params->defaults_set = true; in tegra210_pllx_set_defaults()
1182 pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b); in tegra210_pllx_set_defaults()
1188 if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) { in tegra210_pllx_set_defaults()
1196 if (!pllx->params->defaults_set) in tegra210_pllx_set_defaults()
1199 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_set_defaults()
1202 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1205 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1213 pllx->params->ext_misc_reg[0]); in tegra210_pllx_set_defaults()
1217 pllx->params->ext_misc_reg[1]); in tegra210_pllx_set_defaults()
1220 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_set_defaults()
1224 pllx->params->ext_misc_reg[3]); in tegra210_pllx_set_defaults()
1228 pllx->params->ext_misc_reg[4]); in tegra210_pllx_set_defaults()
1230 pllx->params->ext_misc_reg[5]); in tegra210_pllx_set_defaults()
1237 u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg); in tegra210_pllmb_set_defaults()
1239 pllmb->params->defaults_set = true; in tegra210_pllmb_set_defaults()
1249 _pll_misc_chk_default(clk_base, pllmb->params, 0, val, in tegra210_pllmb_set_defaults()
1252 if (!pllmb->params->defaults_set) in tegra210_pllmb_set_defaults()
1255 val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1258 writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1266 clk_base + pllmb->params->ext_misc_reg[0]); in tegra210_pllmb_set_defaults()
1272 * VCO is exposed to the clock tree directly along with post-divider output.
1273 * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz,
1285 _pll_misc_chk_default(clk_base, pll->params, 0, val, in pllp_check_defaults()
1291 _pll_misc_chk_default(clk_base, pll->params, 1, val, in pllp_check_defaults()
1298 u32 val = readl_relaxed(clk_base + pllp->params->base_reg); in tegra210_pllp_set_defaults()
1300 pllp->params->defaults_set = true; in tegra210_pllp_set_defaults()
1309 if (!pllp->params->defaults_set) in tegra210_pllp_set_defaults()
1313 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1317 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1325 clk_base + pllp->params->ext_misc_reg[0]); in tegra210_pllp_set_defaults()
1328 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]); in tegra210_pllp_set_defaults()
1332 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]); in tegra210_pllp_set_defaults()
1338 * VCO is exposed to the clock tree directly along with post-divider output.
1339 * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz,
1361 u32 val = readl_relaxed(clk_base + pllu->base_reg); in tegra210_pllu_set_defaults()
1363 pllu->defaults_set = true; in tegra210_pllu_set_defaults()
1372 if (!pllu->defaults_set) in tegra210_pllu_set_defaults()
1376 val = readl_relaxed(clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1379 writel_relaxed(val, clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1381 val = readl_relaxed(clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1384 writel_relaxed(val, clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1392 clk_base + pllu->ext_misc_reg[0]); in tegra210_pllu_set_defaults()
1394 clk_base + pllu->ext_misc_reg[1]); in tegra210_pllu_set_defaults()
1398 #define mask(w) ((1 << (w)) - 1)
1399 #define divm_mask(p) mask(p->params->div_nmp->divm_width)
1400 #define divn_mask(p) mask(p->params->div_nmp->divn_width)
1401 #define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
1402 mask(p->params->div_nmp->divp_width))
1404 #define divm_shift(p) ((p)->params->div_nmp->divm_shift)
1405 #define divn_shift(p) ((p)->params->div_nmp->divn_shift)
1406 #define divp_shift(p) ((p)->params->div_nmp->divp_shift)
1419 for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) { in tegra210_wait_for_mask()
1427 return -ETIMEDOUT; in tegra210_wait_for_mask()
1435 ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift) in tegra210_pllx_dyn_ramp()
1438 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1440 val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT; in tegra210_pllx_dyn_ramp()
1441 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1444 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1446 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1449 tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2], in tegra210_pllx_dyn_ramp()
1452 base = readl_relaxed(clk_base + pllx->params->base_reg) & in tegra210_pllx_dyn_ramp()
1454 base |= cfg->n << pllx->params->div_nmp->divn_shift; in tegra210_pllx_dyn_ramp()
1455 writel_relaxed(base, clk_base + pllx->params->base_reg); in tegra210_pllx_dyn_ramp()
1459 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); in tegra210_pllx_dyn_ramp()
1463 __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p, in tegra210_pllx_dyn_ramp()
1464 cfg->input_rate / cfg->m * cfg->n / in tegra210_pllx_dyn_ramp()
1465 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000); in tegra210_pllx_dyn_ramp()
1472 * - always set fixed M-value based on the reference rate
1473 * - always set P-value value 1:1 for output rates above VCO minimum, and
1474 * choose minimum necessary P-value for output rates below VCO maximum
1475 * - calculate N-value based on selected M and P
1476 * - calculate SDM_DIN fractional part
1483 struct tegra_clk_pll_params *params = pll->params; in tegra210_pll_fixed_mdiv_cfg()
1489 return -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1491 if (!(params->flags & TEGRA_PLL_VCO_OUT)) { in tegra210_pll_fixed_mdiv_cfg()
1492 p = DIV_ROUND_UP(params->vco_min, rate); in tegra210_pll_fixed_mdiv_cfg()
1493 p = params->round_p_to_pdiv(p, &pdiv); in tegra210_pll_fixed_mdiv_cfg()
1495 p = rate >= params->vco_min ? 1 : -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1499 return -EINVAL; in tegra210_pll_fixed_mdiv_cfg()
1501 cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate); in tegra210_pll_fixed_mdiv_cfg()
1502 cfg->p = p; in tegra210_pll_fixed_mdiv_cfg()
1505 cfg->p = tegra_pll_p_div_to_hw(pll, cfg->p); in tegra210_pll_fixed_mdiv_cfg()
1508 if (p_rate > params->vco_max) in tegra210_pll_fixed_mdiv_cfg()
1509 p_rate = params->vco_max; in tegra210_pll_fixed_mdiv_cfg()
1510 cf = input_rate / cfg->m; in tegra210_pll_fixed_mdiv_cfg()
1511 cfg->n = p_rate / cf; in tegra210_pll_fixed_mdiv_cfg()
1513 cfg->sdm_data = 0; in tegra210_pll_fixed_mdiv_cfg()
1514 cfg->output_rate = input_rate; in tegra210_pll_fixed_mdiv_cfg()
1515 if (params->sdm_ctrl_reg) { in tegra210_pll_fixed_mdiv_cfg()
1516 unsigned long rem = p_rate - cf * cfg->n; in tegra210_pll_fixed_mdiv_cfg()
1518 if (rem || params->ssc_ctrl_reg) { in tegra210_pll_fixed_mdiv_cfg()
1522 s -= PLL_SDM_COEFF / 2; in tegra210_pll_fixed_mdiv_cfg()
1523 cfg->sdm_data = sdin_din_to_data(s); in tegra210_pll_fixed_mdiv_cfg()
1525 cfg->output_rate *= sdin_get_n_eff(cfg); in tegra210_pll_fixed_mdiv_cfg()
1526 cfg->output_rate /= p * cfg->m * PLL_SDM_COEFF; in tegra210_pll_fixed_mdiv_cfg()
1528 cfg->output_rate *= cfg->n; in tegra210_pll_fixed_mdiv_cfg()
1529 cfg->output_rate /= p * cfg->m; in tegra210_pll_fixed_mdiv_cfg()
1532 cfg->input_rate = input_rate; in tegra210_pll_fixed_mdiv_cfg()
1538 * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
1550 cfg->n = sdin_get_n_eff(cfg); in tegra210_clk_pll_set_gain()
1551 cfg->m *= PLL_SDM_COEFF; in tegra210_clk_pll_set_gain()
1558 unsigned long vco_min = params->vco_min; in tegra210_clk_adjust_vco_min()
1560 params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF); in tegra210_clk_adjust_vco_min()
1561 vco_min = min(vco_min, params->vco_min); in tegra210_clk_adjust_vco_min()
1575 * PLL post divider maps - two types: quasi-linear and exponential
1613 return -EINVAL; in pll_qlin_p_to_pdiv()
1634 i--; in pll_expo_p_to_pdiv()
1642 return -EINVAL; in pll_expo_p_to_pdiv()
2216 /* disable spread-spectrum for pll_d2 */
2617 { .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
2750 return -EINVAL; in tegra210_clk_handle_mbist_war()
2754 if (!mbist_war->handle_lvl2_ovr) in tegra210_clk_handle_mbist_war()
2757 if (mbist_war->num_clks && !mbist_war->clks) in tegra210_clk_handle_mbist_war()
2758 return -ENODEV; in tegra210_clk_handle_mbist_war()
2760 err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks); in tegra210_clk_handle_mbist_war()
2766 mbist_war->handle_lvl2_ovr(mbist_war); in tegra210_clk_handle_mbist_war()
2770 clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks); in tegra210_clk_handle_mbist_war()
2826 /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ in tegra210_utmi_param_configure()
2899 for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) { in tegra210_enable_pllu()
2900 if (fentry->input_rate == pll_ref_freq) in tegra210_enable_pllu()
2904 if (!fentry->input_rate) { in tegra210_enable_pllu()
2906 return -EINVAL; in tegra210_enable_pllu()
2911 reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]); in tegra210_enable_pllu()
2912 reg &= ~BIT(pllu.params->iddq_bit_idx); in tegra210_enable_pllu()
2913 writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]); in tegra210_enable_pllu()
2918 reg |= fentry->m; in tegra210_enable_pllu()
2919 reg |= fentry->n << 8; in tegra210_enable_pllu()
2920 reg |= fentry->p << 16; in tegra210_enable_pllu()
2935 return -ETIMEDOUT; in tegra210_enable_pllu()
3060 * On Tegra210, the sor0 clock doesn't have a mux it bitfield 31:29,
3174 clkp = tegra_lookup_dt_id(init->clk_id, tegra210_clks); in tegra210_periph_clk_init()
3176 pr_warn("clock %u not found\n", init->clk_id); in tegra210_periph_clk_init()
3195 void __iomem *pmc) in tegra210_pll_init() argument
3201 pmc, 0, &pll_c_params, NULL); in tegra210_pll_init()
3224 pmc, 0, &pll_c2_params, NULL); in tegra210_pll_init()
3230 pmc, 0, &pll_c3_params, NULL); in tegra210_pll_init()
3235 clk = tegra_clk_register_pllm("pll_m", "osc", clk_base, pmc, in tegra210_pll_init()
3241 clk = tegra_clk_register_pllmb("pll_mb", "osc", clk_base, pmc, in tegra210_pll_init()
3322 clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, in tegra210_pll_init()
3335 clk_base, pmc, 0, in tegra210_pll_init()
3363 clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc, in tegra210_pll_init()
3423 /* Tegra210 CPU clock and reset control functions */
3543 { .compatible = "nvidia,tegra210-pmc" },
3578 /* TODO find a way to enable this on-demand */
3606 * tegra210_clock_apply_init_table - initialize clocks on Tegra210 SoCs
3609 * by the rest of the kernel, for Tegra210 SoCs. It is intended to be
3610 * called by assigning a pointer to it to tegra_clk_apply_init_table -
3619 * tegra210_car_barrier - wait for pending writes to the CAR to complete
3630 * tegra210_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
3645 * tegra210_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
3668 return -EINVAL; in tegra210_reset_assert()
3688 return -EINVAL; in tegra210_reset_deassert()
3725 * tegra210_clock_init - Tegra210-specific clock initialization
3728 * Register most SoC clocks for the Tegra210 system-on-chip. Intended
3730 * "nvidia,tegra210-car" string is encountered, and declared with
3740 pr_err("ioremap tegra210 CAR failed\n"); in tegra210_clock_init()
3746 pr_err("Failed to find pmc node\n"); in tegra210_clock_init()
3754 pr_err("Can't map pmc registers\n"); in tegra210_clock_init()
3761 pr_err("ioremap tegra210 APE failed\n"); in tegra210_clock_init()
3767 pr_err("ioremap tegra210 DISPA failed\n"); in tegra210_clock_init()
3773 pr_err("ioremap tegra210 VIC failed\n"); in tegra210_clock_init()
3797 /* For Tegra210, PLLD is the only source for DSIA & DSIB */ in tegra210_clock_init()
3818 CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);