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 } 81