* [PATCH 0/6] clk: qcom: PLL updates
@ 2016-07-11 10:50 Rajendra Nayak
2016-07-11 10:50 ` [PATCH 1/6] clk: Fix inconsistencies in usage of data types Rajendra Nayak
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Hi,
This series adds some additional support to the clk-alpha-pll and the
clk-pll drivers in preperation to add the CPU clock driver support
on msm8996
regards,
Rajendra
Rajendra Nayak (6):
clk: Fix inconsistencies in usage of data types
clk: qcom: Add support for alpha pll hwfsm ops
clk: qcom: Add support to initialize alpha plls
clk: qcom: Add support for PLLs with alpha mode
clk: qcom: Add support for PLLs with early output
clk: qcom: Add support for PLLs supporting dynamic reprogramming
drivers/clk/clk.c | 4 +-
drivers/clk/qcom/clk-alpha-pll.c | 132 +++++++++++++++++++++++++++++++++++----
drivers/clk/qcom/clk-alpha-pll.h | 14 +++++
drivers/clk/qcom/clk-pll.c | 116 +++++++++++++++++++++++++++++++++-
drivers/clk/qcom/clk-pll.h | 12 +++-
include/linux/clk-provider.h | 5 +-
6 files changed, 263 insertions(+), 20 deletions(-)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/6] clk: Fix inconsistencies in usage of data types
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
2016-07-11 10:50 ` [PATCH 2/6] clk: qcom: Add support for alpha pll hwfsm ops Rajendra Nayak
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
index is of type u8 in all places except in clk_hw_get_parent_by_index()
and return value of all round_rate functions is long except for
clk_hw_round_rate(). Make them consistent with the rest of the places
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/clk.c | 4 ++--
include/linux/clk-provider.h | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d584004..1af6989 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -359,7 +359,7 @@ static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
}
struct clk_hw *
-clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int index)
+clk_hw_get_parent_by_index(const struct clk_hw *hw, u8 index)
{
struct clk_core *parent;
@@ -845,7 +845,7 @@ int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
}
EXPORT_SYMBOL_GPL(__clk_determine_rate);
-unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
+long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
{
int ret;
struct clk_rate_request req;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index fb39d5a..5cf82cc 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -729,8 +729,7 @@ const char *clk_hw_get_name(const struct clk_hw *hw);
struct clk_hw *__clk_get_hw(struct clk *clk);
unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
-struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
- unsigned int index);
+struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, u8 index);
unsigned int __clk_get_enable_count(struct clk *clk);
unsigned long clk_hw_get_rate(const struct clk_hw *hw);
unsigned long __clk_get_flags(struct clk *clk);
@@ -757,7 +756,7 @@ static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
/*
* FIXME clock api without lock protection
*/
-unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate);
+long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate);
struct of_device_id;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/6] clk: qcom: Add support for alpha pll hwfsm ops
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
2016-07-11 10:50 ` [PATCH 1/6] clk: Fix inconsistencies in usage of data types Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
2016-07-11 10:50 ` [PATCH 3/6] clk: qcom: Add support to initialize alpha plls Rajendra Nayak
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Add support to enable/disable the alpha pll using hwfsm
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/qcom/clk-alpha-pll.c | 109 ++++++++++++++++++++++++++++++++++-----
drivers/clk/qcom/clk-alpha-pll.h | 1 +
2 files changed, 98 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index e6a03ea..bae31f9 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -62,9 +62,10 @@
#define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
struct clk_alpha_pll_postdiv, clkr)
-static int wait_for_pll(struct clk_alpha_pll *pll)
+static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
+ const char *action)
{
- u32 val, mask, off;
+ u32 val, off;
int count;
int ret;
const char *name = clk_hw_get_name(&pll->clkr.hw);
@@ -74,26 +75,101 @@ static int wait_for_pll(struct clk_alpha_pll *pll)
if (ret)
return ret;
- if (val & PLL_VOTE_FSM_ENA)
- mask = PLL_ACTIVE_FLAG;
- else
- mask = PLL_LOCK_DET;
-
- /* Wait for pll to enable. */
for (count = 100; count > 0; count--) {
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return ret;
- if ((val & mask) == mask)
+ if (inverse && (val & mask))
+ return 0;
+ else if ((val & mask) == mask)
return 0;
udelay(1);
}
- WARN(1, "%s didn't enable after voting for it!\n", name);
+ WARN(1, "%s failed to %s!\n", name, action);
return -ETIMEDOUT;
}
+static int wait_for_pll_enable(struct clk_alpha_pll *pll, u32 mask)
+{
+ return wait_for_pll(pll, mask, 0, "enable");
+}
+
+static int wait_for_pll_disable(struct clk_alpha_pll *pll, u32 mask)
+{
+ return wait_for_pll(pll, mask, 1, "disable");
+}
+
+static int wait_for_pll_offline(struct clk_alpha_pll *pll, u32 mask)
+{
+ return wait_for_pll(pll, mask, 0, "offline");
+}
+
+/* alpha pll with hwfsm support */
+#define PLL_OFFLINE_REQ BIT(7)
+#define PLL_FSM_ENA BIT(20)
+#define PLL_OFFLINE_ACK BIT(28)
+#define PLL_ACTIVE_FLAG BIT(30)
+
+static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
+{
+ int ret;
+ u32 val, off;
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+
+ off = pll->offset;
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return ret;
+
+ /* Enable HW FSM mode, clear OFFLINE request */
+ val |= PLL_FSM_ENA;
+ val &= ~PLL_OFFLINE_REQ;
+ ret = regmap_write(pll->clkr.regmap, off + PLL_MODE, val);
+ if (ret)
+ return ret;
+
+ /* Make sure enable request goes through before waiting for update */
+ mb();
+
+ ret = wait_for_pll_enable(pll, PLL_ACTIVE_FLAG);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw)
+{
+ int ret;
+ u32 val, off;
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+
+ off = pll->offset;
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return;
+
+ /* Request PLL_OFFLINE and wait for ack */
+ ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+ PLL_OFFLINE_REQ, PLL_OFFLINE_REQ);
+ if (ret)
+ return;
+
+ ret = wait_for_pll_offline(pll, PLL_OFFLINE_ACK);
+ if (ret)
+ return;
+
+ /* Disable hwfsm */
+ ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+ PLL_FSM_ENA, 0);
+ if (ret)
+ return;
+
+ wait_for_pll_disable(pll, PLL_ACTIVE_FLAG);
+}
+
static int clk_alpha_pll_enable(struct clk_hw *hw)
{
int ret;
@@ -112,7 +188,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)
ret = clk_enable_regmap(hw);
if (ret)
return ret;
- return wait_for_pll(pll);
+ return wait_for_pll_enable(pll, PLL_ACTIVE_FLAG);
}
/* Skip if already enabled */
@@ -136,7 +212,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)
if (ret)
return ret;
- ret = wait_for_pll(pll);
+ ret = wait_for_pll_enable(pll, PLL_LOCK_DET);
if (ret)
return ret;
@@ -300,6 +376,15 @@ const struct clk_ops clk_alpha_pll_ops = {
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);
+const struct clk_ops clk_alpha_pll_hwfsm_ops = {
+ .enable = clk_alpha_pll_hwfsm_enable,
+ .disable = clk_alpha_pll_hwfsm_disable,
+ .recalc_rate = clk_alpha_pll_recalc_rate,
+ .round_rate = clk_alpha_pll_round_rate,
+ .set_rate = clk_alpha_pll_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
+
static unsigned long
clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 90ce201..f78bf4c 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -52,6 +52,7 @@ struct clk_alpha_pll_postdiv {
};
extern const struct clk_ops clk_alpha_pll_ops;
+extern const struct clk_ops clk_alpha_pll_hwfsm_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;
#endif
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/6] clk: qcom: Add support to initialize alpha plls
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
2016-07-11 10:50 ` [PATCH 1/6] clk: Fix inconsistencies in usage of data types Rajendra Nayak
2016-07-11 10:50 ` [PATCH 2/6] clk: qcom: Add support for alpha pll hwfsm ops Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
2016-07-11 10:50 ` [PATCH 4/6] clk: qcom: Add support for PLLs with alpha mode Rajendra Nayak
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Add a function to do initial configuration of the alpha plls
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/qcom/clk-alpha-pll.c | 23 +++++++++++++++++++++++
drivers/clk/qcom/clk-alpha-pll.h | 13 +++++++++++++
2 files changed, 36 insertions(+)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index bae31f9..8b8710f 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -112,6 +112,29 @@ static int wait_for_pll_offline(struct clk_alpha_pll *pll, u32 mask)
#define PLL_OFFLINE_ACK BIT(28)
#define PLL_ACTIVE_FLAG BIT(30)
+void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+ const struct alpha_pll_config *config)
+{
+ u32 val, mask;
+
+ regmap_write(regmap, pll->offset + PLL_CONFIG_CTL,
+ config->config_ctl_val);
+
+ val = config->main_output_mask;
+ val |= config->aux_output_mask;
+ val |= config->aux2_output_mask;
+ val |= config->early_output_mask;
+ val |= config->post_div_val;
+
+ mask = config->main_output_mask;
+ mask |= config->aux_output_mask;
+ mask |= config->aux2_output_mask;
+ mask |= config->early_output_mask;
+ mask |= config->post_div_mask;
+
+ regmap_update_bits(regmap, pll->offset + PLL_USER_CTL, mask, val);
+}
+
static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
{
int ret;
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index f78bf4c..12a349e 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -51,8 +51,21 @@ struct clk_alpha_pll_postdiv {
struct clk_regmap clkr;
};
+struct alpha_pll_config {
+ u32 config_ctl_val;
+ u32 main_output_mask;
+ u32 aux_output_mask;
+ u32 aux2_output_mask;
+ u32 early_output_mask;
+ u32 post_div_val;
+ u32 post_div_mask;
+};
+
extern const struct clk_ops clk_alpha_pll_ops;
extern const struct clk_ops clk_alpha_pll_hwfsm_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;
+void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+ const struct alpha_pll_config *config);
+
#endif
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/6] clk: qcom: Add support for PLLs with alpha mode
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
` (2 preceding siblings ...)
2016-07-11 10:50 ` [PATCH 3/6] clk: qcom: Add support to initialize alpha plls Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
2016-07-11 10:50 ` [PATCH 5/6] clk: qcom: Add support for PLLs with early output Rajendra Nayak
2016-07-11 10:50 ` [PATCH 6/6] clk: qcom: Add support for PLLs supporting dynamic reprogramming Rajendra Nayak
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Some PLLs can support an alpha mode, and a single alpha
register (instead of registers to program the M/N values),
the contents of which depend on the alpha mode selected.
(They are either treated as two's complement or M/N value)
Add support for this in the clk PLL driver.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/qcom/clk-pll.c | 8 ++++++--
drivers/clk/qcom/clk-pll.h | 2 ++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 5b940d6..08d2fa2 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -255,8 +255,12 @@ static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
u32 mask;
regmap_write(regmap, pll->l_reg, config->l);
- regmap_write(regmap, pll->m_reg, config->m);
- regmap_write(regmap, pll->n_reg, config->n);
+ if (pll->alpha_reg) {
+ regmap_write(regmap, pll->alpha_reg, config->alpha);
+ } else {
+ regmap_write(regmap, pll->m_reg, config->m);
+ regmap_write(regmap, pll->n_reg, config->n);
+ }
val = config->vco_val;
val |= config->pre_div_val;
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
index ffd0c63..083727e 100644
--- a/drivers/clk/qcom/clk-pll.h
+++ b/drivers/clk/qcom/clk-pll.h
@@ -48,6 +48,7 @@ struct clk_pll {
u32 l_reg;
u32 m_reg;
u32 n_reg;
+ u32 alpha_reg;
u32 config_reg;
u32 mode_reg;
u32 status_reg;
@@ -70,6 +71,7 @@ struct pll_config {
u16 l;
u32 m;
u32 n;
+ u32 alpha;
u32 vco_val;
u32 vco_mask;
u32 pre_div_val;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/6] clk: qcom: Add support for PLLs with early output
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
` (3 preceding siblings ...)
2016-07-11 10:50 ` [PATCH 4/6] clk: qcom: Add support for PLLs with alpha mode Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
2016-07-11 10:50 ` [PATCH 6/6] clk: qcom: Add support for PLLs supporting dynamic reprogramming Rajendra Nayak
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Some PLLs can have an additional early output (apart from
the main and aux outputs). Add support for the PLL driver
so it can be used to initialize/configure the early output
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/qcom/clk-pll.c | 2 ++
drivers/clk/qcom/clk-pll.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 08d2fa2..b463432 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -268,6 +268,7 @@ static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
val |= config->mn_ena_mask;
val |= config->main_output_mask;
val |= config->aux_output_mask;
+ val |= config->early_output_mask;
mask = config->vco_mask;
mask |= config->pre_div_mask;
@@ -275,6 +276,7 @@ static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
mask |= config->mn_ena_mask;
mask |= config->main_output_mask;
mask |= config->aux_output_mask;
+ mask |= config->early_output_mask;
regmap_update_bits(regmap, pll->config_reg, mask, val);
}
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
index 083727e..dbe22a9 100644
--- a/drivers/clk/qcom/clk-pll.h
+++ b/drivers/clk/qcom/clk-pll.h
@@ -81,6 +81,7 @@ struct pll_config {
u32 mn_ena_mask;
u32 main_output_mask;
u32 aux_output_mask;
+ u32 early_output_mask;
};
void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6/6] clk: qcom: Add support for PLLs supporting dynamic reprogramming
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
` (4 preceding siblings ...)
2016-07-11 10:50 ` [PATCH 5/6] clk: qcom: Add support for PLLs with early output Rajendra Nayak
@ 2016-07-11 10:50 ` Rajendra Nayak
5 siblings, 0 replies; 7+ messages in thread
From: Rajendra Nayak @ 2016-07-11 10:50 UTC (permalink / raw)
To: sboyd, stephen.boyd, mturquette
Cc: linux-clk, linux-arm-msm, linux-kernel, Rajendra Nayak
Some PLLs can support dynamic reprogramming, which means just a L value
change is whats needed to change the PLL frequency without having to
explicitly enable/disable or bypass/re-lock the PLL.
Add support for such PLLs' initial configuration and the ops needed to
support the dynamic reprogramming thereafter.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
drivers/clk/qcom/clk-pll.c | 106 +++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/qcom/clk-pll.h | 9 +++-
2 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index b463432..13d3f64 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -32,6 +32,7 @@
#define PLL_BIAS_COUNT_SHIFT 14
#define PLL_BIAS_COUNT_MASK 0x3f
#define PLL_VOTE_FSM_ENA BIT(20)
+#define PLL_DYN_FSM_ENA BIT(20)
#define PLL_VOTE_FSM_RESET BIT(21)
static int clk_pll_enable(struct clk_hw *hw)
@@ -248,6 +249,19 @@ clk_pll_set_fsm_mode(struct clk_pll *pll, struct regmap *regmap, u8 lock_count)
PLL_VOTE_FSM_ENA);
}
+static void
+clk_pll_set_dynamic_fsm_mode(struct clk_pll *pll, struct regmap *regmap)
+{
+ u32 val;
+ u32 mask;
+
+ mask = PLL_BIAS_COUNT_MASK | PLL_DYN_FSM_ENA;
+ val = 6 << PLL_BIAS_COUNT_SHIFT;
+ val |= PLL_DYN_FSM_ENA;
+
+ regmap_update_bits(regmap, pll->mode_reg, mask, val);
+}
+
static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
const struct pll_config *config)
{
@@ -299,6 +313,21 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
}
EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
+void clk_pll_configure_dynamic(struct clk_pll *pll, struct regmap *regmap,
+ const struct pll_config *config)
+{
+ u32 config_ctl_reg = pll->config_ctl_reg;
+ u32 config_ctl_hi_reg = pll->config_ctl_reg + 4;
+
+ clk_pll_configure(pll, regmap, config);
+
+ regmap_write(regmap, config_ctl_reg, config->config_ctl_val);
+ regmap_write(regmap, config_ctl_hi_reg, config->config_ctl_hi_val);
+
+ clk_pll_set_dynamic_fsm_mode(pll, regmap);
+}
+EXPORT_SYMBOL_GPL(clk_pll_configure_dynamic);
+
static int clk_pll_sr2_enable(struct clk_hw *hw)
{
struct clk_pll *pll = to_clk_pll(hw);
@@ -373,3 +402,80 @@ const struct clk_ops clk_pll_sr2_ops = {
.determine_rate = clk_pll_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);
+
+static int clk_pll_dynamic_enable(struct clk_hw *hw)
+{
+ struct clk_pll *pll = to_clk_pll(hw);
+
+ /* Wait for 50us explicitly to avoid transient locks */
+ udelay(50);
+
+ return wait_for_pll(pll);
+};
+
+static void clk_pll_dynamic_disable(struct clk_hw *hw)
+{
+ /* 8 reference clock cycle delay mandated by the HPG */
+ udelay(1);
+};
+
+static unsigned long
+clk_pll_dynamic_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ u32 l_val;
+ int ret;
+
+ struct clk_pll *pll = to_clk_pll(hw);
+
+ ret = regmap_read(pll->clkr.regmap, pll->l_reg, &l_val);
+ if (ret)
+ return ret;
+
+ return l_val * parent_rate;
+};
+
+static int
+clk_pll_dynamic_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_pll *pll = to_clk_pll(hw);
+ const struct pll_freq_tbl *f;
+
+ f = find_freq(pll->freq_tbl, req->rate);
+ if (!f)
+ req->rate = DIV_ROUND_UP(req->rate, req->best_parent_rate)
+ * req->best_parent_rate;
+ else
+ req->rate = f->freq;
+
+ if (req->rate < pll->min_rate)
+ req->rate = pll->min_rate;
+ else if (req->rate > pll->max_rate)
+ req->rate = pll->max_rate;
+
+ return 0;
+}
+
+static int
+clk_pll_dynamic_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ u32 l_val;
+ struct clk_pll *pll = to_clk_pll(hw);
+
+ if ((rate < pll->min_rate) || (rate > pll->max_rate) || !prate)
+ return -EINVAL;
+
+ l_val = rate / prate;
+ regmap_write(pll->clkr.regmap, pll->l_reg, l_val);
+
+ return 0;
+}
+
+const struct clk_ops clk_pll_dynamic_ops = {
+ .enable = clk_pll_dynamic_enable,
+ .disable = clk_pll_dynamic_disable,
+ .set_rate = clk_pll_dynamic_set_rate,
+ .recalc_rate = clk_pll_dynamic_recalc_rate,
+ .determine_rate = clk_pll_dynamic_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_pll_dynamic_ops);
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
index dbe22a9..627588f 100644
--- a/drivers/clk/qcom/clk-pll.h
+++ b/drivers/clk/qcom/clk-pll.h
@@ -52,9 +52,12 @@ struct clk_pll {
u32 config_reg;
u32 mode_reg;
u32 status_reg;
+ u32 config_ctl_reg;
u8 status_bit;
u8 post_div_width;
u8 post_div_shift;
+ unsigned long min_rate;
+ unsigned long max_rate;
const struct pll_freq_tbl *freq_tbl;
@@ -64,6 +67,7 @@ struct clk_pll {
extern const struct clk_ops clk_pll_ops;
extern const struct clk_ops clk_pll_vote_ops;
extern const struct clk_ops clk_pll_sr2_ops;
+extern const struct clk_ops clk_pll_dynamic_ops;
#define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr)
@@ -78,6 +82,8 @@ struct pll_config {
u32 pre_div_mask;
u32 post_div_val;
u32 post_div_mask;
+ u32 config_ctl_val;
+ u32 config_ctl_hi_val;
u32 mn_ena_mask;
u32 main_output_mask;
u32 aux_output_mask;
@@ -88,5 +94,6 @@ void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
const struct pll_config *config, bool fsm_mode);
void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
const struct pll_config *config, bool fsm_mode);
-
+void clk_pll_configure_dynamic(struct clk_pll *pll, struct regmap *regmap,
+ const struct pll_config *config);
#endif
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-07-11 10:50 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-11 10:50 [PATCH 0/6] clk: qcom: PLL updates Rajendra Nayak
2016-07-11 10:50 ` [PATCH 1/6] clk: Fix inconsistencies in usage of data types Rajendra Nayak
2016-07-11 10:50 ` [PATCH 2/6] clk: qcom: Add support for alpha pll hwfsm ops Rajendra Nayak
2016-07-11 10:50 ` [PATCH 3/6] clk: qcom: Add support to initialize alpha plls Rajendra Nayak
2016-07-11 10:50 ` [PATCH 4/6] clk: qcom: Add support for PLLs with alpha mode Rajendra Nayak
2016-07-11 10:50 ` [PATCH 5/6] clk: qcom: Add support for PLLs with early output Rajendra Nayak
2016-07-11 10:50 ` [PATCH 6/6] clk: qcom: Add support for PLLs supporting dynamic reprogramming Rajendra Nayak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).