Lines Matching +full:emc +full:- +full:cfg

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>
23 #include "clk-id.h"
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;
633 val = readl_relaxed(clk_base + mbist->lvl2_offset);
634 writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset);
636 writel_relaxed(val, clk_base + mbist->lvl2_offset);
742 u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]);
750 params->defaults_set = false;
783 pllcx->params->defaults_set = true;
785 if (readl_relaxed(clk_base + pllcx->params->base_reg) & PLL_ENABLE) {
787 pllcx_check_defaults(pllcx->params);
788 if (!pllcx->params->defaults_set)
796 clk_base + pllcx->params->ext_misc_reg[0]);
798 clk_base + pllcx->params->ext_misc_reg[1]);
800 clk_base + pllcx->params->ext_misc_reg[2]);
802 clk_base + pllcx->params->ext_misc_reg[3]);
834 u32 val = readl_relaxed(clk_base + plla->params->base_reg);
836 plla->params->defaults_set = true;
845 plla->params->defaults_set = false;
852 _pll_misc_chk_default(clk_base, plla->params, 0, val,
856 _pll_misc_chk_default(clk_base, plla->params, 2, val,
860 val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]);
863 writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]);
871 writel_relaxed(val, clk_base + plla->params->base_reg);
873 clk_base + plla->params->ext_misc_reg[0]);
875 clk_base + plla->params->ext_misc_reg[2]);
888 plld->params->defaults_set = true;
890 if (readl_relaxed(clk_base + plld->params->base_reg) &
898 _pll_misc_chk_default(clk_base, plld->params, 1,
905 _pll_misc_chk_default(clk_base, plld->params, 0, val,
908 if (!plld->params->defaults_set)
913 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
916 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
922 val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
926 writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
928 plld->params->ext_misc_reg[1]);
940 u32 val = readl_relaxed(clk_base + plldss->params->base_reg);
942 plldss->params->defaults_set = true;
952 plldss->params->defaults_set = false;
957 _pll_misc_chk_default(clk_base, plldss->params, 0, default_val,
966 if (plldss->params->ssc_ctrl_en_mask) {
968 _pll_misc_chk_default(clk_base, plldss->params, 1,
971 _pll_misc_chk_default(clk_base, plldss->params, 2,
974 _pll_misc_chk_default(clk_base, plldss->params, 3,
976 } else if (plldss->params->ext_misc_reg[1]) {
978 _pll_misc_chk_default(clk_base, plldss->params, 1,
983 if (!plldss->params->defaults_set)
991 plldss->params->base_reg);
994 val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]);
997 writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]);
1006 writel_relaxed(val, clk_base + plldss->params->base_reg);
1009 if (!plldss->params->ext_misc_reg[1]) {
1011 plldss->params->ext_misc_reg[0]);
1017 plldss->params->ext_misc_reg[0]);
1020 clk_base + plldss->params->ext_misc_reg[1]);
1021 writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]);
1022 writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]);
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);
1061 pllre->params->defaults_set = true;
1074 pllre->params->defaults_set = false;
1080 _pll_misc_chk_default(clk_base, pllre->params, 0, val,
1084 val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
1091 writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
1094 if (!pllre->params->defaults_set)
1103 writel_relaxed(val, clk_base + pllre->params->base_reg);
1105 clk_base + pllre->params->ext_misc_reg[0]);
1114 if (!IS_ERR_OR_NULL(hw->clk))
1149 _pll_misc_chk_default(clk_base, pll->params, 0, default_val,
1153 _pll_misc_chk_default(clk_base, pll->params, 1, default_val,
1158 _pll_misc_chk_default(clk_base, pll->params, 2,
1162 _pll_misc_chk_default(clk_base, pll->params, 3, default_val,
1166 _pll_misc_chk_default(clk_base, pll->params, 4, default_val,
1170 _pll_misc_chk_default(clk_base, pll->params, 5, default_val,
1179 pllx->params->defaults_set = true;
1182 pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b);
1188 if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) {
1196 if (!pllx->params->defaults_set)
1199 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
1202 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]);
1205 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]);
1213 pllx->params->ext_misc_reg[0]);
1217 pllx->params->ext_misc_reg[1]);
1220 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
1224 pllx->params->ext_misc_reg[3]);
1228 pllx->params->ext_misc_reg[4]);
1230 pllx->params->ext_misc_reg[5]);
1237 u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
1239 pllmb->params->defaults_set = true;
1249 _pll_misc_chk_default(clk_base, pllmb->params, 0, val,
1252 if (!pllmb->params->defaults_set)
1255 val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
1258 writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
1266 clk_base + pllmb->params->ext_misc_reg[0]);
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,
1291 _pll_misc_chk_default(clk_base, pll->params, 1, val,
1298 u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
1300 pllp->params->defaults_set = true;
1309 if (!pllp->params->defaults_set)
1313 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]);
1317 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]);
1325 clk_base + pllp->params->ext_misc_reg[0]);
1328 val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]);
1332 writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]);
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);
1363 pllu->defaults_set = true;
1372 if (!pllu->defaults_set)
1376 val = readl_relaxed(clk_base + pllu->ext_misc_reg[0]);
1379 writel_relaxed(val, clk_base + pllu->ext_misc_reg[0]);
1381 val = readl_relaxed(clk_base + pllu->ext_misc_reg[1]);
1384 writel_relaxed(val, clk_base + pllu->ext_misc_reg[1]);
1392 clk_base + pllu->ext_misc_reg[0]);
1394 clk_base + pllu->ext_misc_reg[1]);
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++) {
1427 return -ETIMEDOUT;
1431 struct tegra_clk_pll_freq_table *cfg)
1435 ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift)
1438 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
1440 val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT;
1441 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
1444 val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
1446 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
1449 tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2],
1452 base = readl_relaxed(clk_base + pllx->params->base_reg) &
1454 base |= cfg->n << pllx->params->div_nmp->divn_shift;
1455 writel_relaxed(base, clk_base + pllx->params->base_reg);
1459 writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
1463 __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p,
1464 cfg->input_rate / cfg->m * cfg->n /
1465 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
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
1479 struct tegra_clk_pll_freq_table *cfg,
1483 struct tegra_clk_pll_params *params = pll->params;
1489 return -EINVAL;
1491 if (!(params->flags & TEGRA_PLL_VCO_OUT)) {
1492 p = DIV_ROUND_UP(params->vco_min, rate);
1493 p = params->round_p_to_pdiv(p, &pdiv);
1495 p = rate >= params->vco_min ? 1 : -EINVAL;
1499 return -EINVAL;
1501 cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate);
1502 cfg->p = p;
1505 cfg->p = tegra_pll_p_div_to_hw(pll, cfg->p);
1508 if (p_rate > params->vco_max)
1509 p_rate = params->vco_max;
1510 cf = input_rate / cfg->m;
1511 cfg->n = p_rate / cf;
1513 cfg->sdm_data = 0;
1514 cfg->output_rate = input_rate;
1515 if (params->sdm_ctrl_reg) {
1516 unsigned long rem = p_rate - cf * cfg->n;
1518 if (rem || params->ssc_ctrl_reg) {
1522 s -= PLL_SDM_COEFF / 2;
1523 cfg->sdm_data = sdin_din_to_data(s);
1525 cfg->output_rate *= sdin_get_n_eff(cfg);
1526 cfg->output_rate /= p * cfg->m * PLL_SDM_COEFF;
1528 cfg->output_rate *= cfg->n;
1529 cfg->output_rate /= p * cfg->m;
1532 cfg->input_rate = input_rate;
1538 * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
1540 * @cfg: struct tegra_clk_pll_freq_table * cfg
1548 static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
1550 cfg->n = sdin_get_n_eff(cfg);
1551 cfg->m *= PLL_SDM_COEFF;
1558 unsigned long vco_min = params->vco_min;
1560 params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF);
1561 vco_min = min(vco_min, params->vco_min);
1575 * PLL post divider maps - two types: quasi-linear and exponential
1613 return -EINVAL;
1634 i--;
1642 return -EINVAL;
2216 /* disable spread-spectrum for pll_d2 */
2617 { .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
2750 return -EINVAL;
2754 if (!mbist_war->handle_lvl2_ovr)
2757 if (mbist_war->num_clks && !mbist_war->clks)
2758 return -ENODEV;
2760 err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks);
2766 mbist_war->handle_lvl2_ovr(mbist_war);
2770 clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks);
2826 /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
2899 for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
2900 if (fentry->input_rate == pll_ref_freq)
2904 if (!fentry->input_rate) {
2906 return -EINVAL;
2911 reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]);
2912 reg &= ~BIT(pllu.params->iddq_bit_idx);
2913 writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]);
2918 reg |= fentry->m;
2919 reg |= fentry->n << 8;
2920 reg |= fentry->p << 16;
2935 return -ETIMEDOUT;
3174 clkp = tegra_lookup_dt_id(init->clk_id, tegra210_clks);
3176 pr_warn("clock %u not found\n", init->clk_id);
3186 /* emc */
3191 tegra210_clk_register_mc("mc", "emc");
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
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;
3688 return -EINVAL;
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
3818 CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);