diff mbox series

[v2,2/3] clk: qcom: msm8996-cpu: Add CBF support

Message ID 20220510155940.812565-1-y.oudjana@protonmail.com (mailing list archive)
State Changes Requested, archived
Headers show
Series MSM8996 Coherent Bus Fabric clock support | expand

Commit Message

Yassine Oudjana May 10, 2022, 3:59 p.m. UTC
From: Konrad Dybcio <konrad.dybcio@somainline.org>

Add the required code to support the CBF clock, which is responsible for
core cluster interconnect frequency on msm8996.

Somewhat based on AngeloGioacchino del Regno's work at:
https://github.com/sonyxperiadev/kernel/blob/aosp/LE.UM.2.3.2.r1.4/drivers/clk/qcom/clk-cpu-8996.c

This fixes the issue with booting with all 4 cores enabled.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
Signed-off-by: Yassine Oudjana <yassine.oudjana@gmail.com>
---
 drivers/clk/qcom/clk-cpu-8996.c | 162 +++++++++++++++++++++++++++++++-
 1 file changed, 159 insertions(+), 3 deletions(-)

Comments

Dmitry Baryshkov May 11, 2022, 10:17 a.m. UTC | #1
Hi,

On Tue, 10 May 2022 at 19:05, Yassine Oudjana <yassine.oudjana@gmail.com> wrote:
>
> From: Konrad Dybcio <konrad.dybcio@somainline.org>
>
> Add the required code to support the CBF clock, which is responsible for
> core cluster interconnect frequency on msm8996.
>
> Somewhat based on AngeloGioacchino del Regno's work at:
> https://github.com/sonyxperiadev/kernel/blob/aosp/LE.UM.2.3.2.r1.4/drivers/clk/qcom/clk-cpu-8996.c
>
> This fixes the issue with booting with all 4 cores enabled.
>
> Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
> Signed-off-by: Yassine Oudjana <yassine.oudjana@gmail.com>
> ---
>  drivers/clk/qcom/clk-cpu-8996.c | 162 +++++++++++++++++++++++++++++++-
>  1 file changed, 159 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
> index 4a4fde8dd12d..8afc271f92d0 100644
> --- a/drivers/clk/qcom/clk-cpu-8996.c
> +++ b/drivers/clk/qcom/clk-cpu-8996.c
> @@ -68,10 +68,19 @@ enum _pmux_input {
>         NUM_OF_PMUX_INPUTS
>  };
>
> +enum {
> +       CBF_PLL_INDEX = 1,
> +       CBF_DIV_2_INDEX,
> +       CBF_SAFE_INDEX
> +};
> +
>  #define DIV_2_THRESHOLD                600000000
>  #define PWRCL_REG_OFFSET 0x0
>  #define PERFCL_REG_OFFSET 0x80000
>  #define MUX_OFFSET     0x40
> +#define CBF_REG_OFFSET 0x0
> +#define CBF_PLL_OFFSET 0xf000
> +#define CBF_MUX_OFFSET 0x18
>  #define ALT_PLL_OFFSET 0x100
>  #define SSSCTL_OFFSET 0x160
>
> @@ -98,6 +107,17 @@ static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
>         [PLL_OFF_STATUS] = 0x28,
>  };
>
> +static const u8 cbf_pll_regs[PLL_OFF_MAX_REGS] = {
> +       [PLL_OFF_L_VAL] = 0x08,
> +       [PLL_OFF_ALPHA_VAL] = 0x10,
> +       [PLL_OFF_USER_CTL] = 0x18,
> +       [PLL_OFF_CONFIG_CTL] = 0x20,
> +       [PLL_OFF_CONFIG_CTL_U] = 0x24,
> +       [PLL_OFF_TEST_CTL] = 0x30,
> +       [PLL_OFF_TEST_CTL_U] = 0x34,
> +       [PLL_OFF_STATUS] = 0x28,
> +};
> +
>  /* PLLs */
>
>  static const struct alpha_pll_config hfpll_config = {
> @@ -111,6 +131,17 @@ static const struct alpha_pll_config hfpll_config = {
>         .early_output_mask = BIT(3),
>  };
>
> +static const struct alpha_pll_config cbfpll_config = {
> +       .l = 72,
> +       .config_ctl_val = 0x200d4aa8,
> +       .config_ctl_hi_val = 0x006,
> +       .pre_div_mask = BIT(12),
> +       .post_div_mask = 0x3 << 8,
> +       .post_div_val = 0x1 << 8,
> +       .main_output_mask = BIT(0),
> +       .early_output_mask = BIT(3),
> +};
> +
>  static struct clk_alpha_pll perfcl_pll = {
>         .offset = PERFCL_REG_OFFSET,
>         .regs = prim_pll_regs,
> @@ -135,6 +166,18 @@ static struct clk_alpha_pll pwrcl_pll = {
>         },
>  };
>
> +static struct clk_alpha_pll cbf_pll = {
> +       .offset = CBF_PLL_OFFSET,
> +       .regs = cbf_pll_regs,
> +       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
> +       .clkr.hw.init = &(struct clk_init_data){
> +               .name = "cbf_pll",
> +               .parent_names = (const char *[]){ "xo" },
> +               .num_parents = 1,
> +               .ops = &clk_alpha_pll_huayra_ops,
> +       },
> +};
> +
>  static const struct pll_vco alt_pll_vco_modes[] = {
>         VCO(3,  250000000,  500000000),
>         VCO(2,  500000000,  750000000),
> @@ -194,6 +237,9 @@ struct clk_cpu_8996_mux {
>  static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
>                                void *data);
>
> +static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
> +                              void *data);
> +
>  #define to_clk_cpu_8996_mux_nb(_nb) \
>         container_of(_nb, struct clk_cpu_8996_mux, nb)
>
> @@ -329,6 +375,35 @@ static struct clk_cpu_8996_mux perfcl_pmux = {
>         },
>  };
>
> +static struct clk_cpu_8996_mux cbf_mux = {
> +       .reg = CBF_REG_OFFSET + CBF_MUX_OFFSET,
> +       .shift = 0,
> +       .width = 2,
> +       .pll = &cbf_pll.clkr.hw,
> +       .nb.notifier_call = cbf_clk_notifier_cb,
> +       .clkr.hw.init = &(struct clk_init_data) {
> +               .name = "cbf_mux",
> +               .parent_names = (const char *[]){
> +                       "xo",
> +                       "cbf_pll",
> +                       "cbf_pll_main",
> +               },

parent_data please.

> +               .num_parents = 3,
> +               .ops = &clk_cpu_8996_mux_ops,
> +               /* CPU clock is critical and should never be gated */
> +               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> +       },
> +};
> +
> +static const struct regmap_config cbf_msm8996_regmap_config = {
> +       .reg_bits               = 32,
> +       .reg_stride             = 4,
> +       .val_bits               = 32,
> +       .max_register           = 0x10000,
> +       .fast_io                = true,
> +       .val_format_endian      = REGMAP_ENDIAN_LITTLE,
> +};
> +
>  static const struct regmap_config cpu_msm8996_regmap_config = {
>         .reg_bits               = 32,
>         .reg_stride             = 4,
> @@ -397,6 +472,35 @@ static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
>         return ret;
>  }
>
> +static struct clk_regmap *cbf_msm8996_clks[] = {
> +       &cbf_pll.clkr,
> +       &cbf_mux.clkr,
> +};
> +
> +static int qcom_cbf_clk_msm8996_register_clks(struct device *dev,
> +                                             struct regmap *regmap)
> +{
> +       int ret;
> +
> +       cbf_mux.pll_div_2 = clk_hw_register_fixed_factor(dev, "cbf_pll_main",
> +                                                     "cbf_pll", CLK_SET_RATE_PARENT,
> +                                                     1, 2);
> +       if (IS_ERR(cbf_mux.pll_div_2)) {
> +               dev_err(dev, "Failed to initialize cbf_pll_main\n");
> +               return PTR_ERR(cbf_mux.pll_div_2);
> +       }
> +
> +       ret = devm_clk_register_regmap(dev, cbf_msm8996_clks[0]);
> +       ret = devm_clk_register_regmap(dev, cbf_msm8996_clks[1]);
> +
> +       clk_alpha_pll_configure(&cbf_pll, regmap, &cbfpll_config);
> +       clk_set_rate(cbf_pll.clkr.hw.clk, 614400000);
> +       clk_prepare_enable(cbf_pll.clkr.hw.clk);
> +       clk_notifier_register(cbf_mux.clkr.hw.clk, &cbf_mux.nb);
> +
> +       return ret;
> +}
> +
>  static int qcom_cpu_clk_msm8996_unregister_clks(void)
>  {
>         int ret = 0;
> @@ -409,8 +513,13 @@ static int qcom_cpu_clk_msm8996_unregister_clks(void)
>         if (ret)
>                 return ret;
>
> +       ret = clk_notifier_unregister(cbf_mux.clkr.hw.clk, &cbf_mux.nb);
> +       if (ret)
> +               return ret;
> +
>         clk_hw_unregister(perfcl_smux.pll);
>         clk_hw_unregister(pwrcl_smux.pll);
> +       clk_hw_unregister(cbf_mux.pll);
>
>         return 0;
>  }
> @@ -481,14 +590,48 @@ static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
>         return notifier_from_errno(ret);
>  };
>
> +static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
> +                              void *data)
> +{
> +       struct clk_cpu_8996_mux *cbfclk = to_clk_cpu_8996_mux_nb(nb);
> +       struct clk_notifier_data *cnd = data;
> +       struct clk_hw *parent;
> +       int ret;
> +
> +       switch (event) {
> +       case PRE_RATE_CHANGE:
> +               parent = clk_hw_get_parent_by_index(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
> +               ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
> +
> +               if (cnd->old_rate > DIV_2_THRESHOLD && cnd->new_rate < DIV_2_THRESHOLD)
> +                       ret = clk_set_rate(parent->clk, cnd->old_rate / 2);
> +               break;
> +       case POST_RATE_CHANGE:
> +               if (cnd->new_rate < DIV_2_THRESHOLD)
> +                       ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
> +               else {
> +                       parent = clk_hw_get_parent_by_index(&cbfclk->clkr.hw, CBF_PLL_INDEX);
> +                       ret = clk_set_rate(parent->clk, cnd->new_rate);
> +                       ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_PLL_INDEX);
> +               }
> +               break;
> +       default:
> +               ret = 0;
> +               break;
> +       }
> +
> +       return notifier_from_errno(ret);
> +};
> +
>  static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
>  {
> -       struct regmap *regmap;
> +       struct regmap *regmap, *regmap_cbf;
>         struct clk_hw_onecell_data *data;
>         struct device *dev = &pdev->dev;
> +       static void __iomem *cbf_base;
>         int ret;
>
> -       data = devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
> +       data = devm_kzalloc(dev, struct_size(data, hws, 3), GFP_KERNEL);
>         if (!data)
>                 return -ENOMEM;
>
> @@ -506,9 +649,22 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
>
>         qcom_cpu_clk_msm8996_acd_init(base);
>
> +       cbf_base = devm_platform_ioremap_resource(pdev, 1);
> +       if (IS_ERR(cbf_base))
> +               return PTR_ERR(cbf_base);

So, if the reg1 is not provided, thr driver will error out, breaking
the compatibility with existing dts files.
I'd suggest making reg1 optional (you can add a warning printk
demanding the dts to be updated).

