Commit 87b6a5e2 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'clk-v5.11-samsung' of...

Merge tag 'clk-v5.11-samsung' of https://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk into clk-samsung

Pull Samsung clk driver updates from Sylwester Nawrocki:

 - Correction of Kconfig dependencies for better compile test coverage
 - Refactoring of the PLL clocks driver

* tag 'clk-v5.11-samsung' of https://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk:
  clk: samsung: Prevent potential endless loop in the PLL ops
  clk: samsung: Allow compile testing of Exynos, S3C64xx and S5Pv210
parents 3650b228 44a9e78f
Loading
Loading
Loading
Loading
+65 −2
Original line number Diff line number Diff line
@@ -2,10 +2,73 @@
# Recent Exynos platforms should just select COMMON_CLK_SAMSUNG:
config COMMON_CLK_SAMSUNG
	bool "Samsung Exynos clock controller support" if COMPILE_TEST
	# Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by
	# EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7:
	select S3C64XX_COMMON_CLK if ARM && ARCH_S3C64XX
	select S5PV210_COMMON_CLK if ARM && ARCH_S5PV210
	select EXYNOS_3250_COMMON_CLK if ARM && SOC_EXYNOS3250
	select EXYNOS_4_COMMON_CLK if ARM && ARCH_EXYNOS4
	select EXYNOS_5250_COMMON_CLK if ARM && SOC_EXYNOS5250
	select EXYNOS_5260_COMMON_CLK if ARM && SOC_EXYNOS5260
	select EXYNOS_5410_COMMON_CLK if ARM && SOC_EXYNOS5410
	select EXYNOS_5420_COMMON_CLK if ARM && SOC_EXYNOS5420
	select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS

config S3C64XX_COMMON_CLK
	bool "Samsung S3C64xx clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung S3C64xx SoCs.
	  Choose Y here only if you build for this SoC.

config S5PV210_COMMON_CLK
	bool "Samsung S5Pv210 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung S5Pv210 SoCs.
	  Choose Y here only if you build for this SoC.

config EXYNOS_3250_COMMON_CLK
	bool "Samsung Exynos3250 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos3250 SoCs. Choose Y here only if you build for this SoC.

config EXYNOS_4_COMMON_CLK
	bool "Samsung Exynos4 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos4212 and Exynos4412 SoCs. Choose Y here only if you build for
	  this SoC.

config EXYNOS_5250_COMMON_CLK
	bool "Samsung Exynos5250 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos5250 SoCs. Choose Y here only if you build for this SoC.

config EXYNOS_5260_COMMON_CLK
	bool "Samsung Exynos5260 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos5260 SoCs. Choose Y here only if you build for this SoC.

config EXYNOS_5410_COMMON_CLK
	bool "Samsung Exynos5410 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos5410 SoCs. Choose Y here only if you build for this SoC.

config EXYNOS_5420_COMMON_CLK
	bool "Samsung Exynos5420 clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
	help
	  Support for the clock controller present on the Samsung
	  Exynos5420 SoCs. Choose Y here only if you build for this SoC.

config EXYNOS_ARM64_COMMON_CLK
	bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST
	depends on COMMON_CLK_SAMSUNG
+11 −11
Original line number Diff line number Diff line
@@ -4,15 +4,15 @@
#

obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o clk-cpu.o
obj-$(CONFIG_SOC_EXYNOS3250)	+= clk-exynos3250.o
obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4412-isp.o
obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5-subcmu.o
obj-$(CONFIG_SOC_EXYNOS5260)	+= clk-exynos5260.o
obj-$(CONFIG_SOC_EXYNOS5410)	+= clk-exynos5410.o
obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_3250_COMMON_CLK)	+= clk-exynos3250.o
obj-$(CONFIG_EXYNOS_4_COMMON_CLK)	+= clk-exynos4.o
obj-$(CONFIG_EXYNOS_4_COMMON_CLK)	+= clk-exynos4412-isp.o
obj-$(CONFIG_EXYNOS_5250_COMMON_CLK)	+= clk-exynos5250.o
obj-$(CONFIG_EXYNOS_5250_COMMON_CLK)	+= clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_5260_COMMON_CLK)	+= clk-exynos5260.o
obj-$(CONFIG_EXYNOS_5410_COMMON_CLK)	+= clk-exynos5410.o
obj-$(CONFIG_EXYNOS_5420_COMMON_CLK)	+= clk-exynos5420.o
obj-$(CONFIG_EXYNOS_5420_COMMON_CLK)	+= clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK)	+= clk-exynos5433.o
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
obj-$(CONFIG_ARCH_EXYNOS)	+= clk-exynos-clkout.o
@@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
obj-$(CONFIG_ARCH_S3C64XX)	+= clk-s3c64xx.o
obj-$(CONFIG_ARCH_S5PV210)	+= clk-s5pv210.o clk-s5pv210-audss.o
obj-$(CONFIG_S3C64XX_COMMON_CLK)	+= clk-s3c64xx.o
obj-$(CONFIG_S5PV210_COMMON_CLK)	+= clk-s5pv210.o clk-s5pv210-audss.o
+71 −76
Original line number Diff line number Diff line
@@ -8,14 +8,17 @@

