diff options
67 files changed, 4004 insertions, 2957 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt index be909ed45970..511628bb3d3a 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -268,9 +268,19 @@ The common clock framework uses two global locks, the prepare lock and the enable lock. The enable lock is a spinlock and is held across calls to the .enable, -.disable and .is_enabled operations. Those operations are thus not allowed to -sleep, and calls to the clk_enable(), clk_disable() and clk_is_enabled() API -functions are allowed in atomic context. +.disable operations. Those operations are thus not allowed to sleep, +and calls to the clk_enable(), clk_disable() API functions are allowed in +atomic context. + +For clk_is_enabled() API, it is also designed to be allowed to be used in +atomic context. However, it doesn't really make any sense to hold the enable +lock in core, unless you want to do something else with the information of +the enable state with that lock held. Otherwise, seeing if a clk is enabled is +a one-shot read of the enabled state, which could just as easily change after +the function returns because the lock is released. Thus the user of this API +needs to handle synchronizing the read of the state with whatever they're +using it for to make sure that the enable state doesn't change during that +time. The prepare lock is a mutex and is held across calls to all other operations. All those operations are allowed to sleep, and calls to the corresponding API diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt index 35a6f5c7e5c2..9b13b32974f9 100644 --- a/Documentation/devicetree/bindings/clock/ti/divider.txt +++ b/Documentation/devicetree/bindings/clock/ti/divider.txt @@ -75,6 +75,9 @@ Optional properties: - ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, see [2] - ti,set-rate-parent : clk_set_rate is propagated to parent +- ti,latch-bit : latch the divider value to HW, only needed if the register + access requires this. As an example dra76x DPLL_GMAC H14 divider implements + such behavior. Examples: dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt index 2d0d170f8001..eec8994b9be8 100644 --- a/Documentation/devicetree/bindings/clock/ti/mux.txt +++ b/Documentation/devicetree/bindings/clock/ti/mux.txt @@ -48,6 +48,9 @@ Optional properties: zero - ti,set-rate-parent : clk_set_rate is propagated to parent clock, not supported by the composite-mux-clock subtype +- ti,latch-bit : latch the mux value to HW, only needed if the register + access requires this. As an example, dra7x DPLL_GMAC H14 muxing + implements such behavior. Examples: diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..395ea06c427d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12189,6 +12189,7 @@ M: Tomasz Figa <tomasz.figa@gmail.com> M: Chanwoo Choi <cw00.choi@samsung.com> S: Supported L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) +T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: drivers/clk/samsung/ F: include/dt-bindings/clock/exynos*.h F: Documentation/devicetree/bindings/clock/exynos*.txt 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..037035a46b33 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); @@ -2486,19 +2488,7 @@ static int clk_summary_show(struct seq_file *s, void *data) return 0; } - - -static int clk_summary_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_summary_show, inode->i_private); -} - -static const struct file_operations clk_summary_fops = { - .open = clk_summary_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_summary); static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) { @@ -2532,7 +2522,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) seq_putc(s, '}'); } -static int clk_dump(struct seq_file *s, void *data) +static int clk_dump_show(struct seq_file *s, void *data) { struct clk_core *c; bool first_node = true; @@ -2555,19 +2545,7 @@ static int clk_dump(struct seq_file *s, void *data) seq_puts(s, "}\n"); return 0; } - - -static int clk_dump_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_dump, inode->i_private); -} - -static const struct file_operations clk_dump_fops = { - .open = clk_dump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_dump); static const struct { unsigned long flag; @@ -2589,7 +2567,7 @@ static const struct { #undef ENTRY }; -static int clk_flags_dump(struct seq_file *s, void *data) +static int clk_flags_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; unsigned long flags = core->flags; @@ -2608,20 +2586,9 @@ static int clk_flags_dump(struct seq_file *s, void *data) return 0; } +DEFINE_SHOW_ATTRIBUTE(clk_flags); -static int clk_flags_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_flags_dump, inode->i_private); -} - -static const struct file_operations clk_flags_fops = { - .open = clk_flags_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int possible_parents_dump(struct seq_file *s, void *data) +static int possible_parents_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; int i; @@ -2633,18 +2600,7 @@ static int possible_parents_dump(struct seq_file *s, void *data) return 0; } - -static int possible_parents_open(struct inode *inode, struct file *file) -{ - return single_open(file, possible_parents_dump, inode->i_private); -} - -static const struct file_operations possible_parents_fops = { - .open = possible_parents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(possible_parents); static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { @@ -2928,6 +2884,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 +2935,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/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 9cdf9d5050ac..4cb70bed89a9 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -29,21 +29,10 @@ #define SCI_CLK_INPUT_TERMINATION BIT(2) /** - * struct sci_clk_data - TI SCI clock data - * @dev: device index - * @num_clks: number of clocks for this device - */ -struct sci_clk_data { - u16 dev; - u16 num_clks; -}; - -/** * struct sci_clk_provider - TI SCI clock provider representation * @sci: Handle to the System Control Interface protocol handler * @ops: Pointer to the SCI ops to be used by the clocks * @dev: Device pointer for the clock provider - * @clk_data: Clock data * @clocks: Clocks array for this device * @num_clocks: Total number of clocks for this provider */ @@ -51,8 +40,7 @@ struct sci_clk_provider { const struct ti_sci_handle *sci; const struct ti_sci_clk_ops *ops; struct device *dev; - const struct sci_clk_data *clk_data; - struct clk_hw **clocks; + struct sci_clk **clocks; int num_clocks; }; @@ -61,6 +49,7 @@ struct sci_clk_provider { * @hw: Hardware clock cookie for common clock framework * @dev_id: Device index * @clk_id: Clock index + * @num_parents: Number of parents for this clock * @provider: Master clock provider * @flags: Flags for the clock */ @@ -68,6 +57,7 @@ struct sci_clk { struct clk_hw hw; u16 dev_id; u8 clk_id; + u8 num_parents; struct sci_clk_provider *provider; u8 flags; }; @@ -273,38 +263,22 @@ static const struct clk_ops sci_clk_ops = { /** * _sci_clk_get - Gets a handle for an SCI clock * @provider: Handle to SCI clock provider - * @dev_id: device ID for the clock to register - * @clk_id: clock ID for the clock to register + * @sci_clk: Handle to the SCI clock to populate * * Gets a handle to an existing TI SCI hw clock, or builds a new clock * entry and registers it with the common clock framework. Called from * the common clock framework, when a corresponding of_clk_get call is * executed, or recursively from itself when parsing parent clocks. - * Returns a pointer to the hw clock struct, or ERR_PTR value in failure. + * Returns 0 on success, negative error code on failure. */ -static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, - u16 dev_id, u8 clk_id) +static int _sci_clk_build(struct sci_clk_provider *provider, + struct sci_clk *sci_clk) { struct clk_init_data init = { NULL }; - struct sci_clk *sci_clk = NULL; char *name = NULL; char **parent_names = NULL; int i; - int ret; - - sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL); - if (!sci_clk) - return ERR_PTR(-ENOMEM); - - sci_clk->dev_id = dev_id; - sci_clk->clk_id = clk_id; - sci_clk->provider = provider; - - ret = provider->ops->get_num_parents(provider->sci, dev_id, - clk_id, - &init.num_parents); - if (ret) - goto err; + int ret = 0; name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev), sci_clk->dev_id, sci_clk->clk_id); @@ -317,11 +291,11 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, * to have mux functionality. Otherwise it is going to act as a root * clock. */ - if (init.num_parents < 2) - init.num_parents = 0; + if (sci_clk->num_parents < 2) + sci_clk->num_parents = 0; - if (init.num_parents) { - parent_names = kcalloc(init.num_parents, sizeof(char *), + if (sci_clk->num_parents) { + parent_names = kcalloc(sci_clk->num_parents, sizeof(char *), GFP_KERNEL); if (!parent_names) { @@ -329,7 +303,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, goto err; } - for (i = 0; i < init.num_parents; i++) { + for (i = 0; i < sci_clk->num_parents; i++) { char *parent_name; parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d", @@ -346,6 +320,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, } init.ops = &sci_clk_ops; + init.num_parents = sci_clk->num_parents; sci_clk->hw.init = &init; ret = devm_clk_hw_register(provider->dev, &sci_clk->hw); @@ -354,7 +329,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, err: if (parent_names) { - for (i = 0; i < init.num_parents; i++) + for (i = 0; i < sci_clk->num_parents; i++) kfree(parent_names[i]); kfree(parent_names); @@ -362,10 +337,7 @@ err: kfree(name); - if (ret) - return ERR_PTR(ret); - - return &sci_clk->hw; + return ret; } static int _cmp_sci_clk(const void *a, const void *b) @@ -414,253 +386,20 @@ static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data) static int ti_sci_init_clocks(struct sci_clk_provider *p) { - const struct sci_clk_data *data = p->clk_data; - struct clk_hw *hw; int i; - int num_clks = 0; - - while (data->num_clks) { - num_clks += data->num_clks; - data++; - } - - p->num_clocks = num_clks; - - p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk), - GFP_KERNEL); - if (!p->clocks) - return -ENOMEM; - - num_clks = 0; - - data = p->clk_data; - - while (data->num_clks) { - for (i = 0; i < data->num_clks; i++) { - hw = _sci_clk_build(p, data->dev, i); - if (!IS_ERR(hw)) { - p->clocks[num_clks++] = hw; - continue; - } - - /* Skip any holes in the clock lists */ - if (PTR_ERR(hw) == -ENODEV) - continue; + int ret; - return PTR_ERR(hw); - } - data++; + for (i = 0; i < p->num_clocks; i++) { + ret = _sci_clk_build(p, p->clocks[i]); + if (ret) + return ret; } return 0; } -static const struct sci_clk_data k2g_clk_data[] = { - /* pmmc */ - { .dev = 0x0, .num_clks = 4 }, - - /* mlb0 */ - { .dev = 0x1, .num_clks = 5 }, - - /* dss0 */ - { .dev = 0x2, .num_clks = 2 }, - - /* mcbsp0 */ - { .dev = 0x3, .num_clks = 8 }, - - /* mcasp0 */ - { .dev = 0x4, .num_clks = 8 }, - - /* mcasp1 */ - { .dev = 0x5, .num_clks = 8 }, - - /* mcasp2 */ - { .dev = 0x6, .num_clks = 8 }, - - /* dcan0 */ - { .dev = 0x8, .num_clks = 2 }, - - /* dcan1 */ - { .dev = 0x9, .num_clks = 2 }, - - /* emif0 */ - { .dev = 0xa, .num_clks = 6 }, - - /* mmchs0 */ - { .dev = 0xb, .num_clks = 3 }, - - /* mmchs1 */ - { .dev = 0xc, .num_clks = 3 }, - - /* gpmc0 */ - { .dev = 0xd, .num_clks = 1 }, - - /* elm0 */ - { .dev = 0xe, .num_clks = 1 }, - - /* spi0 */ - { .dev = 0x10, .num_clks = 1 }, - - /* spi1 */ - { .dev = 0x11, .num_clks = 1 }, - - /* spi2 */ - { .dev = 0x12, .num_clks = 1 }, - - /* spi3 */ - { .dev = 0x13, .num_clks = 1 }, - - /* icss0 */ - { .dev = 0x14, .num_clks = 6 }, - - /* icss1 */ - { .dev = 0x15, .num_clks = 6 }, - - /* usb0 */ - { .dev = 0x16, .num_clks = 7 }, - - /* usb1 */ - { .dev = 0x17, .num_clks = 7 }, - - /* nss0 */ - { .dev = 0x18, .num_clks = 14 }, - - /* pcie0 */ - { .dev = 0x19, .num_clks = 1 }, - - /* gpio0 */ - { .dev = 0x1b, .num_clks = 1 }, - - /* gpio1 */ - { .dev = 0x1c, .num_clks = 1 }, - - /* timer64_0 */ - { .dev = 0x1d, .num_clks = 9 }, - - /* timer64_1 */ - { .dev = 0x1e, .num_clks = 9 }, - - /* timer64_2 */ - { .dev = 0x1f, .num_clks = 9 }, - - /* timer64_3 */ - { .dev = 0x20, .num_clks = 9 }, - - /* timer64_4 */ - { .dev = 0x21, .num_clks = 9 }, - - /* timer64_5 */ - { .dev = 0x22, .num_clks = 9 }, - - /* timer64_6 */ - { .dev = 0x23, .num_clks = 9 }, - - /* msgmgr0 */ - { .dev = 0x25, .num_clks = 1 }, - - /* bootcfg0 */ - { .dev = 0x26, .num_clks = 1 }, - - /* arm_bootrom0 */ - { .dev = 0x27, .num_clks = 1 }, - - /* dsp_bootrom0 */ - { .dev = 0x29, .num_clks = 1 }, - - /* debugss0 */ - { .dev = 0x2b, .num_clks = 8 }, - - /* uart0 */ - { .dev = 0x2c, .num_clks = 1 }, - - /* uart1 */ - { .dev = 0x2d, .num_clks = 1 }, - - /* uart2 */ - { .dev = 0x2e, .num_clks = 1 }, - - /* ehrpwm0 */ - { .dev = 0x2f, .num_clks = 1 }, - - /* ehrpwm1 */ - { .dev = 0x30, .num_clks = 1 }, - - /* ehrpwm2 */ - { .dev = 0x31, .num_clks = 1 }, - - /* ehrpwm3 */ - { .dev = 0x32, .num_clks = 1 }, - - /* ehrpwm4 */ - { .dev = 0x33, .num_clks = 1 }, - - /* ehrpwm5 */ - { .dev = 0x34, .num_clks = 1 }, - - /* eqep0 */ - { .dev = 0x35, .num_clks = 1 }, - - /* eqep1 */ - { .dev = 0x36, .num_clks = 1 }, - - /* eqep2 */ - { .dev = 0x37, .num_clks = 1 }, - - /* ecap0 */ - { .dev = 0x38, .num_clks = 1 }, - - /* ecap1 */ - { .dev = 0x39, .num_clks = 1 }, - - /* i2c0 */ - { .dev = 0x3a, .num_clks = 1 }, - - /* i2c1 */ - { .dev = 0x3b, .num_clks = 1 }, - - /* i2c2 */ - { .dev = 0x3c, .num_clks = 1 }, - - /* edma0 */ - { .dev = 0x3f, .num_clks = 2 }, - - /* semaphore0 */ - { .dev = 0x40, .num_clks = 1 }, - - /* intc0 */ - { .dev = 0x41, .num_clks = 1 }, - - /* gic0 */ - { .dev = 0x42, .num_clks = 1 }, - - /* qspi0 */ - { .dev = 0x43, .num_clks = 5 }, - - /* arm_64b_counter0 */ - { .dev = 0x44, .num_clks = 2 }, - - /* tetris0 */ - { .dev = 0x45, .num_clks = 2 }, - - /* cgem0 */ - { .dev = 0x46, .num_clks = 2 }, - - /* msmc0 */ - { .dev = 0x47, .num_clks = 1 }, - - /* cbass0 */ - { .dev = 0x49, .num_clks = 1 }, - - /* board0 */ - { .dev = 0x4c, .num_clks = 36 }, - - /* edma1 */ - { .dev = 0x4f, .num_clks = 2 }, - { .num_clks = 0 }, -}; - static const struct of_device_id ti_sci_clk_of_match[] = { - { .compatible = "ti,k2g-sci-clk", .data = &k2g_clk_data }, + { .compatible = "ti,k2g-sci-clk" }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match); @@ -681,12 +420,16 @@ static int ti_sci_clk_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct sci_clk_provider *provider; const struct ti_sci_handle *handle; - const struct sci_clk_data *data; int ret; - - data = of_device_get_match_data(dev); - if (!data) - return -EINVAL; + int num_clks = 0; + struct sci_clk **clks = NULL; + struct sci_clk **tmp_clks; + struct sci_clk *sci_clk; + int max_clks = 0; + int clk_id = 0; + int dev_id = 0; + u8 num_parents; + int gap_size = 0; handle = devm_ti_sci_get_handle(dev); if (IS_ERR(handle)) @@ -696,12 +439,69 @@ static int ti_sci_clk_probe(struct platform_device *pdev) if (!provider) return -ENOMEM; - provider->clk_data = data; - provider->sci = handle; provider->ops = &handle->ops.clk_ops; provider->dev = dev; + while (1) { + ret = provider->ops->get_num_parents(provider->sci, dev_id, + clk_id, &num_parents); + if (ret) { + gap_size++; + if (!clk_id) { + if (gap_size >= 5) + break; + dev_id++; + } else { + if (gap_size >= 2) { + dev_id++; + clk_id = 0; + gap_size = 0; + } else { + clk_id++; + } + } + continue; + } + + gap_size = 0; + + if (num_clks == max_clks) { + tmp_clks = devm_kmalloc_array(dev, max_clks + 64, + sizeof(sci_clk), + GFP_KERNEL); + memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk)); + if (max_clks) + devm_kfree(dev, clks); + max_clks += 64; + clks = tmp_clks; + } + + sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL); + if (!sci_clk) + return -ENOMEM; + sci_clk->dev_id = dev_id; + sci_clk->clk_id = clk_id; + sci_clk->provider = provider; + sci_clk->num_parents = num_parents; + + clks[num_clks] = sci_clk; + + clk_id++; + num_clks++; + } + + provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk), + GFP_KERNEL); + if (!provider->clocks) + return -ENOMEM; + + memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk)); + + provider->num_clocks = num_clks; + + devm_kfree(dev, clks); + ret = ti_sci_init_clocks(provider); if (ret) { pr_err("ti-sci-init-clocks failed.\n"); 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..5f5d468c1efe 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, +static 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 = { }, }; +static 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..b1e4d9557610 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, +static 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, +static 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..cc2992493e0b 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, +static 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, +static 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, + }, +}; + +static 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 */ }, +}; + +static 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, + }, +}; + +static 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, + }, +}; + +static 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,45 @@ 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 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, diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index c26d9007bfc4..850c02a52248 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -686,7 +686,7 @@ static int rpm_smd_clk_probe(struct platform_device *pdev) goto err; } - ret = of_clk_add_hw_provider(pdev->dev.of_node, qcom_smdrpm_clk_hw_get, + ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_smdrpm_clk_hw_get, rcc); if (ret) goto err; @@ -697,19 +697,12 @@ err: return ret; } -static int rpm_smd_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; -} - static struct platform_driver rpm_smd_clk_driver = { .driver = { .name = "qcom-clk-smd-rpm", .of_match_table = rpm_smd_clk_match_table, }, .probe = rpm_smd_clk_probe, - .remove = rpm_smd_clk_remove, }; static int __init rpm_smd_clk_init(void) diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 5d7451209206..3d6452932797 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2895,7 +2895,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { .name = "gcc_aggre0_snoc_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2910,7 +2910,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { .name = "gcc_aggre0_cnoc_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2925,7 +2925,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { .name = "gcc_smmu_aggre0_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2940,7 +2940,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { .name = "gcc_smmu_aggre0_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index ef8900bc077f..513826393158 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -8,9 +8,11 @@ obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o +obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o +obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 5bfc92ee3129..b4b057c7301c 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map audss registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } epll = ERR_PTR(-ENODEV); diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 1b81e283f605..27c9d23657b3 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -670,73 +670,73 @@ static const struct samsung_gate_clock gate_clks[] __initconst = { /* APLL & MPLL & BPLL & UPLL */ static const struct samsung_pll_rate_table exynos3250_pll_rates[] __initconst = { - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1066000000, 533, 6, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE( 960000000, 320, 4, 1), - PLL_35XX_RATE( 900000000, 300, 4, 1), - PLL_35XX_RATE( 850000000, 425, 6, 1), - PLL_35XX_RATE( 800000000, 200, 3, 1), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 667000000, 667, 12, 1), - PLL_35XX_RATE( 600000000, 400, 4, 2), - PLL_35XX_RATE( 533000000, 533, 6, 2), - PLL_35XX_RATE( 520000000, 260, 3, 2), - PLL_35XX_RATE( 500000000, 250, 3, 2), - PLL_35XX_RATE( 400000000, 200, 3, 2), - PLL_35XX_RATE( 200000000, 200, 3, 3), - PLL_35XX_RATE( 100000000, 200, 3, 4), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 960000000, 320, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 850000000, 425, 6, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 520000000, 260, 3, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 100000000, 200, 3, 4), { /* sentinel */ } }; /* EPLL */ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = { - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(288000000, 96, 2, 2, 0), - PLL_36XX_RATE(192000000, 128, 2, 3, 0), - PLL_36XX_RATE(144000000, 96, 2, 3, 0), - PLL_36XX_RATE( 96000000, 128, 2, 4, 0), - PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), - PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), - PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), - PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), - PLL_36XX_RATE( 50000000, 200, 3, 5, 0), - PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), - PLL_36XX_RATE( 48000000, 128, 2, 5, 0), - PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 288000000, 96, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 192000000, 128, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 144000000, 96, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 96000000, 128, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 84000000, 112, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 80000003, 106, 2, 4, 43691), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737598, 270, 3, 5, 62285), + PLL_36XX_RATE(24 * MHZ, 65535999, 174, 2, 5, 49982), + PLL_36XX_RATE(24 * MHZ, 50000000, 200, 3, 5, 0), + PLL_36XX_RATE(24 * MHZ, 49152002, 131, 2, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 48000000, 128, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 45158401, 180, 3, 5, 41524), { /* sentinel */ } }; /* VPLL */ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = { - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(533000000, 266, 3, 2, 32768), - PLL_36XX_RATE(519230987, 173, 2, 2, 5046), - PLL_36XX_RATE(500000000, 250, 3, 2, 0), - PLL_36XX_RATE(445500000, 148, 2, 2, 32768), - PLL_36XX_RATE(445055007, 148, 2, 2, 23047), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(371250000, 123, 2, 2, 49152), - PLL_36XX_RATE(370878997, 185, 3, 2, 28803), - PLL_36XX_RATE(340000000, 170, 3, 2, 0), - PLL_36XX_RATE(335000015, 111, 2, 2, 43691), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(330000000, 110, 2, 2, 0), - PLL_36XX_RATE(320000015, 106, 2, 2, 43691), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(275000000, 275, 3, 3, 0), - PLL_36XX_RATE(222750000, 148, 2, 3, 32768), - PLL_36XX_RATE(222528007, 148, 2, 3, 23069), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(148500000, 99, 2, 3, 0), - PLL_36XX_RATE(148352005, 98, 2, 3, 59070), - PLL_36XX_RATE(108000000, 144, 2, 4, 0), - PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), - PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), - PLL_36XX_RATE( 54000000, 144, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 533000000, 266, 3, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 519230987, 173, 2, 2, 5046), + PLL_36XX_RATE(24 * MHZ, 500000000, 250, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 445500000, 148, 2, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 445055007, 148, 2, 2, 23047), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 371250000, 123, 2, 2, 49152), + PLL_36XX_RATE(24 * MHZ, 370878997, 185, 3, 2, 28803), + PLL_36XX_RATE(24 * MHZ, 340000000, 170, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 335000015, 111, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 330000000, 110, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 320000015, 106, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 275000000, 275, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 222750000, 148, 2, 3, 32768), + PLL_36XX_RATE(24 * MHZ, 222528007, 148, 2, 3, 23069), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148500000, 99, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148352005, 98, 2, 3, 59070), + PLL_36XX_RATE(24 * MHZ, 108000000, 144, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74250000, 99, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74176002, 98, 2, 4, 59070), + PLL_36XX_RATE(24 * MHZ, 54054000, 216, 3, 5, 14156), + PLL_36XX_RATE(24 * MHZ, 54000000, 144, 2, 5, 0), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 134f25f2a913..0421960eb963 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1266,77 +1266,78 @@ static const struct of_device_id ext_clk_match[] __initconst = { /* PLLs PMS values */ static const struct samsung_pll_rate_table exynos4210_apll_rates[] __initconst = { - PLL_45XX_RATE(1200000000, 150, 3, 1, 28), - PLL_45XX_RATE(1000000000, 250, 6, 1, 28), - PLL_45XX_RATE( 800000000, 200, 6, 1, 28), - PLL_45XX_RATE( 666857142, 389, 14, 1, 13), - PLL_45XX_RATE( 600000000, 100, 4, 1, 13), - PLL_45XX_RATE( 533000000, 533, 24, 1, 5), - PLL_45XX_RATE( 500000000, 250, 6, 2, 28), - PLL_45XX_RATE( 400000000, 200, 6, 2, 28), - PLL_45XX_RATE( 200000000, 200, 6, 3, 28), + PLL_4508_RATE(24 * MHZ, 1200000000, 150, 3, 1, 28), + PLL_4508_RATE(24 * MHZ, 1000000000, 250, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 800000000, 200, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 666857142, 389, 14, 1, 13), + PLL_4508_RATE(24 * MHZ, 600000000, 100, 4, 1, 13), + PLL_4508_RATE(24 * MHZ, 533000000, 533, 24, 1, 5), + PLL_4508_RATE(24 * MHZ, 500000000, 250, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 400000000, 200, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 200000000, 200, 6, 3, 28), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_epll_rates[] __initconst = { - PLL_4600_RATE(192000000, 48, 3, 1, 0, 0), - PLL_4600_RATE(180633605, 45, 3, 1, 10381, 0), - PLL_4600_RATE(180000000, 45, 3, 1, 0, 0), - PLL_4600_RATE( 73727996, 73, 3, 3, 47710, 1), - PLL_4600_RATE( 67737602, 90, 4, 3, 20762, 1), - PLL_4600_RATE( 49151992, 49, 3, 3, 9961, 0), - PLL_4600_RATE( 45158401, 45, 3, 3, 10381, 0), + PLL_4600_RATE(24 * MHZ, 192000000, 48, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381, 0), + PLL_4600_RATE(24 * MHZ, 180000000, 45, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710, 1), + PLL_4600_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762, 1), + PLL_4600_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961, 0), + PLL_4600_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_vpll_rates[] __initconst = { - PLL_4650_RATE(360000000, 44, 3, 0, 1024, 0, 14, 0), - PLL_4650_RATE(324000000, 53, 2, 1, 1024, 1, 1, 1), - PLL_4650_RATE(259617187, 63, 3, 1, 1950, 0, 20, 1), - PLL_4650_RATE(110000000, 53, 3, 2, 2048, 0, 17, 0), - PLL_4650_RATE( 55360351, 53, 3, 3, 2417, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 360000000, 44, 3, 0, 1024, 0, 14, 0), + PLL_4650_RATE(24 * MHZ, 324000000, 53, 2, 1, 1024, 1, 1, 1), + PLL_4650_RATE(24 * MHZ, 259617187, 63, 3, 1, 1950, 0, 20, 1), + PLL_4650_RATE(24 * MHZ, 110000000, 53, 3, 2, 2048, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 55360351, 53, 3, 3, 2417, 0, 17, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_apll_rates[] __initconst = { - PLL_35XX_RATE(1704000000, 213, 3, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE( 900000000, 150, 4, 0), - PLL_35XX_RATE( 800000000, 100, 3, 0), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 600000000, 200, 4, 1), - PLL_35XX_RATE( 500000000, 125, 3, 1), - PLL_35XX_RATE( 400000000, 100, 3, 1), - PLL_35XX_RATE( 300000000, 200, 4, 2), - PLL_35XX_RATE( 200000000, 100, 3, 2), + PLL_35XX_RATE(24 * MHZ, 1704000000, 213, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_epll_rates[] __initconst = { - PLL_36XX_RATE(192000000, 48, 3, 1, 0), - PLL_36XX_RATE(180633605, 45, 3, 1, 10381), - PLL_36XX_RATE(180000000, 45, 3, 1, 0), - PLL_36XX_RATE( 73727996, 73, 3, 3, 47710), - PLL_36XX_RATE( 67737602, 90, 4, 3, 20762), - PLL_36XX_RATE( 49151992, 49, 3, 3, 9961), - PLL_36XX_RATE( 45158401, 45, 3, 3, 10381), + PLL_36XX_RATE(24 * MHZ, 196608001, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 192000000, 48, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381), + PLL_36XX_RATE(24 * MHZ, 180000000, 45, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762), + PLL_36XX_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961), + PLL_36XX_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_vpll_rates[] __initconst = { - PLL_36XX_RATE(533000000, 133, 3, 1, 16384), - PLL_36XX_RATE(440000000, 110, 3, 1, 0), - PLL_36XX_RATE(350000000, 175, 3, 2, 0), - PLL_36XX_RATE(266000000, 133, 3, 2, 0), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(106031250, 53, 3, 2, 1024), - PLL_36XX_RATE( 53015625, 53, 3, 3, 1024), + PLL_36XX_RATE(24 * MHZ, 533000000, 133, 3, 1, 16384), + PLL_36XX_RATE(24 * MHZ, 440000000, 110, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 350000000, 175, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 133, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 106031250, 53, 3, 2, 1024), + PLL_36XX_RATE(24 * MHZ, 53015625, 53, 3, 3, 1024), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c new file mode 100644 index 000000000000..93306283d764 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 Samsung Electronics Co., Ltd. +// Author: Marek Szyprowski <m.szyprowski@samsung.com> +// Common Clock Framework support for Exynos5 power-domain dependent clocks + +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> + +#include "clk.h" +#include "clk-exynos5-subcmu.h" + +static struct samsung_clk_provider *ctx; +static const struct exynos5_subcmu_info *cmu; +static int nr_cmus; + +static void exynos5_subcmu_clk_save(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) { + rd->save = readl(base + rd->offset); + writel((rd->save & ~rd->mask) | rd->value, base + rd->offset); + rd->save &= rd->mask; + } +}; + +static void exynos5_subcmu_clk_restore(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) + writel((readl(base + rd->offset) & ~rd->mask) | rd->save, + base + rd->offset); +} + +static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx, + const struct samsung_gate_clock *list, int nr_clk) +{ + while (nr_clk--) + samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER), list++->id); +} + +/* + * Pass the needed clock provider context and register sub-CMU clocks + * + * NOTE: This function has to be called from the main, OF_CLK_DECLARE- + * initialized clock provider driver. This happens very early during boot + * process. Then this driver, during core_initcall registers two platform + * drivers: one which binds to the same device-tree node as OF_CLK_DECLARE + * driver and second, for handling its per-domain child-devices. Those + * platform drivers are bound to their devices a bit later in arch_initcall, + * when OF-core populates all device-tree nodes. + */ +void exynos5_subcmus_init(struct samsung_clk_provider *_ctx, int _nr_cmus, + const struct exynos5_subcmu_info *_cmu) +{ + ctx = _ctx; + cmu = _cmu; + nr_cmus = _nr_cmus; + + for (; _nr_cmus--; _cmu++) { + exynos5_subcmu_defer_gate(ctx, _cmu->gate_clks, + _cmu->nr_gate_clks); + exynos5_subcmu_clk_save(ctx->reg_base, _cmu->suspend_regs, + _cmu->nr_suspend_regs); + } +} + +static int __maybe_unused exynos5_subcmu_suspend(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_save(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __maybe_unused exynos5_subcmu_resume(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_restore(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __init exynos5_subcmu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_get(dev); + + ctx->dev = dev; + samsung_clk_register_div(ctx, info->div_clks, info->nr_div_clks); + samsung_clk_register_gate(ctx, info->gate_clks, info->nr_gate_clks); + ctx->dev = NULL; + + pm_runtime_put_sync(dev); + + return 0; +} + +static const struct dev_pm_ops exynos5_subcmu_pm_ops = { + SET_RUNTIME_PM_OPS(exynos5_subcmu_suspend, + exynos5_subcmu_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos5_subcmu_driver __refdata = { + .driver = { + .name = "exynos5-subcmu", + .suppress_bind_attrs = true, + .pm = &exynos5_subcmu_pm_ops, + }, + .probe = exynos5_subcmu_probe, +}; + +static int __init exynos5_clk_register_subcmu(struct device *parent, + const struct exynos5_subcmu_info *info, + struct device_node *pd_node) +{ + struct of_phandle_args genpdspec = { .np = pd_node }; + struct platform_device *pdev; + + pdev = platform_device_alloc(info->pd_name, -1); + pdev->dev.parent = parent; + pdev->driver_override = "exynos5-subcmu"; + platform_set_drvdata(pdev, (void *)info); + of_genpd_add_device(&genpdspec, &pdev->dev); + platform_device_add(pdev); + + return 0; +} + +static int __init exynos5_clk_probe(struct platform_device *pdev) +{ + struct device_node *np; + const char *name; + int i; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + if (of_property_read_string(np, "label", &name) < 0) + continue; + for (i = 0; i < nr_cmus; i++) + if (strcmp(cmu[i].pd_name, name) == 0) + exynos5_clk_register_subcmu(&pdev->dev, + &cmu[i], np); + } + return 0; +} + +static const struct of_device_id exynos5_clk_of_match[] = { + { .compatible = "samsung,exynos5250-clock", }, + { .compatible = "samsung,exynos5420-clock", }, + { .compatible = "samsung,exynos5800-clock", }, + { }, +}; + +static struct platform_driver exynos5_clk_driver __refdata = { + .driver = { + .name = "exynos5-clock", + .of_match_table = exynos5_clk_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos5_clk_probe, +}; + +static int __init exynos5_clk_drv_init(void) +{ + platform_driver_register(&exynos5_clk_driver); + platform_driver_register(&exynos5_subcmu_driver); + return 0; +} +core_initcall(exynos5_clk_drv_init); diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.h b/drivers/clk/samsung/clk-exynos5-subcmu.h new file mode 100644 index 000000000000..755ee8aaa3de --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __CLK_EXYNOS5_SUBCMU_H +#define __CLK_EXYNOS5_SUBCMU_H + +struct exynos5_subcmu_reg_dump { + u32 offset; + u32 value; + u32 mask; + u32 save; +}; + +struct exynos5_subcmu_info { + const struct samsung_div_clock *div_clks; + unsigned int nr_div_clks; + const struct samsung_gate_clock *gate_clks; + unsigned int nr_gate_clks; + struct exynos5_subcmu_reg_dump *suspend_regs; + unsigned int nr_suspend_regs; + const char *pd_name; +}; + +void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus, + const struct exynos5_subcmu_info *cmu); + +#endif diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 9b073c98a891..347fd80c351b 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -18,6 +18,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -560,6 +561,8 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { 0), GATE(CLK_GSCL3, "gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 3, 0, 0), + GATE(CLK_CAMIF_TOP, "camif_top", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 4, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "div_gscl_wa", GATE_IP_GSCL, 5, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "div_gscl_wb", GATE_IP_GSCL, 6, 0, 0), GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "mout_aclk266_gscl_sub", @@ -570,18 +573,11 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_GSCL, 9, 0, 0), GATE(CLK_SMMU_GSCL3, "smmu_gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 10, 0, 0), + GATE(CLK_SMMU_FIMC_LITE0, "smmu_fimc_lite0", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 11, 0, 0), + GATE(CLK_SMMU_FIMC_LITE1, "smmu_fimc_lite1", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 12, 0, 0), - GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, - 0), - GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, - 0), - GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, - 0), - GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, - 0), - GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, - 0), GATE(CLK_MFC, "mfc", "mout_aclk333_sub", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "mout_aclk333_sub", GATE_IP_MFC, 1, 0, @@ -671,10 +667,6 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE(CLK_WDT, "wdt", "div_aclk66", GATE_IP_PERIS, 19, 0, 0), GATE(CLK_RTC, "rtc", "div_aclk66", GATE_IP_PERIS, 20, 0, 0), GATE(CLK_TMU, "tmu", "div_aclk66", GATE_IP_PERIS, 21, 0, 0), - GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 9, 0, 0), - GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 8, 0, 0), GATE(CLK_SMMU_2D, "smmu_2d", "div_aclk200", GATE_IP_ACP, 7, 0, 0), GATE(CLK_SMMU_FIMC_ISP, "smmu_fimc_isp", "mout_aclk_266_isp_sub", GATE_IP_ISP0, 8, 0, 0), @@ -698,48 +690,80 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_ISP1, 7, 0, 0), }; +static const struct samsung_gate_clock exynos5250_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, + 0), + GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, + 0), + GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, + 0), + GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, + 0), + GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, + 0), + GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 9, 0, 0), + GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 8, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5250_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP3, 0, BIT(4) }, /* MUX mout_aclk200_disp1_sub */ + { SRC_TOP3, 0, BIT(6) }, /* MUX mout_aclk300_disp1_sub */ +}; + +static const struct exynos5_subcmu_info exynos5250_disp_subcmu = { + .gate_clks = exynos5250_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5250_disp_gate_clks), + .suspend_regs = exynos5250_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5250_disp_suspend_regs), + .pd_name = "DISP1", +}; + static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), /* Not in UM, but need for eDP on snow */ - PLL_36XX_RATE(70500000, 94, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 70500000, 94, 2, 4, 0), { }, }; static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), - PLL_36XX_RATE(180000000, 90, 3, 2, 0), - PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), - PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 192000000, 64, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 90, 3, 2, 20762), + PLL_36XX_RATE(24 * MHZ, 180000000, 90, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 2, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 49152000, 98, 3, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 32768001, 131, 3, 5, 4719), { }, }; static const struct samsung_pll_rate_table apll_24mhz_tbl[] __initconst = { /* sorted in descending order */ - /* PLL_35XX_RATE(rate, m, p, s) */ - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE(900000000, 150, 4, 0), - PLL_35XX_RATE(800000000, 100, 3, 0), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 4, 1), - PLL_35XX_RATE(500000000, 125, 3, 1), - PLL_35XX_RATE(400000000, 100, 3, 1), - PLL_35XX_RATE(300000000, 200, 4, 2), - PLL_35XX_RATE(200000000, 100, 3, 2), + /* PLL_35XX_RATE(fin, rate, m, p, s) */ + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), }; static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { @@ -859,10 +883,11 @@ static void __init exynos5250_clk_init(struct device_node *np) __raw_writel(tmp, reg_base + PWR_CTRL2); exynos5250_clk_sleep_init(); + exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu); samsung_clk_of_add_provider(np, ctx); pr_info("Exynos5250: clock setup completed, armclk=%ld\n", _get_rate("div_arm2")); } -CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index fd1d9bfc151b..2cc2583abd87 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -23,57 +23,57 @@ * DISP_PLL, EGL_PLL, KFC_PLL, MEM_PLL, BUS_PLL, MEDIA_PLL, G3D_PLL. */ static const struct samsung_pll_rate_table pll2550_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(933000000, 311, 4, 1), - PLL_35XX_RATE(900000000, 300, 4, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(733000000, 733, 12, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(667000000, 667, 12, 1), - PLL_35XX_RATE(633000000, 211, 4, 1), - PLL_35XX_RATE(620000000, 310, 3, 2), - PLL_35XX_RATE(600000000, 400, 4, 2), - PLL_35XX_RATE(543000000, 362, 4, 2), - PLL_35XX_RATE(533000000, 533, 6, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(450000000, 300, 4, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(350000000, 175, 3, 2), - PLL_35XX_RATE(300000000, 400, 4, 3), - PLL_35XX_RATE(266000000, 266, 3, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), - PLL_35XX_RATE(160000000, 160, 3, 3), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 933000000, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 733000000, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 620000000, 310, 3, 2), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 543000000, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 450000000, 300, 4, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 350000000, 175, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 400, 4, 3), + PLL_35XX_RATE(24 * MHZ, 266000000, 266, 3, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 160000000, 160, 3, 3), }; /* * Applicable for 2650 Type PLL for AUD_PLL. */ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(1600000000, 200, 3, 0, 0), - PLL_36XX_RATE(1200000000, 100, 2, 0, 0), - PLL_36XX_RATE(1000000000, 250, 3, 1, 0), - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(532000000, 266, 3, 2, 0), - PLL_36XX_RATE(480000000, 160, 2, 2, 0), - PLL_36XX_RATE(432000000, 144, 2, 2, 0), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(266000000, 266, 3, 3, 0), - PLL_36XX_RATE(200000000, 200, 3, 3, 0), - PLL_36XX_RATE(166000000, 166, 3, 3, 0), - PLL_36XX_RATE(133000000, 266, 3, 4, 0), - PLL_36XX_RATE(100000000, 200, 3, 4, 0), - PLL_36XX_RATE(66000000, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 1600000000, 200, 3, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1200000000, 100, 2, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1000000000, 250, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 532000000, 266, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 480000000, 160, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 432000000, 144, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 394073128, 459, 7, 2, 49282), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000, 176, 2, 5, 0), }; /* CMU_AUD */ diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index fc471a49e8f4..0a0b09591e6f 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -226,16 +226,16 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { }; static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(333000000U, 111, 2, 2, 0), - PLL_36XX_RATE(300000000U, 100, 2, 2, 0), - PLL_36XX_RATE(266000000U, 266, 3, 3, 0), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(192000000U, 192, 3, 3, 0), - PLL_36XX_RATE(166000000U, 166, 3, 3, 0), - PLL_36XX_RATE(133000000U, 266, 3, 4, 0), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE(66000000U, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 333000000U, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000U, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000U, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 192000000U, 192, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000U, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000U, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000U, 176, 2, 5, 0), }; static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 45d34f601e9e..95e1bf69449b 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -19,6 +19,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -620,7 +621,8 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_group5_5800_p, SRC_TOP7, 16, 2), - MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2), + MUX_F(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2, + CLK_SET_RATE_PARENT, 0), MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1), }; @@ -863,7 +865,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8), DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4), DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4), - DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3), @@ -912,8 +913,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi1", "mout_spi1", DIV_PERIC1, 24, 4), DIV(0, "dout_spi2", "mout_spi2", DIV_PERIC1, 28, 4), - /* Mfc Block */ - DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), /* PCM */ DIV(0, "dout_pcm1", "dout_audio1", DIV_PERIC2, 16, 8), @@ -932,8 +931,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi2_pre", "dout_spi2", DIV_PERIC4, 24, 8), /* GSCL Block */ - DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", - DIV2_RATIO0, 4, 2), DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2), /* MSCL Block */ @@ -1190,8 +1187,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_GSCL_WB, "sclk_gscl_wb", "mout_user_aclk333_432_gscl", GATE_TOP_SCLK_GSCL, 7, 0, 0), - GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), - GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), GATE(CLK_FIMC_3AA, "fimc_3aa", "aclk333_432_gscl", GATE_IP_GSCL0, 4, 0, 0), GATE(CLK_FIMC_LITE0, "fimc_lite0", "aclk333_432_gscl", @@ -1205,10 +1200,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE_IP_GSCL1, 3, 0, 0), GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "dout_gscl_blk_333", GATE_IP_GSCL1, 4, 0, 0), - GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", - GATE_IP_GSCL1, 6, 0, 0), - GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", - GATE_IP_GSCL1, 7, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13, 0, 0), GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "dout_gscl_blk_333", @@ -1227,18 +1218,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk", GATE_IP_MSCL, 10, 0, 0), - GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), - GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), - GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), - GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), - GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", - GATE_IP_DISP1, 7, 0, 0), - GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", - GATE_IP_DISP1, 8, 0, 0), - GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", - GATE_IP_DISP1, 9, 0, 0), - /* ISP */ GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp", GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0), @@ -1255,48 +1234,138 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "dout_isp_sensor2", GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0), + GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +}; + +static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = { + DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), +}; + +static const struct samsung_gate_clock exynos5x_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), + GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), + GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), + GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), + GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", + GATE_IP_DISP1, 7, 0, 0), + GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", + GATE_IP_DISP1, 8, 0, 0), + GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", + GATE_IP_DISP1, 9, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP5, 0, BIT(0) }, /* MUX mout_user_aclk400_disp1 */ + { SRC_TOP5, 0, BIT(24) }, /* MUX mout_user_aclk300_disp1 */ + { SRC_TOP3, 0, BIT(8) }, /* MUX mout_user_aclk200_disp1 */ + { DIV2_RATIO0, 0, 0x30000 }, /* DIV dout_disp1_blk */ +}; + +static const struct samsung_div_clock exynos5x_gsc_div_clks[] __initconst = { + DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", + DIV2_RATIO0, 4, 2), +}; + +static const struct samsung_gate_clock exynos5x_gsc_gate_clks[] __initconst = { + GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), + GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), + GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", + GATE_IP_GSCL1, 6, 0, 0), + GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", + GATE_IP_GSCL1, 7, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_gsc_suspend_regs[] = { + { GATE_IP_GSCL0, 0x3, 0x3 }, /* GSC gates */ + { GATE_IP_GSCL1, 0xc0, 0xc0 }, /* GSC gates */ + { SRC_TOP5, 0, BIT(28) }, /* MUX mout_user_aclk300_gscl */ + { DIV2_RATIO0, 0, 0x30 }, /* DIV dout_gscl_blk_300 */ +}; + +static const struct samsung_div_clock exynos5x_mfc_div_clks[] __initconst = { + DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), +}; + +static const struct samsung_gate_clock exynos5x_mfc_gate_clks[] __initconst = { GATE(CLK_MFC, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCL, "smmu_mfcl", "dout_mfc_blk", GATE_IP_MFC, 1, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "dout_mfc_blk", GATE_IP_MFC, 2, 0, 0), +}; - GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +static struct exynos5_subcmu_reg_dump exynos5x_mfc_suspend_regs[] = { + { GATE_IP_MFC, 0xffffffff, 0xffffffff }, /* MFC gates */ + { SRC_TOP4, 0, BIT(28) }, /* MUX mout_user_aclk333 */ + { DIV4_RATIO, 0, 0x3 }, /* DIV dout_mfc_blk */ +}; + +static const struct exynos5_subcmu_info exynos5x_subcmus[] = { + { + .div_clks = exynos5x_disp_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_disp_div_clks), + .gate_clks = exynos5x_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_disp_gate_clks), + .suspend_regs = exynos5x_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs), + .pd_name = "DISP", + }, { + .div_clks = exynos5x_gsc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_gsc_div_clks), + .gate_clks = exynos5x_gsc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_gsc_gate_clks), + .suspend_regs = exynos5x_gsc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs), + .pd_name = "GSC", + }, { + .div_clks = exynos5x_mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_mfc_div_clks), + .gate_clks = exynos5x_mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_mfc_gate_clks), + .suspend_regs = exynos5x_mfc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs), + .pd_name = "MFC", + }, }; static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(2000000000, 250, 3, 0), - PLL_35XX_RATE(1900000000, 475, 6, 0), - PLL_35XX_RATE(1800000000, 225, 3, 0), - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 2, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(900000000, 150, 2, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 2, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(300000000, 200, 2, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 2000000000, 250, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000, 225, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 2, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 2, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 2, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 2, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), }; static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { - PLL_36XX_RATE(600000000U, 100, 2, 1, 0), - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), - PLL_36XX_RATE(361267218U, 301, 5, 2, 3671), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), - PLL_36XX_RATE(180633609U, 301, 5, 3, 3671), - PLL_36XX_RATE(131072006U, 131, 3, 3, 4719), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE( 65536003U, 131, 3, 4, 4719), - PLL_36XX_RATE( 49152000U, 197, 3, 5, -25690), - PLL_36XX_RATE( 32768001U, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 361267218U, 301, 5, 2, 3671), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 180633609U, 301, 5, 3, 3671), + PLL_36XX_RATE(24 * MHZ, 131072006U, 131, 3, 3, 4719), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 73728000U, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602U, 90, 2, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 65536003U, 131, 3, 4, 4719), + PLL_36XX_RATE(24 * MHZ, 49152000U, 197, 3, 5, -25690), + PLL_36XX_RATE(24 * MHZ, 45158401U, 90, 3, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 32768001U, 131, 3, 5, 4719), }; static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { @@ -1472,6 +1541,8 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0); exynos5420_clk_sleep_init(); + exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus), + exynos5x_subcmus); samsung_clk_of_add_provider(np, ctx); } @@ -1480,10 +1551,12 @@ static void __init exynos5420_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5420); } -CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5420_clk, "samsung,exynos5420-clock", + exynos5420_clk_init); static void __init exynos5800_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5800); } -CLK_OF_DECLARE(exynos5800_clk, "samsung,exynos5800-clock", exynos5800_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5800_clk, "samsung,exynos5800-clock", + exynos5800_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index db270908037a..5305ace514b2 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -703,68 +703,69 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { * & MPHY_PLL & G3D_PLL & DISP_PLL & ISP_PLL */ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = { - PLL_35XX_RATE(2500000000U, 625, 6, 0), - PLL_35XX_RATE(2400000000U, 500, 5, 0), - PLL_35XX_RATE(2300000000U, 575, 6, 0), - PLL_35XX_RATE(2200000000U, 550, 6, 0), - PLL_35XX_RATE(2100000000U, 350, 4, 0), - PLL_35XX_RATE(2000000000U, 500, 6, 0), - PLL_35XX_RATE(1900000000U, 475, 6, 0), - PLL_35XX_RATE(1800000000U, 375, 5, 0), - PLL_35XX_RATE(1700000000U, 425, 6, 0), - PLL_35XX_RATE(1600000000U, 400, 6, 0), - PLL_35XX_RATE(1500000000U, 250, 4, 0), - PLL_35XX_RATE(1400000000U, 350, 6, 0), - PLL_35XX_RATE(1332000000U, 222, 4, 0), - PLL_35XX_RATE(1300000000U, 325, 6, 0), - PLL_35XX_RATE(1200000000U, 500, 5, 1), - PLL_35XX_RATE(1100000000U, 550, 6, 1), - PLL_35XX_RATE(1086000000U, 362, 4, 1), - PLL_35XX_RATE(1066000000U, 533, 6, 1), - PLL_35XX_RATE(1000000000U, 500, 6, 1), - PLL_35XX_RATE(933000000U, 311, 4, 1), - PLL_35XX_RATE(921000000U, 307, 4, 1), - PLL_35XX_RATE(900000000U, 375, 5, 1), - PLL_35XX_RATE(825000000U, 275, 4, 1), - PLL_35XX_RATE(800000000U, 400, 6, 1), - PLL_35XX_RATE(733000000U, 733, 12, 1), - PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(667000000U, 222, 4, 1), - PLL_35XX_RATE(633000000U, 211, 4, 1), - PLL_35XX_RATE(600000000U, 500, 5, 2), - PLL_35XX_RATE(552000000U, 460, 5, 2), - PLL_35XX_RATE(550000000U, 550, 6, 2), - PLL_35XX_RATE(543000000U, 362, 4, 2), - PLL_35XX_RATE(533000000U, 533, 6, 2), - PLL_35XX_RATE(500000000U, 500, 6, 2), - PLL_35XX_RATE(444000000U, 370, 5, 2), - PLL_35XX_RATE(420000000U, 350, 5, 2), - PLL_35XX_RATE(400000000U, 400, 6, 2), - PLL_35XX_RATE(350000000U, 350, 6, 2), - PLL_35XX_RATE(333000000U, 222, 4, 2), - PLL_35XX_RATE(300000000U, 500, 5, 3), - PLL_35XX_RATE(278000000U, 556, 6, 3), - PLL_35XX_RATE(266000000U, 532, 6, 3), - PLL_35XX_RATE(250000000U, 500, 6, 3), - PLL_35XX_RATE(200000000U, 400, 6, 3), - PLL_35XX_RATE(166000000U, 332, 6, 3), - PLL_35XX_RATE(160000000U, 320, 6, 3), - PLL_35XX_RATE(133000000U, 532, 6, 4), - PLL_35XX_RATE(100000000U, 400, 6, 4), + PLL_35XX_RATE(24 * MHZ, 2500000000U, 625, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2400000000U, 500, 5, 0), + PLL_35XX_RATE(24 * MHZ, 2300000000U, 575, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2200000000U, 550, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2100000000U, 350, 4, 0), + PLL_35XX_RATE(24 * MHZ, 2000000000U, 500, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000U, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000U, 375, 5, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000U, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000U, 400, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000U, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000U, 350, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1332000000U, 222, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000U, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000U, 500, 5, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000U, 550, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1086000000U, 362, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000U, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000U, 500, 6, 1), + PLL_35XX_RATE(24 * MHZ, 933000000U, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 921000000U, 307, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000U, 375, 5, 1), + PLL_35XX_RATE(24 * MHZ, 825000000U, 275, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000U, 400, 6, 1), + PLL_35XX_RATE(24 * MHZ, 733000000U, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000U, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 666000000U, 222, 4, 1), + PLL_35XX_RATE(24 * MHZ, 633000000U, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 600000000U, 500, 5, 2), + PLL_35XX_RATE(24 * MHZ, 552000000U, 460, 5, 2), + PLL_35XX_RATE(24 * MHZ, 550000000U, 550, 6, 2), + PLL_35XX_RATE(24 * MHZ, 543000000U, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000U, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000U, 500, 6, 2), + PLL_35XX_RATE(24 * MHZ, 444000000U, 370, 5, 2), + PLL_35XX_RATE(24 * MHZ, 420000000U, 350, 5, 2), + PLL_35XX_RATE(24 * MHZ, 400000000U, 400, 6, 2), + PLL_35XX_RATE(24 * MHZ, 350000000U, 350, 6, 2), + PLL_35XX_RATE(24 * MHZ, 333000000U, 222, 4, 2), + PLL_35XX_RATE(24 * MHZ, 300000000U, 500, 5, 3), + PLL_35XX_RATE(24 * MHZ, 278000000U, 556, 6, 3), + PLL_35XX_RATE(24 * MHZ, 266000000U, 532, 6, 3), + PLL_35XX_RATE(24 * MHZ, 250000000U, 500, 6, 3), + PLL_35XX_RATE(24 * MHZ, 200000000U, 400, 6, 3), + PLL_35XX_RATE(24 * MHZ, 166000000U, 332, 6, 3), + PLL_35XX_RATE(24 * MHZ, 160000000U, 320, 6, 3), + PLL_35XX_RATE(24 * MHZ, 133000000U, 532, 6, 4), + PLL_35XX_RATE(24 * MHZ, 100000000U, 400, 6, 4), { /* sentinel */ } }; /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), - PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), - PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), - PLL_36XX_RATE(288000000U, 96, 1, 3, 0), - PLL_36XX_RATE(252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 384000000U, 128, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(24 * MHZ, 361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(24 * MHZ, 338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(24 * MHZ, 294912002U, 98, 1, 3, 19923), + PLL_36XX_RATE(24 * MHZ, 288000000U, 96, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), { /* sentinel */ } }; @@ -1672,7 +1673,7 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = { ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk", "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10, - CLK_SET_RATE_PARENT, 0), + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric", ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric", @@ -5513,10 +5514,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } for (i = 0; i < info->nr_clk_ids; ++i) ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 5931a4140c3d..492d51691080 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491520000, 20, 1, 0, 31457), + PLL_36XX_RATE(24 * MHZ, 491519897, 20, 1, 0, 31457), {}, }; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 61eb8abbfd9c..ca57b3dfa814 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -41,35 +41,62 @@ enum samsung_pll_type { pll_1460x, }; -#define PLL_35XX_RATE(_rate, _m, _p, _s) \ +#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ + ((u64)(_fin) * (BIT(_ks) * (_m) + (_k)) / BIT(_ks) / ((_p) << (_s))) +#define PLL_VALID_RATE(_fin, _fout, _m, _p, _s, _k, _ks) ((_fout) + \ + BUILD_BUG_ON_ZERO(PLL_RATE(_fin, _m, _p, _s, _k, _ks) != (_fout))) + +#define PLL_35XX_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2410_MPLL_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m + 8, _p + 2, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2440_MPLL_RATE(_fin, _rate, _m, _p, _s) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + 2 * (_m + 8), _p + 2, _s, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ } -#define PLL_36XX_RATE(_rate, _m, _p, _s, _k) \ +#define PLL_36XX_RATE(_fin, _rate, _m, _p, _s, _k) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .kdiv = (_k), \ } -#define PLL_45XX_RATE(_rate, _m, _p, _s, _afc) \ +#define PLL_4508_RATE(_fin, _rate, _m, _p, _s, _afc) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s - 1, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .afc = (_afc), \ } -#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel) \ +#define PLL_4600_RATE(_fin, _rate, _m, _p, _s, _k, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ @@ -77,9 +104,10 @@ enum samsung_pll_type { .vsel = (_vsel), \ } -#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ +#define PLL_4650_RATE(_fin, _rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 10), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index e0650c33863b..a9c887475054 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -95,7 +95,7 @@ static void __init s3c2410_clk_sleep_init(void) {} PNAME(fclk_p) = { "mpll", "div_slow" }; -struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1), }; @@ -111,12 +111,12 @@ static struct clk_div_table divslow_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2410_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_common_dividers[] __initdata = { DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d), DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1), }; -struct samsung_gate_clock s3c2410_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2410_common_gates[] __initdata = { GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0), GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0), @@ -135,7 +135,7 @@ struct samsung_gate_clock s3c2410_common_gates[] __initdata = { }; /* should be added _after_ the soc-specific clocks are created */ -struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), ALIAS(PCLK_ADC, NULL, "adc"), ALIAS(PCLK_RTC, NULL, "rtc"), @@ -162,34 +162,34 @@ struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { /* sorted in descending order */ /* 2410A extras */ - PLL_35XX_RATE(270000000, 127, 1, 1), - PLL_35XX_RATE(268000000, 126, 1, 1), - PLL_35XX_RATE(266000000, 125, 1, 1), - PLL_35XX_RATE(226000000, 105, 1, 1), - PLL_35XX_RATE(210000000, 132, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 270000000, 127, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 268000000, 126, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 266000000, 125, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 226000000, 105, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), - PLL_35XX_RATE(192000000, 88, 1, 1), - PLL_35XX_RATE(186000000, 85, 1, 1), - PLL_35XX_RATE(180000000, 82, 1, 1), - PLL_35XX_RATE(170000000, 77, 1, 1), - PLL_35XX_RATE(158000000, 71, 1, 1), - PLL_35XX_RATE(152000000, 68, 1, 1), - PLL_35XX_RATE(147000000, 90, 2, 1), - PLL_35XX_RATE(135000000, 82, 2, 1), - PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), - PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), - PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), - PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), - PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), - PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 202800000, 161, 3, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 192000000, 88, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 186000000, 85, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 180000000, 82, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 170000000, 77, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 158000000, 71, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 152000000, 68, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 147000000, 90, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 135000000, 82, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 124000000, 116, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 118500000, 150, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 113000000, 105, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 101250000, 127, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 90000000, 112, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 84750000, 105, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 79000000, 71, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 67500000, 82, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 56250000, 142, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 48000000, 120, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 50700000, 161, 3, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 45000000, 82, 1, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 33750000, 82, 2, 3), { /* sentinel */ }, }; @@ -200,11 +200,11 @@ static struct samsung_pll_clock s3c2410_plls[] __initdata = { LOCKTIME, UPLLCON, NULL), }; -struct samsung_div_clock s3c2410_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_dividers[] __initdata = { DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1), }; -struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { /* * armclk is directly supplied by the fclk, without * switching possibility like on the s3c244x below. @@ -215,7 +215,7 @@ struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { FFACTOR(UCLK, "uclk", "upll", 1, 1, 0), }; -struct samsung_clock_alias s3c2410_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"), @@ -229,33 +229,33 @@ struct samsung_clock_alias s3c2410_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = { /* sorted in descending order */ - PLL_35XX_RATE(400000000, 0x5c, 1, 1), - PLL_35XX_RATE(390000000, 0x7a, 2, 1), - PLL_35XX_RATE(380000000, 0x57, 1, 1), - PLL_35XX_RATE(370000000, 0xb1, 4, 1), - PLL_35XX_RATE(360000000, 0x70, 2, 1), - PLL_35XX_RATE(350000000, 0xa7, 4, 1), - PLL_35XX_RATE(340000000, 0x4d, 1, 1), - PLL_35XX_RATE(330000000, 0x66, 2, 1), - PLL_35XX_RATE(320000000, 0x98, 4, 1), - PLL_35XX_RATE(310000000, 0x93, 4, 1), - PLL_35XX_RATE(300000000, 0x75, 3, 1), - PLL_35XX_RATE(240000000, 0x70, 1, 2), - PLL_35XX_RATE(230000000, 0x6b, 1, 2), - PLL_35XX_RATE(220000000, 0x66, 1, 2), - PLL_35XX_RATE(210000000, 0x84, 2, 2), - PLL_35XX_RATE(200000000, 0x5c, 1, 2), - PLL_35XX_RATE(190000000, 0x57, 1, 2), - PLL_35XX_RATE(180000000, 0x70, 2, 2), - PLL_35XX_RATE(170000000, 0x4d, 1, 2), - PLL_35XX_RATE(160000000, 0x98, 4, 2), - PLL_35XX_RATE(150000000, 0x75, 3, 2), - PLL_35XX_RATE(120000000, 0x70, 1, 3), - PLL_35XX_RATE(110000000, 0x66, 1, 3), - PLL_35XX_RATE(100000000, 0x5c, 1, 3), - PLL_35XX_RATE(90000000, 0x70, 2, 3), - PLL_35XX_RATE(80000000, 0x98, 4, 3), - PLL_35XX_RATE(75000000, 0x75, 3, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 400000000, 0x5c, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 390000000, 0x7a, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 380000000, 0x57, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 370000000, 0xb1, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 360000000, 0x70, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 350000000, 0xa7, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 340000000, 0x4d, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 330000000, 0x66, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 320000000, 0x98, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 310000000, 0x93, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 300000000, 0x75, 3, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 240000000, 0x70, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 230000000, 0x6b, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 220000000, 0x66, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 210000000, 0x84, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 200000000, 0x5c, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 190000000, 0x57, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 180000000, 0x70, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 170000000, 0x4d, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 160000000, 0x98, 4, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 150000000, 0x75, 3, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 120000000, 0x70, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 110000000, 0x66, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 100000000, 0x5c, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 90000000, 0x70, 2, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 80000000, 0x98, 4, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 75000000, 0x75, 3, 3), { /* sentinel */ }, }; @@ -269,12 +269,12 @@ static struct samsung_pll_clock s3c244x_common_plls[] __initdata = { PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" }; PNAME(armclk_p) = { "fclk", "hclk" }; -struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2), MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1), }; -struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0), FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT), }; @@ -291,7 +291,7 @@ static struct clk_div_table div_hclk_3_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c244x_common_dividers[] __initdata = { +static struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1), DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1), DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d), @@ -299,11 +299,11 @@ struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(0, "div_cam", "upll", CAMDIVN, 0, 3), }; -struct samsung_gate_clock s3c244x_common_gates[] __initdata = { +static struct samsung_gate_clock s3c244x_common_gates[] __initdata = { GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), @@ -318,23 +318,23 @@ struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { PNAME(s3c2440_camif_p) = { "upll", "ff_cam" }; -struct samsung_mux_clock s3c2440_muxes[] __initdata = { +static struct samsung_mux_clock s3c2440_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1), }; -struct samsung_gate_clock s3c2440_gates[] __initdata = { +static struct samsung_gate_clock s3c2440_gates[] __initdata = { GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0), }; /* S3C2442 specific clocks */ -struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { FFACTOR(0, "upll_3", "upll", 1, 3, 0), }; PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" }; -struct samsung_mux_clock s3c2442_muxes[] __initdata = { +static struct samsung_mux_clock s3c2442_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2), }; @@ -343,7 +343,7 @@ struct samsung_mux_clock s3c2442_muxes[] __initdata = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), }; @@ -468,18 +468,18 @@ void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2410_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2410, 0); + s3c2410_common_clk_init(np, 0, S3C2410, NULL); } CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init); static void __init s3c2440_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2440, 0); + s3c2410_common_clk_init(np, 0, S3C2440, NULL); } CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init); static void __init s3c2442_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2442, 0); + s3c2410_common_clk_init(np, 0, S3C2442, NULL); } CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index b8340a49921b..6bc94d3aff78 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -27,11 +27,6 @@ #define CLKSRC 0x1c #define SWRST 0x30 -/* list of PLLs to be registered */ -enum s3c2412_plls { - mpll, upll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -98,7 +93,7 @@ static struct clk_div_table divxti_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2412_dividers[] __initdata = { +static struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), @@ -110,7 +105,7 @@ struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), }; -struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), }; @@ -130,7 +125,7 @@ PNAME(msysclk_p) = { "mdivclk", "mpll" }; PNAME(mdivclk_p) = { "xti", "div_xti" }; PNAME(armclk_p) = { "armdiv", "hclk" }; -struct samsung_mux_clock s3c2412_muxes[] __initdata = { +static struct samsung_mux_clock s3c2412_muxes[] __initdata = { MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), @@ -144,13 +139,11 @@ struct samsung_mux_clock s3c2412_muxes[] __initdata = { }; static struct samsung_pll_clock s3c2412_plls[] __initdata = { - [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", - LOCKTIME, MPLLCON, NULL), - [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", - LOCKTIME, UPLLCON, NULL), + PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", LOCKTIME, MPLLCON, NULL), + PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL), }; -struct samsung_gate_clock s3c2412_gates[] __initdata = { +static struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), @@ -181,7 +174,7 @@ struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), }; -struct samsung_clock_alias s3c2412_aliases[] __initdata = { +static struct samsung_clock_alias s3c2412_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), @@ -231,7 +224,7 @@ static struct notifier_block s3c2412_restart_handler = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), }; @@ -296,6 +289,6 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2412_clk_init(struct device_node *np) { - s3c2412_common_clk_init(np, 0, 0, 0); + s3c2412_common_clk_init(np, 0, 0, NULL); } CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index d94b85a42356..c46e6d5bc9bc 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -41,11 +41,6 @@ enum supported_socs { S3C2450, }; -/* list of PLLs to be registered */ -enum s3c2443_plls { - mpll, epll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -113,7 +108,7 @@ PNAME(msysclk_p) = { "mpllref", "mpll" }; PNAME(armclk_p) = { "armdiv" , "hclk" }; PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" }; -struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), @@ -141,7 +136,7 @@ static struct clk_div_table mdivclk_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d), DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2), DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d), @@ -154,7 +149,7 @@ struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2), }; -struct samsung_gate_clock s3c2443_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0), GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0), GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0), @@ -188,7 +183,7 @@ struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0), }; -struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { ALIAS(MSYSCLK, NULL, "msysclk"), ALIAS(ARMCLK, NULL, "armclk"), ALIAS(MPLL, NULL, "mpll"), @@ -225,10 +220,8 @@ struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { /* S3C2416 specific clocks */ static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { - [mpll] = PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_6553, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" }; @@ -245,19 +238,19 @@ static struct clk_div_table armdiv_s3c2416_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2416_dividers[] __initdata = { +static struct samsung_div_clock s3c2416_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d), DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4), DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2), }; -struct samsung_mux_clock s3c2416_muxes[] __initdata = { +static struct samsung_mux_clock s3c2416_muxes[] __initdata = { MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1), MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1), MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1), }; -struct samsung_gate_clock s3c2416_gates[] __initdata = { +static struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0), GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0), @@ -267,7 +260,7 @@ struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c2416_aliases[] __initdata = { +static struct samsung_clock_alias s3c2416_aliases[] __initdata = { ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"), @@ -279,10 +272,8 @@ struct samsung_clock_alias s3c2416_aliases[] __initdata = { /* S3C2443 specific clocks */ static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { - [mpll] = PLL(pll_3000, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_2126, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; static struct clk_div_table armdiv_s3c2443_d[] = { @@ -297,12 +288,12 @@ static struct clk_div_table armdiv_s3c2443_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d), DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), }; -struct samsung_gate_clock s3c2443_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0), @@ -311,7 +302,7 @@ struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0), }; -struct samsung_clock_alias s3c2443_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_aliases[] __initdata = { ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), ALIAS(SCLK_CAM, NULL, "camif-upll"), @@ -327,20 +318,20 @@ PNAME(s3c2450_cam_p) = { "div_cam", "hclk" }; PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" }; PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" }; -struct samsung_div_clock s3c2450_dividers[] __initdata = { +static struct samsung_div_clock s3c2450_dividers[] __initdata = { DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2), DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4), DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4), }; -struct samsung_mux_clock s3c2450_muxes[] __initdata = { +static struct samsung_mux_clock s3c2450_muxes[] __initdata = { MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1), MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1), MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2), }; -struct samsung_gate_clock s3c2450_gates[] __initdata = { +static struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0), GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), @@ -351,7 +342,7 @@ struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0), }; -struct samsung_clock_alias s3c2450_aliases[] __initdata = { +static struct samsung_clock_alias s3c2450_aliases[] __initdata = { ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"), ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"), ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"), @@ -374,7 +365,7 @@ static struct notifier_block s3c2443_restart_handler = { * fixed rate clocks generated outside the soc * Only necessary until the devicetree-move is complete */ -struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { FRATE(0, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), FRATE(0, "ext_i2s", NULL, 0, 0), @@ -470,18 +461,18 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2416_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2416, 0); + s3c2443_common_clk_init(np, 0, S3C2416, NULL); } CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init); static void __init s3c2443_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2443, 0); + s3c2443_common_clk_init(np, 0, S3C2443, NULL); } CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init); static void __init s3c2450_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2450, 0); + s3c2443_common_clk_init(np, 0, S3C2450, NULL); } CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init); diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 7306867a0ab8..6db01cf5ab83 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -56,11 +56,6 @@ #define GATE_ON(_id, cname, pname, o, b) \ GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0) -/* list of PLLs to be registered */ -enum s3c64xx_plls { - apll, mpll, epll, -}; - static void __iomem *reg_base; static bool is_s3c6400; @@ -364,12 +359,12 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = { /* List of PLL clocks. */ static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = { - [apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON, NULL), - [mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", - MPLL_LOCK, MPLL_CON, NULL), - [epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", - EPLL_LOCK, EPLL_CON0, NULL), + PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", + APLL_LOCK, APLL_CON, NULL), + PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", + MPLL_LOCK, MPLL_CON, NULL), + PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", + EPLL_LOCK, EPLL_CON0, NULL), }; /* Aliases for common s3c64xx clocks. */ diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 11a5066e5c27..5234acd30e89 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -515,7 +515,7 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, init.name = "emc"; init.ops = &tegra_clk_emc_ops; - init.flags = 0; + init.flags = CLK_IS_CRITICAL; init.parent_names = emc_parent_clk_names; init.num_parents = ARRAY_SIZE(emc_parent_clk_names); diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 7c369e21c91c..830d1c87fa7c 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1151,6 +1151,8 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, }; static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index c02711927d79..2acba2986bc6 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -830,7 +830,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0), GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0), GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0), - GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED), + GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IS_CRITICAL), GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0), GATE("ispa", "isp", 23, 0, tegra_clk_ispa, 0), GATE("ispb", "isp", 3, 0, tegra_clk_ispb, 0), diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 10047107c1dc..89d6b47a27a8 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -125,7 +125,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, /* SCLK */ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); if (dt_clk) { - clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0, + clk = clk_register_divider(NULL, "sclk", "sclk_mux", + CLK_IS_CRITICAL, clk_base + SCLK_DIVIDER, 0, 8, 0, &sysrate_lock); *dt_clk = clk; @@ -137,7 +138,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk = tegra_clk_register_super_mux("sclk", gen_info->sclk_parents, gen_info->num_sclk_parents, - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | + CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); *dt_clk = clk; @@ -151,7 +153,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk_base + SYSTEM_CLK_RATE, 4, 2, 0, &sysrate_lock); clk = clk_register_gate(NULL, "hclk", "hclk_div", - CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE, 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); *dt_clk = clk; diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 63087d17c3e2..5d5a22d529f5 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -955,8 +955,7 @@ static void __init tegra114_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA114_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -1190,6 +1189,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 }, { TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 }, { TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 }, + { TEGRA114_CLK_VDE, TEGRA114_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e81ea5b11577..50088e976611 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1089,8 +1089,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clk_register_clkdev(clk, "pll_m", NULL); clks[TEGRA124_CLK_PLL_M] = clk; @@ -1099,7 +1098,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clk_register_clkdev(clk, "pll_m_out1", NULL); clks[TEGRA124_CLK_PLL_M_OUT1] = clk; @@ -1268,11 +1267,11 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, - { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 }, + { TEGRA124_CLK_VDE, TEGRA124_CLK_CLK_MAX, 600000000, 0 }, { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, - { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 }, + { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 0 }, { TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 }, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index cbd5a2e5c569..0ee56dd04cec 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -576,6 +576,7 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true }, [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA20_CLK_EMC, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) @@ -651,8 +652,7 @@ static void tegra20_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA20_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -660,7 +660,7 @@ static void tegra20_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA20_CLK_PLL_M_OUT1] = clk; @@ -723,7 +723,8 @@ static void tegra20_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, - ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA20_CLK_SCLK] = clk; @@ -814,9 +815,6 @@ static void __init tegra20_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA20_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1019,13 +1017,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 }, { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 }, { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 }, - { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 }, - { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 1 }, - { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 }, - { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 }, + { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 }, + { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, + { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 }, + { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, + { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 }, { TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 }, { TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 }, @@ -1051,6 +1048,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 }, { TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 }, { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 }, + { TEGRA20_CLK_VDE, TEGRA20_CLK_CLK_MAX, 300000000, 0 }, /* must be the last entry */ { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 9e6260869eb9..9fb5d51ccce4 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -22,10 +22,12 @@ #include <linux/of_address.h> #include <linux/delay.h> #include <linux/export.h> +#include <linux/mutex.h> #include <linux/clk/tegra.h> #include <dt-bindings/clock/tegra210-car.h> #include <dt-bindings/reset/tegra210-car.h> #include <linux/iopoll.h> +#include <soc/tegra/pmc.h> #include "clk.h" #include "clk-id.h" @@ -41,6 +43,7 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_SOR1 0x410 +#define CLK_SOURCE_LA 0x1f8 #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 @@ -231,6 +234,30 @@ #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8 #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac +#define LVL2_CLK_GATE_OVRA 0xf8 +#define LVL2_CLK_GATE_OVRC 0x3a0 +#define LVL2_CLK_GATE_OVRD 0x3a4 +#define LVL2_CLK_GATE_OVRE 0x554 + +/* I2S registers to handle during APE MBIST WAR */ +#define TEGRA210_I2S_BASE 0x1000 +#define TEGRA210_I2S_SIZE 0x100 +#define TEGRA210_I2S_CTRLS 5 +#define TEGRA210_I2S_CG 0x88 +#define TEGRA210_I2S_CTRL 0xa0 + +/* DISPA registers to handle during MBIST WAR */ +#define DC_CMD_DISPLAY_COMMAND 0xc8 +#define DC_COM_DSC_TOP_CTL 0xcf8 + +/* VIC register to handle during MBIST WAR */ +#define NV_PVIC_THI_SLCG_OVERRIDE_LOW 0x8c + +/* APE, DISPA and VIC base addesses needed for MBIST WAR */ +#define TEGRA210_AHUB_BASE 0x702d0000 +#define TEGRA210_DISPA_BASE 0x54200000 +#define TEGRA210_VIC_BASE 0x54340000 + /* * SDM fractional divisor is 16-bit 2's complement signed number within * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned @@ -255,8 +282,22 @@ static struct cpu_clk_suspend_context { } tegra210_cpu_clk_sctx; #endif +struct tegra210_domain_mbist_war { + void (*handle_lvl2_ovr)(struct tegra210_domain_mbist_war *mbist); + const u32 lvl2_offset; + const u32 lvl2_mask; + const unsigned int num_clks; + const unsigned int *clk_init_data; + struct clk_bulk_data *clks; +}; + +static struct clk **clks; + static void __iomem *clk_base; static void __iomem *pmc_base; +static void __iomem *ahub_base; +static void __iomem *dispa_base; +static void __iomem *vic_base; static unsigned long osc_freq; static unsigned long pll_ref_freq; @@ -267,6 +308,7 @@ static DEFINE_SPINLOCK(pll_re_lock); static DEFINE_SPINLOCK(pll_u_lock); static DEFINE_SPINLOCK(sor1_lock); static DEFINE_SPINLOCK(emc_lock); +static DEFINE_MUTEX(lvl2_ovr_lock); /* possible OSC frequencies in Hz */ static unsigned long tegra210_input_freq[] = { @@ -310,6 +352,8 @@ static const char *mux_pllmcp_clkm[] = { #define PLLA_MISC2_WRITE_MASK 0x06ffffff /* PLLD */ +#define PLLD_BASE_CSI_CLKSOURCE (1 << 23) + #define PLLD_MISC0_EN_SDM (1 << 16) #define PLLD_MISC0_LOCK_OVERRIDE (1 << 17) #define PLLD_MISC0_LOCK_ENABLE (1 << 18) @@ -513,6 +557,115 @@ void tegra210_set_sata_pll_seq_sw(bool state) } EXPORT_SYMBOL_GPL(tegra210_set_sata_pll_seq_sw); +static void tegra210_generic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 val; + + val = readl_relaxed(clk_base + mbist->lvl2_offset); + writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); + writel_relaxed(val, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); +} + +static void tegra210_venc_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 csi_src, ovra, ovre; + unsigned long flags = 0; + + spin_lock_irqsave(&pll_d_lock, flags); + + csi_src = readl_relaxed(clk_base + PLLD_BASE); + writel_relaxed(csi_src | PLLD_BASE_CSI_CLKSOURCE, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(15), clk_base + LVL2_CLK_GATE_OVRA); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(3), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(csi_src, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + spin_unlock_irqrestore(&pll_d_lock, flags); +} + +static void tegra210_disp_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovra, dsc_top_ctrl; + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(1), clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); + + dsc_top_ctrl = readl_relaxed(dispa_base + DC_COM_DSC_TOP_CTL); + writel_relaxed(dsc_top_ctrl | BIT(2), dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + writel_relaxed(dsc_top_ctrl, dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); +} + +static void tegra210_vic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovre, val; + + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(5), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + val = readl_relaxed(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + writel_relaxed(val | BIT(0) | GENMASK(7, 2) | BIT(24), + vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + fence_udelay(1, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(val, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + readl(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + +static void tegra210_ape_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + void __iomem *i2s_base; + unsigned int i; + u32 ovrc, ovre; + + ovrc = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRC); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovrc | BIT(1), clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre | BIT(10) | BIT(11), + clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + i2s_base = ahub_base + TEGRA210_I2S_BASE; + + for (i = 0; i < TEGRA210_I2S_CTRLS; i++) { + u32 i2s_ctrl; + + i2s_ctrl = readl_relaxed(i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(i2s_ctrl | BIT(10), + i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(0, i2s_base + TEGRA210_I2S_CG); + readl(i2s_base + TEGRA210_I2S_CG); + writel_relaxed(1, i2s_base + TEGRA210_I2S_CG); + writel_relaxed(i2s_ctrl, i2s_base + TEGRA210_I2S_CTRL); + readl(i2s_base + TEGRA210_I2S_CTRL); + + i2s_base += TEGRA210_I2S_SIZE; + } + + writel_relaxed(ovrc, clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + static inline void _pll_misc_chk_default(void __iomem *base, struct tegra_clk_pll_params *params, u8 misc_num, u32 default_val, u32 mask) @@ -2411,13 +2564,150 @@ static struct tegra_audio_clk_info tegra210_audio_plls[] = { { "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" }, }; -static struct clk **clks; - static const char * const aclk_parents[] = { "pll_a1", "pll_c", "pll_p", "pll_a_out0", "pll_c2", "pll_c3", "clk_m" }; +static const unsigned int nvjpg_slcg_clkids[] = { TEGRA210_CLK_NVDEC }; +static const unsigned int nvdec_slcg_clkids[] = { TEGRA210_CLK_NVJPG }; +static const unsigned int sor_slcg_clkids[] = { TEGRA210_CLK_HDA2CODEC_2X, + TEGRA210_CLK_HDA2HDMI, TEGRA210_CLK_DISP1, TEGRA210_CLK_DISP2 }; +static const unsigned int disp_slcg_clkids[] = { TEGRA210_CLK_LA, + TEGRA210_CLK_HOST1X}; +static const unsigned int xusba_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_DEV }; +static const unsigned int xusbb_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int xusbc_slcg_clkids[] = { TEGRA210_CLK_XUSB_DEV, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int venc_slcg_clkids[] = { TEGRA210_CLK_HOST1X, + TEGRA210_CLK_PLL_D }; +static const unsigned int ape_slcg_clkids[] = { TEGRA210_CLK_ACLK, + TEGRA210_CLK_I2S0, TEGRA210_CLK_I2S1, TEGRA210_CLK_I2S2, + TEGRA210_CLK_I2S3, TEGRA210_CLK_I2S4, TEGRA210_CLK_SPDIF_OUT, + TEGRA210_CLK_D_AUDIO }; +static const unsigned int vic_slcg_clkids[] = { TEGRA210_CLK_HOST1X }; + +static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = { + [TEGRA_POWERGATE_VENC] = { + .handle_lvl2_ovr = tegra210_venc_mbist_war, + .num_clks = ARRAY_SIZE(venc_slcg_clkids), + .clk_init_data = venc_slcg_clkids, + }, + [TEGRA_POWERGATE_SATA] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(0) | BIT(17) | BIT(19), + }, + [TEGRA_POWERGATE_MPE] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRE, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_SOR] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .num_clks = ARRAY_SIZE(sor_slcg_clkids), + .clk_init_data = sor_slcg_clkids, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(1) | BIT(2), + }, + [TEGRA_POWERGATE_DIS] = { + .handle_lvl2_ovr = tegra210_disp_mbist_war, + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + }, + [TEGRA_POWERGATE_DISB] = { + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_XUSBA] = { + .num_clks = ARRAY_SIZE(xusba_slcg_clkids), + .clk_init_data = xusba_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBB] = { + .num_clks = ARRAY_SIZE(xusbb_slcg_clkids), + .clk_init_data = xusbb_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBC] = { + .num_clks = ARRAY_SIZE(xusbc_slcg_clkids), + .clk_init_data = xusbc_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_VIC] = { + .num_clks = ARRAY_SIZE(vic_slcg_clkids), + .clk_init_data = vic_slcg_clkids, + .handle_lvl2_ovr = tegra210_vic_mbist_war, + }, + [TEGRA_POWERGATE_NVDEC] = { + .num_clks = ARRAY_SIZE(nvdec_slcg_clkids), + .clk_init_data = nvdec_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_NVJPG] = { + .num_clks = ARRAY_SIZE(nvjpg_slcg_clkids), + .clk_init_data = nvjpg_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_AUD] = { + .num_clks = ARRAY_SIZE(ape_slcg_clkids), + .clk_init_data = ape_slcg_clkids, + .handle_lvl2_ovr = tegra210_ape_mbist_war, + }, + [TEGRA_POWERGATE_VE2] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRD, + .lvl2_mask = BIT(22), + }, +}; + +int tegra210_clk_handle_mbist_war(unsigned int id) +{ + int err; + struct tegra210_domain_mbist_war *mbist_war; + + if (id >= ARRAY_SIZE(tegra210_pg_mbist_war)) { + WARN(1, "unknown domain id in MBIST WAR handler\n"); + return -EINVAL; + } + + mbist_war = &tegra210_pg_mbist_war[id]; + if (!mbist_war->handle_lvl2_ovr) + return 0; + + if (mbist_war->num_clks && !mbist_war->clks) + return -ENODEV; + + err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks); + if (err < 0) + return err; + + mutex_lock(&lvl2_ovr_lock); + + mbist_war->handle_lvl2_ovr(mbist_war); + + mutex_unlock(&lvl2_ovr_lock); + + clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks); + + return 0; +} + void tegra210_put_utmipll_in_iddq(void) { u32 reg; @@ -2654,6 +2944,13 @@ static struct tegra_periph_init_data tegra210_periph[] = { sor1_parents_idx, 0, &sor1_lock), }; +static const char * const la_parents[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_re_out1", "pll_a1", "clk_m", "pll_c4_out0" +}; + +static struct tegra_clk_periph tegra210_la = + TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, 0); + static __init void tegra210_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base) { @@ -2700,6 +2997,12 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, periph_clk_enb_refcnt); clks[TEGRA210_CLK_DSIB] = clk; + /* la */ + clk = tegra_clk_register_periph("la", la_parents, + ARRAY_SIZE(la_parents), &tegra210_la, clk_base, + CLK_SOURCE_LA, 0); + clks[TEGRA210_CLK_LA] = clk; + /* emc mux */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), 0, @@ -3025,7 +3328,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1 }, { TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1 }, - { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1 }, + { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 0 }, { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, @@ -3040,7 +3343,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_XUSB_DEV_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 }, { TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0 }, { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0 }, - { TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1 }, /* TODO find a way to enable this on-demand */ @@ -3149,6 +3451,37 @@ static int tegra210_reset_deassert(unsigned long id) return 0; } +static void tegra210_mbist_clk_init(void) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(tegra210_pg_mbist_war); i++) { + unsigned int num_clks = tegra210_pg_mbist_war[i].num_clks; + struct clk_bulk_data *clk_data; + + if (!num_clks) + continue; + + clk_data = kmalloc_array(num_clks, sizeof(*clk_data), + GFP_KERNEL); + if (WARN_ON(!clk_data)) + return; + + tegra210_pg_mbist_war[i].clks = clk_data; + for (j = 0; j < num_clks; j++) { + int clk_id = tegra210_pg_mbist_war[i].clk_init_data[j]; + struct clk *clk = clks[clk_id]; + + if (WARN(IS_ERR(clk), "clk_id: %d\n", clk_id)) { + kfree(clk_data); + tegra210_pg_mbist_war[i].clks = NULL; + break; + } + clk_data[j].clk = clk; + } + } +} + /** * tegra210_clock_init - Tegra210-specific clock initialization * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -3183,6 +3516,24 @@ static void __init tegra210_clock_init(struct device_node *np) return; } + ahub_base = ioremap(TEGRA210_AHUB_BASE, SZ_64K); + if (!ahub_base) { + pr_err("ioremap tegra210 APE failed\n"); + return; + } + + dispa_base = ioremap(TEGRA210_DISPA_BASE, SZ_256K); + if (!dispa_base) { + pr_err("ioremap tegra210 DISPA failed\n"); + return; + } + + vic_base = ioremap(TEGRA210_VIC_BASE, SZ_256K); + if (!vic_base) { + pr_err("ioremap tegra210 VIC failed\n"); + return; + } + clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX, TEGRA210_CAR_BANK_COUNT); if (!clks) @@ -3219,6 +3570,8 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_add_of_provider(np); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + tegra210_mbist_clk_init(); + tegra_cpu_car_ops = &tegra210_cpu_car_ops; } CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index bee84c554932..b316dfb6f6c7 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -819,6 +819,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true }, [tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true }, [tegra_clk_cec] = { .dt_id = TEGRA30_CLK_CEC, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = true }, }; static const char *pll_e_parents[] = { "pll_ref", "pll_p" }; @@ -843,8 +844,7 @@ static void __init tegra30_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA30_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -852,7 +852,7 @@ static void __init tegra30_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA30_CLK_PLL_M_OUT1] = clk; @@ -990,7 +990,7 @@ static void __init tegra30_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, ARRAY_SIZE(sclk_parents), - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA30_CLK_SCLK] = clk; @@ -1060,9 +1060,6 @@ static void __init tegra30_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA30_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1252,10 +1249,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0 }, - { TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0 }, @@ -1272,6 +1266,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, + { TEGRA30_CLK_VDE, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3b2763df51c2..ba7e20e6a82b 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -812,4 +812,11 @@ int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll); u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate); int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div); +/* Combined read fence with delay */ +#define fence_udelay(delay, reg) \ + do { \ + readl(reg); \ + udelay(delay); \ + } while (0) + #endif /* TEGRA_CLK_H */ diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index f4d6802a8544..7d22e1af2247 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -55,6 +55,29 @@ static void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg) writel_relaxed(val, io->mem + reg->offset); } +static void _clk_rmw(u32 val, u32 mask, void __iomem *ptr) +{ + u32 v; + + v = readl_relaxed(ptr); + v &= ~mask; + v |= val; + writel_relaxed(v, ptr); +} + +static void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg) +{ + struct clk_iomap *io = clk_memmaps[reg->index]; + + if (reg->ptr) { + _clk_rmw(val, mask, reg->ptr); + } else if (io->regmap) { + regmap_update_bits(io->regmap, reg->offset, mask, val); + } else { + _clk_rmw(val, mask, io->mem + reg->offset); + } +} + static u32 clk_memmap_readl(const struct clk_omap_reg *reg) { u32 val; @@ -89,6 +112,7 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) ti_clk_ll_ops = ops; ops->clk_readl = clk_memmap_readl; ops->clk_writel = clk_memmap_writel; + ops->clk_rmw = clk_memmap_rmw; return 0; } @@ -251,6 +275,20 @@ int ti_clk_get_reg_addr(struct device_node *node, int index, return 0; } +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift) +{ + u32 latch; + + if (shift < 0) + return; + + latch = 1 << shift; + + ti_clk_ll_ops->clk_rmw(latch, latch, reg); + ti_clk_ll_ops->clk_rmw(0, latch, reg); + ti_clk_ll_ops->clk_readl(reg); /* OCP barrier */ +} + /** * omap2_clk_provider_init - init master clock provider * @parent: master node diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index d9b43bfc2532..90b86aadfda7 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -22,6 +22,7 @@ struct clk_omap_divider { u8 shift; u8 width; u8 flags; + s8 latch; const struct clk_div_table *table; }; @@ -33,6 +34,7 @@ struct clk_omap_mux { u32 *table; u32 mask; u8 shift; + s8 latch; u8 flags; }; @@ -194,6 +196,8 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con); void ti_clk_add_aliases(void); +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift); + struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 77f93f6d2806..aaa277dd6d99 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -263,6 +263,8 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, val |= value << divider->shift; ti_clk_ll_ops->clk_writel(val, ÷r->reg); + ti_clk_latch(÷r->reg, divider->latch); + return 0; } @@ -276,7 +278,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct clk_omap_reg *reg, - u8 shift, u8 width, u8 clk_divider_flags, + u8 shift, u8 width, s8 latch, + u8 clk_divider_flags, const struct clk_div_table *table) { struct clk_omap_divider *div; @@ -305,6 +308,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, memcpy(&div->reg, reg, sizeof(*reg)); div->shift = shift; div->width = width; + div->latch = latch; div->flags = clk_divider_flags; div->hw.init = &init; div->table = table; @@ -420,6 +424,7 @@ struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup) div->table = _get_div_table_from_setup(setup, &div->width); div->shift = setup->bit_shift; + div->latch = -EINVAL; return &div->hw; } @@ -452,7 +457,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup) clk = _register_divider(NULL, setup->name, div->parent, flags, ®, div->bit_shift, - width, div_flags, table); + width, -EINVAL, div_flags, table); if (IS_ERR(clk)) kfree(table); @@ -556,7 +561,7 @@ static int _get_divider_width(struct device_node *node, static int __init ti_clk_divider_populate(struct device_node *node, struct clk_omap_reg *reg, const struct clk_div_table **table, - u32 *flags, u8 *div_flags, u8 *width, u8 *shift) + u32 *flags, u8 *div_flags, u8 *width, u8 *shift, s8 *latch) { u32 val; int ret; @@ -570,6 +575,13 @@ static int __init ti_clk_divider_populate(struct device_node *node, else *shift = 0; + if (latch) { + if (!of_property_read_u32(node, "ti,latch-bit", &val)) + *latch = val; + else + *latch = -EINVAL; + } + *flags = 0; *div_flags = 0; @@ -606,17 +618,18 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) u8 clk_divider_flags = 0; u8 width = 0; u8 shift = 0; + s8 latch = -EINVAL; const struct clk_div_table *table = NULL; u32 flags = 0; parent_name = of_clk_get_parent_name(node, 0); if (ti_clk_divider_populate(node, ®, &table, &flags, - &clk_divider_flags, &width, &shift)) + &clk_divider_flags, &width, &shift, &latch)) goto cleanup; clk = _register_divider(NULL, node->name, parent_name, flags, ®, - shift, width, clk_divider_flags, table); + shift, width, latch, clk_divider_flags, table); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -639,7 +652,8 @@ static void __init of_ti_composite_divider_clk_setup(struct device_node *node) return; if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, - &div->flags, &div->width, &div->shift) < 0) + &div->flags, &div->width, &div->shift, + NULL) < 0) goto cleanup; if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index d4705803f3d3..69a4308a5a98 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -86,6 +86,7 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) } val |= index << mux->shift; ti_clk_ll_ops->clk_writel(val, &mux->reg); + ti_clk_latch(&mux->reg, mux->latch); return 0; } @@ -100,7 +101,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, struct clk_omap_reg *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table) + s8 latch, u8 clk_mux_flags, u32 *table) { struct clk_omap_mux *mux; struct clk *clk; @@ -121,6 +122,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, memcpy(&mux->reg, reg, sizeof(*reg)); mux->shift = shift; mux->mask = mask; + mux->latch = latch; mux->flags = clk_mux_flags; mux->table = table; mux->hw.init = &init; @@ -160,7 +162,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup) flags |= CLK_SET_RATE_PARENT; return _register_mux(NULL, setup->name, mux->parents, mux->num_parents, - flags, ®, mux->bit_shift, mask, + flags, ®, mux->bit_shift, mask, -EINVAL, mux_flags, NULL); } @@ -179,6 +181,7 @@ static void of_mux_clk_setup(struct device_node *node) u8 clk_mux_flags = 0; u32 mask = 0; u32 shift = 0; + s32 latch = -EINVAL; u32 flags = CLK_SET_RATE_NO_REPARENT; num_parents = of_clk_get_parent_count(node); @@ -197,6 +200,8 @@ static void of_mux_clk_setup(struct device_node *node) of_property_read_u32(node, "ti,bit-shift", &shift); + of_property_read_u32(node, "ti,latch-bit", &latch); + if (of_property_read_bool(node, "ti,index-starts-at-one")) clk_mux_flags |= CLK_MUX_INDEX_ONE; @@ -211,7 +216,8 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 << fls(mask)) - 1; clk = _register_mux(NULL, node->name, parent_names, num_parents, - flags, ®, shift, mask, clk_mux_flags, NULL); + flags, ®, shift, mask, latch, clk_mux_flags, + NULL); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -234,6 +240,7 @@ struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup) return ERR_PTR(-ENOMEM); mux->shift = setup->bit_shift; + mux->latch = -EINVAL; mux->reg.index = setup->module; mux->reg.offset = setup->reg; diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index e7a868b83fe5..dd08ecb498be 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -44,10 +44,10 @@ static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, { struct vexpress_osc *osc = to_vexpress_osc(hw); - if (WARN_ON(osc->rate_min && rate < osc->rate_min)) + if (osc->rate_min && rate < osc->rate_min) rate = osc->rate_min; - if (WARN_ON(osc->rate_max && rate > osc->rate_max)) + if (osc->rate_max && rate > osc->rate_max) rate = osc->rate_max; return rate; @@ -104,6 +104,7 @@ static int vexpress_osc_probe(struct platform_device *pdev) return PTR_ERR(clk); of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk); + clk_hw_set_rate_range(&osc->hw, osc->rate_min, osc->rate_max); dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name); diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index b6a436594a19..caf45cf7aa8e 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -147,6 +147,12 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } +static const char *soc_force_no_clk[] = { + "samsung,exynos5250-clock", + "samsung,exynos5420-clock", + "samsung,exynos5800-clock", +}; + static __init int exynos4_pm_init_power_domain(void) { struct device_node *np; @@ -183,6 +189,11 @@ static __init int exynos4_pm_init_power_domain(void) pd->pd.power_on = exynos_pd_power_on; pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + for (i = 0; i < ARRAY_SIZE(soc_force_no_clk); i++) + if (of_find_compatible_node(NULL, NULL, + soc_force_no_clk[i])) + goto no_clk; + for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { char clk_name[8]; diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h index 941ac70e7f30..555937a25504 100644 --- a/include/dt-bindings/clock/axg-clkc.h +++ b/include/dt-bindings/clock/axg-clkc.h @@ -67,5 +67,6 @@ #define CLKID_AO_I2C 58 #define CLKID_SD_EMMC_B_CLK0 59 #define CLKID_SD_EMMC_C_CLK0 60 +#define CLKID_HIFI_PLL 69 #endif /* __AXG_CLKC_H */ diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h index 6422314e46eb..6b77e721f6b1 100644 --- a/include/dt-bindings/clock/tegra210-car.h +++ b/include/dt-bindings/clock/tegra210-car.h @@ -95,7 +95,7 @@ #define TEGRA210_CLK_CSITE 73 /* 74 */ /* 75 */ -/* 76 */ +#define TEGRA210_CLK_LA 76 /* 77 */ #define TEGRA210_CLK_SOC_THERM 78 #define TEGRA210_CLK_DTV 79 diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index f711be6e8c44..210a890008f9 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -399,6 +399,7 @@ struct clk_divider { spinlock_t *lock; }; +#define clk_div_mask(width) ((1 << (width)) - 1) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define CLK_DIVIDER_ONE_BASED BIT(0) @@ -419,6 +420,10 @@ long divider_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); +long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, + unsigned long rate, unsigned long *prate, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val); int divider_get_val(unsigned long rate, unsigned long parent_rate, const struct clk_div_table *table, u8 width, unsigned long flags); @@ -449,8 +454,9 @@ void clk_hw_unregister_divider(struct clk_hw *hw); * * @hw: handle between common and hardware-specific interfaces * @reg: register controlling multiplexer + * @table: array of register values corresponding to the parent index * @shift: shift to multiplexer bit field - * @width: width of mutliplexer bit field + * @mask: mask of mutliplexer bit field * @flags: hardware-specific flags * @lock: register lock * @@ -510,6 +516,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, void __iomem *reg, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, spinlock_t *lock); +int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val); +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index); + void clk_unregister_mux(struct clk *clk); void clk_hw_unregister_mux(struct clk_hw *hw); @@ -774,6 +784,17 @@ static inline long divider_round_rate(struct clk_hw *hw, unsigned long rate, rate, prate, table, width, flags); } +static inline long divider_ro_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate, + const struct clk_div_table *table, + u8 width, unsigned long flags, + unsigned int val) +{ + return divider_ro_round_rate_parent(hw, clk_hw_get_parent(hw), + rate, prate, table, width, flags, + val); +} + /* * FIXME clock api without lock protection */ diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index d23c9cf26993..afb9edfa5d58 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -128,5 +128,6 @@ extern void tegra210_sata_pll_hw_sequence_start(void); extern void tegra210_set_sata_pll_seq_sw(bool state); extern void tegra210_put_utmipll_in_iddq(void); extern void tegra210_put_utmipll_out_iddq(void); +extern int tegra210_clk_handle_mbist_war(unsigned int id); #endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index d18da839b810..9e8611470187 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -211,6 +211,7 @@ enum { * struct ti_clk_ll_ops - low-level ops for clocks * @clk_readl: pointer to register read function * @clk_writel: pointer to register write function + * @clk_rmw: pointer to register read-modify-write function * @clkdm_clk_enable: pointer to clockdomain enable function * @clkdm_clk_disable: pointer to clockdomain disable function * @clkdm_lookup: pointer to clockdomain lookup function @@ -226,6 +227,7 @@ enum { struct ti_clk_ll_ops { u32 (*clk_readl)(const struct clk_omap_reg *reg); void (*clk_writel)(u32 val, const struct clk_omap_reg *reg); + void (*clk_rmw)(u32 val, u32 mask, const struct clk_omap_reg *reg); int (*clkdm_clk_enable)(struct clockdomain *clkdm, struct clk *clk); int (*clkdm_clk_disable)(struct clockdomain *clkdm, struct clk *clk); |