mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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>
This commit is contained in:
committed by
Krzysztof Kozlowski
parent
83c4e3c39b
commit
84a222d1b3
@@ -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
|
||||
|
||||
80
drivers/firmware/samsung/exynos-acpm-dvfs.c
Normal file
80
drivers/firmware/samsung/exynos-acpm-dvfs.c
Normal file
@@ -0,0 +1,80 @@
|
||||
// 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)
|
||||
|
||||
#define ACPM_DVFS_FREQ_REQ 0
|
||||
#define ACPM_DVFS_FREQ_GET 1
|
||||
|
||||
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)
|
||||
{
|
||||
cmd[0] = FIELD_PREP(ACPM_DVFS_ID, clk_id);
|
||||
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)
|
||||
{
|
||||
struct acpm_xfer xfer;
|
||||
unsigned int cmd[4] = {0};
|
||||
int ret;
|
||||
|
||||
acpm_dvfs_init_get_rate_cmd(cmd, clk_id);
|
||||
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;
|
||||
}
|
||||
21
drivers/firmware/samsung/exynos-acpm-dvfs.h
Normal file
21
drivers/firmware/samsung/exynos-acpm-dvfs.h
Normal file
@@ -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);
|
||||
|
||||
#endif /* __EXYNOS_ACPM_DVFS_H__ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user