#include <linux/errno.h>
#include <linux/hrtimer.h>
#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/timekeeping.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include "clk.h"
#include "clk-pll.h"

#define PLL_TIMEOUT_MS		10
#define PLL_TIMEOUT_US		20000U
#define PLL_TIMEOUT_LOOPS	1000000U

struct samsung_clk_pll {
	struct clk_hw		hw;
@@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
	return rate_table[i - 1].rate;
}

static bool pll_early_timeout = true;

static int __init samsung_pll_disable_early_timeout(void)
{
	pll_early_timeout = false;
	return 0;
}
arch_initcall(samsung_pll_disable_early_timeout);

/* Wait until the PLL is locked */
static int samsung_pll_lock_wait(struct samsung_clk_pll *pll,
				 unsigned int reg_mask)
{
	int i, ret;
	u32 val;

	/*
	 * This function might be called when the timekeeping API can't be used
	 * to detect timeouts. One situation is when the clocksource is not yet
	 * initialized, another when the timekeeping is suspended. udelay() also
	 * cannot be used when the clocksource is not running on arm64, since
	 * the current timer is used as cycle counter. So a simple busy loop
	 * is used here in that special cases. The limit of iterations has been
	 * derived from experimental measurements of various PLLs on multiple
	 * Exynos SoC variants. Single register read time was usually in range
	 * 0.4...1.5 us, never less than 0.4 us.
	 */
	if (pll_early_timeout || timekeeping_suspended) {
		i = PLL_TIMEOUT_LOOPS;
		while (i-- > 0) {
			if (readl_relaxed(pll->con_reg) & reg_mask)
				return 0;

			cpu_relax();
		}
		ret = -ETIMEDOUT;
	} else {
		ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val,
					val & reg_mask, 0, PLL_TIMEOUT_US);
	}

	if (ret < 0)
		pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw));

	return ret;
}

static int samsung_pll3xxx_enable(struct clk_hw *hw)
{
	struct samsung_clk_pll *pll = to_clk_pll(hw);
@@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw)
	tmp |= BIT(pll->enable_offs);
	writel_relaxed(tmp, pll->con_reg);

	/* wait lock time */
	do {
		cpu_relax();
		tmp = readl_relaxed(pll->con_reg);
	} while (!(tmp & BIT(pll->lock_offs)));

	return 0;
	return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
}

static void samsung_pll3xxx_disable(struct clk_hw *hw)
@@ -240,13 +284,10 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
			(rate->sdiv << PLL35XX_SDIV_SHIFT);
	writel_relaxed(tmp, pll->con_reg);

	/* Wait until the PLL is locked if it is enabled. */
	if (tmp & BIT(pll->enable_offs)) {
		do {
			cpu_relax();
			tmp = readl_relaxed(pll->con_reg);
		} while (!(tmp & BIT(pll->lock_offs)));
	}
	/* Wait for PLL lock if the PLL is enabled */
	if (tmp & BIT(pll->enable_offs))
		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));

	return 0;
}

@@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
					unsigned long parent_rate)
{
	struct samsung_clk_pll *pll = to_clk_pll(hw);
	u32 tmp, pll_con0, pll_con1;
	u32 pll_con0, pll_con1;
	const struct samsung_pll_rate_table *rate;

	rate = samsung_get_pll_settings(pll, drate);
@@ -356,13 +397,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
	pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
	writel_relaxed(pll_con1, pll->con_reg + 4);

	/* wait_lock_time */
	if (pll_con0 & BIT(pll->enable_offs)) {
		do {
			cpu_relax();
			tmp = readl_relaxed(pll->con_reg);
		} while (!(tmp & BIT(pll->lock_offs)));
	}
	if (pll_con0 & BIT(pll->enable_offs))
		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));

	return 0;
}
@@ -437,7 +473,6 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
	struct samsung_clk_pll *pll = to_clk_pll(hw);
	const struct samsung_pll_rate_table *rate;
	u32 con0, con1;
	ktime_t start;

	/* Get required rate settings from table */
	rate = samsung_get_pll_settings(pll, drate);
