diff options
Diffstat (limited to 'drivers/clk/tegra/clk-tegra210.c')
-rw-r--r-- | drivers/clk/tegra/clk-tegra210.c | 2852 |
1 files changed, 2852 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c new file mode 100644 index 000000000000..58514c44ea83 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra210.c @@ -0,0 +1,2852 @@ +/* + * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> +#include <dt-bindings/clock/tegra210-car.h> + +#include "clk.h" +#include "clk-id.h" + +/* + * TEGRA210_CAR_BANK_COUNT: the number of peripheral clock register + * banks present in the Tegra210 CAR IP block. The banks are + * identified by single letters, e.g.: L, H, U, V, W, X, Y. See + * periph_regs[] in drivers/clk/tegra/clk.c + */ +#define TEGRA210_CAR_BANK_COUNT 7 + +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_EMC 0x19c + +#define PLLC_BASE 0x80 +#define PLLC_OUT 0x84 +#define PLLC_MISC0 0x88 +#define PLLC_MISC1 0x8c +#define PLLC_MISC2 0x5d0 +#define PLLC_MISC3 0x5d4 + +#define PLLC2_BASE 0x4e8 +#define PLLC2_MISC0 0x4ec +#define PLLC2_MISC1 0x4f0 +#define PLLC2_MISC2 0x4f4 +#define PLLC2_MISC3 0x4f8 + +#define PLLC3_BASE 0x4fc +#define PLLC3_MISC0 0x500 +#define PLLC3_MISC1 0x504 +#define PLLC3_MISC2 0x508 +#define PLLC3_MISC3 0x50c + +#define PLLM_BASE 0x90 +#define PLLM_MISC0 0x9c +#define PLLM_MISC1 0x98 +#define PLLP_BASE 0xa0 +#define PLLP_MISC0 0xac +#define PLLP_MISC1 0x680 +#define PLLA_BASE 0xb0 +#define PLLA_MISC0 0xbc +#define PLLA_MISC1 0xb8 +#define PLLA_MISC2 0x5d8 +#define PLLD_BASE 0xd0 +#define PLLD_MISC0 0xdc +#define PLLD_MISC1 0xd8 +#define PLLU_BASE 0xc0 +#define PLLU_OUTA 0xc4 +#define PLLU_MISC0 0xcc +#define PLLU_MISC1 0xc8 +#define PLLX_BASE 0xe0 +#define PLLX_MISC0 0xe4 +#define PLLX_MISC1 0x510 +#define PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 +#define PLLX_MISC4 0x5f0 +#define PLLX_MISC5 0x5f4 +#define PLLE_BASE 0xe8 +#define PLLE_MISC0 0xec +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC0 0x4bc +#define PLLD2_MISC1 0x570 +#define PLLD2_MISC2 0x574 +#define PLLD2_MISC3 0x578 +#define PLLE_AUX 0x48c +#define PLLRE_BASE 0x4c4 +#define PLLRE_MISC0 0x4c8 +#define PLLDP_BASE 0x590 +#define PLLDP_MISC 0x594 + +#define PLLC4_BASE 0x5a4 +#define PLLC4_MISC0 0x5a8 +#define PLLC4_OUT 0x5e4 +#define PLLMB_BASE 0x5e8 +#define PLLMB_MISC0 0x5ec +#define PLLA1_BASE 0x6a4 +#define PLLA1_MISC0 0x6a8 +#define PLLA1_MISC1 0x6ac +#define PLLA1_MISC2 0x6b0 +#define PLLA1_MISC3 0x6b4 + +#define PLLU_IDDQ_BIT 31 +#define PLLCX_IDDQ_BIT 27 +#define PLLRE_IDDQ_BIT 24 +#define PLLA_IDDQ_BIT 25 +#define PLLD_IDDQ_BIT 20 +#define PLLSS_IDDQ_BIT 18 +#define PLLM_IDDQ_BIT 5 +#define PLLMB_IDDQ_BIT 17 +#define PLLXP_IDDQ_BIT 3 + +#define PLLCX_RESET_BIT 30 + +#define PLL_BASE_LOCK BIT(27) +#define PLLCX_BASE_LOCK BIT(26) +#define PLLE_MISC_LOCK BIT(11) +#define PLLRE_MISC_LOCK BIT(27) + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLC_MISC_LOCK_ENABLE 24 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLU_MISC_LOCK_ENABLE 29 +#define PLLE_MISC_LOCK_ENABLE 9 +#define PLLRE_MISC_LOCK_ENABLE 30 +#define PLLSS_MISC_LOCK_ENABLE 30 +#define PLLP_MISC_LOCK_ENABLE 18 +#define PLLM_MISC_LOCK_ENABLE 4 +#define PLLMB_MISC_LOCK_ENABLE 16 +#define PLLA_MISC_LOCK_ENABLE 28 +#define PLLU_MISC_LOCK_ENABLE 29 +#define PLLD_MISC_LOCK_ENABLE 18 + +#define PLLA_SDM_DIN_MASK 0xffff +#define PLLA_SDM_EN_MASK BIT(26) + +#define PLLD_SDM_EN_MASK BIT(16) + +#define PLLD2_SDM_EN_MASK BIT(31) +#define PLLD2_SSC_EN_MASK BIT(30) + +#define PLLDP_SS_CFG 0x598 +#define PLLDP_SDM_EN_MASK BIT(31) +#define PLLDP_SSC_EN_MASK BIT(30) +#define PLLDP_SS_CTRL1 0x59c +#define PLLDP_SS_CTRL2 0x5a0 + +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP BIT(1) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP BIT(3) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERUP BIT(5) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN BIT(24) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP BIT(25) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) + +#define UTMIPLL_HW_PWRDN_CFG0 0x52c +#define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE BIT(7) +#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4) +#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) + +#define PLLU_HW_PWRDN_CFG0 0x530 +#define PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE BIT(28) +#define PLLU_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT BIT(7) +#define PLLU_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL BIT(0) + +#define XUSB_PLL_CFG0 0x534 +#define XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY 0x3ff +#define XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK (0x3ff << 14) + +#define SPARE_REG0 0x55c +#define CLK_M_DIVISOR_SHIFT 2 +#define CLK_M_DIVISOR_MASK 0x3 + +/* + * SDM fractional divisor is 16-bit 2's complement signed number within + * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned + * 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used to + * indicate that SDM is disabled. + * + * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13 + */ +#define PLL_SDM_COEFF BIT(13) +#define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU)) +#define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat) + +/* Tegra CPU clock and reset control regs */ +#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 + +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { + u32 clk_csite_src; +} tegra210_cpu_clk_sctx; +#endif + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static unsigned long osc_freq; +static unsigned long pll_ref_freq; + +static DEFINE_SPINLOCK(pll_d_lock); +static DEFINE_SPINLOCK(pll_e_lock); +static DEFINE_SPINLOCK(pll_re_lock); +static DEFINE_SPINLOCK(pll_u_lock); +static DEFINE_SPINLOCK(emc_lock); + +/* possible OSC frequencies in Hz */ +static unsigned long tegra210_input_freq[] = { + [5] = 38400000, + [8] = 12000000, +}; + +static const char *mux_pllmcp_clkm[] = { + "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", +}; +#define mux_pllmcp_clkm_idx NULL + +#define PLL_ENABLE (1 << 30) + +#define PLLCX_MISC1_IDDQ (1 << 27) +#define PLLCX_MISC0_RESET (1 << 30) + +#define PLLCX_MISC0_DEFAULT_VALUE 0x40080000 +#define PLLCX_MISC0_WRITE_MASK 0x400ffffb +#define PLLCX_MISC1_DEFAULT_VALUE 0x08000000 +#define PLLCX_MISC1_WRITE_MASK 0x08003cff +#define PLLCX_MISC2_DEFAULT_VALUE 0x1f720f05 +#define PLLCX_MISC2_WRITE_MASK 0xffffff17 +#define PLLCX_MISC3_DEFAULT_VALUE 0x000000c4 +#define PLLCX_MISC3_WRITE_MASK 0x00ffffff + +/* PLLA */ +#define PLLA_BASE_IDDQ (1 << 25) +#define PLLA_BASE_LOCK (1 << 27) + +#define PLLA_MISC0_LOCK_ENABLE (1 << 28) +#define PLLA_MISC0_LOCK_OVERRIDE (1 << 27) + +#define PLLA_MISC2_EN_SDM (1 << 26) +#define PLLA_MISC2_EN_DYNRAMP (1 << 25) + +#define PLLA_MISC0_DEFAULT_VALUE 0x12000020 +#define PLLA_MISC0_WRITE_MASK 0x7fffffff +#define PLLA_MISC2_DEFAULT_VALUE 0x0 +#define PLLA_MISC2_WRITE_MASK 0x06ffffff + +/* PLLD */ +#define PLLD_MISC0_EN_SDM (1 << 16) +#define PLLD_MISC0_LOCK_OVERRIDE (1 << 17) +#define PLLD_MISC0_LOCK_ENABLE (1 << 18) +#define PLLD_MISC0_IDDQ (1 << 20) +#define PLLD_MISC0_DSI_CLKENABLE (1 << 21) + +#define PLLD_MISC0_DEFAULT_VALUE 0x00140000 +#define PLLD_MISC0_WRITE_MASK 0x3ff7ffff +#define PLLD_MISC1_DEFAULT_VALUE 0x20 +#define PLLD_MISC1_WRITE_MASK 0x00ffffff + +/* PLLD2 and PLLDP and PLLC4 */ +#define PLLDSS_BASE_LOCK (1 << 27) +#define PLLDSS_BASE_LOCK_OVERRIDE (1 << 24) +#define PLLDSS_BASE_IDDQ (1 << 18) +#define PLLDSS_BASE_REF_SEL_SHIFT 25 +#define PLLDSS_BASE_REF_SEL_MASK (0x3 << PLLDSS_BASE_REF_SEL_SHIFT) + +#define PLLDSS_MISC0_LOCK_ENABLE (1 << 30) + +#define PLLDSS_MISC1_CFG_EN_SDM (1 << 31) +#define PLLDSS_MISC1_CFG_EN_SSC (1 << 30) + +#define PLLD2_MISC0_DEFAULT_VALUE 0x40000020 +#define PLLD2_MISC1_CFG_DEFAULT_VALUE 0x10000000 +#define PLLD2_MISC2_CTRL1_DEFAULT_VALUE 0x0 +#define PLLD2_MISC3_CTRL2_DEFAULT_VALUE 0x0 + +#define PLLDP_MISC0_DEFAULT_VALUE 0x40000020 +#define PLLDP_MISC1_CFG_DEFAULT_VALUE 0xc0000000 +#define PLLDP_MISC2_CTRL1_DEFAULT_VALUE 0xf400f0da +#define PLLDP_MISC3_CTRL2_DEFAULT_VALUE 0x2004f400 + +#define PLLDSS_MISC0_WRITE_MASK 0x47ffffff +#define PLLDSS_MISC1_CFG_WRITE_MASK 0xf8000000 +#define PLLDSS_MISC2_CTRL1_WRITE_MASK 0xffffffff +#define PLLDSS_MISC3_CTRL2_WRITE_MASK 0xffffffff + +#define PLLC4_MISC0_DEFAULT_VALUE 0x40000000 + +/* PLLRE */ +#define PLLRE_MISC0_LOCK_ENABLE (1 << 30) +#define PLLRE_MISC0_LOCK_OVERRIDE (1 << 29) +#define PLLRE_MISC0_LOCK (1 << 27) +#define PLLRE_MISC0_IDDQ (1 << 24) + +#define PLLRE_BASE_DEFAULT_VALUE 0x0 +#define PLLRE_MISC0_DEFAULT_VALUE 0x41000000 + +#define PLLRE_BASE_DEFAULT_MASK 0x1c000000 +#define PLLRE_MISC0_WRITE_MASK 0x67ffffff + +/* PLLX */ +#define PLLX_USE_DYN_RAMP 1 +#define PLLX_BASE_LOCK (1 << 27) + +#define PLLX_MISC0_FO_G_DISABLE (0x1 << 28) +#define PLLX_MISC0_LOCK_ENABLE (0x1 << 18) + +#define PLLX_MISC2_DYNRAMP_STEPB_SHIFT 24 +#define PLLX_MISC2_DYNRAMP_STEPB_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPB_SHIFT) +#define PLLX_MISC2_DYNRAMP_STEPA_SHIFT 16 +#define PLLX_MISC2_DYNRAMP_STEPA_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPA_SHIFT) +#define PLLX_MISC2_NDIV_NEW_SHIFT 8 +#define PLLX_MISC2_NDIV_NEW_MASK (0xFF << PLLX_MISC2_NDIV_NEW_SHIFT) +#define PLLX_MISC2_LOCK_OVERRIDE (0x1 << 4) +#define PLLX_MISC2_DYNRAMP_DONE (0x1 << 2) +#define PLLX_MISC2_EN_DYNRAMP (0x1 << 0) + +#define PLLX_MISC3_IDDQ (0x1 << 3) + +#define PLLX_MISC0_DEFAULT_VALUE PLLX_MISC0_LOCK_ENABLE +#define PLLX_MISC0_WRITE_MASK 0x10c40000 +#define PLLX_MISC1_DEFAULT_VALUE 0x20 +#define PLLX_MISC1_WRITE_MASK 0x00ffffff +#define PLLX_MISC2_DEFAULT_VALUE 0x0 +#define PLLX_MISC2_WRITE_MASK 0xffffff11 +#define PLLX_MISC3_DEFAULT_VALUE PLLX_MISC3_IDDQ +#define PLLX_MISC3_WRITE_MASK 0x01ff0f0f +#define PLLX_MISC4_DEFAULT_VALUE 0x0 +#define PLLX_MISC4_WRITE_MASK 0x8000ffff +#define PLLX_MISC5_DEFAULT_VALUE 0x0 +#define PLLX_MISC5_WRITE_MASK 0x0000ffff + +#define PLLX_HW_CTRL_CFG 0x548 +#define PLLX_HW_CTRL_CFG_SWCTRL (0x1 << 0) + +/* PLLMB */ +#define PLLMB_BASE_LOCK (1 << 27) + +#define PLLMB_MISC0_LOCK_OVERRIDE (1 << 18) +#define PLLMB_MISC0_IDDQ (1 << 17) +#define PLLMB_MISC0_LOCK_ENABLE (1 << 16) + +#define PLLMB_MISC0_DEFAULT_VALUE 0x00030000 +#define PLLMB_MISC0_WRITE_MASK 0x0007ffff + +/* PLLP */ +#define PLLP_BASE_OVERRIDE (1 << 28) +#define PLLP_BASE_LOCK (1 << 27) + +#define PLLP_MISC0_LOCK_ENABLE (1 << 18) +#define PLLP_MISC0_LOCK_OVERRIDE (1 << 17) +#define PLLP_MISC0_IDDQ (1 << 3) + +#define PLLP_MISC1_HSIO_EN_SHIFT 29 +#define PLLP_MISC1_HSIO_EN (1 << PLLP_MISC1_HSIO_EN_SHIFT) +#define PLLP_MISC1_XUSB_EN_SHIFT 28 +#define PLLP_MISC1_XUSB_EN (1 << PLLP_MISC1_XUSB_EN_SHIFT) + +#define PLLP_MISC0_DEFAULT_VALUE 0x00040008 +#define PLLP_MISC1_DEFAULT_VALUE 0x0 + +#define PLLP_MISC0_WRITE_MASK 0xdc6000f +#define PLLP_MISC1_WRITE_MASK 0x70ffffff + +/* PLLU */ +#define PLLU_BASE_LOCK (1 << 27) +#define PLLU_BASE_OVERRIDE (1 << 24) +#define PLLU_BASE_CLKENABLE_USB (1 << 21) +#define PLLU_BASE_CLKENABLE_HSIC (1 << 22) +#define PLLU_BASE_CLKENABLE_ICUSB (1 << 23) +#define PLLU_BASE_CLKENABLE_48M (1 << 25) +#define PLLU_BASE_CLKENABLE_ALL (PLLU_BASE_CLKENABLE_USB |\ + PLLU_BASE_CLKENABLE_HSIC |\ + PLLU_BASE_CLKENABLE_ICUSB |\ + PLLU_BASE_CLKENABLE_48M) + +#define PLLU_MISC0_IDDQ (1 << 31) +#define PLLU_MISC0_LOCK_ENABLE (1 << 29) +#define PLLU_MISC1_LOCK_OVERRIDE (1 << 0) + +#define PLLU_MISC0_DEFAULT_VALUE 0xa0000000 +#define PLLU_MISC1_DEFAULT_VALUE 0x0 + +#define PLLU_MISC0_WRITE_MASK 0xbfffffff +#define PLLU_MISC1_WRITE_MASK 0x00000007 + +static inline void _pll_misc_chk_default(void __iomem *base, + struct tegra_clk_pll_params *params, + u8 misc_num, u32 default_val, u32 mask) +{ + u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]); + + boot_val &= mask; + default_val &= mask; + if (boot_val != default_val) { + pr_warn("boot misc%d 0x%x: expected 0x%x\n", + misc_num, boot_val, default_val); + pr_warn(" (comparison mask = 0x%x)\n", mask); + params->defaults_set = false; + } +} + +/* + * PLLCX: PLLC, PLLC2, PLLC3, PLLA1 + * Hybrid PLLs with dynamic ramp. Dynamic ramp is allowed for any transition + * that changes NDIV only, while PLL is already locked. + */ +static void pllcx_check_defaults(struct tegra_clk_pll_params *params) +{ + u32 default_val; + + default_val = PLLCX_MISC0_DEFAULT_VALUE & (~PLLCX_MISC0_RESET); + _pll_misc_chk_default(clk_base, params, 0, default_val, + PLLCX_MISC0_WRITE_MASK); + + default_val = PLLCX_MISC1_DEFAULT_VALUE & (~PLLCX_MISC1_IDDQ); + _pll_misc_chk_default(clk_base, params, 1, default_val, + PLLCX_MISC1_WRITE_MASK); + + default_val = PLLCX_MISC2_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, params, 2, default_val, + PLLCX_MISC2_WRITE_MASK); + + default_val = PLLCX_MISC3_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, params, 3, default_val, + PLLCX_MISC3_WRITE_MASK); +} + +void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx) +{ + pllcx->params->defaults_set = true; + + if (readl_relaxed(clk_base + pllcx->params->base_reg) & + PLL_ENABLE) { + /* PLL is ON: only check if defaults already set */ + pllcx_check_defaults(pllcx->params); + pr_warn("%s already enabled. Postponing set full defaults\n", + name); + return; + } + + /* Defaults assert PLL reset, and set IDDQ */ + writel_relaxed(PLLCX_MISC0_DEFAULT_VALUE, + clk_base + pllcx->params->ext_misc_reg[0]); + writel_relaxed(PLLCX_MISC1_DEFAULT_VALUE, + clk_base + pllcx->params->ext_misc_reg[1]); + writel_relaxed(PLLCX_MISC2_DEFAULT_VALUE, + clk_base + pllcx->params->ext_misc_reg[2]); + writel_relaxed(PLLCX_MISC3_DEFAULT_VALUE, + clk_base + pllcx->params->ext_misc_reg[3]); + udelay(1); +} + +void _pllc_set_defaults(struct tegra_clk_pll *pllcx) +{ + tegra210_pllcx_set_defaults("PLL_C", pllcx); +} + +void _pllc2_set_defaults(struct tegra_clk_pll *pllcx) +{ + tegra210_pllcx_set_defaults("PLL_C2", pllcx); +} + +void _pllc3_set_defaults(struct tegra_clk_pll *pllcx) +{ + tegra210_pllcx_set_defaults("PLL_C3", pllcx); +} + +void _plla1_set_defaults(struct tegra_clk_pll *pllcx) +{ + tegra210_pllcx_set_defaults("PLL_A1", pllcx); +} + +/* + * PLLA + * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used. + * Fractional SDM is allowed to provide exact audio rates. + */ +void tegra210_plla_set_defaults(struct tegra_clk_pll *plla) +{ + u32 mask; + u32 val = readl_relaxed(clk_base + plla->params->base_reg); + + plla->params->defaults_set = true; + + if (val & PLL_ENABLE) { + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + if (val & PLLA_BASE_IDDQ) { + pr_warn("PLL_A boot enabled with IDDQ set\n"); + plla->params->defaults_set = false; + } + + pr_warn("PLL_A already enabled. Postponing set full defaults\n"); + + val = PLLA_MISC0_DEFAULT_VALUE; /* ignore lock enable */ + mask = PLLA_MISC0_LOCK_ENABLE | PLLA_MISC0_LOCK_OVERRIDE; + _pll_misc_chk_default(clk_base, plla->params, 0, val, + ~mask & PLLA_MISC0_WRITE_MASK); + + val = PLLA_MISC2_DEFAULT_VALUE; /* ignore all but control bit */ + _pll_misc_chk_default(clk_base, plla->params, 2, val, + PLLA_MISC2_EN_DYNRAMP); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]); + val &= ~mask; + val |= PLLA_MISC0_DEFAULT_VALUE & mask; + writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect, disable dynamic ramp and SDM */ + val |= PLLA_BASE_IDDQ; + writel_relaxed(val, clk_base + plla->params->base_reg); + writel_relaxed(PLLA_MISC0_DEFAULT_VALUE, + clk_base + plla->params->ext_misc_reg[0]); + writel_relaxed(PLLA_MISC2_DEFAULT_VALUE, + clk_base + plla->params->ext_misc_reg[2]); + udelay(1); +} + +/* + * PLLD + * PLL with fractional SDM. + */ +void tegra210_plld_set_defaults(struct tegra_clk_pll *plld) +{ + u32 val; + u32 mask = 0xffff; + + plld->params->defaults_set = true; + + if (readl_relaxed(clk_base + plld->params->base_reg) & + PLL_ENABLE) { + pr_warn("PLL_D already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + val = PLLD_MISC1_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, plld->params, 1, + val, PLLD_MISC1_WRITE_MASK); + + /* ignore lock, DSI and SDM controls, make sure IDDQ not set */ + val = PLLD_MISC0_DEFAULT_VALUE & (~PLLD_MISC0_IDDQ); + mask |= PLLD_MISC0_DSI_CLKENABLE | PLLD_MISC0_LOCK_ENABLE | + PLLD_MISC0_LOCK_OVERRIDE | PLLD_MISC0_EN_SDM; + _pll_misc_chk_default(clk_base, plld->params, 0, val, + ~mask & PLLD_MISC0_WRITE_MASK); + + /* Enable lock detect */ + mask = PLLD_MISC0_LOCK_ENABLE | PLLD_MISC0_LOCK_OVERRIDE; + val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); + val &= ~mask; + val |= PLLD_MISC0_DEFAULT_VALUE & mask; + writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]); + val &= PLLD_MISC0_DSI_CLKENABLE; + val |= PLLD_MISC0_DEFAULT_VALUE; + /* set IDDQ, enable lock detect, disable SDM */ + writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]); + writel_relaxed(PLLD_MISC1_DEFAULT_VALUE, clk_base + + plld->params->ext_misc_reg[1]); + udelay(1); +} + +/* + * PLLD2, PLLDP + * PLL with fractional SDM and Spread Spectrum (SDM is a must if SSC is used). + */ +static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss, + u32 misc0_val, u32 misc1_val, u32 misc2_val, u32 misc3_val) +{ + u32 default_val; + u32 val = readl_relaxed(clk_base + plldss->params->base_reg); + + plldss->params->defaults_set = true; + + if (val & PLL_ENABLE) { + pr_warn("%s already enabled. Postponing set full defaults\n", + pll_name); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + if (val & PLLDSS_BASE_IDDQ) { + pr_warn("plldss boot enabled with IDDQ set\n"); + plldss->params->defaults_set = false; + } + + /* ignore lock enable */ + default_val = misc0_val; + _pll_misc_chk_default(clk_base, plldss->params, 0, default_val, + PLLDSS_MISC0_WRITE_MASK & + (~PLLDSS_MISC0_LOCK_ENABLE)); + + /* + * If SSC is used, check all settings, otherwise just confirm + * that SSC is not used on boot as well. Do nothing when using + * this function for PLLC4 that has only MISC0. + */ + if (plldss->params->ssc_ctrl_en_mask) { + default_val = misc1_val; + _pll_misc_chk_default(clk_base, plldss->params, 1, + default_val, PLLDSS_MISC1_CFG_WRITE_MASK); + default_val = misc2_val; + _pll_misc_chk_default(clk_base, plldss->params, 2, + default_val, PLLDSS_MISC2_CTRL1_WRITE_MASK); + default_val = misc3_val; + _pll_misc_chk_default(clk_base, plldss->params, 3, + default_val, PLLDSS_MISC3_CTRL2_WRITE_MASK); + } else if (plldss->params->ext_misc_reg[1]) { + default_val = misc1_val; + _pll_misc_chk_default(clk_base, plldss->params, 1, + default_val, PLLDSS_MISC1_CFG_WRITE_MASK & + (~PLLDSS_MISC1_CFG_EN_SDM)); + } + + /* Enable lock detect */ + if (val & PLLDSS_BASE_LOCK_OVERRIDE) { + val &= ~PLLDSS_BASE_LOCK_OVERRIDE; + writel_relaxed(val, clk_base + + plldss->params->base_reg); + } + + val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]); + val &= ~PLLDSS_MISC0_LOCK_ENABLE; + val |= misc0_val & PLLDSS_MISC0_LOCK_ENABLE; + writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect, configure SDM/SSC */ + val |= PLLDSS_BASE_IDDQ; + val &= ~PLLDSS_BASE_LOCK_OVERRIDE; + writel_relaxed(val, clk_base + plldss->params->base_reg); + + /* When using this function for PLLC4 exit here */ + if (!plldss->params->ext_misc_reg[1]) { + writel_relaxed(misc0_val, clk_base + + plldss->params->ext_misc_reg[0]); + udelay(1); + return; + } + + writel_relaxed(misc0_val, clk_base + + plldss->params->ext_misc_reg[0]); + /* if SSC used set by 1st enable */ + writel_relaxed(misc1_val & (~PLLDSS_MISC1_CFG_EN_SSC), + clk_base + plldss->params->ext_misc_reg[1]); + writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]); + writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]); + udelay(1); +} + +void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2) +{ + plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE, + PLLD2_MISC1_CFG_DEFAULT_VALUE, + PLLD2_MISC2_CTRL1_DEFAULT_VALUE, + PLLD2_MISC3_CTRL2_DEFAULT_VALUE); +} + +void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp) +{ + plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE, + PLLDP_MISC1_CFG_DEFAULT_VALUE, + PLLDP_MISC2_CTRL1_DEFAULT_VALUE, + PLLDP_MISC3_CTRL2_DEFAULT_VALUE); +} + +/* + * PLLC4 + * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support. + * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers. + */ +void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4) +{ + plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0); +} + +/* + * PLLRE + * VCO is exposed to the clock tree directly along with post-divider output + */ +void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) +{ + u32 mask; + u32 val = readl_relaxed(clk_base + pllre->params->base_reg); + + pllre->params->defaults_set = true; + + if (val & PLL_ENABLE) { + pr_warn("PLL_RE already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + val &= PLLRE_BASE_DEFAULT_MASK; + if (val != PLLRE_BASE_DEFAULT_VALUE) { + pr_warn("pllre boot base 0x%x : expected 0x%x\n", + val, PLLRE_BASE_DEFAULT_VALUE); + pr_warn("(comparison mask = 0x%x)\n", + PLLRE_BASE_DEFAULT_MASK); + pllre->params->defaults_set = false; + } + + /* Ignore lock enable */ + val = PLLRE_MISC0_DEFAULT_VALUE & (~PLLRE_MISC0_IDDQ); + mask = PLLRE_MISC0_LOCK_ENABLE | PLLRE_MISC0_LOCK_OVERRIDE; + _pll_misc_chk_default(clk_base, pllre->params, 0, val, + ~mask & PLLRE_MISC0_WRITE_MASK); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]); + val &= ~mask; + val |= PLLRE_MISC0_DEFAULT_VALUE & mask; + writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect */ + val &= ~PLLRE_BASE_DEFAULT_MASK; + val |= PLLRE_BASE_DEFAULT_VALUE & PLLRE_BASE_DEFAULT_MASK; + writel_relaxed(val, clk_base + pllre->params->base_reg); + writel_relaxed(PLLRE_MISC0_DEFAULT_VALUE, + clk_base + pllre->params->ext_misc_reg[0]); + udelay(1); +} + +static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b) +{ + unsigned long input_rate; + + if (!IS_ERR_OR_NULL(hw->clk)) { + input_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); + /* cf rate */ + input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate); + } else { + input_rate = 38400000; + } + + switch (input_rate) { + case 12000000: + case 12800000: + case 13000000: + *step_a = 0x2B; + *step_b = 0x0B; + return; + case 19200000: + *step_a = 0x12; + *step_b = 0x08; + return; + case 38400000: + *step_a = 0x04; + *step_b = 0x05; + return; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, input_rate); + BUG(); + } +} + +static void pllx_check_defaults(struct tegra_clk_pll *pll) +{ + u32 default_val; + + default_val = PLLX_MISC0_DEFAULT_VALUE; + /* ignore lock enable */ + _pll_misc_chk_default(clk_base, pll->params, 0, default_val, + PLLX_MISC0_WRITE_MASK & (~PLLX_MISC0_LOCK_ENABLE)); + + default_val = PLLX_MISC1_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, pll->params, 1, default_val, + PLLX_MISC1_WRITE_MASK); + + /* ignore all but control bit */ + default_val = PLLX_MISC2_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, pll->params, 2, + default_val, PLLX_MISC2_EN_DYNRAMP); + + default_val = PLLX_MISC3_DEFAULT_VALUE & (~PLLX_MISC3_IDDQ); + _pll_misc_chk_default(clk_base, pll->params, 3, default_val, + PLLX_MISC3_WRITE_MASK); + + default_val = PLLX_MISC4_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, pll->params, 4, default_val, + PLLX_MISC4_WRITE_MASK); + + default_val = PLLX_MISC5_DEFAULT_VALUE; + _pll_misc_chk_default(clk_base, pll->params, 5, default_val, + PLLX_MISC5_WRITE_MASK); +} + +void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx) +{ + u32 val; + u32 step_a, step_b; + + pllx->params->defaults_set = true; + + /* Get ready dyn ramp state machine settings */ + pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b); + val = PLLX_MISC2_DEFAULT_VALUE & (~PLLX_MISC2_DYNRAMP_STEPA_MASK) & + (~PLLX_MISC2_DYNRAMP_STEPB_MASK); + val |= step_a << PLLX_MISC2_DYNRAMP_STEPA_SHIFT; + val |= step_b << PLLX_MISC2_DYNRAMP_STEPB_SHIFT; + + if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) { + pr_warn("PLL_X already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + pllx_check_defaults(pllx); + + /* Configure dyn ramp, disable lock override */ + writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]); + val &= ~PLLX_MISC0_LOCK_ENABLE; + val |= PLLX_MISC0_DEFAULT_VALUE & PLLX_MISC0_LOCK_ENABLE; + writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* Enable lock detect and CPU output */ + writel_relaxed(PLLX_MISC0_DEFAULT_VALUE, clk_base + + pllx->params->ext_misc_reg[0]); + + /* Setup */ + writel_relaxed(PLLX_MISC1_DEFAULT_VALUE, clk_base + + pllx->params->ext_misc_reg[1]); + + /* Configure dyn ramp state machine, disable lock override */ + writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]); + + /* Set IDDQ */ + writel_relaxed(PLLX_MISC3_DEFAULT_VALUE, clk_base + + pllx->params->ext_misc_reg[3]); + + /* Disable SDM */ + writel_relaxed(PLLX_MISC4_DEFAULT_VALUE, clk_base + + pllx->params->ext_misc_reg[4]); + writel_relaxed(PLLX_MISC5_DEFAULT_VALUE, clk_base + + pllx->params->ext_misc_reg[5]); + udelay(1); +} + +/* PLLMB */ +void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb) +{ + u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg); + + pllmb->params->defaults_set = true; + + if (val & PLL_ENABLE) { + pr_warn("PLL_MB already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ); + mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE; + _pll_misc_chk_default(clk_base, pllmb->params, 0, val, + ~mask & PLLMB_MISC0_WRITE_MASK); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]); + val &= ~mask; + val |= PLLMB_MISC0_DEFAULT_VALUE & mask; + writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect */ + writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE, + clk_base + pllmb->params->ext_misc_reg[0]); + udelay(1); +} + +/* + * PLLP + * VCO is exposed to the clock tree directly along with post-divider output. + * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz, + * respectively. + */ +static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled) +{ + u32 val, mask; + + /* Ignore lock enable (will be set), make sure not in IDDQ if enabled */ + val = PLLP_MISC0_DEFAULT_VALUE & (~PLLP_MISC0_IDDQ); + mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE; + if (!enabled) + mask |= PLLP_MISC0_IDDQ; + _pll_misc_chk_default(clk_base, pll->params, 0, val, + ~mask & PLLP_MISC0_WRITE_MASK); + + /* Ignore branch controls */ + val = PLLP_MISC1_DEFAULT_VALUE; + mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN; + _pll_misc_chk_default(clk_base, pll->params, 1, val, + ~mask & PLLP_MISC1_WRITE_MASK); +} + +void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp) +{ + u32 mask; + u32 val = readl_relaxed(clk_base + pllp->params->base_reg); + + pllp->params->defaults_set = true; + + if (val & PLL_ENABLE) { + pr_warn("PLL_P already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + pllp_check_defaults(pllp, true); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]); + mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE; + val &= ~mask; + val |= PLLP_MISC0_DEFAULT_VALUE & mask; + writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect */ + writel_relaxed(PLLP_MISC0_DEFAULT_VALUE, + clk_base + pllp->params->ext_misc_reg[0]); + + /* Preserve branch control */ + val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]); + mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN; + val &= mask; + val |= ~mask & PLLP_MISC1_DEFAULT_VALUE; + writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]); + udelay(1); +} + +/* + * PLLU + * VCO is exposed to the clock tree directly along with post-divider output. + * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz, + * respectively. + */ +static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control) +{ + u32 val, mask; + + /* Ignore lock enable (will be set) and IDDQ if under h/w control */ + val = PLLU_MISC0_DEFAULT_VALUE & (~PLLU_MISC0_IDDQ); + mask = PLLU_MISC0_LOCK_ENABLE | (hw_control ? PLLU_MISC0_IDDQ : 0); + _pll_misc_chk_default(clk_base, pll->params, 0, val, + ~mask & PLLU_MISC0_WRITE_MASK); + + val = PLLU_MISC1_DEFAULT_VALUE; + mask = PLLU_MISC1_LOCK_OVERRIDE; + _pll_misc_chk_default(clk_base, pll->params, 1, val, + ~mask & PLLU_MISC1_WRITE_MASK); +} + +void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu) +{ + u32 val = readl_relaxed(clk_base + pllu->params->base_reg); + + pllu->params->defaults_set = true; + + if (val & PLL_ENABLE) { + pr_warn("PLL_U already enabled. Postponing set full defaults\n"); + + /* + * PLL is ON: check if defaults already set, then set those + * that can be updated in flight. + */ + pllu_check_defaults(pllu, false); + + /* Enable lock detect */ + val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[0]); + val &= ~PLLU_MISC0_LOCK_ENABLE; + val |= PLLU_MISC0_DEFAULT_VALUE & PLLU_MISC0_LOCK_ENABLE; + writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[0]); + + val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[1]); + val &= ~PLLU_MISC1_LOCK_OVERRIDE; + val |= PLLU_MISC1_DEFAULT_VALUE & PLLU_MISC1_LOCK_OVERRIDE; + writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[1]); + udelay(1); + + return; + } + + /* set IDDQ, enable lock detect */ + writel_relaxed(PLLU_MISC0_DEFAULT_VALUE, + clk_base + pllu->params->ext_misc_reg[0]); + writel_relaxed(PLLU_MISC1_DEFAULT_VALUE, + clk_base + pllu->params->ext_misc_reg[1]); + udelay(1); +} + +#define mask(w) ((1 << (w)) - 1) +#define divm_mask(p) mask(p->params->div_nmp->divm_width) +#define divn_mask(p) mask(p->params->div_nmp->divn_width) +#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\ + mask(p->params->div_nmp->divp_width)) + +#define divm_shift(p) ((p)->params->div_nmp->divm_shift) +#define divn_shift(p) ((p)->params->div_nmp->divn_shift) +#define divp_shift(p) ((p)->params->div_nmp->divp_shift) + +#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p)) +#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p)) +#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p)) + +#define PLL_LOCKDET_DELAY 2 /* Lock detection safety delays */ +static int tegra210_wait_for_mask(struct tegra_clk_pll *pll, + u32 reg, u32 mask) +{ + int i; + u32 val = 0; + + for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) { + udelay(PLL_LOCKDET_DELAY); + val = readl_relaxed(clk_base + reg); + if ((val & mask) == mask) { + udelay(PLL_LOCKDET_DELAY); + return 0; + } + } + return -ETIMEDOUT; +} + +static int tegra210_pllx_dyn_ramp(struct tegra_clk_pll *pllx, + struct tegra_clk_pll_freq_table *cfg) +{ + u32 val, base, ndiv_new_mask; + + ndiv_new_mask = (divn_mask(pl |