Updates for QCOM Alpha PLL
Subsystems (3)
cover Updates for QCOM Alpha PLL
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the pll_type which will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.
The previous RFC series can be found for this in
https://www.spinics.net/lists/linux-clk/msg19305.html
Abhishek Sahu (13):
clk: qcom: remove redundant PLL_MODE macro offset
clk: qcom: minor code reorganization related with offset variable
clk: qcom: support for alpha pll properties
clk: qcom: fix 16 bit alpha support calculation
clk: qcom: add and use alpha register width from PLL properties
clk: qcom: flag for 64 bit CONFIG_CTL
clk: qcom: support for alpha mode configuration
clk: qcom: support for dynamic updating the PLL
clk: qcom: add flag for VCO operation
clk: qcom: support for Huayra PLL
clk: qcom: support for Brammo PLL
clk: qcom: support for 2 bit PLL post divider
clk: qcom: add read-only alpha pll post divider operations
drivers/clk/qcom/clk-alpha-pll.c | 701 +++++++++++++++++++++++++++++++++------ drivers/clk/qcom/clk-alpha-pll.h | 19 +- 2 files changed, 609 insertions(+), 111 deletions(-)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH 1/13 clk: qcom: remove redundant PLL_MODE macro offset
The PLL_MODE offset macro is redundant which is defined as zero. The offset in PLL structure is the address of PLL_MODE register itself so the PLL_MODE can be removed. It will help in subsequent patches to support different PLL offset registers to reduce the code diff.
--- drivers/clk/qcom/clk-alpha-pll.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +16 -17
@@ -20,7 +20,6 @@#include "clk-alpha-pll.h" #include "common.h" -#define PLL_MODE 0x00# define PLL_OUTCTRL BIT(0)# define PLL_BYPASSNL BIT(1)# define PLL_RESET_N BIT(2)
@@ -77,12 +76,12 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,const char *name =clk_hw_get_name (&pll->clkr.hw); off = pll->offset; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;for (count =100 ; count >0 ; count--) { - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;if (inverse && !(val & mask))
@@ -139,7 +138,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,regmap_update_bits (regmap, off +PLL_USER_CTL , mask, val);if (pll->flags &SUPPORTS_FSM_MODE ) -qcom_pll_set_fsm_mode (regmap, off +PLL_MODE ,6 ,0 ); +qcom_pll_set_fsm_mode (regmap, off,6 ,0 ); }static int clk_alpha_pll_hwfsm_enable (struct clk_hw *hw)
@@ -149,7 +148,7 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); off = pll->offset; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -158,7 +157,7 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)if (pll->flags &SUPPORTS_OFFLINE_REQ ) val &= ~PLL_OFFLINE_REQ ; - ret =regmap_write (pll->clkr.regmap, off +PLL_MODE , val); + ret =regmap_write (pll->clkr.regmap, off, val);if (ret)return ret;
@@ -175,12 +174,12 @@ static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw)struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); off = pll->offset; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ;if (pll->flags &SUPPORTS_OFFLINE_REQ ) { - ret =regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , + ret =regmap_update_bits (pll->clkr.regmap, off,PLL_OFFLINE_REQ ,PLL_OFFLINE_REQ );if (ret)return ;
@@ -191,7 +190,7 @@ static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw) }/* Disable hwfsm */ - ret =regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , + ret =regmap_update_bits (pll->clkr.regmap, off,PLL_FSM_ENA ,0 );if (ret)return ;
@@ -206,7 +205,7 @@ static int pll_is_enabled(struct clk_hw *hw, u32 mask)struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); off = pll->offset; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -232,7 +231,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) off = pll->offset; mask =PLL_OUTCTRL |PLL_RESET_N |PLL_BYPASSNL ; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -248,7 +247,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)if ((val & mask) == mask)return 0 ; - ret =regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , + ret =regmap_update_bits (pll->clkr.regmap, off,PLL_BYPASSNL ,PLL_BYPASSNL );if (ret)return ret;
@@ -260,7 +259,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)mb ();udelay (5 ); - ret =regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , + ret =regmap_update_bits (pll->clkr.regmap, off,PLL_RESET_N ,PLL_RESET_N );if (ret)return ret;
@@ -269,7 +268,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)if (ret)return ret; - ret =regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , + ret =regmap_update_bits (pll->clkr.regmap, off,PLL_OUTCTRL ,PLL_OUTCTRL );/* Ensure that the write above goes through before returning. */
@@ -285,7 +284,7 @@ static void clk_alpha_pll_disable(struct clk_hw *hw) off = pll->offset; - ret =regmap_read (pll->clkr.regmap, off +PLL_MODE , &val); + ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ;
@@ -296,14 +295,14 @@ static void clk_alpha_pll_disable(struct clk_hw *hw) } mask =PLL_OUTCTRL ; -regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , mask,0 ); +regmap_update_bits (pll->clkr.regmap, off, mask,0 );/* Delay of 2 output clock ticks required until output is disabled */ mb ();udelay (1 ); mask =PLL_RESET_N |PLL_BYPASSNL ; -regmap_update_bits (pll->clkr.regmap, off +PLL_MODE , mask,0 ); +regmap_update_bits (pll->clkr.regmap, off, mask,0 ); }static unsigned long alpha_pll_calc_rate (u64 prate,u32 l,u32 a)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH 2/13 clk: qcom: minor code reorganization related with offset variable
In reply to Abhishek SahuThis patch does minor code reorganization related with offset variable assignment. The offset variable can be directly defined which will help in subsequent patches to support different PLL offset registers.
--- drivers/clk/qcom/clk-alpha-pll.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +9 -17
@@ -70,12 +70,11 @@static int wait_for_pll (struct clk_alpha_pll *pll,u32 mask,bool inverse,const char *action) { -u32 val, off; +u32 val, off = pll->offset;int count;int ret;const char *name =clk_hw_get_name (&pll->clkr.hw); - off = pll->offset; ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -143,11 +142,10 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,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); +int ret; +u32 val, off = pll->offset; - off = pll->offset; ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -169,11 +167,10 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)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); +int ret; +u32 val, off = pll->offset; - off = pll->offset; ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ;
@@ -200,11 +197,10 @@ static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw)static int pll_is_enabled (struct clk_hw *hw,u32 mask) { -int ret; -u32 val, off;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +int ret; +u32 val, off = pll->offset; - off = pll->offset; ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)return ret;
@@ -226,9 +222,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 val, mask, off; - - off = pll->offset; +u32 val, mask, off = pll->offset; mask =PLL_OUTCTRL |PLL_RESET_N |PLL_BYPASSNL ; ret =regmap_read (pll->clkr.regmap, off, &val);
@@ -280,9 +274,7 @@ static void clk_alpha_pll_disable(struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 val, mask, off; - - off = pll->offset; +u32 val, mask, off = pll->offset; ret =regmap_read (pll->clkr.regmap, off, &val);if (ret)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH 3/13 clk: qcom: support for alpha pll properties
In reply to Abhishek SahuAlpha PLL is a generic name used for QCOM PLL’s which uses L and Alpha values for configuring the integer and fractional part. QCOM SoC’s use different types of Alpha PLL’s for which basic software configuration part is common with following differences.
1. All These PLL’s will have same basic registers like PLL_MODE, L_VAL, ALPHA_VAL but some of the register offsets are different in each PLL type.
2. PLL dynamic programming sequence will be different in some of the Alpha PLL’s
3. Some of the PLL won’t have 64 bit config control, 64 bit user control, VCO configuration etc.
Now, this patch adds the Alpha PLL type in clock node and adds alpha PLL properties structure inside clk-alpha-pll.c. This PLL property will contain everything including register offsets, clock operations and other properties since all these properties will be fixed for Alpha PLL.
This allows to support other types of Alpha PLL without addition of new flag and variable in structures of clk_alpha_pll.h. Also, we don’t have to add operation for each Alpha PLL’s and export them.
In future, we can get rid of most of the flags like following
struct clk_alpha_pll {
#define SUPPORTS_OFFLINE_REQ BIT(0)
#define SUPPORTS_16BIT_ALPHA BIT(1)
#define SUPPORTS_FSM_MODE BIT(2)
u8 flags;
};
struct clk_alpha_pll_postdiv {
u8 width;
};Since all the above properties will be always same for different instances of same type of Alpha PLL’s.
--- drivers/clk/qcom/clk-alpha-pll.c | 231 ++++++++++++++++++++++++++++++++------- drivers/clk/qcom/clk-alpha-pll.h | 10 ++ 2 files changed, 200 insertions(+), 41 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +190 -41
@@ -35,25 +35,12 @@# define PLL_ACTIVE_FLAG BIT(30)# define PLL_LOCK_DET BIT(31) -#define PLL_L_VAL 0x04 -#define PLL_ALPHA_VAL 0x08 -#define PLL_ALPHA_VAL_U 0x0c - -#define PLL_USER_CTL 0x10# define PLL_POST_DIV_SHIFT 8# define PLL_POST_DIV_MASK 0xf# define PLL_ALPHA_EN BIT(24)# define PLL_VCO_SHIFT 20# define PLL_VCO_MASK 0x3 -#define PLL_USER_CTL_U 0x14 - -#define PLL_CONFIG_CTL 0x18 -#define PLL_CONFIG_CTL_U 0x20 -#define PLL_TEST_CTL 0x1c -#define PLL_TEST_CTL_U 0x20 -#define PLL_STATUS 0x24 -/* * Even though 40 bits are present, use only 32 for ease of calculation. */
@@ -61,12 +48,90 @@#define ALPHA_BITWIDTH 32#define ALPHA_16BIT_MASK 0xffff +/* Returns the alpha_pll_clk_ops for pll type */ +#define pll_clk_ops (hw) (alpha_pll_props[to_clk_alpha_pll(hw)-> \ + pll_type].ops) + +/* Returns the actual register offset for the reg crossponding to pll type */ +#define pll_reg (type, reg) alpha_pll_props[type].reg_offsets[reg] + +/* Helpers to return the actual register offset */ +#define pll_l (type) pll_reg(type, PLL_L_VAL) +#define pll_alpha (type) pll_reg(type, PLL_ALPHA_VAL) +#define pll_alpha_u (type) pll_reg(type, PLL_ALPHA_VAL_U) +#define pll_user_ctl (type) pll_reg(type, PLL_USER_CTL) +#define pll_user_ctl_u (type) pll_reg(type, PLL_USER_CTL_U) +#define pll_cfg_ctl (type) pll_reg(type, PLL_CONFIG_CTL) +#define pll_test_ctl (type) pll_reg(type, PLL_TEST_CTL) +#define pll_test_ctl_u (type) pll_reg(type, PLL_TEST_CTL_U) +#define pll_status (type) pll_reg(type, PLL_STATUS) +#define pll_cfg_ctl_u (type) pll_reg(type, PLL_CONFIG_CTL_U) +#define to_clk_alpha_pll (_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr)#define to_clk_alpha_pll_postdiv (_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll_postdiv, clkr) +/** +* Contains the index which will be used for mapping with actual +* register offset in Alpha PLL +*/ +enum { +PLL_L_VAL , +PLL_ALPHA_VAL , +PLL_ALPHA_VAL_U , +PLL_USER_CTL , +PLL_USER_CTL_U , +PLL_CONFIG_CTL , +PLL_CONFIG_CTL_U , +PLL_TEST_CTL , +PLL_TEST_CTL_U , +PLL_STATUS , +PLL_MAX_REGS , +}; + +/** +* struct alpha_pll_clk_ops - operations for alpha PLL +* @enable: enable function when HW voting FSM is disabled +* @disable: disable function when HW voting FSM is disabled +* @is_enabled: check whether PLL is enabled when HW voting FSM is disabled +* @hwfsm_enable: check whether PLL is enabled when HW voting FSM is enabled +* @hwfsm_disable: check whether PLL is disabled when HW voting FSM is enabled +* @hwfsm_is_enabled: check whether PLL is enabled when HW voting FSM is enabled +* @recalc_rate: recalculate the rate of PLL by reading mode, L and Alpha Value +* @round_rate: returns the closest supported rate of PLL +* @set_rate: change the rate of this clock by actually programming the mode, L +* and Alpha Value registers +*/ +struct alpha_pll_clk_ops { +int (*enable)(struct clk_hw *hw); +void (*disable)(struct clk_hw *hw); +int (*is_enabled)(struct clk_hw *hw); +int (*hwfsm_enable)(struct clk_hw *hw); +void (*hwfsm_disable)(struct clk_hw *hw); +int (*hwfsm_is_enabled)(struct clk_hw *hw); +unsigned long (*recalc_rate)(struct clk_hw *hw, +unsigned long parent_rate); +long (*round_rate)(struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate); +int (*set_rate)(struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate); +}; + +/** +* struct alpha_pll_props - contains the various properties which +* will be fixed for PLL type. +* @reg_offsets: register offsets mapping array +* @ops: clock operations for alpha PLL +*/ +struct alpha_pll_props { +u8 reg_offsets[PLL_MAX_REGS ]; +struct alpha_pll_clk_ops ops; +}; + +static const struct alpha_pll_props alpha_pll_props[]; +static int wait_for_pll (struct clk_alpha_pll *pll,u32 mask,bool inverse,const char *action) {
@@ -112,11 +177,13 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, {u32 val, mask;u32 off = pll->offset; +u8 type = pll->pll_type; -regmap_write (regmap, off +PLL_L_VAL , config->l); -regmap_write (regmap, off +PLL_ALPHA_VAL , config->alpha); -regmap_write (regmap, off +PLL_CONFIG_CTL , config->config_ctl_val); -regmap_write (regmap, off +PLL_CONFIG_CTL_U , config->config_ctl_hi_val); +regmap_write (regmap, off +pll_l (type), config->l); +regmap_write (regmap, off +pll_alpha (type), config->alpha); +regmap_write (regmap, off +pll_cfg_ctl (type), config->config_ctl_val); +regmap_write (regmap, off +pll_cfg_ctl_u (type), + config->config_ctl_hi_val); val = config->main_output_mask; val |= config->aux_output_mask;
@@ -134,13 +201,13 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, mask |= config->post_div_mask; mask |= config->vco_mask; -regmap_update_bits (regmap, off +PLL_USER_CTL , mask, val); +regmap_update_bits (regmap, off +pll_user_ctl (type), mask, val);if (pll->flags &SUPPORTS_FSM_MODE )qcom_pll_set_fsm_mode (regmap, off,6 ,0 ); } -static int clk_alpha_pll_hwfsm_enable (struct clk_hw *hw) +static int alpha_pll_default_hwfsm_enable (struct clk_hw *hw) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);int ret;
@@ -165,7 +232,7 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)return wait_for_pll_enable_active (pll); } -static void clk_alpha_pll_hwfsm_disable (struct clk_hw *hw) +static void alpha_pll_default_hwfsm_disable (struct clk_hw *hw) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);int ret;
@@ -208,17 +275,17 @@ static int pll_is_enabled(struct clk_hw *hw, u32 mask)return !!(val & mask); } -static int clk_alpha_pll_hwfsm_is_enabled (struct clk_hw *hw) +static int alpha_pll_default_hwfsm_is_enabled (struct clk_hw *hw) {return pll_is_enabled (hw,PLL_ACTIVE_FLAG ); } -static int clk_alpha_pll_is_enabled (struct clk_hw *hw) +static int alpha_pll_default_is_enabled (struct clk_hw *hw) {return pll_is_enabled (hw,PLL_LOCK_DET ); } -static int clk_alpha_pll_enable (struct clk_hw *hw) +static int alpha_pll_default_enable (struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);
@@ -270,7 +337,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)return ret; } -static void clk_alpha_pll_disable (struct clk_hw *hw) +static void alpha_pll_default_disable (struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);
@@ -342,22 +409,23 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a) }static unsigned long -clk_alpha_pll_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) +alpha_pll_default_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) {u32 l, low, high, ctl;u64 a =0 , prate = parent_rate;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);u32 off = pll->offset; +u8 type = pll->pll_type; -regmap_read (pll->clkr.regmap, off +PLL_L_VAL , &l); +regmap_read (pll->clkr.regmap, off +pll_l (type), &l); -regmap_read (pll->clkr.regmap, off +PLL_USER_CTL , &ctl); +regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl);if (ctl &PLL_ALPHA_EN ) { -regmap_read (pll->clkr.regmap, off +PLL_ALPHA_VAL , &low); +regmap_read (pll->clkr.regmap, off +pll_alpha (type), &low);if (pll->flags &SUPPORTS_16BIT_ALPHA ) { a = low &ALPHA_16BIT_MASK ; }else { -regmap_read (pll->clkr.regmap, off +PLL_ALPHA_VAL_U , +regmap_read (pll->clkr.regmap, off +pll_alpha_u (type), &high); a = (u64 )high <<32 | low; a >>=ALPHA_REG_BITWIDTH -ALPHA_BITWIDTH ;
@@ -367,12 +435,13 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)return alpha_pll_calc_rate (prate, l, a); } -static int clk_alpha_pll_set_rate (struct clk_hw *hw,unsigned long rate, -unsigned long prate) +static int alpha_pll_default_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);const struct pll_vco *vco;u32 l, off = pll->offset; +u8 type = pll->pll_type;u64 a; rate =alpha_pll_round_rate (rate, prate, &l, &a);
@@ -382,28 +451,29 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,return -EINVAL ; } -regmap_write (pll->clkr.regmap, off +PLL_L_VAL , l); +regmap_write (pll->clkr.regmap, off +pll_l (type), l);if (pll->flags &SUPPORTS_16BIT_ALPHA ) { -regmap_write (pll->clkr.regmap, off +PLL_ALPHA_VAL , +regmap_write (pll->clkr.regmap, off +pll_alpha (type), a &ALPHA_16BIT_MASK ); }else { a <<= (ALPHA_REG_BITWIDTH -ALPHA_BITWIDTH ); -regmap_write (pll->clkr.regmap, off +PLL_ALPHA_VAL_U , a >>32 ); +regmap_write (pll->clkr.regmap, off +pll_alpha_u (type), + a >>32 ); } -regmap_update_bits (pll->clkr.regmap, off +PLL_USER_CTL , +regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type),PLL_VCO_MASK <<PLL_VCO_SHIFT , vco->val <<PLL_VCO_SHIFT ); -regmap_update_bits (pll->clkr.regmap, off +PLL_USER_CTL ,PLL_ALPHA_EN , -PLL_ALPHA_EN ); +regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +PLL_ALPHA_EN ,PLL_ALPHA_EN );return 0 ; } -static long clk_alpha_pll_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *prate) +static long alpha_pll_default_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);u32 l;
@@ -420,6 +490,54 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,return clamp (rate, min_freq, max_freq); } +static int clk_alpha_pll_enable (struct clk_hw *hw) +{ +return pll_clk_ops (hw).enable (hw); +} + +static void clk_alpha_pll_disable (struct clk_hw *hw) +{ +pll_clk_ops (hw).disable (hw); +} + +static int clk_alpha_pll_is_enabled (struct clk_hw *hw) +{ +return pll_clk_ops (hw).is_enabled (hw); +} + +static unsigned long +clk_alpha_pll_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) +{ +return pll_clk_ops (hw).recalc_rate (hw, parent_rate); +} + +static long clk_alpha_pll_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) +{ +return pll_clk_ops (hw).round_rate (hw, rate, prate); +} + +static int clk_alpha_pll_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long prate) +{ +return pll_clk_ops (hw).set_rate (hw, rate, prate); +} + +static int clk_alpha_pll_hwfsm_enable (struct clk_hw *hw) +{ +return pll_clk_ops (hw).hwfsm_enable (hw); +} + +static void clk_alpha_pll_hwfsm_disable (struct clk_hw *hw) +{ +pll_clk_ops (hw).hwfsm_disable (hw); +} + +static int clk_alpha_pll_hwfsm_is_enabled (struct clk_hw *hw) +{ +return pll_clk_ops (hw).hwfsm_is_enabled (hw); +} +const struct clk_ops clk_alpha_pll_ops = { .enable = clk_alpha_pll_enable, .disable = clk_alpha_pll_disable,
@@ -446,7 +564,8 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,struct clk_alpha_pll_postdiv *pll =to_clk_alpha_pll_postdiv (hw);u32 ctl; -regmap_read (pll->clkr.regmap, pll->offset +PLL_USER_CTL , &ctl); +regmap_read (pll->clkr.regmap, pll->offset +pll_user_ctl (pll->pll_type), + &ctl); ctl >>=PLL_POST_DIV_SHIFT ; ctl &=PLL_POST_DIV_MASK ;
@@ -482,7 +601,8 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,/* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */ div =DIV_ROUND_UP_ULL ((u64 )parent_rate, rate) -1 ; -return regmap_update_bits (pll->clkr.regmap, pll->offset +PLL_USER_CTL , +return regmap_update_bits (pll->clkr.regmap, pll->offset + +pll_user_ctl (pll->pll_type),PLL_POST_DIV_MASK <<PLL_POST_DIV_SHIFT , div <<PLL_POST_DIV_SHIFT ); }
@@ -493,3 +613,32 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, .set_rate = clk_alpha_pll_postdiv_set_rate, };EXPORT_SYMBOL_GPL (clk_alpha_pll_postdiv_ops); + +/* Contains actual property values for different PLL types */ +static const struct +alpha_pll_props alpha_pll_props[CLK_ALPHA_PLL_TYPE_MAX ] = { + [CLK_ALPHA_PLL_TYPE_DEFAULT ] = { + .reg_offsets = { + [PLL_L_VAL ] =0x04 , + [PLL_ALPHA_VAL ] =0x08 , + [PLL_ALPHA_VAL_U ] =0x0c , + [PLL_USER_CTL ] =0x10 , + [PLL_USER_CTL_U ] =0x14 , + [PLL_CONFIG_CTL ] =0x18 , + [PLL_TEST_CTL ] =0x1c , + [PLL_TEST_CTL_U ] =0x20 , + [PLL_STATUS ] =0x24 , + }, + .ops = { + .enable = alpha_pll_default_enable, + .disable = alpha_pll_default_disable, + .is_enabled = alpha_pll_default_is_enabled, + .hwfsm_enable = alpha_pll_default_hwfsm_enable, + .hwfsm_disable = alpha_pll_default_hwfsm_disable, + .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, + .recalc_rate = alpha_pll_default_recalc_rate, + .round_rate = alpha_pll_default_round_rate, + .set_rate = alpha_pll_default_set_rate, + }, + }, +};
drivers/clk/qcom/clk-alpha-pll.h +10 -0
@@ -17,6 +17,12 @@#include <linux/clk-provider.h> #include "clk-regmap.h" +/* Alpha PLL types */ +enum { +CLK_ALPHA_PLL_TYPE_DEFAULT , +CLK_ALPHA_PLL_TYPE_MAX , +}; +struct pll_vco {unsigned long min_freq;unsigned long max_freq;
@@ -27,6 +33,7 @@ struct pll_vco {* struct clk_alpha_pll - phase locked loop (PLL) * @offset: base address of registers * @vco_table: array of VCO settings +* @pll_type: alpha pll type * @clkr: regmap clock handle */ struct clk_alpha_pll {
@@ -38,6 +45,7 @@ struct clk_alpha_pll {#define SUPPORTS_16BIT_ALPHA BIT(1)#define SUPPORTS_FSM_MODE BIT(2)u8 flags; +u8 pll_type;struct clk_regmap clkr; };
@@ -45,11 +53,13 @@ struct clk_alpha_pll {/** * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider * @offset: base address of registers +* @pll_type: alpha pll type * @width: width of post-divider * @clkr: regmap clock handle */ struct clk_alpha_pll_postdiv {u32 offset; +u8 pll_type;u8 width;struct clk_regmap clkr;
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 03/13] clk: qcom: support for alpha pll properties
Quoted 36 lines · Abhishek Sahu
Alpha PLL is a generic name used for QCOM PLL’s which uses L and Alpha values for configuring the integer and fractional part. QCOM SoC’s use different types of Alpha PLL’s for which basic software configuration part is common with following differences.
1. All These PLL’s will have same basic registers like
PLL_MODE,L_VAL,ALPHA_VALbut some of the register offsets are different in each PLL type.
2. PLL dynamic programming sequence will be different in some of the Alpha PLL’s
3. Some of the PLL won’t have 64 bit config control, 64 bit user control, VCO configuration etc.Now, this patch adds the Alpha PLL type in clock node and adds alpha PLL properties structure inside
clk-alpha-pll.c. This PLL property will contain everything including register offsets, clock operations and other properties since all these properties will be fixed for Alpha PLL.This allows to support other types of Alpha PLL without addition of new flag and variable in structures of
clk_alpha_pll.h. Also, we don’t have to add operation for each Alpha PLL’s and export them.In future, we can get rid of most of the flags like following
struct clk_alpha_pll { #define SUPPORTS_OFFLINE_REQ BIT(0) #define SUPPORTS_16BIT_ALPHA BIT(1) #define SUPPORTS_FSM_MODE BIT(2) u8 flags; }; struct clk_alpha_pll_postdiv { u8 width; };
Quoted 5 lines
Since all the above properties will be always same for different instances of same type of Alpha PLL’s.
Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 4/13 clk: qcom: fix 16 bit alpha support calculation
In reply to Abhishek SahuThe alpha value calculation function has been written for 40 bit alpha which is not coming properly for 16 bit
1. Alpha value is being calculated on the basis of ALPHA_BITWIDTH to make the computation easy for 40 bit alpha. After calculating the 32 bit alpha, It is being converted to 40 bit alpha by making making lower bits zero. But if actual alpha register width is less than ALPHA_BITWIDTH, then the actual width can be used for calculation
2. During 40 bit alpha pll set rate, the lower alpha register is not being configured
Now the changes have been made to calculate the rate and register values from alpha_width instead hardcoding it so that it can work for all the cases.
--- drivers/clk/qcom/clk-alpha-pll.c | 55 ++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +33 -22
@@ -45,8 +45,12 @@* Even though 40 bits are present, use only 32 for ease of calculation. */ #define ALPHA_REG_BITWIDTH 40 +#define ALPHA_REG_16BIT_WIDTH 16#define ALPHA_BITWIDTH 32 -#define ALPHA_16BIT_MASK 0xffff + +/* Returns the Alpha register width for pll */ +#define pll_alpha_width (pll) (pll->flags & SUPPORTS_16BIT_ALPHA ? \ + ALPHA_REG_16BIT_WIDTH : ALPHA_REG_BITWIDTH)/* Returns the alpha_pll_clk_ops for pll type */ #define pll_clk_ops (hw) (alpha_pll_props[to_clk_alpha_pll(hw)-> \
@@ -364,13 +368,16 @@ static void alpha_pll_default_disable(struct clk_hw *hw)regmap_update_bits (pll->clkr.regmap, off, mask,0 ); } -static unsigned long alpha_pll_calc_rate (u64 prate,u32 l,u32 a) +static unsigned long +alpha_pll_calc_rate (u64 prate,u32 l,u32 a,u32 alpha_width) { -return (prate * l) + ((prate * a) >>ALPHA_BITWIDTH ); +return (prate * l) + ((prate * a) >> + (alpha_width <ALPHA_BITWIDTH ? alpha_width :ALPHA_BITWIDTH )); }static unsigned long -alpha_pll_round_rate (unsigned long rate,unsigned long prate,u32 *l,u64 *a) +alpha_pll_round_rate (unsigned long rate,unsigned long prate,u32 *l,u64 *a, +u32 alpha_width) {u64 remainder;u64 quotient;
@@ -385,14 +392,16 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a) }/* Upper ALPHA_BITWIDTH bits of Alpha */ - quotient = remainder <<ALPHA_BITWIDTH ; + quotient = remainder << (alpha_width <ALPHA_BITWIDTH ? + alpha_width :ALPHA_BITWIDTH ); + remainder =do_div (quotient, prate);if (remainder) quotient++; *a = quotient; -return alpha_pll_calc_rate (prate, *l, *a); +return alpha_pll_calc_rate (prate, *l, *a, alpha_width); } static const struct pll_vco *
@@ -414,7 +423,7 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)u32 l, low, high, ctl;u64 a =0 , prate = parent_rate;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 off = pll->offset; +u32 off = pll->offset, alpha_width =pll_alpha_width (pll);u8 type = pll->pll_type;regmap_read (pll->clkr.regmap, off +pll_l (type), &l);
@@ -422,17 +431,19 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl);if (ctl &PLL_ALPHA_EN ) {regmap_read (pll->clkr.regmap, off +pll_alpha (type), &low); -if (pll->flags &SUPPORTS_16BIT_ALPHA ) { - a = low &ALPHA_16BIT_MASK ; - }else { +if (alpha_width >32 ) {regmap_read (pll->clkr.regmap, off +pll_alpha_u (type), &high); a = (u64 )high <<32 | low; - a >>=ALPHA_REG_BITWIDTH -ALPHA_BITWIDTH ; + }else { + a = low &GENMASK (alpha_width -1 ,0 ); } + +if (alpha_width >ALPHA_BITWIDTH ) + a >>= alpha_width -ALPHA_BITWIDTH ; } -return alpha_pll_calc_rate (prate, l, a); +return alpha_pll_calc_rate (prate, l, a, alpha_width); } static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -440,11 +451,11 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate, {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);const struct pll_vco *vco; -u32 l, off = pll->offset; +u32 l, off = pll->offset, alpha_width =pll_alpha_width (pll);u8 type = pll->pll_type;u64 a; - rate =alpha_pll_round_rate (rate, prate, &l, &a); + rate =alpha_pll_round_rate (rate, prate, &l, &a, alpha_width); vco =alpha_pll_find_vco (pll, rate);if (!vco) {pr_err ("alpha pll not in a valid vco range\n" );
@@ -453,14 +464,14 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate,regmap_write (pll->clkr.regmap, off +pll_l (type), l); -if (pll->flags &SUPPORTS_16BIT_ALPHA ) { -regmap_write (pll->clkr.regmap, off +pll_alpha (type), - a &ALPHA_16BIT_MASK ); - }else { - a <<= (ALPHA_REG_BITWIDTH -ALPHA_BITWIDTH ); +if (alpha_width >ALPHA_BITWIDTH ) + a <<= alpha_width -ALPHA_BITWIDTH ; + +if (alpha_width >32 )regmap_write (pll->clkr.regmap, off +pll_alpha_u (type), a >>32 ); - } + +regmap_write (pll->clkr.regmap, off +pll_alpha (type), a); regmap_update_bits(pll->clkr.regmap, off + pll_user_ctl(type), PLL_VCO_MASK << PLL_VCO_SHIFT,
@@ -476,11 +487,11 @@ static long alpha_pll_default_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 l; +u32 l, alpha_width =pll_alpha_width (pll);u64 a;unsigned long min_freq, max_freq; - rate =alpha_pll_round_rate (rate, *prate, &l, &a); + rate =alpha_pll_round_rate (rate, *prate, &l, &a, alpha_width);if (alpha_pll_find_vco (pll, rate))return rate;
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 04/13] clk: qcom: fix 16 bit alpha support calculation
Quoted 13 lines · Abhishek Sahu
The alpha value calculation function has been written for 40 bit alpha which is not coming properly for 16 bit
1. Alpha value is being calculated on the basis of
ALPHA_BITWIDTHto make the computation easy for 40 bit alpha. After calculating the 32 bit alpha, It is being converted to 40 bit alpha by making making lower bits zero. But if actual alpha register width is less thanALPHA_BITWIDTH, then the actual width can be used for calculation2. During 40 bit alpha pll set rate, the lower alpha register is not being configured
Quoted 6 lines
Now the changes have been made to calculate the rate and register values from
alpha_widthinstead hardcoding it so that it can work for all the cases.Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 5/13 clk: qcom: add and use alpha register width from PLL properties
In reply to Abhishek SahuCurrently SUPPORTS_16BIT_ALPHA flag determines the PLL alpha register width. If this flag is set then the alpha register width is 16 bits otherwise it is 40 bits. The alpha width is always fixed for PLL type so it can be added in PLL properties and clock driver don’t have to specify explicitly.
The SUPPORTS_16BIT_ALPHA flag is unused in the current code so it’s safe to remove this flags.
--- drivers/clk/qcom/clk-alpha-pll.c | 16 ++++++++-------- drivers/clk/qcom/clk-alpha-pll.h | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +8 -8
@@ -44,13 +44,10 @@/* * Even though 40 bits are present, use only 32 for ease of calculation. */ -#define ALPHA_REG_BITWIDTH 40 -#define ALPHA_REG_16BIT_WIDTH 16#define ALPHA_BITWIDTH 32 -/* Returns the Alpha register width for pll */ -#define pll_alpha_width (pll) (pll->flags & SUPPORTS_16BIT_ALPHA ? \ - ALPHA_REG_16BIT_WIDTH : ALPHA_REG_BITWIDTH) +/* Returns the Alpha register width for pll type */ +#define pll_alpha_width (type) (alpha_pll_props[type].alpha_width)/* Returns the alpha_pll_clk_ops for pll type */ #define pll_clk_ops (hw) (alpha_pll_props[to_clk_alpha_pll(hw)-> \
@@ -127,10 +124,12 @@ struct alpha_pll_clk_ops {* struct alpha_pll_props - contains the various properties which * will be fixed for PLL type. * @reg_offsets: register offsets mapping array +* @alpha_width: alpha value width * @ops: clock operations for alpha PLL */ struct alpha_pll_props {u8 reg_offsets[PLL_MAX_REGS ]; +u8 alpha_width;struct alpha_pll_clk_ops ops; };
@@ -423,8 +422,8 @@ static void alpha_pll_default_disable(struct clk_hw *hw)u32 l, low, high, ctl;u64 a =0 , prate = parent_rate;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 off = pll->offset, alpha_width =pll_alpha_width (pll);u8 type = pll->pll_type; +u32 off = pll->offset, alpha_width =pll_alpha_width (type);regmap_read (pll->clkr.regmap, off +pll_l (type), &l);
@@ -451,8 +450,8 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate, {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);const struct pll_vco *vco; -u32 l, off = pll->offset, alpha_width =pll_alpha_width (pll);u8 type = pll->pll_type; +u32 l, off = pll->offset, alpha_width =pll_alpha_width (type);u64 a; rate =alpha_pll_round_rate (rate, prate, &l, &a, alpha_width);
@@ -487,7 +486,7 @@ static long alpha_pll_default_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 l, alpha_width =pll_alpha_width (pll); +u32 l, alpha_width =pll_alpha_width (pll->pll_type);u64 a;unsigned long min_freq, max_freq;
@@ -640,6 +639,7 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, [PLL_TEST_CTL_U] = 0x20, [PLL_STATUS ] =0x24 , }, + .alpha_width = 40, .ops = { .enable = alpha_pll_default_enable, .disable = alpha_pll_default_disable,
drivers/clk/qcom/clk-alpha-pll.h +1 -2
@@ -42,8 +42,7 @@ struct clk_alpha_pll {const struct pll_vco *vco_table;size_t num_vco;#define SUPPORTS_OFFLINE_REQ BIT(0) -#define SUPPORTS_16BIT_ALPHA BIT(1) -#define SUPPORTS_FSM_MODE BIT(2) +#define SUPPORTS_FSM_MODE BIT(1)u8 flags;u8 pll_type;
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 05/13] clk: qcom: add and use alpha register width from PLL properties
Quoted 11 lines · Abhishek Sahu
Currently
SUPPORTS_16BIT_ALPHAflag determines the PLL alpha register width. If this flag is set then the alpha register width is 16 bits otherwise it is 40 bits. The alpha width is always fixed for PLL type so it can be added in PLL properties and clock driver don’t have to specify explicitly.The
SUPPORTS_16BIT_ALPHAflag is unused in the current code so it’s safe to remove this flags.Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 6/13 clk: qcom: flag for 64 bit CONFIG_CTL
In reply to Abhishek SahuSome of the Alpha PLL’s (like Spark, Brammo PLL) do not have CONFIG_CTL_U register. This patch adds the flag in properties for PLL’s which have CONFIG_CTL_U register and checks the same while doing PLL initial configuration.
--- drivers/clk/qcom/clk-alpha-pll.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/clk/qcom/clk-alpha-pll.c +11 -1
@@ -49,6 +49,9 @@/* Returns the Alpha register width for pll type */ #define pll_alpha_width (type) (alpha_pll_props[type].alpha_width) +/* Returns the flags for pll type */ +#define pll_flags (type) (alpha_pll_props[type].flags) +/* Returns the alpha_pll_clk_ops for pll type */ #define pll_clk_ops (hw) (alpha_pll_props[to_clk_alpha_pll(hw)-> \ pll_type].ops)
@@ -130,6 +133,9 @@ struct alpha_pll_clk_ops {struct alpha_pll_props {u8 reg_offsets[PLL_MAX_REGS ];u8 alpha_width; + +#define HAVE_64BIT_CONFIG_CTL BIT(0) +u8 flags;struct alpha_pll_clk_ops ops; };
@@ -180,7 +186,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, {u32 val, mask;u32 off = pll->offset; -u8 type = pll->pll_type; +u8 type = pll->pll_type, flags =pll_flags (type);regmap_write (regmap, off +pll_l (type), config->l);regmap_write (regmap, off +pll_alpha (type), config->alpha);
@@ -188,6 +194,10 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,regmap_write (regmap, off +pll_cfg_ctl_u (type), config->config_ctl_hi_val); +if (flags &HAVE_64BIT_CONFIG_CTL ) +regmap_write (regmap, off +pll_cfg_ctl_u (type), + config->config_ctl_hi_val); + val = config->main_output_mask; val |= config->aux_output_mask; val |= config->aux2_output_mask;
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 06/13] clk: qcom: flag for 64 bit CONFIG_CTL
Quoted 7 lines · Abhishek Sahu
Some of the Alpha PLL’s (like Spark, Brammo PLL) do not have
CONFIG_CTL_Uregister. This patch adds the flag in properties for PLL’s which haveCONFIG_CTL_Uregister and checks the same while doing PLL initial configuration.Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 7/13 clk: qcom: support for alpha mode configuration
In reply to Abhishek SahuThe current configuration does not fully configure PLL alpha mode and values so this patch
1. Configures PLL_ALPHA_VAL_U for PLL which supports 40 bit alpha.
2. Adds alpha enable and alpha mode configuration support.
--- drivers/clk/qcom/clk-alpha-pll.c | 6 ++++++ drivers/clk/qcom/clk-alpha-pll.h | 3 +++ 2 files changed, 9 insertions(+)
drivers/clk/qcom/clk-alpha-pll.c +6 -0
@@ -198,6 +198,10 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,regmap_write (regmap, off +pll_cfg_ctl_u (type), config->config_ctl_hi_val); +if (pll_alpha_width (type) >32 ) +regmap_write (regmap, off +pll_alpha_u (type), + config->alpha_hi); + val = config->main_output_mask; val |= config->aux_output_mask; val |= config->aux2_output_mask;
@@ -205,6 +209,8 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, val |= config->pre_div_val; val |= config->post_div_val; val |= config->vco_val; + val |= config->alpha_en_mask; + val |= config->alpha_mode_mask; mask = config->main_output_mask; mask |= config->aux_output_mask;
drivers/clk/qcom/clk-alpha-pll.h +3 -0
@@ -67,12 +67,15 @@ struct clk_alpha_pll_postdiv {struct alpha_pll_config {u32 l;u32 alpha; +u32 alpha_hi;u32 config_ctl_val;u32 config_ctl_hi_val;u32 main_output_mask;u32 aux_output_mask;u32 aux2_output_mask;u32 early_output_mask; +u32 alpha_en_mask; +u32 alpha_mode_mask;u32 pre_div_val;u32 pre_div_mask;u32 post_div_val;
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 07/13] clk: qcom: support for alpha mode configuration
Quoted 8 lines · Abhishek Sahu
The current configuration does not fully configure PLL alpha mode and values so this patch
1. Configures
PLL_ALPHA_VAL_Ufor PLL which supports 40 bit alpha.
2. Adds alpha enable and alpha mode configuration support.Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 8/13 clk: qcom: support for dynamic updating the PLL
In reply to Abhishek SahuSome of the Alpha PLL’s support dynamic update in which the frequency can be changed dynamically without turning off the PLL.
This dynamic update requires the following sequence
1. Write the desired values to pll_l_val and pll_alpha_val
2. Toggle pll_latch_input from low to high
3. Wait for pll_ack_latch to transition from low to high The new L and alpha values have been latched. It make take some time for the PLL to fully settle with these new values
4. Pull pll_latch_input low
--- drivers/clk/qcom/clk-alpha-pll.c | 69 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +67 -2
@@ -31,7 +31,10 @@# define PLL_VOTE_FSM_ENA BIT(20)# define PLL_FSM_ENA BIT(20)# define PLL_VOTE_FSM_RESET BIT(21) +# define PLL_UPDATE BIT(22) +# define PLL_UPDATE_BYPASS BIT(23)# define PLL_OFFLINE_ACK BIT(28) +# define ALPHA_PLL_ACK_LATCH BIT(29)# define PLL_ACTIVE_FLAG BIT(30)# define PLL_LOCK_DET BIT(31)
@@ -134,7 +137,8 @@ struct alpha_pll_props {u8 reg_offsets[PLL_MAX_REGS ];u8 alpha_width; -#define HAVE_64BIT_CONFIG_CTL BIT(0) +#define HAVE_64BIT_CONFIG_CTL BIT(0) +#define SUPPORTS_DYNAMIC_UPDATE BIT(1)u8 flags;struct alpha_pll_clk_ops ops; };
@@ -181,6 +185,15 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,#define wait_for_pll_offline (pll) \ wait_for_pll(pll, PLL_OFFLINE_ACK, 0, "offline") +#define wait_for_pll_update (pll) \ + wait_for_pll(pll, PLL_UPDATE, 1, "update") + +#define wait_for_pll_update_ack_set (pll) \ + wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 0, "update_ack_set") + +#define wait_for_pll_update_ack_clear (pll) \ + wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear") +void clk_alpha_pll_configure (struct clk_alpha_pll *pll,struct regmap *regmap,const struct alpha_pll_config *config) {
@@ -461,6 +474,54 @@ static void alpha_pll_default_disable(struct clk_hw *hw)return alpha_pll_calc_rate (prate, l, a, alpha_width); } +static int clk_alpha_pll_update_latch (struct clk_alpha_pll *pll) +{ +int ret; +u32 mode, off = pll->offset; + +regmap_read (pll->clkr.regmap, off, &mode); + +/* Latch the input to the PLL */ +regmap_update_bits (pll->clkr.regmap, off,PLL_UPDATE ,PLL_UPDATE ); + +/* Make sure PLL_UPDATE request goes through*/ +mb (); + +/* Wait for 2 reference cycle before checking ACK bit */ +udelay (1 ); + +/* +* PLL will latch the new L, Alpha and freq control word. +* PLL will respond by raising PLL_ACK_LATCH output when new programming +* has been latched in and PLL is being updated. When +* UPDATE_LOGIC_BYPASS bit is not set, PLL_UPDATE will be cleared +* automatically by hardware when PLL_ACK_LATCH is asserted by PLL. +*/ +if (mode &PLL_UPDATE_BYPASS ) { + ret =wait_for_pll_update_ack_set (pll); +if (ret) +return ret; + +regmap_update_bits (pll->clkr.regmap, off,PLL_UPDATE ,0 ); + +/* Make sure PLL_UPDATE request goes through*/ +mb (); + }else { + ret =wait_for_pll_update (pll); +if (ret) +return ret; + } + + ret =wait_for_pll_update_ack_clear (pll); +if (ret) +return ret; + +/* Wait for PLL output to stabilize */ +udelay (10 ); + +return 0 ; +} +static int alpha_pll_default_set_rate (struct clk_hw *hw,unsigned long rate,unsigned long prate) {
@@ -495,7 +556,11 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate,regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type),PLL_ALPHA_EN ,PLL_ALPHA_EN ); -return 0 ; +if (!clk_hw_is_enabled (hw) || + !(pll_flags (type) &SUPPORTS_DYNAMIC_UPDATE )) +return 0 ; + +return clk_alpha_pll_update_latch (pll); } static long alpha_pll_default_round_rate(struct clk_hw *hw, unsigned long rate,
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 08/13] clk: qcom: support for dynamic updating the PLL
Quoted 13 lines · Abhishek Sahu
Some of the Alpha PLL’s support dynamic update in which the frequency can be changed dynamically without turning off the PLL.
This dynamic update requires the following sequence
1. Write the desired values to
pll_l_valandpll_alpha_val
2. Togglepll_latch_inputfrom low to high
3. Wait forpll_ack_latchto transition from low to high The new L and alpha values have been latched. It make take some time for the PLL to fully settle with these new values
4. Pullpll_latch_inputlow
Quoted 4 lines
Signed-off-by Rajendra Nayak <[email protected]>Signed-off-by Taniya Das <[email protected]>Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 9/13 clk: qcom: add flag for VCO operation
In reply to Abhishek SahuSome of the Alpha PLL’s does not have VCO configuration so this patch adds the flag and does not perform VCO operation if this flag is set.
--- drivers/clk/qcom/clk-alpha-pll.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +17 -12
@@ -139,6 +139,7 @@ struct alpha_pll_props {#define HAVE_64BIT_CONFIG_CTL BIT(0)#define SUPPORTS_DYNAMIC_UPDATE BIT(1) +#define SUPPORTS_VCO BIT(2)u8 flags;struct alpha_pll_clk_ops ops; };
@@ -527,15 +528,17 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate, {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);const struct pll_vco *vco; -u8 type = pll->pll_type; +u8 type = pll->pll_type, flags =pll_flags (type);u32 l, off = pll->offset, alpha_width =pll_alpha_width (type);u64 a; rate =alpha_pll_round_rate (rate, prate, &l, &a, alpha_width); - vco =alpha_pll_find_vco (pll, rate); -if (!vco) { -pr_err ("alpha pll not in a valid vco range\n" ); -return -EINVAL ; +if (flags &SUPPORTS_VCO ) { + vco =alpha_pll_find_vco (pll, rate); +if (!vco) { +pr_err ("alpha pll not in a valid vco range\n" ); +return -EINVAL ; + } }regmap_write (pll->clkr.regmap, off +pll_l (type), l);
@@ -549,15 +552,15 @@ static int alpha_pll_default_set_rate(struct clk_hw *hw, unsigned long rate,regmap_write (pll->clkr.regmap, off +pll_alpha (type), a); -regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), -PLL_VCO_MASK <<PLL_VCO_SHIFT , - vco->val <<PLL_VCO_SHIFT ); +if (flags &SUPPORTS_VCO ) +regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +PLL_VCO_MASK <<PLL_VCO_SHIFT , + vco->val <<PLL_VCO_SHIFT );regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type),PLL_ALPHA_EN ,PLL_ALPHA_EN ); -if (!clk_hw_is_enabled (hw) || - !(pll_flags (type) &SUPPORTS_DYNAMIC_UPDATE )) +if (!clk_hw_is_enabled (hw) || !(flags &SUPPORTS_DYNAMIC_UPDATE ))return 0 ;return clk_alpha_pll_update_latch (pll);
@@ -567,12 +570,13 @@ static long alpha_pll_default_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 l, alpha_width =pll_alpha_width (pll->pll_type); +u8 type = pll->pll_type; +u32 l, alpha_width =pll_alpha_width (type);u64 a;unsigned long min_freq, max_freq; rate =alpha_pll_round_rate (rate, *prate, &l, &a, alpha_width); -if (alpha_pll_find_vco (pll, rate)) +if (!(pll_flags (type) &SUPPORTS_VCO ) ||alpha_pll_find_vco (pll, rate))return rate; min_freq = pll->vco_table[0 ].min_freq;
@@ -721,6 +725,7 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, [PLL_STATUS ] =0x24 , }, .alpha_width = 40, + .flags = SUPPORTS_VCO, .ops = { .enable = alpha_pll_default_enable, .disable = alpha_pll_default_disable,
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 09/13] clk: qcom: add flag for VCO operation
Quoted 6 lines · Abhishek Sahu
Some of the Alpha PLL’s does not have VCO configuration so this patch adds the flag and does not perform VCO operation if this flag is set.
Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 10/13 clk: qcom: support for Huayra PLL
In reply to Abhishek SahuFollowing are the major differences in Huayra PLL
1. PLL Alpha Value is 16 bits
2. Depending on alpha_mode, the pll_alpha_val can be treated as M/N value or as a two’s compliment number.
3. Huayra PLL supports PLL dynamic programming. User can change L_VAL, without having to go through the power on sequence.
Since the decoding of alpha val and dynamic programming are completely different from other Alpha PLL’s so this patch made adds separate functions for Huayra PLL.
--- drivers/clk/qcom/clk-alpha-pll.c | 184 +++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 1 + 2 files changed, 185 insertions(+)
drivers/clk/qcom/clk-alpha-pll.c +184 -0
@@ -41,9 +41,17 @@# define PLL_POST_DIV_SHIFT 8# define PLL_POST_DIV_MASK 0xf# define PLL_ALPHA_EN BIT(24) +# define PLL_ALPHA_MODE BIT(25)# define PLL_VCO_SHIFT 20# define PLL_VCO_MASK 0x3 +#define PLL_HUAYRA_M_WIDTH 8 +#define PLL_HUAYRA_M_SHIFT 8 +#define PLL_HUAYRA_M_MASK 0xff +#define PLL_HUAYRA_N_SHIFT 0 +#define PLL_HUAYRA_N_MASK 0xff +#define PLL_HUAYRA_ALPHA_WIDTH 16 +/* * Even though 40 bits are present, use only 32 for ease of calculation. */
@@ -585,6 +593,157 @@ static long alpha_pll_default_round_rate(struct clk_hw *hw, unsigned long rate,return clamp (rate, min_freq, max_freq); } +static unsigned long +alpha_huayra_pll_calc_rate (u64 prate,u32 l,u32 a) +{ +/* +* a contains 16 bit alpha_val in two’s compliment number in the range +* of [-0.5, 0.5). +*/ +if (a >=BIT (PLL_HUAYRA_ALPHA_WIDTH -1 )) + l -=1 ; + +return (prate * l) + (prate * a >>PLL_HUAYRA_ALPHA_WIDTH ); +} + +static unsigned long +alpha_huayra_pll_round_rate (unsigned long rate,unsigned long prate, +u32 *l,u32 *a) +{ +u64 remainder; +u64 quotient; + + quotient = rate; + remainder =do_div (quotient, prate); + *l = quotient; + +if (!remainder) { + *a =0 ; +return rate; + } + + quotient = remainder <<PLL_HUAYRA_ALPHA_WIDTH ; + remainder =do_div (quotient, prate); + +if (remainder) + quotient++; + +/* +* alpha_val should be in two’s compliment number in the range +* of [-0.5, 0.5) so if quotient >= 0.5 then increment the l value +* since alpha value will be subtracted in this case. +*/ +if (quotient >=BIT (PLL_HUAYRA_ALPHA_WIDTH -1 )) + *l +=1 ; + + *a = quotient; +return alpha_huayra_pll_calc_rate (prate, *l, *a); +} + +static unsigned long +alpha_pll_huayra_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) +{ +u64 rate = parent_rate, tmp; +struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +u8 type = pll->pll_type; +u32 l, alpha =0 , ctl, alpha_m, alpha_n, off = pll->offset; + +regmap_read (pll->clkr.regmap, off +pll_l (type), &l); +regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl); + +if (ctl &PLL_ALPHA_EN ) { +regmap_read (pll->clkr.regmap, off +pll_alpha (type), &alpha); +/* +* Depending upon alpha_mode, it can be treated as M/N value or +* as a two’s compliment number. When +* alpha_mode=1 pll_alpha_val<15:8>=M & pll_apla_val<7:0>=N +* Fout=FIN*(L+(M/N)) +* M is a signed number (-128 to 127) and N is unsigned +* (0 to 255). M/N has to be within +/-0.5. +* +* alpha_mode=0, it is a two’s compliment number in the range +* of [-0.5, 0.5). +* Fout=FIN*(L+(alpha_val)/2^16),where alpha_val is +* two’s compliment number. +*/ +if (!(ctl &PLL_ALPHA_MODE )) +return alpha_huayra_pll_calc_rate (rate, l, alpha); + + alpha_m = alpha >>PLL_HUAYRA_M_SHIFT &PLL_HUAYRA_M_MASK ; + alpha_n = alpha >>PLL_HUAYRA_N_SHIFT &PLL_HUAYRA_N_MASK ; + + rate *= l; + tmp = parent_rate; +if (alpha_m >=BIT (PLL_HUAYRA_M_WIDTH -1 )) { + alpha_m =BIT (PLL_HUAYRA_M_WIDTH ) - alpha_m; + tmp *= alpha_m; +do_div (tmp, alpha_n); + rate -= tmp; + }else { + tmp *= alpha_m; +do_div (tmp, alpha_n); + rate += tmp; + } + +return rate; + } + +return alpha_huayra_pll_calc_rate (rate, l, alpha); +} + +static int alpha_pll_huayra_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long prate) +{ +struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +u8 type = pll->pll_type; +u32 l, a, ctl, cur_alpha =0 , off = pll->offset; + + rate =alpha_huayra_pll_round_rate (rate, prate, &l, &a); + +regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl); + +if (ctl &PLL_ALPHA_EN ) +regmap_read (pll->clkr.regmap, off +pll_alpha (type), + &cur_alpha); + +/* +* Huayra PLL supports PLL dynamic programming. User can change L_VAL, +* without having to go through the power on sequence. +*/ +if (clk_hw_is_enabled (hw)) { +if (cur_alpha != a) { +pr_err ("clock needs to be gated %s\n" , +clk_hw_get_name (hw)); +return -EBUSY ; + } + +regmap_write (pll->clkr.regmap, off +pll_l (type), l); +/* Ensure that the write above goes to detect L val change. */ +mb (); +return wait_for_pll_enable_lock (pll); + } + +regmap_write (pll->clkr.regmap, off +pll_l (type), l); +regmap_write (pll->clkr.regmap, off +pll_alpha (type), a); + +if (a ==0 ) +regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +PLL_ALPHA_EN ,0x0 ); +else +regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +PLL_ALPHA_EN |PLL_ALPHA_MODE ,PLL_ALPHA_EN ); + +return 0 ; +} + +static long alpha_pll_huayra_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) +{ +u32 l, a; + +return alpha_huayra_pll_round_rate (rate, *prate, &l, &a); +} +static int clk_alpha_pll_enable (struct clk_hw *hw) {return pll_clk_ops (hw).enable (hw);
@@ -738,4 +897,29 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, .set_rate = alpha_pll_default_set_rate, }, }, + [CLK_ALPHA_PLL_TYPE_HUAYRA ] = { + .reg_offsets = { + [PLL_L_VAL ] =0x04 , + [PLL_ALPHA_VAL ] =0x08 , + [PLL_USER_CTL ] =0x10 , + [PLL_CONFIG_CTL ] =0x14 , + [PLL_CONFIG_CTL_U ] =0x18 , + [PLL_TEST_CTL ] =0x1c , + [PLL_TEST_CTL_U ] =0x20 , + [PLL_STATUS ] =0x24 , + }, + .alpha_width =16 , + .flags =SUPPORTS_DYNAMIC_UPDATE |HAVE_64BIT_CONFIG_CTL , + .ops = { + .enable = alpha_pll_default_enable, + .disable = alpha_pll_default_disable, + .is_enabled = alpha_pll_default_is_enabled, + .hwfsm_enable = alpha_pll_default_hwfsm_enable, + .hwfsm_disable = alpha_pll_default_hwfsm_disable, + .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, + .recalc_rate = alpha_pll_huayra_recalc_rate, + .round_rate = alpha_pll_huayra_round_rate, + .set_rate = alpha_pll_huayra_set_rate, + }, + }, };
drivers/clk/qcom/clk-alpha-pll.h +1 -0
@@ -20,6 +20,7 @@/* Alpha PLL types */ enum {CLK_ALPHA_PLL_TYPE_DEFAULT , +CLK_ALPHA_PLL_TYPE_HUAYRA ,CLK_ALPHA_PLL_TYPE_MAX , };
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 10/13] clk: qcom: support for Huayra PLL
Quoted 8 lines · Abhishek Sahu
Following are the major differences in Huayra PLL
1. PLL Alpha Value is 16 bits
2. Depending onalpha_mode, thepll_alpha_valcan be treated as M/N value or as a two’s compliment number.
3. Huayra PLL supports PLL dynamic programming. User can changeL_VAL, without having to go through the power on sequence.
Quoted 6 lines
Since the decoding of alpha val and dynamic programming are completely different from other Alpha PLL’s so this patch made adds separate functions for Huayra PLL.
Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 11/13 clk: qcom: support for Brammo PLL
In reply to Abhishek Sahu1. Brammo PLL does not allow configuration of VCO
2. Supports the dynamic update in which the frequency can be changed dynamically without turning off the PLL
3. The register offsets are different from normal Alpha PLL
--- drivers/clk/qcom/clk-alpha-pll.c | 24 ++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 1 + 2 files changed, 25 insertions(+)
drivers/clk/qcom/clk-alpha-pll.c +24 -0
@@ -922,4 +922,28 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, .set_rate = alpha_pll_huayra_set_rate, }, }, + [CLK_ALPHA_PLL_TYPE_BRAMMO ] = { + .reg_offsets = { + [PLL_L_VAL ] =0x04 , + [PLL_ALPHA_VAL ] =0x08 , + [PLL_ALPHA_VAL_U ] =0x0c , + [PLL_USER_CTL ] =0x10 , + [PLL_CONFIG_CTL ] =0x18 , + [PLL_TEST_CTL ] =0x1c , + [PLL_STATUS ] =0x24 , + }, + .alpha_width =40 , + .flags =SUPPORTS_DYNAMIC_UPDATE , + .ops = { + .enable = alpha_pll_default_enable, + .disable = alpha_pll_default_disable, + .is_enabled = alpha_pll_default_is_enabled, + .hwfsm_enable = alpha_pll_default_hwfsm_enable, + .hwfsm_disable = alpha_pll_default_hwfsm_disable, + .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, + .recalc_rate = alpha_pll_default_recalc_rate, + .round_rate = alpha_pll_default_round_rate, + .set_rate = alpha_pll_default_set_rate, + }, + }, };
drivers/clk/qcom/clk-alpha-pll.h +1 -0
@@ -21,6 +21,7 @@enum {CLK_ALPHA_PLL_TYPE_DEFAULT ,CLK_ALPHA_PLL_TYPE_HUAYRA , +CLK_ALPHA_PLL_TYPE_BRAMMO ,CLK_ALPHA_PLL_TYPE_MAX , };
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 11/13] clk: qcom: support for Brammo PLL
Quoted 7 lines · Abhishek Sahu
1. Brammo PLL does not allow configuration of VCO
2. Supports the dynamic update in which the frequency can be changed dynamically without turning off the PLL
3. The register offsets are different from normal Alpha PLLSigned-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 12/13 clk: qcom: support for 2 bit PLL post divider
In reply to Abhishek SahuCurrent PLL driver only supports 4 bit PLL post divider so modified the PLL divider operations to support 2 bit PLL post divider.
--- drivers/clk/qcom/clk-alpha-pll.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/clk/qcom/clk-alpha-pll.c +16 -4
@@ -39,7 +39,6 @@# define PLL_LOCK_DET BIT(31)# define PLL_POST_DIV_SHIFT 8 -# define PLL_POST_DIV_MASK 0xf# define PLL_ALPHA_EN BIT(24)# define PLL_ALPHA_MODE BIT(25)# define PLL_VCO_SHIFT 20
@@ -822,7 +821,7 @@ static int clk_alpha_pll_hwfsm_is_enabled(struct clk_hw *hw) &ctl); ctl >>=PLL_POST_DIV_SHIFT ; - ctl &=PLL_POST_DIV_MASK ; + ctl &=BIT (pll->width) -1 ;return parent_rate >>fls (ctl); }
@@ -836,13 +835,26 @@ static int clk_alpha_pll_hwfsm_is_enabled(struct clk_hw *hw) { } }; +static const struct clk_div_table clk_alpha_2bit_div_table[] = { + {0x0 ,1 }, + {0x1 ,2 }, + {0x3 ,4 }, + { } +}; +static long clk_alpha_pll_postdiv_round_rate (struct clk_hw *hw,unsigned long rate,unsigned long *prate) {struct clk_alpha_pll_postdiv *pll =to_clk_alpha_pll_postdiv (hw); +const struct clk_div_table *table; -return divider_round_rate (hw, rate, prate, clk_alpha_div_table, +if (pll->width ==2 ) + table = clk_alpha_2bit_div_table; +else + table = clk_alpha_div_table; + +return divider_round_rate (hw, rate, prate, table, pll->width,CLK_DIVIDER_POWER_OF_TWO ); }
@@ -857,7 +869,7 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,return regmap_update_bits (pll->clkr.regmap, pll->offset +pll_user_ctl (pll->pll_type), -PLL_POST_DIV_MASK <<PLL_POST_DIV_SHIFT , + (BIT (pll->width) -1 ) <<PLL_POST_DIV_SHIFT , div <<PLL_POST_DIV_SHIFT ); }
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 12/13] clk: qcom: support for 2 bit PLL post divider
Quoted 6 lines · Abhishek Sahu
Current PLL driver only supports 4 bit PLL post divider so modified the PLL divider operations to support 2 bit PLL post divider.
Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 13/13 clk: qcom: add read-only alpha pll post divider operations
In reply to Abhishek SahuSome of the divider settings are preconfigured and should not be changed by the clock framework during frequency change. This patch adds the read-only divider operation for QCOM alpha pll post divider which is equivalent to generic divider operations in 'commit 79c6ab509558 ("clk: divider: add CLK_DIVIDER_READ_ONLY flag")'.
--- drivers/clk/qcom/clk-alpha-pll.c | 26 ++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 1 + 2 files changed, 27 insertions(+)
drivers/clk/qcom/clk-alpha-pll.c +26 -0
@@ -858,6 +858,26 @@ static int clk_alpha_pll_hwfsm_is_enabled(struct clk_hw *hw) pll->width, CLK_DIVIDER_POWER_OF_TWO); } +static long +clk_alpha_pll_postdiv_round_ro_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) +{ +struct clk_alpha_pll_postdiv *pll =to_clk_alpha_pll_postdiv (hw); +u32 ctl, div; + +regmap_read (pll->clkr.regmap, pll->offset +pll_user_ctl (pll->pll_type), + &ctl); + + ctl >>=PLL_POST_DIV_SHIFT ; + ctl &=BIT (pll->width) -1 ; + div =1 <<fls (ctl); + +if (clk_hw_get_flags (hw) &CLK_SET_RATE_PARENT ) + *prate =clk_hw_round_rate (clk_hw_get_parent (hw), div * rate); + +return DIV_ROUND_UP_ULL ((u64)*prate, div); +} +static int clk_alpha_pll_postdiv_set_rate (struct clk_hw *hw,unsigned long rate,unsigned long parent_rate) {
@@ -880,6 +900,12 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, };EXPORT_SYMBOL_GPL (clk_alpha_pll_postdiv_ops); +const struct clk_ops clk_alpha_pll_postdiv_ro_ops = { + .round_rate = clk_alpha_pll_postdiv_round_ro_rate, + .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, +}; +EXPORT_SYMBOL_GPL (clk_alpha_pll_postdiv_ro_ops); +/* Contains actual property values for different PLL types */ static const struct alpha_pll_props alpha_pll_props[CLK_ALPHA_PLL_TYPE_MAX ] = {
drivers/clk/qcom/clk-alpha-pll.h +1 -0
@@ -89,6 +89,7 @@ struct alpha_pll_config {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; +extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops;void clk_alpha_pll_configure (struct clk_alpha_pll *pll,struct regmap *regmap,const struct alpha_pll_config *config);
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Stephen Boyd
AppliedRe: [PATCH 13/13] clk: qcom: add read-only alpha pll post divider operations
Quoted 8 lines · Abhishek Sahu
Some of the divider settings are preconfigured and should not be changed by the clock framework during frequency change. This patch adds the read-only divider operation for QCOM alpha pll post divider which is equivalent to generic divider operations in 'commit
79c6ab509558("clk: divider: addCLK_DIVIDER_READ_ONLYflag")'.Signed-off-by Abhishek Sahu <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.
Ok. I took a long look at this today. I rewrote a bunch of stuff. Let me know if anything looks wrong. I'm not really interested in having a type template design that causes us to jump through one clk op to another set of them. I'd rather keep it flatter. I also kept around the macros for the offsets and had it use a register map in each struct instead. Yes, we have to go modify the PLL types to point to the right register offset, but really that's fine and I don't really care. We could have a default fallback when the reg pointer is NULL, but I'm not sure that is useful. The alternative is to make a bunch of new ops structures that passes it down into the final functions but that seemed like more work for the handful of PLLs we have to worry about. You seem to agree here. All told, it got cut down by 100 lines so the patches got smaller.
---8<----
drivers/clk/qcom/clk-alpha-pll.c +165 -331
@@ -20,6 +20,7 @@#include "clk-alpha-pll.h" #include "common.h" +#define PLL_MODE (p) ((p)->offset + 0x0)# define PLL_OUTCTRL BIT(0)# define PLL_BYPASSNL BIT(1)# define PLL_RESET_N BIT(2)
@@ -38,12 +39,67 @@# define PLL_ACTIVE_FLAG BIT(30)# define PLL_LOCK_DET BIT(31) +#define PLL_L_VAL (p) ((p)->offset + (p)->regs[PLL_OFF_L_VAL]) +#define PLL_ALPHA_VAL (p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL]) +#define PLL_ALPHA_VAL_U (p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL_U]) + +#define PLL_USER_CTL (p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL])# define PLL_POST_DIV_SHIFT 8 +# define PLL_POST_DIV_MASK (p) GENMASK((p)->width, 0)# define PLL_ALPHA_EN BIT(24)# define PLL_ALPHA_MODE BIT(25)# define PLL_VCO_SHIFT 20# define PLL_VCO_MASK 0x3 +#define PLL_USER_CTL_U (p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL_U]) + +#define PLL_CONFIG_CTL (p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL]) +#define PLL_CONFIG_CTL_U (p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U]) +#define PLL_TEST_CTL (p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL]) +#define PLL_TEST_CTL_U (p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U]) +#define PLL_STATUS (p) ((p)->offset + (p)->regs[PLL_OFF_STATUS]) + +const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS ] = { + [CLK_ALPHA_PLL_TYPE_DEFAULT ] = { + [PLL_OFF_L_VAL ] =0x04 , + [PLL_OFF_ALPHA_VAL ] =0x08 , + [PLL_OFF_ALPHA_VAL_U ] =0x0c , + [PLL_OFF_USER_CTL ] =0x10 , + [PLL_OFF_USER_CTL_U ] =0x14 , + [PLL_OFF_CONFIG_CTL ] =0x18 , + [PLL_OFF_TEST_CTL ] =0x1c , + [PLL_OFF_TEST_CTL_U ] =0x20 , + [PLL_OFF_STATUS ] =0x24 , + }, + [CLK_ALPHA_PLL_TYPE_HUAYRA ] = { + [PLL_OFF_L_VAL ] =0x04 , + [PLL_OFF_ALPHA_VAL ] =0x08 , + [PLL_OFF_USER_CTL ] =0x10 , + [PLL_OFF_CONFIG_CTL ] =0x14 , + [PLL_OFF_CONFIG_CTL_U ] =0x18 , + [PLL_OFF_TEST_CTL ] =0x1c , + [PLL_OFF_TEST_CTL_U ] =0x20 , + [PLL_OFF_STATUS ] =0x24 , + }, + [CLK_ALPHA_PLL_TYPE_BRAMMO ] = { + [PLL_OFF_L_VAL ] =0x04 , + [PLL_OFF_ALPHA_VAL ] =0x08 , + [PLL_OFF_ALPHA_VAL_U ] =0x0c , + [PLL_OFF_USER_CTL ] =0x10 , + [PLL_OFF_CONFIG_CTL ] =0x18 , + [PLL_OFF_TEST_CTL ] =0x1c , + [PLL_OFF_STATUS ] =0x24 , + }, +}; + +/* +* Even though 40 bits are present, use only 32 for ease of calculation. +*/ +#define ALPHA_REG_BITWIDTH 40 +#define ALPHA_REG_16BIT_WIDTH 16 +#define ALPHA_BITWIDTH 32U +#define ALPHA_SHIFT (w) min(w, ALPHA_BITWIDTH) +#define PLL_HUAYRA_M_WIDTH 8#define PLL_HUAYRA_M_SHIFT 8#define PLL_HUAYRA_M_MASK 0xff
@@ -51,35 +107,11 @@#define PLL_HUAYRA_N_MASK 0xff#define PLL_HUAYRA_ALPHA_WIDTH 16 -/* -* Even though 40 bits are present, use only 32 for ease of calculation. -*/ -#define ALPHA_BITWIDTH 32 - -/* Returns the Alpha register width for pll type */ -#define pll_alpha_width (type) (alpha_pll_props[type].alpha_width) - -/* Returns the flags for pll type */ -#define pll_flags (type) (alpha_pll_props[type].flags) - -/* Returns the alpha_pll_clk_ops for pll type */ -#define pll_clk_ops (hw) (alpha_pll_props[to_clk_alpha_pll(hw)-> \ - pll_type].ops) +#define pll_alpha_width (p) \ + ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \ + ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH) -/* Returns the actual register offset for the reg crossponding to pll type */ -#define pll_reg (type, reg) alpha_pll_props[type].reg_offsets[reg] - -/* Helpers to return the actual register offset */ -#define pll_l (type) pll_reg(type, PLL_L_VAL) -#define pll_alpha (type) pll_reg(type, PLL_ALPHA_VAL) -#define pll_alpha_u (type) pll_reg(type, PLL_ALPHA_VAL_U) -#define pll_user_ctl (type) pll_reg(type, PLL_USER_CTL) -#define pll_user_ctl_u (type) pll_reg(type, PLL_USER_CTL_U) -#define pll_cfg_ctl (type) pll_reg(type, PLL_CONFIG_CTL) -#define pll_test_ctl (type) pll_reg(type, PLL_TEST_CTL) -#define pll_test_ctl_u (type) pll_reg(type, PLL_TEST_CTL_U) -#define pll_status (type) pll_reg(type, PLL_STATUS) -#define pll_cfg_ctl_u (type) pll_reg(type, PLL_CONFIG_CTL_U) +#define pll_has_64bit_config (p) ((PLL_CONFIG_CTL_U(p) - PLL_CONFIG_CTL(p)) == 4)#define to_clk_alpha_pll (_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr)
@@ -87,86 +119,20 @@#define to_clk_alpha_pll_postdiv (_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll_postdiv, clkr) -/** -* Contains the index which will be used for mapping with actual -* register offset in Alpha PLL -*/ -enum { -PLL_L_VAL , -PLL_ALPHA_VAL , -PLL_ALPHA_VAL_U , -PLL_USER_CTL , -PLL_USER_CTL_U , -PLL_CONFIG_CTL , -PLL_CONFIG_CTL_U , -PLL_TEST_CTL , -PLL_TEST_CTL_U , -PLL_STATUS , -PLL_MAX_REGS , -}; - -/** -* struct alpha_pll_clk_ops - operations for alpha PLL -* @enable: enable function when HW voting FSM is disabled -* @disable: disable function when HW voting FSM is disabled -* @is_enabled: check whether PLL is enabled when HW voting FSM is disabled -* @hwfsm_enable: check whether PLL is enabled when HW voting FSM is enabled -* @hwfsm_disable: check whether PLL is disabled when HW voting FSM is enabled -* @hwfsm_is_enabled: check whether PLL is enabled when HW voting FSM is enabled -* @recalc_rate: recalculate the rate of PLL by reading mode, L and Alpha Value -* @round_rate: returns the closest supported rate of PLL -* @set_rate: change the rate of this clock by actually programming the mode, L -* and Alpha Value registers -*/ -struct alpha_pll_clk_ops { -int (*enable)(struct clk_hw *hw); -void (*disable)(struct clk_hw *hw); -int (*is_enabled)(struct clk_hw *hw); -int (*hwfsm_enable)(struct clk_hw *hw); -void (*hwfsm_disable)(struct clk_hw *hw); -int (*hwfsm_is_enabled)(struct clk_hw *hw); -unsigned long (*recalc_rate)(struct clk_hw *hw, -unsigned long parent_rate); -long (*round_rate)(struct clk_hw *hw,unsigned long rate, -unsigned long *parent_rate); -int (*set_rate)(struct clk_hw *hw,unsigned long rate, -unsigned long parent_rate); -}; - -/** -* struct alpha_pll_props - contains the various properties which -* will be fixed for PLL type. -* @reg_offsets: register offsets mapping array -* @alpha_width: alpha value width -* @ops: clock operations for alpha PLL -*/ -struct alpha_pll_props { -u8 reg_offsets[PLL_MAX_REGS ]; -u8 alpha_width; - -#define HAVE_64BIT_CONFIG_CTL BIT(0) -#define SUPPORTS_DYNAMIC_UPDATE BIT(1) -#define SUPPORTS_VCO BIT(2) -u8 flags; -struct alpha_pll_clk_ops ops; -}; - -static const struct alpha_pll_props alpha_pll_props[]; -static int wait_for_pll (struct clk_alpha_pll *pll,u32 mask,bool inverse,const char *action) { -u32 val, off = pll->offset; +u32 val;int count;int ret;const char *name =clk_hw_get_name (&pll->clkr.hw); - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ret;for (count =100 ; count >0 ; count--) { - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ret;if (inverse && !(val & mask))
@@ -206,22 +172,17 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) {u32 val, mask; -u32 off = pll->offset; -u8 type = pll->pll_type, flags =pll_flags (type); -regmap_write (regmap, off +pll_l (type), config->l); -regmap_write (regmap, off +pll_alpha (type), config->alpha); -regmap_write (regmap, off +pll_cfg_ctl (type), config->config_ctl_val); -regmap_write (regmap, off +pll_cfg_ctl_u (type), - config->config_ctl_hi_val); +regmap_write (regmap,PLL_L_VAL (pll), config->l); +regmap_write (regmap,PLL_ALPHA_VAL (pll), config->alpha); +regmap_write (regmap,PLL_CONFIG_CTL (pll), config->config_ctl_val); -if (flags &HAVE_64BIT_CONFIG_CTL ) -regmap_write (regmap, off +pll_cfg_ctl_u (type), +if (pll_has_64bit_config (pll)) +regmap_write (regmap,PLL_CONFIG_CTL_U (pll), config->config_ctl_hi_val); -if (pll_alpha_width (type) >32 ) -regmap_write (regmap, off +pll_alpha_u (type), - config->alpha_hi); +if (pll_alpha_width (pll) >32 ) +regmap_write (regmap,PLL_ALPHA_VAL_U (pll), config->alpha_hi); val = config->main_output_mask; val |= config->aux_output_mask;
@@ -241,19 +202,19 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, mask |= config->post_div_mask; mask |= config->vco_mask; -regmap_update_bits (regmap, off +pll_user_ctl (type), mask, val); +regmap_update_bits (regmap,PLL_USER_CTL (pll), mask, val);if (pll->flags &SUPPORTS_FSM_MODE ) -qcom_pll_set_fsm_mode (regmap, off,6 ,0 ); +qcom_pll_set_fsm_mode (regmap,PLL_MODE (pll),6 ,0 ); } -static int alpha_pll_default_hwfsm_enable (struct clk_hw *hw) +static int clk_alpha_pll_hwfsm_enable (struct clk_hw *hw) { -struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);int ret; -u32 val, off = pll->offset; +struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +u32 val; - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ret;
@@ -262,7 +223,7 @@ static int alpha_pll_default_hwfsm_enable(struct clk_hw *hw)if (pll->flags &SUPPORTS_OFFLINE_REQ ) val &= ~PLL_OFFLINE_REQ ; - ret =regmap_write (pll->clkr.regmap, off, val); + ret =regmap_write (pll->clkr.regmap,PLL_MODE (pll), val);if (ret)return ret;
@@ -272,18 +233,18 @@ static int alpha_pll_default_hwfsm_enable(struct clk_hw *hw)return wait_for_pll_enable_active (pll); } -static void alpha_pll_default_hwfsm_disable (struct clk_hw *hw) +static void clk_alpha_pll_hwfsm_disable (struct clk_hw *hw) { -struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);int ret; -u32 val, off = pll->offset; +struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +u32 val; - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ;if (pll->flags &SUPPORTS_OFFLINE_REQ ) { - ret =regmap_update_bits (pll->clkr.regmap, off, + ret =regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll),PLL_OFFLINE_REQ ,PLL_OFFLINE_REQ );if (ret)return ;
@@ -294,7 +255,7 @@ static void alpha_pll_default_hwfsm_disable(struct clk_hw *hw) }/* Disable hwfsm */ - ret =regmap_update_bits (pll->clkr.regmap, off, + ret =regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll),PLL_FSM_ENA ,0 );if (ret)return ;
@@ -304,35 +265,35 @@ static void alpha_pll_default_hwfsm_disable(struct clk_hw *hw)static int pll_is_enabled (struct clk_hw *hw,u32 mask) { -struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);int ret; -u32 val, off = pll->offset; +struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); +u32 val; - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ret;return !!(val & mask); } -static int alpha_pll_default_hwfsm_is_enabled (struct clk_hw *hw) +static int clk_alpha_pll_hwfsm_is_enabled (struct clk_hw *hw) {return pll_is_enabled (hw,PLL_ACTIVE_FLAG ); } -static int alpha_pll_default_is_enabled (struct clk_hw *hw) +static int clk_alpha_pll_is_enabled (struct clk_hw *hw) {return pll_is_enabled (hw,PLL_LOCK_DET ); } -static int alpha_pll_default_enable (struct clk_hw *hw) +static int clk_alpha_pll_enable (struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 val, mask, off = pll->offset; +u32 val, mask; mask =PLL_OUTCTRL |PLL_RESET_N |PLL_BYPASSNL ; - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ret;
@@ -348,7 +309,7 @@ static int alpha_pll_default_enable(struct clk_hw *hw)if ((val & mask) == mask)return 0 ; - ret =regmap_update_bits (pll->clkr.regmap, off, + ret =regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll),PLL_BYPASSNL ,PLL_BYPASSNL );if (ret)return ret;
@@ -360,7 +321,7 @@ static int alpha_pll_default_enable(struct clk_hw *hw)mb ();udelay (5 ); - ret =regmap_update_bits (pll->clkr.regmap, off, + ret =regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll),PLL_RESET_N ,PLL_RESET_N );if (ret)return ret;
@@ -369,7 +330,7 @@ static int alpha_pll_default_enable(struct clk_hw *hw)if (ret)return ret; - ret =regmap_update_bits (pll->clkr.regmap, off, + ret =regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll),PLL_OUTCTRL ,PLL_OUTCTRL );/* Ensure that the write above goes through before returning. */
@@ -377,13 +338,13 @@ static int alpha_pll_default_enable(struct clk_hw *hw)return ret; } -static void alpha_pll_default_disable (struct clk_hw *hw) +static void clk_alpha_pll_disable (struct clk_hw *hw) {int ret;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u32 val, mask, off = pll->offset; +u32 val, mask; - ret =regmap_read (pll->clkr.regmap, off, &val); + ret =regmap_read (pll->clkr.regmap,PLL_MODE (pll), &val);if (ret)return ;
@@ -394,21 +355,20 @@ static void alpha_pll_default_disable(struct clk_hw *hw) } mask =PLL_OUTCTRL ; -regmap_update_bits (pll->clkr.regmap, off, mask,0 ); +regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll), mask,0 );/* Delay of 2 output clock ticks required until output is disabled */ mb ();udelay (1 ); mask =PLL_RESET_N |PLL_BYPASSNL ; -regmap_update_bits (pll->clkr.regmap, off, mask,0 ); +regmap_update_bits (pll->clkr.regmap,PLL_MODE (pll), mask,0 ); }static unsigned long alpha_pll_calc_rate (u64 prate,u32 l,u32 a,u32 alpha_width) { -return (prate * l) + ((prate * a) >> - (alpha_width <ALPHA_BITWIDTH ? alpha_width :ALPHA_BITWIDTH )); +return (prate * l) + ((prate * a) >>ALPHA_SHIFT (alpha_width)); } static unsigned long
@@ -428,8 +388,7 @@ alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a, }/* Upper ALPHA_BITWIDTH bits of Alpha */ - quotient = remainder << (alpha_width <ALPHA_BITWIDTH ? - alpha_width :ALPHA_BITWIDTH ); + quotient = remainder <<ALPHA_SHIFT (alpha_width); remainder =do_div (quotient, prate);
@@ -454,21 +413,20 @@ alpha_pll_find_vco(const struct clk_alpha_pll *pll, unsigned long rate) }static unsigned long -alpha_pll_default_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) +clk_alpha_pll_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) {u32 l, low, high, ctl;u64 a =0 , prate = parent_rate;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u8 type = pll->pll_type; -u32 off = pll->offset, alpha_width =pll_alpha_width (type); +u32 alpha_width =pll_alpha_width (pll); -regmap_read (pll->clkr.regmap, off +pll_l (type), &l); +regmap_read (pll->clkr.regmap,PLL_L_VAL (pll), &l); -regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl); +regmap_read (pll->clkr.regmap,PLL_USER_CTL (pll), &ctl);if (ctl &PLL_ALPHA_EN ) { -regmap_read (pll->clkr.regmap, off +pll_alpha (type), &low); +regmap_read (pll->clkr.regmap,PLL_ALPHA_VAL (pll), &low);if (alpha_width >32 ) { -regmap_read (pll->clkr.regmap, off +pll_alpha_u (type), +regmap_read (pll->clkr.regmap,PLL_ALPHA_VAL_U (pll), &high); a = (u64 )high <<32 | low; }else {
@@ -492,7 +450,7 @@ static int clk_alpha_pll_update_latch(struct clk_alpha_pll *pll)/* Latch the input to the PLL */ regmap_update_bits (pll->clkr.regmap, off,PLL_UPDATE ,PLL_UPDATE ); -/* Make sure PLL_UPDATE request goes through*/ +/* Make sure PLL_UPDATE request goes through */ mb ();/* Wait for 2 reference cycle before checking ACK bit */
@@ -512,7 +470,7 @@ static int clk_alpha_pll_update_latch(struct clk_alpha_pll *pll)regmap_update_bits (pll->clkr.regmap, off,PLL_UPDATE ,0 ); -/* Make sure PLL_UPDATE request goes through*/ +/* Make sure PLL_UPDATE request goes through */ mb (); }else { ret =wait_for_pll_update (pll);
@@ -530,60 +488,56 @@ static int clk_alpha_pll_update_latch(struct clk_alpha_pll *pll)return 0 ; } -static int alpha_pll_default_set_rate (struct clk_hw *hw,unsigned long rate, -unsigned long prate) +static int clk_alpha_pll_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw);const struct pll_vco *vco; -u8 type = pll->pll_type, flags =pll_flags (type); -u32 l, off = pll->offset, alpha_width =pll_alpha_width (type); +u32 l, alpha_width =pll_alpha_width (pll);u64 a; rate =alpha_pll_round_rate (rate, prate, &l, &a, alpha_width); -if (flags &SUPPORTS_VCO ) { - vco =alpha_pll_find_vco (pll, rate); -if (!vco) { -pr_err ("alpha pll not in a valid vco range\n" ); -return -EINVAL ; - } + vco =alpha_pll_find_vco (pll, rate); +if (pll->vco_table && !vco) { +pr_err ("alpha pll not in a valid vco range\n" ); +return -EINVAL ; } -regmap_write (pll->clkr.regmap, off +pll_l (type), l); +regmap_write (pll->clkr.regmap,PLL_L_VAL (pll), l);if (alpha_width >ALPHA_BITWIDTH ) a <<= alpha_width -ALPHA_BITWIDTH ;if (alpha_width >32 ) -regmap_write (pll->clkr.regmap, off +pll_alpha_u (type), - a >>32 ); +regmap_write (pll->clkr.regmap,PLL_ALPHA_VAL_U (pll), a >>32 ); -regmap_write (pll->clkr.regmap, off +pll_alpha (type), a); +regmap_write (pll->clkr.regmap,PLL_ALPHA_VAL (pll), a); -if (flags &SUPPORTS_VCO ) -regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +if (vco) { +regmap_update_bits (pll->clkr.regmap,PLL_USER_CTL (pll),PLL_VCO_MASK <<PLL_VCO_SHIFT , vco->val <<PLL_VCO_SHIFT ); + } -regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +regmap_update_bits (pll->clkr.regmap,PLL_USER_CTL (pll),PLL_ALPHA_EN ,PLL_ALPHA_EN ); -if (!clk_hw_is_enabled (hw) || !(flags &SUPPORTS_DYNAMIC_UPDATE )) +if (!clk_hw_is_enabled (hw) || !(pll->flags &SUPPORTS_DYNAMIC_UPDATE ))return 0 ;return clk_alpha_pll_update_latch (pll); } -static long alpha_pll_default_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *prate) +static long clk_alpha_pll_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u8 type = pll->pll_type; -u32 l, alpha_width =pll_alpha_width (type); +u32 l, alpha_width =pll_alpha_width (pll);u64 a;unsigned long min_freq, max_freq; rate =alpha_pll_round_rate (rate, *prate, &l, &a, alpha_width); -if (!(pll_flags (type) &SUPPORTS_VCO ) ||alpha_pll_find_vco (pll, rate)) +if (!pll->vco_table ||alpha_pll_find_vco (pll, rate))return rate; min_freq = pll->vco_table[0 ].min_freq;
@@ -644,26 +598,29 @@ alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) {u64 rate = parent_rate, tmp;struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u8 type = pll->pll_type; -u32 l, alpha =0 , ctl, alpha_m, alpha_n, off = pll->offset; +u32 l, alpha =0 , ctl, alpha_m, alpha_n; -regmap_read (pll->clkr.regmap, off +pll_l (type), &l); -regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl); +regmap_read (pll->clkr.regmap,PLL_L_VAL (pll), &l); +regmap_read (pll->clkr.regmap,PLL_USER_CTL (pll), &ctl);if (ctl &PLL_ALPHA_EN ) { -regmap_read (pll->clkr.regmap, off +pll_alpha (type), &alpha); +regmap_read (pll->clkr.regmap,PLL_ALPHA_VAL (pll), &alpha);/* * Depending upon alpha_mode, it can be treated as M/N value or -* as a two’s compliment number. When -* alpha_mode=1 pll_alpha_val<15:8>=M & pll_apla_val<7:0>=N +* as a two’s compliment number. When alpha_mode=1, +* pll_alpha_val<15:8>=M and pll_apla_val<7:0>=N +* * Fout=FIN*(L+(M/N)) +* * M is a signed number (-128 to 127) and N is unsigned * (0 to 255). M/N has to be within +/-0.5. * -* alpha_mode=0, it is a two’s compliment number in the range -* of [-0.5, 0.5). -* Fout=FIN*(L+(alpha_val)/2^16),where alpha_val is -* two’s compliment number. +* When alpha_mode=0, it is a two’s compliment number in the +* range [-0.5, 0.5). +* +* Fout=FIN*(L+(alpha_val)/2^16) +* +* where alpha_val is two’s compliment number. */ if (!(ctl &PLL_ALPHA_MODE ))return alpha_huayra_pll_calc_rate (rate, l, alpha);
@@ -694,16 +651,14 @@ static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) {struct clk_alpha_pll *pll =to_clk_alpha_pll (hw); -u8 type = pll->pll_type; -u32 l, a, ctl, cur_alpha =0 , off = pll->offset; +u32 l, a, ctl, cur_alpha =0 ; rate =alpha_huayra_pll_round_rate (rate, prate, &l, &a); -regmap_read (pll->clkr.regmap, off +pll_user_ctl (type), &ctl); +regmap_read (pll->clkr.regmap,PLL_USER_CTL (pll), &ctl);if (ctl &PLL_ALPHA_EN ) -regmap_read (pll->clkr.regmap, off +pll_alpha (type), - &cur_alpha); +regmap_read (pll->clkr.regmap,PLL_ALPHA_VAL (pll), &cur_alpha);/* * Huayra PLL supports PLL dynamic programming. User can change L_VAL,
@@ -716,20 +671,20 @@ static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate,return -EBUSY ; } -regmap_write (pll->clkr.regmap, off +pll_l (type), l); +regmap_write (pll->clkr.regmap,PLL_L_VAL (pll), l);/* Ensure that the write above goes to detect L val change. */ mb ();return wait_for_pll_enable_lock (pll); } -regmap_write (pll->clkr.regmap, off +pll_l (type), l); -regmap_write (pll->clkr.regmap, off +pll_alpha (type), a); +regmap_write (pll->clkr.regmap,PLL_L_VAL (pll), l); +regmap_write (pll->clkr.regmap,PLL_ALPHA_VAL (pll), a);if (a ==0 ) -regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +regmap_update_bits (pll->clkr.regmap,PLL_USER_CTL (pll),PLL_ALPHA_EN ,0x0 );else -regmap_update_bits (pll->clkr.regmap, off +pll_user_ctl (type), +regmap_update_bits (pll->clkr.regmap,PLL_USER_CTL (pll),PLL_ALPHA_EN |PLL_ALPHA_MODE ,PLL_ALPHA_EN );return 0 ;
@@ -743,54 +698,6 @@ static long alpha_pll_huayra_round_rate(struct clk_hw *hw, unsigned long rate,return alpha_huayra_pll_round_rate (rate, *prate, &l, &a); } -static int clk_alpha_pll_enable (struct clk_hw *hw) -{ -return pll_clk_ops (hw).enable (hw); -} - -static void clk_alpha_pll_disable (struct clk_hw *hw) -{ -pll_clk_ops (hw).disable (hw); -} - -static int clk_alpha_pll_is_enabled (struct clk_hw *hw) -{ -return pll_clk_ops (hw).is_enabled (hw); -} - -static unsigned long -clk_alpha_pll_recalc_rate (struct clk_hw *hw,unsigned long parent_rate) -{ -return pll_clk_ops (hw).recalc_rate (hw, parent_rate); -} - -static long clk_alpha_pll_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *prate) -{ -return pll_clk_ops (hw).round_rate (hw, rate, prate); -} - -static int clk_alpha_pll_set_rate (struct clk_hw *hw,unsigned long rate, -unsigned long prate) -{ -return pll_clk_ops (hw).set_rate (hw, rate, prate); -} - -static int clk_alpha_pll_hwfsm_enable (struct clk_hw *hw) -{ -return pll_clk_ops (hw).hwfsm_enable (hw); -} - -static void clk_alpha_pll_hwfsm_disable (struct clk_hw *hw) -{ -pll_clk_ops (hw).hwfsm_disable (hw); -} - -static int clk_alpha_pll_hwfsm_is_enabled (struct clk_hw *hw) -{ -return pll_clk_ops (hw).hwfsm_is_enabled (hw); -} -const struct clk_ops clk_alpha_pll_ops = { .enable = clk_alpha_pll_enable, .disable = clk_alpha_pll_disable,
@@ -801,6 +708,16 @@ const struct clk_ops clk_alpha_pll_ops = { };EXPORT_SYMBOL_GPL (clk_alpha_pll_ops); +const struct clk_ops clk_alpha_pll_huayra_ops = { + .enable = clk_alpha_pll_enable, + .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = alpha_pll_huayra_recalc_rate, + .round_rate = alpha_pll_huayra_round_rate, + .set_rate = alpha_pll_huayra_set_rate, +}; +EXPORT_SYMBOL_GPL (clk_alpha_pll_huayra_ops); +const struct clk_ops clk_alpha_pll_hwfsm_ops = { .enable = clk_alpha_pll_hwfsm_enable, .disable = clk_alpha_pll_hwfsm_disable,
@@ -817,11 +734,10 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)struct clk_alpha_pll_postdiv *pll =to_clk_alpha_pll_postdiv (hw);u32 ctl; -regmap_read (pll->clkr.regmap, pll->offset +pll_user_ctl (pll->pll_type), - &ctl); +regmap_read (pll->clkr.regmap,PLL_USER_CTL (pll), &ctl); ctl >>=PLL_POST_DIV_SHIFT ; - ctl &=BIT (pll->width) -1 ; + ctl &=PLL_POST_DIV_MASK (pll);return parent_rate >>fls (ctl); }
@@ -865,8 +781,7 @@ clk_alpha_pll_postdiv_round_ro_rate(struct clk_hw *hw, unsigned long rate,struct clk_alpha_pll_postdiv *pll =to_clk_alpha_pll_postdiv (hw);u32 ctl, div; -regmap_read (pll->clkr.regmap, pll->offset +pll_user_ctl (pll->pll_type), - &ctl); +regmap_read (pll->clkr.regmap,PLL_USER_CTL (pll), &ctl); ctl >>=PLL_POST_DIV_SHIFT ; ctl &=BIT (pll->width) -1 ;
@@ -887,9 +802,8 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,/* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */ div =DIV_ROUND_UP_ULL ((u64 )parent_rate, rate) -1 ; -return regmap_update_bits (pll->clkr.regmap, pll->offset + -pll_user_ctl (pll->pll_type), - (BIT (pll->width) -1 ) <<PLL_POST_DIV_SHIFT , +return regmap_update_bits (pll->clkr.regmap,PLL_USER_CTL (pll), +PLL_POST_DIV_MASK (pll) <<PLL_POST_DIV_SHIFT , div <<PLL_POST_DIV_SHIFT ); }
@@ -905,83 +819,3 @@ const struct clk_ops clk_alpha_pll_postdiv_ro_ops = { .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, };EXPORT_SYMBOL_GPL (clk_alpha_pll_postdiv_ro_ops); - -/* Contains actual property values for different PLL types */ -static const struct -alpha_pll_props alpha_pll_props[CLK_ALPHA_PLL_TYPE_MAX ] = { - [CLK_ALPHA_PLL_TYPE_DEFAULT ] = { - .reg_offsets = { - [PLL_L_VAL ] =0x04 , - [PLL_ALPHA_VAL ] =0x08 , - [PLL_ALPHA_VAL_U ] =0x0c , - [PLL_USER_CTL ] =0x10 , - [PLL_USER_CTL_U ] =0x14 , - [PLL_CONFIG_CTL ] =0x18 , - [PLL_TEST_CTL ] =0x1c , - [PLL_TEST_CTL_U ] =0x20 , - [PLL_STATUS ] =0x24 , - }, - .alpha_width =40 , - .flags =SUPPORTS_VCO , - .ops = { - .enable = alpha_pll_default_enable, - .disable = alpha_pll_default_disable, - .is_enabled = alpha_pll_default_is_enabled, - .hwfsm_enable = alpha_pll_default_hwfsm_enable, - .hwfsm_disable = alpha_pll_default_hwfsm_disable, - .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, - .recalc_rate = alpha_pll_default_recalc_rate, - .round_rate = alpha_pll_default_round_rate, - .set_rate = alpha_pll_default_set_rate, - }, - }, - [CLK_ALPHA_PLL_TYPE_HUAYRA ] = { - .reg_offsets = { - [PLL_L_VAL ] =0x04 , - [PLL_ALPHA_VAL ] =0x08 , - [PLL_USER_CTL ] =0x10 , - [PLL_CONFIG_CTL ] =0x14 , - [PLL_CONFIG_CTL_U ] =0x18 , - [PLL_TEST_CTL ] =0x1c , - [PLL_TEST_CTL_U ] =0x20 , - [PLL_STATUS ] =0x24 , - }, - .alpha_width =16 , - .flags =SUPPORTS_DYNAMIC_UPDATE |HAVE_64BIT_CONFIG_CTL , - .ops = { - .enable = alpha_pll_default_enable, - .disable = alpha_pll_default_disable, - .is_enabled = alpha_pll_default_is_enabled, - .hwfsm_enable = alpha_pll_default_hwfsm_enable, - .hwfsm_disable = alpha_pll_default_hwfsm_disable, - .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, - .recalc_rate = alpha_pll_huayra_recalc_rate, - .round_rate = alpha_pll_huayra_round_rate, - .set_rate = alpha_pll_huayra_set_rate, - }, - }, - [CLK_ALPHA_PLL_TYPE_BRAMMO ] = { - .reg_offsets = { - [PLL_L_VAL ] =0x04 , - [PLL_ALPHA_VAL ] =0x08 , - [PLL_ALPHA_VAL_U ] =0x0c , - [PLL_USER_CTL ] =0x10 , - [PLL_CONFIG_CTL ] =0x18 , - [PLL_TEST_CTL ] =0x1c , - [PLL_STATUS ] =0x24 , - }, - .alpha_width =40 , - .flags =SUPPORTS_DYNAMIC_UPDATE , - .ops = { - .enable = alpha_pll_default_enable, - .disable = alpha_pll_default_disable, - .is_enabled = alpha_pll_default_is_enabled, - .hwfsm_enable = alpha_pll_default_hwfsm_enable, - .hwfsm_disable = alpha_pll_default_hwfsm_disable, - .hwfsm_is_enabled = alpha_pll_default_hwfsm_is_enabled, - .recalc_rate = alpha_pll_default_recalc_rate, - .round_rate = alpha_pll_default_round_rate, - .set_rate = alpha_pll_default_set_rate, - }, - }, -};
drivers/clk/qcom/clk-alpha-pll.h +23 -5
@@ -25,6 +25,22 @@ enum { CLK_ALPHA_PLL_TYPE_MAX, }; +enum { +PLL_OFF_L_VAL , +PLL_OFF_ALPHA_VAL , +PLL_OFF_ALPHA_VAL_U , +PLL_OFF_USER_CTL , +PLL_OFF_USER_CTL_U , +PLL_OFF_CONFIG_CTL , +PLL_OFF_CONFIG_CTL_U , +PLL_OFF_TEST_CTL , +PLL_OFF_TEST_CTL_U , +PLL_OFF_STATUS , +PLL_OFF_MAX_REGS +}; + +extern const u8 clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_MAX ][PLL_OFF_MAX_REGS ]; +struct pll_vco {unsigned long min_freq;unsigned long max_freq;
@@ -35,18 +51,19 @@ struct pll_vco {* struct clk_alpha_pll - phase locked loop (PLL) * @offset: base address of registers * @vco_table: array of VCO settings -* @pll_type: alpha pll type +* @regs: alpha pll register map (see @clk_alpha_pll_regs) * @clkr: regmap clock handle */ struct clk_alpha_pll {u32 offset; +const u8 *regs;const struct pll_vco *vco_table;size_t num_vco;#define SUPPORTS_OFFLINE_REQ BIT(0) -#define SUPPORTS_FSM_MODE BIT(1) +#define SUPPORTS_FSM_MODE BIT(2) +#define SUPPORTS_DYNAMIC_UPDATE BIT(3)u8 flags; -u8 pll_type;struct clk_regmap clkr; };
@@ -54,14 +71,14 @@ struct clk_alpha_pll {/** * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider * @offset: base address of registers -* @pll_type: alpha pll type +* @regs: alpha pll register map (see @clk_alpha_pll_regs) * @width: width of post-divider * @clkr: regmap clock handle */ struct clk_alpha_pll_postdiv {u32 offset; -u8 pll_type;u8 width; +const u8 *regs;struct clk_regmap clkr; };
@@ -89,6 +106,7 @@ struct alpha_pll_config {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; +extern const struct clk_ops clk_alpha_pll_huayra_ops;extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
drivers/clk/qcom/gcc-ipq8074.c +2 -0
@@ -52,6 +52,7 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = {static struct clk_alpha_pll gpll0_main = { .offset =0x21000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr = { .enable_reg =0x0b000 , .enable_mask =BIT (0 ),
@@ -82,6 +83,7 @@ static struct clk_fixed_factor gpll0_out_main_div2 = {static struct clk_alpha_pll_postdiv gpll0 = { .offset =0x21000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr.hw.init = &(struct clk_init_data ){ .name ="gpll0" , .parent_names = (const char *[]){
drivers/clk/qcom/gcc-msm8994.c +4 -0
@@ -73,6 +73,7 @@ static struct clk_fixed_factor xo = {static struct clk_alpha_pll gpll0_early = { .offset =0x00000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr = { .enable_reg =0x1480 , .enable_mask =BIT (0 ),
@@ -88,6 +89,7 @@ static struct clk_alpha_pll gpll0_early = {static struct clk_alpha_pll_postdiv gpll0 = { .offset =0x00000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr.hw.init = &(struct clk_init_data ) { .name ="gpll0" ,
@@ -99,6 +101,7 @@ static struct clk_alpha_pll_postdiv gpll0 = {static struct clk_alpha_pll gpll4_early = { .offset =0x1dc0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr = { .enable_reg =0x1480 , .enable_mask =BIT (4 ),
@@ -114,6 +117,7 @@ static struct clk_alpha_pll gpll4_early = {static struct clk_alpha_pll_postdiv gpll4 = { .offset =0x1dc0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr.hw.init = &(struct clk_init_data ) { .name ="gpll4" ,
drivers/clk/qcom/gcc-msm8996.c +4 -0
@@ -227,6 +227,7 @@ static struct clk_fixed_factor xo = {static struct clk_alpha_pll gpll0_early = { .offset =0x00000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr = { .enable_reg =0x52000 , .enable_mask =BIT (0 ),
@@ -252,6 +253,7 @@ static struct clk_fixed_factor gpll0_early_div = {static struct clk_alpha_pll_postdiv gpll0 = { .offset =0x00000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr.hw.init = &(struct clk_init_data ){ .name ="gpll0" , .parent_names = (const char *[]){"gpll0_early" },
@@ -262,6 +264,7 @@ static struct clk_alpha_pll_postdiv gpll0 = {static struct clk_alpha_pll gpll4_early = { .offset =0x77000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr = { .enable_reg =0x52000 , .enable_mask =BIT (4 ),
@@ -276,6 +279,7 @@ static struct clk_alpha_pll gpll4_early = {static struct clk_alpha_pll_postdiv gpll4 = { .offset =0x77000 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .clkr.hw.init = &(struct clk_init_data ){ .name ="gpll4" , .parent_names = (const char *[]){"gpll4_early" },
drivers/clk/qcom/mmcc-msm8996.c +16 -0
@@ -267,6 +267,7 @@ static struct pll_vco mmpll_t_vco[] = {static struct clk_alpha_pll mmpll0_early = { .offset =0x0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_p_vco, .num_vco =ARRAY_SIZE (mmpll_p_vco), .clkr = {
@@ -283,6 +284,7 @@ static struct clk_alpha_pll mmpll0_early = {static struct clk_alpha_pll_postdiv mmpll0 = { .offset =0x0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll0" ,
@@ -295,6 +297,7 @@ static struct clk_alpha_pll_postdiv mmpll0 = {static struct clk_alpha_pll mmpll1_early = { .offset =0x30 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_p_vco, .num_vco =ARRAY_SIZE (mmpll_p_vco), .clkr = {
@@ -311,6 +314,7 @@ static struct clk_alpha_pll mmpll1_early = {static struct clk_alpha_pll_postdiv mmpll1 = { .offset =0x30 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll1" ,
@@ -323,6 +327,7 @@ static struct clk_alpha_pll_postdiv mmpll1 = {static struct clk_alpha_pll mmpll2_early = { .offset =0x4100 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_gfx_vco, .num_vco =ARRAY_SIZE (mmpll_gfx_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -335,6 +340,7 @@ static struct clk_alpha_pll mmpll2_early = {static struct clk_alpha_pll_postdiv mmpll2 = { .offset =0x4100 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll2" ,
@@ -347,6 +353,7 @@ static struct clk_alpha_pll_postdiv mmpll2 = {static struct clk_alpha_pll mmpll3_early = { .offset =0x60 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_p_vco, .num_vco =ARRAY_SIZE (mmpll_p_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -359,6 +366,7 @@ static struct clk_alpha_pll mmpll3_early = {static struct clk_alpha_pll_postdiv mmpll3 = { .offset =0x60 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll3" ,
@@ -371,6 +379,7 @@ static struct clk_alpha_pll_postdiv mmpll3 = {static struct clk_alpha_pll mmpll4_early = { .offset =0x90 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_t_vco, .num_vco =ARRAY_SIZE (mmpll_t_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -383,6 +392,7 @@ static struct clk_alpha_pll mmpll4_early = {static struct clk_alpha_pll_postdiv mmpll4 = { .offset =0x90 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =2 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll4" ,
@@ -395,6 +405,7 @@ static struct clk_alpha_pll_postdiv mmpll4 = {static struct clk_alpha_pll mmpll5_early = { .offset =0xc0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_p_vco, .num_vco =ARRAY_SIZE (mmpll_p_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -407,6 +418,7 @@ static struct clk_alpha_pll mmpll5_early = {static struct clk_alpha_pll_postdiv mmpll5 = { .offset =0xc0 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll5" ,
@@ -419,6 +431,7 @@ static struct clk_alpha_pll_postdiv mmpll5 = {static struct clk_alpha_pll mmpll8_early = { .offset =0x4130 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_gfx_vco, .num_vco =ARRAY_SIZE (mmpll_gfx_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -431,6 +444,7 @@ static struct clk_alpha_pll mmpll8_early = {static struct clk_alpha_pll_postdiv mmpll8 = { .offset =0x4130 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =4 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll8" ,
@@ -443,6 +457,7 @@ static struct clk_alpha_pll_postdiv mmpll8 = {static struct clk_alpha_pll mmpll9_early = { .offset =0x4200 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .vco_table = mmpll_t_vco, .num_vco =ARRAY_SIZE (mmpll_t_vco), .clkr.hw.init = &(struct clk_init_data ){
@@ -455,6 +470,7 @@ static struct clk_alpha_pll mmpll9_early = {static struct clk_alpha_pll_postdiv mmpll9 = { .offset =0x4200 , + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT ], .width =2 , .clkr.hw.init = &(struct clk_init_data ){ .name ="mmpll9" ,
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 13 lines · Stephen Boyd
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.
Quoted 1 line
Ok. I took a long look at this today. I rewrote a bunch of stuff.
Thanks Stephen for reviewing the changes and making the code cleaner. I checked all the code changes and everything looks good. It will work for all of our requirement. I will check with other PLL users also once and then update the patch series with all your suggested code changes after complete testing.
Quoted 8 lines
Let me know if anything looks wrong. I'm not really interested in having a type template design that causes us to jump through one clk op to another set of them. I'd rather keep it flatter. I also kept around the macros for the offsets and had it use a register map in each struct instead. Yes, we have to go modify the PLL types to point to the right register offset, but really that's fine and I don't really care. We could have a default fallback when the reg pointer is NULL, but I'm not sure that is useful.
The main reason for going with type template design is due to different register offsets. Now, if passing the register offsets from pll structure is ok, then we can get rid of this function indirection approach.
Adding NULL check seems to be overhead in all our register macros since these PLL structure will be populated by QCOM clock drivers only and now, we are making this parameter mandatory.
Quoted 6 lines
The alternative is to make a bunch of new ops structures that passes it down into the final functions but that seemed like more work for the handful of PLLs we have to worry about. You seem to agree here. All told, it got cut down by 100 lines so the patches got smaller.
Passing the ops into final function will be lead to again type template design for passing the register offsets. Since, now we have very few PLL's in current upstream code so adding register offsets will be more convenient and maintainable.
Also, now the register offset is coming from our own array so always we can retrieve the PLL type from that. In future, if someone want to have code which requires PLL type then, it can be retrieved from diff of passed pll structure address and array base address.
Thanks,
Abhishek
Quoted 14 lines · Abhishek Sahu
Quoted 13 lines · Stephen Boyd
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.
Quoted 8 lines
Quoted 1 line
Ok. I took a long look at this today. I rewrote a bunch of stuff.
Thanks Stephen for reviewing the changes and making the code cleaner. I checked all the code changes and everything looks good. It will work for all of our requirement. I will check with other PLL users also once and then update the patch series with all your suggested code changes after complete testing.
Ok. Please don't resend. I've pushed out the branch to clk-next, and it can be adjusted if needed, or dropped and rewritten if something is totally busted.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 24 lines · Stephen Boyd
Quoted 14 lines · Abhishek Sahu
Quoted 13 lines · Stephen Boyd
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.Quoted 8 lines
Quoted 1 line
Ok. I took a long look at this today. I rewrote a bunch of stuff.
Thanks Stephen for reviewing the changes and making the code cleaner. I checked all the code changes and everything looks good. It will work for all of our requirement. I will check with other PLL users also once and then update the patch series with all your suggested code changes after complete testing.
Quoted 3 lines
Ok. Please don't resend. I've pushed out the branch to clk-next, and it can be adjusted if needed, or dropped and rewritten if something is totally busted.
Thanks Stephen for your great help and support.
It seems, we are getting the error in the following error with these patches because of missing EXPORT_SYMBOL_GPL for clk_alpha_pll_regs and clk_hw_is_enabled.
ERROR: "clk_alpha_pll_regs" [drivers/clk/qcom/mmcc-msm8996.ko] undefined!
ERROR: "clk_hw_is_enabled" [drivers/clk/qcom/clk-qcom.ko] undefined!
Caused by commits
d1506b749e92 ("clk: qcom: support for alpha pll properties") e66a4d6d0081 ("clk: qcom: support for dynamic updating the PLL") 301803e6013b ("clk: qcom: support Huayra type Alpha PLL")
Quoted 38 lines · Abhishek Sahu
Quoted 24 lines · Stephen Boyd
Quoted 14 lines · Abhishek Sahu
Quoted 13 lines · Stephen Boyd
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.Quoted 8 lines
Quoted 1 line
Ok. I took a long look at this today. I rewrote a bunch of stuff.
Thanks Stephen for reviewing the changes and making the code cleaner. I checked all the code changes and everything looks good. It will work for all of our requirement. I will check with other PLL users also once and then update the patch series with all your suggested code changes after complete testing.
Quoted 3 lines
Ok. Please don't resend. I've pushed out the branch to clk-next, and it can be adjusted if needed, or dropped and rewritten if something is totally busted.
Thanks Stephen for your great help and support.
It seems, we are getting the error in the following error with these patches because of missingEXPORT_SYMBOL_GPLforclk_alpha_pll_regsandclk_hw_is_enabled.ERROR: "
clk_alpha_pll_regs" [drivers/clk/qcom/mmcc-msm8996.ko] undefined!
Quoted 7 lines
ERROR: "
clk_hw_is_enabled" [drivers/clk/qcom/clk-qcom.ko] undefined!Caused by commits
d1506b749e92("clk: qcom: support for alpha pll properties")e66a4d6d0081("clk: qcom: support for dynamic updating the PLL")301803e6013b("clk: qcom: support Huayra type Alpha PLL")
Yep. I'll export the regs and remove the clk_hw_is_enabled() usage. Should be possible to do that inside the ops directly instead of going through the framework for it.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 43 lines · Stephen Boyd
Quoted 42 lines · Abhishek Sahu
Quoted 24 lines · Stephen Boyd
Quoted 14 lines · Abhishek Sahu
Quoted 13 lines · Stephen Boyd
Quoted 11 lines · Abhishek Sahu
This patch series does the miscellaneous changes in QCOM Alpha PLL operation and structure to support other types of Alpha PLL’s.
1. It adds the
pll_typewhich will be used for determining all the properties of Alpha PLL.
2. It adds the support for Brammo and Huayra PLL’s for which the support is not available in existing alpha PLL code.
3. There won’t be any change in existing users of Alpha PLL’s since all the newly added code will be under flag for the default PLL operations.Quoted 8 lines
Quoted 1 line
Ok. I took a long look at this today. I rewrote a bunch of stuff.
Thanks Stephen for reviewing the changes and making the code cleaner. I checked all the code changes and everything looks good. It will work for all of our requirement. I will check with other PLL users also once and then update the patch series with all your suggested code changes after complete testing.
Quoted 3 lines
Ok. Please don't resend. I've pushed out the branch to clk-next, and it can be adjusted if needed, or dropped and rewritten if something is totally busted.
Thanks Stephen for your great help and support.
It seems, we are getting the error in the following error with these patches because of missingEXPORT_SYMBOL_GPLforclk_alpha_pll_regsandclk_hw_is_enabled.ERROR: "
clk_alpha_pll_regs" [drivers/clk/qcom/mmcc-msm8996.ko] undefined!ERROR: "
clk_hw_is_enabled" [drivers/clk/qcom/clk-qcom.ko] undefined!Caused by commits
Quoted 7 lines
Quoted 3 lines
d1506b749e92("clk: qcom: support for alpha pll properties")e66a4d6d0081("clk: qcom: support for dynamic updating the PLL")301803e6013b("clk: qcom: support Huayra type Alpha PLL")Yep. I'll export the regs and remove the
clk_hw_is_enabled()usage. Should be possible to do that inside the ops directly instead of going through the framework for it.
Thanks Stephen for updating the patches :-)
Correct. clk_alpha_pll_is_enabled can do that.