@@ -488,21 +523,8 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
	writel_relaxed(con1, pll->con_reg + 0x4);
	writel_relaxed(con0, pll->con_reg);

	/* Wait for locking. */
	start = ktime_get();
	while (!(readl_relaxed(pll->con_reg) & PLL45XX_LOCKED)) {
		ktime_t delta = ktime_sub(ktime_get(), start);

		if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
			pr_err("%s: could not lock PLL %s\n",
					__func__, clk_hw_get_name(hw));
			return -EFAULT;
		}

		cpu_relax();
	}

	return 0;
	/* Wait for PLL lock */
	return samsung_pll_lock_wait(pll, PLL45XX_LOCKED);
}

static const struct clk_ops samsung_pll45xx_clk_ops = {
@@ -588,7 +610,6 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
	struct samsung_clk_pll *pll = to_clk_pll(hw);
	const struct samsung_pll_rate_table *rate;
	u32 con0, con1, lock;
	ktime_t start;

	/* Get required rate settings from table */
	rate = samsung_get_pll_settings(pll, drate);
@@ -647,21 +668,8 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
	writel_relaxed(con0, pll->con_reg);
	writel_relaxed(con1, pll->con_reg + 0x4);

	/* Wait for locking. */
	start = ktime_get();
	while (!(readl_relaxed(pll->con_reg) & PLL46XX_LOCKED)) {
		ktime_t delta = ktime_sub(ktime_get(), start);

		if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
			pr_err("%s: could not lock PLL %s\n",
					__func__, clk_hw_get_name(hw));
			return -EFAULT;
		}

		cpu_relax();
	}

	return 0;
	/* Wait for PLL lock */
	return samsung_pll_lock_wait(pll, PLL46XX_LOCKED);
}

static const struct clk_ops samsung_pll46xx_clk_ops = {
@@ -1035,14 +1043,9 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
			(rate->sdiv << PLL2550XX_S_SHIFT);
	writel_relaxed(tmp, pll->con_reg);

	/* wait_lock_time */
	do {
		cpu_relax();
		tmp = readl_relaxed(pll->con_reg);
	} while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
			<< PLL2550XX_LOCK_STAT_SHIFT)));

	return 0;
	/* Wait for PLL lock */
	return samsung_pll_lock_wait(pll,
			PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT);
}

static const struct clk_ops samsung_pll2550xx_clk_ops = {
@@ -1132,13 +1135,9 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
	con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
	writel_relaxed(con1, pll->con_reg + 4);

	do {
		cpu_relax();
		con0 = readl_relaxed(pll->con_reg);
	} while (!(con0 & (PLL2650X_LOCK_STAT_MASK
			<< PLL2650X_LOCK_STAT_SHIFT)));

	return 0;
	/* Wait for PLL lock */
	return samsung_pll_lock_wait(pll,
			PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT);
}

static const struct clk_ops samsung_pll2650x_clk_ops = {
@@ -1196,7 +1195,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
					unsigned long parent_rate)
{
	struct samsung_clk_pll *pll = to_clk_pll(hw);
	u32 tmp, pll_con0, pll_con2;
	u32 pll_con0, pll_con2;
	const struct samsung_pll_rate_table *rate;

	rate = samsung_get_pll_settings(pll, drate);
@@ -1229,11 +1228,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
	writel_relaxed(pll_con0, pll->con_reg);
	writel_relaxed(pll_con2, pll->con_reg + 8);

	do {
		tmp = readl_relaxed(pll->con_reg);
	} while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));

	return 0;
	return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT);
}

static const struct clk_ops samsung_pll2650xx_clk_ops = {
+2 −2
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@

struct device_node;

#ifdef CONFIG_ARCH_S3C64XX
#ifdef CONFIG_S3C64XX_COMMON_CLK
void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
		      unsigned long xusbxti_f, bool s3c6400,
		      void __iomem *base);
@@ -19,7 +19,7 @@ static inline void s3c64xx_clk_init(struct device_node *np,
				    unsigned long xtal_f,
				    unsigned long xusbxti_f,
				    bool s3c6400, void __iomem *base) { }
#endif /* CONFIG_ARCH_S3C64XX */
#endif /* CONFIG_S3C64XX_COMMON_CLK */

#ifdef CONFIG_S3C2410_COMMON_CLK
void s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,