Commit 72be2d5f authored by Michael Turquette's avatar Michael Turquette
Browse files

Merge tag 'tegra-for-4.12-clk' of...

Merge tag 'tegra-for-4.12-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-next

Pull Tegra clk driver updates from Thierry Reding:

This contains a bunch of fixes and cleanups, mostly to the Tegra210
clock driver.

* tag 'tegra-for-4.12-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: (24 commits)
  clk: tegra: Don't reset PLL-CX if it is already enabled
  clk: tegra: Add missing Tegra210 clocks
  clk: tegra: Propagate clk_out_x rate to parent
  clk: tegra: Fix build warnings on Tegra20/Tegra30
  clk: tegra: Mark TEGRA210_CLK_DBGAPB as always on
  clk: tegra: Add SATA seq input control
  clk: tegra: Add Tegra210 special resets
  clk: tegra: Rework pll_u
  clk: tegra: Implement reset control reset
  clk: tegra: Fix disable unused for clocks sharing enable bit
  clk: tegra: Handle UTMIPLL IDDQ
  clk: tegra: Add aclk
  clk: tegra: Add super clock mux/divider
  clk: tegra: Define Tegra210 DMIC clocks
  clk: tegra: Fix constness for peripheral clocks
  clk: tegra: Define Tegra210 DMIC sync clocks
  clk: tegra: Add CEC clock
  clk: tegra: Fix type for m field
  clk: tegra: Correct tegra210_pll_fixed_mdiv_cfg rate calculation
  clk: tegra: Don't warn for PLL defaults unnecessarily
  ...
parents 1f9dfd7a 1116d5a7
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -307,6 +307,23 @@ enum clk_id {
	tegra_clk_xusb_ssp_src,
	tegra_clk_sclk_mux,
	tegra_clk_sor_safe,
	tegra_clk_cec,
	tegra_clk_ispa,
	tegra_clk_dmic1,
	tegra_clk_dmic2,
	tegra_clk_dmic3,
	tegra_clk_dmic1_sync_clk,
	tegra_clk_dmic2_sync_clk,
	tegra_clk_dmic3_sync_clk,
	tegra_clk_dmic1_sync_clk_mux,
	tegra_clk_dmic2_sync_clk_mux,
	tegra_clk_dmic3_sync_clk_mux,
	tegra_clk_iqc1,
	tegra_clk_iqc2,
	tegra_clk_pll_a_out_adsp,
	tegra_clk_pll_a_out0_out_adsp,
	tegra_clk_adsp,
	tegra_clk_adsp_neon,
	tegra_clk_max,
};

+3 −0
Original line number Diff line number Diff line
@@ -159,6 +159,9 @@ struct clk *tegra_clk_register_periph_gate(const char *name,
	gate->enable_refcnt = enable_refcnt;
	gate->regs = pregs;

	if (read_enb(gate) & periph_clk_to_bit(gate))
		enable_refcnt[clk_num]++;

	/* Data in .init is copied by clk_register(), so stack variable OK */
	gate->hw.init = &init;

+3 −3
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
};

static struct clk *_tegra_clk_register_periph(const char *name,
			const char **parent_names, int num_parents,
			const char * const *parent_names, int num_parents,
			struct tegra_clk_periph *periph,
			void __iomem *clk_base, u32 offset,
			unsigned long flags)
@@ -186,7 +186,7 @@ static struct clk *_tegra_clk_register_periph(const char *name,
}

