[PATCH 05/13] clk: qcom: common: Add helpers to control clocks using CRM

From: Jagadeesh Kona

Date: Mon Apr 20 2026 - 13:04:54 EST


CESTA Resource Manager (CRM) scales clock frequencies based on
performance operating levels. Introduce qcom_find_crm_freq_index()
to convert a requested clock rate into a CRM LUT performance level.

Additionally, add clk_crm and qcom_clk_crm_soc_data structures, which
capture the CRM-specific clock configuration for a clock controller
(register layout, LUT information, CRM device etc). This info is used
to read frequency lookup tables provided by CRM and for sending votes
through CRM to scale the clock frequencies.

Co-developed-by: Taniya Das <taniya.das@xxxxxxxxxxxxxxxx>
Signed-off-by: Taniya Das <taniya.das@xxxxxxxxxxxxxxxx>
Signed-off-by: Jagadeesh Kona <jagadeesh.kona@xxxxxxxxxxxxxxxx>
---
drivers/clk/qcom/common.c | 39 +++++++++++++++++++++++++++++++++++++++
drivers/clk/qcom/common.h | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index eec369d2173b5ce24bc1ca860d2ac1bbdce04524..968e19997daf5eebec65315974cd0c41e08e55ec 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/

#include <linux/export.h>
@@ -80,6 +81,44 @@ const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
}
EXPORT_SYMBOL_GPL(qcom_find_freq_floor);

+/**
+ * qcom_find_crm_freq_index - Map a clock rate to a CRM LUT performance level
+ * @f: pointer to the frequency table
+ * @rate: requested clock rate in Hz
+ *
+ * Convert a requested clock rate into a CRM LUT performance level index.
+ * CRM treats performance level 0 as CLK_OFF, so valid performance levels
+ * start from 1.
+ *
+ * Return: a non-negative performance level index on success, or -EINVAL
+ * if @f is NULL or the frequency table is empty.
+ */
+
+int qcom_find_crm_freq_index(const struct freq_tbl *f, unsigned long rate)
+{
+ int index;
+
+ if (!f || !f->freq)
+ return -EINVAL;
+
+ /* Return 0 for CRM to disable the clocks */
+ if (!rate)
+ return 0;
+
+ /*
+ * Calculate the perf level for supported frequencies starting
+ * from 1, since PERF_OL 0 is treated as CLK_OFF by CRM.
+ */
+ for (index = 1; f->freq; f++, index++) {
+ if (rate <= f->freq)
+ return index;
+ }
+
+ /* Default to highest corner */
+ return index - 1;
+}
+EXPORT_SYMBOL_GPL(qcom_find_crm_freq_index);
+
int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
{
int i, num_parents = clk_hw_get_num_parents(hw);
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 6f2406f8839e8f432ef34ce32c930cf045f6ae7a..9987cec84324a258f3405c7b9093237f52a41b45 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */

#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__
@@ -62,6 +65,39 @@ struct parent_map {
u8 cfg;
};

+/**
+ * struct qcom_clk_crm_soc_data - CRM clock register layout for a clock controller
+ *
+ * @reg_cfg_rcgr_lut_base: Base register address for CFG_RCGR LUT values
+ * @reg_l_val_lut_base: Base register address for PLL L and ALPHA LUT values
+ * @vcd_offset: Offset between consecutive VCD blocks
+ * @lut_level_offset: Offset between consecutive LUT levels within a VCD
+ */
+struct qcom_clk_crm_soc_data {
+ u32 reg_cfg_rcgr_lut_base;
+ u32 reg_l_val_lut_base;
+ u32 vcd_offset;
+ u32 lut_level_offset;
+};
+
+/**
+ * struct clk_crm - Clock CRM used to communicate with CRM
+ *
+ * @crm_dev: Pointer to CRM device structure used to communicate with CESTA
+ * @regmap_crmc: regmap for the crmc instance to read frequency look up tables
+ * @regs: CRMC (CRM clock) base register addresses and offsets
+ * @max_perf_ol: Maximum number of performance operating levels supported
+ * @client_idx: SW Client Index
+ */
+struct clk_crm {
+ struct device *crm_dev;
+ struct regmap *regmap_crmc;
+ struct qcom_clk_crm_soc_data regs;
+ u8 max_perf_ol;
+ u8 client_idx;
+};
+
+extern int qcom_find_crm_freq_index(const struct freq_tbl *f, unsigned long rate);
extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
unsigned long rate);
extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,

--
2.34.1