From 1db77b7094d8893fcc3a216a228b30bdfd28569e Mon Sep 17 00:00:00 2001 From: Shivnandan Kumar Date: Wed, 14 Dec 2022 13:27:34 +0530 Subject: [PATCH] drivers: firmware: arm_scmi: Add qcom vendor protocol Add Qcom vendor consolidated protocol. This change adds client and vendor driver for Qcom SCMI consolidated protocol. Change-Id: I8100d9487fd5da706004f6090a25a271a482b2fe Signed-off-by: Shivnandan Kumar --- drivers/firmware/arm_scmi/Kconfig | 13 +- drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/qcom_scmi_vendor.c | 148 +++++++++++++++++++ drivers/soc/qcom/dcvs/Kconfig | 13 +- drivers/soc/qcom/dcvs/Makefile | 1 + drivers/soc/qcom/dcvs/qcom_scmi_client.c | 57 +++++++ include/linux/qcom_scmi_vendor.h | 38 +++++ 7 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 drivers/firmware/arm_scmi/qcom_scmi_vendor.c create mode 100644 drivers/soc/qcom/dcvs/qcom_scmi_client.c create mode 100644 include/linux/qcom_scmi_vendor.h diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index c5871a57630e..661f1c198d7d 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -143,7 +143,18 @@ config QTI_SCMI_PMU_PROTOCOL This protocol provides interface to communicate with micro controller which maintains the PMU configuration for multiple clients. - This driver defines the comands or message ID's used for this + This driver defines the commands or message ID's used for this + communication and also exposes the ops used by clients. + +config QTI_SCMI_VENDOR_PROTOCOL + tristate "Qualcomm Technologies, Inc. Qcom SCMI vendor Protocol" + depends on ARM || ARM64 || COMPILE_TEST + depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP + help + System Control and Management Interface (SCMI) Qcom vendor protocol. + This protocol provides interface to communicate with micro controller. + + This driver defines the commands or message ID's used for this communication and also exposes the ops used by clients. config QTI_SCMI_C1DCVS_PROTOCOL diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index d59800b17943..85a0c5f9c3ac 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o obj-$(CONFIG_QTI_SCMI_PMU_PROTOCOL) += pmu_vendor.o obj-$(CONFIG_QTI_SCMI_C1DCVS_PROTOCOL) += c1dcvs_vendor.o obj-$(CONFIG_QTI_SCMI_MEMLAT_PROTOCOL) += memlat_vendor.o +obj-$(CONFIG_QTI_SCMI_VENDOR_PROTOCOL) += qcom_scmi_vendor.o ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame diff --git a/drivers/firmware/arm_scmi/qcom_scmi_vendor.c b/drivers/firmware/arm_scmi/qcom_scmi_vendor.c new file mode 100644 index 000000000000..c38e9ea2177e --- /dev/null +++ b/drivers/firmware/arm_scmi/qcom_scmi_vendor.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "common.h" +#include + +#define EXTENDED_MSG_ID 0 +#define SCMI_MAX_TX_RX_SIZE 128 +#define PROTOCOL_PAYLOAD_SIZE 16 +#define SET_PARAM 0x10 +#define GET_PARAM 0x11 +#define START_ACTIVITY 0x12 +#define STOP_ACTIVITY 0x13 + +static int qcom_scmi_set_param(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t size) +{ + int ret = -EINVAL; + struct scmi_xfer *t; + uint32_t *msg; + + if (!ph || !ph->xops) + return ret; + ret = ph->xops->xfer_get_init(ph, SET_PARAM, size + PROTOCOL_PAYLOAD_SIZE, + SCMI_MAX_TX_RX_SIZE, &t); + if (ret) + return ret; + msg = t->tx.buf; + *msg++ = cpu_to_le32(EXTENDED_MSG_ID); + *msg++ = cpu_to_le32(algo_str & GENMASK(31, 0)); + *msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32); + *msg++ = cpu_to_le32(param_id); + memcpy(msg, buf, size); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int qcom_scmi_get_param(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t tx_size, size_t rx_size) +{ + + int ret = -EINVAL; + struct scmi_xfer *t; + uint32_t *msg; + + if (!ph || !ph->xops || !buf) + return ret; + ret = ph->xops->xfer_get_init(ph, GET_PARAM, tx_size + PROTOCOL_PAYLOAD_SIZE, + SCMI_MAX_TX_RX_SIZE, &t); + if (ret) + return ret; + msg = t->tx.buf; + *msg++ = cpu_to_le32(EXTENDED_MSG_ID); + *msg++ = cpu_to_le32(algo_str & GENMASK(31, 0)); + *msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32); + *msg++ = cpu_to_le32(param_id); + memcpy(msg, buf, tx_size); + ret = ph->xops->do_xfer(ph, t); + if (t->rx.len > rx_size) { + pr_err("SCMI received buffer size %d is more than expected size %d\n", + t->rx.len, rx_size); + return -EMSGSIZE; + } + memcpy(buf, t->rx.buf, t->rx.len); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int qcom_scmi_start_activity(const struct scmi_protocol_handle *ph, + void *buf, u64 algo_str, u32 param_id, size_t size) +{ + int ret = -EINVAL; + struct scmi_xfer *t; + uint32_t *msg; + + if (!ph || !ph->xops) + return ret; + ret = ph->xops->xfer_get_init(ph, START_ACTIVITY, size + PROTOCOL_PAYLOAD_SIZE, + SCMI_MAX_TX_RX_SIZE, &t); + if (ret) + return ret; + msg = t->tx.buf; + *msg++ = cpu_to_le32(EXTENDED_MSG_ID); + *msg++ = cpu_to_le32(algo_str & GENMASK(31, 0)); + *msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32); + *msg++ = cpu_to_le32(param_id); + memcpy(msg, buf, size); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int qcom_scmi_stop_activity(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t size) +{ + int ret = -EINVAL; + struct scmi_xfer *t; + uint32_t *msg; + + if (!ph || !ph->xops) + return ret; + ret = ph->xops->xfer_get_init(ph, STOP_ACTIVITY, size + PROTOCOL_PAYLOAD_SIZE, + SCMI_MAX_TX_RX_SIZE, &t); + if (ret) + return ret; + msg = t->tx.buf; + *msg++ = cpu_to_le32(EXTENDED_MSG_ID); + *msg++ = cpu_to_le32(algo_str & GENMASK(31, 0)); + *msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32); + *msg++ = cpu_to_le32(param_id); + memcpy(msg, buf, size); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} +static struct qcom_scmi_vendor_ops qcom_proto_ops = { + .set_param = qcom_scmi_set_param, + .get_param = qcom_scmi_get_param, + .start_activity = qcom_scmi_start_activity, + .stop_activity = qcom_scmi_stop_activity, +}; + +static int qcom_scmi_vendor_protocol_init(const struct scmi_protocol_handle *ph) +{ + u32 version; + + ph->xops->version_get(ph, &version); + + dev_dbg(ph->dev, "qcom scmi version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + return 0; +} + +static const struct scmi_protocol qcom_scmi_vendor = { + .id = QCOM_SCMI_VENDOR_PROTOCOL, + .owner = THIS_MODULE, + .instance_init = &qcom_scmi_vendor_protocol_init, + .ops = &qcom_proto_ops, +}; +module_scmi_protocol(qcom_scmi_vendor); + +MODULE_DESCRIPTION("qcom scmi vendor Protocol"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/dcvs/Kconfig b/drivers/soc/qcom/dcvs/Kconfig index 8a6044cd5e55..f1dccb62cd70 100644 --- a/drivers/soc/qcom/dcvs/Kconfig +++ b/drivers/soc/qcom/dcvs/Kconfig @@ -76,7 +76,18 @@ config QTI_PMU_SCMI_CLIENT This driver delivers the pmu vendor protocol handle to interface driver, and interface driver will use this handle to communicate with - rimps. + cpucp. + +config QTI_QCOM_SCMI_CLIENT + tristate "Qualcomm Technologies Inc. SCMI client driver" + depends on QTI_SCMI_VENDOR_PROTOCOL + default n + help + SCMI client driver registers for Qcom vendor protocol. + + This driver delivers the qcom vendor protocol handle to interface + driver, and interface driver will use this handle to communicate with + cpucp. config QTI_C1DCVS_SCMI_CLIENT tristate "Qualcomm Technologies Inc. SCMI client driver for cpudcvs" diff --git a/drivers/soc/qcom/dcvs/Makefile b/drivers/soc/qcom/dcvs/Makefile index eb22fd6627c3..2fde2f63d1c7 100644 --- a/drivers/soc/qcom/dcvs/Makefile +++ b/drivers/soc/qcom/dcvs/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_BWMON) += bwmon.o obj-$(CONFIG_QTI_PMU_SCMI_CLIENT) += pmu_scmi.o obj-$(CONFIG_QTI_C1DCVS_SCMI_CLIENT) += c1dcvs_scmi.o obj-$(CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT) += memlat_scmi.o +obj-$(CONFIG_QTI_QCOM_SCMI_CLIENT) += qcom_scmi_client.o diff --git a/drivers/soc/qcom/dcvs/qcom_scmi_client.c b/drivers/soc/qcom/dcvs/qcom_scmi_client.c new file mode 100644 index 000000000000..b444515b60c6 --- /dev/null +++ b/drivers/soc/qcom/dcvs/qcom_scmi_client.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct scmi_device *scmi_dev; +static int scmi_client_inited; + +struct scmi_device *get_qcom_scmi_device(void) +{ + if (!scmi_client_inited) + return ERR_PTR(-EPROBE_DEFER); + + if (!scmi_dev || !scmi_dev->handle) + return ERR_PTR(-ENODEV); + return scmi_dev; +} +EXPORT_SYMBOL(get_qcom_scmi_device); + +static int scmi_client_probe(struct scmi_device *sdev) +{ + int ret = 0; + + scmi_dev = sdev; + if (!sdev) + ret = -ENODEV; + scmi_client_inited = 1; + return ret; +} + +static const struct scmi_device_id scmi_id_table[] = { + { .protocol_id = QCOM_SCMI_VENDOR_PROTOCOL, .name = "qcom_scmi_vendor_protocol" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver qcom_scmi_client_drv = { + .name = "qcom-scmi-driver", + .probe = scmi_client_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(qcom_scmi_client_drv); + +MODULE_SOFTDEP("pre: qcom_scmi_vendor"); +MODULE_DESCRIPTION("QCOM SCMI client driver"); +MODULE_LICENSE("GPL"); + + diff --git a/include/linux/qcom_scmi_vendor.h b/include/linux/qcom_scmi_vendor.h new file mode 100644 index 000000000000..b918dead18a3 --- /dev/null +++ b/include/linux/qcom_scmi_vendor.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Qcom scmi vendor protocol's header + * + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _QCOM_SCMI_VENDOR_H +#define _QCOM_SCMI_VENDOR_H + +#include +#include +#include + +#define QCOM_SCMI_VENDOR_PROTOCOL 0x80 + +struct scmi_protocol_handle; +extern struct scmi_device *get_qcom_scmi_device(void); + + +/** + * struct qcom_scmi_vendor_ops - represents the various operations provided + * by qcom scmi vendor protocol + */ +struct qcom_scmi_vendor_ops { + int (*set_param)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t size); + int (*get_param)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t tx_size, size_t rx_size); + int (*start_activity)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t size); + int (*stop_activity)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str, + u32 param_id, size_t size); +}; + + +#endif /* _QCOM_SCMI_VENDOR_H */ +