diff options
author | Stephen Boyd <sboyd@kernel.org> | 2018-03-14 23:16:23 +0100 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-03-14 23:16:23 +0100 |
commit | 186dcd4ab2400d2d97329dbb515b9648151fedba (patch) | |
tree | a935c47e31f186223cf3ce735537d2600db3c415 /drivers/clk | |
parent | Linux 4.16-rc1 (diff) | |
parent | clk: meson: clean-up clk81 clocks (diff) | |
download | linux-186dcd4ab2400d2d97329dbb515b9648151fedba.tar.xz linux-186dcd4ab2400d2d97329dbb515b9648151fedba.zip |
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
...
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/clk-divider.c | 58 | ||||
-rw-r--r-- | drivers/clk/clk-mux.c | 75 | ||||
-rw-r--r-- | drivers/clk/clk.c | 63 | ||||
-rw-r--r-- | drivers/clk/meson/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/meson/Makefile | 5 | ||||
-rw-r--r-- | drivers/clk/meson/axg.c | 955 | ||||
-rw-r--r-- | drivers/clk/meson/axg.h | 12 | ||||
-rw-r--r-- | drivers/clk/meson/clk-audio-divider.c | 63 | ||||
-rw-r--r-- | drivers/clk/meson/clk-cpu.c | 178 | ||||
-rw-r--r-- | drivers/clk/meson/clk-mpll.c | 125 | ||||
-rw-r--r-- | drivers/clk/meson/clk-pll.c | 306 | ||||
-rw-r--r-- | drivers/clk/meson/clk-regmap.c | 166 | ||||
-rw-r--r-- | drivers/clk/meson/clk-regmap.h | 111 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 107 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb-aoclk-regmap.c | 46 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb-aoclk.c | 20 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb-aoclk.h | 11 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 1591 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.h | 14 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.c | 706 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.h | 17 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-regmap-divider.c | 20 |
22 files changed, 2583 insertions, 2075 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b49942b9fe50..b6234a5da12d 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -28,12 +28,10 @@ * 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, 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; for (clkt = table; clkt->div; clkt++) @@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, unsigned long flags) { if (flags & CLK_DIVIDER_ONE_BASED) - return div_mask(width); + return clk_div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) - return 1 << div_mask(width); + return 1 << clk_div_mask(width); if (table) 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, @@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) - return val ? val : div_mask(width) + 1; + return val ? val : clk_div_mask(width) + 1; if (table) return _get_table_div(table, val); return val + 1; @@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return __ffs(div); 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) return _get_table_val(table, div); return div - 1; @@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, unsigned int val; 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, divider->flags, divider->width); @@ -344,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *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, unsigned long *prate) { struct clk_divider *divider = to_clk_divider(hw); - int bestdiv; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = clk_readl(divider->reg) >> divider->shift; - bestdiv &= div_mask(divider->width); - bestdiv = _get_div(divider->table, bestdiv, divider->flags, - divider->width); - return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + u32 val; + + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); } return divider_round_rate(hw, rate, prate, divider->table, @@ -376,7 +398,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, 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); @@ -399,10 +421,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, __acquire(divider->lock); 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 { 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; clk_writel(val, divider->reg); diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 39cabe157163..ac4a042f8658 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -26,35 +26,24 @@ * 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); - 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; for (i = 0; i < num_parents; i++) - if (mux->table[i] == val) + if (table[i] == val) return i; return -EINVAL; } - if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + if (val && (flags & CLK_MUX_INDEX_BIT)) val = ffs(val) - 1; - if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + if (val && (flags & CLK_MUX_INDEX_ONE)) val--; if (val >= num_parents) @@ -62,36 +51,58 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) 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); - u32 val; - unsigned long flags = 0; + unsigned int val = index; - if (mux->table) { - index = mux->table[index]; + if (table) { + val = table[index]; } else { - if (mux->flags & CLK_MUX_INDEX_BIT) - index = 1 << index; + if (flags & CLK_MUX_INDEX_BIT) + val = 1 << index; - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; + if (flags & CLK_MUX_INDEX_ONE) + 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) spin_lock_irqsave(mux->lock, flags); else __acquire(mux->lock); if (mux->flags & CLK_MUX_HIWORD_MASK) { - val = mux->mask << (mux->shift + 16); + reg = mux->mask << (mux->shift + 16); } else { - val = clk_readl(mux->reg); - val &= ~(mux->mask << mux->shift); + reg = clk_readl(mux->reg); + reg &= ~(mux->mask << mux->shift); } - val |= index << mux->shift; - clk_writel(val, mux->reg); + val = val << mux->shift; + reg |= val; + clk_writel(reg, mux->reg); if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0f686a9dac3e..9d56be6ead39 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1125,8 +1125,10 @@ static int clk_core_round_rate_nolock(struct clk_core *core, { lockdep_assert_held(&prepare_lock); - if (!core) + if (!core) { + req->rate = 0; return 0; + } clk_core_init_rate_req(core, req); @@ -2928,6 +2930,17 @@ static int __clk_core_init(struct clk_core *core) } /* + * 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 * .recalc_accuracy. For simple clocks and lazy developers the default * fallback is to use the parent's accuracy. If a clock doesn't have a @@ -2968,48 +2981,42 @@ static int __clk_core_init(struct clk_core *core) 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 * parent. */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); - unsigned long flags; /* - * we could call __clk_set_parent, but that would result in a - * redundant call to the .set_rate op, if it exists + * We need to use __clk_set_parent_before() and _after() to + * 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) { /* update the clk tree topology */ - flags = clk_enable_lock(); - clk_reparent(orphan, parent); - clk_enable_unlock(flags); + __clk_set_parent_before(orphan, parent); + __clk_set_parent_after(orphan, parent, NULL); __clk_recalc_accuracies(orphan); __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); out: clk_pm_runtime_put(core); diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 7694302c70a4..d5cbec522aec 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -3,10 +3,15 @@ config COMMON_CLK_AMLOGIC depends on OF depends on ARCH_MESON || COMPILE_TEST +config COMMON_CLK_REGMAP_MESON + bool + select REGMAP + config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you @@ -16,6 +21,8 @@ config COMMON_CLK_GXBB bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. Say Y if you want peripherals and CPU frequency scaling to work. @@ -24,6 +31,8 @@ config COMMON_CLK_AXG bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 3c03ce583798..ffee82e60b7a 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,7 +2,8 @@ # 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_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_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 1294f3ad7cd5..99b2738c204f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -11,125 +11,51 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/mfd/syscon.h> #include <linux/platform_device.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "axg.h" 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 struct meson_clk_pll axg_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap axg_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .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, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -138,25 +64,34 @@ static struct meson_clk_pll axg_fixed_pll = { }, }; -static struct meson_clk_pll axg_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap axg_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -257,40 +192,51 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct pll_params_table axg_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), -}; - -static struct meson_clk_pll axg_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = axg_gp0_params_table, - .params_count = ARRAY_SIZE(axg_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, - }, - .rate_table = axg_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), - .lock = &meson_clk_lock, +const struct reg_sequence axg_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap axg_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .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), + }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -299,234 +245,427 @@ 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_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 = { +static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap axg_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap axg_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .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, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap axg_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .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){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, +static struct clk_regmap axg_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap axg_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 1, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, +static struct clk_regmap axg_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap axg_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll3 = { - .sdm = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 12, - .width = 14, +static struct clk_regmap axg_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 11, - .width = 1, + .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 struct clk_regmap axg_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 12, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 11, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 2, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 3, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .n2 = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 2, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, }, - .en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 0, - .width = 1, +}; + +static struct clk_regmap axg_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL3_CNTL0, + .bit_idx = 0, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll3", - .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll3_div" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; -static struct clk_mux axg_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, .parent_names = clk81_parent_names, .num_parents = ARRAY_SIZE(clk81_parent_names), }, }; -static struct clk_divider axg_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), @@ -545,42 +684,45 @@ static const char * const axg_sd_emmc_clk0_parent_names[] = { }; /* SDcard clock */ -static struct clk_mux axg_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider axg_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -588,42 +730,45 @@ static struct clk_gate axg_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux axg_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider axg_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -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_DIV] = &axg_sd_emmc_c_clk0_div.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, }, .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -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[] = { +/* Convenience table to populate regmap in .probe */ +static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, &axg_audio_locker, @@ -818,113 +960,100 @@ static struct clk_gate *const axg_clk_gates[] = { &axg_ao_i2c, &axg_sd_emmc_b_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_sd_emmc_b_clk0_div, &axg_sd_emmc_c_clk0_div, -}; - -struct clkc_data { - struct clk_gate *const *clk_gates; - unsigned int clk_gates_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 clk_hw_onecell_data *hw_onecell_data; -}; - -static const struct clkc_data axg_clkc_data = { - .clk_gates = axg_clk_gates, - .clk_gates_count = ARRAY_SIZE(axg_clk_gates), - .clk_mplls = axg_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), - .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, + &axg_mpeg_clk_sel, + &axg_sd_emmc_b_clk0_sel, + &axg_sd_emmc_c_clk0_sel, + &axg_mpll0, + &axg_mpll1, + &axg_mpll2, + &axg_mpll3, + &axg_mpll0_div, + &axg_mpll1_div, + &axg_mpll2_div, + &axg_mpll3_div, + &axg_fixed_pll, + &axg_sys_pll, + &axg_gp0_pll, + &axg_hifi_pll, + &axg_mpll_prediv, + &axg_fclk_div2, + &axg_fclk_div3, + &axg_fclk_div4, + &axg_fclk_div5, + &axg_fclk_div7, }; 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) { struct device *dev = &pdev->dev; - const struct clkc_data *clkc_data; struct resource *res; - void __iomem *clk_base; - int ret, clkid, i; - - clkc_data = of_device_get_match_data(&pdev->dev); - if (!clkc_data) - return -EINVAL; - - /* Generic clocks and PLLs */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - clk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!clk_base) { - dev_err(&pdev->dev, "Unable to map clk base\n"); - return -ENXIO; - } + void __iomem *clk_base = NULL; + struct regmap *map; + int ret, i; - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; + /* Get the hhi system controller node if available */ + 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"); - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; + /* + * 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; - /* 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; + clk_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } + + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + } - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) + axg_clk_regmaps[i]->map = map; - 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 */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!axg_hw_onecell_data.hws[i]) continue; - ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); + ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]); if (ret) { - dev_err(&pdev->dev, "Clock registration failed\n"); + dev_err(dev, "Clock registration failed\n"); return ret; } } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &axg_hw_onecell_data); } static struct platform_driver axg_driver = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index ce0bafdb6b28..b421df6a7ea0 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -117,8 +117,18 @@ #define CLKID_SD_EMMC_B_CLK0_DIV 62 #define CLKID_SD_EMMC_C_CLK0_SEL 63 #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 <dt-bindings/clock/axg-clkc.h> diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c index 6c07db06642d..f7ab5b1db342 100644 --- a/drivers/clk/meson/clk-audio-divider.c +++ b/drivers/clk/meson/clk-audio-divider.c @@ -28,8 +28,11 @@ #include <linux/clk-provider.h> #include "clkc.h" -#define to_meson_clk_audio_divider(_hw) container_of(_hw, \ - struct meson_clk_audio_divider, hw) +static inline struct meson_clk_audio_div_data * +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, unsigned long flags) @@ -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; } -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 = - to_meson_clk_audio_divider(hw); - int max_divider; - u8 width; - - width = adiv->div.width; - max_divider = 1 << width; + int max_divider = 1 << width; return clamp(divider, 1, max_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, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, divider; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + unsigned long divider; - p = &adiv->div; - reg = readl(adiv->base + p->reg_off); - divider = PARM_GET(p->width, p->shift, reg) + 1; + divider = meson_parm_read(clk->map, &adiv->div); return DIV_ROUND_UP_ULL((u64)parent_rate, divider); } @@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); unsigned long max_prate; int divider; if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { 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); } @@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw, /* Get the corresponding rounded down divider */ divider = max_prate / rate; - divider = _valid_divider(hw, divider); + divider = _valid_divider(adiv->div.width, divider); /* Get actual rate of the parent */ *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, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, flags = 0; - int 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); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + int val = _get_val(parent_rate, rate); + + meson_parm_write(clk->map, &adiv->div, val); return 0; } diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c deleted file mode 100644 index f8b2b7efd016..000000000000 --- a/drivers/clk/meson/clk-cpu.c +++ /dev/null @@ -1,178 +0,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, -}; diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 5144360e2c80..0df1227b65b3 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -68,11 +68,15 @@ #define N2_MIN 4 #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, - unsigned long sdm, - unsigned long n2) + unsigned int sdm, + unsigned int n2) { unsigned long divisor = (SDM_DEN * n2) + sdm; @@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate, static void params_from_rate(unsigned long requested_rate, unsigned long parent_rate, - unsigned long *sdm, - unsigned long *n2) + unsigned int *sdm, + unsigned int *n2) { uint64_t div = parent_rate; unsigned long rem = do_div(div, 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, unsigned long parent_rate) { - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg, sdm, n2; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; long rate; - p = &mpll->sdm; - reg = readl(mpll->base + p->reg_off); - 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); + sdm = meson_parm_read(clk->map, &mpll->sdm); + n2 = meson_parm_read(clk->map, &mpll->n2); rate = rate_from_params(parent_rate, sdm, n2); - if (rate < 0) - return 0; - - return rate; + return rate < 0 ? 0 : rate; } static long mpll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - unsigned long sdm, n2; + unsigned int sdm, n2; params_from_rate(rate, *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, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg, sdm, n2; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; unsigned long flags = 0; params_from_rate(rate, parent_rate, &sdm, &n2); @@ -151,97 +147,36 @@ static int mpll_set_rate(struct clk_hw *hw, else __acquire(mpll->lock); - p = &mpll->sdm; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, sdm); - 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; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, n2); - writel(reg, mpll->base + p->reg_off); - - if (mpll->lock) - spin_unlock_irqrestore(mpll->lock, flags); - else - __release(mpll->lock); - - return 0; -} + /* Enable and set the fractional part */ + meson_parm_write(clk->map, &mpll->sdm, sdm); + meson_parm_write(clk->map, &mpll->sdm_en, 1); -static void mpll_enable_core(struct clk_hw *hw, int enable) -{ - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg; - unsigned long flags = 0; + /* Set additional fractional part enable if required */ + if (MESON_PARM_APPLICABLE(&mpll->ssen)) + meson_parm_write(clk->map, &mpll->ssen, 1); - if (mpll->lock) - spin_lock_irqsave(mpll->lock, flags); - else - __acquire(mpll->lock); + /* Set the integer divider part */ + meson_parm_write(clk->map, &mpll->n2, n2); - 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); + /* Set the magic misc bit if required */ + if (MESON_PARM_APPLICABLE(&mpll->misc)) + meson_parm_write(clk->map, &mpll->misc, 1); if (mpll->lock) spin_unlock_irqrestore(mpll->lock, flags); else __release(mpll->lock); -} - - -static int mpll_enable(struct clk_hw *hw) -{ - mpll_enable_core(hw, 1); 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 = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, - .is_enabled = mpll_is_enabled, }; const struct clk_ops meson_clk_mpll_ops = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, .set_rate = mpll_set_rate, - .enable = mpll_enable, - .disable = mpll_disable, - .is_enabled = mpll_is_enabled, }; diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 01341553f50b..65a7bd903551 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -2,6 +2,9 @@ * Copyright (c) 2015 Endless Mobile, Inc. * 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 * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -27,13 +30,14 @@ * | | * FREF VCO * - * out = (in * M / N) >> OD + * out = in * (m + frac / frac_max) / (n << sum(ods)) */ #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/slab.h> @@ -41,209 +45,213 @@ #include "clkc.h" -#define MESON_PLL_RESET BIT(29) -#define MESON_PLL_LOCK BIT(31) - -#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) - -static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static inline struct meson_clk_pll_data * +meson_clk_pll_data(struct clk_regmap *clk) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; - unsigned long parent_rate_mhz = parent_rate / 1000000; - unsigned long rate_mhz; - u16 n, m, frac = 0, od, od2 = 0; - u32 reg; - - p = &pll->n; - 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; - 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; + return (struct meson_clk_pll_data *)clk->data; } -static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static unsigned long __pll_params_to_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); - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + u64 rate = (u64)parent_rate * pllt->m; + unsigned int od = pllt->od + pllt->od2 + pllt->od3; - for (i = 0; i < pll->rate_count; i++) { - if (rate <= rate_table[i].rate) - return rate_table[i].rate; + if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { + u64 frac_rate = (u64)parent_rate * frac; + + rate += DIV_ROUND_UP_ULL(frac_rate, + (1 << pll->frac.width)); } - /* else return the smallest value */ - return rate_table[0].rate; + return DIV_ROUND_UP_ULL(rate, pllt->n << od); } -static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, - unsigned long rate) +static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + struct pll_rate_table pllt; + u16 frac; - for (i = 0; i < pll->rate_count; i++) { - if (rate == rate_table[i].rate) - return &rate_table[i]; - } - return NULL; + pllt.n = meson_parm_read(clk->map, &pll->n); + pllt.m = meson_parm_read(clk->map, &pll->m); + 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; + + frac = MESON_PARM_APPLICABLE(&pll->frac) ? + meson_parm_read(clk->map, &pll->frac) : + 0; + + return __pll_params_to_rate(parent_rate, &pllt, frac, pll); } -/* Specific wait loop for GXL/GXM GP0 PLL */ -static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, - struct parm *p_n) +static u16 __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + const struct pll_rate_table *pllt, + struct meson_clk_pll_data *pll) { - int delay = 100; - u32 reg; + u16 frac_max = (1 << pll->frac.width); + u64 val = (u64)rate * pllt->n; - while (delay > 0) { - reg = readl(pll->base + p_n->reg_off); - writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); - udelay(10); - writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); + val <<= pllt->od + pllt->od2 + pllt->od3; - /* This delay comes from AMLogic tree clk-gp0-gxl driver */ - mdelay(1); + if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) + val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); + else + val = div_u64(val * frac_max, parent_rate); - reg = readl(pll->base + p_n->reg_off); - if (reg & MESON_PLL_LOCK) - return 0; - delay--; + val -= pllt->m * frac_max; + + return min((u16)val, (u16)(frac_max - 1)); +} + +static const struct pll_rate_table * +meson_clk_get_pll_settings(unsigned long rate, + struct meson_clk_pll_data *pll) +{ + const struct pll_rate_table *table = pll->table; + unsigned int i = 0; + + if (!table) + return NULL; + + /* Find the first table element exceeding rate */ + while (table[i].rate && table[i].rate <= rate) + i++; + + if (i != 0) { + if (MESON_PARM_APPLICABLE(&pll->frac) || + !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + (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, - struct parm *p_n) +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { - int delay = 24000000; - u32 reg; + struct clk_regmap *clk = to_clk_regmap(hw); + 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) { - reg = readl(pll->base + p_n->reg_off); +static int meson_clk_pll_wait_lock(struct clk_hw *hw) +{ + 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; + delay--; - } + } while (delay > 0); + 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; - - for (i = 0 ; i < pll->params.params_count ; ++i) - writel(pll->params.params_table[i].value, - pll->base + pll->params.params_table[i].reg_off); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + if (pll->init_count) { + 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, unsigned long parent_rate) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; - const struct pll_rate_table *rate_set; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt; unsigned long old_rate; - int ret = 0; - u32 reg; + u16 frac = 0; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - rate_set = meson_clk_get_pll_settings(pll, rate); - if (!rate_set) + pllt = meson_clk_get_pll_settings(rate, pll); + if (!pllt) return -EINVAL; - /* Initialize the PLL in a clean state if specified */ - if (pll->params.params_count) - 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); - } + /* Put the pll in reset to write the params */ + meson_parm_write(clk->map, &pll->rst, 1); - p = &pll->frac; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); - writel(reg, pll->base + p->reg_off); - } + meson_parm_write(clk->map, &pll->n, pllt->n); + meson_parm_write(clk->map, &pll->m, pllt->m); + meson_parm_write(clk->map, &pll->od, pllt->od); + + if (MESON_PARM_APPLICABLE(&pll->od2)) + meson_parm_write(clk->map, &pll->od2, pllt->od2); + + if (MESON_PARM_APPLICABLE(&pll->od3)) + meson_parm_write(clk->map, &pll->od3, pllt->od3); - p = &pll->n; - /* If clear_reset_for_lock is provided, remove the reset bit here */ - if (pll->params.clear_reset_for_lock) { - reg = readl(pll->base + p->reg_off); - writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); + 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 */ - if (pll->params.reset_lock_loop) - ret = meson_clk_pll_wait_lock_reset(pll, p); - else - ret = meson_clk_pll_wait_lock(pll, p); - if (ret) { + /* make sure the reset is cleared at this point */ + meson_parm_write(clk->map, &pll->rst, 0); + + if (meson_clk_pll_wait_lock(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __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); } - return ret; + return 0; } const struct clk_ops meson_clk_pll_ops = { + .init = meson_clk_pll_init, .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c new file mode 100644 index 000000000000..3645fdb62343 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.c @@ -0,0 +1,166 @@ +// 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); diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h new file mode 100644 index 000000000000..627c888026d7 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.h @@ -0,0 +1,111 @@ +// 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 */ diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index c2ff0520ce53..8fe73c4edca8 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -18,6 +18,9 @@ #ifndef __CLKC_H #define __CLKC_H +#include <linux/clk-provider.h> +#include "clk-regmap.h" + #define PMASK(width) GENMASK(width - 1, 0) #define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) #define CLRPMASK(width, shift) (~SETPMASK(width, shift)) @@ -35,13 +38,29 @@ struct parm { 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 { unsigned long rate; u16 m; u16 n; u16 od; u16 od2; - u16 frac; + u16 od3; }; #define PLL_RATE(_r, _m, _n, _od) \ @@ -50,97 +69,53 @@ struct pll_rate_table { .m = (_m), \ .n = (_n), \ .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 { - 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; -}; +#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) -struct meson_clk_pll { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_pll_data { struct parm m; struct parm n; struct parm frac; struct parm od; struct parm od2; - const struct pll_setup_params params; - const struct pll_rate_table *rate_table; - unsigned int rate_count; - spinlock_t *lock; + struct parm od3; + struct parm l; + struct parm rst; + 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) -struct meson_clk_cpu { - 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 meson_clk_mpll_data { struct parm sdm; struct parm sdm_en; struct parm n2; - struct parm en; struct parm ssen; + struct parm misc; spinlock_t *lock; }; -struct meson_clk_audio_divider { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_audio_div_data { struct parm div; u8 flags; - spinlock_t *lock; }; #define MESON_GATE(_name, _reg, _bit) \ -struct clk_gate _name = { \ - .reg = (void __iomem *) _reg, \ - .bit_idx = (_bit), \ - .lock = &meson_clk_lock, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &clk_gate_ops, \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ }, \ }; diff --git a/drivers/clk/meson/gxbb-aoclk-regmap.c b/drivers/clk/meson/gxbb-aoclk-regmap.c deleted file mode 100644 index 2515fbfa0467..000000000000 --- a/drivers/clk/meson/gxbb-aoclk-regmap.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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, -}; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 6c161e0a8e59..9ec23ae9a219 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -62,10 +62,9 @@ #include <linux/delay.h> #include <dt-bindings/clock/gxbb-aoclkc.h> #include <dt-bindings/reset/gxbb-aoclkc.h> +#include "clk-regmap.h" #include "gxbb-aoclk.h" -static DEFINE_SPINLOCK(gxbb_aoclk_lock); - struct gxbb_aoclk_reset_controller { struct reset_controller_dev reset; unsigned int *data; @@ -87,12 +86,14 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = { }; #define GXBB_AO_GATE(_name, _bit) \ -static struct aoclk_gate_regmap _name##_ao = { \ - .bit_idx = (_bit), \ - .lock = &gxbb_aoclk_lock, \ +static struct clk_regmap _name##_ao = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = AO_RTI_GEN_CNTL_REG0, \ + .bit_idx = (_bit), \ + }, \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ - .ops = &meson_aoclk_gate_regmap_ops, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ @@ -107,7 +108,6 @@ GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); static struct aoclk_cec_32k cec_32k_ao = { - .lock = &gxbb_aoclk_lock, .hw.init = &(struct clk_init_data) { .name = "cec_32k_ao", .ops = &meson_aoclk_cec_32k_ops, @@ -126,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = { [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_I2C_MASTER] = &i2c_master_ao, [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, @@ -177,10 +177,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) * Populate regmap and register all clks */ 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, - gxbb_aoclk_onecell_data.hws[clkid]); + gxbb_aoclk_onecell_data.hws[clkid]); if (ret) return ret; } diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index e8604c8f7eee..0be78383f257 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -17,22 +17,11 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #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; struct aoclk_cec_32k { struct clk_hw hw; struct regmap *regmap; - spinlock_t *lock; }; #define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index af24455af5b4..db5e0dcbb5aa 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -19,108 +19,19 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/mfd/syscon.h> #include <linux/platform_device.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "gxbb.h" +#include "clk-regmap.h" 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[] = { PLL_RATE(96000000, 32, 1, 3), PLL_RATE(99000000, 33, 1, 3), @@ -278,23 +189,39 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct meson_clk_pll gxbb_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .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, + }, }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -304,33 +231,118 @@ static struct meson_clk_pll gxbb_fixed_pll = { }, }; -static struct meson_clk_pll gxbb_hdmi_pll = { - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, +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, }, - .frac = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 0, - .width = 12, +}; + +static struct clk_regmap gxbb_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 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + }, + .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, + }, }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 16, - .width = 2, + .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, }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 22, - .width = 2, +}; + +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, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, @@ -340,25 +352,34 @@ static struct meson_clk_pll gxbb_hdmi_pll = { }, }; -static struct meson_clk_pll gxbb_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -368,38 +389,44 @@ static struct meson_clk_pll gxbb_sys_pll = { }, }; -struct pll_params_table gxbb_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), -}; - -static struct meson_clk_pll gxbb_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = gxbb_gp0_params_table, - .params_count = ARRAY_SIZE(gxbb_gp0_params_table), - .no_init_reset = true, - .clear_reset_for_lock = true, +const struct reg_sequence gxbb_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, +}; + +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .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){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -409,40 +436,51 @@ static struct meson_clk_pll gxbb_gp0_pll = { }, }; -struct pll_params_table gxl_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), -}; - -static struct meson_clk_pll gxl_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, +const struct reg_sequence gxl_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap gxl_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .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), }, - .params = { - .params_table = gxl_gp0_params_table, - .params_count = ARRAY_SIZE(gxl_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, - }, - .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){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -452,161 +490,267 @@ 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, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap gxbb_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap gxbb_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .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, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, +static struct clk_regmap gxbb_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, +static struct clk_regmap gxbb_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ +static struct clk_regmap gxbb_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, + .flags = CLK_SET_RATE_PARENT, + }, +}; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { @@ -614,16 +758,16 @@ static const char * const clk81_parent_names[] = { "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -631,72 +775,75 @@ static struct clk_mux gxbb_mpeg_clk_sel = { */ .parent_names = 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 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; -/* the mother of dragons^W gates */ -static struct clk_gate gxbb_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +/* the mother of dragons gates */ +static struct clk_regmap gxbb_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + .flags = CLK_IS_CRITICAL, }, }; -static struct clk_mux gxbb_sar_adc_clk_sel = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SAR_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .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 */ .parent_names = (const char *[]){ "xtal", "clk81", }, .num_parents = 2, }, }; -static struct clk_divider gxbb_sar_adc_clk_div = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .shift = 0, - .width = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SAR_CLK_CNTL, + .shift = 0, + .width = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sar_adc_clk_sel" }, .num_parents = 1, }, }; -static struct clk_gate gxbb_sar_adc_clk = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SAR_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sar_adc_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -708,21 +855,20 @@ static struct clk_gate gxbb_sar_adc_clk = { * 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[] = { "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mali_0_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -734,42 +880,44 @@ static struct clk_mux gxbb_mali_0_sel = { }, }; -static struct clk_divider gxbb_mali_0_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_gate gxbb_mali_0 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_mali_1_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -781,77 +929,79 @@ static struct clk_mux gxbb_mali_1_sel = { }, }; -static struct clk_divider gxbb_mali_1_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_gate gxbb_mali_1 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static u32 mux_table_mali[] = {0, 1}; static const char * const gxbb_mali_parent_names[] = { "mali_0", "mali_1" }; -static struct clk_mux gxbb_mali = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 1, - .shift = 31, - .table = mux_table_mali, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "mali", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_mali_parent_names, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_mux gxbb_cts_amclk_sel = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .mask = 0x3, - .shift = 9, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_amclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .table = (u32[]){ 1, 2, 3 }, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, }, }; -static struct meson_clk_audio_divider gxbb_cts_amclk_div = { - .div = { - .reg_off = HHI_AUD_CLK_CNTL, - .shift = 0, - .width = 8, +static struct clk_regmap gxbb_cts_amclk_div = { + .data = &(struct meson_clk_audio_div_data){ + .div = { + .reg_off = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .flags = CLK_DIVIDER_ROUND_CLOSEST, }, - .flags = CLK_DIVIDER_ROUND_CLOSEST, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &meson_clk_audio_divider_ops, @@ -861,71 +1011,75 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { }, }; -static struct clk_gate gxbb_cts_amclk = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_amclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_amclk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_cts_mclk_i958_sel = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x3, - .shift = 25, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .table = (u32[]){ 1, 2, 3 }, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_cts_mclk_i958_div = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .shift = 16, - .width = 8, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_cts_mclk_i958_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_cts_mclk_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_mclk_i958_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_cts_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x1, - .shift = 27, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_i958 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_i958", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, .num_parents = 2, /* @@ -936,27 +1090,29 @@ static struct clk_mux gxbb_cts_i958 = { }, }; -static struct clk_divider gxbb_32k_clk_div = { - .reg = (void *)HHI_32K_CLK_CNTL, - .shift = 0, - .width = 14, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_32K_CLK_CNTL, + .shift = 0, + .width = 14, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "32k_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, }, }; -static struct clk_gate gxbb_32k_clk = { - .reg = (void *)HHI_32K_CLK_CNTL, - .bit_idx = 15, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_32K_CLK_CNTL, + .bit_idx = 15, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "32k_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -967,14 +1123,15 @@ static const char * const gxbb_32k_clk_parent_names[] = { "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_32k_clk_sel = { - .reg = (void *)HHI_32K_CLK_CNTL, - .mask = 0x3, - .shift = 16, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_32k_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_32K_CLK_CNTL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ .name = "32k_clk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_32k_clk_parent_names, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, @@ -993,42 +1150,45 @@ static const char * const gxbb_sd_emmc_clk0_parent_names[] = { }; /* SDIO clock */ -static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_a_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_a_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1036,42 +1196,45 @@ static struct clk_gate gxbb_sd_emmc_a_clk0 = { }; /* SDcard clock */ -static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1079,42 +1242,45 @@ static struct clk_gate gxbb_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1123,20 +1289,19 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = { /* VPU Clock */ -static u32 mux_table_vpu[] = {0, 1, 2, 3}; static const char * const gxbb_vpu_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vpu_0_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1147,42 +1312,44 @@ static struct clk_mux gxbb_vpu_0_sel = { }, }; -static struct clk_divider gxbb_vpu_0_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vpu_0 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vpu_1_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1193,41 +1360,44 @@ static struct clk_mux gxbb_vpu_1_sel = { }, }; -static struct clk_divider gxbb_vpu_1_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vpu_1 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vpu = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vpu", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vpu_0 or vpu_1 @@ -1240,20 +1410,19 @@ static struct clk_mux gxbb_vpu = { /* VAPB Clock */ -static u32 mux_table_vapb[] = {0, 1, 2, 3}; static const char * const gxbb_vapb_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vapb_0_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1264,42 +1433,44 @@ static struct clk_mux gxbb_vapb_0_sel = { }, }; -static struct clk_divider gxbb_vapb_0_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vapb_0 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vapb_1_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1310,41 +1481,44 @@ static struct clk_mux gxbb_vapb_1_sel = { }, }; -static struct clk_divider gxbb_vapb_1_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vapb_1 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vapb_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vapb_0 or vapb_1 @@ -1355,13 +1529,14 @@ static struct clk_mux gxbb_vapb_sel = { }, }; -static struct clk_gate gxbb_vapb = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 30, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, .hw.init = &(struct clk_init_data) { .name = "vapb", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1601,6 +1776,16 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.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, }, .num = NR_CLKS, @@ -1609,7 +1794,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { static struct clk_hw_onecell_data gxl_hw_onecell_data = { .hws = { [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_FCLK_DIV2] = &gxbb_fclk_div2.hw, [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, @@ -1748,34 +1933,31 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.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, }, .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -static struct meson_clk_pll *const gxbb_clk_plls[] = { - &gxbb_fixed_pll, - &gxbb_hdmi_pll, - &gxbb_sys_pll, +static struct clk_regmap *const gxbb_clk_regmaps[] = { &gxbb_gp0_pll, -}; - -static struct meson_clk_pll *const gxl_clk_plls[] = { - &gxbb_fixed_pll, &gxbb_hdmi_pll, - &gxbb_sys_pll, - &gxl_gp0_pll, }; -static struct meson_clk_mpll *const gxbb_clk_mplls[] = { - &gxbb_mpll0, - &gxbb_mpll1, - &gxbb_mpll2, +static struct clk_regmap *const gxl_clk_regmaps[] = { + &gxl_gp0_pll, + &gxl_hdmi_pll, }; -static struct clk_gate *const gxbb_clk_gates[] = { +static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_clk81, &gxbb_ddr, &gxbb_dos, @@ -1872,9 +2054,19 @@ static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_vapb_0, &gxbb_vapb_1, &gxbb_vapb, -}; - -static struct clk_mux *const gxbb_clk_muxes[] = { + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &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_sar_adc_clk_sel, &gxbb_mali_0_sel, @@ -1893,73 +2085,38 @@ static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_vapb_0_sel, &gxbb_vapb_1_sel, &gxbb_vapb_sel, -}; - -static struct clk_divider *const gxbb_clk_dividers[] = { - &gxbb_mpeg_clk_div, - &gxbb_sar_adc_clk_div, - &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, -}; - -static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { + &gxbb_mpll0, + &gxbb_mpll1, + &gxbb_mpll2, + &gxbb_mpll0_div, + &gxbb_mpll1_div, + &gxbb_mpll2_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 clk_gate *const *clk_gates; - unsigned int clk_gates_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_regmap *const *regmap_clks; + unsigned int regmap_clks_count; struct clk_hw_onecell_data *hw_onecell_data; }; static const struct clkc_data gxbb_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), - .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), + .regmap_clks = gxbb_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps), .hw_onecell_data = &gxbb_hw_onecell_data, }; static const struct clkc_data gxl_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), - .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), + .regmap_clks = gxl_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps), .hw_onecell_data = &gxl_hw_onecell_data, }; @@ -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) { const struct clkc_data *clkc_data; + struct resource *res; void __iomem *clk_base; - int ret, clkid, i; + struct regmap *map; + int ret, i; 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) return -EINVAL; - /* Generic clocks and PLLs */ - clk_base = of_iomap(dev->of_node, 0); - if (!clk_base) { - pr_err("%s: Unable to map clk base\n", __func__); - return -ENXIO; - } - - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; - - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; + /* Get the hhi system controller node if available */ + 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"); - /* 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; + /* + * 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) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } + + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + } - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; + /* Populate regmap for the common regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) + gx_clk_regmaps[i]->map = map; - /* Populate base address for the audio dividers */ - for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) - clkc_data->clk_audio_dividers[i]->base = clk_base; + /* Populate regmap for soc specific clocks */ + for (i = 0; i < clkc_data->regmap_clks_count; i++) + clkc_data->regmap_clks[i]->map = map; - /* - * register all clks - */ - for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + /* Register all clks */ + for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!clkc_data->hw_onecell_data->hws[i]) continue; ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); - if (ret) - goto iounmap; + clkc_data->hw_onecell_data->hws[i]); + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); - -iounmap: - iounmap(clk_base); - return ret; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clkc_data->hw_onecell_data); } static struct platform_driver gxbb_driver = { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index aee6fbba2004..9febf3f03739 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -194,8 +194,18 @@ #define CLKID_VPU_1_DIV 130 #define CLKID_VAPB_0_DIV 134 #define CLKID_VAPB_1_DIV 137 - -#define NR_CLKS 141 +#define CLKID_HDMI_PLL_PRE_MULT 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 <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3ffea80c1308..b324c44d36eb 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -23,14 +23,16 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "meson8b.h" +#include "clk-regmap.h" static DEFINE_SPINLOCK(meson_clk_lock); @@ -97,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = { { /* 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 = { .fixed_rate = 24000000, .hw.init = &(struct clk_init_data){ @@ -120,23 +108,39 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct meson_clk_pll meson8b_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .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, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -146,23 +150,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { }, }; -static struct meson_clk_pll meson8b_vid_pll = { - .m = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .n = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vid_pll", .ops = &meson_clk_pll_ro_ops, @@ -172,213 +187,317 @@ static struct meson_clk_pll meson8b_vid_pll = { }, }; -static struct meson_clk_pll meson8b_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = sys_pll_rate_table, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", - .ops = &meson_clk_pll_ops, + .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_fixed_factor meson8b_fclk_div2 = { +static struct clk_fixed_factor meson8b_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div_div3", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .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, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap meson8b_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap meson8b_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .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, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, +static struct clk_regmap meson8b_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, +static struct clk_regmap meson8b_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .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, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -/* - * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL - * post-dividers and should be modeled with their respective PLLs via the - * forthcoming coordinated clock rates feature - */ -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, +static struct clk_regmap meson8b_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, .hw.init = &(struct clk_init_data){ - .name = "cpu_clk", - .ops = &meson_clk_cpu_ops, - .parent_names = (const char *[]){ "sys_pll" }, + .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[] = { 6, 5, 7 }; - -struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * FIXME bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -387,34 +506,136 @@ struct clk_mux meson8b_mpeg_clk_sel = { .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", "fclk_div5" }, .num_parents = 3, - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), }, }; -struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +struct clk_regmap meson8b_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; -struct clk_gate meson8b_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +struct clk_regmap meson8b_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .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 = { [CLKID_MPLL0] = &meson8b_mpll0.hw, [CLKID_MPLL1] = &meson8b_mpll1.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, }, .num = CLK_NR_CLKS, }; -static struct meson_clk_pll *const meson8b_clk_plls[] = { - &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[] = { +static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, &meson8b_dos, @@ -695,14 +918,27 @@ static struct clk_gate *const meson8b_clk_gates[] = { &meson8b_ao_ahb_sram, &meson8b_ao_ahb_bus, &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_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 { @@ -804,82 +1040,46 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { .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) { - int ret, clkid, i; - struct clk_hw *parent_hw; - struct clk *parent_clk; + int ret, i; + struct clk *clk; struct device *dev = &pdev->dev; + struct regmap *map; if (!clk_base) return -ENXIO; - /* Populate base address for PLLs */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) - meson8b_clk_plls[i]->base = clk_base; - - /* 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 */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++) - meson8b_clk_muxes[i]->reg = clk_base + - (u32)meson8b_clk_muxes[i]->reg; + map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); - /* 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; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) + meson8b_clk_regmaps[i]->map = map; /* * register all clks * 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 */ - if (!meson8b_hw_onecell_data.hws[clkid]) + if (!meson8b_hw_onecell_data.hws[i]) continue; - /* FIXME convert to devm_clk_register */ - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); + ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); if (ret) return ret; } - /* - * 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); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); } static const struct of_device_id meson8b_clkc_match_table[] = { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 2eaf8a52e7dd..6e414bd36981 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -69,7 +69,22 @@ * 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 diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 4e9b8c2c8980..1ee75a5e93f4 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -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 *clkr = ÷r->clkr; - u32 div; - 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; + u32 val; - *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, |