struct clk *tegra_clk_register_periph(const char *name,
		const char **parent_names, int num_parents,
		const char * const *parent_names, int num_parents,
		struct tegra_clk_periph *periph, void __iomem *clk_base,
		u32 offset, unsigned long flags)
{
@@ -195,7 +195,7 @@ struct clk *tegra_clk_register_periph(const char *name,
}

struct clk *tegra_clk_register_periph_nodiv(const char *name,
		const char **parent_names, int num_parents,
		const char * const *parent_names, int num_parents,
		struct tegra_clk_periph *periph, void __iomem *clk_base,
		u32 offset)
{
+0 −174
Original line number Diff line number Diff line
@@ -2517,152 +2517,6 @@ static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
	return val & PLLE_BASE_ENABLE ? 1 : 0;
}

static int clk_pllu_tegra210_enable(struct clk_hw *hw)
{
	struct tegra_clk_pll *pll = to_clk_pll(hw);
	struct clk_hw *pll_ref = clk_hw_get_parent(hw);
	struct clk_hw *osc = clk_hw_get_parent(pll_ref);
	const struct utmi_clk_param *params = NULL;
	unsigned long flags = 0, input_rate;
	unsigned int i;
	int ret = 0;
	u32 value;

	if (!osc) {
		pr_err("%s: failed to get OSC clock\n", __func__);
		return -EINVAL;
	}

	input_rate = clk_hw_get_rate(osc);

	if (pll->lock)
		spin_lock_irqsave(pll->lock, flags);

	_clk_pll_enable(hw);

	ret = clk_pll_wait_for_lock(pll);
	if (ret < 0)
		goto out;

	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
		if (input_rate == utmi_parameters[i].osc_frequency) {
			params = &utmi_parameters[i];
			break;
		}
	}

	if (!params) {
		pr_err("%s: unexpected input rate %lu Hz\n", __func__,
		       input_rate);
		ret = -EINVAL;
		goto out;
	}

	value = pll_readl_base(pll);
	value &= ~PLLU_BASE_OVERRIDE;
	pll_writel_base(value, pll);

	/* Put PLLU under HW control */
	value = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
	value |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
	         PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
	         PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
	value &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
		   PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
	writel_relaxed(value, pll->clk_base + PLLU_HW_PWRDN_CFG0);

	value = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
	value &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY;
	writel_relaxed(value, pll->clk_base + XUSB_PLL_CFG0);

	udelay(1);

	value = readl_relaxed(pll->clk_base + PLLU_HW_PWRDN_CFG0);
	value |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
	writel_relaxed(value, pll->clk_base + PLLU_HW_PWRDN_CFG0);

	udelay(1);

	/* Disable PLLU clock branch to UTMIPLL since it uses OSC */
	value = pll_readl_base(pll);
	value &= ~PLLU_BASE_CLKENABLE_USB;
	pll_writel_base(value, pll);

	value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
	if (value & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE) {
		pr_debug("UTMIPLL already enabled\n");
		goto out;
	}

	value &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
	writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);

	/* Program UTMIP PLL stable and active counts */
	value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
	value &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
	value |= UTMIP_PLL_CFG2_STABLE_COUNT(params->stable_count);
	value &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
	value |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(params->active_delay_count);
	value |= UTMIP_PLL_CFG2_PHY_XTAL_CLOCKEN;
	writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);

	/* Program UTMIP PLL delay and oscillator frequency counts */
	value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
	value &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
	value |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(params->enable_delay_count);
	value &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
	value |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(params->xtal_freq_count);
	writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);

	/* Remove power downs from UTMIP PLL control bits */
	value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
	value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
	value |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
	writel(value, pll->clk_base + UTMIP_PLL_CFG1);

	udelay(1);

	/* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
	value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG2);
	value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
	value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
	value |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
	value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
	value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
	value &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
	writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG2);

	/* Setup HW control of UTMIPLL */
	value = readl_relaxed(pll->clk_base + UTMIP_PLL_CFG1);
	value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
	value &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
	writel_relaxed(value, pll->clk_base + UTMIP_PLL_CFG1);

	value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
	value |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
	value &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
	writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);

	udelay(1);

	value = readl_relaxed(pll->clk_base + XUSB_PLL_CFG0);
	value &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
	writel_relaxed(value, pll->clk_base + XUSB_PLL_CFG0);

	udelay(1);

	/* Enable HW control of UTMIPLL */
	value = readl_relaxed(pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);
	value |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
	writel_relaxed(value, pll->clk_base + UTMIPLL_HW_PWRDN_CFG0);

out:
	if (pll->lock)
		spin_unlock_irqrestore(pll->lock, flags);

	return ret;
}

