Re: [PATCH v2 1/5] clk: qcom: ipq4019: Added the clock nodes and operations for pll

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06/21, Abhishek Sahu wrote:
> The current ipq4019 clock driver registered the PLL clocks and
> dividers as fixed clock. These fixed clock needs to be removed
> from driver probe function and same need to be registered with
> clock framework. These PLL clocks should be programmed only
> once and the same are being programmed already by the boot
> loader so the set rate operation is not required for these
> clocks. Only the rate can be calculated by clock operations
> in clock driver file so this patch adds the same.
> 
> The PLL takes the reference clock from XO and generates the
> intermediate VCO frequency. This VCO frequency will be divided
> down by different PLL internal dividers. Some of the PLL
> internal dividers are fixed while other are programmable.
> 
> This patch does the following changes.
> 1. Operation for calculating PLL intermediate VCO frequency by
>    reading the reference clock divider and feedback divider from
>    register. Since VCO frequency falls outside the limit of
>    unsigned long for IPQ4019, so this operation will return the
>    VCO frequency in KHz.
> 
> 2. Operation for calculating the internal PLL divider clock
>    frequency. Clock Divider node should give either fixed
>    divider value or divider table(maps the register divider
>    value to actual divider value).
> 
> 3. Adds and registers clock nodes for VCO(APPS DDR PLL and FE
>    PLL) and PLL internal dividers(SDCC, FEPLL 500 Mhz, FEPLL
>    200 Mhz, FEPLL 125 Mhz, FEPLL 125 Mhz with delay,
>    programmable WCSS 2G and 5G).
> 
> 4. Changes the regmap limit from 0x2DFFF to 0x2FFFF for
>    supporting the PLL registers read.
> 
> 5. Changes the fixed clock name to have consistency in all
>    clock names
> 
> Signed-off-by: Abhishek Sahu <absahu@xxxxxxxxxxxxxx>

Thanks for fixing this up, just some minor things to fix.

> diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c
> index 3cd1af0..17ca6d3 100644
> --- a/drivers/clk/qcom/gcc-ipq4019.c
> +++ b/drivers/clk/qcom/gcc-ipq4019.c
> @@ -20,6 +20,11 @@
>  #include <linux/clk-provider.h>
>  #include <linux/regmap.h>
>  #include <linux/reset-controller.h>
> +#include <linux/clk.h>

Is this include used?

> +#include <linux/delay.h>

Is this include used?

> +#include <linux/bitops.h>
> +#include <linux/math64.h>
> +#include <asm/div64.h>

Are both includes needed?

