qualcommax: use upstreamed multiple conf clock patches
Multiple conf support was upstreamed into kernel 6.10, so lets use the upstreamed patches and mark them as so. Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
d6ba1c99fd
commit
cc50cac8a0
5 changed files with 606 additions and 332 deletions
|
@ -0,0 +1,83 @@
|
||||||
|
From d06b1043644a1831ab141bbee2669002bba15b0f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 20 Dec 2023 23:17:22 +0100
|
||||||
|
Subject: [PATCH] clk: qcom: clk-rcg: introduce support for multiple conf for
|
||||||
|
same freq
|
||||||
|
|
||||||
|
Some RCG frequency can be reached by multiple configuration.
|
||||||
|
|
||||||
|
We currently declare multiple configuration for the same frequency but
|
||||||
|
that is not supported and always the first configuration will be taken.
|
||||||
|
|
||||||
|
These multiple configuration are needed as based on the current parent
|
||||||
|
configuration, it may be needed to use a different configuration to
|
||||||
|
reach the same frequency.
|
||||||
|
|
||||||
|
To handle this introduce 3 new macro, C, FM and FMS:
|
||||||
|
|
||||||
|
- C is used to declare a freq_conf where src, pre_div, m and n are
|
||||||
|
provided.
|
||||||
|
|
||||||
|
- FM is used to declare a freq_multi_tbl with the frequency and an
|
||||||
|
array of confs to insert all the config for the provided frequency.
|
||||||
|
|
||||||
|
- FMS is used to declare a freq_multi_tbl with the frequency and an
|
||||||
|
array of a single conf with the provided src, pre_div, m and n.
|
||||||
|
|
||||||
|
Struct clk_rcg2 is changed to add a union type to reference a simple
|
||||||
|
freq_tbl or a complex freq_multi_tbl.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Stephen Boyd <sboyd@kernel.org>
|
||||||
|
Link: https://lore.kernel.org/r/20231220221724.3822-2-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
|
||||||
|
---
|
||||||
|
drivers/clk/qcom/clk-rcg.h | 23 ++++++++++++++++++++++-
|
||||||
|
1 file changed, 22 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/clk/qcom/clk-rcg.h
|
||||||
|
+++ b/drivers/clk/qcom/clk-rcg.h
|
||||||
|
@@ -17,6 +17,23 @@ struct freq_tbl {
|
||||||
|
u16 n;
|
||||||
|
};
|
||||||
|
|
||||||
|
+#define C(s, h, m, n) { (s), (2 * (h) - 1), (m), (n) }
|
||||||
|
+#define FM(f, confs) { (f), ARRAY_SIZE(confs), (confs) }
|
||||||
|
+#define FMS(f, s, h, m, n) { (f), 1, (const struct freq_conf []){ C(s, h, m, n) } }
|
||||||
|
+
|
||||||
|
+struct freq_conf {
|
||||||
|
+ u8 src;
|
||||||
|
+ u8 pre_div;
|
||||||
|
+ u16 m;
|
||||||
|
+ u16 n;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct freq_multi_tbl {
|
||||||
|
+ unsigned long freq;
|
||||||
|
+ size_t num_confs;
|
||||||
|
+ const struct freq_conf *confs;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* struct mn - M/N:D counter
|
||||||
|
* @mnctr_en_bit: bit to enable mn counter
|
||||||
|
@@ -138,6 +155,7 @@ extern const struct clk_ops clk_dyn_rcg_
|
||||||
|
* @safe_src_index: safe src index value
|
||||||
|
* @parent_map: map from software's parent index to hardware's src_sel field
|
||||||
|
* @freq_tbl: frequency table
|
||||||
|
+ * @freq_multi_tbl: frequency table for clocks reachable with multiple RCGs conf
|
||||||
|
* @clkr: regmap clock handle
|
||||||
|
* @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG
|
||||||
|
* @parked_cfg: cached value of the CFG register for parked RCGs
|
||||||
|
@@ -149,7 +167,10 @@ struct clk_rcg2 {
|
||||||
|
u8 hid_width;
|
||||||
|
u8 safe_src_index;
|
||||||
|
const struct parent_map *parent_map;
|
||||||
|
- const struct freq_tbl *freq_tbl;
|
||||||
|
+ union {
|
||||||
|
+ const struct freq_tbl *freq_tbl;
|
||||||
|
+ const struct freq_multi_tbl *freq_multi_tbl;
|
||||||
|
+ };
|
||||||
|
struct clk_regmap clkr;
|
||||||
|
u8 cfg_off;
|
||||||
|
u32 parked_cfg;
|
|
@ -0,0 +1,296 @@
|
||||||
|
From 89da22456af0762477d8c1345fdd17961b3ada80 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 20 Dec 2023 23:17:23 +0100
|
||||||
|
Subject: [PATCH] clk: qcom: clk-rcg2: add support for rcg2 freq multi ops
|
||||||
|
|
||||||
|
Some RCG frequency can be reached by multiple configuration.
|
||||||
|
|
||||||
|
Add clk_rcg2_fm_ops ops to support these special RCG configurations.
|
||||||
|
|
||||||
|
These alternative ops will select the frequency using a CEIL policy.
|
||||||
|
|
||||||
|
When the correct frequency is found, the correct config is selected by
|
||||||
|
calculating the final rate (by checking the defined parent and values
|
||||||
|
in the config that is being checked) and deciding based on the one that
|
||||||
|
is less different than the requested one.
|
||||||
|
|
||||||
|
These check are skipped if there is just one config for the requested
|
||||||
|
freq.
|
||||||
|
|
||||||
|
qcom_find_freq_multi is added to search the freq with the new struct
|
||||||
|
freq_multi_tbl.
|
||||||
|
__clk_rcg2_select_conf is used to select the correct conf by simulating
|
||||||
|
the final clock.
|
||||||
|
If a conf can't be found due to parent not reachable, a WARN is printed
|
||||||
|
and -EINVAL is returned.
|
||||||
|
|
||||||
|
Tested-by: Wei Lei <quic_leiwei@quicinc.com>
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Stephen Boyd <sboyd@kernel.org>
|
||||||
|
Link: https://lore.kernel.org/r/20231220221724.3822-3-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
|
||||||
|
---
|
||||||
|
drivers/clk/qcom/clk-rcg.h | 1 +
|
||||||
|
drivers/clk/qcom/clk-rcg2.c | 166 ++++++++++++++++++++++++++++++++++++
|
||||||
|
drivers/clk/qcom/common.c | 18 ++++
|
||||||
|
drivers/clk/qcom/common.h | 2 +
|
||||||
|
4 files changed, 187 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/clk/qcom/clk-rcg.h
|
||||||
|
+++ b/drivers/clk/qcom/clk-rcg.h
|
||||||
|
@@ -190,6 +190,7 @@ struct clk_rcg2_gfx3d {
|
||||||
|
|
||||||
|
extern const struct clk_ops clk_rcg2_ops;
|
||||||
|
extern const struct clk_ops clk_rcg2_floor_ops;
|
||||||
|
+extern const struct clk_ops clk_rcg2_fm_ops;
|
||||||
|
extern const struct clk_ops clk_rcg2_mux_closest_ops;
|
||||||
|
extern const struct clk_ops clk_edp_pixel_ops;
|
||||||
|
extern const struct clk_ops clk_byte_ops;
|
||||||
|
--- a/drivers/clk/qcom/clk-rcg2.c
|
||||||
|
+++ b/drivers/clk/qcom/clk-rcg2.c
|
||||||
|
@@ -260,6 +260,115 @@ static int _freq_tbl_determine_rate(stru
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static const struct freq_conf *
|
||||||
|
+__clk_rcg2_select_conf(struct clk_hw *hw, const struct freq_multi_tbl *f,
|
||||||
|
+ unsigned long req_rate)
|
||||||
|
+{
|
||||||
|
+ unsigned long rate_diff, best_rate_diff = ULONG_MAX;
|
||||||
|
+ const struct freq_conf *conf, *best_conf = NULL;
|
||||||
|
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||||
|
+ const char *name = clk_hw_get_name(hw);
|
||||||
|
+ unsigned long parent_rate, rate;
|
||||||
|
+ struct clk_hw *p;
|
||||||
|
+ int index, i;
|
||||||
|
+
|
||||||
|
+ /* Exit early if only one config is defined */
|
||||||
|
+ if (f->num_confs == 1) {
|
||||||
|
+ best_conf = f->confs;
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Search in each provided config the one that is near the wanted rate */
|
||||||
|
+ for (i = 0, conf = f->confs; i < f->num_confs; i++, conf++) {
|
||||||
|
+ index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
|
||||||
|
+ if (index < 0)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ p = clk_hw_get_parent_by_index(hw, index);
|
||||||
|
+ if (!p)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ parent_rate = clk_hw_get_rate(p);
|
||||||
|
+ rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
|
||||||
|
+
|
||||||
|
+ if (rate == req_rate) {
|
||||||
|
+ best_conf = conf;
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rate_diff = abs_diff(req_rate, rate);
|
||||||
|
+ if (rate_diff < best_rate_diff) {
|
||||||
|
+ best_rate_diff = rate_diff;
|
||||||
|
+ best_conf = conf;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Very unlikely. Warn if we couldn't find a correct config
|
||||||
|
+ * due to parent not found in every config.
|
||||||
|
+ */
|
||||||
|
+ if (unlikely(!best_conf)) {
|
||||||
|
+ WARN(1, "%s: can't find a configuration for rate %lu\n",
|
||||||
|
+ name, req_rate);
|
||||||
|
+ return ERR_PTR(-EINVAL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+exit:
|
||||||
|
+ return best_conf;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int _freq_tbl_fm_determine_rate(struct clk_hw *hw, const struct freq_multi_tbl *f,
|
||||||
|
+ struct clk_rate_request *req)
|
||||||
|
+{
|
||||||
|
+ unsigned long clk_flags, rate = req->rate;
|
||||||
|
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||||
|
+ const struct freq_conf *conf;
|
||||||
|
+ struct clk_hw *p;
|
||||||
|
+ int index;
|
||||||
|
+
|
||||||
|
+ f = qcom_find_freq_multi(f, rate);
|
||||||
|
+ if (!f || !f->confs)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ conf = __clk_rcg2_select_conf(hw, f, rate);
|
||||||
|
+ if (IS_ERR(conf))
|
||||||
|
+ return PTR_ERR(conf);
|
||||||
|
+ index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
|
||||||
|
+ if (index < 0)
|
||||||
|
+ return index;
|
||||||
|
+
|
||||||
|
+ clk_flags = clk_hw_get_flags(hw);
|
||||||
|
+ p = clk_hw_get_parent_by_index(hw, index);
|
||||||
|
+ if (!p)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (clk_flags & CLK_SET_RATE_PARENT) {
|
||||||
|
+ rate = f->freq;
|
||||||
|
+ if (conf->pre_div) {
|
||||||
|
+ if (!rate)
|
||||||
|
+ rate = req->rate;
|
||||||
|
+ rate /= 2;
|
||||||
|
+ rate *= conf->pre_div + 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (conf->n) {
|
||||||
|
+ u64 tmp = rate;
|
||||||
|
+
|
||||||
|
+ tmp = tmp * conf->n;
|
||||||
|
+ do_div(tmp, conf->m);
|
||||||
|
+ rate = tmp;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ rate = clk_hw_get_rate(p);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ req->best_parent_hw = p;
|
||||||
|
+ req->best_parent_rate = rate;
|
||||||
|
+ req->rate = f->freq;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int clk_rcg2_determine_rate(struct clk_hw *hw,
|
||||||
|
struct clk_rate_request *req)
|
||||||
|
{
|
||||||
|
@@ -276,6 +385,14 @@ static int clk_rcg2_determine_floor_rate
|
||||||
|
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int clk_rcg2_fm_determine_rate(struct clk_hw *hw,
|
||||||
|
+ struct clk_rate_request *req)
|
||||||
|
+{
|
||||||
|
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||||
|
+
|
||||||
|
+ return _freq_tbl_fm_determine_rate(hw, rcg->freq_multi_tbl, req);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f,
|
||||||
|
u32 *_cfg)
|
||||||
|
{
|
||||||
|
@@ -371,6 +488,30 @@ static int __clk_rcg2_set_rate(struct cl
|
||||||
|
return clk_rcg2_configure(rcg, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int __clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate)
|
||||||
|
+{
|
||||||
|
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||||
|
+ const struct freq_multi_tbl *f;
|
||||||
|
+ const struct freq_conf *conf;
|
||||||
|
+ struct freq_tbl f_tbl = {};
|
||||||
|
+
|
||||||
|
+ f = qcom_find_freq_multi(rcg->freq_multi_tbl, rate);
|
||||||
|
+ if (!f || !f->confs)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ conf = __clk_rcg2_select_conf(hw, f, rate);
|
||||||
|
+ if (IS_ERR(conf))
|
||||||
|
+ return PTR_ERR(conf);
|
||||||
|
+
|
||||||
|
+ f_tbl.freq = f->freq;
|
||||||
|
+ f_tbl.src = conf->src;
|
||||||
|
+ f_tbl.pre_div = conf->pre_div;
|
||||||
|
+ f_tbl.m = conf->m;
|
||||||
|
+ f_tbl.n = conf->n;
|
||||||
|
+
|
||||||
|
+ return clk_rcg2_configure(rcg, &f_tbl);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||||
|
unsigned long parent_rate)
|
||||||
|
{
|
||||||
|
@@ -383,6 +524,12 @@ static int clk_rcg2_set_floor_rate(struc
|
||||||
|
return __clk_rcg2_set_rate(hw, rate, FLOOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||||
|
+ unsigned long parent_rate)
|
||||||
|
+{
|
||||||
|
+ return __clk_rcg2_fm_set_rate(hw, rate);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw,
|
||||||
|
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||||
|
{
|
||||||
|
@@ -395,6 +542,12 @@ static int clk_rcg2_set_floor_rate_and_p
|
||||||
|
return __clk_rcg2_set_rate(hw, rate, FLOOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int clk_rcg2_fm_set_rate_and_parent(struct clk_hw *hw,
|
||||||
|
+ unsigned long rate, unsigned long parent_rate, u8 index)
|
||||||
|
+{
|
||||||
|
+ return __clk_rcg2_fm_set_rate(hw, rate);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
||||||
|
{
|
||||||
|
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||||
|
@@ -505,6 +658,19 @@ const struct clk_ops clk_rcg2_floor_ops
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
|
||||||
|
|
||||||
|
+const struct clk_ops clk_rcg2_fm_ops = {
|
||||||
|
+ .is_enabled = clk_rcg2_is_enabled,
|
||||||
|
+ .get_parent = clk_rcg2_get_parent,
|
||||||
|
+ .set_parent = clk_rcg2_set_parent,
|
||||||
|
+ .recalc_rate = clk_rcg2_recalc_rate,
|
||||||
|
+ .determine_rate = clk_rcg2_fm_determine_rate,
|
||||||
|
+ .set_rate = clk_rcg2_fm_set_rate,
|
||||||
|
+ .set_rate_and_parent = clk_rcg2_fm_set_rate_and_parent,
|
||||||
|
+ .get_duty_cycle = clk_rcg2_get_duty_cycle,
|
||||||
|
+ .set_duty_cycle = clk_rcg2_set_duty_cycle,
|
||||||
|
+};
|
||||||
|
+EXPORT_SYMBOL_GPL(clk_rcg2_fm_ops);
|
||||||
|
+
|
||||||
|
const struct clk_ops clk_rcg2_mux_closest_ops = {
|
||||||
|
.determine_rate = __clk_mux_determine_rate_closest,
|
||||||
|
.get_parent = clk_rcg2_get_parent,
|
||||||
|
--- a/drivers/clk/qcom/common.c
|
||||||
|
+++ b/drivers/clk/qcom/common.c
|
||||||
|
@@ -41,6 +41,24 @@ struct freq_tbl *qcom_find_freq(const st
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_find_freq);
|
||||||
|
|
||||||
|
+const struct freq_multi_tbl *qcom_find_freq_multi(const struct freq_multi_tbl *f,
|
||||||
|
+ unsigned long rate)
|
||||||
|
+{
|
||||||
|
+ if (!f)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ if (!f->freq)
|
||||||
|
+ return f;
|
||||||
|
+
|
||||||
|
+ for (; f->freq; f++)
|
||||||
|
+ if (rate <= f->freq)
|
||||||
|
+ return f;
|
||||||
|
+
|
||||||
|
+ /* Default to our fastest rate */
|
||||||
|
+ return f - 1;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(qcom_find_freq_multi);
|
||||||
|
+
|
||||||
|
const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
|
||||||
|
unsigned long rate)
|
||||||
|
{
|
||||||
|
--- a/drivers/clk/qcom/common.h
|
||||||
|
+++ b/drivers/clk/qcom/common.h
|
||||||
|
@@ -45,6 +45,8 @@ extern const struct freq_tbl *qcom_find_
|
||||||
|
unsigned long rate);
|
||||||
|
extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
|
||||||
|
unsigned long rate);
|
||||||
|
+extern const struct freq_multi_tbl *qcom_find_freq_multi(const struct freq_multi_tbl *f,
|
||||||
|
+ unsigned long rate);
|
||||||
|
extern void
|
||||||
|
qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count);
|
||||||
|
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
|
|
@ -0,0 +1,227 @@
|
||||||
|
From e88f03230dc07aa3293b6aeb078bd27370bb2594 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 20 Dec 2023 23:17:24 +0100
|
||||||
|
Subject: [PATCH] clk: qcom: gcc-ipq8074: rework nss_port5/6 clock to multiple
|
||||||
|
conf
|
||||||
|
|
||||||
|
Rework nss_port5/6 to use the new multiple configuration implementation
|
||||||
|
and correctly fix the clocks for these port under some corner case.
|
||||||
|
|
||||||
|
This is particularly relevant for device that have 2.5G or 10G port
|
||||||
|
connected to port5 or port 6 on ipq8074. As the parent are shared
|
||||||
|
across multiple port it may be required to select the correct
|
||||||
|
configuration to accomplish the desired clock. Without this patch such
|
||||||
|
port doesn't work in some specific ethernet speed as the clock will be
|
||||||
|
set to the wrong frequency as we just select the first configuration for
|
||||||
|
the related frequency instead of selecting the best one.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Stephen Boyd <sboyd@kernel.org>
|
||||||
|
Link: https://lore.kernel.org/r/20231220221724.3822-4-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
|
||||||
|
---
|
||||||
|
drivers/clk/qcom/gcc-ipq8074.c | 120 +++++++++++++++++++++------------
|
||||||
|
1 file changed, 76 insertions(+), 44 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||||
|
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||||
|
@@ -1677,15 +1677,23 @@ static struct clk_regmap_div nss_port4_t
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
|
||||||
|
- F(19200000, P_XO, 1, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY0_RX, 5, 0, 0),
|
||||||
|
- F(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY0_RX, 1, 0, 0),
|
||||||
|
- F(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||||
|
- F(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||||
|
+static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = {
|
||||||
|
+ C(P_UNIPHY1_RX, 12.5, 0, 0),
|
||||||
|
+ C(P_UNIPHY0_RX, 5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = {
|
||||||
|
+ C(P_UNIPHY1_RX, 2.5, 0, 0),
|
||||||
|
+ C(P_UNIPHY0_RX, 1, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_multi_tbl ftbl_nss_port5_rx_clk_src[] = {
|
||||||
|
+ FMS(19200000, P_XO, 1, 0, 0),
|
||||||
|
+ FM(25000000, ftbl_nss_port5_rx_clk_src_25),
|
||||||
|
+ FMS(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||||
|
+ FM(125000000, ftbl_nss_port5_rx_clk_src_125),
|
||||||
|
+ FMS(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||||
|
+ FMS(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1712,14 +1720,14 @@ gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32
|
||||||
|
|
||||||
|
static struct clk_rcg2 nss_port5_rx_clk_src = {
|
||||||
|
.cmd_rcgr = 0x68060,
|
||||||
|
- .freq_tbl = ftbl_nss_port5_rx_clk_src,
|
||||||
|
+ .freq_multi_tbl = ftbl_nss_port5_rx_clk_src,
|
||||||
|
.hid_width = 5,
|
||||||
|
.parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map,
|
||||||
|
.clkr.hw.init = &(struct clk_init_data){
|
||||||
|
.name = "nss_port5_rx_clk_src",
|
||||||
|
.parent_data = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
|
||||||
|
.num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias),
|
||||||
|
- .ops = &clk_rcg2_ops,
|
||||||
|
+ .ops = &clk_rcg2_fm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1739,15 +1747,23 @@ static struct clk_regmap_div nss_port5_r
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
|
||||||
|
- F(19200000, P_XO, 1, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY0_TX, 5, 0, 0),
|
||||||
|
- F(78125000, P_UNIPHY1_TX, 4, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY0_TX, 1, 0, 0),
|
||||||
|
- F(156250000, P_UNIPHY1_TX, 2, 0, 0),
|
||||||
|
- F(312500000, P_UNIPHY1_TX, 1, 0, 0),
|
||||||
|
+static const struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = {
|
||||||
|
+ C(P_UNIPHY1_TX, 12.5, 0, 0),
|
||||||
|
+ C(P_UNIPHY0_TX, 5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = {
|
||||||
|
+ C(P_UNIPHY1_TX, 2.5, 0, 0),
|
||||||
|
+ C(P_UNIPHY0_TX, 1, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_multi_tbl ftbl_nss_port5_tx_clk_src[] = {
|
||||||
|
+ FMS(19200000, P_XO, 1, 0, 0),
|
||||||
|
+ FM(25000000, ftbl_nss_port5_tx_clk_src_25),
|
||||||
|
+ FMS(78125000, P_UNIPHY1_TX, 4, 0, 0),
|
||||||
|
+ FM(125000000, ftbl_nss_port5_tx_clk_src_125),
|
||||||
|
+ FMS(156250000, P_UNIPHY1_TX, 2, 0, 0),
|
||||||
|
+ FMS(312500000, P_UNIPHY1_TX, 1, 0, 0),
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1774,14 +1790,14 @@ gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32
|
||||||
|
|
||||||
|
static struct clk_rcg2 nss_port5_tx_clk_src = {
|
||||||
|
.cmd_rcgr = 0x68068,
|
||||||
|
- .freq_tbl = ftbl_nss_port5_tx_clk_src,
|
||||||
|
+ .freq_multi_tbl = ftbl_nss_port5_tx_clk_src,
|
||||||
|
.hid_width = 5,
|
||||||
|
.parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map,
|
||||||
|
.clkr.hw.init = &(struct clk_init_data){
|
||||||
|
.name = "nss_port5_tx_clk_src",
|
||||||
|
.parent_data = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
|
||||||
|
.num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias),
|
||||||
|
- .ops = &clk_rcg2_ops,
|
||||||
|
+ .ops = &clk_rcg2_fm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1801,15 +1817,23 @@ static struct clk_regmap_div nss_port5_t
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
|
||||||
|
- F(19200000, P_XO, 1, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY2_RX, 5, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
|
||||||
|
- F(78125000, P_UNIPHY2_RX, 4, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY2_RX, 1, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
|
||||||
|
- F(156250000, P_UNIPHY2_RX, 2, 0, 0),
|
||||||
|
- F(312500000, P_UNIPHY2_RX, 1, 0, 0),
|
||||||
|
+static const struct freq_conf ftbl_nss_port6_rx_clk_src_25[] = {
|
||||||
|
+ C(P_UNIPHY2_RX, 5, 0, 0),
|
||||||
|
+ C(P_UNIPHY2_RX, 12.5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_conf ftbl_nss_port6_rx_clk_src_125[] = {
|
||||||
|
+ C(P_UNIPHY2_RX, 1, 0, 0),
|
||||||
|
+ C(P_UNIPHY2_RX, 2.5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_multi_tbl ftbl_nss_port6_rx_clk_src[] = {
|
||||||
|
+ FMS(19200000, P_XO, 1, 0, 0),
|
||||||
|
+ FM(25000000, ftbl_nss_port6_rx_clk_src_25),
|
||||||
|
+ FMS(78125000, P_UNIPHY2_RX, 4, 0, 0),
|
||||||
|
+ FM(125000000, ftbl_nss_port6_rx_clk_src_125),
|
||||||
|
+ FMS(156250000, P_UNIPHY2_RX, 2, 0, 0),
|
||||||
|
+ FMS(312500000, P_UNIPHY2_RX, 1, 0, 0),
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1831,14 +1855,14 @@ static const struct parent_map gcc_xo_un
|
||||||
|
|
||||||
|
static struct clk_rcg2 nss_port6_rx_clk_src = {
|
||||||
|
.cmd_rcgr = 0x68070,
|
||||||
|
- .freq_tbl = ftbl_nss_port6_rx_clk_src,
|
||||||
|
+ .freq_multi_tbl = ftbl_nss_port6_rx_clk_src,
|
||||||
|
.hid_width = 5,
|
||||||
|
.parent_map = gcc_xo_uniphy2_rx_tx_ubi32_bias_map,
|
||||||
|
.clkr.hw.init = &(struct clk_init_data){
|
||||||
|
.name = "nss_port6_rx_clk_src",
|
||||||
|
.parent_data = gcc_xo_uniphy2_rx_tx_ubi32_bias,
|
||||||
|
.num_parents = ARRAY_SIZE(gcc_xo_uniphy2_rx_tx_ubi32_bias),
|
||||||
|
- .ops = &clk_rcg2_ops,
|
||||||
|
+ .ops = &clk_rcg2_fm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1858,15 +1882,23 @@ static struct clk_regmap_div nss_port6_r
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
|
||||||
|
- F(19200000, P_XO, 1, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY2_TX, 5, 0, 0),
|
||||||
|
- F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
|
||||||
|
- F(78125000, P_UNIPHY2_TX, 4, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY2_TX, 1, 0, 0),
|
||||||
|
- F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
|
||||||
|
- F(156250000, P_UNIPHY2_TX, 2, 0, 0),
|
||||||
|
- F(312500000, P_UNIPHY2_TX, 1, 0, 0),
|
||||||
|
+static const struct freq_conf ftbl_nss_port6_tx_clk_src_25[] = {
|
||||||
|
+ C(P_UNIPHY2_TX, 5, 0, 0),
|
||||||
|
+ C(P_UNIPHY2_TX, 12.5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_conf ftbl_nss_port6_tx_clk_src_125[] = {
|
||||||
|
+ C(P_UNIPHY2_TX, 1, 0, 0),
|
||||||
|
+ C(P_UNIPHY2_TX, 2.5, 0, 0),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct freq_multi_tbl ftbl_nss_port6_tx_clk_src[] = {
|
||||||
|
+ FMS(19200000, P_XO, 1, 0, 0),
|
||||||
|
+ FM(25000000, ftbl_nss_port6_tx_clk_src_25),
|
||||||
|
+ FMS(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||||
|
+ FM(125000000, ftbl_nss_port6_tx_clk_src_125),
|
||||||
|
+ FMS(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||||
|
+ FMS(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1888,14 +1920,14 @@ static const struct parent_map gcc_xo_un
|
||||||
|
|
||||||
|
static struct clk_rcg2 nss_port6_tx_clk_src = {
|
||||||
|
.cmd_rcgr = 0x68078,
|
||||||
|
- .freq_tbl = ftbl_nss_port6_tx_clk_src,
|
||||||
|
+ .freq_multi_tbl = ftbl_nss_port6_tx_clk_src,
|
||||||
|
.hid_width = 5,
|
||||||
|
.parent_map = gcc_xo_uniphy2_tx_rx_ubi32_bias_map,
|
||||||
|
.clkr.hw.init = &(struct clk_init_data){
|
||||||
|
.name = "nss_port6_tx_clk_src",
|
||||||
|
.parent_data = gcc_xo_uniphy2_tx_rx_ubi32_bias,
|
||||||
|
.num_parents = ARRAY_SIZE(gcc_xo_uniphy2_tx_rx_ubi32_bias),
|
||||||
|
- .ops = &clk_rcg2_ops,
|
||||||
|
+ .ops = &clk_rcg2_fm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
From 032be4f49dda786fea9e1501212f6cd09a7ded96 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
|
||||||
Date: Thu, 3 Nov 2022 14:49:43 +0100
|
|
||||||
Subject: [PATCH] clk: qcom: clk-rcg2: introduce support for multiple conf for
|
|
||||||
same freq
|
|
||||||
|
|
||||||
Some RCG frequency can be reached by multiple configuration.
|
|
||||||
|
|
||||||
We currently declare multiple configuration for the same frequency but
|
|
||||||
that is not supported and always the first configuration will be taken.
|
|
||||||
|
|
||||||
These multiple configuration are needed as based on the current parent
|
|
||||||
configuration, it may be needed to use a different configuration to
|
|
||||||
reach the same frequency.
|
|
||||||
|
|
||||||
To handle this introduce 2 new macro, FM and C.
|
|
||||||
|
|
||||||
- FM is used to declare an empty freq_tbl with just the frequency and an
|
|
||||||
array of confs to insert all the config for the provided frequency.
|
|
||||||
|
|
||||||
- C is used to declare a fre_conf where src, pre_div, m and n are
|
|
||||||
provided.
|
|
||||||
|
|
||||||
The driver is changed to handle this special freq_tbl and select the
|
|
||||||
correct config by calculating the final rate and deciding based on the
|
|
||||||
one that is less different than the requested one.
|
|
||||||
|
|
||||||
Tested-by: Robert Marko <robimarko@gmail.com>
|
|
||||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
|
||||||
---
|
|
||||||
drivers/clk/qcom/clk-rcg.h | 14 ++++++-
|
|
||||||
drivers/clk/qcom/clk-rcg2.c | 84 +++++++++++++++++++++++++++++++++----
|
|
||||||
2 files changed, 88 insertions(+), 10 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/clk/qcom/clk-rcg.h
|
|
||||||
+++ b/drivers/clk/qcom/clk-rcg.h
|
|
||||||
@@ -7,7 +7,17 @@
|
|
||||||
#include <linux/clk-provider.h>
|
|
||||||
#include "clk-regmap.h"
|
|
||||||
|
|
||||||
-#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
|
|
||||||
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n), 0, NULL }
|
|
||||||
+
|
|
||||||
+#define FM(_f, _confs) { .freq = (_f), .confs_num = ARRAY_SIZE(_confs), .confs = (_confs) }
|
|
||||||
+#define C(s, h, m, n) { (s), (2 * (h) - 1), (m), (n) }
|
|
||||||
+
|
|
||||||
+struct freq_conf {
|
|
||||||
+ u8 src;
|
|
||||||
+ u8 pre_div;
|
|
||||||
+ u16 m;
|
|
||||||
+ u16 n;
|
|
||||||
+};
|
|
||||||
|
|
||||||
struct freq_tbl {
|
|
||||||
unsigned long freq;
|
|
||||||
@@ -15,6 +25,8 @@ struct freq_tbl {
|
|
||||||
u8 pre_div;
|
|
||||||
u16 m;
|
|
||||||
u16 n;
|
|
||||||
+ int confs_num;
|
|
||||||
+ const struct freq_conf *confs;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
--- a/drivers/clk/qcom/clk-rcg2.c
|
|
||||||
+++ b/drivers/clk/qcom/clk-rcg2.c
|
|
||||||
@@ -203,11 +203,60 @@ clk_rcg2_recalc_rate(struct clk_hw *hw,
|
|
||||||
return __clk_rcg2_recalc_rate(hw, parent_rate, cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void
|
|
||||||
+clk_rcg2_select_conf(struct clk_hw *hw, struct freq_tbl *f_tbl,
|
|
||||||
+ const struct freq_tbl *f, unsigned long req_rate)
|
|
||||||
+{
|
|
||||||
+ unsigned long best_rate = 0, parent_rate, rate;
|
|
||||||
+ const struct freq_conf *conf, *best_conf;
|
|
||||||
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
|
||||||
+ struct clk_hw *p;
|
|
||||||
+ int index, i;
|
|
||||||
+
|
|
||||||
+ /* Search in each provided config the one that is near the wanted rate */
|
|
||||||
+ for (i = 0, conf = f->confs; i < f->confs_num; i++, conf++) {
|
|
||||||
+ index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
|
|
||||||
+ if (index < 0)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ p = clk_hw_get_parent_by_index(hw, index);
|
|
||||||
+ if (!p)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ parent_rate = clk_hw_get_rate(p);
|
|
||||||
+ rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
|
|
||||||
+
|
|
||||||
+ if (rate == req_rate) {
|
|
||||||
+ best_conf = conf;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (abs(req_rate - rate) < abs(best_rate - rate)) {
|
|
||||||
+ best_rate = rate;
|
|
||||||
+ best_conf = conf;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Very unlikely.
|
|
||||||
+ * Force the first conf if we can't find a correct config.
|
|
||||||
+ */
|
|
||||||
+ if (unlikely(i == f->confs_num))
|
|
||||||
+ best_conf = f->confs;
|
|
||||||
+
|
|
||||||
+ /* Apply the config */
|
|
||||||
+ f_tbl->src = best_conf->src;
|
|
||||||
+ f_tbl->pre_div = best_conf->pre_div;
|
|
||||||
+ f_tbl->m = best_conf->m;
|
|
||||||
+ f_tbl->n = best_conf->n;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
|
|
||||||
struct clk_rate_request *req,
|
|
||||||
enum freq_policy policy)
|
|
||||||
{
|
|
||||||
unsigned long clk_flags, rate = req->rate;
|
|
||||||
+ struct freq_tbl f_tbl;
|
|
||||||
struct clk_hw *p;
|
|
||||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
|
||||||
int index;
|
|
||||||
@@ -226,7 +275,15 @@ static int _freq_tbl_determine_rate(stru
|
|
||||||
if (!f)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
- index = qcom_find_src_index(hw, rcg->parent_map, f->src);
|
|
||||||
+ f_tbl = *f;
|
|
||||||
+ /*
|
|
||||||
+ * A single freq may be reached by multiple configuration.
|
|
||||||
+ * Try to find the bast one if we have this kind of freq_table.
|
|
||||||
+ */
|
|
||||||
+ if (f->confs)
|
|
||||||
+ clk_rcg2_select_conf(hw, &f_tbl, f, rate);
|
|
||||||
+
|
|
||||||
+ index = qcom_find_src_index(hw, rcg->parent_map, f_tbl.src);
|
|
||||||
if (index < 0)
|
|
||||||
return index;
|
|
||||||
|
|
||||||
@@ -236,18 +293,18 @@ static int _freq_tbl_determine_rate(stru
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (clk_flags & CLK_SET_RATE_PARENT) {
|
|
||||||
- rate = f->freq;
|
|
||||||
- if (f->pre_div) {
|
|
||||||
+ rate = f_tbl.freq;
|
|
||||||
+ if (f_tbl.pre_div) {
|
|
||||||
if (!rate)
|
|
||||||
rate = req->rate;
|
|
||||||
rate /= 2;
|
|
||||||
- rate *= f->pre_div + 1;
|
|
||||||
+ rate *= f_tbl.pre_div + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (f->n) {
|
|
||||||
+ if (f_tbl.n) {
|
|
||||||
u64 tmp = rate;
|
|
||||||
- tmp = tmp * f->n;
|
|
||||||
- do_div(tmp, f->m);
|
|
||||||
+ tmp = tmp * f_tbl.n;
|
|
||||||
+ do_div(tmp, f_tbl.m);
|
|
||||||
rate = tmp;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
@@ -255,7 +312,7 @@ static int _freq_tbl_determine_rate(stru
|
|
||||||
}
|
|
||||||
req->best_parent_hw = p;
|
|
||||||
req->best_parent_rate = rate;
|
|
||||||
- req->rate = f->freq;
|
|
||||||
+ req->rate = f_tbl.freq;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -353,6 +410,7 @@ static int __clk_rcg2_set_rate(struct cl
|
|
||||||
{
|
|
||||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
|
||||||
const struct freq_tbl *f;
|
|
||||||
+ struct freq_tbl f_tbl;
|
|
||||||
|
|
||||||
switch (policy) {
|
|
||||||
case FLOOR:
|
|
||||||
@@ -368,7 +426,15 @@ static int __clk_rcg2_set_rate(struct cl
|
|
||||||
if (!f)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
- return clk_rcg2_configure(rcg, f);
|
|
||||||
+ f_tbl = *f;
|
|
||||||
+ /*
|
|
||||||
+ * A single freq may be reached by multiple configuration.
|
|
||||||
+ * Try to find the best one if we have this kind of freq_table.
|
|
||||||
+ */
|
|
||||||
+ if (f->confs)
|
|
||||||
+ clk_rcg2_select_conf(hw, &f_tbl, f, rate);
|
|
||||||
+
|
|
||||||
+ return clk_rcg2_configure(rcg, &f_tbl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
@ -1,129 +0,0 @@
|
||||||
From f778553f296792f4d1e8b3552603ad6116ea3eb3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
|
||||||
Date: Thu, 3 Nov 2022 14:49:44 +0100
|
|
||||||
Subject: [PATCH] clk: qcom: gcc-ipq8074: rework nss_port5/6 clock to multiple
|
|
||||||
conf
|
|
||||||
|
|
||||||
Rework nss_port5/6 to use the new multiple configuration implementation
|
|
||||||
and correctly fix the clocks for these port under some corner case.
|
|
||||||
|
|
||||||
This is particularly relevant for device that have 2.5G or 10G port
|
|
||||||
connected to port5 or port 6 on ipq8074. As the parent are shared
|
|
||||||
across multiple port it may be required to select the correct
|
|
||||||
configuration to accomplish the desired clock. Without this patch such
|
|
||||||
port doesn't work in some specific ethernet speed as the clock will be
|
|
||||||
set to the wrong frequency as we just select the first configuration for
|
|
||||||
the related frequency instead of selecting the best one.
|
|
||||||
|
|
||||||
Tested-by: Robert Marko <robimarko@gmail.com> # ipq8074 Qnap QHora-301W
|
|
||||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
|
||||||
---
|
|
||||||
drivers/clk/qcom/gcc-ipq8074.c | 64 +++++++++++++++++++++++++---------
|
|
||||||
1 file changed, 48 insertions(+), 16 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
|
||||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
|
||||||
@@ -1677,13 +1677,21 @@ static struct clk_regmap_div nss_port4_t
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = {
|
|
||||||
+ C(P_UNIPHY1_RX, 12.5, 0, 0),
|
|
||||||
+ C(P_UNIPHY0_RX, 5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = {
|
|
||||||
+ C(P_UNIPHY1_RX, 2.5, 0, 0),
|
|
||||||
+ C(P_UNIPHY0_RX, 1, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
|
|
||||||
F(19200000, P_XO, 1, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY0_RX, 5, 0, 0),
|
|
||||||
+ FM(25000000, ftbl_nss_port5_rx_clk_src_25),
|
|
||||||
F(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY0_RX, 1, 0, 0),
|
|
||||||
+ FM(125000000, ftbl_nss_port5_rx_clk_src_125),
|
|
||||||
F(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
|
||||||
F(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
|
||||||
{ }
|
|
||||||
@@ -1739,13 +1747,21 @@ static struct clk_regmap_div nss_port5_r
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+static struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = {
|
|
||||||
+ C(P_UNIPHY1_TX, 12.5, 0, 0),
|
|
||||||
+ C(P_UNIPHY0_TX, 5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = {
|
|
||||||
+ C(P_UNIPHY1_TX, 2.5, 0, 0),
|
|
||||||
+ C(P_UNIPHY0_TX, 1, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
|
|
||||||
F(19200000, P_XO, 1, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY0_TX, 5, 0, 0),
|
|
||||||
+ FM(25000000, ftbl_nss_port5_tx_clk_src_25),
|
|
||||||
F(78125000, P_UNIPHY1_TX, 4, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY0_TX, 1, 0, 0),
|
|
||||||
+ FM(125000000, ftbl_nss_port5_tx_clk_src_125),
|
|
||||||
F(156250000, P_UNIPHY1_TX, 2, 0, 0),
|
|
||||||
F(312500000, P_UNIPHY1_TX, 1, 0, 0),
|
|
||||||
{ }
|
|
||||||
@@ -1801,13 +1817,21 @@ static struct clk_regmap_div nss_port5_t
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+static struct freq_conf ftbl_nss_port6_rx_clk_src_25[] = {
|
|
||||||
+ C(P_UNIPHY2_RX, 5, 0, 0),
|
|
||||||
+ C(P_UNIPHY2_RX, 12.5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct freq_conf ftbl_nss_port6_rx_clk_src_125[] = {
|
|
||||||
+ C(P_UNIPHY2_RX, 1, 0, 0),
|
|
||||||
+ C(P_UNIPHY2_RX, 2.5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
|
|
||||||
F(19200000, P_XO, 1, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY2_RX, 5, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
|
|
||||||
+ FM(25000000, ftbl_nss_port6_rx_clk_src_25),
|
|
||||||
F(78125000, P_UNIPHY2_RX, 4, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY2_RX, 1, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
|
|
||||||
+ FM(125000000, ftbl_nss_port6_rx_clk_src_125),
|
|
||||||
F(156250000, P_UNIPHY2_RX, 2, 0, 0),
|
|
||||||
F(312500000, P_UNIPHY2_RX, 1, 0, 0),
|
|
||||||
{ }
|
|
||||||
@@ -1858,13 +1882,21 @@ static struct clk_regmap_div nss_port6_r
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+static struct freq_conf ftbl_nss_port6_tx_clk_src_25[] = {
|
|
||||||
+ C(P_UNIPHY2_TX, 5, 0, 0),
|
|
||||||
+ C(P_UNIPHY2_TX, 12.5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct freq_conf ftbl_nss_port6_tx_clk_src_125[] = {
|
|
||||||
+ C(P_UNIPHY2_TX, 1, 0, 0),
|
|
||||||
+ C(P_UNIPHY2_TX, 2.5, 0, 0),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
|
|
||||||
F(19200000, P_XO, 1, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY2_TX, 5, 0, 0),
|
|
||||||
- F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
|
|
||||||
+ FM(25000000, ftbl_nss_port6_tx_clk_src_25),
|
|
||||||
F(78125000, P_UNIPHY2_TX, 4, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY2_TX, 1, 0, 0),
|
|
||||||
- F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
|
|
||||||
+ FM(125000000, ftbl_nss_port6_tx_clk_src_125),
|
|
||||||
F(156250000, P_UNIPHY2_TX, 2, 0, 0),
|
|
||||||
F(312500000, P_UNIPHY2_TX, 1, 0, 0),
|
|
||||||
{ }
|
|
Loading…
Reference in a new issue