static const struct clk_ops tegra_clk_plle_tegra210_ops = {
	.is_enabled =  clk_plle_tegra210_is_enabled,
	.enable = clk_plle_tegra210_enable,
@@ -2670,13 +2524,6 @@ static const struct clk_ops tegra_clk_plle_tegra210_ops = {
	.recalc_rate = clk_pll_recalc_rate,
};

static const struct clk_ops tegra_clk_pllu_tegra210_ops = {
	.is_enabled =  clk_pll_is_enabled,
	.enable = clk_pllu_tegra210_enable,
	.disable = clk_pll_disable,
	.recalc_rate = clk_pllre_recalc_rate,
};

struct clk *tegra_clk_register_plle_tegra210(const char *name,
				const char *parent_name,
				void __iomem *clk_base, unsigned long flags,
@@ -2918,25 +2765,4 @@ struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
	return clk;
}

struct clk *tegra_clk_register_pllu_tegra210(const char *name,
		const char *parent_name, void __iomem *clk_base,
		unsigned long flags, struct tegra_clk_pll_params *pll_params,
		spinlock_t *lock)
{
	struct tegra_clk_pll *pll;
	struct clk *clk;

	pll_params->flags |= TEGRA_PLLU;

	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
	if (IS_ERR(pll))
		return ERR_CAST(pll);

	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
				      &tegra_clk_pllu_tegra210_ops);
	if (IS_ERR(clk))
		kfree(pll);

	return clk;
}
#endif
+83 −4
Original line number Diff line number Diff line
@@ -121,9 +121,50 @@ out:
	return err;
}

const struct clk_ops tegra_clk_super_mux_ops = {
	.get_parent = clk_super_get_parent,
	.set_parent = clk_super_set_parent,
};

static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate,
				 unsigned long *parent_rate)
{
	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
	struct clk_hw *div_hw = &super->frac_div.hw;

	__clk_hw_set_clk(div_hw, hw);

	return super->div_ops->round_rate(div_hw, rate, parent_rate);
}

static unsigned long clk_super_recalc_rate(struct clk_hw *hw,
					   unsigned long parent_rate)
{
	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
	struct clk_hw *div_hw = &super->frac_div.hw;

	__clk_hw_set_clk(div_hw, hw);

	return super->div_ops->recalc_rate(div_hw, parent_rate);
}

static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,
			      unsigned long parent_rate)
{
	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
	struct clk_hw *div_hw = &super->frac_div.hw;

	__clk_hw_set_clk(div_hw, hw);

	return super->div_ops->set_rate(div_hw, rate, parent_rate);
}

const struct clk_ops tegra_clk_super_ops = {
	.get_parent = clk_super_get_parent,
	.set_parent = clk_super_set_parent,
	.set_rate = clk_super_set_rate,
	.round_rate = clk_super_round_rate,
	.recalc_rate = clk_super_recalc_rate,
};

struct clk *tegra_clk_register_super_mux(const char *name,
@@ -136,13 +177,11 @@ struct clk *tegra_clk_register_super_mux(const char *name,
	struct clk_init_data init;

	super = kzalloc(sizeof(*super), GFP_KERNEL);
	if (!super) {
		pr_err("%s: could not allocate super clk\n", __func__);
	if (!super)
		return ERR_PTR(-ENOMEM);
	}

	init.name = name;
	init.ops = &tegra_clk_super_ops;
	init.ops = &tegra_clk_super_mux_ops;
	init.flags = flags;
	init.parent_names = parent_names;
	init.num_parents = num_parents;
@@ -163,3 +202,43 @@ struct clk *tegra_clk_register_super_mux(const char *name,

	return clk;
}

struct clk *tegra_clk_register_super_clk(const char *name,
		const char * const *parent_names, u8 num_parents,
		unsigned long flags, void __iomem *reg, u8 clk_super_flags,
		spinlock_t *lock)
{
	struct tegra_clk_super_mux *super;
	struct clk *clk;
	struct clk_init_data init;

	super = kzalloc(sizeof(*super), GFP_KERNEL);
	if (!super)
		return ERR_PTR(-ENOMEM);

	init.name = name;
	init.ops = &tegra_clk_super_ops;
	init.flags = flags;
	init.parent_names = parent_names;
	init.num_parents = num_parents;

	super->reg = reg;
	super->lock = lock;
	super->width = 4;
	super->flags = clk_super_flags;
	super->frac_div.reg = reg + 4;
	super->frac_div.shift = 16;
	super->frac_div.width = 8;
	super->frac_div.frac_width = 1;
	super->frac_div.lock = lock;
	super->div_ops = &tegra_clk_frac_div_ops;

	/* Data in .init is copied by clk_register(), so stack variable OK */
	super->hw.init = &init;

	clk = clk_register(NULL, &super->hw);
	if (IS_ERR(clk))
		kfree(super);

	return clk;
}
Loading