[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250819-acpm-clk-v1-2-6bbd97474671@linaro.org>
Date: Tue, 19 Aug 2025 11:45:37 +0000
From: Tudor Ambarus <tudor.ambarus@...aro.org>
To: Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Peter Griffin <peter.griffin@...aro.org>,
André Draszik <andre.draszik@...aro.org>,
Michael Turquette <mturquette@...libre.com>,
Stephen Boyd <sboyd@...nel.org>, Krzysztof Kozlowski <krzk@...nel.org>,
Alim Akhtar <alim.akhtar@...sung.com>,
Sylwester Nawrocki <s.nawrocki@...sung.com>,
Chanwoo Choi <cw00.choi@...sung.com>
Cc: linux-kernel@...r.kernel.org, linux-samsung-soc@...r.kernel.org,
devicetree@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
linux-clk@...r.kernel.org, willmcvicker@...gle.com, kernel-team@...roid.com,
Tudor Ambarus <tudor.ambarus@...aro.org>
Subject: [PATCH 2/3] firmware: exynos-acpm: add DVFS protocol
Add ACPM DVFS protocol handler. It constructs DVFS messages that
the APM firmware can understand.
Signed-off-by: Tudor Ambarus <tudor.ambarus@...aro.org>
---
drivers/firmware/samsung/Makefile | 4 +-
drivers/firmware/samsung/exynos-acpm-dvfs.c | 85 ++++++++++++++++++++++
drivers/firmware/samsung/exynos-acpm-dvfs.h | 21 ++++++
drivers/firmware/samsung/exynos-acpm.c | 5 ++
.../linux/firmware/samsung/exynos-acpm-protocol.h | 10 +++
5 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/samsung/Makefile b/drivers/firmware/samsung/Makefile
index 7b4c9f6f34f54fd731886d97a615fe1aa97ba9a0..80d4f89b33a9558b68c9083da675c70ec3d05f19 100644
--- a/drivers/firmware/samsung/Makefile
+++ b/drivers/firmware/samsung/Makefile
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-acpm-protocol-objs := exynos-acpm.o exynos-acpm-pmic.o
+acpm-protocol-objs := exynos-acpm.o
+acpm-protocol-objs += exynos-acpm-pmic.o
+acpm-protocol-objs += exynos-acpm-dvfs.o
obj-$(CONFIG_EXYNOS_ACPM_PROTOCOL) += acpm-protocol.o
diff --git a/drivers/firmware/samsung/exynos-acpm-dvfs.c b/drivers/firmware/samsung/exynos-acpm-dvfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee457c1a3de2ff2e4395d9fc3ff4c13294473b2d
--- /dev/null
+++ b/drivers/firmware/samsung/exynos-acpm-dvfs.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Samsung Electronics Co., Ltd.
+ * Copyright 2020 Google LLC.
+ * Copyright 2025 Linaro Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/firmware/samsung/exynos-acpm-protocol.h>
+#include <linux/ktime.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "exynos-acpm.h"
+#include "exynos-acpm-dvfs.h"
+
+#define ACPM_DVFS_ID GENMASK(11, 0)
+#define ACPM_DVFS_REQ_TYPE GENMASK(15, 0)
+
+enum exynos_acpm_dvfs_func {
+ ACPM_DVFS_FREQ_REQ,
+ ACPM_DVFS_FREQ_GET,
+};
+
+static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
+ unsigned int acpm_chan_id, bool response)
+{
+ xfer->acpm_chan_id = acpm_chan_id;
+ xfer->txd = cmd;
+ xfer->txlen = cmdlen;
+
+ if (response) {
+ xfer->rxd = cmd;
+ xfer->rxlen = cmdlen;
+ }
+}
+
+static void acpm_dvfs_init_set_rate_cmd(u32 cmd[4], unsigned int clk_id,
+ unsigned long rate)
+{
+ cmd[0] = FIELD_PREP(ACPM_DVFS_ID, clk_id);
+ cmd[1] = rate / HZ_PER_KHZ;
+ cmd[2] = FIELD_PREP(ACPM_DVFS_REQ_TYPE, ACPM_DVFS_FREQ_REQ);
+ cmd[3] = ktime_to_ms(ktime_get());
+}
+
+int acpm_dvfs_set_rate(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id, unsigned int clk_id,
+ unsigned long rate)
+{
+ struct acpm_xfer xfer = {0};
+ u32 cmd[4];
+
+ acpm_dvfs_init_set_rate_cmd(cmd, clk_id, rate);
+ acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, false);
+
+ return acpm_do_xfer(handle, &xfer);
+}
+
+static void acpm_dvfs_init_get_rate_cmd(u32 cmd[4], unsigned int clk_id,
+ u32 dbg_val)
+{
+ cmd[0] = FIELD_PREP(ACPM_DVFS_ID, clk_id);
+ cmd[1] = dbg_val;
+ cmd[2] = FIELD_PREP(ACPM_DVFS_REQ_TYPE, ACPM_DVFS_FREQ_GET);
+ cmd[3] = ktime_to_ms(ktime_get());
+}
+
+unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id, unsigned int clk_id,
+ u32 dbg_val)
+{
+ struct acpm_xfer xfer;
+ unsigned int cmd[4];
+ int ret;
+
+ acpm_dvfs_init_get_rate_cmd(cmd, clk_id, dbg_val);
+ acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, true);
+
+ ret = acpm_do_xfer(handle, &xfer);
+ if (ret)
+ return 0;
+
+ return xfer.rxd[1] * HZ_PER_KHZ;
+}
diff --git a/drivers/firmware/samsung/exynos-acpm-dvfs.h b/drivers/firmware/samsung/exynos-acpm-dvfs.h
new file mode 100644
index 0000000000000000000000000000000000000000..85a10bd535d118f2f36e9888e41b9b705b08ea59
--- /dev/null
+++ b/drivers/firmware/samsung/exynos-acpm-dvfs.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Samsung Electronics Co., Ltd.
+ * Copyright 2020 Google LLC.
+ * Copyright 2025 Linaro Ltd.
+ */
+#ifndef __EXYNOS_ACPM_DVFS_H__
+#define __EXYNOS_ACPM_DVFS_H__
+
+#include <linux/types.h>
+
+struct acpm_handle;
+
+int acpm_dvfs_set_rate(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id, unsigned int id,
+ unsigned long rate);
+unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id, unsigned int clk_id,
+ u32 dbg_val);
+
+#endif /* __EXYNOS_ACPM_DVFS_H__ */
diff --git a/drivers/firmware/samsung/exynos-acpm.c b/drivers/firmware/samsung/exynos-acpm.c
index 3a69fe3234c75e0b5a93cbea6bb210dc6f69d2a6..9fa0335ccf5db32892fdf09e8d4b0a885a8f8fb5 100644
--- a/drivers/firmware/samsung/exynos-acpm.c
+++ b/drivers/firmware/samsung/exynos-acpm.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include "exynos-acpm.h"
+#include "exynos-acpm-dvfs.h"
#include "exynos-acpm-pmic.h"
#define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16)
@@ -590,8 +591,12 @@ static int acpm_channels_init(struct acpm_info *acpm)
*/
static void acpm_setup_ops(struct acpm_info *acpm)
{
+ struct acpm_dvfs_ops *dvfs_ops = &acpm->handle.ops.dvfs_ops;
struct acpm_pmic_ops *pmic_ops = &acpm->handle.ops.pmic_ops;
+ dvfs_ops->set_rate = acpm_dvfs_set_rate;
+ dvfs_ops->get_rate = acpm_dvfs_get_rate;
+
pmic_ops->read_reg = acpm_pmic_read_reg;
pmic_ops->bulk_read = acpm_pmic_bulk_read;
pmic_ops->write_reg = acpm_pmic_write_reg;
diff --git a/include/linux/firmware/samsung/exynos-acpm-protocol.h b/include/linux/firmware/samsung/exynos-acpm-protocol.h
index f628bf1862c25fa018a2fe5e7e123bf05c5254b9..e41055316bb578bb8250a1b1177f1059eeeb2611 100644
--- a/include/linux/firmware/samsung/exynos-acpm-protocol.h
+++ b/include/linux/firmware/samsung/exynos-acpm-protocol.h
@@ -13,6 +13,15 @@
struct acpm_handle;
struct device_node;
+struct acpm_dvfs_ops {
+ int (*set_rate)(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id, unsigned int clk_id,
+ unsigned long rate);
+ unsigned long (*get_rate)(const struct acpm_handle *handle,
+ unsigned int acpm_chan_id,
+ unsigned int clk_id, u32 dbg_val);
+};
+
struct acpm_pmic_ops {
int (*read_reg)(const struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
@@ -32,6 +41,7 @@ struct acpm_pmic_ops {
};
struct acpm_ops {
+ struct acpm_dvfs_ops dvfs_ops;
struct acpm_pmic_ops pmic_ops;
};
--
2.51.0.rc1.167.g924127e9c0-goog
Powered by blists - more mailing lists