xref: /linux/drivers/firmware/samsung/exynos-acpm-dvfs.c (revision ba65a4e7120a616d9c592750d9147f6dcafedffa)
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 
acpm_dvfs_set_xfer(struct acpm_xfer * xfer,u32 * cmd,size_t cmdlen,unsigned int acpm_chan_id,bool response)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 
acpm_dvfs_init_set_rate_cmd(u32 cmd[4],unsigned int clk_id,unsigned long rate)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 
acpm_dvfs_set_rate(const struct acpm_handle * handle,unsigned int acpm_chan_id,unsigned int clk_id,unsigned long rate)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 
acpm_dvfs_init_get_rate_cmd(u32 cmd[4],unsigned int clk_id)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 
acpm_dvfs_get_rate(const struct acpm_handle * handle,unsigned int acpm_chan_id,unsigned int clk_id)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 }
81