diff mbox series

[03/15] clk: qcom: gcc-sm6375: Unregister critical clocks

Message ID 20230717-topic-branch_aon_cleanup-v1-3-27784d27a4f4@linaro.org
State Superseded
Headers show
Series Unregister critical branch clocks + some RPM | expand

Commit Message

Konrad Dybcio July 17, 2023, 3:19 p.m. UTC
Some clocks need to be always-on, but we don't really do anything
with them, other than calling enable() once and telling Linux they're
enabled.

Unregister them to save a couple of bytes and, perhaps more
importantly, allow for runtime suspend of the clock controller device,
as CLK_IS_CRITICAL prevents the latter.

Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
---
 drivers/clk/qcom/gcc-sm6375.c | 103 ++++++------------------------------------
 1 file changed, 13 insertions(+), 90 deletions(-)

Comments

Johan Hovold July 18, 2023, 1:20 p.m. UTC | #1
On Mon, Jul 17, 2023 at 05:19:10PM +0200, Konrad Dybcio wrote:
> Some clocks need to be always-on, but we don't really do anything
> with them, other than calling enable() once and telling Linux they're
> enabled.
> 
> Unregister them to save a couple of bytes and, perhaps more
> importantly, allow for runtime suspend of the clock controller device,
> as CLK_IS_CRITICAL prevents the latter.

But this doesn't sound right. How can you disable a controller which
still has clocks enabled?

Shouldn't instead these clocks be modelled properly so that they are
only enabled when actually needed?

Johan
Konrad Dybcio July 18, 2023, 1:26 p.m. UTC | #2
On 18.07.2023 15:20, Johan Hovold wrote:
> On Mon, Jul 17, 2023 at 05:19:10PM +0200, Konrad Dybcio wrote:
>> Some clocks need to be always-on, but we don't really do anything
>> with them, other than calling enable() once and telling Linux they're
>> enabled.
>>
>> Unregister them to save a couple of bytes and, perhaps more
>> importantly, allow for runtime suspend of the clock controller device,
>> as CLK_IS_CRITICAL prevents the latter.
> 
> But this doesn't sound right. How can you disable a controller which
> still has clocks enabled?
> 
> Shouldn't instead these clocks be modelled properly so that they are
> only enabled when actually needed?
Hm.. We do have clk_branch2_aon_ops, but something still needs to
toggle these clocks.

I *think* we could leave a permanent vote in probe() without breaking
runtime pm! I'll give it a spin bit later..

Konrad
Bjorn Andersson July 18, 2023, 4:23 p.m. UTC | #3
On Tue, Jul 18, 2023 at 03:26:51PM +0200, Konrad Dybcio wrote:
> On 18.07.2023 15:20, Johan Hovold wrote:
> > On Mon, Jul 17, 2023 at 05:19:10PM +0200, Konrad Dybcio wrote:
> >> Some clocks need to be always-on, but we don't really do anything
> >> with them, other than calling enable() once and telling Linux they're
> >> enabled.
> >>
> >> Unregister them to save a couple of bytes and, perhaps more
> >> importantly, allow for runtime suspend of the clock controller device,
> >> as CLK_IS_CRITICAL prevents the latter.
> > 
> > But this doesn't sound right. How can you disable a controller which
> > still has clocks enabled?
> > 
> > Shouldn't instead these clocks be modelled properly so that they are
> > only enabled when actually needed?
> Hm.. We do have clk_branch2_aon_ops, but something still needs to
> toggle these clocks.
> 

Before we started replacing these clocks with static votes, I handled
exactly this problem in the turingcc-qcs404 driver by registering the
ahb clock with a pm_clk_add(). The clock framework will then
automagically keep the clock enabled around operations, but it will also
keep the runtime state active as long as the clock is prepared.

As mentioned in an earlier reply today, there's no similarity to this in
the reset or gdsc code, so we'd need to add that in order to rely on
such mechanism.

> I *think* we could leave a permanent vote in probe() without breaking
> runtime pm! I'll give it a spin bit later..
> 

Modelling the AHB clock in DT and putting a devm_clk_get_enabled() would
properly connect the two, and thereby handle probe order between the two
clock controllers.

But it would prevent the power-domain of the parent provider to ever
suspending. Using pm_clk_add() this would at least depend on client
votes.

