Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Tudor Ambarus and committed by
Krzysztof Kozlowski
84a222d1 83c4e3c3

+119 -1
+3 -1
drivers/firmware/samsung/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 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 4 6 obj-$(CONFIG_EXYNOS_ACPM_PROTOCOL) += acpm-protocol.o
+80
drivers/firmware/samsung/exynos-acpm-dvfs.c
··· 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 + }
+21
drivers/firmware/samsung/exynos-acpm-dvfs.h
··· 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__ */
+5
drivers/firmware/samsung/exynos-acpm.c
··· 29 29 #include <linux/types.h> 30 30 31 31 #include "exynos-acpm.h" 32 + #include "exynos-acpm-dvfs.h" 32 33 #include "exynos-acpm-pmic.h" 33 34 34 35 #define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16) ··· 591 590 */ 592 591 static void acpm_setup_ops(struct acpm_info *acpm) 593 592 { 593 + struct acpm_dvfs_ops *dvfs_ops = &acpm->handle.ops.dvfs_ops; 594 594 struct acpm_pmic_ops *pmic_ops = &acpm->handle.ops.pmic_ops; 595 + 596 + dvfs_ops->set_rate = acpm_dvfs_set_rate; 597 + dvfs_ops->get_rate = acpm_dvfs_get_rate; 595 598 596 599 pmic_ops->read_reg = acpm_pmic_read_reg; 597 600 pmic_ops->bulk_read = acpm_pmic_bulk_read;
+10
include/linux/firmware/samsung/exynos-acpm-protocol.h
··· 13 13 struct acpm_handle; 14 14 struct device_node; 15 15 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 + 16 25 struct acpm_pmic_ops { 17 26 int (*read_reg)(const struct acpm_handle *handle, 18 27 unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan, ··· 41 32 }; 42 33 43 34 struct acpm_ops { 35 + struct acpm_dvfs_ops dvfs_ops; 44 36 struct acpm_pmic_ops pmic_ops; 45 37 }; 46 38