[PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE

Abhinaba Rakshit posted 3 patches 2 weeks, 3 days ago
There is a newer version of this series
[PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE
Posted by Abhinaba Rakshit 2 weeks, 3 days ago
Register optional operation-points-v2 table for ICE device
and aquire its minimum and maximum frequency during ICE
device probe.

Introduce clock scaling API qcom_ice_scale_clk which scale ICE
core clock if valid (non-zero) frequencies are obtained from
OPP-table. Disable clock scaling if OPP-table is not registered.

When an ICE-device specific OPP table is available, use the PM OPP
framework to manage frequency scaling and maintain proper power-domain
constraints.

Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
---
 drivers/soc/qcom/ice.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/soc/qcom/ice.h |  1 +
 2 files changed, 64 insertions(+)

diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index b203bc685cadd21d6f96eb1799963a13db4b2b72..ca6a7df7a6827378af1f013c7e62a835d1b80cc5 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_opp.h>
 
 #include <linux/firmware/qcom/qcom_scm.h>
 
@@ -111,6 +112,9 @@ struct qcom_ice {
 	bool use_hwkm;
 	bool hwkm_init_complete;
 	u8 hwkm_version;
+	unsigned long max_freq;
+	unsigned long min_freq;
+	bool has_opp;
 };
 
 static bool qcom_ice_check_supported(struct qcom_ice *ice)
@@ -549,10 +553,29 @@ int qcom_ice_import_key(struct qcom_ice *ice,
 }
 EXPORT_SYMBOL_GPL(qcom_ice_import_key);
 
+int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up)
+{
+	int ret = 0;
+
+	if (!ice->has_opp)
+		return ret;
+
+	if (scale_up && ice->max_freq)
+		ret = dev_pm_opp_set_rate(ice->dev, ice->max_freq);
+	else if (!scale_up && ice->min_freq)
+		ret = dev_pm_opp_set_rate(ice->dev, ice->min_freq);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_ice_scale_clk);
+
 static struct qcom_ice *qcom_ice_create(struct device *dev,
 					void __iomem *base)
 {
 	struct qcom_ice *engine;
+	struct dev_pm_opp *opp;
+	int err;
+	unsigned long rate;
 
 	if (!qcom_scm_is_available())
 		return ERR_PTR(-EPROBE_DEFER);
@@ -584,6 +607,46 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
 	if (IS_ERR(engine->core_clk))
 		return ERR_CAST(engine->core_clk);
 
+	/* Register the OPP table only when ICE is described as a standalone
+	 * device node. Older platforms place ICE inside the storage controller
+	 * node, so they don't need an OPP table here, as they are handled in
+	 * storage controller.
+	 */
+	if (of_device_is_compatible(dev->of_node, "qcom,inline-crypto-engine")) {
+		/* OPP table is optional */
+		err = devm_pm_opp_of_add_table(dev);
+		if (err && err != -ENODEV) {
+			dev_err(dev, "Invalid OPP table in Device tree\n");
+			return ERR_PTR(err);
+		}
+		engine->has_opp = (err == 0);
+
+		if (!engine->has_opp)
+			dev_info(dev, "ICE OPP table is not registered\n");
+	}
+
+	if (engine->has_opp) {
+		/* Find the ICE core clock min frequency */
+		rate = 0;
+		opp = dev_pm_opp_find_freq_ceil_indexed(dev, &rate, 0);
+		if (IS_ERR(opp)) {
+			dev_warn(dev, "Unable to find ICE core clock min freq\n");
+		} else {
+			engine->min_freq = rate;
+			dev_pm_opp_put(opp);
+		}
+
+		/* Find the ICE core clock max frequency */
+		rate = ULONG_MAX;
+		opp = dev_pm_opp_find_freq_floor_indexed(dev, &rate, 0);
+		if (IS_ERR(opp)) {
+			dev_warn(dev, "Unable to find ICE core clock max freq\n");
+		} else {
+			engine->max_freq = rate;
+			dev_pm_opp_put(opp);
+		}
+	}
+
 	if (!qcom_ice_check_supported(engine))
 		return ERR_PTR(-EOPNOTSUPP);
 
diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h
index 4bee553f0a59d86ec6ce20f7c7b4bce28a706415..b701ec9e062f70152f6dea8bf6c4637ab6ef20f1 100644
--- a/include/soc/qcom/ice.h
+++ b/include/soc/qcom/ice.h
@@ -30,5 +30,6 @@ int qcom_ice_import_key(struct qcom_ice *ice,
 			const u8 *raw_key, size_t raw_key_size,
 			u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
 struct qcom_ice *devm_of_qcom_ice_get(struct device *dev);
+int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up);
 
 #endif /* __QCOM_ICE_H__ */

-- 
2.34.1
Re: [PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE
Posted by Dmitry Baryshkov 2 weeks, 2 days ago
On Fri, Jan 23, 2026 at 12:42:12PM +0530, Abhinaba Rakshit wrote:
> Register optional operation-points-v2 table for ICE device
> and aquire its minimum and maximum frequency during ICE
> device probe.
> 
> Introduce clock scaling API qcom_ice_scale_clk which scale ICE
> core clock if valid (non-zero) frequencies are obtained from
> OPP-table. Disable clock scaling if OPP-table is not registered.
> 
> When an ICE-device specific OPP table is available, use the PM OPP
> framework to manage frequency scaling and maintain proper power-domain
> constraints.
> 
> Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
> ---
>  drivers/soc/qcom/ice.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/soc/qcom/ice.h |  1 +
>  2 files changed, 64 insertions(+)
> 
> diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
> index b203bc685cadd21d6f96eb1799963a13db4b2b72..ca6a7df7a6827378af1f013c7e62a835d1b80cc5 100644
> --- a/drivers/soc/qcom/ice.c
> +++ b/drivers/soc/qcom/ice.c
> @@ -16,6 +16,7 @@
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_opp.h>
>  
>  #include <linux/firmware/qcom/qcom_scm.h>
>  
> @@ -111,6 +112,9 @@ struct qcom_ice {
>  	bool use_hwkm;
>  	bool hwkm_init_complete;
>  	u8 hwkm_version;
> +	unsigned long max_freq;
> +	unsigned long min_freq;
> +	bool has_opp;
>  };
>  
>  static bool qcom_ice_check_supported(struct qcom_ice *ice)
> @@ -549,10 +553,29 @@ int qcom_ice_import_key(struct qcom_ice *ice,
>  }
>  EXPORT_SYMBOL_GPL(qcom_ice_import_key);
>  
> +int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up)
> +{
> +	int ret = 0;
> +
> +	if (!ice->has_opp)
> +		return ret;
> +
> +	if (scale_up && ice->max_freq)
> +		ret = dev_pm_opp_set_rate(ice->dev, ice->max_freq);
> +	else if (!scale_up && ice->min_freq)
> +		ret = dev_pm_opp_set_rate(ice->dev, ice->min_freq);

Do we expect that there allways will be only two entries in the OPP?
If so, it should be a part of the bindings. If not, please design the
API with more flexibility in mind.

> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(qcom_ice_scale_clk);
> +

-- 
With best wishes
Dmitry
Re: [PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE
Posted by Abhinaba Rakshit 1 week, 6 days ago
On Fri, Jan 23, 2026 at 09:21:40PM +0200, Dmitry Baryshkov wrote:
> On Fri, Jan 23, 2026 at 12:42:12PM +0530, Abhinaba Rakshit wrote:
> > Register optional operation-points-v2 table for ICE device
> > and aquire its minimum and maximum frequency during ICE
> > device probe.
> > 
> > Introduce clock scaling API qcom_ice_scale_clk which scale ICE
> > core clock if valid (non-zero) frequencies are obtained from
> > OPP-table. Disable clock scaling if OPP-table is not registered.
> > 
> > When an ICE-device specific OPP table is available, use the PM OPP
> > framework to manage frequency scaling and maintain proper power-domain
> > constraints.
> > 
> > Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
> > ---
> >  drivers/soc/qcom/ice.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/soc/qcom/ice.h |  1 +
> >  2 files changed, 64 insertions(+)
> > 
> > diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
> > index b203bc685cadd21d6f96eb1799963a13db4b2b72..ca6a7df7a6827378af1f013c7e62a835d1b80cc5 100644
> > --- a/drivers/soc/qcom/ice.c
> > +++ b/drivers/soc/qcom/ice.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/of.h>
> >  #include <linux/of_platform.h>
> >  #include <linux/platform_device.h>
> > +#include <linux/pm_opp.h>
> >  
> >  #include <linux/firmware/qcom/qcom_scm.h>
> >  
> > @@ -111,6 +112,9 @@ struct qcom_ice {
> >  	bool use_hwkm;
> >  	bool hwkm_init_complete;
> >  	u8 hwkm_version;
> > +	unsigned long max_freq;
> > +	unsigned long min_freq;
> > +	bool has_opp;
> >  };
> >  
> >  static bool qcom_ice_check_supported(struct qcom_ice *ice)
> > @@ -549,10 +553,29 @@ int qcom_ice_import_key(struct qcom_ice *ice,
> >  }
> >  EXPORT_SYMBOL_GPL(qcom_ice_import_key);
> >  
> > +int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up)
> > +{
> > +	int ret = 0;
> > +
> > +	if (!ice->has_opp)
> > +		return ret;
> > +
> > +	if (scale_up && ice->max_freq)
> > +		ret = dev_pm_opp_set_rate(ice->dev, ice->max_freq);
> > +	else if (!scale_up && ice->min_freq)
> > +		ret = dev_pm_opp_set_rate(ice->dev, ice->min_freq);
> 
> Do we expect that there allways will be only two entries in the OPP?
> If so, it should be a part of the bindings. If not, please design the
> API with more flexibility in mind.

No.
Thanks for pointing this out. With OPP v2 being used we can indeed,
support multiple frequencies.

Also UFS core using devfreq clock scaling can scale among
multiple-frequencies depending on the load.

Will update the patch-set, with multi-frequency scale support.
Re: [PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE
Posted by Konrad Dybcio 2 weeks ago
On 1/23/26 8:21 PM, Dmitry Baryshkov wrote:
> On Fri, Jan 23, 2026 at 12:42:12PM +0530, Abhinaba Rakshit wrote:
>> Register optional operation-points-v2 table for ICE device
>> and aquire its minimum and maximum frequency during ICE
>> device probe.
>>
>> Introduce clock scaling API qcom_ice_scale_clk which scale ICE
>> core clock if valid (non-zero) frequencies are obtained from
>> OPP-table. Disable clock scaling if OPP-table is not registered.
>>
>> When an ICE-device specific OPP table is available, use the PM OPP
>> framework to manage frequency scaling and maintain proper power-domain
>> constraints.
>>
>> Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
>> ---

[...]

>> +int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!ice->has_opp)
>> +		return ret;
>> +
>> +	if (scale_up && ice->max_freq)
>> +		ret = dev_pm_opp_set_rate(ice->dev, ice->max_freq);
>> +	else if (!scale_up && ice->min_freq)
>> +		ret = dev_pm_opp_set_rate(ice->dev, ice->min_freq);
> 
> Do we expect that there allways will be only two entries in the OPP?
> If so, it should be a part of the bindings. If not, please design the
> API with more flexibility in mind.

hamoa:

LOW_SVS: 100 MHz
SVS: 201.5 MHz
NOM: 403 MHz

Konrad
Re: [PATCH v3 1/3] soc: qcom: ice: Add OPP-based clock scaling support for ICE
Posted by Abhinaba Rakshit 1 week, 6 days ago
On Mon, Jan 26, 2026 at 11:23:51AM +0100, Konrad Dybcio wrote:
> On 1/23/26 8:21 PM, Dmitry Baryshkov wrote:
> > On Fri, Jan 23, 2026 at 12:42:12PM +0530, Abhinaba Rakshit wrote:
> >> Register optional operation-points-v2 table for ICE device
> >> and aquire its minimum and maximum frequency during ICE
> >> device probe.
> >>
> >> Introduce clock scaling API qcom_ice_scale_clk which scale ICE
> >> core clock if valid (non-zero) frequencies are obtained from
> >> OPP-table. Disable clock scaling if OPP-table is not registered.
> >>
> >> When an ICE-device specific OPP table is available, use the PM OPP
> >> framework to manage frequency scaling and maintain proper power-domain
> >> constraints.
> >>
> >> Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
> >> ---
> 
> [...]
> 
> >> +int qcom_ice_scale_clk(struct qcom_ice *ice, bool scale_up)
> >> +{
> >> +	int ret = 0;
> >> +
> >> +	if (!ice->has_opp)
> >> +		return ret;
> >> +
> >> +	if (scale_up && ice->max_freq)
> >> +		ret = dev_pm_opp_set_rate(ice->dev, ice->max_freq);
> >> +	else if (!scale_up && ice->min_freq)
> >> +		ret = dev_pm_opp_set_rate(ice->dev, ice->min_freq);
> > 
> > Do we expect that there allways will be only two entries in the OPP?
> > If so, it should be a part of the bindings. If not, please design the
> > API with more flexibility in mind.
> 
> hamoa:
> 
> LOW_SVS: 100 MHz
> SVS: 201.5 MHz
> NOM: 403 MHz
> 

Understood, will update the patch-series with multiple-frequency
clock scaling support.