> @@ -40,6 +55,20 @@ enum {
>  	P_DDRPLLAPSS,
>  };
>  
> +struct clk_pll_vco {
> +	u32 fdbkdiv_shift;
> +	u32 fdbkdiv_width;
> +	struct clk_regmap_div cdiv;
> +};
> +
> +struct clk_pll_div {
> +	u32 fixed_div;
> +	const u8 *parent_map;
> +	struct clk_regmap_div cdiv;
> +	const struct clk_div_table *div_table;
> +	const struct freq_tbl *freq_tbl;
> +};
> +
>  static struct parent_map gcc_xo_200_500_map[] = {
>  	{ P_XO, 0 },
>  	{ P_FEPLL200, 1 },
> @@ -48,8 +77,8 @@ static struct parent_map gcc_xo_200_500_map[] = {
>  
>  static const char * const gcc_xo_200_500[] = {
>  	"xo",
> -	"fepll200",
> -	"fepll500",
> +	"gcc_fepll200_clk",
> +	"gcc_fepll500_clk",
>  };
>  
>  static struct parent_map gcc_xo_200_map[] = {
> @@ -59,7 +88,7 @@ static struct parent_map gcc_xo_200_map[] = {
>  
>  static const char * const gcc_xo_200[] = {
>  	"xo",
> -	"fepll200",
> +	"gcc_fepll200_clk",
>  };
>  
>  static struct parent_map gcc_xo_200_spi_map[] = {
> @@ -69,7 +98,7 @@ static struct parent_map gcc_xo_200_spi_map[] = {
>  
>  static const char * const gcc_xo_200_spi[] = {
>  	"xo",
> -	"fepll200",
> +	"gcc_fepll200_clk",
>  };
>  
>  static struct parent_map gcc_xo_sdcc1_500_map[] = {
> @@ -80,8 +109,8 @@ static struct parent_map gcc_xo_sdcc1_500_map[] = {
>  
>  static const char * const gcc_xo_sdcc1_500[] = {
>  	"xo",
> -	"ddrpll",
> -	"fepll500",
> +	"gcc_apps_sdcc_clk",
> +	"gcc_fepll500_clk",
>  };
>  
>  static struct parent_map gcc_xo_wcss2g_map[] = {
> @@ -91,7 +120,7 @@ static struct parent_map gcc_xo_wcss2g_map[] = {
>  
>  static const char * const gcc_xo_wcss2g[] = {
>  	"xo",
> -	"fepllwcss2g",
> +	"gcc_fepllwcss2g_clk",
>  };
>  
>  static struct parent_map gcc_xo_wcss5g_map[] = {
> @@ -101,7 +130,7 @@ static struct parent_map gcc_xo_wcss5g_map[] = {
>  
>  static const char * const gcc_xo_wcss5g[] = {
>  	"xo",
> -	"fepllwcss5g",
> +	"gcc_fepllwcss5g_clk",
>  };
>  
>  static struct parent_map gcc_xo_125_dly_map[] = {
> @@ -111,7 +140,7 @@ static struct parent_map gcc_xo_125_dly_map[] = {
>  
>  static const char * const gcc_xo_125_dly[] = {
>  	"xo",
> -	"fepll125dly",
> +	"gcc_fepll125dly_clk",
>  };
>  
>  static struct parent_map gcc_xo_ddr_500_200_map[] = {
> @@ -123,8 +152,8 @@ static struct parent_map gcc_xo_ddr_500_200_map[] = {
>  
>  static const char * const gcc_xo_ddr_500_200[] = {
>  	"xo",
> -	"fepll200",
> -	"fepll500",
> +	"gcc_fepll200_clk",
> +	"gcc_fepll500_clk",
>  	"ddrpllapss",
>  };

Was it necessary to change all these names? The gcc_ prefix
doesn't seem to be adding much besides noise to this patch.

>  
> @@ -506,7 +535,7 @@ static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
>  	F(25000000,  P_FEPLL500,		1,  1, 20),
>  	F(50000000,  P_FEPLL500,		1,  1, 10),
>  	F(100000000, P_FEPLL500,		1,  1, 5),
> -	F(193000000, P_DDRPLL,		1,  0, 0),
> +	F(190000000, P_DDRPLL,		1,  0, 0),

This looks like an unrelated bug fix.

>  	{ }
>  };
>  
> @@ -658,7 +687,7 @@ static struct clk_branch gcc_crypto_axi_clk = {
>  		.hw.init = &(struct clk_init_data){
>  			.name = "gcc_crypto_axi_clk",
>  			.parent_names = (const char *[]){
> -				"fepll125",
> +				"gcc_fepll125_clk",
>  			},
>  			.num_parents = 1,
>  			.ops = &clk_branch2_ops,
> @@ -675,7 +704,7 @@ static struct clk_branch gcc_crypto_clk = {
>  		.hw.init = &(struct clk_init_data){
>  			.name = "gcc_crypto_clk",
>  			.parent_names = (const char *[]){
> -				"fepll125",
> +				"gcc_fepll125_clk",
>  			},
>  			.num_parents = 1,
>  			.ops = &clk_branch2_ops,
> @@ -709,7 +738,7 @@ static struct clk_branch gcc_imem_axi_clk = {
>  		.hw.init = &(struct clk_init_data){
>  			.name = "gcc_imem_axi_clk",
>  			.parent_names = (const char *[]){
> -				"fepll200",
> +				"gcc_fepll200_clk",
>  			},
>  			.num_parents = 1,
>  			.ops = &clk_branch2_ops,
> @@ -773,7 +802,7 @@ static struct clk_branch gcc_pcie_axi_s_clk = {
>  		.hw.init = &(struct clk_init_data){
>  			.name = "gcc_pcie_axi_s_clk",
>  			.parent_names = (const char *[]){
> -				"fepll200",
> +				"gcc_fepll200_clk",
>  			},
>  			.num_parents = 1,
>  			.ops = &clk_branch2_ops,
> @@ -955,7 +984,7 @@ static struct clk_branch gcc_usb3_master_clk = {
>  		.hw.init = &(struct clk_init_data){
>  			.name = "gcc_usb3_master_clk",
>  			.parent_names = (const char *[]){
> -				"fepll125",
> +				"gcc_fepll125_clk",
>  			},
>  			.num_parents = 1,
>  			.ops = &clk_branch2_ops,
> @@ -1155,6 +1184,238 @@ static struct clk_branch gcc_wcss5g_rtc_clk = {
>  	},
>  };
>  
> +/*
> + * Calculates the rate from parent rate and divider and round the rate
> + * in Mhz. This function takes the parent rate in Khz and returns the
> + * rate in Hz.
> + */
> +static unsigned long clk_calc_divider_rate(unsigned long parent_rate,
> +				unsigned int div)
> +{
> +	u64 rate = parent_rate;
> +
> +	do_div(rate, div);
> +
> +	/*
> +	 * This rate is in KHz so divide with 1000 and multiply with 1000000

s/KHz/kHz/

> +	 * to get the rate in Hz.
> +	 */
> +	do_div(rate, 1000);
> +	rate *= 1000000;
> +
> +	return (unsigned long)rate;

Unnecessary cast, please remove.

> +}
> +
> +/*
> + * Calculates the VCO rate for PLL.
> + * VCO rate value is greater than unsigned long limit. Since this is an
> + * intermediate clock node for actual PLL dividers, so it returns the
> + * rate in Khz. The child nodes will return the value in Hz after its
> + * divide operation.
> + */
> +static unsigned long clk_regmap_vco_recalc_rate(struct clk_hw *hw,
> +						unsigned long parent_rate)
> +{
> +	struct clk_pll_vco *rcg = to_clk_pll_vco(hw);
> +	u32 fdbkdiv, refclkdiv, cdiv;
> +	u64 vco;
> +
> +	regmap_read(rcg->cdiv.clkr.regmap, rcg->cdiv.reg, &cdiv);
> +	refclkdiv = (cdiv >> rcg->cdiv.shift) & (BIT(rcg->cdiv.width) - 1);
> +	fdbkdiv = (cdiv >> rcg->fdbkdiv_shift) & (BIT(rcg->fdbkdiv_width) - 1);
> +
> +	vco = parent_rate;
> +	do_div(vco, refclkdiv);
> +	do_div(vco, 1000);
> +	vco *= 2;
> +	vco *= fdbkdiv;
> +
> +	return (unsigned long)vco;

unnecessary cast.

> +}
> +
> +const struct clk_ops clk_regmap_vco_ops = {

static?

> +	.recalc_rate = clk_regmap_vco_recalc_rate,
> +};
> +
> +static struct clk_pll_vco gcc_apps_ddrpll_vco = {
> +	.fdbkdiv_shift = 16,
> +	.fdbkdiv_width = 8,
> +	.cdiv.reg = 0x2E020,

lowercase hex please.

> +	.cdiv.shift = 24,
> +	.cdiv.width = 5,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_apps_ddrpll_vco",
> +			.parent_names = (const char *[]){
> +				"xo",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_vco_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_pll_vco gcc_fepll_vco = {
> +	.fdbkdiv_shift = 16,
> +	.fdbkdiv_width = 8,
> +	.cdiv.reg = 0x2F020,
> +	.cdiv.shift = 24,
> +	.cdiv.width = 5,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepll_vco",
> +			.parent_names = (const char *[]){
> +				"xo",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_vco_ops,
> +		},
> +	},
> +};
> +
> +/* Calculates the rate for PLL divider.

Style nit, /* goes on its own line

> + * If the divider value is not fixed then it gets the actual divider value
> + * from divider table. Then, it calculate the clock rate by dividing the
> + * parent rate with actual divider value.
> + */
> +static unsigned long clk_regmap_clk_div_recalc_rate(struct clk_hw *hw,
> +					   unsigned long parent_rate)
> +{
> +	struct clk_pll_div *rcg = to_clk_pll_div(hw);
> +	u32 cdiv, pre_div = 1;
> +	const struct clk_div_table *clkt;
> +
> +	if (rcg->fixed_div) {
> +		pre_div = rcg->fixed_div;
> +	} else {
> +		regmap_read(rcg->cdiv.clkr.regmap, rcg->cdiv.reg, &cdiv);
> +		cdiv = (cdiv >> rcg->cdiv.shift) & (BIT(rcg->cdiv.width) - 1);
> +
> +		for (clkt = rcg->div_table; clkt->div; clkt++) {
> +			if (clkt->val == cdiv)
> +				pre_div = clkt->div;
> +		}
> +	}
> +
> +	return clk_calc_divider_rate(parent_rate, pre_div);
> +};
> +
> +const struct clk_ops clk_regmap_clk_div_ops = {

static?

> +	.recalc_rate = clk_regmap_clk_div_recalc_rate,
> +};
> +
> +static struct clk_pll_div gcc_apps_sdcc_clk = {
> +	.fixed_div = 28,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_apps_sdcc_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_apps_ddrpll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_pll_div gcc_fepll125_clk = {
> +	.fixed_div = 32,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepll125_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_pll_div gcc_fepll125dly_clk = {
> +	.fixed_div = 32,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepll125dly_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_pll_div gcc_fepll200_clk = {
> +	.fixed_div = 20,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepll200_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_pll_div gcc_fepll500_clk = {
> +	.fixed_div = 8,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepll500_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +};
> +
> +static const struct clk_div_table fepllwcss_clk_div_table[] = {
> +	{0, 15},
> +	{1, 16},
> +	{2, 18},
> +	{3, 20},

Nitpick: Please add some spaces here

	{ 0, 15 },

> +	{},
> +};
> +
> +static struct clk_pll_div gcc_fepllwcss2g_clk = {
> +	.cdiv.reg = 0x2F020,
> +	.cdiv.shift = 8,
> +	.cdiv.width = 2,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepllwcss2g_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +	.div_table = fepllwcss_clk_div_table
> +};
> +
> +static struct clk_pll_div gcc_fepllwcss5g_clk = {
> +	.cdiv.reg = 0x2F020,
> +	.cdiv.shift = 12,
> +	.cdiv.width = 2,
> +	.cdiv.clkr = {
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_fepllwcss5g_clk",
> +			.parent_names = (const char *[]){
> +				"gcc_fepll_vco",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_regmap_clk_div_ops,
> +		},
> +	},
> +	.div_table = fepllwcss_clk_div_table
> +};
> +
>  static struct clk_regmap *gcc_ipq4019_clocks[] = {
>  	[AUDIO_CLK_SRC] = &audio_clk_src.clkr,
>  	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
> @@ -1215,6 +1476,15 @@ static struct clk_regmap *gcc_ipq4019_clocks[] = {
>  	[GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr,
>  	[GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr,
>  	[GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr,
> +	[GCC_APPS_DDRPLL_VCO] = &gcc_apps_ddrpll_vco.cdiv.clkr,
> +	[GCC_FEPLL_VCO] = &gcc_fepll_vco.cdiv.clkr,
> +	[GCC_SDCC_PLLDIV_CLK] = &gcc_apps_sdcc_clk.cdiv.clkr,
> +	[GCC_FEPLL125_CLK] = &gcc_fepll125_clk.cdiv.clkr,
> +	[GCC_FEPLL125DLY_CLK] = &gcc_fepll125dly_clk.cdiv.clkr,
> +	[GCC_FEPLL200_CLK] = &gcc_fepll200_clk.cdiv.clkr,
> +	[GCC_FEPLL500_CLK] = &gcc_fepll500_clk.cdiv.clkr,
> +	[GCC_FEPLL_WCSS2G_CLK] = &gcc_fepllwcss2g_clk.cdiv.clkr,
> +	[GCC_FEPLL_WCSS5G_CLK] = &gcc_fepllwcss5g_clk.cdiv.clkr,
>  };
>  
>  static const struct qcom_reset_map gcc_ipq4019_resets[] = {
> @@ -1295,7 +1565,7 @@ static const struct regmap_config gcc_ipq4019_regmap_config = {
>  	.reg_bits	= 32,
>  	.reg_stride	= 4,
>  	.val_bits	= 32,
> -	.max_register	= 0x2dfff,
> +	.max_register	= 0x2FFFF,

Lowercase.

>  	.fast_io	= true,
>  };

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe linux-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux