Skip to content

Commit 84a222d

Browse files
ambaruskrzk
authored andcommitted
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@linaro.org> Reviewed-by: Peter Griffin <peter.griffin@linaro.org> Tested-by: Peter Griffin <peter.griffin@linaro.org> # on gs101-oriole Link: https://patch.msgid.link/20251010-acpm-clk-v6-2-321ee8826fd4@linaro.org Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
1 parent 83c4e3c commit 84a222d

5 files changed

Lines changed: 119 additions & 1 deletion

File tree

drivers/firmware/samsung/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22

3-
acpm-protocol-objs := exynos-acpm.o exynos-acpm-pmic.o
3+
acpm-protocol-objs := exynos-acpm.o
4+
acpm-protocol-objs += exynos-acpm-pmic.o
5+
acpm-protocol-objs += exynos-acpm-dvfs.o
46
obj-$(CONFIG_EXYNOS_ACPM_PROTOCOL) += acpm-protocol.o
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright 2020 Samsung Electronics Co., Ltd.
4+
* Copyright 2020 Google LLC.
5+
* Copyright 2025 Linaro Ltd.
6+
*/
7+
8+
#include <linux/bitfield.h>
9+
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
10+
#include <linux/ktime.h>
11+
#include <linux/types.h>
12+
#include <linux/units.h>
13+
14+
#include "exynos-acpm.h"
15+
#include "exynos-acpm-dvfs.h"
16+
17+
#define ACPM_DVFS_ID GENMASK(11, 0)
18+
#define ACPM_DVFS_REQ_TYPE GENMASK(15, 0)
19+
20+
#define ACPM_DVFS_FREQ_REQ 0
21+
#define ACPM_DVFS_FREQ_GET 1
22+
23+
static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
24+
unsigned int acpm_chan_id, bool response)
25+
{
26+
xfer->acpm_chan_id = acpm_chan_id;
27+
xfer->txd = cmd;
28+
xfer->txlen = cmdlen;
29+
30+
if (response) {
31+
xfer->rxd = cmd;
32+
xfer->rxlen = cmdlen;
33+
}
34+
}
35+
36+
static void acpm_dvfs_init_set_rate_cmd(u32 cmd[4], unsigned int clk_id,
37+
unsigned long rate)
38+
{
39+
cmd[0] = FIELD_PREP(ACPM_DVFS_ID, clk_id);
40+
cmd[1] = rate / HZ_PER_KHZ;
41+
cmd[2] = FIELD_PREP(ACPM_DVFS_REQ_TYPE, ACPM_DVFS_FREQ_REQ);
42+
cmd[3] = ktime_to_ms(ktime_get());
43+
}
44+
45+
int acpm_dvfs_set_rate(const struct acpm_handle *handle,
46+
unsigned int acpm_chan_id, unsigned int clk_id,
47+
unsigned long rate)
48+
{
49+
struct acpm_xfer xfer = {0};
50+
u32 cmd[4];
51+
52+
acpm_dvfs_init_set_rate_cmd(cmd, clk_id, rate);
53+
acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, false);
54+
55+
return acpm_do_xfer(handle, &xfer);
56+
}
57+
58+
static void acpm_dvfs_init_get_rate_cmd(u32 cmd[4], unsigned int clk_id)
59+
{
60+
cmd[0] = FIELD_PREP(ACPM_DVFS_ID, clk_id);
61+
cmd[2] = FIELD_PREP(ACPM_DVFS_REQ_TYPE, ACPM_DVFS_FREQ_GET);
62+
cmd[3] = ktime_to_ms(ktime_get());
63+
}
64+
65+
unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
66+
unsigned int acpm_chan_id, unsigned int clk_id)
67+
{
68+
struct acpm_xfer xfer;
69+
unsigned int cmd[4] = {0};
70+
int ret;
71+
72+
acpm_dvfs_init_get_rate_cmd(cmd, clk_id);
73+
acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, true);
74+
75+
ret = acpm_do_xfer(handle, &xfer);
76+
if (ret)
77+
return 0;
78+
79+
return xfer.rxd[1] * HZ_PER_KHZ;
80+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright 2020 Samsung Electronics Co., Ltd.
4+
* Copyright 2020 Google LLC.
5+
* Copyright 2025 Linaro Ltd.
6+
*/
7+
#ifndef __EXYNOS_ACPM_DVFS_H__
8+
#define __EXYNOS_ACPM_DVFS_H__
9+
10+
#include <linux/types.h>
11+
12+
struct acpm_handle;
13+
14+
int acpm_dvfs_set_rate(const struct acpm_handle *handle,
15+
unsigned int acpm_chan_id, unsigned int id,
16+
unsigned long rate);
17+
unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
18+
unsigned int acpm_chan_id,
19+
unsigned int clk_id);
20+
21+
#endif /* __EXYNOS_ACPM_DVFS_H__ */

drivers/firmware/samsung/exynos-acpm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/types.h>
3030

3131
#include "exynos-acpm.h"
32+
#include "exynos-acpm-dvfs.h"
3233
#include "exynos-acpm-pmic.h"
3334

3435
#define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16)
@@ -590,8 +591,12 @@ static int acpm_channels_init(struct acpm_info *acpm)
590591
*/
591592
static void acpm_setup_ops(struct acpm_info *acpm)
592593
{
594+
struct acpm_dvfs_ops *dvfs_ops = &acpm->handle.ops.dvfs_ops;
593595
struct acpm_pmic_ops *pmic_ops = &acpm->handle.ops.pmic_ops;
594596

597+
dvfs_ops->set_rate = acpm_dvfs_set_rate;
598+
dvfs_ops->get_rate = acpm_dvfs_get_rate;
599+
595600
pmic_ops->read_reg = acpm_pmic_read_reg;
596601
pmic_ops->bulk_read = acpm_pmic_bulk_read;
597602
pmic_ops->write_reg = acpm_pmic_write_reg;

include/linux/firmware/samsung/exynos-acpm-protocol.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
struct acpm_handle;
1414
struct device_node;
1515

16+
struct acpm_dvfs_ops {
17+
int (*set_rate)(const struct acpm_handle *handle,
18+
unsigned int acpm_chan_id, unsigned int clk_id,
19+
unsigned long rate);
20+
unsigned long (*get_rate)(const struct acpm_handle *handle,
21+
unsigned int acpm_chan_id,
22+
unsigned int clk_id);
23+
};
24+
1625
struct acpm_pmic_ops {
1726
int (*read_reg)(const struct acpm_handle *handle,
1827
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
@@ -32,6 +41,7 @@ struct acpm_pmic_ops {
3241
};
3342

3443
struct acpm_ops {
44+
struct acpm_dvfs_ops dvfs_ops;
3545
struct acpm_pmic_ops pmic_ops;
3646
};
3747

0 commit comments

Comments
 (0)