diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index e92975bc8d31..cfe983d86512 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -39,6 +39,17 @@ config QTI_SCMI_MEMLAT_PROTOCOL This driver defines the comands or message ID's used for this communication and also exposes the ops used by clients. +config QTI_SCMI_PLH_PROTOCOL + tristate "Qualcomm Technologies, Inc. SCMI PLH vendor Protocol" + depends on ARM_SCMI_PROTOCOL && QCOM_RIMPS && QGKI + help + System Control and Management Interface (SCMI) plh vendor protocol + this protocol provides interface to communicate with micro controller + which is executing the plh algorithm + + This driver defines the comands or message ID's used for this + communication and also exposes the ops used by clients. + config ARM_SCMI_POWER_DOMAIN tristate "SCMI power domain driver" depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index eeabc570042d..3a463ac60fca 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -5,3 +5,4 @@ scmi-driver-y = driver.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o obj-$(CONFIG_QTI_SCMI_MEMLAT_PROTOCOL) += memlat_vendor.o +obj-$(CONFIG_QTI_SCMI_PLH_PROTOCOL) += plh_vendor.o diff --git a/drivers/firmware/arm_scmi/plh_vendor.c b/drivers/firmware/arm_scmi/plh_vendor.c new file mode 100644 index 000000000000..710244eb176b --- /dev/null +++ b/drivers/firmware/arm_scmi/plh_vendor.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include "common.h" + +#define SCMI_VENDOR_MSG_MAX_TX_SIZE (100) /* in bytes */ +#define SCMI_VENDOR_MSG_START (3) +#define SCMI_VENDOR_MSG_PLH_START (16) + +enum scmi_plh_protocol_cmd { + PERF_LOCK_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START, + PERF_LOCK_SCROLL_INIT_IPC_FREQ_TBL_MSG_ID = SCMI_VENDOR_MSG_PLH_START, + PERF_LOCK_SCROLL_START_MSG_ID, + PERF_LOCK_SCROLL_STOP_MSG_ID, + PERF_LOCK_MAX_MSG_ID, +}; + + +static int scmi_plh_scroll_init_ipc_freq_tbl(const struct scmi_handle *handle, + u16 *p_init_args, u16 init_len) +{ + int ret, i = 0; + struct scmi_xfer *t; + uint32_t *msg, msg_size, msg_val, align_init_len = init_len; + + if (init_len % 2) + align_init_len += 1; /* align in multiple of u32 */ + + msg_size = align_init_len * sizeof(*p_init_args); + + if (msg_size > SCMI_VENDOR_MSG_MAX_TX_SIZE) + return -EINVAL; + + ret = scmi_xfer_get_init(handle, PERF_LOCK_SCROLL_INIT_IPC_FREQ_TBL_MSG_ID, + SCMI_PROTOCOL_PLH, + (msg_size), sizeof(uint32_t), &t); + if (ret) + return ret; + + msg = t->tx.buf; + + for (i = 0; i < init_len/2 ; i++) { + msg_val = *p_init_args++; + msg_val |= ((*p_init_args++) << 16); + *msg++ = cpu_to_le32(msg_val); + } + + if (init_len % 2) + *msg = cpu_to_le32(*p_init_args); + + ret = scmi_do_xfer(handle, t); + scmi_xfer_put(handle, t); + return ret; +} + + +static int scmi_send_start_stop(const struct scmi_handle *handle, + u16 fps, u32 msg_id) +{ + int ret = 0; + struct scmi_xfer *t; + uint32_t *msg; + + ret = scmi_xfer_get_init(handle, msg_id, + SCMI_PROTOCOL_PLH, + sizeof(*msg), sizeof(uint32_t), &t); + if (ret) + return ret; + + msg = t->tx.buf; + *msg = cpu_to_le32(fps); + ret = scmi_do_xfer(handle, t); + scmi_xfer_put(handle, t); + return ret; +} + +static int scmi_plh_scroll_start_cmd(const struct scmi_handle *handle, + u16 fps) +{ + return scmi_send_start_stop(handle, fps, PERF_LOCK_SCROLL_START_MSG_ID); +} + +static int scmi_plh_scroll_stop_cmd(const struct scmi_handle *handle) +{ + return scmi_send_start_stop(handle, 0, PERF_LOCK_SCROLL_STOP_MSG_ID); +} + +static int scmi_plh_set_log_level(const struct scmi_handle *handle, + u16 val) +{ + int ret = 0; + struct scmi_xfer *t; + uint32_t *msg; + + ret = scmi_xfer_get_init(handle, PERF_LOCK_SET_LOG_LEVEL, + SCMI_PROTOCOL_PLH, sizeof(*msg), + sizeof(uint32_t), &t); + if (ret) + return ret; + + msg = t->tx.buf; + *msg = cpu_to_le32(val); + ret = scmi_do_xfer(handle, t); + scmi_xfer_put(handle, t); + return ret; +} + +static struct scmi_plh_vendor_ops plh_ops = { + .init_splh_ipc_freq_tbl = scmi_plh_scroll_init_ipc_freq_tbl, + .start_splh = scmi_plh_scroll_start_cmd, + .stop_splh = scmi_plh_scroll_stop_cmd, + .set_plh_log_level = scmi_plh_set_log_level, +}; + +static int scmi_plh_vendor_protocol_init(struct scmi_handle *handle) +{ + u32 version; + + scmi_version_get(handle, SCMI_PROTOCOL_PLH, &version); + + dev_dbg(handle->dev, "PLH version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + handle->plh_ops = &plh_ops; + + return 0; +} + +static int __init scmi_plh_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_PLH, + &scmi_plh_vendor_protocol_init); +} +subsys_initcall(scmi_plh_init); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 6f0c03b0b8f6..ac125cd94bb6 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -747,6 +747,19 @@ config QTI_SYSTEM_PM config QTI_SYSTEM_PM_RPM bool +config QTI_PLH_SCMI_CLIENT + tristate "Qualcomm Technologies Inc. SCMI client driver for PLH" + depends on QTI_PLH + default n + help + SCMI client driver registers itself with SCMI framework for PLH + vendor protocol, and also registers with the plh interface driver + msm_performance. + + This driver deliver the PLH vendor protocol handle to interface + driver, and interface driver will use this handle to communicate + with RIMPS PLH. + config QTI_HW_MEMLAT tristate "Qualcomm Technologies Inc. RIMPS memlat interface driver" depends on PERF_EVENTS diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 98557a7f9b35..66207079ef97 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd-debug.o endif obj-$(CONFIG_QTI_SYS_PM_VX) += sys_pm_vx.o obj-$(CONFIG_ICNSS2) += icnss2/ +obj-$(CONFIG_QTI_PLH_SCMI_CLIENT) += plh_scmi.o obj-$(CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT) += memlat_scmi.o obj-$(CONFIG_QTI_HW_MEMLAT) += rimps_memlat.o obj-$(CONFIG_QTI_HW_MEMLAT_LOG) += rimps_log.o diff --git a/drivers/soc/qcom/plh_scmi.c b/drivers/soc/qcom/plh_scmi.c new file mode 100644 index 000000000000..67ddad6413a5 --- /dev/null +++ b/drivers/soc/qcom/plh_scmi.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +extern void rimps_plh_init(struct scmi_handle *handle); + +static int scmi_plh_probe(struct scmi_device *sdev) +{ + struct scmi_handle *handle = sdev->handle; + + if (!handle || !handle->plh_ops) + return -ENODEV; + + rimps_plh_init(handle); + return 0; +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_PLH }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_plh_drv = { + .name = "scmi-plh-driver", + .probe = scmi_plh_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_plh_drv); + +MODULE_DESCRIPTION("ARM SCMI PLH driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 63c5a8edcd20..65ebd4f01223 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -266,6 +266,26 @@ struct scmi_memlat_vendor_ops { }; #endif +#ifdef CONFIG_QTI_SCMI_PLH_PROTOCOL +/** + * struct scmi_plh_vendor_ops - represents the various operations provided + * by SCMI PLH Protocol + * + * @init_splh_ipc_freq_tbl: initialize scroll plh ipc freq voting table in rimps + * @start_splh: starts scroll plh in rimps + * @stop_splh: stops scroll plh in rimps + * @set_plh_log_level: configure the supported log_level in plh module of rimps + */ +struct scmi_plh_vendor_ops { + int (*init_splh_ipc_freq_tbl)(const struct scmi_handle *handle, + u16 *p_init_args, u16 init_len); + int (*start_splh)(const struct scmi_handle *handle, u16 fps); + int (*stop_splh)(const struct scmi_handle *handle); + int (*set_plh_log_level)(const struct scmi_handle *handle, + u16 log_level); +}; +#endif + /** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * @@ -297,6 +317,9 @@ struct scmi_handle { struct scmi_reset_ops *reset_ops; #ifdef CONFIG_QTI_SCMI_MEMLAT_PROTOCOL struct scmi_memlat_vendor_ops *memlat_ops; +#endif +#ifdef CONFIG_QTI_SCMI_PLH_PROTOCOL + struct scmi_plh_vendor_ops *plh_ops; #endif /* for protocol internal use */ void *perf_priv; @@ -317,6 +340,9 @@ enum scmi_std_protocol { #ifdef CONFIG_QTI_SCMI_MEMLAT_PROTOCOL SCMI_PROTOCOL_MEMLAT = 0x80, #endif +#ifdef CONFIG_QTI_SCMI_PLH_PROTOCOL + SCMI_PROTOCOL_PLH = 0x81, +#endif }; struct scmi_device {