> +       regmap_cbf = devm_regmap_init_mmio(dev, cbf_base, &cbf_msm8996_regmap_config);
> +       if (IS_ERR(regmap_cbf))
> +               return PTR_ERR(regmap_cbf);
> +
> +       ret = qcom_cbf_clk_msm8996_register_clks(dev, regmap_cbf);
> +       if (ret)
> +               return ret;
> +
>         data->hws[0] = &pwrcl_pmux.clkr.hw;
>         data->hws[1] = &perfcl_pmux.clkr.hw;
> -       data->num = 2;
> +       data->hws[2] = &cbf_mux.clkr.hw;
> +       data->num = 3;
>
>         return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
>  }
> --
> 2.36.0
>
diff mbox series

Patch

diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index 4a4fde8dd12d..8afc271f92d0 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -68,10 +68,19 @@  enum _pmux_input {
 	NUM_OF_PMUX_INPUTS
 };
 
+enum {
+	CBF_PLL_INDEX = 1,
+	CBF_DIV_2_INDEX,
+	CBF_SAFE_INDEX
+};
+
 #define DIV_2_THRESHOLD		600000000
 #define PWRCL_REG_OFFSET 0x0
 #define PERFCL_REG_OFFSET 0x80000
 #define MUX_OFFSET	0x40
