Commit 249592bf authored by Paul Cercueil's avatar Paul Cercueil Committed by Stephen Boyd
Browse files

clk: Support bypassing dividers



When a clock is declared as both CGU_CLK_DIV and CGU_CLK_MUX, the CGU
code expects the mux to be applied first, the divider second.

On the JZ4760, and maybe on some other SoCs, some clocks also have a mux
setting and a divider, but the divider is not applied to all parents
selectable from the mux.

This could be solved by creating two clocks, one with CGU_CLK_DIV and
one with CGU_CLK_MUX, but that would increase the number of clocks.

Instead, add a 8-bit mask to CGU_CLK_DIV clocks. If the bit
corresponding to the parent clock's index is set, the divider is
bypassed.

Signed-off-by: default avatarPaul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20210530164923.18134-3-paul@crapouillou.net


Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 2e1ae04f
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -369,8 +369,12 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
	struct ingenic_cgu *cgu = ingenic_clk->cgu;
	unsigned long rate = parent_rate;
	u32 div_reg, div;
	u8 parent;

	if (clk_info->type & CGU_CLK_DIV) {
		parent = ingenic_clk_get_parent(hw);

		if (!(clk_info->div.bypass_mask & BIT(parent))) {
			div_reg = readl(cgu->base + clk_info->div.reg);
			div = (div_reg >> clk_info->div.shift) &
			      GENMASK(clk_info->div.bits - 1, 0);
@@ -381,6 +385,7 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
				div = (div + 1) * clk_info->div.div;

			rate /= div;
		}
	} else if (clk_info->type & CGU_CLK_FIXDIV) {
		rate /= clk_info->fixdiv.div;
	}
@@ -410,10 +415,16 @@ ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
}

static unsigned
ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
ingenic_clk_calc_div(struct clk_hw *hw,
		     const struct ingenic_cgu_clk_info *clk_info,
		     unsigned long parent_rate, unsigned long req_rate)
{
	unsigned int div, hw_div;
	u8 parent;

	parent = ingenic_clk_get_parent(hw);
	if (clk_info->div.bypass_mask & BIT(parent))
		return 1;

	/* calculate the divide */
	div = DIV_ROUND_UP(parent_rate, req_rate);
@@ -448,7 +459,7 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
	unsigned int div = 1;

	if (clk_info->type & CGU_CLK_DIV)
		div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
		div = ingenic_clk_calc_div(hw, clk_info, *parent_rate, req_rate);
	else if (clk_info->type & CGU_CLK_FIXDIV)
		div = clk_info->fixdiv.div;
	else if (clk_hw_can_set_rate_parent(hw))
@@ -480,7 +491,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
	int ret = 0;

	if (clk_info->type & CGU_CLK_DIV) {
		div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
		div = ingenic_clk_calc_div(hw, clk_info, parent_rate, req_rate);
		rate = DIV_ROUND_UP(parent_rate, div);

		if (rate != req_rate)
+2 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct ingenic_cgu_mux_info {
 *          isn't one
 * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
 * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
 * @bypass_mask: mask of parent clocks for which the divider does not apply
 * @div_table: optional table to map the value read from the register to the
 *             actual divider value
 */
@@ -95,6 +96,7 @@ struct ingenic_cgu_div_info {
	s8 ce_bit;
	s8 busy_bit;
	s8 stop_bit;
	u8 bypass_mask;
	const u8 *div_table;
};

+6 −6
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"pll half", CGU_CLK_DIV,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
			jz4725b_cgu_pll_half_div_table,
		},
	},
@@ -89,7 +89,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"cclk", CGU_CLK_DIV,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
			jz4725b_cgu_cpccr_div_table,
		},
	},
@@ -98,7 +98,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"hclk", CGU_CLK_DIV,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
			jz4725b_cgu_cpccr_div_table,
		},
	},
@@ -107,7 +107,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"pclk", CGU_CLK_DIV,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
			jz4725b_cgu_cpccr_div_table,
		},
	},
@@ -116,7 +116,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"mclk", CGU_CLK_DIV,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
			jz4725b_cgu_cpccr_div_table,
		},
	},
@@ -125,7 +125,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
		"ipu", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
			jz4725b_cgu_cpccr_div_table,
		},
		.gate = { CGU_REG_CLKGR, 13 },
+6 −6
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"pll half", CGU_CLK_DIV,
		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
			jz4740_cgu_pll_half_div_table,
		},
	},
@@ -104,7 +104,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"cclk", CGU_CLK_DIV,
		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
			jz4740_cgu_cpccr_div_table,
		},
	},
@@ -113,7 +113,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"hclk", CGU_CLK_DIV,
		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
			jz4740_cgu_cpccr_div_table,
		},
	},
@@ -122,7 +122,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"pclk", CGU_CLK_DIV,
		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
			jz4740_cgu_cpccr_div_table,
		},
	},
@@ -131,7 +131,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"mclk", CGU_CLK_DIV,
		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
			jz4740_cgu_cpccr_div_table,
		},
	},
@@ -140,7 +140,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
		"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
		.div = {
			CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1,
			CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1, 0,
			jz4740_cgu_cpccr_div_table,
		},
		.gate = { CGU_REG_CLKGR, 10 },
+6 −6
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"cclk", CGU_CLK_DIV,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
	},
@@ -160,7 +160,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"h0clk", CGU_CLK_DIV,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
	},
@@ -168,7 +168,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
		.gate = { CGU_REG_CLKGR1, 7 },
@@ -177,7 +177,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"h2clk", CGU_CLK_DIV,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
	},
@@ -185,7 +185,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
		.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
@@ -194,7 +194,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
		"pclk", CGU_CLK_DIV,
		.parents = { JZ4770_CLK_PLL0, },
		.div = {
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
			jz4770_cgu_cpccr_div_table,
		},
	},