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

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
...@@ -2,10 +2,73 @@ ...@@ -2,10 +2,73 @@
# Recent Exynos platforms should just select COMMON_CLK_SAMSUNG: # Recent Exynos platforms should just select COMMON_CLK_SAMSUNG:
config COMMON_CLK_SAMSUNG config COMMON_CLK_SAMSUNG
bool "Samsung Exynos clock controller support" if COMPILE_TEST bool "Samsung Exynos clock controller support" if COMPILE_TEST
# Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by select S3C64XX_COMMON_CLK if ARM && ARCH_S3C64XX
# EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7: 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 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 config EXYNOS_ARM64_COMMON_CLK
bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST
depends on COMMON_CLK_SAMSUNG depends on COMMON_CLK_SAMSUNG
......
...@@ -4,15 +4,15 @@ ...@@ -4,15 +4,15 @@
# #
obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o
obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_EXYNOS_3250_COMMON_CLK) += clk-exynos3250.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4412-isp.o
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5250.o
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5-subcmu.o
obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_EXYNOS_5260_COMMON_CLK) += clk-exynos5260.o
obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_EXYNOS_5410_COMMON_CLK) += clk-exynos5410.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o
...@@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o ...@@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o
obj-$(CONFIG_ARCH_S5PV210) += clk-s5pv210.o clk-s5pv210-audss.o obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o
...@@ -8,14 +8,17 @@ ...@@ -8,14 +8,17 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/iopoll.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timekeeping.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include "clk.h" #include "clk.h"
#include "clk-pll.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 samsung_clk_pll {
struct clk_hw hw; struct clk_hw hw;
...@@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw, ...@@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
return rate_table[i - 1].rate; 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) static int samsung_pll3xxx_enable(struct clk_hw *hw)
{ {
struct samsung_clk_pll *pll = to_clk_pll(hw); struct samsung_clk_pll *pll = to_clk_pll(hw);
...@@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw) ...@@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw)
tmp |= BIT(pll->enable_offs); tmp |= BIT(pll->enable_offs);
writel_relaxed(tmp, pll->con_reg); writel_relaxed(tmp, pll->con_reg);
/* wait lock time */ return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(pll->lock_offs)));
return 0;
} }
static void samsung_pll3xxx_disable(struct clk_hw *hw) 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, ...@@ -240,13 +284,10 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
(rate->sdiv << PLL35XX_SDIV_SHIFT); (rate->sdiv << PLL35XX_SDIV_SHIFT);
writel_relaxed(tmp, pll->con_reg); writel_relaxed(tmp, pll->con_reg);
/* Wait until the PLL is locked if it is enabled. */ /* Wait for PLL lock if the PLL is enabled */
if (tmp & BIT(pll->enable_offs)) { if (tmp & BIT(pll->enable_offs))
do { return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(pll->lock_offs)));
}
return 0; return 0;
} }
...@@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct samsung_clk_pll *pll = to_clk_pll(hw); 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; const struct samsung_pll_rate_table *rate;
rate = samsung_get_pll_settings(pll, drate); rate = samsung_get_pll_settings(pll, drate);
...@@ -356,13 +397,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long 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; pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
writel_relaxed(pll_con1, pll->con_reg + 4); writel_relaxed(pll_con1, pll->con_reg + 4);
/* wait_lock_time */ if (pll_con0 & BIT(pll->enable_offs))
if (pll_con0 & BIT(pll->enable_offs)) { return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(pll->lock_offs)));
}
return 0; return 0;
} }
...@@ -437,7 +473,6 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -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); struct samsung_clk_pll *pll = to_clk_pll(hw);
const struct samsung_pll_rate_table *rate; const struct samsung_pll_rate_table *rate;
u32 con0, con1; u32 con0, con1;
ktime_t start;
/* Get required rate settings from table */ /* Get required rate settings from table */
rate = samsung_get_pll_settings(pll, drate); rate = samsung_get_pll_settings(pll, drate);
...@@ -488,21 +523,8 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long 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(con1, pll->con_reg + 0x4);
writel_relaxed(con0, pll->con_reg); writel_relaxed(con0, pll->con_reg);
/* Wait for locking. */ /* Wait for PLL lock */
start = ktime_get(); return samsung_pll_lock_wait(pll, PLL45XX_LOCKED);
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;
} }
static const struct clk_ops samsung_pll45xx_clk_ops = { 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, ...@@ -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); struct samsung_clk_pll *pll = to_clk_pll(hw);
const struct samsung_pll_rate_table *rate; const struct samsung_pll_rate_table *rate;
u32 con0, con1, lock; u32 con0, con1, lock;
ktime_t start;
/* Get required rate settings from table */ /* Get required rate settings from table */
rate = samsung_get_pll_settings(pll, drate); rate = samsung_get_pll_settings(pll, drate);
...@@ -647,21 +668,8 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long 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(con0, pll->con_reg);
writel_relaxed(con1, pll->con_reg + 0x4); writel_relaxed(con1, pll->con_reg + 0x4);
/* Wait for locking. */ /* Wait for PLL lock */
start = ktime_get(); return samsung_pll_lock_wait(pll, PLL46XX_LOCKED);
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;
} }
static const struct clk_ops samsung_pll46xx_clk_ops = { 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, ...@@ -1035,14 +1043,9 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
(rate->sdiv << PLL2550XX_S_SHIFT); (rate->sdiv << PLL2550XX_S_SHIFT);
writel_relaxed(tmp, pll->con_reg); writel_relaxed(tmp, pll->con_reg);
/* wait_lock_time */ /* Wait for PLL lock */
do { return samsung_pll_lock_wait(pll,
cpu_relax(); PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT);
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
<< PLL2550XX_LOCK_STAT_SHIFT)));
return 0;
} }
static const struct clk_ops samsung_pll2550xx_clk_ops = { 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, ...@@ -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); con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
writel_relaxed(con1, pll->con_reg + 4); writel_relaxed(con1, pll->con_reg + 4);
do { /* Wait for PLL lock */
cpu_relax(); return samsung_pll_lock_wait(pll,
con0 = readl_relaxed(pll->con_reg); PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT);
} while (!(con0 & (PLL2650X_LOCK_STAT_MASK
<< PLL2650X_LOCK_STAT_SHIFT)));
return 0;
} }
static const struct clk_ops samsung_pll2650x_clk_ops = { 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, ...@@ -1196,7 +1195,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct samsung_clk_pll *pll = to_clk_pll(hw); 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; const struct samsung_pll_rate_table *rate;
rate = samsung_get_pll_settings(pll, drate); rate = samsung_get_pll_settings(pll, drate);
...@@ -1229,11 +1228,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long 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_con0, pll->con_reg);
writel_relaxed(pll_con2, pll->con_reg + 8); writel_relaxed(pll_con2, pll->con_reg + 8);
do { return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT);
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
return 0;
} }
static const struct clk_ops samsung_pll2650xx_clk_ops = { static const struct clk_ops samsung_pll2650xx_clk_ops = {
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
struct device_node; struct device_node;
#ifdef CONFIG_ARCH_S3C64XX #ifdef CONFIG_S3C64XX_COMMON_CLK
void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
unsigned long xusbxti_f, bool s3c6400, unsigned long xusbxti_f, bool s3c6400,
void __iomem *base); void __iomem *base);
...@@ -19,7 +19,7 @@ static inline void s3c64xx_clk_init(struct device_node *np, ...@@ -19,7 +19,7 @@ static inline void s3c64xx_clk_init(struct device_node *np,
unsigned long xtal_f, unsigned long xtal_f,
unsigned long xusbxti_f, unsigned long xusbxti_f,
bool s3c6400, void __iomem *base) { } bool s3c6400, void __iomem *base) { }
#endif /* CONFIG_ARCH_S3C64XX */ #endif /* CONFIG_S3C64XX_COMMON_CLK */
#ifdef CONFIG_S3C2410_COMMON_CLK #ifdef CONFIG_S3C2410_COMMON_CLK
void s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, void s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment