[PATCH v2 2/2] clk: samsung: acpm: add Exynos850 support

From: Alexey Klimov

Date: Mon Sep 14 2026 - 19:11:09 EST


The Exynos850 SoC utilizes the APM co-processor for clock management
via ACPM, similar to the GS101 SoC.

Add the Exynos850-specific clock variant array (including mif, int,
cpucl0, cpucl1, g3d, aud, cam, disp, and cp) and wire it up to the
driver data infrastructure. Add the "exynos850-acpm-clk" device ID
to enable dynamic instantiation of these clocks during probe().

Unlike GS101, the ACPM firmware on Exynos850 does not implement a
dynamic rate read call over ACPM IPC. To return sane clock rate in
->recalc_rate introduce a SoC-specific ->get_rate() driver data
callback. For Exynos850, this falls back to reading the upstream parent
CMU clock rate.
When ->get_rate() is set, populate pdata.fw_name during clock registration
to let clock framework to link the parent clock.

Signed-off-by: Alexey Klimov <alexey.klimov@xxxxxxxxxx>
---
drivers/clk/samsung/clk-acpm.c | 46 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/samsung/clk-acpm.c b/drivers/clk/samsung/clk-acpm.c
index 4b68b44fe615..9f46fbdd999d 100644
--- a/drivers/clk/samsung/clk-acpm.c
+++ b/drivers/clk/samsung/clk-acpm.c
@@ -22,6 +22,7 @@ struct acpm_clk {
struct clk_hw hw;
unsigned int mbox_chan_id;
struct acpm_handle *handle;
+ const struct acpm_clk_driver_data *drv_data;
};

struct acpm_clk_variant {
@@ -32,6 +33,8 @@ struct acpm_clk_driver_data {
const struct acpm_clk_variant *clks;
unsigned int nr_clks;
unsigned int mbox_chan_id;
+ /* For SoCs where ACPM firmware doesn't implement get_rate call */
+ unsigned long (*get_rate)(struct clk_hw *clk, unsigned long parent_rate);
};

#define to_acpm_clk(clk) container_of(clk, struct acpm_clk, hw)
@@ -41,6 +44,18 @@ struct acpm_clk_driver_data {
.name = cname, \
}

+static const struct acpm_clk_variant exynos850_acpm_clks[] = {
+ ACPM_CLK("mif"),
+ ACPM_CLK("int"),
+ ACPM_CLK("cpucl0"),
+ ACPM_CLK("cpucl1"),
+ ACPM_CLK("g3d"),
+ ACPM_CLK("aud"),
+ ACPM_CLK("cam"),
+ ACPM_CLK("disp"),
+ ACPM_CLK("cp"),
+};
+
static const struct acpm_clk_variant gs101_acpm_clks[] = {
ACPM_CLK("mif"),
ACPM_CLK("int"),
@@ -58,6 +73,19 @@ static const struct acpm_clk_variant gs101_acpm_clks[] = {
ACPM_CLK("bo"),
};

+static unsigned long bypass_acpm_exynos850_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static const struct acpm_clk_driver_data acpm_clk_exynos850 = {
+ .clks = exynos850_acpm_clks,
+ .nr_clks = ARRAY_SIZE(exynos850_acpm_clks),
+ .mbox_chan_id = 0,
+ .get_rate = bypass_acpm_exynos850_get_rate,
+};
+
static const struct acpm_clk_driver_data acpm_clk_gs101 = {
.clks = gs101_acpm_clks,
.nr_clks = ARRAY_SIZE(gs101_acpm_clks),
@@ -69,6 +97,9 @@ static unsigned long acpm_clk_recalc_rate(struct clk_hw *hw,
{
struct acpm_clk *clk = to_acpm_clk(hw);

+ if (clk->drv_data->get_rate)
+ return clk->drv_data->get_rate(hw, parent_rate);
+
return clk->handle->ops->dvfs.get_rate(clk->handle, clk->mbox_chan_id,
clk->id);
}
@@ -89,14 +120,23 @@ static const struct clk_ops acpm_clk_ops = {
};

static int acpm_clk_register(struct device *dev, struct acpm_clk *aclk,
- const char *name)
+ const char *name, const struct acpm_clk_driver_data *drv_data)
{
struct clk_init_data init = {};
+ struct clk_parent_data pdata = {};

init.name = name;
init.ops = &acpm_clk_ops;
aclk->hw.init = &init;

+ /* If get_rate is set, the SoC relies on parent topology */
+ if (drv_data->get_rate) {
+ pdata.fw_name = name;
+ init.parent_data = &pdata;
+ init.num_parents = 1;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ }
+
return devm_clk_hw_register(dev, &aclk->hw);
}

@@ -145,13 +185,14 @@ static int acpm_clk_probe(struct platform_device *pdev)
* The code assumes the clock IDs start from zero,
* are sequential and do not have gaps.
*/
+ aclk->drv_data = drv_data;
aclk->id = i;
aclk->handle = acpm_handle;
aclk->mbox_chan_id = mbox_chan_id;

hws[i] = &aclk->hw;

- err = acpm_clk_register(dev, aclk, drv_data->clks[i].name);
+ err = acpm_clk_register(dev, aclk, drv_data->clks[i].name, drv_data);
if (err)
return dev_err_probe(dev, err,
"Failed to register clock\n");
@@ -162,6 +203,7 @@ static int acpm_clk_probe(struct platform_device *pdev)
}

static const struct platform_device_id acpm_clk_id[] = {
+ { .name = "exynos850-acpm-clk", (kernel_ulong_t)&acpm_clk_exynos850 },
{ .name = "gs101-acpm-clk", (kernel_ulong_t)&acpm_clk_gs101 },
{ }
};

--
2.51.0