Regards,
Bjorn
Johan Hovold July 19, 2023, 8:43 a.m. UTC | #4
On Tue, Jul 18, 2023 at 09:23:52AM -0700, Bjorn Andersson wrote:
> On Tue, Jul 18, 2023 at 03:26:51PM +0200, Konrad Dybcio wrote:
> > On 18.07.2023 15:20, Johan Hovold wrote:
> > > On Mon, Jul 17, 2023 at 05:19:10PM +0200, Konrad Dybcio wrote:
> > >> Some clocks need to be always-on, but we don't really do anything
> > >> with them, other than calling enable() once and telling Linux they're
> > >> enabled.
> > >>
> > >> Unregister them to save a couple of bytes and, perhaps more
> > >> importantly, allow for runtime suspend of the clock controller device,
> > >> as CLK_IS_CRITICAL prevents the latter.
> > > 
> > > But this doesn't sound right. How can you disable a controller which
> > > still has clocks enabled?
> > > 
> > > Shouldn't instead these clocks be modelled properly so that they are
> > > only enabled when actually needed?
> > Hm.. We do have clk_branch2_aon_ops, but something still needs to
> > toggle these clocks.
> > 
> 
> Before we started replacing these clocks with static votes, I handled
> exactly this problem in the turingcc-qcs404 driver by registering the
> ahb clock with a pm_clk_add(). The clock framework will then
> automagically keep the clock enabled around operations, but it will also
> keep the runtime state active as long as the clock is prepared.
> 
> As mentioned in an earlier reply today, there's no similarity to this in
> the reset or gdsc code, so we'd need to add that in order to rely on
> such mechanism.

This reminds me of:

	4cc47e8add63 ("clk: qcom: gdsc: Remove direct runtime PM calls")

which recently removed a broken attempt to implement this for gdscs.

Just stumbled over GENPD_FLAG_PM_CLK which may provide a way forward at
least for genpd (but see below).

> > I *think* we could leave a permanent vote in probe() without breaking
> > runtime pm! I'll give it a spin bit later..
> > 
> 
> Modelling the AHB clock in DT and putting a devm_clk_get_enabled() would
> properly connect the two, and thereby handle probe order between the two
> clock controllers.

Yeah, this dependency really should be described eventually.

> But it would prevent the power-domain of the parent provider to ever
> suspending. Using pm_clk_add() this would at least depend on client
> votes.

IIUC using pm_clk_add() would also prevent the parent from suspending
due to that resume call in clk_prepare().

And this mechanism is also used for GENPD_FLAG_PM_CLK...

Johan
Konrad Dybcio Aug. 9, 2023, 4:52 p.m. UTC | #5
On 19.07.2023 10:43, Johan Hovold wrote:
> On Tue, Jul 18, 2023 at 09:23:52AM -0700, Bjorn Andersson wrote:
>> On Tue, Jul 18, 2023 at 03:26:51PM +0200, Konrad Dybcio wrote:
>>> On 18.07.2023 15:20, Johan Hovold wrote:
>>>> On Mon, Jul 17, 2023 at 05:19:10PM +0200, Konrad Dybcio wrote:
>>>>> Some clocks need to be always-on, but we don't really do anything
>>>>> with them, other than calling enable() once and telling Linux they're
>>>>> enabled.
>>>>>
>>>>> Unregister them to save a couple of bytes and, perhaps more
>>>>> importantly, allow for runtime suspend of the clock controller device,
>>>>> as CLK_IS_CRITICAL prevents the latter.
>>>>
>>>> But this doesn't sound right. How can you disable a controller which
>>>> still has clocks enabled?
>>>>
>>>> Shouldn't instead these clocks be modelled properly so that they are
>>>> only enabled when actually needed?
>>> Hm.. We do have clk_branch2_aon_ops, but something still needs to
>>> toggle these clocks.
>>>
>>
>> Before we started replacing these clocks with static votes, I handled
>> exactly this problem in the turingcc-qcs404 driver by registering the
>> ahb clock with a pm_clk_add(). The clock framework will then
>> automagically keep the clock enabled around operations, but it will also
>> keep the runtime state active as long as the clock is prepared.
>>
>> As mentioned in an earlier reply today, there's no similarity to this in
>> the reset or gdsc code, so we'd need to add that in order to rely on
>> such mechanism.
> 
> This reminds me of:
> 
> 	4cc47e8add63 ("clk: qcom: gdsc: Remove direct runtime PM calls")
> 
> which recently removed a broken attempt to implement this for gdscs.
> 
> Just stumbled over GENPD_FLAG_PM_CLK which may provide a way forward at
> least for genpd (but see below).
> 
>>> I *think* we could leave a permanent vote in probe() without breaking
>>> runtime pm! I'll give it a spin bit later..
>>>
>>
>> Modelling the AHB clock in DT and putting a devm_clk_get_enabled() would
>> properly connect the two, and thereby handle probe order between the two
>> clock controllers.
> 
> Yeah, this dependency really should be described eventually.
> 
>> But it would prevent the power-domain of the parent provider to ever
>> suspending. Using pm_clk_add() this would at least depend on client
>> votes.
> 
> IIUC using pm_clk_add() would also prevent the parent from suspending
> due to that resume call in clk_prepare().
> 
> And this mechanism is also used for GENPD_FLAG_PM_CLK...
So.. how do we go about solving the issue that this patch tried to
address?