+#define CBF_REG_OFFSET	0x0
+#define CBF_PLL_OFFSET	0xf000
+#define CBF_MUX_OFFSET 0x18
 #define ALT_PLL_OFFSET	0x100
 #define SSSCTL_OFFSET 0x160
 
@@ -98,6 +107,17 @@  static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
 	[PLL_OFF_STATUS] = 0x28,
 };
 
+static const u8 cbf_pll_regs[PLL_OFF_MAX_REGS] = {
+	[PLL_OFF_L_VAL] = 0x08,
+	[PLL_OFF_ALPHA_VAL] = 0x10,
+	[PLL_OFF_USER_CTL] = 0x18,
+	[PLL_OFF_CONFIG_CTL] = 0x20,
+	[PLL_OFF_CONFIG_CTL_U] = 0x24,
+	[PLL_OFF_TEST_CTL] = 0x30,
+	[PLL_OFF_TEST_CTL_U] = 0x34,
+	[PLL_OFF_STATUS] = 0x28,
+};
+
 /* PLLs */
 
 static const struct alpha_pll_config hfpll_config = {
@@ -111,6 +131,17 @@  static const struct alpha_pll_config hfpll_config = {
 	.early_output_mask = BIT(3),
 };
 
+static const struct alpha_pll_config cbfpll_config = {
+	.l = 72,
+	.config_ctl_val = 0x200d4aa8,
+	.config_ctl_hi_val = 0x006,
+	.pre_div_mask = BIT(12),
+	.post_div_mask = 0x3 << 8,
+	.post_div_val = 0x1 << 8,
+	.main_output_mask = BIT(0),
+	.early_output_mask = BIT(3),
+};
+
 static struct clk_alpha_pll perfcl_pll = {
 	.offset = PERFCL_REG_OFFSET,
 	.regs = prim_pll_regs,
@@ -135,6 +166,18 @@  static struct clk_alpha_pll pwrcl_pll = {
 	},
 };
 
+static struct clk_alpha_pll cbf_pll = {
+	.offset = CBF_PLL_OFFSET,
+	.regs = cbf_pll_regs,
+	.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "cbf_pll",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_huayra_ops,
+	},
+};
+
 static const struct pll_vco alt_pll_vco_modes[] = {
 	VCO(3,  250000000,  500000000),
 	VCO(2,  500000000,  750000000),
@@ -194,6 +237,9 @@  struct clk_cpu_8996_mux {
 static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 			       void *data);
 
+static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+			       void *data);
+
 #define to_clk_cpu_8996_mux_nb(_nb) \
 	container_of(_nb, struct clk_cpu_8996_mux, nb)
 
