[PATCH v2 3/3] soc: qcom: ice: Add SCMI support for sa8255p based targets

From: Linlin Zhang

Date: Thu May 07 2026 - 07:29:50 EST


The Qualcomm automotive SA8255p SoC relies on firmware to configure
platform resources, including clocks, interconnects and TLMM.
The driver requests resources operations over SCMI using power
and performance protocols.

The SCMI power protocol enables or disables resources like clocks,
interconnect paths, and TLMM (GPIOs) using runtime PM framework APIs,
such as resume/suspend, to control power states(on/off).

The SCMI performance protocol manages ICE clock, with a power domain
set for ICE clock. The driver uses runtime PM framework APIs to
request power on/off status of the clock.

Reviewed-by: Neeraj Soni <neeraj.soni@xxxxxxxxxxxxxxxx>
Reviewed-by: Deepti Jaggi <quic_djaggi@xxxxxxxxxxx>
Signed-off-by: Linlin Zhang <linlin.zhang@xxxxxxxxxxxxxxxx>
---
drivers/soc/qcom/ice.c | 64 ++++++++++++++++++++++++++++--------------
1 file changed, 43 insertions(+), 21 deletions(-)

diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index 6f9d679b530c..cf185a6e1973 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -68,6 +68,10 @@ union crypto_cfg {
};
};

+struct engine_desc {
+ bool fw_managed;
+};
+
/* QCOM ICE HWKM (Hardware Key Manager) registers */

#define HWKM_OFFSET 0x8000
@@ -554,6 +558,7 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
void __iomem *base)
{
struct qcom_ice *engine;
+ const struct engine_desc *engine_cfg = NULL;

if (!qcom_scm_is_available())
return ERR_PTR(-EPROBE_DEFER);
@@ -570,20 +575,23 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
engine->dev = dev;
engine->base = base;

- /*
- * Legacy DT binding uses different clk names for each consumer,
- * so lets try those first. If none of those are a match, it means
- * the we only have one clock and it is part of the dedicated DT node.
- * Also, enable the clock before we check what HW version the driver
- * supports.
- */
- engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
- if (!engine->core_clk)
- engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
- if (!engine->core_clk)
- engine->core_clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(engine->core_clk))
- return ERR_CAST(engine->core_clk);
+ engine_cfg = device_get_match_data(dev);
+ if (!engine_cfg || !engine_cfg->fw_managed) {
+ /*
+ * Legacy DT binding uses different clk names for each consumer,
+ * so lets try those first. If none of those are a match, it means
+ * the we only have one clock and it is part of the dedicated DT node.
+ * Also, enable the clock before we check what HW version the driver
+ * supports.
+ */
+ engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
+ if (!engine->core_clk)
+ engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
+ if (!engine->core_clk)
+ engine->core_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(engine->core_clk))
+ return ERR_CAST(engine->core_clk);
+ }

if (!qcom_ice_check_supported(engine))
return ERR_PTR(-EOPNOTSUPP);
@@ -756,13 +764,17 @@ static void qcom_ice_remove(struct platform_device *pdev)

static int ice_runtime_resume(struct device *dev)
{
- struct qcom_ice *ice = dev_get_drvdata(dev);
+ struct engine_desc *engine_cfg = device_get_match_data(dev);
int err = 0;

- err = clk_prepare_enable(ice->core_clk);
- if (err) {
- dev_err(dev, "failed to enable core clock (%d)\n",
- err);
+ if (!engine_cfg || !engine_cfg->fw_managed) {
+ struct qcom_ice *ice = dev_get_drvdata(dev);
+
+ err = clk_prepare_enable(ice->core_clk);
+ if (err) {
+ dev_err(dev, "failed to enable core clock (%d)\n",
+ err);
+ }
}

return err;
@@ -770,9 +782,14 @@ static int ice_runtime_resume(struct device *dev)

static int ice_runtime_suspend(struct device *dev)
{
- struct qcom_ice *ice = dev_get_drvdata(dev);
+ const struct engine_desc *engine_cfg = device_get_match_data(dev);
+
+ if (!engine_cfg || !engine_cfg->fw_managed) {
+ struct qcom_ice *ice = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(ice->core_clk);
+ }

- clk_disable_unprepare(ice->core_clk);
return 0;
}

@@ -780,8 +797,13 @@ static const struct dev_pm_ops ice_pm_ops = {
SET_RUNTIME_PM_OPS(ice_runtime_suspend, ice_runtime_resume, NULL)
};

+static const struct engine_desc cfg_fw_managed = {
+ .fw_managed = true,
+};
+
static const struct of_device_id qcom_ice_of_match_table[] = {
{ .compatible = "qcom,inline-crypto-engine" },
+ { .compatible = "qcom,sa8255p-inline-crypto-engine", .data = &cfg_fw_managed },
{ },
};
MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
--
2.34.1