Konrad
diff mbox series

Patch

diff --git a/drivers/clk/qcom/gcc-sm6375.c b/drivers/clk/qcom/gcc-sm6375.c
index e94e88bdfb91..14dafea45ac9 100644
--- a/drivers/clk/qcom/gcc-sm6375.c
+++ b/drivers/clk/qcom/gcc-sm6375.c
@@ -1742,22 +1742,6 @@  static struct clk_branch gcc_cam_throttle_rt_clk = {
 	},
 };
 
-static struct clk_branch gcc_camera_ahb_clk = {
-	.halt_reg = 0x17008,
-	.halt_check = BRANCH_HALT_DELAY,
-	.hwcg_reg = 0x17008,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x17008,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_camera_ahb_clk",
-			.flags = CLK_IS_CRITICAL,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_camss_axi_clk = {
 	.halt_reg = 0x58044,
 	.halt_check = BRANCH_HALT,
@@ -2308,22 +2292,6 @@  static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
 	},
 };
 
-static struct clk_branch gcc_disp_ahb_clk = {
-	.halt_reg = 0x1700c,
-	.halt_check = BRANCH_HALT_VOTED,
-	.hwcg_reg = 0x1700c,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x1700c,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_disp_ahb_clk",
-			.flags = CLK_IS_CRITICAL,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_regmap_div gcc_disp_gpll0_clk_src = {
 	.reg = 0x17058,
 	.shift = 0,
@@ -2454,22 +2422,6 @@  static struct clk_branch gcc_gp3_clk = {
 	},
 };
 
-static struct clk_branch gcc_gpu_cfg_ahb_clk = {
-	.halt_reg = 0x36004,
-	.halt_check = BRANCH_HALT_VOTED,
-	.hwcg_reg = 0x36004,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x36004,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_gpu_cfg_ahb_clk",
-			.flags = CLK_IS_CRITICAL,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_gpu_gpll0_clk_src = {
 	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
@@ -3093,26 +3045,6 @@  static struct clk_branch gcc_sdcc2_apps_clk = {
 	},
 };
 
-static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = {
-	.halt_reg = 0x2b06c,
-	.halt_check = BRANCH_HALT_VOTED,
-	.hwcg_reg = 0x2b06c,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x79004,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_sys_noc_cpuss_ahb_clk",
-			.parent_hws = (const struct clk_hw*[]) {
-				&gcc_cpuss_ahb_postdiv_clk_src.clkr.hw,
-			},
-			.num_parents = 1,
-			.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_sys_noc_ufs_phy_axi_clk = {
 	.halt_reg = 0x45098,
 	.halt_check = BRANCH_HALT,
@@ -3432,22 +3364,6 @@  static struct clk_branch gcc_venus_ctl_axi_clk = {
 	},
 };
 
-static struct clk_branch gcc_video_ahb_clk = {
-	.halt_reg = 0x17004,
-	.halt_check = BRANCH_HALT_DELAY,
-	.hwcg_reg = 0x17004,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x17004,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_video_ahb_clk",
-			.flags = CLK_IS_CRITICAL,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_video_axi0_clk = {
 	.halt_reg = 0x1701c,
 	.halt_check = BRANCH_HALT_VOTED,
@@ -3614,7 +3530,6 @@  static struct clk_regmap *gcc_sm6375_clocks[] = {
 	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
 	[GCC_CAM_THROTTLE_NRT_CLK] = &gcc_cam_throttle_nrt_clk.clkr,
 	[GCC_CAM_THROTTLE_RT_CLK] = &gcc_cam_throttle_rt_clk.clkr,
-	[GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr,
 	[GCC_CAMSS_AXI_CLK] = &gcc_camss_axi_clk.clkr,
 	[GCC_CAMSS_AXI_CLK_SRC] = &gcc_camss_axi_clk_src.clkr,
 	[GCC_CAMSS_CCI_0_CLK] = &gcc_camss_cci_0_clk.clkr,
@@ -3670,7 +3585,6 @@  static struct clk_regmap *gcc_sm6375_clocks[] = {
 	[GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
 	[GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr,
 	[GCC_CPUSS_AHB_POSTDIV_CLK_SRC] = &gcc_cpuss_ahb_postdiv_clk_src.clkr,
-	[GCC_DISP_AHB_CLK] = &gcc_disp_ahb_clk.clkr,
 	[GCC_DISP_GPLL0_CLK_SRC] = &gcc_disp_gpll0_clk_src.clkr,
 	[GCC_DISP_GPLL0_DIV_CLK_SRC] = &gcc_disp_gpll0_div_clk_src.clkr,
 	[GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
@@ -3682,7 +3596,6 @@  static struct clk_regmap *gcc_sm6375_clocks[] = {
 	[GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
 	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
 	[GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
-	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
 	[GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
 	[GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
 	[GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
@@ -3738,7 +3651,6 @@  static struct clk_regmap *gcc_sm6375_clocks[] = {
 	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
 	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
 	[GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
-	[GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr,
 	[GCC_SYS_NOC_UFS_PHY_AXI_CLK] = &gcc_sys_noc_ufs_phy_axi_clk.clkr,
 	[GCC_SYS_NOC_USB3_PRIM_AXI_CLK] = &gcc_sys_noc_usb3_prim_axi_clk.clkr,
 	[GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
@@ -3765,7 +3677,6 @@  static struct clk_regmap *gcc_sm6375_clocks[] = {
 	[GCC_VCODEC0_AXI_CLK] = &gcc_vcodec0_axi_clk.clkr,
 	[GCC_VENUS_AHB_CLK] = &gcc_venus_ahb_clk.clkr,
 	[GCC_VENUS_CTL_AXI_CLK] = &gcc_venus_ctl_axi_clk.clkr,
-	[GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr,
 	[GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
 	[GCC_VIDEO_THROTTLE_CORE_CLK] = &gcc_video_throttle_core_clk.clkr,
 	[GCC_VIDEO_VCODEC0_SYS_CLK] = &gcc_video_vcodec0_sys_clk.clkr,
@@ -3883,11 +3794,23 @@  static int gcc_sm6375_probe(struct platform_device *pdev)
 
 	/*
 	 * Keep the following clocks always on:
-	 * GCC_CAMERA_XO_CLK, GCC_CPUSS_GNOC_CLK, GCC_DISP_XO_CLK
+	 * GCC_CAMERA_XO_CLK
+	 * GCC_CPUSS_GNOC_CLK
+	 * GCC_DISP_XO_CLK
+	 * GCC_CAMERA_AHB_CLK
+	 * GCC_DISP_AHB_CLK
+	 * GCC_GPU_CFG_AHB_CLK
+	 * GCC_SYS_NOC_CPUSS_AHB_CLK
+	 * GCC_VIDEO_AHB_CLK
 	 */
 	qcom_branch_set_clk_en(regmap, 0x17028);
 	qcom_branch_set_clk_en(regmap, 0x2b004);
 	qcom_branch_set_clk_en(regmap, 0x1702c);
+	qcom_branch_set_clk_en(regmap, 0x17008);
+	qcom_branch_set_clk_en(regmap, 0x1700c);
+	qcom_branch_set_clk_en(regmap, 0x36004);
+	qcom_branch_set_clk_en(regmap, 0x2b06c);
+	qcom_branch_set_clk_en(regmap, 0x17004);
 
 	clk_lucid_pll_configure(&gpll10, regmap, &gpll10_config);
 	clk_lucid_pll_configure(&gpll11, regmap, &gpll11_config);