@@ -329,6 +375,35 @@  static struct clk_cpu_8996_mux perfcl_pmux = {
 	},
 };
 
+static struct clk_cpu_8996_mux cbf_mux = {
+	.reg = CBF_REG_OFFSET + CBF_MUX_OFFSET,
+	.shift = 0,
+	.width = 2,
+	.pll = &cbf_pll.clkr.hw,
+	.nb.notifier_call = cbf_clk_notifier_cb,
+	.clkr.hw.init = &(struct clk_init_data) {
+		.name = "cbf_mux",
+		.parent_names = (const char *[]){
+			"xo",
+			"cbf_pll",
+			"cbf_pll_main",
+		},
+		.num_parents = 3,
+		.ops = &clk_cpu_8996_mux_ops,
+		/* CPU clock is critical and should never be gated */
+		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+	},
+};
+
+static const struct regmap_config cbf_msm8996_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= 0x10000,
+	.fast_io		= true,
+	.val_format_endian	= REGMAP_ENDIAN_LITTLE,
+};
+
 static const struct regmap_config cpu_msm8996_regmap_config = {
 	.reg_bits		= 32,
 	.reg_stride		= 4,
@@ -397,6 +472,35 @@  static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
 	return ret;
 }
 
+static struct clk_regmap *cbf_msm8996_clks[] = {
+	&cbf_pll.clkr,
+	&cbf_mux.clkr,
+};
+
+static int qcom_cbf_clk_msm8996_register_clks(struct device *dev,
+					      struct regmap *regmap)
+{
+	int ret;
+
+	cbf_mux.pll_div_2 = clk_hw_register_fixed_factor(dev, "cbf_pll_main",
+						      "cbf_pll", CLK_SET_RATE_PARENT,
+						      1, 2);
+	if (IS_ERR(cbf_mux.pll_div_2)) {
+		dev_err(dev, "Failed to initialize cbf_pll_main\n");
+		return PTR_ERR(cbf_mux.pll_div_2);
+	}
+
+	ret = devm_clk_register_regmap(dev, cbf_msm8996_clks[0]);
+	ret = devm_clk_register_regmap(dev, cbf_msm8996_clks[1]);
+
+	clk_alpha_pll_configure(&cbf_pll, regmap, &cbfpll_config);
+	clk_set_rate(cbf_pll.clkr.hw.clk, 614400000);
+	clk_prepare_enable(cbf_pll.clkr.hw.clk);
+	clk_notifier_register(cbf_mux.clkr.hw.clk, &cbf_mux.nb);
+
+	return ret;
+}
+
 static int qcom_cpu_clk_msm8996_unregister_clks(void)
 {
 	int ret = 0;
@@ -409,8 +513,13 @@  static int qcom_cpu_clk_msm8996_unregister_clks(void)
 	if (ret)
 		return ret;
 
+	ret = clk_notifier_unregister(cbf_mux.clkr.hw.clk, &cbf_mux.nb);
+	if (ret)
+		return ret;
+
 	clk_hw_unregister(perfcl_smux.pll);
 	clk_hw_unregister(pwrcl_smux.pll);
+	clk_hw_unregister(cbf_mux.pll);
 
 	return 0;
 }
