Commit 186dcd4a authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'clk-for-v4.17-1' of https://github.com/BayLibre/clk-meson into clk-amlogic

Pull amlogic clk driver updates from Neil Armstrong:

 - pll fixes for GXBB, GXL and AXG
 - use regmap in clock controllers for GXBB, GXL and AXG
 - general clock updates for Meson8, GXBB, GXL and AXG

(Based on the clk-helpers topic branch as a dependency)

* tag 'clk-for-v4.17-1' of https://github.com/BayLibre/clk-meson: (49 commits)
  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: meson: migrate muxes to clk_regmap
  ...
parents 7928b2cb 5b13ef64
...@@ -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
...@@ -11,109 +11,20 @@ ...@@ -11,109 +11,20 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/init.h> #include <linux/regmap.h>
#include "clkc.h" #include "clkc.h"
#include "axg.h" #include "axg.h"
static DEFINE_SPINLOCK(meson_clk_lock); static DEFINE_SPINLOCK(meson_clk_lock);
static const struct pll_rate_table sys_pll_rate_table[] = { static struct clk_regmap axg_fixed_pll = {
PLL_RATE(24000000, 56, 1, 2), .data = &(struct meson_clk_pll_data){
PLL_RATE(48000000, 64, 1, 2),
PLL_RATE(72000000, 72, 1, 2),
PLL_RATE(96000000, 64, 1, 2),
PLL_RATE(120000000, 80, 1, 2),
PLL_RATE(144000000, 96, 1, 2),
PLL_RATE(168000000, 56, 1, 1),
PLL_RATE(192000000, 64, 1, 1),
PLL_RATE(216000000, 72, 1, 1),
PLL_RATE(240000000, 80, 1, 1),
PLL_RATE(264000000, 88, 1, 1),
PLL_RATE(288000000, 96, 1, 1),
PLL_RATE(312000000, 52, 1, 2),
PLL_RATE(336000000, 56, 1, 2),
PLL_RATE(360000000, 60, 1, 2),
PLL_RATE(384000000, 64, 1, 2),
PLL_RATE(408000000, 68, 1, 2),
PLL_RATE(432000000, 72, 1, 2),
PLL_RATE(456000000, 76, 1, 2),
PLL_RATE(480000000, 80, 1, 2),
PLL_RATE(504000000, 84, 1, 2),
PLL_RATE(528000000, 88, 1, 2),
PLL_RATE(552000000, 92, 1, 2),
PLL_RATE(576000000, 96, 1, 2),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(768000000, 64, 1, 1),
PLL_RATE(792000000, 66, 1, 1),
PLL_RATE(816000000, 68, 1, 1),
PLL_RATE(840000000, 70, 1, 1),
PLL_RATE(864000000, 72, 1, 1),
PLL_RATE(888000000, 74, 1, 1),
PLL_RATE(912000000, 76, 1, 1),
PLL_RATE(936000000, 78, 1, 1),
PLL_RATE(960000000, 80, 1, 1),
PLL_RATE(984000000, 82, 1, 1),
PLL_RATE(1008000000, 84, 1, 1),
PLL_RATE(1032000000, 86, 1, 1),
PLL_RATE(1056000000, 88, 1, 1),
PLL_RATE(1080000000, 90, 1, 1),
PLL_RATE(1104000000, 92, 1, 1),
PLL_RATE(1128000000, 94, 1, 1),
PLL_RATE(1152000000, 96, 1, 1),
PLL_RATE(1176000000, 98, 1, 1),
PLL_RATE(1200000000, 50, 1, 0),
PLL_RATE(1224000000, 51, 1, 0),
PLL_RATE(1248000000, 52, 1, 0),
PLL_RATE(1272000000, 53, 1, 0),
PLL_RATE(1296000000, 54, 1, 0),
PLL_RATE(1320000000, 55, 1, 0),
PLL_RATE(1344000000, 56, 1, 0),
PLL_RATE(1368000000, 57, 1, 0),
PLL_RATE(1392000000, 58, 1, 0),
PLL_RATE(1416000000, 59, 1, 0),
PLL_RATE(1440000000, 60, 1, 0),
PLL_RATE(1464000000, 61, 1, 0),
PLL_RATE(1488000000, 62, 1, 0),
PLL_RATE(1512000000, 63, 1, 0),
PLL_RATE(1536000000, 64, 1, 0),
PLL_RATE(1560000000, 65, 1, 0),
PLL_RATE(1584000000, 66, 1, 0),
PLL_RATE(1608000000, 67, 1, 0),
PLL_RATE(1632000000, 68, 1, 0),
PLL_RATE(1656000000, 68, 1, 0),
PLL_RATE(1680000000, 68, 1, 0),
PLL_RATE(1704000000, 68, 1, 0),
PLL_RATE(1728000000, 69, 1, 0),
PLL_RATE(1752000000, 69, 1, 0),
PLL_RATE(1776000000, 69, 1, 0),
PLL_RATE(1800000000, 69, 1, 0),
PLL_RATE(1824000000, 70, 1, 0),
PLL_RATE(1848000000, 70, 1, 0),
PLL_RATE(1872000000, 70, 1, 0),
PLL_RATE(1896000000, 70, 1, 0),
PLL_RATE(1920000000, 71, 1, 0),
PLL_RATE(1944000000, 71, 1, 0),
PLL_RATE(1968000000, 71, 1, 0),
PLL_RATE(1992000000, 71, 1, 0),
PLL_RATE(2016000000, 72, 1, 0),
PLL_RATE(2040000000, 72, 1, 0),
PLL_RATE(2064000000, 72, 1, 0),
PLL_RATE(2088000000, 72, 1, 0),
PLL_RATE(2112000000, 73, 1, 0),
{ /* sentinel */ },
};
static struct meson_clk_pll axg_fixed_pll = {
.m = { .m = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 0, .shift = 0,
...@@ -129,7 +40,22 @@ static struct meson_clk_pll axg_fixed_pll = { ...@@ -129,7 +40,22 @@ static struct meson_clk_pll axg_fixed_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.lock = &meson_clk_lock, .frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fixed_pll", .name = "fixed_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -138,7 +64,8 @@ static struct meson_clk_pll axg_fixed_pll = { ...@@ -138,7 +64,8 @@ static struct meson_clk_pll axg_fixed_pll = {
}, },
}; };
static struct meson_clk_pll axg_sys_pll = { static struct clk_regmap axg_sys_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_SYS_PLL_CNTL, .reg_off = HHI_SYS_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -151,12 +78,20 @@ static struct meson_clk_pll axg_sys_pll = { ...@@ -151,12 +78,20 @@ static struct meson_clk_pll axg_sys_pll = {
}, },
.od = { .od = {
.reg_off = HHI_SYS_PLL_CNTL, .reg_off = HHI_SYS_PLL_CNTL,
.shift = 10, .shift = 16,
.width = 2, .width = 2,
}, },
.rate_table = sys_pll_rate_table, .l = {
.rate_count = ARRAY_SIZE(sys_pll_rate_table), .reg_off = HHI_SYS_PLL_CNTL,
.lock = &meson_clk_lock, .shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sys_pll", .name = "sys_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -257,16 +192,17 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { ...@@ -257,16 +192,17 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
static struct pll_params_table axg_gp0_params_table[] = { const struct reg_sequence axg_gp0_init_regs[] = {
PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 },
PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be },
PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
}; };
static struct meson_clk_pll axg_gp0_pll = { static struct clk_regmap axg_gp0_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_GP0_PLL_CNTL, .reg_off = HHI_GP0_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -282,15 +218,25 @@ static struct meson_clk_pll axg_gp0_pll = { ...@@ -282,15 +218,25 @@ static struct meson_clk_pll axg_gp0_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.params = { .frac = {
.params_table = axg_gp0_params_table, .reg_off = HHI_GP0_PLL_CNTL1,
.params_count = ARRAY_SIZE(axg_gp0_params_table), .shift = 0,
.no_init_reset = true, .width = 10,
.reset_lock_loop = true, },
.l = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = axg_gp0_pll_rate_table,
.init_regs = axg_gp0_init_regs,
.init_count = ARRAY_SIZE(axg_gp0_init_regs),
}, },
.rate_table = axg_gp0_pll_rate_table,
.rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table),
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gp0_pll", .name = "gp0_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ops,
...@@ -299,63 +245,196 @@ static struct meson_clk_pll axg_gp0_pll = { ...@@ -299,63 +245,196 @@ static struct meson_clk_pll axg_gp0_pll = {
}, },
}; };
const struct reg_sequence axg_hifi_init_regs[] = {
{ .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 },
{ .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 },
{ .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 },
{ .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 },
};
static struct clk_fixed_factor axg_fclk_div2 = { static struct clk_regmap axg_hifi_pll = {
.data = &(struct meson_clk_pll_data){
.m = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_HIFI_PLL_CNTL5,
.shift = 0,
.width = 13,
},
.l = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = axg_gp0_pll_rate_table,
.init_regs = axg_hifi_init_regs,
.init_count = ARRAY_SIZE(axg_hifi_init_regs),
.flags = CLK_MESON_PLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "hifi_pll",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_fixed_factor axg_fclk_div2_div = {
.mult = 1, .mult = 1,
.div = 2, .div = 2,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div2", .name = "fclk_div2_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor axg_fclk_div3 = { static struct clk_regmap axg_fclk_div2 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 27,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div2_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor axg_fclk_div3_div = {
.mult = 1, .mult = 1,
.div = 3, .div = 3,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div3", .name = "fclk_div3_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor axg_fclk_div4 = { static struct clk_regmap axg_fclk_div3 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 28,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div3",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor axg_fclk_div4_div = {
.mult = 1, .mult = 1,
.div = 4, .div = 4,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div4", .name = "fclk_div4_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor axg_fclk_div5 = { static struct clk_regmap axg_fclk_div4 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 29,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div4",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div4_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor axg_fclk_div5_div = {
.mult = 1, .mult = 1,
.div = 5, .div = 5,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div5", .name = "fclk_div5_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor axg_fclk_div7 = { static struct clk_regmap axg_fclk_div5 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 30,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div5",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div5_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor axg_fclk_div7_div = {
.mult = 1, .mult = 1,
.div = 7, .div = 7,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div7", .name = "fclk_div7_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll axg_mpll0 = { static struct clk_regmap axg_fclk_div7 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 31,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div7",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div7_div" },
.num_parents = 1,
},
};
static struct clk_regmap axg_mpll_prediv = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL5,
.shift = 12,
.width = 1,
},
.hw.init = &(struct clk_init_data){
.name = "mpll_prediv",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
static struct clk_regmap axg_mpll0_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL7, .reg_off = HHI_MPLL_CNTL7,
.shift = 0, .shift = 0,
...@@ -371,26 +450,42 @@ static struct meson_clk_mpll axg_mpll0 = { ...@@ -371,26 +450,42 @@ static struct meson_clk_mpll axg_mpll0 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 14,
.width = 1,
},
.ssen = { .ssen = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 25, .shift = 25,
.width = 1, .width = 1,
}, },
.misc = {
.reg_off = HHI_PLL_TOP_MISC,
.shift = 0,
.width = 1,
},
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll0", .name = "mpll0_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1,
},
};
static struct clk_regmap axg_mpll0 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL7,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll0",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct meson_clk_mpll axg_mpll1 = { static struct clk_regmap axg_mpll1_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL8, .reg_off = HHI_MPLL_CNTL8,
.shift = 0, .shift = 0,
...@@ -406,21 +501,37 @@ static struct meson_clk_mpll axg_mpll1 = { ...@@ -406,21 +501,37 @@ static struct meson_clk_mpll axg_mpll1 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = { .misc = {
.reg_off = HHI_MPLL_CNTL8, .reg_off = HHI_PLL_TOP_MISC,
.shift = 14, .shift = 1,
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll1", .name = "mpll1_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll axg_mpll2 = { static struct clk_regmap axg_mpll1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL8,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll1_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_mpll2_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL9, .reg_off = HHI_MPLL_CNTL9,
.shift = 0, .shift = 0,
...@@ -436,21 +547,37 @@ static struct meson_clk_mpll axg_mpll2 = { ...@@ -436,21 +547,37 @@ static struct meson_clk_mpll axg_mpll2 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = { .misc = {
.reg_off = HHI_MPLL_CNTL9, .reg_off = HHI_PLL_TOP_MISC,
.shift = 14, .shift = 2,
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll2", .name = "mpll2_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1,
},
};
static struct clk_regmap axg_mpll2 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL9,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll2_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct meson_clk_mpll axg_mpll3 = { static struct clk_regmap axg_mpll3_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL3_CNTL0, .reg_off = HHI_MPLL3_CNTL0,
.shift = 12, .shift = 12,
...@@ -466,67 +593,79 @@ static struct meson_clk_mpll axg_mpll3 = { ...@@ -466,67 +593,79 @@ static struct meson_clk_mpll axg_mpll3 = {
.shift = 2, .shift = 2,
.width = 9, .width = 9,
}, },
.en = { .misc = {
.reg_off = HHI_MPLL3_CNTL0, .reg_off = HHI_PLL_TOP_MISC,
.shift = 0, .shift = 3,
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll3", .name = "mpll3_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
/* static struct clk_regmap axg_mpll3 = {
* FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers .data = &(struct clk_regmap_gate_data){
* and should be modeled with their respective PLLs via the forthcoming .offset = HHI_MPLL3_CNTL0,
* coordinated clock rates feature .bit_idx = 0,
*/ },
.hw.init = &(struct clk_init_data){
.name = "mpll3",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll3_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 };
static const char * const clk81_parent_names[] = { static const char * const clk81_parent_names[] = {
"xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
"fclk_div3", "fclk_div5" "fclk_div3", "fclk_div5"
}; };
static struct clk_mux axg_mpeg_clk_sel = { static struct clk_regmap axg_mpeg_clk_sel = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_MPEG_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 12, .shift = 12,
.flags = CLK_MUX_READ_ONLY,
.table = mux_table_clk81, .table = mux_table_clk81,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_sel", .name = "mpeg_clk_sel",
.ops = &clk_mux_ro_ops, .ops = &clk_regmap_mux_ro_ops,
.parent_names = clk81_parent_names, .parent_names = clk81_parent_names,
.num_parents = ARRAY_SIZE(clk81_parent_names), .num_parents = ARRAY_SIZE(clk81_parent_names),
}, },
}; };
static struct clk_divider axg_mpeg_clk_div = { static struct clk_regmap axg_mpeg_clk_div = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_MPEG_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_div", .name = "mpeg_clk_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "mpeg_clk_sel" }, .parent_names = (const char *[]){ "mpeg_clk_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate axg_clk81 = { static struct clk_regmap axg_clk81 = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_MPEG_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "clk81", .name = "clk81",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpeg_clk_div" }, .parent_names = (const char *[]){ "mpeg_clk_div" },
.num_parents = 1, .num_parents = 1,
.flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL),
...@@ -545,42 +684,45 @@ static const char * const axg_sd_emmc_clk0_parent_names[] = { ...@@ -545,42 +684,45 @@ static const char * const axg_sd_emmc_clk0_parent_names[] = {
}; };
/* SDcard clock */ /* SDcard clock */
static struct clk_mux axg_sd_emmc_b_clk0_sel = { static struct clk_regmap axg_sd_emmc_b_clk0_sel = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 25, .shift = 25,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_b_clk0_sel", .name = "sd_emmc_b_clk0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = axg_sd_emmc_clk0_parent_names, .parent_names = axg_sd_emmc_clk0_parent_names,
.num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names),
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider axg_sd_emmc_b_clk0_div = { static struct clk_regmap axg_sd_emmc_b_clk0_div = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.shift = 16, .shift = 16,
.width = 7, .width = 7,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_b_clk0_div", .name = "sd_emmc_b_clk0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate axg_sd_emmc_b_clk0 = { static struct clk_regmap axg_sd_emmc_b_clk0 = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.bit_idx = 23, .bit_idx = 23,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sd_emmc_b_clk0", .name = "sd_emmc_b_clk0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -588,42 +730,45 @@ static struct clk_gate axg_sd_emmc_b_clk0 = { ...@@ -588,42 +730,45 @@ static struct clk_gate axg_sd_emmc_b_clk0 = {
}; };
/* EMMC/NAND clock */ /* EMMC/NAND clock */
static struct clk_mux axg_sd_emmc_c_clk0_sel = { static struct clk_regmap axg_sd_emmc_c_clk0_sel = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_NAND_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_c_clk0_sel", .name = "sd_emmc_c_clk0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = axg_sd_emmc_clk0_parent_names, .parent_names = axg_sd_emmc_clk0_parent_names,
.num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names),
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider axg_sd_emmc_c_clk0_div = { static struct clk_regmap axg_sd_emmc_c_clk0_div = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_NAND_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_c_clk0_div", .name = "sd_emmc_c_clk0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate axg_sd_emmc_c_clk0 = { static struct clk_regmap axg_sd_emmc_c_clk0 = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_NAND_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sd_emmc_c_clk0", .name = "sd_emmc_c_clk0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -750,27 +895,24 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { ...@@ -750,27 +895,24 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
[CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw,
[CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw,
[CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw, [CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw,
[CLKID_MPLL0_DIV] = &axg_mpll0_div.hw,
[CLKID_MPLL1_DIV] = &axg_mpll1_div.hw,
[CLKID_MPLL2_DIV] = &axg_mpll2_div.hw,
[CLKID_MPLL3_DIV] = &axg_mpll3_div.hw,
[CLKID_HIFI_PLL] = &axg_hifi_pll.hw,
[CLKID_MPLL_PREDIV] = &axg_mpll_prediv.hw,
[CLKID_FCLK_DIV2_DIV] = &axg_fclk_div2_div.hw,
[CLKID_FCLK_DIV3_DIV] = &axg_fclk_div3_div.hw,
[CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw,
[NR_CLKS] = NULL, [NR_CLKS] = NULL,
}, },
.num = NR_CLKS, .num = NR_CLKS,
}; };
/* Convenience tables to populate base addresses in .probe */ /* Convenience table to populate regmap in .probe */
static struct clk_regmap *const axg_clk_regmaps[] = {
static struct meson_clk_pll *const axg_clk_plls[] = {
&axg_fixed_pll,
&axg_sys_pll,
&axg_gp0_pll,
};
static struct meson_clk_mpll *const axg_clk_mplls[] = {
&axg_mpll0,
&axg_mpll1,
&axg_mpll2,
&axg_mpll3,
};
static struct clk_gate *const axg_clk_gates[] = {
&axg_clk81, &axg_clk81,
&axg_ddr, &axg_ddr,
&axg_audio_locker, &axg_audio_locker,
...@@ -818,113 +960,100 @@ static struct clk_gate *const axg_clk_gates[] = { ...@@ -818,113 +960,100 @@ static struct clk_gate *const axg_clk_gates[] = {
&axg_ao_i2c, &axg_ao_i2c,
&axg_sd_emmc_b_clk0, &axg_sd_emmc_b_clk0,
&axg_sd_emmc_c_clk0, &axg_sd_emmc_c_clk0,
};
static struct clk_mux *const axg_clk_muxes[] = {
&axg_mpeg_clk_sel,
&axg_sd_emmc_b_clk0_sel,
&axg_sd_emmc_c_clk0_sel,
};
static struct clk_divider *const axg_clk_dividers[] = {
&axg_mpeg_clk_div, &axg_mpeg_clk_div,
&axg_sd_emmc_b_clk0_div, &axg_sd_emmc_b_clk0_div,
&axg_sd_emmc_c_clk0_div, &axg_sd_emmc_c_clk0_div,
}; &axg_mpeg_clk_sel,
&axg_sd_emmc_b_clk0_sel,
struct clkc_data { &axg_sd_emmc_c_clk0_sel,
struct clk_gate *const *clk_gates; &axg_mpll0,
unsigned int clk_gates_count; &axg_mpll1,
struct meson_clk_mpll *const *clk_mplls; &axg_mpll2,
unsigned int clk_mplls_count; &axg_mpll3,
struct meson_clk_pll *const *clk_plls; &axg_mpll0_div,
unsigned int clk_plls_count; &axg_mpll1_div,
struct clk_mux *const *clk_muxes; &axg_mpll2_div,
unsigned int clk_muxes_count; &axg_mpll3_div,
struct clk_divider *const *clk_dividers; &axg_fixed_pll,
unsigned int clk_dividers_count; &axg_sys_pll,
struct clk_hw_onecell_data *hw_onecell_data; &axg_gp0_pll,
}; &axg_hifi_pll,
&axg_mpll_prediv,
static const struct clkc_data axg_clkc_data = { &axg_fclk_div2,
.clk_gates = axg_clk_gates, &axg_fclk_div3,
.clk_gates_count = ARRAY_SIZE(axg_clk_gates), &axg_fclk_div4,
.clk_mplls = axg_clk_mplls, &axg_fclk_div5,
.clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), &axg_fclk_div7,
.clk_plls = axg_clk_plls,
.clk_plls_count = ARRAY_SIZE(axg_clk_plls),
.clk_muxes = axg_clk_muxes,
.clk_muxes_count = ARRAY_SIZE(axg_clk_muxes),
.clk_dividers = axg_clk_dividers,
.clk_dividers_count = ARRAY_SIZE(axg_clk_dividers),
.hw_onecell_data = &axg_hw_onecell_data,
}; };
static const struct of_device_id clkc_match_table[] = { static const struct of_device_id clkc_match_table[] = {
{ .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, { .compatible = "amlogic,axg-clkc" },
{} {}
}; };
static const struct regmap_config clkc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int axg_clkc_probe(struct platform_device *pdev) static int axg_clkc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct clkc_data *clkc_data;
struct resource *res; struct resource *res;
void __iomem *clk_base; void __iomem *clk_base = NULL;
int ret, clkid, i; struct regmap *map;
int ret, i;
clkc_data = of_device_get_match_data(&pdev->dev); /* Get the hhi system controller node if available */
if (!clkc_data) map = syscon_node_to_regmap(of_get_parent(dev->of_node));
return -EINVAL; if (IS_ERR(map)) {
dev_err(dev,
"failed to get HHI regmap - Trying obsolete regs\n");
/* Generic clocks and PLLs */ /*
* FIXME: HHI registers should be accessed through
* the appropriate system controller. This is required because
* there is more than just clocks in this register space
*
* This fallback method is only provided temporarily until
* all the platform DTs are properly using the syscon node
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
return -EINVAL; return -EINVAL;
clk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
clk_base = devm_ioremap(dev, res->start, resource_size(res));
if (!clk_base) { if (!clk_base) {
dev_err(&pdev->dev, "Unable to map clk base\n"); dev_err(dev, "Unable to map clk base\n");
return -ENXIO; return -ENXIO;
} }
/* Populate base address for PLLs */ map = devm_regmap_init_mmio(dev, clk_base,
for (i = 0; i < clkc_data->clk_plls_count; i++) &clkc_regmap_config);
clkc_data->clk_plls[i]->base = clk_base; if (IS_ERR(map))
return PTR_ERR(map);
/* Populate base address for MPLLs */ }
for (i = 0; i < clkc_data->clk_mplls_count; i++)
clkc_data->clk_mplls[i]->base = clk_base;
/* Populate base address for gates */
for (i = 0; i < clkc_data->clk_gates_count; i++)
clkc_data->clk_gates[i]->reg = clk_base +
(u64)clkc_data->clk_gates[i]->reg;
/* Populate base address for muxes */
for (i = 0; i < clkc_data->clk_muxes_count; i++)
clkc_data->clk_muxes[i]->reg = clk_base +
(u64)clkc_data->clk_muxes[i]->reg;
/* Populate base address for dividers */ /* Populate regmap for the regmap backed clocks */
for (i = 0; i < clkc_data->clk_dividers_count; i++) for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++)
clkc_data->clk_dividers[i]->reg = clk_base + axg_clk_regmaps[i]->map = map;
(u64)clkc_data->clk_dividers[i]->reg;
for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { for (i = 0; i < axg_hw_onecell_data.num; i++) {
/* array might be sparse */ /* array might be sparse */
if (!clkc_data->hw_onecell_data->hws[clkid]) if (!axg_hw_onecell_data.hws[i])
continue; continue;
ret = devm_clk_hw_register(dev, ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]);
clkc_data->hw_onecell_data->hws[clkid]);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Clock registration failed\n"); dev_err(dev, "Clock registration failed\n");
return ret; return ret;
} }
} }
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clkc_data->hw_onecell_data); &axg_hw_onecell_data);
} }
static struct platform_driver axg_driver = { static struct platform_driver axg_driver = {
......
...@@ -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)
......
...@@ -19,108 +19,19 @@ ...@@ -19,108 +19,19 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/init.h> #include <linux/regmap.h>
#include "clkc.h" #include "clkc.h"
#include "gxbb.h" #include "gxbb.h"
#include "clk-regmap.h"
static DEFINE_SPINLOCK(meson_clk_lock); static DEFINE_SPINLOCK(meson_clk_lock);
static const struct pll_rate_table sys_pll_rate_table[] = {
PLL_RATE(24000000, 56, 1, 2),
PLL_RATE(48000000, 64, 1, 2),
PLL_RATE(72000000, 72, 1, 2),
PLL_RATE(96000000, 64, 1, 2),
PLL_RATE(120000000, 80, 1, 2),
PLL_RATE(144000000, 96, 1, 2),
PLL_RATE(168000000, 56, 1, 1),
PLL_RATE(192000000, 64, 1, 1),
PLL_RATE(216000000, 72, 1, 1),
PLL_RATE(240000000, 80, 1, 1),
PLL_RATE(264000000, 88, 1, 1),
PLL_RATE(288000000, 96, 1, 1),
PLL_RATE(312000000, 52, 1, 2),
PLL_RATE(336000000, 56, 1, 2),
PLL_RATE(360000000, 60, 1, 2),
PLL_RATE(384000000, 64, 1, 2),
PLL_RATE(408000000, 68, 1, 2),
PLL_RATE(432000000, 72, 1, 2),
PLL_RATE(456000000, 76, 1, 2),
PLL_RATE(480000000, 80, 1, 2),
PLL_RATE(504000000, 84, 1, 2),
PLL_RATE(528000000, 88, 1, 2),
PLL_RATE(552000000, 92, 1, 2),
PLL_RATE(576000000, 96, 1, 2),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(768000000, 64, 1, 1),
PLL_RATE(792000000, 66, 1, 1),
PLL_RATE(816000000, 68, 1, 1),
PLL_RATE(840000000, 70, 1, 1),
PLL_RATE(864000000, 72, 1, 1),
PLL_RATE(888000000, 74, 1, 1),
PLL_RATE(912000000, 76, 1, 1),
PLL_RATE(936000000, 78, 1, 1),
PLL_RATE(960000000, 80, 1, 1),
PLL_RATE(984000000, 82, 1, 1),
PLL_RATE(1008000000, 84, 1, 1),
PLL_RATE(1032000000, 86, 1, 1),
PLL_RATE(1056000000, 88, 1, 1),
PLL_RATE(1080000000, 90, 1, 1),
PLL_RATE(1104000000, 92, 1, 1),
PLL_RATE(1128000000, 94, 1, 1),
PLL_RATE(1152000000, 96, 1, 1),
PLL_RATE(1176000000, 98, 1, 1),
PLL_RATE(1200000000, 50, 1, 0),
PLL_RATE(1224000000, 51, 1, 0),
PLL_RATE(1248000000, 52, 1, 0),
PLL_RATE(1272000000, 53, 1, 0),
PLL_RATE(1296000000, 54, 1, 0),
PLL_RATE(1320000000, 55, 1, 0),
PLL_RATE(1344000000, 56, 1, 0),
PLL_RATE(1368000000, 57, 1, 0),
PLL_RATE(1392000000, 58, 1, 0),
PLL_RATE(1416000000, 59, 1, 0),
PLL_RATE(1440000000, 60, 1, 0),
PLL_RATE(1464000000, 61, 1, 0),
PLL_RATE(1488000000, 62, 1, 0),
PLL_RATE(1512000000, 63, 1, 0),
PLL_RATE(1536000000, 64, 1, 0),
PLL_RATE(1560000000, 65, 1, 0),
PLL_RATE(1584000000, 66, 1, 0),
PLL_RATE(1608000000, 67, 1, 0),
PLL_RATE(1632000000, 68, 1, 0),
PLL_RATE(1656000000, 68, 1, 0),
PLL_RATE(1680000000, 68, 1, 0),
PLL_RATE(1704000000, 68, 1, 0),
PLL_RATE(1728000000, 69, 1, 0),
PLL_RATE(1752000000, 69, 1, 0),
PLL_RATE(1776000000, 69, 1, 0),
PLL_RATE(1800000000, 69, 1, 0),
PLL_RATE(1824000000, 70, 1, 0),
PLL_RATE(1848000000, 70, 1, 0),
PLL_RATE(1872000000, 70, 1, 0),
PLL_RATE(1896000000, 70, 1, 0),
PLL_RATE(1920000000, 71, 1, 0),
PLL_RATE(1944000000, 71, 1, 0),
PLL_RATE(1968000000, 71, 1, 0),
PLL_RATE(1992000000, 71, 1, 0),
PLL_RATE(2016000000, 72, 1, 0),
PLL_RATE(2040000000, 72, 1, 0),
PLL_RATE(2064000000, 72, 1, 0),
PLL_RATE(2088000000, 72, 1, 0),
PLL_RATE(2112000000, 73, 1, 0),
{ /* sentinel */ },
};
static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = {
PLL_RATE(96000000, 32, 1, 3), PLL_RATE(96000000, 32, 1, 3),
PLL_RATE(99000000, 33, 1, 3), PLL_RATE(99000000, 33, 1, 3),
...@@ -278,7 +189,8 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { ...@@ -278,7 +189,8 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
static struct meson_clk_pll gxbb_fixed_pll = { static struct clk_regmap gxbb_fixed_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 0, .shift = 0,
...@@ -294,7 +206,22 @@ static struct meson_clk_pll gxbb_fixed_pll = { ...@@ -294,7 +206,22 @@ static struct meson_clk_pll gxbb_fixed_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.lock = &meson_clk_lock, .frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fixed_pll", .name = "fixed_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -304,7 +231,19 @@ static struct meson_clk_pll gxbb_fixed_pll = { ...@@ -304,7 +231,19 @@ static struct meson_clk_pll gxbb_fixed_pll = {
}, },
}; };
static struct meson_clk_pll gxbb_hdmi_pll = { static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = {
.mult = 2,
.div = 1,
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_pre_mult",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap gxbb_hdmi_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_HDMI_PLL_CNTL, .reg_off = HHI_HDMI_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -330,7 +269,80 @@ static struct meson_clk_pll gxbb_hdmi_pll = { ...@@ -330,7 +269,80 @@ static struct meson_clk_pll gxbb_hdmi_pll = {
.shift = 22, .shift = 22,
.width = 2, .width = 2,
}, },
.lock = &meson_clk_lock, .od3 = {
.reg_off = HHI_HDMI_PLL_CNTL2,
.shift = 18,
.width = 2,
},
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 28,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_pre_mult" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxl_hdmi_pll = {
.data = &(struct meson_clk_pll_data){
.m = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 9,
.width = 5,
},
.frac = {
/*
* On gxl, there is a register shift due to
* HHI_HDMI_PLL_CNTL1 which does not exist on gxbb,
* so we compute the register offset based on the PLL
* base to get it right
*/
.reg_off = HHI_HDMI_PLL_CNTL + 4,
.shift = 0,
.width = 12,
},
.od = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 21,
.width = 2,
},
.od2 = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 23,
.width = 2,
},
.od3 = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 19,
.width = 2,
},
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "hdmi_pll", .name = "hdmi_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -340,7 +352,8 @@ static struct meson_clk_pll gxbb_hdmi_pll = { ...@@ -340,7 +352,8 @@ static struct meson_clk_pll gxbb_hdmi_pll = {
}, },
}; };
static struct meson_clk_pll gxbb_sys_pll = { static struct clk_regmap gxbb_sys_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_SYS_PLL_CNTL, .reg_off = HHI_SYS_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -356,9 +369,17 @@ static struct meson_clk_pll gxbb_sys_pll = { ...@@ -356,9 +369,17 @@ static struct meson_clk_pll gxbb_sys_pll = {
.shift = 10, .shift = 10,
.width = 2, .width = 2,
}, },
.rate_table = sys_pll_rate_table, .l = {
.rate_count = ARRAY_SIZE(sys_pll_rate_table), .reg_off = HHI_SYS_PLL_CNTL,
.lock = &meson_clk_lock, .shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sys_pll", .name = "sys_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -368,14 +389,15 @@ static struct meson_clk_pll gxbb_sys_pll = { ...@@ -368,14 +389,15 @@ static struct meson_clk_pll gxbb_sys_pll = {
}, },
}; };
struct pll_params_table gxbb_gp0_params_table[] = { const struct reg_sequence gxbb_gp0_init_regs[] = {
PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 },
PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 },
PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d },
PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 },
}; };
static struct meson_clk_pll gxbb_gp0_pll = { static struct clk_regmap gxbb_gp0_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_GP0_PLL_CNTL, .reg_off = HHI_GP0_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -391,15 +413,20 @@ static struct meson_clk_pll gxbb_gp0_pll = { ...@@ -391,15 +413,20 @@ static struct meson_clk_pll gxbb_gp0_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.params = { .l = {
.params_table = gxbb_gp0_params_table, .reg_off = HHI_GP0_PLL_CNTL,
.params_count = ARRAY_SIZE(gxbb_gp0_params_table), .shift = 31,
.no_init_reset = true, .width = 1,
.clear_reset_for_lock = true, },
.rst = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = gxbb_gp0_pll_rate_table,
.init_regs = gxbb_gp0_init_regs,
.init_count = ARRAY_SIZE(gxbb_gp0_init_regs),
}, },
.rate_table = gxbb_gp0_pll_rate_table,
.rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table),
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gp0_pll", .name = "gp0_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ops,
...@@ -409,16 +436,17 @@ static struct meson_clk_pll gxbb_gp0_pll = { ...@@ -409,16 +436,17 @@ static struct meson_clk_pll gxbb_gp0_pll = {
}, },
}; };
struct pll_params_table gxl_gp0_params_table[] = { const struct reg_sequence gxl_gp0_init_regs[] = {
PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 },
PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be },
PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
}; };
static struct meson_clk_pll gxl_gp0_pll = { static struct clk_regmap gxl_gp0_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_GP0_PLL_CNTL, .reg_off = HHI_GP0_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -434,15 +462,25 @@ static struct meson_clk_pll gxl_gp0_pll = { ...@@ -434,15 +462,25 @@ static struct meson_clk_pll gxl_gp0_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.params = { .frac = {
.params_table = gxl_gp0_params_table, .reg_off = HHI_GP0_PLL_CNTL1,
.params_count = ARRAY_SIZE(gxl_gp0_params_table), .shift = 0,
.no_init_reset = true, .width = 10,
.reset_lock_loop = true, },
.l = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = gxl_gp0_pll_rate_table,
.init_regs = gxl_gp0_init_regs,
.init_count = ARRAY_SIZE(gxl_gp0_init_regs),
}, },
.rate_table = gxl_gp0_pll_rate_table,
.rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table),
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gp0_pll", .name = "gp0_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ops,
...@@ -452,62 +490,142 @@ static struct meson_clk_pll gxl_gp0_pll = { ...@@ -452,62 +490,142 @@ static struct meson_clk_pll gxl_gp0_pll = {
}, },
}; };
static struct clk_fixed_factor gxbb_fclk_div2 = { static struct clk_fixed_factor gxbb_fclk_div2_div = {
.mult = 1, .mult = 1,
.div = 2, .div = 2,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div2", .name = "fclk_div2_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor gxbb_fclk_div3 = { static struct clk_regmap gxbb_fclk_div2 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 27,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div2_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_fclk_div3_div = {
.mult = 1, .mult = 1,
.div = 3, .div = 3,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div3", .name = "fclk_div3_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor gxbb_fclk_div4 = { static struct clk_regmap gxbb_fclk_div3 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 28,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div3",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_fclk_div4_div = {
.mult = 1, .mult = 1,
.div = 4, .div = 4,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div4", .name = "fclk_div4_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor gxbb_fclk_div5 = { static struct clk_regmap gxbb_fclk_div4 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 29,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div4",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div4_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_fclk_div5_div = {
.mult = 1, .mult = 1,
.div = 5, .div = 5,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div5", .name = "fclk_div5_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor gxbb_fclk_div7 = { static struct clk_regmap gxbb_fclk_div5 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 30,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div5",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div5_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_fclk_div7_div = {
.mult = 1, .mult = 1,
.div = 7, .div = 7,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div7", .name = "fclk_div7_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll gxbb_mpll0 = { static struct clk_regmap gxbb_fclk_div7 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 31,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div7",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div7_div" },
.num_parents = 1,
},
};
static struct clk_regmap gxbb_mpll_prediv = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL5,
.shift = 12,
.width = 1,
},
.hw.init = &(struct clk_init_data){
.name = "mpll_prediv",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
static struct clk_regmap gxbb_mpll0_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL7, .reg_off = HHI_MPLL_CNTL7,
.shift = 0, .shift = 0,
...@@ -523,26 +641,37 @@ static struct meson_clk_mpll gxbb_mpll0 = { ...@@ -523,26 +641,37 @@ static struct meson_clk_mpll gxbb_mpll0 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 14,
.width = 1,
},
.ssen = { .ssen = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 25, .shift = 25,
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll0", .name = "mpll0_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1,
},
};
static struct clk_regmap gxbb_mpll0 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL7,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll0",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct meson_clk_mpll gxbb_mpll1 = { static struct clk_regmap gxbb_mpll1_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL8, .reg_off = HHI_MPLL_CNTL8,
.shift = 0, .shift = 0,
...@@ -558,21 +687,32 @@ static struct meson_clk_mpll gxbb_mpll1 = { ...@@ -558,21 +687,32 @@ static struct meson_clk_mpll gxbb_mpll1 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 14,
.width = 1,
},
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll1", .name = "mpll1_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll gxbb_mpll2 = { static struct clk_regmap gxbb_mpll1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL8,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll1_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_mpll2_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL9, .reg_off = HHI_MPLL_CNTL9,
.shift = 0, .shift = 0,
...@@ -588,25 +728,29 @@ static struct meson_clk_mpll gxbb_mpll2 = { ...@@ -588,25 +728,29 @@ static struct meson_clk_mpll gxbb_mpll2 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 14,
.width = 1,
},
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll2", .name = "mpll2_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
/* static struct clk_regmap gxbb_mpll2 = {
* FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers .data = &(struct clk_regmap_gate_data){
* and should be modeled with their respective PLLs via the forthcoming .offset = HHI_MPLL_CNTL9,
* coordinated clock rates feature .bit_idx = 14,
*/ },
.hw.init = &(struct clk_init_data){
.name = "mpll2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll2_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 };
static const char * const clk81_parent_names[] = { static const char * const clk81_parent_names[] = {
...@@ -614,16 +758,16 @@ static const char * const clk81_parent_names[] = { ...@@ -614,16 +758,16 @@ static const char * const clk81_parent_names[] = {
"fclk_div3", "fclk_div5" "fclk_div3", "fclk_div5"
}; };
static struct clk_mux gxbb_mpeg_clk_sel = { static struct clk_regmap gxbb_mpeg_clk_sel = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_MPEG_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 12, .shift = 12,
.flags = CLK_MUX_READ_ONLY,
.table = mux_table_clk81, .table = mux_table_clk81,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_sel", .name = "mpeg_clk_sel",
.ops = &clk_mux_ro_ops, .ops = &clk_regmap_mux_ro_ops,
/* /*
* bits 14:12 selects from 8 possible parents: * bits 14:12 selects from 8 possible parents:
* xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2,
...@@ -631,72 +775,75 @@ static struct clk_mux gxbb_mpeg_clk_sel = { ...@@ -631,72 +775,75 @@ static struct clk_mux gxbb_mpeg_clk_sel = {
*/ */
.parent_names = clk81_parent_names, .parent_names = clk81_parent_names,
.num_parents = ARRAY_SIZE(clk81_parent_names), .num_parents = ARRAY_SIZE(clk81_parent_names),
.flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED),
}, },
}; };
static struct clk_divider gxbb_mpeg_clk_div = { static struct clk_regmap gxbb_mpeg_clk_div = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_MPEG_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_div", .name = "mpeg_clk_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "mpeg_clk_sel" }, .parent_names = (const char *[]){ "mpeg_clk_sel" },
.num_parents = 1, .num_parents = 1,
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
}, },
}; };
/* the mother of dragons^W gates */ /* the mother of dragons gates */
static struct clk_gate gxbb_clk81 = { static struct clk_regmap gxbb_clk81 = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_MPEG_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "clk81", .name = "clk81",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpeg_clk_div" }, .parent_names = (const char *[]){ "mpeg_clk_div" },
.num_parents = 1, .num_parents = 1,
.flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), .flags = CLK_IS_CRITICAL,
}, },
}; };
static struct clk_mux gxbb_sar_adc_clk_sel = { static struct clk_regmap gxbb_sar_adc_clk_sel = {
.reg = (void *)HHI_SAR_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_SAR_CLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sar_adc_clk_sel", .name = "sar_adc_clk_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* NOTE: The datasheet doesn't list the parents for bit 10 */ /* NOTE: The datasheet doesn't list the parents for bit 10 */
.parent_names = (const char *[]){ "xtal", "clk81", }, .parent_names = (const char *[]){ "xtal", "clk81", },
.num_parents = 2, .num_parents = 2,
}, },
}; };
static struct clk_divider gxbb_sar_adc_clk_div = { static struct clk_regmap gxbb_sar_adc_clk_div = {
.reg = (void *)HHI_SAR_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_SAR_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 8, .width = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sar_adc_clk_div", .name = "sar_adc_clk_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sar_adc_clk_sel" }, .parent_names = (const char *[]){ "sar_adc_clk_sel" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_gate gxbb_sar_adc_clk = { static struct clk_regmap gxbb_sar_adc_clk = {
.reg = (void *)HHI_SAR_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_SAR_CLK_CNTL,
.bit_idx = 8, .bit_idx = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sar_adc_clk", .name = "sar_adc_clk",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sar_adc_clk_div" }, .parent_names = (const char *[]){ "sar_adc_clk_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -708,21 +855,20 @@ static struct clk_gate gxbb_sar_adc_clk = { ...@@ -708,21 +855,20 @@ static struct clk_gate gxbb_sar_adc_clk = {
* muxed by a glitch-free switch. * muxed by a glitch-free switch.
*/ */
static u32 mux_table_mali_0_1[] = {0, 1, 2, 3, 4, 5, 6, 7};
static const char * const gxbb_mali_0_1_parent_names[] = { static const char * const gxbb_mali_0_1_parent_names[] = {
"xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7",
"fclk_div4", "fclk_div3", "fclk_div5" "fclk_div4", "fclk_div3", "fclk_div5"
}; };
static struct clk_mux gxbb_mali_0_sel = { static struct clk_regmap gxbb_mali_0_sel = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 9, .shift = 9,
.table = mux_table_mali_0_1, },
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_0_sel", .name = "mali_0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 10:9 selects from 8 possible parents: * bits 10:9 selects from 8 possible parents:
* xtal, gp0_pll, mpll2, mpll1, fclk_div7, * xtal, gp0_pll, mpll2, mpll1, fclk_div7,
...@@ -734,42 +880,44 @@ static struct clk_mux gxbb_mali_0_sel = { ...@@ -734,42 +880,44 @@ static struct clk_mux gxbb_mali_0_sel = {
}, },
}; };
static struct clk_divider gxbb_mali_0_div = { static struct clk_regmap gxbb_mali_0_div = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_MALI_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_0_div", .name = "mali_0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "mali_0_sel" }, .parent_names = (const char *[]){ "mali_0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_NO_REPARENT, .flags = CLK_SET_RATE_NO_REPARENT,
}, },
}; };
static struct clk_gate gxbb_mali_0 = { static struct clk_regmap gxbb_mali_0 = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_MALI_CLK_CNTL,
.bit_idx = 8, .bit_idx = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_0", .name = "mali_0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mali_0_div" }, .parent_names = (const char *[]){ "mali_0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_mux gxbb_mali_1_sel = { static struct clk_regmap gxbb_mali_1_sel = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 25, .shift = 25,
.table = mux_table_mali_0_1, },
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_1_sel", .name = "mali_1_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 10:9 selects from 8 possible parents: * bits 10:9 selects from 8 possible parents:
* xtal, gp0_pll, mpll2, mpll1, fclk_div7, * xtal, gp0_pll, mpll2, mpll1, fclk_div7,
...@@ -781,77 +929,79 @@ static struct clk_mux gxbb_mali_1_sel = { ...@@ -781,77 +929,79 @@ static struct clk_mux gxbb_mali_1_sel = {
}, },
}; };
static struct clk_divider gxbb_mali_1_div = { static struct clk_regmap gxbb_mali_1_div = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_MALI_CLK_CNTL,
.shift = 16, .shift = 16,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_1_div", .name = "mali_1_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "mali_1_sel" }, .parent_names = (const char *[]){ "mali_1_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_NO_REPARENT, .flags = CLK_SET_RATE_NO_REPARENT,
}, },
}; };
static struct clk_gate gxbb_mali_1 = { static struct clk_regmap gxbb_mali_1 = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_MALI_CLK_CNTL,
.bit_idx = 24, .bit_idx = 24,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali_1", .name = "mali_1",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mali_1_div" }, .parent_names = (const char *[]){ "mali_1_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static u32 mux_table_mali[] = {0, 1};
static const char * const gxbb_mali_parent_names[] = { static const char * const gxbb_mali_parent_names[] = {
"mali_0", "mali_1" "mali_0", "mali_1"
}; };
static struct clk_mux gxbb_mali = { static struct clk_regmap gxbb_mali = {
.reg = (void *)HHI_MALI_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 1, .mask = 1,
.shift = 31, .shift = 31,
.table = mux_table_mali, },
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mali", .name = "mali",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = gxbb_mali_parent_names, .parent_names = gxbb_mali_parent_names,
.num_parents = 2, .num_parents = 2,
.flags = CLK_SET_RATE_NO_REPARENT, .flags = CLK_SET_RATE_NO_REPARENT,
}, },
}; };
static struct clk_mux gxbb_cts_amclk_sel = { static struct clk_regmap gxbb_cts_amclk_sel = {
.reg = (void *) HHI_AUD_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 9, .shift = 9,
/* Default parent unknown (register reset value: 0) */
.table = (u32[]){ 1, 2, 3 }, .table = (u32[]){ 1, 2, 3 },
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cts_amclk_sel", .name = "cts_amclk_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
.num_parents = 3, .num_parents = 3,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct meson_clk_audio_divider gxbb_cts_amclk_div = { static struct clk_regmap gxbb_cts_amclk_div = {
.data = &(struct meson_clk_audio_div_data){
.div = { .div = {
.reg_off = HHI_AUD_CLK_CNTL, .reg_off = HHI_AUD_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 8, .width = 8,
}, },
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cts_amclk_div", .name = "cts_amclk_div",
.ops = &meson_clk_audio_divider_ops, .ops = &meson_clk_audio_divider_ops,
...@@ -861,71 +1011,75 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { ...@@ -861,71 +1011,75 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = {
}, },
}; };
static struct clk_gate gxbb_cts_amclk = { static struct clk_regmap gxbb_cts_amclk = {
.reg = (void *) HHI_AUD_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_AUD_CLK_CNTL,
.bit_idx = 8, .bit_idx = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cts_amclk", .name = "cts_amclk",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_amclk_div" }, .parent_names = (const char *[]){ "cts_amclk_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_mux gxbb_cts_mclk_i958_sel = { static struct clk_regmap gxbb_cts_mclk_i958_sel = {
.reg = (void *)HHI_AUD_CLK_CNTL2, .data = &(struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL2,
.mask = 0x3, .mask = 0x3,
.shift = 25, .shift = 25,
/* Default parent unknown (register reset value: 0) */
.table = (u32[]){ 1, 2, 3 }, .table = (u32[]){ 1, 2, 3 },
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "cts_mclk_i958_sel", .name = "cts_mclk_i958_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
.num_parents = 3, .num_parents = 3,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider gxbb_cts_mclk_i958_div = { static struct clk_regmap gxbb_cts_mclk_i958_div = {
.reg = (void *)HHI_AUD_CLK_CNTL2, .data = &(struct clk_regmap_div_data){
.offset = HHI_AUD_CLK_CNTL2,
.shift = 16, .shift = 16,
.width = 8, .width = 8,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "cts_mclk_i958_div", .name = "cts_mclk_i958_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_mclk_i958_sel" }, .parent_names = (const char *[]){ "cts_mclk_i958_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_cts_mclk_i958 = { static struct clk_regmap gxbb_cts_mclk_i958 = {
.reg = (void *)HHI_AUD_CLK_CNTL2, .data = &(struct clk_regmap_gate_data){
.offset = HHI_AUD_CLK_CNTL2,
.bit_idx = 24, .bit_idx = 24,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cts_mclk_i958", .name = "cts_mclk_i958",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_mclk_i958_div" }, .parent_names = (const char *[]){ "cts_mclk_i958_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_mux gxbb_cts_i958 = { static struct clk_regmap gxbb_cts_i958 = {
.reg = (void *)HHI_AUD_CLK_CNTL2, .data = &(struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL2,
.mask = 0x1, .mask = 0x1,
.shift = 27, .shift = 27,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cts_i958", .name = "cts_i958",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" },
.num_parents = 2, .num_parents = 2,
/* /*
...@@ -936,27 +1090,29 @@ static struct clk_mux gxbb_cts_i958 = { ...@@ -936,27 +1090,29 @@ static struct clk_mux gxbb_cts_i958 = {
}, },
}; };
static struct clk_divider gxbb_32k_clk_div = { static struct clk_regmap gxbb_32k_clk_div = {
.reg = (void *)HHI_32K_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_32K_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 14, .width = 14,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "32k_clk_div", .name = "32k_clk_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "32k_clk_sel" }, .parent_names = (const char *[]){ "32k_clk_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST,
}, },
}; };
static struct clk_gate gxbb_32k_clk = { static struct clk_regmap gxbb_32k_clk = {
.reg = (void *)HHI_32K_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_32K_CLK_CNTL,
.bit_idx = 15, .bit_idx = 15,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "32k_clk", .name = "32k_clk",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "32k_clk_div" }, .parent_names = (const char *[]){ "32k_clk_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -967,14 +1123,15 @@ static const char * const gxbb_32k_clk_parent_names[] = { ...@@ -967,14 +1123,15 @@ static const char * const gxbb_32k_clk_parent_names[] = {
"xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5"
}; };
static struct clk_mux gxbb_32k_clk_sel = { static struct clk_regmap gxbb_32k_clk_sel = {
.reg = (void *)HHI_32K_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_32K_CLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 16, .shift = 16,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "32k_clk_sel", .name = "32k_clk_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = gxbb_32k_clk_parent_names, .parent_names = gxbb_32k_clk_parent_names,
.num_parents = 4, .num_parents = 4,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -993,42 +1150,45 @@ static const char * const gxbb_sd_emmc_clk0_parent_names[] = { ...@@ -993,42 +1150,45 @@ static const char * const gxbb_sd_emmc_clk0_parent_names[] = {
}; };
/* SDIO clock */ /* SDIO clock */
static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_a_clk0_sel", .name = "sd_emmc_a_clk0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = gxbb_sd_emmc_clk0_parent_names, .parent_names = gxbb_sd_emmc_clk0_parent_names,
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider gxbb_sd_emmc_a_clk0_div = { static struct clk_regmap gxbb_sd_emmc_a_clk0_div = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_a_clk0_div", .name = "sd_emmc_a_clk0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_sd_emmc_a_clk0 = { static struct clk_regmap gxbb_sd_emmc_a_clk0 = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sd_emmc_a_clk0", .name = "sd_emmc_a_clk0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -1036,42 +1196,45 @@ static struct clk_gate gxbb_sd_emmc_a_clk0 = { ...@@ -1036,42 +1196,45 @@ static struct clk_gate gxbb_sd_emmc_a_clk0 = {
}; };
/* SDcard clock */ /* SDcard clock */
static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 25, .shift = 25,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_b_clk0_sel", .name = "sd_emmc_b_clk0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = gxbb_sd_emmc_clk0_parent_names, .parent_names = gxbb_sd_emmc_clk0_parent_names,
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider gxbb_sd_emmc_b_clk0_div = { static struct clk_regmap gxbb_sd_emmc_b_clk0_div = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.shift = 16, .shift = 16,
.width = 7, .width = 7,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_b_clk0_div", .name = "sd_emmc_b_clk0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_sd_emmc_b_clk0 = { static struct clk_regmap gxbb_sd_emmc_b_clk0 = {
.reg = (void *)HHI_SD_EMMC_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_SD_EMMC_CLK_CNTL,
.bit_idx = 23, .bit_idx = 23,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sd_emmc_b_clk0", .name = "sd_emmc_b_clk0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -1079,42 +1242,45 @@ static struct clk_gate gxbb_sd_emmc_b_clk0 = { ...@@ -1079,42 +1242,45 @@ static struct clk_gate gxbb_sd_emmc_b_clk0 = {
}; };
/* EMMC/NAND clock */ /* EMMC/NAND clock */
static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_NAND_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_c_clk0_sel", .name = "sd_emmc_c_clk0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
.parent_names = gxbb_sd_emmc_clk0_parent_names, .parent_names = gxbb_sd_emmc_clk0_parent_names,
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_divider gxbb_sd_emmc_c_clk0_div = { static struct clk_regmap gxbb_sd_emmc_c_clk0_div = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_NAND_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock,
.flags = CLK_DIVIDER_ROUND_CLOSEST, .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "sd_emmc_c_clk0_div", .name = "sd_emmc_c_clk0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_sd_emmc_c_clk0 = { static struct clk_regmap gxbb_sd_emmc_c_clk0 = {
.reg = (void *)HHI_NAND_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_NAND_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sd_emmc_c_clk0", .name = "sd_emmc_c_clk0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
...@@ -1123,20 +1289,19 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = { ...@@ -1123,20 +1289,19 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = {
/* VPU Clock */ /* VPU Clock */
static u32 mux_table_vpu[] = {0, 1, 2, 3};
static const char * const gxbb_vpu_parent_names[] = { static const char * const gxbb_vpu_parent_names[] = {
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
}; };
static struct clk_mux gxbb_vpu_0_sel = { static struct clk_regmap gxbb_vpu_0_sel = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.table = mux_table_vpu,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vpu_0_sel", .name = "vpu_0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 9:10 selects from 4 possible parents: * bits 9:10 selects from 4 possible parents:
* fclk_div4, fclk_div3, fclk_div5, fclk_div7, * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
...@@ -1147,42 +1312,44 @@ static struct clk_mux gxbb_vpu_0_sel = { ...@@ -1147,42 +1312,44 @@ static struct clk_mux gxbb_vpu_0_sel = {
}, },
}; };
static struct clk_divider gxbb_vpu_0_div = { static struct clk_regmap gxbb_vpu_0_div = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_VPU_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vpu_0_div", .name = "vpu_0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vpu_0_sel" }, .parent_names = (const char *[]){ "vpu_0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_vpu_0 = { static struct clk_regmap gxbb_vpu_0 = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_VPU_CLK_CNTL,
.bit_idx = 8, .bit_idx = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "vpu_0", .name = "vpu_0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vpu_0_div" }, .parent_names = (const char *[]){ "vpu_0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
}, },
}; };
static struct clk_mux gxbb_vpu_1_sel = { static struct clk_regmap gxbb_vpu_1_sel = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 25, .shift = 25,
.lock = &meson_clk_lock, },
.table = mux_table_vpu,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vpu_1_sel", .name = "vpu_1_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 25:26 selects from 4 possible parents: * bits 25:26 selects from 4 possible parents:
* fclk_div4, fclk_div3, fclk_div5, fclk_div7, * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
...@@ -1193,41 +1360,44 @@ static struct clk_mux gxbb_vpu_1_sel = { ...@@ -1193,41 +1360,44 @@ static struct clk_mux gxbb_vpu_1_sel = {
}, },
}; };
static struct clk_divider gxbb_vpu_1_div = { static struct clk_regmap gxbb_vpu_1_div = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_VPU_CLK_CNTL,
.shift = 16, .shift = 16,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vpu_1_div", .name = "vpu_1_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vpu_1_sel" }, .parent_names = (const char *[]){ "vpu_1_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_vpu_1 = { static struct clk_regmap gxbb_vpu_1 = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_VPU_CLK_CNTL,
.bit_idx = 24, .bit_idx = 24,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "vpu_1", .name = "vpu_1",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vpu_1_div" }, .parent_names = (const char *[]){ "vpu_1_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
}, },
}; };
static struct clk_mux gxbb_vpu = { static struct clk_regmap gxbb_vpu = {
.reg = (void *)HHI_VPU_CLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 1, .mask = 1,
.shift = 31, .shift = 31,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vpu", .name = "vpu",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bit 31 selects from 2 possible parents: * bit 31 selects from 2 possible parents:
* vpu_0 or vpu_1 * vpu_0 or vpu_1
...@@ -1240,20 +1410,19 @@ static struct clk_mux gxbb_vpu = { ...@@ -1240,20 +1410,19 @@ static struct clk_mux gxbb_vpu = {
/* VAPB Clock */ /* VAPB Clock */
static u32 mux_table_vapb[] = {0, 1, 2, 3};
static const char * const gxbb_vapb_parent_names[] = { static const char * const gxbb_vapb_parent_names[] = {
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
}; };
static struct clk_mux gxbb_vapb_0_sel = { static struct clk_regmap gxbb_vapb_0_sel = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VAPBCLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 9, .shift = 9,
.lock = &meson_clk_lock, },
.table = mux_table_vapb,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vapb_0_sel", .name = "vapb_0_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 9:10 selects from 4 possible parents: * bits 9:10 selects from 4 possible parents:
* fclk_div4, fclk_div3, fclk_div5, fclk_div7, * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
...@@ -1264,42 +1433,44 @@ static struct clk_mux gxbb_vapb_0_sel = { ...@@ -1264,42 +1433,44 @@ static struct clk_mux gxbb_vapb_0_sel = {
}, },
}; };
static struct clk_divider gxbb_vapb_0_div = { static struct clk_regmap gxbb_vapb_0_div = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_VAPBCLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vapb_0_div", .name = "vapb_0_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vapb_0_sel" }, .parent_names = (const char *[]){ "vapb_0_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_vapb_0 = { static struct clk_regmap gxbb_vapb_0 = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_VAPBCLK_CNTL,
.bit_idx = 8, .bit_idx = 8,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "vapb_0", .name = "vapb_0",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vapb_0_div" }, .parent_names = (const char *[]){ "vapb_0_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
}, },
}; };
static struct clk_mux gxbb_vapb_1_sel = { static struct clk_regmap gxbb_vapb_1_sel = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VAPBCLK_CNTL,
.mask = 0x3, .mask = 0x3,
.shift = 25, .shift = 25,
.lock = &meson_clk_lock, },
.table = mux_table_vapb,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vapb_1_sel", .name = "vapb_1_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bits 25:26 selects from 4 possible parents: * bits 25:26 selects from 4 possible parents:
* fclk_div4, fclk_div3, fclk_div5, fclk_div7, * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
...@@ -1310,41 +1481,44 @@ static struct clk_mux gxbb_vapb_1_sel = { ...@@ -1310,41 +1481,44 @@ static struct clk_mux gxbb_vapb_1_sel = {
}, },
}; };
static struct clk_divider gxbb_vapb_1_div = { static struct clk_regmap gxbb_vapb_1_div = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_VAPBCLK_CNTL,
.shift = 16, .shift = 16,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vapb_1_div", .name = "vapb_1_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vapb_1_sel" }, .parent_names = (const char *[]){ "vapb_1_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct clk_gate gxbb_vapb_1 = { static struct clk_regmap gxbb_vapb_1 = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_VAPBCLK_CNTL,
.bit_idx = 24, .bit_idx = 24,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "vapb_1", .name = "vapb_1",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vapb_1_div" }, .parent_names = (const char *[]){ "vapb_1_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
}, },
}; };
static struct clk_mux gxbb_vapb_sel = { static struct clk_regmap gxbb_vapb_sel = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_mux_data){
.offset = HHI_VAPBCLK_CNTL,
.mask = 1, .mask = 1,
.shift = 31, .shift = 31,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vapb_sel", .name = "vapb_sel",
.ops = &clk_mux_ops, .ops = &clk_regmap_mux_ops,
/* /*
* bit 31 selects from 2 possible parents: * bit 31 selects from 2 possible parents:
* vapb_0 or vapb_1 * vapb_0 or vapb_1
...@@ -1355,13 +1529,14 @@ static struct clk_mux gxbb_vapb_sel = { ...@@ -1355,13 +1529,14 @@ static struct clk_mux gxbb_vapb_sel = {
}, },
}; };
static struct clk_gate gxbb_vapb = { static struct clk_regmap gxbb_vapb = {
.reg = (void *)HHI_VAPBCLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_VAPBCLK_CNTL,
.bit_idx = 30, .bit_idx = 30,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data) { .hw.init = &(struct clk_init_data) {
.name = "vapb", .name = "vapb",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vapb_sel" }, .parent_names = (const char *[]){ "vapb_sel" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
...@@ -1601,6 +1776,16 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { ...@@ -1601,6 +1776,16 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
[CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_1] = &gxbb_vapb_1.hw,
[CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw,
[CLKID_VAPB] = &gxbb_vapb.hw, [CLKID_VAPB] = &gxbb_vapb.hw,
[CLKID_HDMI_PLL_PRE_MULT] = &gxbb_hdmi_pll_pre_mult.hw,
[CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw,
[CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw,
[CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw,
[CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw,
[CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw,
[CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw,
[CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw,
[NR_CLKS] = NULL, [NR_CLKS] = NULL,
}, },
.num = NR_CLKS, .num = NR_CLKS,
...@@ -1609,7 +1794,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { ...@@ -1609,7 +1794,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
static struct clk_hw_onecell_data gxl_hw_onecell_data = { static struct clk_hw_onecell_data gxl_hw_onecell_data = {
.hws = { .hws = {
[CLKID_SYS_PLL] = &gxbb_sys_pll.hw, [CLKID_SYS_PLL] = &gxbb_sys_pll.hw,
[CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, [CLKID_HDMI_PLL] = &gxl_hdmi_pll.hw,
[CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw,
[CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw,
[CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw,
...@@ -1748,34 +1933,31 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { ...@@ -1748,34 +1933,31 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_1] = &gxbb_vapb_1.hw,
[CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw,
[CLKID_VAPB] = &gxbb_vapb.hw, [CLKID_VAPB] = &gxbb_vapb.hw,
[CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw,
[CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw,
[CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw,
[CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw,
[CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw,
[CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw,
[CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw,
[NR_CLKS] = NULL, [NR_CLKS] = NULL,
}, },
.num = NR_CLKS, .num = NR_CLKS,
}; };
/* Convenience tables to populate base addresses in .probe */ static struct clk_regmap *const gxbb_clk_regmaps[] = {
static struct meson_clk_pll *const gxbb_clk_plls[] = {
&gxbb_fixed_pll,
&gxbb_hdmi_pll,
&gxbb_sys_pll,
&gxbb_gp0_pll, &gxbb_gp0_pll,
};
static struct meson_clk_pll *const gxl_clk_plls[] = {
&gxbb_fixed_pll,
&gxbb_hdmi_pll, &gxbb_hdmi_pll,
&gxbb_sys_pll,
&gxl_gp0_pll,
}; };
static struct meson_clk_mpll *const gxbb_clk_mplls[] = { static struct clk_regmap *const gxl_clk_regmaps[] = {
&gxbb_mpll0, &gxl_gp0_pll,
&gxbb_mpll1, &gxl_hdmi_pll,
&gxbb_mpll2,
}; };
static struct clk_gate *const gxbb_clk_gates[] = { static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_clk81, &gxbb_clk81,
&gxbb_ddr, &gxbb_ddr,
&gxbb_dos, &gxbb_dos,
...@@ -1872,9 +2054,19 @@ static struct clk_gate *const gxbb_clk_gates[] = { ...@@ -1872,9 +2054,19 @@ static struct clk_gate *const gxbb_clk_gates[] = {
&gxbb_vapb_0, &gxbb_vapb_0,
&gxbb_vapb_1, &gxbb_vapb_1,
&gxbb_vapb, &gxbb_vapb,
}; &gxbb_mpeg_clk_div,
&gxbb_sar_adc_clk_div,
static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_mali_0_div,
&gxbb_mali_1_div,
&gxbb_cts_mclk_i958_div,
&gxbb_32k_clk_div,
&gxbb_sd_emmc_a_clk0_div,
&gxbb_sd_emmc_b_clk0_div,
&gxbb_sd_emmc_c_clk0_div,
&gxbb_vpu_0_div,
&gxbb_vpu_1_div,
&gxbb_vapb_0_div,
&gxbb_vapb_1_div,
&gxbb_mpeg_clk_sel, &gxbb_mpeg_clk_sel,
&gxbb_sar_adc_clk_sel, &gxbb_sar_adc_clk_sel,
&gxbb_mali_0_sel, &gxbb_mali_0_sel,
...@@ -1893,73 +2085,38 @@ static struct clk_mux *const gxbb_clk_muxes[] = { ...@@ -1893,73 +2085,38 @@ static struct clk_mux *const gxbb_clk_muxes[] = {
&gxbb_vapb_0_sel, &gxbb_vapb_0_sel,
&gxbb_vapb_1_sel, &gxbb_vapb_1_sel,
&gxbb_vapb_sel, &gxbb_vapb_sel,
}; &gxbb_mpll0,
&gxbb_mpll1,
static struct clk_divider *const gxbb_clk_dividers[] = { &gxbb_mpll2,
&gxbb_mpeg_clk_div, &gxbb_mpll0_div,
&gxbb_sar_adc_clk_div, &gxbb_mpll1_div,
&gxbb_mali_0_div, &gxbb_mpll2_div,
&gxbb_mali_1_div,
&gxbb_cts_mclk_i958_div,
&gxbb_32k_clk_div,
&gxbb_sd_emmc_a_clk0_div,
&gxbb_sd_emmc_b_clk0_div,
&gxbb_sd_emmc_c_clk0_div,
&gxbb_vpu_0_div,
&gxbb_vpu_1_div,
&gxbb_vapb_0_div,
&gxbb_vapb_1_div,
};
static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
&gxbb_cts_amclk_div, &gxbb_cts_amclk_div,
&gxbb_fixed_pll,
&gxbb_sys_pll,
&gxbb_mpll_prediv,
&gxbb_fclk_div2,
&gxbb_fclk_div3,
&gxbb_fclk_div4,
&gxbb_fclk_div5,
&gxbb_fclk_div7,
}; };
struct clkc_data { struct clkc_data {
struct clk_gate *const *clk_gates; struct clk_regmap *const *regmap_clks;
unsigned int clk_gates_count; unsigned int regmap_clks_count;
struct meson_clk_mpll *const *clk_mplls;
unsigned int clk_mplls_count;
struct meson_clk_pll *const *clk_plls;
unsigned int clk_plls_count;
struct clk_mux *const *clk_muxes;
unsigned int clk_muxes_count;
struct clk_divider *const *clk_dividers;
unsigned int clk_dividers_count;
struct meson_clk_audio_divider *const *clk_audio_dividers;
unsigned int clk_audio_dividers_count;
struct clk_hw_onecell_data *hw_onecell_data; struct clk_hw_onecell_data *hw_onecell_data;
}; };
static const struct clkc_data gxbb_clkc_data = { static const struct clkc_data gxbb_clkc_data = {
.clk_gates = gxbb_clk_gates, .regmap_clks = gxbb_clk_regmaps,
.clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps),
.clk_mplls = gxbb_clk_mplls,
.clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls),
.clk_plls = gxbb_clk_plls,
.clk_plls_count = ARRAY_SIZE(gxbb_clk_plls),
.clk_muxes = gxbb_clk_muxes,
.clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes),
.clk_dividers = gxbb_clk_dividers,
.clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers),
.clk_audio_dividers = gxbb_audio_dividers,
.clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers),
.hw_onecell_data = &gxbb_hw_onecell_data, .hw_onecell_data = &gxbb_hw_onecell_data,
}; };
static const struct clkc_data gxl_clkc_data = { static const struct clkc_data gxl_clkc_data = {
.clk_gates = gxbb_clk_gates, .regmap_clks = gxl_clk_regmaps,
.clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps),
.clk_mplls = gxbb_clk_mplls,
.clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls),
.clk_plls = gxl_clk_plls,
.clk_plls_count = ARRAY_SIZE(gxl_clk_plls),
.clk_muxes = gxbb_clk_muxes,
.clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes),
.clk_dividers = gxbb_clk_dividers,
.clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers),
.clk_audio_dividers = gxbb_audio_dividers,
.clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers),
.hw_onecell_data = &gxl_hw_onecell_data, .hw_onecell_data = &gxl_hw_onecell_data,
}; };
...@@ -1969,71 +2126,79 @@ static const struct of_device_id clkc_match_table[] = { ...@@ -1969,71 +2126,79 @@ static const struct of_device_id clkc_match_table[] = {
{}, {},
}; };
static const struct regmap_config clkc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int gxbb_clkc_probe(struct platform_device *pdev) static int gxbb_clkc_probe(struct platform_device *pdev)
{ {
const struct clkc_data *clkc_data; const struct clkc_data *clkc_data;
struct resource *res;
void __iomem *clk_base; void __iomem *clk_base;
int ret, clkid, i; struct regmap *map;
int ret, i;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
clkc_data = of_device_get_match_data(&pdev->dev); clkc_data = of_device_get_match_data(dev);
if (!clkc_data) if (!clkc_data)
return -EINVAL; return -EINVAL;
/* Generic clocks and PLLs */ /* Get the hhi system controller node if available */
clk_base = of_iomap(dev->of_node, 0); map = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(map)) {
dev_err(dev,
"failed to get HHI regmap - Trying obsolete regs\n");
/*
* FIXME: HHI registers should be accessed through
* the appropriate system controller. This is required because
* there is more than just clocks in this register space
*
* This fallback method is only provided temporarily until
* all the platform DTs are properly using the syscon node
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
clk_base = devm_ioremap(dev, res->start, resource_size(res));
if (!clk_base) { if (!clk_base) {
pr_err("%s: Unable to map clk base\n", __func__); dev_err(dev, "Unable to map clk base\n");
return -ENXIO; return -ENXIO;
} }
/* Populate base address for PLLs */ map = devm_regmap_init_mmio(dev, clk_base,
for (i = 0; i < clkc_data->clk_plls_count; i++) &clkc_regmap_config);
clkc_data->clk_plls[i]->base = clk_base; if (IS_ERR(map))
return PTR_ERR(map);
/* Populate base address for MPLLs */ }
for (i = 0; i < clkc_data->clk_mplls_count; i++)
clkc_data->clk_mplls[i]->base = clk_base;
/* Populate base address for gates */
for (i = 0; i < clkc_data->clk_gates_count; i++)
clkc_data->clk_gates[i]->reg = clk_base +
(u64)clkc_data->clk_gates[i]->reg;
/* Populate base address for muxes */
for (i = 0; i < clkc_data->clk_muxes_count; i++)
clkc_data->clk_muxes[i]->reg = clk_base +
(u64)clkc_data->clk_muxes[i]->reg;
/* Populate base address for dividers */ /* Populate regmap for the common regmap backed clocks */
for (i = 0; i < clkc_data->clk_dividers_count; i++) for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++)
clkc_data->clk_dividers[i]->reg = clk_base + gx_clk_regmaps[i]->map = map;
(u64)clkc_data->clk_dividers[i]->reg;
/* Populate base address for the audio dividers */ /* Populate regmap for soc specific clocks */
for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) for (i = 0; i < clkc_data->regmap_clks_count; i++)
clkc_data->clk_audio_dividers[i]->base = clk_base; clkc_data->regmap_clks[i]->map = map;
/* /* Register all clks */
* register all clks for (i = 0; i < clkc_data->hw_onecell_data->num; i++) {
*/
for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) {
/* array might be sparse */ /* array might be sparse */
if (!clkc_data->hw_onecell_data->hws[clkid]) if (!clkc_data->hw_onecell_data->hws[i])
continue; continue;
ret = devm_clk_hw_register(dev, ret = devm_clk_hw_register(dev,
clkc_data->hw_onecell_data->hws[clkid]); clkc_data->hw_onecell_data->hws[i]);
if (ret) if (ret) {
goto iounmap; dev_err(dev, "Clock registration failed\n");
return ret;
}
} }
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clkc_data->hw_onecell_data); clkc_data->hw_onecell_data);
iounmap:
iounmap(clk_base);
return ret;
} }
static struct platform_driver gxbb_driver = { static struct platform_driver gxbb_driver = {
......
...@@ -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>
......
...@@ -23,14 +23,16 @@ ...@@ -23,14 +23,16 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/regmap.h>
#include "clkc.h" #include "clkc.h"
#include "meson8b.h" #include "meson8b.h"
#include "clk-regmap.h"
static DEFINE_SPINLOCK(meson_clk_lock); static DEFINE_SPINLOCK(meson_clk_lock);
...@@ -97,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = { ...@@ -97,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
static const struct clk_div_table cpu_div_table[] = {
{ .val = 1, .div = 1 },
{ .val = 2, .div = 2 },
{ .val = 3, .div = 3 },
{ .val = 2, .div = 4 },
{ .val = 3, .div = 6 },
{ .val = 4, .div = 8 },
{ .val = 5, .div = 10 },
{ .val = 6, .div = 12 },
{ .val = 7, .div = 14 },
{ .val = 8, .div = 16 },
{ /* sentinel */ },
};
static struct clk_fixed_rate meson8b_xtal = { static struct clk_fixed_rate meson8b_xtal = {
.fixed_rate = 24000000, .fixed_rate = 24000000,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
...@@ -120,7 +108,8 @@ static struct clk_fixed_rate meson8b_xtal = { ...@@ -120,7 +108,8 @@ static struct clk_fixed_rate meson8b_xtal = {
}, },
}; };
static struct meson_clk_pll meson8b_fixed_pll = { static struct clk_regmap meson8b_fixed_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 0, .shift = 0,
...@@ -136,7 +125,22 @@ static struct meson_clk_pll meson8b_fixed_pll = { ...@@ -136,7 +125,22 @@ static struct meson_clk_pll meson8b_fixed_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.lock = &meson_clk_lock, .frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fixed_pll", .name = "fixed_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -146,7 +150,8 @@ static struct meson_clk_pll meson8b_fixed_pll = { ...@@ -146,7 +150,8 @@ static struct meson_clk_pll meson8b_fixed_pll = {
}, },
}; };
static struct meson_clk_pll meson8b_vid_pll = { static struct clk_regmap meson8b_vid_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_VID_PLL_CNTL, .reg_off = HHI_VID_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -162,7 +167,17 @@ static struct meson_clk_pll meson8b_vid_pll = { ...@@ -162,7 +167,17 @@ static struct meson_clk_pll meson8b_vid_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.lock = &meson_clk_lock, .l = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vid_pll", .name = "vid_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -172,7 +187,8 @@ static struct meson_clk_pll meson8b_vid_pll = { ...@@ -172,7 +187,8 @@ static struct meson_clk_pll meson8b_vid_pll = {
}, },
}; };
static struct meson_clk_pll meson8b_sys_pll = { static struct clk_regmap meson8b_sys_pll = {
.data = &(struct meson_clk_pll_data){
.m = { .m = {
.reg_off = HHI_SYS_PLL_CNTL, .reg_off = HHI_SYS_PLL_CNTL,
.shift = 0, .shift = 0,
...@@ -188,74 +204,163 @@ static struct meson_clk_pll meson8b_sys_pll = { ...@@ -188,74 +204,163 @@ static struct meson_clk_pll meson8b_sys_pll = {
.shift = 16, .shift = 16,
.width = 2, .width = 2,
}, },
.rate_table = sys_pll_rate_table, .l = {
.rate_count = ARRAY_SIZE(sys_pll_rate_table), .reg_off = HHI_SYS_PLL_CNTL,
.lock = &meson_clk_lock, .shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = sys_pll_rate_table,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sys_pll", .name = "sys_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" }, .parent_names = (const char *[]){ "xtal" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE, .flags = CLK_GET_RATE_NOCACHE,
}, },
}; };
static struct clk_fixed_factor meson8b_fclk_div2 = { static struct clk_fixed_factor meson8b_fclk_div2_div = {
.mult = 1, .mult = 1,
.div = 2, .div = 2,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div2", .name = "fclk_div2_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor meson8b_fclk_div3 = { static struct clk_regmap meson8b_fclk_div2 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 27,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div2_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div3_div = {
.mult = 1, .mult = 1,
.div = 3, .div = 3,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div3", .name = "fclk_div_div3",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor meson8b_fclk_div4 = { static struct clk_regmap meson8b_fclk_div3 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 28,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div3",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div4_div = {
.mult = 1, .mult = 1,
.div = 4, .div = 4,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div4", .name = "fclk_div4_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor meson8b_fclk_div5 = { static struct clk_regmap meson8b_fclk_div4 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 29,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div4",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div4_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div5_div = {
.mult = 1, .mult = 1,
.div = 5, .div = 5,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div5", .name = "fclk_div5_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct clk_fixed_factor meson8b_fclk_div7 = { static struct clk_regmap meson8b_fclk_div5 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 30,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div5",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div5_div" },
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div7_div = {
.mult = 1, .mult = 1,
.div = 7, .div = 7,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fclk_div7", .name = "fclk_div7_div",
.ops = &clk_fixed_factor_ops, .ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll meson8b_mpll0 = { static struct clk_regmap meson8b_fclk_div7 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 31,
},
.hw.init = &(struct clk_init_data){
.name = "fclk_div7",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div7_div" },
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll_prediv = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL5,
.shift = 12,
.width = 1,
},
.hw.init = &(struct clk_init_data){
.name = "mpll_prediv",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll0_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL7, .reg_off = HHI_MPLL_CNTL7,
.shift = 0, .shift = 0,
...@@ -271,26 +376,37 @@ static struct meson_clk_mpll meson8b_mpll0 = { ...@@ -271,26 +376,37 @@ static struct meson_clk_mpll meson8b_mpll0 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 14,
.width = 1,
},
.ssen = { .ssen = {
.reg_off = HHI_MPLL_CNTL, .reg_off = HHI_MPLL_CNTL,
.shift = 25, .shift = 25,
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll0", .name = "mpll0_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
static struct meson_clk_mpll meson8b_mpll1 = { static struct clk_regmap meson8b_mpll0 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL7,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll0",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll0_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mpll1_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL8, .reg_off = HHI_MPLL_CNTL8,
.shift = 0, .shift = 0,
...@@ -306,21 +422,32 @@ static struct meson_clk_mpll meson8b_mpll1 = { ...@@ -306,21 +422,32 @@ static struct meson_clk_mpll meson8b_mpll1 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 14,
.width = 1,
},
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll1", .name = "mpll1_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL8,
.bit_idx = 14,
},
.hw.init = &(struct clk_init_data){
.name = "mpll1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpll1_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
static struct meson_clk_mpll meson8b_mpll2 = { static struct clk_regmap meson8b_mpll2_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = { .sdm = {
.reg_off = HHI_MPLL_CNTL9, .reg_off = HHI_MPLL_CNTL9,
.shift = 0, .shift = 0,
...@@ -336,49 +463,41 @@ static struct meson_clk_mpll meson8b_mpll2 = { ...@@ -336,49 +463,41 @@ static struct meson_clk_mpll meson8b_mpll2 = {
.shift = 16, .shift = 16,
.width = 9, .width = 9,
}, },
.en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 14,
.width = 1,
},
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll2", .name = "mpll2_div",
.ops = &meson_clk_mpll_ops, .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" }, .parent_names = (const char *[]){ "mpll_prediv" },
.num_parents = 1, .num_parents = 1,
}, },
}; };
/* static struct clk_regmap meson8b_mpll2 = {
* FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL .data = &(struct clk_regmap_gate_data){
* post-dividers and should be modeled with their respective PLLs via the .offset = HHI_MPLL_CNTL9,
* forthcoming coordinated clock rates feature .bit_idx = 14,
*/ },
static struct meson_clk_cpu meson8b_cpu_clk = {
.reg_off = HHI_SYS_CPU_CLK_CNTL1,
.div_table = cpu_div_table,
.clk_nb.notifier_call = meson_clk_cpu_notifier_cb,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "cpu_clk", .name = "mpll2",
.ops = &meson_clk_cpu_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "sys_pll" }, .parent_names = (const char *[]){ "mpll2_div" },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}, },
}; };
static u32 mux_table_clk81[] = { 6, 5, 7 }; static u32 mux_table_clk81[] = { 6, 5, 7 };
static struct clk_regmap meson8b_mpeg_clk_sel = {
struct clk_mux meson8b_mpeg_clk_sel = { .data = &(struct clk_regmap_mux_data){
.reg = (void *)HHI_MPEG_CLK_CNTL, .offset = HHI_MPEG_CLK_CNTL,
.mask = 0x7, .mask = 0x7,
.shift = 12, .shift = 12,
.flags = CLK_MUX_READ_ONLY,
.table = mux_table_clk81, .table = mux_table_clk81,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_sel", .name = "mpeg_clk_sel",
.ops = &clk_mux_ro_ops, .ops = &clk_regmap_mux_ro_ops,
/* /*
* FIXME bits 14:12 selects from 8 possible parents: * FIXME bits 14:12 selects from 8 possible parents:
* xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2,
...@@ -387,34 +506,136 @@ struct clk_mux meson8b_mpeg_clk_sel = { ...@@ -387,34 +506,136 @@ struct clk_mux meson8b_mpeg_clk_sel = {
.parent_names = (const char *[]){ "fclk_div3", "fclk_div4", .parent_names = (const char *[]){ "fclk_div3", "fclk_div4",
"fclk_div5" }, "fclk_div5" },
.num_parents = 3, .num_parents = 3,
.flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED),
}, },
}; };
struct clk_divider meson8b_mpeg_clk_div = { struct clk_regmap meson8b_mpeg_clk_div = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_div_data){
.offset = HHI_MPEG_CLK_CNTL,
.shift = 0, .shift = 0,
.width = 7, .width = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpeg_clk_div", .name = "mpeg_clk_div",
.ops = &clk_divider_ops, .ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "mpeg_clk_sel" }, .parent_names = (const char *[]){ "mpeg_clk_sel" },
.num_parents = 1, .num_parents = 1,
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
}, },
}; };
struct clk_gate meson8b_clk81 = { struct clk_regmap meson8b_clk81 = {
.reg = (void *)HHI_MPEG_CLK_CNTL, .data = &(struct clk_regmap_gate_data){
.offset = HHI_MPEG_CLK_CNTL,
.bit_idx = 7, .bit_idx = 7,
.lock = &meson_clk_lock, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "clk81", .name = "clk81",
.ops = &clk_gate_ops, .ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "mpeg_clk_div" }, .parent_names = (const char *[]){ "mpeg_clk_div" },
.num_parents = 1, .num_parents = 1,
.flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), .flags = CLK_IS_CRITICAL,
},
};
struct clk_regmap meson8b_cpu_in_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x1,
.shift = 0,
},
.hw.init = &(struct clk_init_data){
.name = "cpu_in_sel",
.ops = &clk_regmap_mux_ro_ops,
.parent_names = (const char *[]){ "xtal", "sys_pll" },
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT),
},
};
static struct clk_fixed_factor meson8b_cpu_div2 = {
.mult = 1,
.div = 2,
.hw.init = &(struct clk_init_data){
.name = "cpu_div2",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "cpu_in_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_cpu_div3 = {
.mult = 1,
.div = 3,
.hw.init = &(struct clk_init_data){
.name = "cpu_div3",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "cpu_in_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_div_table cpu_scale_table[] = {
{ .val = 2, .div = 4 },
{ .val = 3, .div = 6 },
{ .val = 4, .div = 8 },
{ .val = 5, .div = 10 },
{ .val = 6, .div = 12 },
{ .val = 7, .div = 14 },
{ .val = 8, .div = 16 },
{ /* sentinel */ },
};
struct clk_regmap meson8b_cpu_scale_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.shift = 20,
.width = 9,
.table = cpu_scale_table,
.flags = CLK_DIVIDER_ALLOW_ZERO,
},
.hw.init = &(struct clk_init_data){
.name = "cpu_scale_div",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "cpu_in_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
struct clk_regmap meson8b_cpu_scale_out_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x3,
.shift = 2,
},
.hw.init = &(struct clk_init_data){
.name = "cpu_scale_out_sel",
.ops = &clk_regmap_mux_ro_ops,
.parent_names = (const char *[]) { "cpu_in_sel",
"cpu_div2",
"cpu_div3",
"cpu_scale_div" },
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
},
};
struct clk_regmap meson8b_cpu_clk = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x1,
.shift = 7,
},
.hw.init = &(struct clk_init_data){
.name = "cpu_clk",
.ops = &clk_regmap_mux_ro_ops,
.parent_names = (const char *[]){ "xtal", "cpu_out_sel" },
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT),
}, },
}; };
...@@ -599,24 +820,26 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { ...@@ -599,24 +820,26 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_MPLL0] = &meson8b_mpll0.hw, [CLKID_MPLL0] = &meson8b_mpll0.hw,
[CLKID_MPLL1] = &meson8b_mpll1.hw, [CLKID_MPLL1] = &meson8b_mpll1.hw,
[CLKID_MPLL2] = &meson8b_mpll2.hw, [CLKID_MPLL2] = &meson8b_mpll2.hw,
[CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw,
[CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw,
[CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw,
[CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw,
[CLKID_CPU_DIV2] = &meson8b_cpu_div2.hw,
[CLKID_CPU_DIV3] = &meson8b_cpu_div3.hw,
[CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw,
[CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw,
[CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw,
[CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw,
[CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw,
[CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw,
[CLK_NR_CLKS] = NULL, [CLK_NR_CLKS] = NULL,
}, },
.num = CLK_NR_CLKS, .num = CLK_NR_CLKS,
}; };
static struct meson_clk_pll *const meson8b_clk_plls[] = { static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_fixed_pll,
&meson8b_vid_pll,
&meson8b_sys_pll,
};
static struct meson_clk_mpll *const meson8b_clk_mplls[] = {
&meson8b_mpll0,
&meson8b_mpll1,
&meson8b_mpll2,
};
static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_clk81, &meson8b_clk81,
&meson8b_ddr, &meson8b_ddr,
&meson8b_dos, &meson8b_dos,
...@@ -695,14 +918,27 @@ static struct clk_gate *const meson8b_clk_gates[] = { ...@@ -695,14 +918,27 @@ static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_ao_ahb_sram, &meson8b_ao_ahb_sram,
&meson8b_ao_ahb_bus, &meson8b_ao_ahb_bus,
&meson8b_ao_iface, &meson8b_ao_iface,
};
static struct clk_mux *const meson8b_clk_muxes[] = {
&meson8b_mpeg_clk_sel,
};
static struct clk_divider *const meson8b_clk_dividers[] = {
&meson8b_mpeg_clk_div, &meson8b_mpeg_clk_div,
&meson8b_mpeg_clk_sel,
&meson8b_mpll0,
&meson8b_mpll1,
&meson8b_mpll2,
&meson8b_mpll0_div,
&meson8b_mpll1_div,
&meson8b_mpll2_div,
&meson8b_fixed_pll,
&meson8b_vid_pll,
&meson8b_sys_pll,
&meson8b_cpu_in_sel,
&meson8b_cpu_scale_div,
&meson8b_cpu_scale_out_sel,
&meson8b_cpu_clk,
&meson8b_mpll_prediv,
&meson8b_fclk_div2,
&meson8b_fclk_div3,
&meson8b_fclk_div4,
&meson8b_fclk_div5,
&meson8b_fclk_div7,
}; };
static const struct meson8b_clk_reset_line { static const struct meson8b_clk_reset_line {
...@@ -804,81 +1040,45 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { ...@@ -804,81 +1040,45 @@ static const struct reset_control_ops meson8b_clk_reset_ops = {
.deassert = meson8b_clk_reset_deassert, .deassert = meson8b_clk_reset_deassert,
}; };
static const struct regmap_config clkc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int meson8b_clkc_probe(struct platform_device *pdev) static int meson8b_clkc_probe(struct platform_device *pdev)
{ {
int ret, clkid, i; int ret, i;
struct clk_hw *parent_hw; struct clk *clk;
struct clk *parent_clk;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct regmap *map;
if (!clk_base) if (!clk_base)
return -ENXIO; return -ENXIO;
/* Populate base address for PLLs */ map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config);
for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) if (IS_ERR(map))
meson8b_clk_plls[i]->base = clk_base; return PTR_ERR(map);
/* Populate base address for MPLLs */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++)
meson8b_clk_mplls[i]->base = clk_base;
/* Populate the base address for CPU clk */
meson8b_cpu_clk.base = clk_base;
/* Populate base address for gates */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++)
meson8b_clk_gates[i]->reg = clk_base +
(u32)meson8b_clk_gates[i]->reg;
/* Populate base address for muxes */ /* Populate regmap for the regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++) for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++)
meson8b_clk_muxes[i]->reg = clk_base + meson8b_clk_regmaps[i]->map = map;
(u32)meson8b_clk_muxes[i]->reg;
/* Populate base address for dividers */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++)
meson8b_clk_dividers[i]->reg = clk_base +
(u32)meson8b_clk_dividers[i]->reg;
/* /*
* register all clks * register all clks
* CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
*/ */
for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) {
/* array might be sparse */ /* array might be sparse */
if (!meson8b_hw_onecell_data.hws[clkid]) if (!meson8b_hw_onecell_data.hws[i])
continue; continue;
/* FIXME convert to devm_clk_register */ ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]);
ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]);
if (ret) if (ret)
return ret; return ret;
} }
/* return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
* Register CPU clk notifier
*
* FIXME this is wrong for a lot of reasons. First, the muxes should be
* struct clk_hw objects. Second, we shouldn't program the muxes in
* notifier handlers. The tricky programming sequence will be handled
* by the forthcoming coordinated clock rates mechanism once that
* feature is released.
*
* Furthermore, looking up the parent this way is terrible. At some
* point we will stop allocating a default struct clk when registering
* a new clk_hw, and this hack will no longer work. Releasing the ccr
* feature before that time solves the problem :-)
*/
parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw);
parent_clk = parent_hw->clk;
ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb);
if (ret) {
pr_err("%s: failed to register clock notifier for cpu_clk\n",
__func__);
return ret;
}
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
&meson8b_hw_onecell_data); &meson8b_hw_onecell_data);
} }
......
...@@ -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,
......
...@@ -67,5 +67,6 @@ ...@@ -67,5 +67,6 @@
#define CLKID_AO_I2C 58 #define CLKID_AO_I2C 58
#define CLKID_SD_EMMC_B_CLK0 59 #define CLKID_SD_EMMC_B_CLK0 59
#define CLKID_SD_EMMC_C_CLK0 60 #define CLKID_SD_EMMC_C_CLK0 60
#define CLKID_HIFI_PLL 69
#endif /* __AXG_CLKC_H */ #endif /* __AXG_CLKC_H */
...@@ -399,6 +399,7 @@ struct clk_divider { ...@@ -399,6 +399,7 @@ struct clk_divider {
spinlock_t *lock; spinlock_t *lock;
}; };
#define clk_div_mask(width) ((1 << (width)) - 1)
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#define CLK_DIVIDER_ONE_BASED BIT(0) #define CLK_DIVIDER_ONE_BASED BIT(0)
...@@ -419,6 +420,10 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, ...@@ -419,6 +420,10 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate, unsigned long *prate, unsigned long rate, unsigned long *prate,
const struct clk_div_table *table, const struct clk_div_table *table,
u8 width, unsigned long flags); u8 width, unsigned long flags);
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 divider_get_val(unsigned long rate, unsigned long parent_rate, int divider_get_val(unsigned long rate, unsigned long parent_rate,
const struct clk_div_table *table, u8 width, const struct clk_div_table *table, u8 width,
unsigned long flags); unsigned long flags);
...@@ -449,8 +454,9 @@ void clk_hw_unregister_divider(struct clk_hw *hw); ...@@ -449,8 +454,9 @@ void clk_hw_unregister_divider(struct clk_hw *hw);
* *
* @hw: handle between common and hardware-specific interfaces * @hw: handle between common and hardware-specific interfaces
* @reg: register controlling multiplexer * @reg: register controlling multiplexer
* @table: array of register values corresponding to the parent index
* @shift: shift to multiplexer bit field * @shift: shift to multiplexer bit field
* @width: width of mutliplexer bit field * @mask: mask of mutliplexer bit field
* @flags: hardware-specific flags * @flags: hardware-specific flags
* @lock: register lock * @lock: register lock
* *
...@@ -510,6 +516,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, ...@@ -510,6 +516,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
void __iomem *reg, u8 shift, u32 mask, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock); u8 clk_mux_flags, u32 *table, spinlock_t *lock);
int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
unsigned int val);
unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
void clk_unregister_mux(struct clk *clk); void clk_unregister_mux(struct clk *clk);
void clk_hw_unregister_mux(struct clk_hw *hw); void clk_hw_unregister_mux(struct clk_hw *hw);
...@@ -774,6 +784,17 @@ static inline long divider_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -774,6 +784,17 @@ static inline long divider_round_rate(struct clk_hw *hw, unsigned long rate,
rate, prate, table, width, flags); rate, prate, table, width, flags);
} }
static inline long divider_ro_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate,
const struct clk_div_table *table,
u8 width, unsigned long flags,
unsigned int val)
{
return divider_ro_round_rate_parent(hw, clk_hw_get_parent(hw),
rate, prate, table, width, flags,
val);
}
/* /*
* FIXME clock api without lock protection * FIXME clock api without lock protection
*/ */
......
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