Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8791db53 authored by Mike Turquette's avatar Mike Turquette
Browse files

Merge tag 'clk-mvebu-3.18' of git://git.infradead.org/linux-mvebu into clk-next

clock changes for mvebu for v3.18

 - correct timer drift caused by SSCG deviation
 - fix typo in comment
parents c873d14d ceac26c6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
 */

#define SARL				0	/* Low part [0:31] */
#define	 SARL_A370_SSCG_ENABLE		BIT(10)
#define	 SARL_A370_PCLK_FREQ_OPT	11
#define	 SARL_A370_PCLK_FREQ_OPT_MASK	0xF
#define	 SARL_A370_FAB_FREQ_OPT		15
@@ -133,10 +134,17 @@ static void __init a370_get_clk_ratio(
	}
}

static bool a370_is_sscg_enabled(void __iomem *sar)
{
	return !(readl(sar) & SARL_A370_SSCG_ENABLE);
}

static const struct coreclk_soc_desc a370_coreclks = {
	.get_tclk_freq = a370_get_tclk_freq,
	.get_cpu_freq = a370_get_cpu_freq,
	.get_clk_ratio = a370_get_clk_ratio,
	.is_sscg_enabled = a370_is_sscg_enabled,
	.fix_sscg_deviation = kirkwood_fix_sscg_deviation,
	.ratios = a370_coreclk_ratios,
	.num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
};
+2 −2
Original line number Diff line number Diff line
@@ -27,14 +27,14 @@
 * all modified at the same time, and not separately as for the Armada
 * 370 or the Armada XP SoCs.
 *
 * SAR0[21:17]   : CPU frequency    DDR frequency   L2 frequency
 * SAR1[21:17]   : CPU frequency    DDR frequency   L2 frequency
 *		 6   =  400 MHz	    400 MHz	    200 MHz
 *		 15  =  600 MHz	    600 MHz	    300 MHz
 *		 21  =  800 MHz	    534 MHz	    400 MHz
 *		 25  = 1000 MHz	    500 MHz	    500 MHz
 *		 others reserved.
 *
 * SAR0[22]   : TCLK frequency
 * SAR1[22]   : TCLK frequency
 *		 0 = 166 MHz
 *		 1 = 200 MHz
 */
+82 −0
Original line number Diff line number Diff line
@@ -26,8 +26,85 @@
 * Core Clocks
 */

#define SSCG_CONF_MODE(reg)	(((reg) >> 16) & 0x3)
#define SSCG_SPREAD_DOWN	0x0
#define SSCG_SPREAD_UP		0x1
#define SSCG_SPREAD_CENTRAL	0x2
#define SSCG_CONF_LOW(reg)	(((reg) >> 8) & 0xFF)
#define SSCG_CONF_HIGH(reg)	((reg) & 0xFF)

static struct clk_onecell_data clk_data;

/*
 * This function can be used by the Kirkwood, the Armada 370, the
 * Armada XP and the Armada 375 SoC. The name of the function was
 * chosen following the dt convention: using the first known SoC
 * compatible with it.
 */
u32 kirkwood_fix_sscg_deviation(struct device_node *np, u32 system_clk)
{
	struct device_node *sscg_np = NULL;
	void __iomem *sscg_map;
	u32 sscg_reg;
	s32 low_bound, high_bound;
	u64 freq_swing_half;

	sscg_np = of_find_node_by_name(np, "sscg");
	if (sscg_np == NULL) {
		pr_err("cannot get SSCG register node\n");
		return system_clk;
	}

	sscg_map = of_iomap(sscg_np, 0);
	if (sscg_map == NULL) {
		pr_err("cannot map SSCG register\n");
		goto out;
	}

	sscg_reg = readl(sscg_map);
	high_bound = SSCG_CONF_HIGH(sscg_reg);
	low_bound = SSCG_CONF_LOW(sscg_reg);

	if ((high_bound - low_bound) <= 0)
		goto out;
	/*
	 * From Marvell engineer we got the following formula (when
	 * this code was written, the datasheet was erroneous)
	 * Spread percentage = 1/96 * (H - L) / H
	 * H = SSCG_High_Boundary
	 * L = SSCG_Low_Boundary
	 *
	 * As the deviation is half of spread then it lead to the
	 * following formula in the code.
	 *
	 * To avoid an overflow and not lose any significant digit in
	 * the same time we have to use a 64 bit integer.
	 */

	freq_swing_half = (((u64)high_bound - (u64)low_bound)
			* (u64)system_clk);
	do_div(freq_swing_half, (2 * 96 * high_bound));

	switch (SSCG_CONF_MODE(sscg_reg)) {
	case SSCG_SPREAD_DOWN:
		system_clk -= freq_swing_half;
		break;
	case SSCG_SPREAD_UP:
		system_clk += freq_swing_half;
		break;
	case SSCG_SPREAD_CENTRAL:
	default:
		break;
	}

	iounmap(sscg_map);

out:
	of_node_put(sscg_np);

	return system_clk;
}

void __init mvebu_coreclk_setup(struct device_node *np,
				const struct coreclk_soc_desc *desc)
{
@@ -62,6 +139,11 @@ void __init mvebu_coreclk_setup(struct device_node *np,
	of_property_read_string_index(np, "clock-output-names", 1,
				      &cpuclk_name);
	rate = desc->get_cpu_freq(base);

	if (desc->is_sscg_enabled && desc->fix_sscg_deviation
		&& desc->is_sscg_enabled(base))
		rate = desc->fix_sscg_deviation(np, rate);

	clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
						   CLK_IS_ROOT, rate);
	WARN_ON(IS_ERR(clk_data.clks[1]));
+7 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ struct coreclk_soc_desc {
	u32 (*get_tclk_freq)(void __iomem *sar);
	u32 (*get_cpu_freq)(void __iomem *sar);
	void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
	bool (*is_sscg_enabled)(void __iomem *sar);
	u32 (*fix_sscg_deviation)(struct device_node *np, u32 system_clk);
	const struct coreclk_ratio *ratios;
	int num_ratios;
};
@@ -47,4 +49,9 @@ void __init mvebu_coreclk_setup(struct device_node *np,
void __init mvebu_clk_gating_setup(struct device_node *np,
				   const struct clk_gating_soc_desc *desc);

/*
 * This function is shared among the Kirkwood, Armada 370, Armada XP
 * and Armada 375 SoC
 */
u32 kirkwood_fix_sscg_deviation(struct device_node *np, u32 system_clk);
#endif