@@ -481,14 +590,48 @@  static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 	return notifier_from_errno(ret);
 };
 
+static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+			       void *data)
+{
+	struct clk_cpu_8996_mux *cbfclk = to_clk_cpu_8996_mux_nb(nb);
+	struct clk_notifier_data *cnd = data;
+	struct clk_hw *parent;
+	int ret;
+
+	switch (event) {
+	case PRE_RATE_CHANGE:
+		parent = clk_hw_get_parent_by_index(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
+		ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
+
+		if (cnd->old_rate > DIV_2_THRESHOLD && cnd->new_rate < DIV_2_THRESHOLD)
+			ret = clk_set_rate(parent->clk, cnd->old_rate / 2);
+		break;
+	case POST_RATE_CHANGE:
+		if (cnd->new_rate < DIV_2_THRESHOLD)
+			ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_DIV_2_INDEX);
+		else {
+			parent = clk_hw_get_parent_by_index(&cbfclk->clkr.hw, CBF_PLL_INDEX);
+			ret = clk_set_rate(parent->clk, cnd->new_rate);
+			ret = clk_cpu_8996_mux_set_parent(&cbfclk->clkr.hw, CBF_PLL_INDEX);
+		}
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	return notifier_from_errno(ret);
+};
+
 static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 {
-	struct regmap *regmap;
+	struct regmap *regmap, *regmap_cbf;
 	struct clk_hw_onecell_data *data;
 	struct device *dev = &pdev->dev;
+	static void __iomem *cbf_base;
 	int ret;
 
-	data = devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
+	data = devm_kzalloc(dev, struct_size(data, hws, 3), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -506,9 +649,22 @@  static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 
 	qcom_cpu_clk_msm8996_acd_init(base);
 
+	cbf_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(cbf_base))
+		return PTR_ERR(cbf_base);
+
+	regmap_cbf = devm_regmap_init_mmio(dev, cbf_base, &cbf_msm8996_regmap_config);
+	if (IS_ERR(regmap_cbf))
+		return PTR_ERR(regmap_cbf);
+
+	ret = qcom_cbf_clk_msm8996_register_clks(dev, regmap_cbf);
+	if (ret)
+		return ret;
+
 	data->hws[0] = &pwrcl_pmux.clkr.hw;
 	data->hws[1] = &perfcl_pmux.clkr.hw;
-	data->num = 2;
+	data->hws[2] = &cbf_mux.clkr.hw;
+	data->num = 3;
 
 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
 }