提交 15afa044 编写于 作者: S Stephen Boyd

Merge branches 'clk-ti', 'clk-amlogic', 'clk-tegra' and 'clk-samsung' into clk-next

* clk-ti:
  clk: keystone: sci-clk: add support for dynamically probing clocks
  clk: ti: add support for clock latching to mux clocks
  clk: ti: add support for clock latching to divider clocks
  clk: ti: add generic support for clock latching
  clk: ti: add support for register read-modify-write low-level operation
  dt-bindings: clock: ti: add latching support to mux and divider clocks

* clk-amlogic: (50 commits)
  clk: meson: Drop unused local variable and add static
  clk: meson: clean-up clk81 clocks
  clk: meson: add fdiv clock gates
  clk: meson: add mpll pre-divider
  clk: meson: axg: add hifi pll clock
  clk: meson: axg: add hifi clock bindings
  clk: meson: add ROUND_CLOSEST to the pll driver
  clk: meson: add gp0 frac parameter for axg and gxl
  clk: meson: improve pll driver results with frac
  clk: meson: remove special gp0 lock loop
  clk: meson: poke pll CNTL last
  clk: meson: add fractional part of meson8b fixed_pll
  clk: meson: use hhi syscon if available
  clk: meson: remove obsolete cpu_clk
  clk: meson: rework meson8b cpu clock
  clk: meson: split divider and gate part of mpll
  clk: meson: migrate plls clocks to clk_regmap
  clk: meson: migrate the audio divider clock to clk_regmap
  clk: meson: migrate mplls clocks to clk_regmap
  clk: meson: add regmap helpers for parm
  ...

* clk-tegra:
  clk: tegra: Fix pll_u rate configuration
  clk: tegra: Specify VDE clock rate
  clk: tegra20: Correct PLL_C_OUT1 setup
  clk: tegra: Mark HCLK, SCLK and EMC as critical
  clk: tegra: MBIST work around for Tegra210
  clk: tegra: add fence_delay for clock registers
  clk: tegra: Add la clock for Tegra210

* clk-samsung: (22 commits)
  clk: samsung: Mark a few things static
  clk: samsung: Add fout=196608001 Hz EPLL rate entry for exynos4412
  clk: samsung: exynos5250: Add missing clocks for FIMC LITE SYSMMU devices
  clk: samsung: exynos5420: Add more entries to EPLL rate table
  clk: samsung: exynos5420: Add CLK_SET_RATE_PARENT flag to mout_mau_epll_clk
  clk: samsung: exynos5250: Move PD-dependent clocks to Exynos5 sub-CMU
  clk: samsung: exynos5420: Move PD-dependent clocks to Exynos5 sub-CMU
  clk: samsung: Add Exynos5 sub-CMU clock driver
  soc: samsung: pm_domains: Add blacklisting clock handling
  clk: samsung: Add compile time PLL rate validators
  clk: samsung: s3c2410: Fix PLL rates
  clk: samsung: exynos7: Fix PLL rates
  clk: samsung: exynos5433: Fix PLL rates
  clk: samsung: exynos5260: Fix PLL rates
  clk: samsung: exynos5250: Fix PLL rates
  clk: samsung: exynos3250: Fix PLL rates
  clk: exynos5433: Extend list of available AUD_PLL output frequencies
  clk: exynos5433: Add CLK_IGNORE_UNUSED flag to sclk_ioclk_i2s1_bclk
  clk: samsung: Add a git tree entry to MAINTAINERS
  clk: samsung: Remove redundant dev_err call in exynos_audss_clk_probe()
  ...
...@@ -12189,6 +12189,7 @@ M: Tomasz Figa <tomasz.figa@gmail.com> ...@@ -12189,6 +12189,7 @@ M: Tomasz Figa <tomasz.figa@gmail.com>
M: Chanwoo Choi <cw00.choi@samsung.com> M: Chanwoo Choi <cw00.choi@samsung.com>
S: Supported S: Supported
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
F: drivers/clk/samsung/ F: drivers/clk/samsung/
F: include/dt-bindings/clock/exynos*.h F: include/dt-bindings/clock/exynos*.h
F: Documentation/devicetree/bindings/clock/exynos*.txt F: Documentation/devicetree/bindings/clock/exynos*.txt
......
...@@ -28,12 +28,10 @@ ...@@ -28,12 +28,10 @@
* parent - fixed parent. No clk_set_parent support * parent - fixed parent. No clk_set_parent support
*/ */
#define div_mask(width) ((1 << (width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table, static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
u8 width) u8 width)
{ {
unsigned int maxdiv = 0, mask = div_mask(width); unsigned int maxdiv = 0, mask = clk_div_mask(width);
const struct clk_div_table *clkt; const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++) for (clkt = table; clkt->div; clkt++)
...@@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, ...@@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
unsigned long flags) unsigned long flags)
{ {
if (flags & CLK_DIVIDER_ONE_BASED) if (flags & CLK_DIVIDER_ONE_BASED)
return div_mask(width); return clk_div_mask(width);
if (flags & CLK_DIVIDER_POWER_OF_TWO) if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(width); return 1 << clk_div_mask(width);
if (table) if (table)
return _get_table_maxdiv(table, width); return _get_table_maxdiv(table, width);
return div_mask(width) + 1; return clk_div_mask(width) + 1;
} }
static unsigned int _get_table_div(const struct clk_div_table *table, static unsigned int _get_table_div(const struct clk_div_table *table,
...@@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table, ...@@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table,
if (flags & CLK_DIVIDER_POWER_OF_TWO) if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val; return 1 << val;
if (flags & CLK_DIVIDER_MAX_AT_ZERO) if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return val ? val : div_mask(width) + 1; return val ? val : clk_div_mask(width) + 1;
if (table) if (table)
return _get_table_div(table, val); return _get_table_div(table, val);
return val + 1; return val + 1;
...@@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table, ...@@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table,
if (flags & CLK_DIVIDER_POWER_OF_TWO) if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div); return __ffs(div);
if (flags & CLK_DIVIDER_MAX_AT_ZERO) if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return (div == div_mask(width) + 1) ? 0 : div; return (div == clk_div_mask(width) + 1) ? 0 : div;
if (table) if (table)
return _get_table_val(table, div); return _get_table_val(table, div);
return div - 1; return div - 1;
...@@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, ...@@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned int val; unsigned int val;
val = clk_readl(divider->reg) >> divider->shift; val = clk_readl(divider->reg) >> divider->shift;
val &= div_mask(divider->width); val &= clk_div_mask(divider->width);
return divider_recalc_rate(hw, parent_rate, val, divider->table, return divider_recalc_rate(hw, parent_rate, val, divider->table,
divider->flags, divider->width); divider->flags, divider->width);
...@@ -344,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, ...@@ -344,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
} }
EXPORT_SYMBOL_GPL(divider_round_rate_parent); EXPORT_SYMBOL_GPL(divider_round_rate_parent);
long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate, unsigned long *prate,
const struct clk_div_table *table, u8 width,
unsigned long flags, unsigned int val)
{
int div;
div = _get_div(table, val, flags, width);
/* Even a read-only clock can propagate a rate change */
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
if (!parent)
return -EINVAL;
*prate = clk_hw_round_rate(parent, rate * div);
}
return DIV_ROUND_UP_ULL((u64)*prate, div);
}
EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate) unsigned long *prate)
{ {
struct clk_divider *divider = to_clk_divider(hw); struct clk_divider *divider = to_clk_divider(hw);
int bestdiv;
/* if read only, just return current value */ /* if read only, just return current value */
if (divider->flags & CLK_DIVIDER_READ_ONLY) { if (divider->flags & CLK_DIVIDER_READ_ONLY) {
bestdiv = clk_readl(divider->reg) >> divider->shift; u32 val;
bestdiv &= div_mask(divider->width);
bestdiv = _get_div(divider->table, bestdiv, divider->flags, val = clk_readl(divider->reg) >> divider->shift;
divider->width); val &= clk_div_mask(divider->width);
return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
return divider_ro_round_rate(hw, rate, prate, divider->table,
divider->width, divider->flags,
val);
} }
return divider_round_rate(hw, rate, prate, divider->table, return divider_round_rate(hw, rate, prate, divider->table,
...@@ -376,7 +398,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, ...@@ -376,7 +398,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
value = _get_val(table, div, flags, width); value = _get_val(table, div, flags, width);
return min_t(unsigned int, value, div_mask(width)); return min_t(unsigned int, value, clk_div_mask(width));
} }
EXPORT_SYMBOL_GPL(divider_get_val); EXPORT_SYMBOL_GPL(divider_get_val);
...@@ -399,10 +421,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -399,10 +421,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
__acquire(divider->lock); __acquire(divider->lock);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider->width) << (divider->shift + 16); val = clk_div_mask(divider->width) << (divider->shift + 16);
} else { } else {
val = clk_readl(divider->reg); val = clk_readl(divider->reg);
val &= ~(div_mask(divider->width) << divider->shift); val &= ~(clk_div_mask(divider->width) << divider->shift);
} }
val |= (u32)value << divider->shift; val |= (u32)value << divider->shift;
clk_writel(val, divider->reg); clk_writel(val, divider->reg);
......
...@@ -26,35 +26,24 @@ ...@@ -26,35 +26,24 @@
* parent - parent is adjustable through clk_set_parent * parent - parent is adjustable through clk_set_parent
*/ */
static u8 clk_mux_get_parent(struct clk_hw *hw) int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
unsigned int val)
{ {
struct clk_mux *mux = to_clk_mux(hw);
int num_parents = clk_hw_get_num_parents(hw); int num_parents = clk_hw_get_num_parents(hw);
u32 val;
/*
* FIXME need a mux-specific flag to determine if val is bitwise or numeric
* e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
* to 0x7 (index starts at one)
* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
* val = 0x4 really means "bit 2, index starts at bit 0"
*/
val = clk_readl(mux->reg) >> mux->shift;
val &= mux->mask;
if (mux->table) { if (table) {
int i; int i;
for (i = 0; i < num_parents; i++) for (i = 0; i < num_parents; i++)
if (mux->table[i] == val) if (table[i] == val)
return i; return i;
return -EINVAL; return -EINVAL;
} }
if (val && (mux->flags & CLK_MUX_INDEX_BIT)) if (val && (flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1; val = ffs(val) - 1;
if (val && (mux->flags & CLK_MUX_INDEX_ONE)) if (val && (flags & CLK_MUX_INDEX_ONE))
val--; val--;
if (val >= num_parents) if (val >= num_parents)
...@@ -62,36 +51,58 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) ...@@ -62,36 +51,58 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
return val; return val;
} }
EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
static int clk_mux_set_parent(struct clk_hw *hw, u8 index) unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
{ {
struct clk_mux *mux = to_clk_mux(hw); unsigned int val = index;
u32 val;
unsigned long flags = 0;
if (mux->table) { if (table) {
index = mux->table[index]; val = table[index];
} else { } else {
if (mux->flags & CLK_MUX_INDEX_BIT) if (flags & CLK_MUX_INDEX_BIT)
index = 1 << index; val = 1 << index;
if (mux->flags & CLK_MUX_INDEX_ONE) if (flags & CLK_MUX_INDEX_ONE)
index++; val++;
} }
return val;
}
EXPORT_SYMBOL_GPL(clk_mux_index_to_val);
static u8 clk_mux_get_parent(struct clk_hw *hw)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val;
val = clk_readl(mux->reg) >> mux->shift;
val &= mux->mask;
return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
}
static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
unsigned long flags = 0;
u32 reg;
if (mux->lock) if (mux->lock)
spin_lock_irqsave(mux->lock, flags); spin_lock_irqsave(mux->lock, flags);
else else
__acquire(mux->lock); __acquire(mux->lock);
if (mux->flags & CLK_MUX_HIWORD_MASK) { if (mux->flags & CLK_MUX_HIWORD_MASK) {
val = mux->mask << (mux->shift + 16); reg = mux->mask << (mux->shift + 16);
} else { } else {
val = clk_readl(mux->reg); reg = clk_readl(mux->reg);
val &= ~(mux->mask << mux->shift); reg &= ~(mux->mask << mux->shift);
} }
val |= index << mux->shift; val = val << mux->shift;
clk_writel(val, mux->reg); reg |= val;
clk_writel(reg, mux->reg);
if (mux->lock) if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags); spin_unlock_irqrestore(mux->lock, flags);
......
...@@ -1125,8 +1125,10 @@ static int clk_core_round_rate_nolock(struct clk_core *core, ...@@ -1125,8 +1125,10 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
{ {
lockdep_assert_held(&prepare_lock); lockdep_assert_held(&prepare_lock);
if (!core) if (!core) {
req->rate = 0;
return 0; return 0;
}
clk_core_init_rate_req(core, req); clk_core_init_rate_req(core, req);
...@@ -2927,6 +2929,17 @@ static int __clk_core_init(struct clk_core *core) ...@@ -2927,6 +2929,17 @@ static int __clk_core_init(struct clk_core *core)
core->orphan = true; core->orphan = true;
} }
/*
* optional platform-specific magic
*
* The .init callback is not used by any of the basic clock types, but
* exists for weird hardware that must perform initialization magic.
* Please consider other ways of solving initialization problems before
* using this callback, as its use is discouraged.
*/
if (core->ops->init)
core->ops->init(core->hw);
/* /*
* Set clk's accuracy. The preferred method is to use * Set clk's accuracy. The preferred method is to use
* .recalc_accuracy. For simple clocks and lazy developers the default * .recalc_accuracy. For simple clocks and lazy developers the default
...@@ -2967,49 +2980,43 @@ static int __clk_core_init(struct clk_core *core) ...@@ -2967,49 +2980,43 @@ static int __clk_core_init(struct clk_core *core)
rate = 0; rate = 0;
core->rate = core->req_rate = rate; core->rate = core->req_rate = rate;
/*
* Enable CLK_IS_CRITICAL clocks so newly added critical clocks
* don't get accidentally disabled when walking the orphan tree and
* reparenting clocks
*/
if (core->flags & CLK_IS_CRITICAL) {
unsigned long flags;
clk_core_prepare(core);
flags = clk_enable_lock();
clk_core_enable(core);
clk_enable_unlock(flags);
}
/* /*
* walk the list of orphan clocks and reparent any that newly finds a * walk the list of orphan clocks and reparent any that newly finds a
* parent. * parent.
*/ */
hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
struct clk_core *parent = __clk_init_parent(orphan); struct clk_core *parent = __clk_init_parent(orphan);
unsigned long flags;
/* /*
* we could call __clk_set_parent, but that would result in a * We need to use __clk_set_parent_before() and _after() to
* redundant call to the .set_rate op, if it exists * to properly migrate any prepare/enable count of the orphan
* clock. This is important for CLK_IS_CRITICAL clocks, which
* are enabled during init but might not have a parent yet.
*/ */
if (parent) { if (parent) {
/* update the clk tree topology */ /* update the clk tree topology */
flags = clk_enable_lock(); __clk_set_parent_before(orphan, parent);
clk_reparent(orphan, parent); __clk_set_parent_after(orphan, parent, NULL);
clk_enable_unlock(flags);
__clk_recalc_accuracies(orphan); __clk_recalc_accuracies(orphan);
__clk_recalc_rates(orphan, 0); __clk_recalc_rates(orphan, 0);
} }
} }
/*
* optional platform-specific magic
*
* The .init callback is not used by any of the basic clock types, but
* exists for weird hardware that must perform initialization magic.
* Please consider other ways of solving initialization problems before
* using this callback, as its use is discouraged.
*/
if (core->ops->init)
core->ops->init(core->hw);
if (core->flags & CLK_IS_CRITICAL) {
unsigned long flags;
clk_core_prepare(core);
flags = clk_enable_lock();
clk_core_enable(core);
clk_enable_unlock(flags);
}
kref_init(&core->ref); kref_init(&core->ref);
out: out:
clk_pm_runtime_put(core); clk_pm_runtime_put(core);
......
...@@ -3,10 +3,15 @@ config COMMON_CLK_AMLOGIC ...@@ -3,10 +3,15 @@ config COMMON_CLK_AMLOGIC
depends on OF depends on OF
depends on ARCH_MESON || COMPILE_TEST depends on ARCH_MESON || COMPILE_TEST
config COMMON_CLK_REGMAP_MESON
bool
select REGMAP
config COMMON_CLK_MESON8B config COMMON_CLK_MESON8B
bool bool
depends on COMMON_CLK_AMLOGIC depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER select RESET_CONTROLLER
select COMMON_CLK_REGMAP_MESON
help help
Support for the clock controller on AmLogic S802 (Meson8), Support for the clock controller on AmLogic S802 (Meson8),
S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
...@@ -16,6 +21,8 @@ config COMMON_CLK_GXBB ...@@ -16,6 +21,8 @@ config COMMON_CLK_GXBB
bool bool
depends on COMMON_CLK_AMLOGIC depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER select RESET_CONTROLLER
select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON
help help
Support for the clock controller on AmLogic S905 devices, aka gxbb. Support for the clock controller on AmLogic S905 devices, aka gxbb.
Say Y if you want peripherals and CPU frequency scaling to work. Say Y if you want peripherals and CPU frequency scaling to work.
...@@ -24,6 +31,8 @@ config COMMON_CLK_AXG ...@@ -24,6 +31,8 @@ config COMMON_CLK_AXG
bool bool
depends on COMMON_CLK_AMLOGIC depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER select RESET_CONTROLLER
select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON
help help
Support for the clock controller on AmLogic A113D devices, aka axg. Support for the clock controller on AmLogic A113D devices, aka axg.
Say Y if you want peripherals and CPU frequency scaling to work. Say Y if you want peripherals and CPU frequency scaling to work.
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
# Makefile for Meson specific clk # Makefile for Meson specific clk
# #
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o
此差异已折叠。
...@@ -117,8 +117,18 @@ ...@@ -117,8 +117,18 @@
#define CLKID_SD_EMMC_B_CLK0_DIV 62 #define CLKID_SD_EMMC_B_CLK0_DIV 62
#define CLKID_SD_EMMC_C_CLK0_SEL 63 #define CLKID_SD_EMMC_C_CLK0_SEL 63
#define CLKID_SD_EMMC_C_CLK0_DIV 64 #define CLKID_SD_EMMC_C_CLK0_DIV 64
#define CLKID_MPLL0_DIV 65
#define CLKID_MPLL1_DIV 66
#define CLKID_MPLL2_DIV 67
#define CLKID_MPLL3_DIV 68
#define CLKID_MPLL_PREDIV 70
#define CLKID_FCLK_DIV2_DIV 71
#define CLKID_FCLK_DIV3_DIV 72
#define CLKID_FCLK_DIV4_DIV 73
#define CLKID_FCLK_DIV5_DIV 74
#define CLKID_FCLK_DIV7_DIV 75
#define NR_CLKS 65 #define NR_CLKS 76
/* include the CLKIDs that have been made part of the DT binding */ /* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/axg-clkc.h> #include <dt-bindings/clock/axg-clkc.h>
......
...@@ -28,8 +28,11 @@ ...@@ -28,8 +28,11 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include "clkc.h" #include "clkc.h"
#define to_meson_clk_audio_divider(_hw) container_of(_hw, \ static inline struct meson_clk_audio_div_data *
struct meson_clk_audio_divider, hw) meson_clk_audio_div_data(struct clk_regmap *clk)
{
return (struct meson_clk_audio_div_data *)clk->data;
}
static int _div_round(unsigned long parent_rate, unsigned long rate, static int _div_round(unsigned long parent_rate, unsigned long rate,
unsigned long flags) unsigned long flags)
...@@ -45,15 +48,9 @@ static int _get_val(unsigned long parent_rate, unsigned long rate) ...@@ -45,15 +48,9 @@ static int _get_val(unsigned long parent_rate, unsigned long rate)
return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
} }
static int _valid_divider(struct clk_hw *hw, int divider) static int _valid_divider(unsigned int width, int divider)
{ {
struct meson_clk_audio_divider *adiv = int max_divider = 1 << width;
to_meson_clk_audio_divider(hw);
int max_divider;
u8 width;
width = adiv->div.width;
max_divider = 1 << width;
return clamp(divider, 1, max_divider); return clamp(divider, 1, max_divider);
} }
...@@ -61,14 +58,11 @@ static int _valid_divider(struct clk_hw *hw, int divider) ...@@ -61,14 +58,11 @@ static int _valid_divider(struct clk_hw *hw, int divider)
static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, static unsigned long audio_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_audio_divider *adiv = struct clk_regmap *clk = to_clk_regmap(hw);
to_meson_clk_audio_divider(hw); struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
struct parm *p; unsigned long divider;
unsigned long reg, divider;
p = &adiv->div; divider = meson_parm_read(clk->map, &adiv->div);
reg = readl(adiv->base + p->reg_off);
divider = PARM_GET(p->width, p->shift, reg) + 1;
return DIV_ROUND_UP_ULL((u64)parent_rate, divider); return DIV_ROUND_UP_ULL((u64)parent_rate, divider);
} }
...@@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw, ...@@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
struct meson_clk_audio_divider *adiv = struct clk_regmap *clk = to_clk_regmap(hw);
to_meson_clk_audio_divider(hw); struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
unsigned long max_prate; unsigned long max_prate;
int divider; int divider;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
divider = _div_round(*parent_rate, rate, adiv->flags); divider = _div_round(*parent_rate, rate, adiv->flags);
divider = _valid_divider(hw, divider); divider = _valid_divider(adiv->div.width, divider);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
} }
...@@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw, ...@@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw,
/* Get the corresponding rounded down divider */ /* Get the corresponding rounded down divider */
divider = max_prate / rate; divider = max_prate / rate;
divider = _valid_divider(hw, divider); divider = _valid_divider(adiv->div.width, divider);
/* Get actual rate of the parent */ /* Get actual rate of the parent */
*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
...@@ -106,28 +100,11 @@ static int audio_divider_set_rate(struct clk_hw *hw, ...@@ -106,28 +100,11 @@ static int audio_divider_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_audio_divider *adiv = struct clk_regmap *clk = to_clk_regmap(hw);
to_meson_clk_audio_divider(hw); struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
struct parm *p; int val = _get_val(parent_rate, rate);
unsigned long reg, flags = 0;
int val; meson_parm_write(clk->map, &adiv->div, val);
val = _get_val(parent_rate, rate);
if (adiv->lock)
spin_lock_irqsave(adiv->lock, flags);
else
__acquire(adiv->lock);
p = &adiv->div;
reg = readl(adiv->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, val);
writel(reg, adiv->base + p->reg_off);
if (adiv->lock)
spin_unlock_irqrestore(adiv->lock, flags);
else
__release(adiv->lock);
return 0; return 0;
} }
......
/*
* Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* CPU clock path:
*
* +-[/N]-----|3|
* MUX2 +--[/3]-+----------|2| MUX1
* [sys_pll]---|1| |--[/2]------------|1|-|1|
* | |---+------------------|0| | |----- [a5_clk]
* +--|0| | |
* [xtal]---+-------------------------------|0|
*
*
*
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#define MESON_CPU_CLK_CNTL1 0x00
#define MESON_CPU_CLK_CNTL 0x40
#define MESON_CPU_CLK_MUX1 BIT(7)
#define MESON_CPU_CLK_MUX2 BIT(0)
#define MESON_N_WIDTH 9
#define MESON_N_SHIFT 20
#define MESON_SEL_WIDTH 2
#define MESON_SEL_SHIFT 2
#include "clkc.h"
#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw)
#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb)
static long meson_clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
return divider_round_rate(hw, rate, prate, clk_cpu->div_table,
MESON_N_WIDTH, CLK_DIVIDER_ROUND_CLOSEST);
}
static int meson_clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
unsigned int div, sel, N = 0;
u32 reg;
div = DIV_ROUND_UP(parent_rate, rate);
if (div <= 3) {
sel = div - 1;
} else {
sel = 3;
N = div / 2;
}
reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
reg = PARM_SET(MESON_N_WIDTH, MESON_N_SHIFT, reg, N);
writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
reg = PARM_SET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg, sel);
writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
return 0;
}
static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
unsigned int N, sel;
unsigned int div = 1;
u32 reg;
reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
N = PARM_GET(MESON_N_WIDTH, MESON_N_SHIFT, reg);
reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
sel = PARM_GET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg);
if (sel < 3)
div = sel + 1;
else
div = 2 * N;
return parent_rate / div;
}
/* FIXME MUX1 & MUX2 should be struct clk_hw objects */
static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu,
struct clk_notifier_data *ndata)
{
u32 cpu_clk_cntl;
/* switch MUX1 to xtal */
cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off
+ MESON_CPU_CLK_CNTL);
cpu_clk_cntl &= ~MESON_CPU_CLK_MUX1;
writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+ MESON_CPU_CLK_CNTL);
udelay(100);
/* switch MUX2 to sys-pll */
cpu_clk_cntl |= MESON_CPU_CLK_MUX2;
writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+ MESON_CPU_CLK_CNTL);
return 0;
}
/* FIXME MUX1 & MUX2 should be struct clk_hw objects */
static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu,
struct clk_notifier_data *ndata)
{
u32 cpu_clk_cntl;
/* switch MUX1 to divisors' output */
cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off
+ MESON_CPU_CLK_CNTL);
cpu_clk_cntl |= MESON_CPU_CLK_MUX1;
writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+ MESON_CPU_CLK_CNTL);
udelay(100);
return 0;
}
/*
* This clock notifier is called when the frequency of the of the parent
* PLL clock is to be changed. We use the xtal input as temporary parent
* while the PLL frequency is stabilized.
*/
int meson_clk_cpu_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct clk_notifier_data *ndata = data;
struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_nb(nb);
int ret = 0;
if (event == PRE_RATE_CHANGE)
ret = meson_clk_cpu_pre_rate_change(clk_cpu, ndata);
else if (event == POST_RATE_CHANGE)
ret = meson_clk_cpu_post_rate_change(clk_cpu, ndata);
return notifier_from_errno(ret);
}
const struct clk_ops meson_clk_cpu_ops = {
.recalc_rate = meson_clk_cpu_recalc_rate,
.round_rate = meson_clk_cpu_round_rate,
.set_rate = meson_clk_cpu_set_rate,
};
...@@ -68,11 +68,15 @@ ...@@ -68,11 +68,15 @@
#define N2_MIN 4 #define N2_MIN 4
#define N2_MAX 511 #define N2_MAX 511
#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) static inline struct meson_clk_mpll_data *
meson_clk_mpll_data(struct clk_regmap *clk)
{
return (struct meson_clk_mpll_data *)clk->data;
}
static long rate_from_params(unsigned long parent_rate, static long rate_from_params(unsigned long parent_rate,
unsigned long sdm, unsigned int sdm,
unsigned long n2) unsigned int n2)
{ {
unsigned long divisor = (SDM_DEN * n2) + sdm; unsigned long divisor = (SDM_DEN * n2) + sdm;
...@@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate, ...@@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate,
static void params_from_rate(unsigned long requested_rate, static void params_from_rate(unsigned long requested_rate,
unsigned long parent_rate, unsigned long parent_rate,
unsigned long *sdm, unsigned int *sdm,
unsigned long *n2) unsigned int *n2)
{ {
uint64_t div = parent_rate; uint64_t div = parent_rate;
unsigned long rem = do_div(div, requested_rate); unsigned long rem = do_div(div, requested_rate);
...@@ -105,31 +109,23 @@ static void params_from_rate(unsigned long requested_rate, ...@@ -105,31 +109,23 @@ static void params_from_rate(unsigned long requested_rate,
static unsigned long mpll_recalc_rate(struct clk_hw *hw, static unsigned long mpll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
struct parm *p; struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
unsigned long reg, sdm, n2; unsigned int sdm, n2;
long rate; long rate;
p = &mpll->sdm; sdm = meson_parm_read(clk->map, &mpll->sdm);
reg = readl(mpll->base + p->reg_off); n2 = meson_parm_read(clk->map, &mpll->n2);
sdm = PARM_GET(p->width, p->shift, reg);
p = &mpll->n2;
reg = readl(mpll->base + p->reg_off);
n2 = PARM_GET(p->width, p->shift, reg);
rate = rate_from_params(parent_rate, sdm, n2); rate = rate_from_params(parent_rate, sdm, n2);
if (rate < 0) return rate < 0 ? 0 : rate;
return 0;
return rate;
} }
static long mpll_round_rate(struct clk_hw *hw, static long mpll_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
unsigned long sdm, n2; unsigned int sdm, n2;
params_from_rate(rate, *parent_rate, &sdm, &n2); params_from_rate(rate, *parent_rate, &sdm, &n2);
return rate_from_params(*parent_rate, sdm, n2); return rate_from_params(*parent_rate, sdm, n2);
...@@ -139,9 +135,9 @@ static int mpll_set_rate(struct clk_hw *hw, ...@@ -139,9 +135,9 @@ static int mpll_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
struct parm *p; struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
unsigned long reg, sdm, n2; unsigned int sdm, n2;
unsigned long flags = 0; unsigned long flags = 0;
params_from_rate(rate, parent_rate, &sdm, &n2); params_from_rate(rate, parent_rate, &sdm, &n2);
...@@ -151,97 +147,36 @@ static int mpll_set_rate(struct clk_hw *hw, ...@@ -151,97 +147,36 @@ static int mpll_set_rate(struct clk_hw *hw,
else else
__acquire(mpll->lock); __acquire(mpll->lock);
p = &mpll->sdm; /* Enable and set the fractional part */
reg = readl(mpll->base + p->reg_off); meson_parm_write(clk->map, &mpll->sdm, sdm);
reg = PARM_SET(p->width, p->shift, reg, sdm); meson_parm_write(clk->map, &mpll->sdm_en, 1);
writel(reg, mpll->base + p->reg_off);
p = &mpll->sdm_en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);
p = &mpll->ssen;
if (p->width != 0) {
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);
}
p = &mpll->n2; /* Set additional fractional part enable if required */
reg = readl(mpll->base + p->reg_off); if (MESON_PARM_APPLICABLE(&mpll->ssen))
reg = PARM_SET(p->width, p->shift, reg, n2); meson_parm_write(clk->map, &mpll->ssen, 1);
writel(reg, mpll->base + p->reg_off);
if (mpll->lock) /* Set the integer divider part */
spin_unlock_irqrestore(mpll->lock, flags); meson_parm_write(clk->map, &mpll->n2, n2);
else
__release(mpll->lock);
return 0;
}
static void mpll_enable_core(struct clk_hw *hw, int enable) /* Set the magic misc bit if required */
{ if (MESON_PARM_APPLICABLE(&mpll->misc))
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); meson_parm_write(clk->map, &mpll->misc, 1);
struct parm *p;
unsigned long reg;
unsigned long flags = 0;
if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);
p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0);
writel(reg, mpll->base + p->reg_off);
if (mpll->lock) if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags); spin_unlock_irqrestore(mpll->lock, flags);
else else
__release(mpll->lock); __release(mpll->lock);
}
static int mpll_enable(struct clk_hw *hw)
{
mpll_enable_core(hw, 1);
return 0; return 0;
} }
static void mpll_disable(struct clk_hw *hw)
{
mpll_enable_core(hw, 0);
}
static int mpll_is_enabled(struct clk_hw *hw)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg;
int en;
p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
en = PARM_GET(p->width, p->shift, reg);
return en;
}
const struct clk_ops meson_clk_mpll_ro_ops = { const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate, .recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate, .round_rate = mpll_round_rate,
.is_enabled = mpll_is_enabled,
}; };
const struct clk_ops meson_clk_mpll_ops = { const struct clk_ops meson_clk_mpll_ops = {
.recalc_rate = mpll_recalc_rate, .recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate, .round_rate = mpll_round_rate,
.set_rate = mpll_set_rate, .set_rate = mpll_set_rate,
.enable = mpll_enable,
.disable = mpll_disable,
.is_enabled = mpll_is_enabled,
}; };
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
* Copyright (c) 2015 Endless Mobile, Inc. * Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com> * Author: Carlo Caione <carlo@endlessm.com>
* *
* Copyright (c) 2018 Baylibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation. * version 2, as published by the Free Software Foundation.
...@@ -27,13 +30,14 @@ ...@@ -27,13 +30,14 @@
* | | * | |
* FREF VCO * FREF VCO
* *
* out = (in * M / N) >> OD * out = in * (m + frac / frac_max) / (n << sum(ods))
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -41,209 +45,213 @@ ...@@ -41,209 +45,213 @@
#include "clkc.h" #include "clkc.h"
#define MESON_PLL_RESET BIT(29) static inline struct meson_clk_pll_data *
#define MESON_PLL_LOCK BIT(31) meson_clk_pll_data(struct clk_regmap *clk)
{
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) return (struct meson_clk_pll_data *)clk->data;
}
static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static unsigned long __pll_params_to_rate(unsigned long parent_rate,
unsigned long parent_rate) const struct pll_rate_table *pllt,
u16 frac,
struct meson_clk_pll_data *pll)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); u64 rate = (u64)parent_rate * pllt->m;
struct parm *p; unsigned int od = pllt->od + pllt->od2 + pllt->od3;
unsigned long parent_rate_mhz = parent_rate / 1000000;
unsigned long rate_mhz; if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
u16 n, m, frac = 0, od, od2 = 0; u64 frac_rate = (u64)parent_rate * frac;
u32 reg;
rate += DIV_ROUND_UP_ULL(frac_rate,
p = &pll->n; (1 << pll->frac.width));
reg = readl(pll->base + p->reg_off);
n = PARM_GET(p->width, p->shift, reg);
p = &pll->m;
reg = readl(pll->base + p->reg_off);
m = PARM_GET(p->width, p->shift, reg);
p = &pll->od;
reg = readl(pll->base + p->reg_off);
od = PARM_GET(p->width, p->shift, reg);
p = &pll->od2;
if (p->width) {
reg = readl(pll->base + p->reg_off);
od2 = PARM_GET(p->width, p->shift, reg);
} }
p = &pll->frac; return DIV_ROUND_UP_ULL(rate, pllt->n << od);
if (p->width) {
reg = readl(pll->base + p->reg_off);
frac = PARM_GET(p->width, p->shift, reg);
rate_mhz = (parent_rate_mhz * m + \
(parent_rate_mhz * frac >> 12)) * 2 / n;
rate_mhz = rate_mhz >> od >> od2;
} else
rate_mhz = (parent_rate_mhz * m / n) >> od >> od2;
return rate_mhz * 1000000;
} }
static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long *parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
const struct pll_rate_table *rate_table = pll->rate_table; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
int i; struct pll_rate_table pllt;
u16 frac;
for (i = 0; i < pll->rate_count; i++) { pllt.n = meson_parm_read(clk->map, &pll->n);
if (rate <= rate_table[i].rate) pllt.m = meson_parm_read(clk->map, &pll->m);
return rate_table[i].rate; pllt.od = meson_parm_read(clk->map, &pll->od);
}
pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
meson_parm_read(clk->map, &pll->od2) :
0;
pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
meson_parm_read(clk->map, &pll->od3) :
0;
/* else return the smallest value */ frac = MESON_PARM_APPLICABLE(&pll->frac) ?
return rate_table[0].rate; meson_parm_read(clk->map, &pll->frac) :
0;
return __pll_params_to_rate(parent_rate, &pllt, frac, pll);
} }
static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, static u16 __pll_params_with_frac(unsigned long rate,
unsigned long rate) unsigned long parent_rate,
const struct pll_rate_table *pllt,
struct meson_clk_pll_data *pll)
{ {
const struct pll_rate_table *rate_table = pll->rate_table; u16 frac_max = (1 << pll->frac.width);
int i; u64 val = (u64)rate * pllt->n;
for (i = 0; i < pll->rate_count; i++) { val <<= pllt->od + pllt->od2 + pllt->od3;
if (rate == rate_table[i].rate)
return &rate_table[i]; if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
} val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
return NULL; else
val = div_u64(val * frac_max, parent_rate);
val -= pllt->m * frac_max;
return min((u16)val, (u16)(frac_max - 1));
} }
/* Specific wait loop for GXL/GXM GP0 PLL */ static const struct pll_rate_table *
static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, meson_clk_get_pll_settings(unsigned long rate,
struct parm *p_n) struct meson_clk_pll_data *pll)
{ {
int delay = 100; const struct pll_rate_table *table = pll->table;
u32 reg; unsigned int i = 0;
while (delay > 0) { if (!table)
reg = readl(pll->base + p_n->reg_off); return NULL;
writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off);
udelay(10);
writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off);
/* This delay comes from AMLogic tree clk-gp0-gxl driver */ /* Find the first table element exceeding rate */
mdelay(1); while (table[i].rate && table[i].rate <= rate)
i++;
reg = readl(pll->base + p_n->reg_off); if (i != 0) {
if (reg & MESON_PLL_LOCK) if (MESON_PARM_APPLICABLE(&pll->frac) ||
return 0; !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
delay--; (abs(rate - table[i - 1].rate) <
abs(rate - table[i].rate)))
i--;
} }
return -ETIMEDOUT;
return (struct pll_rate_table *)&table[i];
} }
static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
struct parm *p_n) unsigned long *parent_rate)
{ {
int delay = 24000000; struct clk_regmap *clk = to_clk_regmap(hw);
u32 reg; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
const struct pll_rate_table *pllt =
meson_clk_get_pll_settings(rate, pll);
u16 frac;
if (!pllt)
return meson_clk_pll_recalc_rate(hw, *parent_rate);
if (!MESON_PARM_APPLICABLE(&pll->frac)
|| rate == pllt->rate)
return pllt->rate;
/*
* The rate provided by the setting is not an exact match, let's
* try to improve the result using the fractional parameter
*/
frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll);
return __pll_params_to_rate(*parent_rate, pllt, frac, pll);
}
while (delay > 0) { static int meson_clk_pll_wait_lock(struct clk_hw *hw)
reg = readl(pll->base + p_n->reg_off); {
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
int delay = 24000000;
if (reg & MESON_PLL_LOCK) do {
/* Is the clock locked now ? */
if (meson_parm_read(clk->map, &pll->l))
return 0; return 0;
delay--; delay--;
} } while (delay > 0);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void meson_clk_pll_init_params(struct meson_clk_pll *pll) static void meson_clk_pll_init(struct clk_hw *hw)
{ {
int i; struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
for (i = 0 ; i < pll->params.params_count ; ++i)
writel(pll->params.params_table[i].value, if (pll->init_count) {
pll->base + pll->params.params_table[i].reg_off); meson_parm_write(clk->map, &pll->rst, 1);
regmap_multi_reg_write(clk->map, pll->init_regs,
pll->init_count);
meson_parm_write(clk->map, &pll->rst, 0);
}
} }
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
struct parm *p; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
const struct pll_rate_table *rate_set; const struct pll_rate_table *pllt;
unsigned long old_rate; unsigned long old_rate;
int ret = 0; u16 frac = 0;
u32 reg;
if (parent_rate == 0 || rate == 0) if (parent_rate == 0 || rate == 0)
return -EINVAL; return -EINVAL;
old_rate = rate; old_rate = rate;
rate_set = meson_clk_get_pll_settings(pll, rate); pllt = meson_clk_get_pll_settings(rate, pll);
if (!rate_set) if (!pllt)
return -EINVAL; return -EINVAL;
/* Initialize the PLL in a clean state if specified */ /* Put the pll in reset to write the params */
if (pll->params.params_count) meson_parm_write(clk->map, &pll->rst, 1);
meson_clk_pll_init_params(pll);
/* PLL reset */
p = &pll->n;
reg = readl(pll->base + p->reg_off);
/* If no_init_reset is provided, avoid resetting at this point */
if (!pll->params.no_init_reset)
writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
writel(reg, pll->base + p->reg_off);
p = &pll->m;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
writel(reg, pll->base + p->reg_off);
p = &pll->od;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
writel(reg, pll->base + p->reg_off);
p = &pll->od2;
if (p->width) {
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od2);
writel(reg, pll->base + p->reg_off);
}
p = &pll->frac; meson_parm_write(clk->map, &pll->n, pllt->n);
if (p->width) { meson_parm_write(clk->map, &pll->m, pllt->m);
reg = readl(pll->base + p->reg_off); meson_parm_write(clk->map, &pll->od, pllt->od);
reg = PARM_SET(p->width, p->shift, reg, rate_set->frac);
writel(reg, pll->base + p->reg_off);
}
p = &pll->n; if (MESON_PARM_APPLICABLE(&pll->od2))
/* If clear_reset_for_lock is provided, remove the reset bit here */ meson_parm_write(clk->map, &pll->od2, pllt->od2);
if (pll->params.clear_reset_for_lock) {
reg = readl(pll->base + p->reg_off); if (MESON_PARM_APPLICABLE(&pll->od3))
writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); meson_parm_write(clk->map, &pll->od3, pllt->od3);
if (MESON_PARM_APPLICABLE(&pll->frac)) {
frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
meson_parm_write(clk->map, &pll->frac, frac);
} }
/* If reset_lock_loop, use a special loop including resetting */ /* make sure the reset is cleared at this point */
if (pll->params.reset_lock_loop) meson_parm_write(clk->map, &pll->rst, 0);
ret = meson_clk_pll_wait_lock_reset(pll, p);
else if (meson_clk_pll_wait_lock(hw)) {
ret = meson_clk_pll_wait_lock(pll, p);
if (ret) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
__func__, old_rate); __func__, old_rate);
/*
* FIXME: Do we really need/want this HACK ?
* It looks unsafe. what happens if the clock gets into a
* broken state and we can't lock back on the old_rate ? Looks
* like an infinite recursion is possible
*/
meson_clk_pll_set_rate(hw, old_rate, parent_rate); meson_clk_pll_set_rate(hw, old_rate, parent_rate);
} }
return ret; return 0;
} }
const struct clk_ops meson_clk_pll_ops = { const struct clk_ops meson_clk_pll_ops = {
.init = meson_clk_pll_init,
.recalc_rate = meson_clk_pll_recalc_rate, .recalc_rate = meson_clk_pll_recalc_rate,
.round_rate = meson_clk_pll_round_rate, .round_rate = meson_clk_pll_round_rate,
.set_rate = meson_clk_pll_set_rate, .set_rate = meson_clk_pll_set_rate,
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018 BayLibre, SAS.
// Author: Jerome Brunet <jbrunet@baylibre.com>
#include "clk-regmap.h"
static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
set ^= enable;
return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx),
set ? BIT(gate->bit_idx) : 0);
}
static int clk_regmap_gate_enable(struct clk_hw *hw)
{
return clk_regmap_gate_endisable(hw, 1);
}
static void clk_regmap_gate_disable(struct clk_hw *hw)
{
clk_regmap_gate_endisable(hw, 0);
}
static int clk_regmap_gate_is_enabled(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
unsigned int val;
regmap_read(clk->map, gate->offset, &val);
if (gate->flags & CLK_GATE_SET_TO_DISABLE)
val ^= BIT(gate->bit_idx);
val &= BIT(gate->bit_idx);
return val ? 1 : 0;
}
const struct clk_ops clk_regmap_gate_ops = {
.enable = clk_regmap_gate_enable,
.disable = clk_regmap_gate_disable,
.is_enabled = clk_regmap_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_regmap_gate_ops);
static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
unsigned int val;
int ret;
ret = regmap_read(clk->map, div->offset, &val);
if (ret)
/* Gives a hint that something is wrong */
return 0;
val >>= div->shift;
val &= clk_div_mask(div->width);
return divider_recalc_rate(hw, prate, val, div->table, div->flags,
div->width);
}
static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
unsigned int val;
int ret;
/* if read only, just return current value */
if (div->flags & CLK_DIVIDER_READ_ONLY) {
ret = regmap_read(clk->map, div->offset, &val);
if (ret)
/* Gives a hint that something is wrong */
return 0;
val >>= div->shift;
val &= clk_div_mask(div->width);
return divider_ro_round_rate(hw, rate, prate, div->table,
div->width, div->flags, val);
}
return divider_round_rate(hw, rate, prate, div->table, div->width,
div->flags);
}
static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
unsigned int val;
int ret;
ret = divider_get_val(rate, parent_rate, div->table, div->width,
div->flags);
if (ret < 0)
return ret;
val = (unsigned int)ret << div->shift;
return regmap_update_bits(clk->map, div->offset,
clk_div_mask(div->width) << div->shift, val);
};
/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
const struct clk_ops clk_regmap_divider_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
.round_rate = clk_regmap_div_round_rate,
.set_rate = clk_regmap_div_set_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
const struct clk_ops clk_regmap_divider_ro_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
.round_rate = clk_regmap_div_round_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
unsigned int val;
int ret;
ret = regmap_read(clk->map, mux->offset, &val);
if (ret)
return ret;
val >>= mux->shift;
val &= mux->mask;
return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
}
static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index);
return regmap_update_bits(clk->map, mux->offset,
mux->mask << mux->shift,
val << mux->shift);
}
const struct clk_ops clk_regmap_mux_ops = {
.get_parent = clk_regmap_mux_get_parent,
.set_parent = clk_regmap_mux_set_parent,
.determine_rate = __clk_mux_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_mux_ops);
const struct clk_ops clk_regmap_mux_ro_ops = {
.get_parent = clk_regmap_mux_get_parent,
};
EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018 BayLibre, SAS.
// Author: Jerome Brunet <jbrunet@baylibre.com>
#ifndef __CLK_REGMAP_H
#define __CLK_REGMAP_H
#include <linux/clk-provider.h>
#include <linux/regmap.h>
/**
* struct clk_regmap - regmap backed clock
*
* @hw: handle between common and hardware-specific interfaces
* @map: pointer to the regmap structure controlling the clock
* @data: data specific to the clock type
*
* Clock which is controlled by regmap backed registers. The actual type of
* of the clock is controlled by the clock_ops and data.
*/
struct clk_regmap {
struct clk_hw hw;
struct regmap *map;
void *data;
};
#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw)
/**
* struct clk_regmap_gate_data - regmap backed gate specific data
*
* @offset: offset of the register controlling gate
* @bit_idx: single bit controlling gate
* @flags: hardware-specific flags
*
* Flags:
* Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored
*/
struct clk_regmap_gate_data {
unsigned int offset;
u8 bit_idx;
u8 flags;
};
static inline struct clk_regmap_gate_data *
clk_get_regmap_gate_data(struct clk_regmap *clk)
{
return (struct clk_regmap_gate_data *)clk->data;
}
extern const struct clk_ops clk_regmap_gate_ops;
/**
* struct clk_regmap_div_data - regmap backed adjustable divider specific data
*
* @offset: offset of the register controlling the divider
* @shift: shift to the divider bit field
* @width: width of the divider bit field
* @table: array of value/divider pairs, last entry should have div = 0
*
* Flags:
* Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored
*/
struct clk_regmap_div_data {
unsigned int offset;
u8 shift;
u8 width;
u8 flags;
const struct clk_div_table *table;
};
static inline struct clk_regmap_div_data *
clk_get_regmap_div_data(struct clk_regmap *clk)
{
return (struct clk_regmap_div_data *)clk->data;
}
extern const struct clk_ops clk_regmap_divider_ops;
extern const struct clk_ops clk_regmap_divider_ro_ops;
/**
* struct clk_regmap_mux_data - regmap backed multiplexer clock specific data
*
* @hw: handle between common and hardware-specific interfaces
* @offset: offset of theregister controlling multiplexer
* @table: array of parent indexed register values
* @shift: shift to multiplexer bit field
* @mask: mask of mutliplexer bit field
* @flags: hardware-specific flags
*
* Flags:
* Same as clk_divider except CLK_MUX_HIWORD_MASK which is ignored
*/
struct clk_regmap_mux_data {
unsigned int offset;
u32 *table;
u32 mask;
u8 shift;
u8 flags;
};
static inline struct clk_regmap_mux_data *
clk_get_regmap_mux_data(struct clk_regmap *clk)
{
return (struct clk_regmap_mux_data *)clk->data;
}
extern const struct clk_ops clk_regmap_mux_ops;
extern const struct clk_ops clk_regmap_mux_ro_ops;
#endif /* __CLK_REGMAP_H */
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#ifndef __CLKC_H #ifndef __CLKC_H
#define __CLKC_H #define __CLKC_H
#include <linux/clk-provider.h>
#include "clk-regmap.h"
#define PMASK(width) GENMASK(width - 1, 0) #define PMASK(width) GENMASK(width - 1, 0)
#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) #define SETPMASK(width, shift) GENMASK(shift + width - 1, shift)
#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) #define CLRPMASK(width, shift) (~SETPMASK(width, shift))
...@@ -35,13 +38,29 @@ struct parm { ...@@ -35,13 +38,29 @@ struct parm {
u8 width; u8 width;
}; };
static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p)
{
unsigned int val;
regmap_read(map, p->reg_off, &val);
return PARM_GET(p->width, p->shift, val);
}
static inline void meson_parm_write(struct regmap *map, struct parm *p,
unsigned int val)
{
regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift),
val << p->shift);
}
struct pll_rate_table { struct pll_rate_table {
unsigned long rate; unsigned long rate;
u16 m; u16 m;
u16 n; u16 n;
u16 od; u16 od;
u16 od2; u16 od2;
u16 frac; u16 od3;
}; };
#define PLL_RATE(_r, _m, _n, _od) \ #define PLL_RATE(_r, _m, _n, _od) \
...@@ -50,94 +69,50 @@ struct pll_rate_table { ...@@ -50,94 +69,50 @@ struct pll_rate_table {
.m = (_m), \ .m = (_m), \
.n = (_n), \ .n = (_n), \
.od = (_od), \ .od = (_od), \
} \
#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \
{ \
.rate = (_r), \
.m = (_m), \
.n = (_n), \
.od = (_od), \
.od2 = (_od2), \
.frac = (_frac), \
} \
struct pll_params_table {
unsigned int reg_off;
unsigned int value;
};
#define PLL_PARAM(_reg, _val) \
{ \
.reg_off = (_reg), \
.value = (_val), \
} }
struct pll_setup_params { #define CLK_MESON_PLL_ROUND_CLOSEST BIT(0)
struct pll_params_table *params_table;
unsigned int params_count;
/* Workaround for GP0, do not reset before configuring */
bool no_init_reset;
/* Workaround for GP0, unreset right before checking for lock */
bool clear_reset_for_lock;
/* Workaround for GXL GP0, reset in the lock checking loop */
bool reset_lock_loop;
};
struct meson_clk_pll { struct meson_clk_pll_data {
struct clk_hw hw;
void __iomem *base;
struct parm m; struct parm m;
struct parm n; struct parm n;
struct parm frac; struct parm frac;
struct parm od; struct parm od;
struct parm od2; struct parm od2;
const struct pll_setup_params params; struct parm od3;
const struct pll_rate_table *rate_table; struct parm l;
unsigned int rate_count; struct parm rst;
spinlock_t *lock; const struct reg_sequence *init_regs;
unsigned int init_count;
const struct pll_rate_table *table;
u8 flags;
}; };
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
struct meson_clk_cpu { struct meson_clk_mpll_data {
struct clk_hw hw;
void __iomem *base;
u16 reg_off;
struct notifier_block clk_nb;
const struct clk_div_table *div_table;
};
int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event,
void *data);
struct meson_clk_mpll {
struct clk_hw hw;
void __iomem *base;
struct parm sdm; struct parm sdm;
struct parm sdm_en; struct parm sdm_en;
struct parm n2; struct parm n2;
struct parm en;
struct parm ssen; struct parm ssen;
struct parm misc;
spinlock_t *lock; spinlock_t *lock;
}; };
struct meson_clk_audio_divider { struct meson_clk_audio_div_data {
struct clk_hw hw;
void __iomem *base;
struct parm div; struct parm div;
u8 flags; u8 flags;
spinlock_t *lock;
}; };
#define MESON_GATE(_name, _reg, _bit) \ #define MESON_GATE(_name, _reg, _bit) \
struct clk_gate _name = { \ struct clk_regmap _name = { \
.reg = (void __iomem *) _reg, \ .data = &(struct clk_regmap_gate_data){ \
.offset = (_reg), \
.bit_idx = (_bit), \ .bit_idx = (_bit), \
.lock = &meson_clk_lock, \ }, \
.hw.init = &(struct clk_init_data) { \ .hw.init = &(struct clk_init_data) { \
.name = #_name, \ .name = #_name, \
.ops = &clk_gate_ops, \ .ops = &clk_regmap_gate_ops, \
.parent_names = (const char *[]){ "clk81" }, \ .parent_names = (const char *[]){ "clk81" }, \
.num_parents = 1, \ .num_parents = 1, \
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
......
/*
* Copyright (c) 2017 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/clk-provider.h>
#include <linux/bitfield.h>
#include <linux/regmap.h>
#include "gxbb-aoclk.h"
static int aoclk_gate_regmap_enable(struct clk_hw *hw)
{
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
BIT(gate->bit_idx), BIT(gate->bit_idx));
}
static void aoclk_gate_regmap_disable(struct clk_hw *hw)
{
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
BIT(gate->bit_idx), 0);
}
static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw)
{
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
unsigned int val;
int ret;
ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val);
if (ret)
return ret;
return (val & BIT(gate->bit_idx)) != 0;
}
const struct clk_ops meson_aoclk_gate_regmap_ops = {
.enable = aoclk_gate_regmap_enable,
.disable = aoclk_gate_regmap_disable,
.is_enabled = aoclk_gate_regmap_is_enabled,
};
...@@ -62,10 +62,9 @@ ...@@ -62,10 +62,9 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <dt-bindings/clock/gxbb-aoclkc.h> #include <dt-bindings/clock/gxbb-aoclkc.h>
#include <dt-bindings/reset/gxbb-aoclkc.h> #include <dt-bindings/reset/gxbb-aoclkc.h>
#include "clk-regmap.h"
#include "gxbb-aoclk.h" #include "gxbb-aoclk.h"
static DEFINE_SPINLOCK(gxbb_aoclk_lock);
struct gxbb_aoclk_reset_controller { struct gxbb_aoclk_reset_controller {
struct reset_controller_dev reset; struct reset_controller_dev reset;
unsigned int *data; unsigned int *data;
...@@ -87,12 +86,14 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = { ...@@ -87,12 +86,14 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = {
}; };
#define GXBB_AO_GATE(_name, _bit) \ #define GXBB_AO_GATE(_name, _bit) \
static struct aoclk_gate_regmap _name##_ao = { \ static struct clk_regmap _name##_ao = { \
.data = &(struct clk_regmap_gate_data) { \
.offset = AO_RTI_GEN_CNTL_REG0, \
.bit_idx = (_bit), \ .bit_idx = (_bit), \
.lock = &gxbb_aoclk_lock, \ }, \
.hw.init = &(struct clk_init_data) { \ .hw.init = &(struct clk_init_data) { \
.name = #_name "_ao", \ .name = #_name "_ao", \
.ops = &meson_aoclk_gate_regmap_ops, \ .ops = &clk_regmap_gate_ops, \
.parent_names = (const char *[]){ "clk81" }, \ .parent_names = (const char *[]){ "clk81" }, \
.num_parents = 1, \ .num_parents = 1, \
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
...@@ -107,7 +108,6 @@ GXBB_AO_GATE(uart2, 5); ...@@ -107,7 +108,6 @@ GXBB_AO_GATE(uart2, 5);
GXBB_AO_GATE(ir_blaster, 6); GXBB_AO_GATE(ir_blaster, 6);
static struct aoclk_cec_32k cec_32k_ao = { static struct aoclk_cec_32k cec_32k_ao = {
.lock = &gxbb_aoclk_lock,
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "cec_32k_ao", .name = "cec_32k_ao",
.ops = &meson_aoclk_cec_32k_ops, .ops = &meson_aoclk_cec_32k_ops,
...@@ -126,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = { ...@@ -126,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = {
[RESET_AO_IR_BLASTER] = 23, [RESET_AO_IR_BLASTER] = 23,
}; };
static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = { static struct clk_regmap *gxbb_aoclk_gate[] = {
[CLKID_AO_REMOTE] = &remote_ao, [CLKID_AO_REMOTE] = &remote_ao,
[CLKID_AO_I2C_MASTER] = &i2c_master_ao, [CLKID_AO_I2C_MASTER] = &i2c_master_ao,
[CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao,
...@@ -177,7 +177,7 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) ...@@ -177,7 +177,7 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
* Populate regmap and register all clks * Populate regmap and register all clks
*/ */
for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) { for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) {
gxbb_aoclk_gate[clkid]->regmap = regmap; gxbb_aoclk_gate[clkid]->map = regmap;
ret = devm_clk_hw_register(dev, ret = devm_clk_hw_register(dev,
gxbb_aoclk_onecell_data.hws[clkid]); gxbb_aoclk_onecell_data.hws[clkid]);
......
...@@ -17,22 +17,11 @@ ...@@ -17,22 +17,11 @@
#define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL0 0x94
#define AO_RTC_ALT_CLK_CNTL1 0x98 #define AO_RTC_ALT_CLK_CNTL1 0x98
struct aoclk_gate_regmap {
struct clk_hw hw;
unsigned bit_idx;
struct regmap *regmap;
spinlock_t *lock;
};
#define to_aoclk_gate_regmap(_hw) \
container_of(_hw, struct aoclk_gate_regmap, hw)
extern const struct clk_ops meson_aoclk_gate_regmap_ops; extern const struct clk_ops meson_aoclk_gate_regmap_ops;
struct aoclk_cec_32k { struct aoclk_cec_32k {
struct clk_hw hw; struct clk_hw hw;
struct regmap *regmap; struct regmap *regmap;
spinlock_t *lock;
}; };
#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) #define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw)
......
此差异已折叠。
...@@ -194,8 +194,18 @@ ...@@ -194,8 +194,18 @@
#define CLKID_VPU_1_DIV 130 #define CLKID_VPU_1_DIV 130
#define CLKID_VAPB_0_DIV 134 #define CLKID_VAPB_0_DIV 134
#define CLKID_VAPB_1_DIV 137 #define CLKID_VAPB_1_DIV 137
#define CLKID_HDMI_PLL_PRE_MULT 141
#define NR_CLKS 141 #define CLKID_MPLL0_DIV 142
#define CLKID_MPLL1_DIV 143
#define CLKID_MPLL2_DIV 144
#define CLKID_MPLL_PREDIV 145
#define CLKID_FCLK_DIV2_DIV 146
#define CLKID_FCLK_DIV3_DIV 147
#define CLKID_FCLK_DIV4_DIV 148
#define CLKID_FCLK_DIV5_DIV 149
#define CLKID_FCLK_DIV7_DIV 150
#define NR_CLKS 151
/* include the CLKIDs that have been made part of the DT binding */ /* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h> #include <dt-bindings/clock/gxbb-clkc.h>
......
此差异已折叠。
...@@ -69,7 +69,22 @@ ...@@ -69,7 +69,22 @@
* will remain defined here. * will remain defined here.
*/ */
#define CLK_NR_CLKS 96 #define CLKID_MPLL0_DIV 96
#define CLKID_MPLL1_DIV 97
#define CLKID_MPLL2_DIV 98
#define CLKID_CPU_IN_SEL 99
#define CLKID_CPU_DIV2 100
#define CLKID_CPU_DIV3 101
#define CLKID_CPU_SCALE_DIV 102
#define CLKID_CPU_SCALE_OUT_SEL 103
#define CLKID_MPLL_PREDIV 104
#define CLKID_FCLK_DIV2_DIV 105
#define CLKID_FCLK_DIV3_DIV 106
#define CLKID_FCLK_DIV4_DIV 107
#define CLKID_FCLK_DIV5_DIV 108
#define CLKID_FCLK_DIV7_DIV 109
#define CLK_NR_CLKS 110
/* /*
* include the CLKID and RESETID that have * include the CLKID and RESETID that have
......
...@@ -28,22 +28,14 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, ...@@ -28,22 +28,14 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate,
{ {
struct clk_regmap_div *divider = to_clk_regmap_div(hw); struct clk_regmap_div *divider = to_clk_regmap_div(hw);
struct clk_regmap *clkr = &divider->clkr; struct clk_regmap *clkr = &divider->clkr;
u32 div; u32 val;
struct clk_hw *hw_parent = clk_hw_get_parent(hw);
regmap_read(clkr->regmap, divider->reg, &div);
div >>= divider->shift;
div &= BIT(divider->width) - 1;
div += 1;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
if (!hw_parent)
return -EINVAL;
*prate = clk_hw_round_rate(hw_parent, rate * div); regmap_read(clkr->regmap, divider->reg, &val);
} val >>= divider->shift;
val &= BIT(divider->width) - 1;
return DIV_ROUND_UP_ULL((u64)*prate, div); return divider_ro_round_rate(hw, rate, prate, NULL, divider->width,
CLK_DIVIDER_ROUND_CLOSEST, val);
} }
static long div_round_rate(struct clk_hw *hw, unsigned long rate, static long div_round_rate(struct clk_hw *hw, unsigned long rate,
......
...@@ -8,9 +8,11 @@ obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o ...@@ -8,9 +8,11 @@ obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.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_EXYNOS5260) += clk-exynos5260.o
obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
......
...@@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) ...@@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(dev, res); reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(reg_base)) { if (IS_ERR(reg_base))
dev_err(dev, "failed to map audss registers\n");
return PTR_ERR(reg_base); return PTR_ERR(reg_base);
}
epll = ERR_PTR(-ENODEV); epll = ERR_PTR(-ENODEV);
......
...@@ -670,73 +670,73 @@ static const struct samsung_gate_clock gate_clks[] __initconst = { ...@@ -670,73 +670,73 @@ static const struct samsung_gate_clock gate_clks[] __initconst = {
/* APLL & MPLL & BPLL & UPLL */ /* APLL & MPLL & BPLL & UPLL */
static const struct samsung_pll_rate_table exynos3250_pll_rates[] __initconst = { static const struct samsung_pll_rate_table exynos3250_pll_rates[] __initconst = {
PLL_35XX_RATE(1200000000, 400, 4, 1), PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1),
PLL_35XX_RATE(1100000000, 275, 3, 1), PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1),
PLL_35XX_RATE(1066000000, 533, 6, 1), PLL_35XX_RATE(24 * MHZ, 1066000000, 533, 6, 1),
PLL_35XX_RATE(1000000000, 250, 3, 1), PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1),
PLL_35XX_RATE( 960000000, 320, 4, 1), PLL_35XX_RATE(24 * MHZ, 960000000, 320, 4, 1),
PLL_35XX_RATE( 900000000, 300, 4, 1), PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1),
PLL_35XX_RATE( 850000000, 425, 6, 1), PLL_35XX_RATE(24 * MHZ, 850000000, 425, 6, 1),
PLL_35XX_RATE( 800000000, 200, 3, 1), PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1),
PLL_35XX_RATE( 700000000, 175, 3, 1), PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1),
PLL_35XX_RATE( 667000000, 667, 12, 1), PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1),
PLL_35XX_RATE( 600000000, 400, 4, 2), PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2),
PLL_35XX_RATE( 533000000, 533, 6, 2), PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2),
PLL_35XX_RATE( 520000000, 260, 3, 2), PLL_35XX_RATE(24 * MHZ, 520000000, 260, 3, 2),
PLL_35XX_RATE( 500000000, 250, 3, 2), PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2),
PLL_35XX_RATE( 400000000, 200, 3, 2), PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2),
PLL_35XX_RATE( 200000000, 200, 3, 3), PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3),
PLL_35XX_RATE( 100000000, 200, 3, 4), PLL_35XX_RATE(24 * MHZ, 100000000, 200, 3, 4),
{ /* sentinel */ } { /* sentinel */ }
}; };
/* EPLL */ /* EPLL */
static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = { static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = {
PLL_36XX_RATE(800000000, 200, 3, 1, 0), PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0),
PLL_36XX_RATE(288000000, 96, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 288000000, 96, 2, 2, 0),
PLL_36XX_RATE(192000000, 128, 2, 3, 0), PLL_36XX_RATE(24 * MHZ, 192000000, 128, 2, 3, 0),
PLL_36XX_RATE(144000000, 96, 2, 3, 0), PLL_36XX_RATE(24 * MHZ, 144000000, 96, 2, 3, 0),
PLL_36XX_RATE( 96000000, 128, 2, 4, 0), PLL_36XX_RATE(24 * MHZ, 96000000, 128, 2, 4, 0),
PLL_36XX_RATE( 84000000, 112, 2, 4, 0), PLL_36XX_RATE(24 * MHZ, 84000000, 112, 2, 4, 0),
PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), PLL_36XX_RATE(24 * MHZ, 80000003, 106, 2, 4, 43691),
PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923),
PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), PLL_36XX_RATE(24 * MHZ, 67737598, 270, 3, 5, 62285),
PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), PLL_36XX_RATE(24 * MHZ, 65535999, 174, 2, 5, 49982),
PLL_36XX_RATE( 50000000, 200, 3, 5, 0), PLL_36XX_RATE(24 * MHZ, 50000000, 200, 3, 5, 0),
PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), PLL_36XX_RATE(24 * MHZ, 49152002, 131, 2, 5, 4719),
PLL_36XX_RATE( 48000000, 128, 2, 5, 0), PLL_36XX_RATE(24 * MHZ, 48000000, 128, 2, 5, 0),
PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), PLL_36XX_RATE(24 * MHZ, 45158401, 180, 3, 5, 41524),
{ /* sentinel */ } { /* sentinel */ }
}; };
/* VPLL */ /* VPLL */
static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = { static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = {
PLL_36XX_RATE(600000000, 100, 2, 1, 0), PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0),
PLL_36XX_RATE(533000000, 266, 3, 2, 32768), PLL_36XX_RATE(24 * MHZ, 533000000, 266, 3, 2, 32768),
PLL_36XX_RATE(519230987, 173, 2, 2, 5046), PLL_36XX_RATE(24 * MHZ, 519230987, 173, 2, 2, 5046),
PLL_36XX_RATE(500000000, 250, 3, 2, 0), PLL_36XX_RATE(24 * MHZ, 500000000, 250, 3, 2, 0),
PLL_36XX_RATE(445500000, 148, 2, 2, 32768), PLL_36XX_RATE(24 * MHZ, 445500000, 148, 2, 2, 32768),
PLL_36XX_RATE(445055007, 148, 2, 2, 23047), PLL_36XX_RATE(24 * MHZ, 445055007, 148, 2, 2, 23047),
PLL_36XX_RATE(400000000, 200, 3, 2, 0), PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0),
PLL_36XX_RATE(371250000, 123, 2, 2, 49152), PLL_36XX_RATE(24 * MHZ, 371250000, 123, 2, 2, 49152),
PLL_36XX_RATE(370878997, 185, 3, 2, 28803), PLL_36XX_RATE(24 * MHZ, 370878997, 185, 3, 2, 28803),
PLL_36XX_RATE(340000000, 170, 3, 2, 0), PLL_36XX_RATE(24 * MHZ, 340000000, 170, 3, 2, 0),
PLL_36XX_RATE(335000015, 111, 2, 2, 43691), PLL_36XX_RATE(24 * MHZ, 335000015, 111, 2, 2, 43691),
PLL_36XX_RATE(333000000, 111, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0),
PLL_36XX_RATE(330000000, 110, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 330000000, 110, 2, 2, 0),
PLL_36XX_RATE(320000015, 106, 2, 2, 43691), PLL_36XX_RATE(24 * MHZ, 320000015, 106, 2, 2, 43691),
PLL_36XX_RATE(300000000, 100, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0),
PLL_36XX_RATE(275000000, 275, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 275000000, 275, 3, 3, 0),
PLL_36XX_RATE(222750000, 148, 2, 3, 32768), PLL_36XX_RATE(24 * MHZ, 222750000, 148, 2, 3, 32768),
PLL_36XX_RATE(222528007, 148, 2, 3, 23069), PLL_36XX_RATE(24 * MHZ, 222528007, 148, 2, 3, 23069),
PLL_36XX_RATE(160000000, 160, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0),
PLL_36XX_RATE(148500000, 99, 2, 3, 0), PLL_36XX_RATE(24 * MHZ, 148500000, 99, 2, 3, 0),
PLL_36XX_RATE(148352005, 98, 2, 3, 59070), PLL_36XX_RATE(24 * MHZ, 148352005, 98, 2, 3, 59070),
PLL_36XX_RATE(108000000, 144, 2, 4, 0), PLL_36XX_RATE(24 * MHZ, 108000000, 144, 2, 4, 0),
PLL_36XX_RATE( 74250000, 99, 2, 4, 0), PLL_36XX_RATE(24 * MHZ, 74250000, 99, 2, 4, 0),
PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), PLL_36XX_RATE(24 * MHZ, 74176002, 98, 2, 4, 59070),
PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), PLL_36XX_RATE(24 * MHZ, 54054000, 216, 3, 5, 14156),
PLL_36XX_RATE( 54000000, 144, 2, 5, 0), PLL_36XX_RATE(24 * MHZ, 54000000, 144, 2, 5, 0),
{ /* sentinel */ } { /* sentinel */ }
}; };
......
此差异已折叠。
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __CLK_EXYNOS5_SUBCMU_H
#define __CLK_EXYNOS5_SUBCMU_H
struct exynos5_subcmu_reg_dump {
u32 offset;
u32 value;
u32 mask;
u32 save;
};
struct exynos5_subcmu_info {
const struct samsung_div_clock *div_clks;
unsigned int nr_div_clks;
const struct samsung_gate_clock *gate_clks;
unsigned int nr_gate_clks;
struct exynos5_subcmu_reg_dump *suspend_regs;
unsigned int nr_suspend_regs;
const char *pd_name;
};
void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus,
const struct exynos5_subcmu_info *cmu);
#endif
...@@ -226,16 +226,16 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { ...@@ -226,16 +226,16 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = {
}; };
static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = { static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = {
PLL_36XX_RATE(400000000U, 200, 3, 2, 0), PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0),
PLL_36XX_RATE(333000000U, 111, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 333000000U, 111, 2, 2, 0),
PLL_36XX_RATE(300000000U, 100, 2, 2, 0), PLL_36XX_RATE(24 * MHZ, 300000000U, 100, 2, 2, 0),
PLL_36XX_RATE(266000000U, 266, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 266000000U, 266, 3, 3, 0),
PLL_36XX_RATE(200000000U, 200, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0),
PLL_36XX_RATE(192000000U, 192, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 192000000U, 192, 3, 3, 0),
PLL_36XX_RATE(166000000U, 166, 3, 3, 0), PLL_36XX_RATE(24 * MHZ, 166000000U, 166, 3, 3, 0),
PLL_36XX_RATE(133000000U, 266, 3, 4, 0), PLL_36XX_RATE(24 * MHZ, 133000000U, 266, 3, 4, 0),
PLL_36XX_RATE(100000000U, 200, 3, 4, 0), PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0),
PLL_36XX_RATE(66000000U, 176, 2, 5, 0), PLL_36XX_RATE(24 * MHZ, 66000000U, 176, 2, 5, 0),
}; };
static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = { static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = {
......
...@@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { ...@@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = {
}; };
static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = {
PLL_36XX_RATE(491520000, 20, 1, 0, 31457), PLL_36XX_RATE(24 * MHZ, 491519897, 20, 1, 0, 31457),
{}, {},
}; };
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -56,11 +56,6 @@ ...@@ -56,11 +56,6 @@
#define GATE_ON(_id, cname, pname, o, b) \ #define GATE_ON(_id, cname, pname, o, b) \
GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0) GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0)
/* list of PLLs to be registered */
enum s3c64xx_plls {
apll, mpll, epll,
};
static void __iomem *reg_base; static void __iomem *reg_base;
static bool is_s3c6400; static bool is_s3c6400;
...@@ -364,11 +359,11 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = { ...@@ -364,11 +359,11 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = {
/* List of PLL clocks. */ /* List of PLL clocks. */
static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = { static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = {
[apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll",
APLL_LOCK, APLL_CON, NULL), APLL_LOCK, APLL_CON, NULL),
[mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll",
MPLL_LOCK, MPLL_CON, NULL), MPLL_LOCK, MPLL_CON, NULL),
[epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll",
EPLL_LOCK, EPLL_CON0, NULL), EPLL_LOCK, EPLL_CON0, NULL),
}; };
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册