Commit 3f4e557d authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'for-5.14-clk' of...

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

Pull Tegra clk driver updates from Thierry Reding:

This contains a few fixes across the board and adds stubs to allow
certain drivers to be compile-tested. One other notable change added
here is that clock enabling no longer deasserts the reset. Drivers are
now supposed to do that explicitly because doing it implicitly can get
in the way of certain power-up sequences.

* tag 'for-5.14-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  clk: tegra: tegra124-emc: Fix clock imbalance in emc_set_timing()
  clk: tegra: Add stubs needed for compile-testing
  clk: tegra: Don't deassert reset on enabling clocks
  clk: tegra: Mark external clocks as not having reset control
  clk: tegra: cclk: Handle thermal DIV2 CPU frequency throttling
  clk: tegra: Don't allow zero clock rate for PLLs
  clk: tegra: Halve SCLK rate on Tegra20
  clk: tegra: Ensure that PLLU configuration is applied properly
  clk: tegra: Fix refcounting of gate clocks
  clk: tegra30: Use 300MHz for video decoder by default
parents 6efb943b f13570e7
Loading
Loading
Loading
Loading
+47 −33
Original line number Diff line number Diff line
@@ -48,36 +48,45 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
	return state;
}

static int clk_periph_enable(struct clk_hw *hw)
static void clk_periph_enable_locked(struct clk_hw *hw)
{
	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
	unsigned long flags = 0;

	spin_lock_irqsave(&periph_ref_lock, flags);

	gate->enable_refcnt[gate->clk_num]++;
	if (gate->enable_refcnt[gate->clk_num] > 1) {
		spin_unlock_irqrestore(&periph_ref_lock, flags);
		return 0;
	}

	write_enb_set(periph_clk_to_bit(gate), gate);
	udelay(2);

	if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
	    !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
		if (read_rst(gate) & periph_clk_to_bit(gate)) {
			udelay(5); /* reset propogation delay */
			write_rst_clr(periph_clk_to_bit(gate), gate);
		}
	}

	if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
		writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
		writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
		udelay(1);
		writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
	}
}

static void clk_periph_disable_locked(struct clk_hw *hw)
{
	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);

	/*
	 * If peripheral is in the APB bus then read the APB bus to
	 * flush the write operation in apb bus. This will avoid the
	 * peripheral access after disabling clock
	 */
	if (gate->flags & TEGRA_PERIPH_ON_APB)
		tegra_read_chipid();

	write_enb_clr(periph_clk_to_bit(gate), gate);
}

static int clk_periph_enable(struct clk_hw *hw)
{
	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
	unsigned long flags = 0;

	spin_lock_irqsave(&periph_ref_lock, flags);

	if (!gate->enable_refcnt[gate->clk_num]++)
		clk_periph_enable_locked(hw);

	spin_unlock_irqrestore(&periph_ref_lock, flags);

@@ -91,21 +100,28 @@ static void clk_periph_disable(struct clk_hw *hw)

	spin_lock_irqsave(&periph_ref_lock, flags);

	gate->enable_refcnt[gate->clk_num]--;
	if (gate->enable_refcnt[gate->clk_num] > 0) {
	WARN_ON(!gate->enable_refcnt[gate->clk_num]);

	if (--gate->enable_refcnt[gate->clk_num] == 0)
		clk_periph_disable_locked(hw);

	spin_unlock_irqrestore(&periph_ref_lock, flags);
		return;
}

static void clk_periph_disable_unused(struct clk_hw *hw)
{
	struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
	unsigned long flags = 0;

	spin_lock_irqsave(&periph_ref_lock, flags);

	/*
	 * If peripheral is in the APB bus then read the APB bus to
	 * flush the write operation in apb bus. This will avoid the
	 * peripheral access after disabling clock
	 * Some clocks are duplicated and some of them are marked as critical,
	 * like fuse and fuse_burn for example, thus the enable_refcnt will
	 * be non-zero here if the "unused" duplicate is disabled by CCF.
	 */
	if (gate->flags & TEGRA_PERIPH_ON_APB)
		tegra_read_chipid();

	write_enb_clr(periph_clk_to_bit(gate), gate);
	if (!gate->enable_refcnt[gate->clk_num])
		clk_periph_disable_locked(hw);

	spin_unlock_irqrestore(&periph_ref_lock, flags);
}
@@ -114,6 +130,7 @@ const struct clk_ops tegra_clk_periph_gate_ops = {
	.is_enabled = clk_periph_is_enabled,
	.enable = clk_periph_enable,
	.disable = clk_periph_disable,
	.disable_unused = clk_periph_disable_unused,
};

struct clk *tegra_clk_register_periph_gate(const char *name,
@@ -148,9 +165,6 @@ 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;

+11 −0
Original line number Diff line number Diff line
@@ -100,6 +100,15 @@ static void clk_periph_disable(struct clk_hw *hw)
	gate_ops->disable(gate_hw);
}

static void clk_periph_disable_unused(struct clk_hw *hw)
{
	struct tegra_clk_periph *periph = to_clk_periph(hw);
	const struct clk_ops *gate_ops = periph->gate_ops;
	struct clk_hw *gate_hw = &periph->gate.hw;

	gate_ops->disable_unused(gate_hw);
}

static void clk_periph_restore_context(struct clk_hw *hw)
{
	struct tegra_clk_periph *periph = to_clk_periph(hw);
@@ -126,6 +135,7 @@ const struct clk_ops tegra_clk_periph_ops = {
	.is_enabled = clk_periph_is_enabled,
	.enable = clk_periph_enable,
	.disable = clk_periph_disable,
	.disable_unused = clk_periph_disable_unused,
	.restore_context = clk_periph_restore_context,
};

@@ -135,6 +145,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
	.is_enabled = clk_periph_is_enabled,
	.enable = clk_periph_enable,
	.disable = clk_periph_disable,
	.disable_unused = clk_periph_disable_unused,
	.restore_context = clk_periph_restore_context,
};

+7 −5
Original line number Diff line number Diff line
@@ -558,6 +558,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
	u32 p_div = 0;
	int ret;

	if (!rate)
		return -EINVAL;

	switch (parent_rate) {
	case 12000000:
	case 26000000:
@@ -1131,6 +1134,7 @@ static int clk_pllu_enable(struct clk_hw *hw)
	if (pll->lock)
		spin_lock_irqsave(pll->lock, flags);

	if (!clk_pll_is_enabled(hw))
		_clk_pll_enable(hw);

	ret = clk_pll_wait_for_lock(pll);
@@ -1748,14 +1752,12 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
		return -EINVAL;
	}

	if (clk_pll_is_enabled(hw))
		return 0;

	input_rate = clk_hw_get_rate(__clk_get_hw(osc));

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

	if (!clk_pll_is_enabled(hw))
		_clk_pll_enable(hw);

	ret = clk_pll_wait_for_lock(pll);
+3 −3
Original line number Diff line number Diff line
@@ -712,9 +712,9 @@ static struct tegra_periph_init_data periph_clks[] = {
	MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
	MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
	MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
	MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, 0, tegra_clk_extern1),
	MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
	MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
	MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, TEGRA_PERIPH_NO_RESET, tegra_clk_extern1),
	MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, TEGRA_PERIPH_NO_RESET, tegra_clk_extern2),
	MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, TEGRA_PERIPH_NO_RESET, tegra_clk_extern3),
	MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
	MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
	MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
+14 −2
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@

#define SUPER_CDIV_ENB		BIT(31)

#define TSENSOR_SLOWDOWN	BIT(23)

static struct tegra_clk_super_mux *cclk_super;
static bool cclk_on_pllx;

@@ -47,10 +49,20 @@ static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate,
static unsigned long cclk_super_recalc_rate(struct clk_hw *hw,
					    unsigned long parent_rate)
{
	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
	u32 val = readl_relaxed(super->reg);
	unsigned int div2;

	/* check whether thermal throttling is active */
	if (val & TSENSOR_SLOWDOWN)
		div2 = 1;
	else
		div2 = 0;

	if (cclk_super_get_parent(hw) == PLLX_INDEX)
		return parent_rate;
		return parent_rate >> div2;

	return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
	return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2;
}

static int cclk_super_determine_rate(struct clk_hw *hw,
Loading