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