From 61598093bbdd283a7edc367d900f223070ead8d2 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:03 +0000 Subject: [PATCH] add ax88772C AX88772C_eeprom_tools --- kernel/drivers/clk/rockchip/clk.c | 359 ++++++++++++++++++++++++++++++++--------------------------- 1 files changed, 195 insertions(+), 164 deletions(-) diff --git a/kernel/drivers/clk/rockchip/clk.c b/kernel/drivers/clk/rockchip/clk.c index 06769a0..1c91007 100644 --- a/kernel/drivers/clk/rockchip/clk.c +++ b/kernel/drivers/clk/rockchip/clk.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 MundoReader S.L. * Author: Heiko Stuebner <heiko@sntech.de> @@ -11,26 +12,21 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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. */ #include <linux/slab.h> #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/io.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/reboot.h> #include <linux/rational.h> #include "clk.h" + +#ifdef MODULE +static HLIST_HEAD(clk_ctx_list); +#endif /** * Register a clock branch. @@ -52,7 +48,7 @@ u8 gate_shift, u8 gate_flags, unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk_hw *hw; struct clk_mux *mux = NULL; struct clk_gate *gate = NULL; struct clk_divider *div = NULL; @@ -110,20 +106,18 @@ : &clk_divider_ops; } - clk = clk_register_composite(NULL, name, parent_names, num_parents, - mux ? &mux->hw : NULL, mux_ops, - div ? &div->hw : NULL, div_ops, - gate ? &gate->hw : NULL, gate_ops, - flags); - - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto err_composite; + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags); + if (IS_ERR(hw)) { + kfree(div); + kfree(gate); + return ERR_CAST(hw); } - return clk; -err_composite: - kfree(div); + return hw->clk; err_div: kfree(gate); err_gate: @@ -194,22 +188,23 @@ unsigned long p_rate, p_parent_rate; struct clk_hw *p_parent; unsigned long scale; - u32 div; + + if (rate == 0) { + pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n", + clk_hw_get_name(hw), *parent_rate, rate); + *m = 0; + *n = 1; + return; + } p_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); - if (((rate * 20 > p_rate) && (p_rate % rate != 0)) || - (fd->max_prate && fd->max_prate < p_rate)) { + if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { p_parent = clk_hw_get_parent(clk_hw_get_parent(hw)); if (!p_parent) { *parent_rate = p_rate; } else { p_parent_rate = clk_hw_get_rate(p_parent); *parent_rate = p_parent_rate; - if (fd->max_prate && p_parent_rate > fd->max_prate) { - div = DIV_ROUND_UP(p_parent_rate, - fd->max_prate); - *parent_rate = p_parent_rate / div; - } } if (*parent_rate < rate * 20) { @@ -238,6 +233,13 @@ * for m and n. In the result it will be the nearest rate left shifted * by (scale - fd->nwidth) bits. */ + if (*parent_rate == 0) { + pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n", + clk_hw_get_name(hw), *parent_rate, rate); + *m = 0; + *n = 1; + return; + } scale = fls_long(*parent_rate / rate - 1); if (scale > fd->nwidth) rate <<= scale - fd->nwidth; @@ -253,10 +255,10 @@ void __iomem *base, int muxdiv_offset, u8 div_flags, int gate_offset, u8 gate_shift, u8 gate_flags, unsigned long flags, struct rockchip_clk_branch *child, - unsigned long max_prate, spinlock_t *lock) + spinlock_t *lock) { + struct clk_hw *hw; struct rockchip_clk_frac *frac; - struct clk *clk; struct clk_gate *gate = NULL; struct clk_fractional_divider *div = NULL; const struct clk_ops *div_ops = NULL, *gate_ops = NULL; @@ -294,22 +296,21 @@ div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift; div->lock = lock; div->approximation = rockchip_fractional_approximation; - div->max_prate = max_prate; div_ops = &clk_fractional_divider_ops; - clk = clk_register_composite(NULL, name, parent_names, num_parents, - NULL, NULL, - &div->hw, div_ops, - gate ? &gate->hw : NULL, gate_ops, - flags | CLK_SET_RATE_UNGATE); - if (IS_ERR(clk)) { + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + NULL, NULL, + &div->hw, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags | CLK_SET_RATE_UNGATE); + if (IS_ERR(hw)) { kfree(frac); - return clk; + return ERR_CAST(hw); } if (child) { struct clk_mux *frac_mux = &frac->mux; - struct clk_init_data init = {}; + struct clk_init_data init; struct clk *mux_clk; int ret; @@ -336,7 +337,7 @@ mux_clk = clk_register(NULL, &frac_mux->hw); if (IS_ERR(mux_clk)) { kfree(frac); - return clk; + return mux_clk; } rockchip_clk_add_lookup(ctx, mux_clk, child->id); @@ -345,7 +346,7 @@ if (frac->mux_frac_idx >= 0) { pr_debug("%s: found fractional parent in mux at pos %d\n", __func__, frac->mux_frac_idx); - ret = clk_notifier_register(clk, &frac->clk_nb); + ret = clk_notifier_register(hw->clk, &frac->clk_nb); if (ret) pr_err("%s: failed to register clock notifier for %s\n", __func__, name); @@ -355,7 +356,7 @@ } } - return clk; + return hw->clk; } static struct clk *rockchip_clk_register_factor_branch(const char *name, @@ -364,7 +365,7 @@ int gate_offset, u8 gate_shift, u8 gate_flags, unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk_hw *hw; struct clk_gate *gate = NULL; struct clk_fixed_factor *fix = NULL; @@ -393,75 +394,22 @@ fix->mult = mult; fix->div = div; - clk = clk_register_composite(NULL, name, parent_names, num_parents, - NULL, NULL, - &fix->hw, &clk_fixed_factor_ops, - &gate->hw, &clk_gate_ops, flags); - if (IS_ERR(clk)) { + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + NULL, NULL, + &fix->hw, &clk_fixed_factor_ops, + &gate->hw, &clk_gate_ops, flags); + if (IS_ERR(hw)) { kfree(fix); kfree(gate); + return ERR_CAST(hw); } - return clk; + return hw->clk; } -static struct clk *rockchip_clk_register_composite_brother_branch( - struct rockchip_clk_provider *ctx, const char *name, - const char *const *parent_names, u8 num_parents, - void __iomem *base, int muxdiv_offset, u8 mux_shift, - u8 mux_width, u8 mux_flags, u32 *mux_table, - int div_offset, u8 div_shift, u8 div_width, u8 div_flags, - struct clk_div_table *div_table, int gate_offset, - u8 gate_shift, u8 gate_flags, unsigned long flags, - struct rockchip_clk_branch *brother, spinlock_t *lock) -{ - struct clk *clk, *brother_clk; - struct clk_composite *composite, *brother_composite; - struct clk_hw *hw, *brother_hw; - - if (brother && brother->branch_type != branch_half_divider) { - pr_err("%s: composite brother for %s can only be a halfdiv\n", - __func__, name); - return ERR_PTR(-EINVAL); - } - - clk = rockchip_clk_register_branch(name, parent_names, num_parents, - base, muxdiv_offset, mux_shift, - mux_width, mux_flags, mux_table, - div_offset, div_shift, div_width, - div_flags, div_table, - gate_offset, gate_shift, gate_flags, - flags, lock); - if (IS_ERR(clk)) - return clk; - - brother_clk = rockchip_clk_register_halfdiv(brother->name, - brother->parent_names, brother->num_parents, - base, brother->muxdiv_offset, - brother->mux_shift, brother->mux_width, - brother->mux_flags, brother->div_offset, - brother->div_shift, brother->div_width, - brother->div_flags, brother->gate_offset, - brother->gate_shift, brother->gate_flags, - flags, lock); - if (IS_ERR(brother_clk)) - return brother_clk; - rockchip_clk_add_lookup(ctx, brother_clk, brother->id); - - hw = __clk_get_hw(clk); - brother_hw = __clk_get_hw(brother_clk); - if (hw && brother_hw) { - composite = to_clk_composite(hw); - brother_composite = to_clk_composite(brother_hw); - composite->brother_hw = brother_hw; - brother_composite->brother_hw = hw; - } - - return clk; -} - -struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, - void __iomem *base, unsigned long nr_clks) +struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, + void __iomem *base, + unsigned long nr_clks) { struct rockchip_clk_provider *ctx; struct clk **clk_table; @@ -489,20 +437,26 @@ ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node, "rockchip,pmugrf"); +#ifdef MODULE + hlist_add_head(&ctx->list_node, &clk_ctx_list); +#endif + return ctx; err_free: kfree(ctx); return ERR_PTR(-ENOMEM); } +EXPORT_SYMBOL_GPL(rockchip_clk_init); -void __init rockchip_clk_of_add_provider(struct device_node *np, - struct rockchip_clk_provider *ctx) +void rockchip_clk_of_add_provider(struct device_node *np, + struct rockchip_clk_provider *ctx) { if (of_clk_add_provider(np, of_clk_src_onecell_get, &ctx->clk_data)) pr_err("%s: could not register clk provider\n", __func__); } +EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider); void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, struct clk *clk, unsigned int id) @@ -510,8 +464,9 @@ if (ctx->clk_data.clks && id) ctx->clk_data.clks[id] = clk; } +EXPORT_SYMBOL_GPL(rockchip_clk_add_lookup); -void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, +void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, struct rockchip_pll_clock *list, unsigned int nr_pll, int grf_lock_offset) { @@ -534,11 +489,11 @@ rockchip_clk_add_lookup(ctx, clk, list->id); } } +EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); -void __init rockchip_clk_register_branches( - struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk) +void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk) { struct clk *clk = NULL; unsigned int idx; @@ -604,7 +559,7 @@ list->div_flags, list->gate_offset, list->gate_shift, list->gate_flags, flags, list->child, - list->max_prate, &ctx->lock); + &ctx->lock); break; case branch_half_divider: clk = rockchip_clk_register_halfdiv(list->name, @@ -618,8 +573,15 @@ flags, &ctx->lock); break; case branch_gate: - if (!(list->gate_flags & CLK_GATE_NO_SET_RATE)) - flags |= CLK_SET_RATE_PARENT; + flags |= CLK_SET_RATE_PARENT; + + clk = clk_register_gate(NULL, list->name, + list->parent_names[0], flags, + ctx->reg_base + list->gate_offset, + list->gate_shift, list->gate_flags, &ctx->lock); + break; + case branch_gate_no_set_rate: + flags &= ~CLK_SET_RATE_PARENT; clk = clk_register_gate(NULL, list->name, list->parent_names[0], flags, @@ -637,19 +599,6 @@ list->div_flags, list->div_table, list->gate_offset, list->gate_shift, list->gate_flags, flags, &ctx->lock); - break; - case branch_composite_brother: - clk = rockchip_clk_register_composite_brother_branch( - ctx, list->name, list->parent_names, - list->num_parents, ctx->reg_base, - list->muxdiv_offset, list->mux_shift, - list->mux_width, list->mux_flags, - list->mux_table, list->div_offset, - list->div_shift, list->div_width, - list->div_flags, list->div_table, - list->gate_offset, list->gate_shift, - list->gate_flags, flags, list->child, - &ctx->lock); break; case branch_mmc: clk = rockchip_clk_register_mmc( @@ -685,18 +634,6 @@ list->div_width, list->div_flags, ctx->reg_base); break; - case branch_dclk_divider: -#ifdef CONFIG_ROCKCHIP_DCLK_DIV - clk = rockchip_clk_register_dclk_branch(list->name, - list->parent_names, list->num_parents, - ctx->reg_base, list->muxdiv_offset, list->mux_shift, - list->mux_width, list->mux_flags, - list->div_offset, list->div_shift, list->div_width, - list->div_flags, list->div_table, - list->gate_offset, list->gate_shift, - list->gate_flags, flags, list->max_prate, &ctx->lock); -#endif - break; } /* none of the cases above matched */ @@ -715,18 +652,21 @@ rockchip_clk_add_lookup(ctx, clk, list->id); } } +EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); -void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, - unsigned int lookup_id, - const char *name, const char *const *parent_names, - u8 num_parents, - const struct rockchip_cpuclk_reg_data *reg_data, - const struct rockchip_cpuclk_rate_table *rates, - int nrates) +void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, + unsigned int lookup_id, + const char *name, + u8 num_parents, + struct clk *parent, struct clk *alt_parent, + const struct rockchip_cpuclk_reg_data *reg_data, + const struct rockchip_cpuclk_rate_table *rates, + int nrates) { struct clk *clk; - clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, + clk = rockchip_clk_register_cpuclk(name, num_parents, + parent, alt_parent, reg_data, rates, nrates, ctx->reg_base, &ctx->lock); if (IS_ERR(clk)) { @@ -737,20 +677,31 @@ rockchip_clk_add_lookup(ctx, clk, lookup_id); } +EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); -void __init rockchip_clk_protect_critical(const char *const clocks[], - int nclocks) +void rockchip_clk_register_armclk_v2(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + const struct rockchip_cpuclk_rate_table *rates, + int nrates) { - int i; + struct clk *clk; - /* Protect the clocks that needs to stay on */ - for (i = 0; i < nclocks; i++) { - struct clk *clk = __clk_lookup(clocks[i]); - - if (clk) - clk_prepare_enable(clk); + clk = rockchip_clk_register_cpuclk_v2(list->name, list->parent_names, + list->num_parents, ctx->reg_base, + list->muxdiv_offset, list->mux_shift, + list->mux_width, list->mux_flags, + list->div_offset, list->div_shift, + list->div_width, list->div_flags, + list->flags, &ctx->lock, rates, nrates); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s: %ld\n", + __func__, list->name, PTR_ERR(clk)); + return; } + + rockchip_clk_add_lookup(ctx, clk, list->id); } +EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk_v2); void (*rk_dump_cru)(void); EXPORT_SYMBOL(rk_dump_cru); @@ -785,10 +736,10 @@ .priority = 128, }; -void __init +void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, - unsigned int reg, - void (*cb)(void)) + unsigned int reg, + void (*cb)(void)) { int ret; @@ -802,3 +753,83 @@ atomic_notifier_chain_register(&panic_notifier_list, &rk_clk_panic_block); } +EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier); + +#ifdef MODULE +static struct clk **protect_clocks; +static unsigned int protect_nclocks; + +int rockchip_clk_protect(struct rockchip_clk_provider *ctx, + unsigned int *clocks, unsigned int nclocks) +{ + struct clk *clk = NULL; + int i = 0; + + if (protect_clocks || !ctx || !clocks || !ctx->clk_data.clks) + return 0; + + protect_clocks = kcalloc(nclocks, sizeof(void *), GFP_KERNEL); + if (!protect_clocks) + return -ENOMEM; + + for (i = 0; i < nclocks; i++) { + if (clocks[i] >= ctx->clk_data.clk_num) { + pr_err("%s: invalid clock id %u\n", __func__, clocks[i]); + continue; + } + clk = ctx->clk_data.clks[clocks[i]]; + if (clk) { + clk_prepare_enable(clk); + protect_clocks[i] = clk; + } + } + protect_nclocks = nclocks; + + return 0; +} +EXPORT_SYMBOL_GPL(rockchip_clk_protect); + +void rockchip_clk_unprotect(void) +{ + int i = 0; + + if (!protect_clocks || !protect_nclocks) + return; + + for (i = 0; i < protect_nclocks; i++) { + if (protect_clocks[i]) + clk_disable_unprepare(protect_clocks[i]); + } + protect_nclocks = 0; + kfree(protect_clocks); + protect_clocks = NULL; + +} +EXPORT_SYMBOL_GPL(rockchip_clk_unprotect); + +void rockchip_clk_disable_unused(void) +{ + struct rockchip_clk_provider *ctx; + struct clk *clk; + struct clk_hw *hw; + int i = 0, flag = 0; + + hlist_for_each_entry(ctx, &clk_ctx_list, list_node) { + for (i = 0; i < ctx->clk_data.clk_num; i++) { + clk = ctx->clk_data.clks[i]; + if (clk && !IS_ERR(clk)) { + hw = __clk_get_hw(clk); + if (hw) + flag = clk_hw_get_flags(hw); + if (flag & CLK_IGNORE_UNUSED) + continue; + if (flag & CLK_IS_CRITICAL) + continue; + clk_prepare_enable(clk); + clk_disable_unprepare(clk); + } + } + } +} +EXPORT_SYMBOL_GPL(rockchip_clk_disable_unused); +#endif /* MODULE */ -- Gitblit v1.6.2