From 0076ed22a390794f36cc739de0adae050ff48bb7 Mon Sep 17 00:00:00 2001 From: Amir Vajid Date: Mon, 29 Aug 2022 23:03:01 -0700 Subject: [PATCH] drivers: firmware: arm_scmi: Add snapshot of dcvs scmi drivers Add dcvs scmi drivers. This snapshot is taken as of msm-5.15 commit 250869d2bdc2192 ("sched: improve the scheduler"). Change-Id: Id8408e23a11c60de4ac7fa7e3205f907af68ea08 Signed-off-by: Amir Vajid --- drivers/firmware/arm_scmi/Kconfig | 35 ++ drivers/firmware/arm_scmi/Makefile | 3 + drivers/firmware/arm_scmi/c1dcvs_vendor.c | 164 +++++++++ drivers/firmware/arm_scmi/memlat_vendor.c | 387 ++++++++++++++++++++++ drivers/firmware/arm_scmi/pmu_vendor.c | 106 ++++++ 5 files changed, 695 insertions(+) create mode 100644 drivers/firmware/arm_scmi/c1dcvs_vendor.c create mode 100644 drivers/firmware/arm_scmi/memlat_vendor.c create mode 100644 drivers/firmware/arm_scmi/pmu_vendor.c diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index a14f65444b35..c5871a57630e 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -134,6 +134,41 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE in atomic context too, at the price of using a number of busy-waiting primitives all over instead. If unsure say N. +config QTI_SCMI_PMU_PROTOCOL + tristate "Qualcomm Technologies, Inc. SCMI PMU vendor Protocol" + depends on ARM || ARM64 || COMPILE_TEST + depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP + help + System Control and Management Interface (SCMI) pmu vendor 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 + communication and also exposes the ops used by clients. + +config QTI_SCMI_C1DCVS_PROTOCOL + tristate "Qualcomm Technologies, Inc. SCMI C1DCVS vendor Protocol" + depends on ARM || ARM64 || COMPILE_TEST + depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP + help + System Control and Management Interface (SCMI) c1dcvs vendor protocol. + This protocol provides interface to communicate with micro controller + which maintains the c1dcvs algorithm. + + This driver defines the comands or message ID's used for this + communication and also exposes the ops used by clients. + +config QTI_SCMI_MEMLAT_PROTOCOL + tristate "Qualcomm Technologies, Inc. SCMI MEMLAT vendor Protocol" + depends on ARM || ARM64 || COMPILE_TEST + depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP + help + System Control and Management Interface (SCMI) memlat vendor protocol. + This protocol provides interface to communicate with micro controller + which is executing the hw memlat governor. This driver defines the + commands or message ID's used for this communication and also exposes + the ops used by clients. + endif #ARM_SCMI_PROTOCOL config ARM_SCMI_POWER_DOMAIN diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 9ea86f8cc8f7..d59800b17943 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -13,6 +13,9 @@ scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \ obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o 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 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/c1dcvs_vendor.c b/drivers/firmware/arm_scmi/c1dcvs_vendor.c new file mode 100644 index 000000000000..738b890fe001 --- /dev/null +++ b/drivers/firmware/arm_scmi/c1dcvs_vendor.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "common.h" + +#define SCMI_MAX_RX_SIZE 128 + +enum scmi_c1dcvs_protocol_cmd { + SET_ENABLE_C1DCVS = 11, + GET_ENABLE_C1DCVS, + SET_ENABLE_TRACE, + GET_ENABLE_TRACE, + SET_IPC_THRESH, + GET_IPC_THRESH, + SET_EFREQ_THRESH, + GET_EFREQ_THRESH, + SET_HYSTERESIS, + GET_HYSTERESIS, +}; + +struct c1dcvs_thresh { + unsigned int cluster; + unsigned int thresh; +}; + +static int scmi_send_tunable_c1dcvs(const struct scmi_protocol_handle *ph, + void *buf, u32 msg_id) +{ + int ret; + struct scmi_xfer *t; + unsigned int *msg; + unsigned int *src = buf; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + *msg = cpu_to_le32(*src); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_get_tunable_c1dcvs(const struct scmi_protocol_handle *ph, + void *buf, u32 msg_id) +{ + int ret; + struct scmi_xfer *t; + struct c1dcvs_thresh *msg; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), SCMI_MAX_RX_SIZE, + &t); + if (ret) + return ret; + + ret = ph->xops->do_xfer(ph, t); + memcpy(buf, t->rx.buf, t->rx.len); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_send_thresh_c1dcvs(const struct scmi_protocol_handle *ph, + void *buf, u32 msg_id) +{ + int ret; + struct scmi_xfer *t; + struct c1dcvs_thresh *msg; + unsigned int *src = buf; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->cluster = cpu_to_le32(src[0]); + msg->thresh = cpu_to_le32(src[1]); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_set_enable_c1dcvs(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_tunable_c1dcvs(ph, buf, SET_ENABLE_C1DCVS); +} +static int scmi_get_enable_c1dcvs(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_get_tunable_c1dcvs(ph, buf, GET_ENABLE_C1DCVS); +} +static int scmi_set_enable_trace(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_tunable_c1dcvs(ph, buf, SET_ENABLE_TRACE); +} +static int scmi_get_enable_trace(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_get_tunable_c1dcvs(ph, buf, GET_ENABLE_TRACE); +} +static int scmi_set_ipc_thresh(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_thresh_c1dcvs(ph, buf, SET_IPC_THRESH); +} +static int scmi_get_ipc_thresh(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_get_tunable_c1dcvs(ph, buf, GET_IPC_THRESH); +} +static int scmi_set_efreq_thresh(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_thresh_c1dcvs(ph, buf, SET_EFREQ_THRESH); +} +static int scmi_get_efreq_thresh(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_get_tunable_c1dcvs(ph, buf, GET_EFREQ_THRESH); +} +static int scmi_set_hysteresis(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_tunable_c1dcvs(ph, buf, SET_HYSTERESIS); +} +static int scmi_get_hysteresis(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_get_tunable_c1dcvs(ph, buf, GET_HYSTERESIS); +} + +static struct scmi_c1dcvs_vendor_ops c1dcvs_config_ops = { + .set_enable_c1dcvs = scmi_set_enable_c1dcvs, + .get_enable_c1dcvs = scmi_get_enable_c1dcvs, + .set_enable_trace = scmi_set_enable_trace, + .get_enable_trace = scmi_get_enable_trace, + .set_ipc_thresh = scmi_set_ipc_thresh, + .get_ipc_thresh = scmi_get_ipc_thresh, + .set_efreq_thresh = scmi_set_efreq_thresh, + .get_efreq_thresh = scmi_get_efreq_thresh, + .set_hysteresis = scmi_set_hysteresis, + .get_hysteresis = scmi_get_hysteresis, +}; + +static int scmi_c1dcvs_protocol_init(const struct scmi_protocol_handle *ph) +{ + u32 version; + + ph->xops->version_get(ph, &version); + + dev_dbg(ph->dev, "version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + return 0; +} + +static const struct scmi_protocol scmi_c1dcvs = { + .id = SCMI_C1DCVS_PROTOCOL, + .owner = THIS_MODULE, + .instance_init = &scmi_c1dcvs_protocol_init, + .ops = &c1dcvs_config_ops, +}; +module_scmi_protocol(scmi_c1dcvs); + +MODULE_DESCRIPTION("SCMI C1DCVS vendor Protocol"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/arm_scmi/memlat_vendor.c b/drivers/firmware/arm_scmi/memlat_vendor.c new file mode 100644 index 000000000000..15abf1cf65f7 --- /dev/null +++ b/drivers/firmware/arm_scmi/memlat_vendor.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "common.h" + +#define MAX_MAP_ENTRIES 14 + +#define SCMI_VENDOR_MSG_START (3) +#define SCMI_VENDOR_MSG_MODULE_START (16) +#define SCMI_MAX_RX_SIZE 128 +#define SCMI_MAX_GET_DATA_SIZE 124 +#define INVALID_IDX 0xFF + +enum scmi_memlat_protocol_cmd { + MEMLAT_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START, + MEMLAT_FLUSH_LOGBUF, + MEMLAT_SET_MEM_GROUP = SCMI_VENDOR_MSG_MODULE_START, + MEMLAT_SET_MONITOR, + MEMLAT_SET_COMMON_EV_MAP, + MEMLAT_SET_GRP_EV_MAP, + MEMLAT_ADAPTIVE_LOW_FREQ, + MEMLAT_ADAPTIVE_HIGH_FREQ, + MEMLAT_GET_ADAPTIVE_CUR_FREQ, + MEMLAT_IPM_CEIL, + MEMLAT_FE_STALL_FLOOR, + MEMLAT_BE_STALL_FLOOR, + MEMLAT_WB_PCT, + MEMLAT_IPM_FILTER, + MEMLAT_FREQ_SCALE_PCT, + MEMLAT_FREQ_SCALE_LIMIT_MHZ, + MEMLAT_SAMPLE_MS, + MEMLAT_MON_FREQ_MAP, + MEMLAT_SET_MIN_FREQ, + MEMLAT_SET_MAX_FREQ, + MEMLAT_GET_CUR_FREQ, + MEMLAT_START_TIMER, + MEMLAT_STOP_TIMER, + MEMLAT_GET_TIMESTAMP, + MEMLAT_MAX_MSG +}; + +struct node_msg { + uint32_t cpumask; + uint32_t hw_type; + uint32_t mon_type; + uint32_t mon_idx; + char mon_name[MAX_NAME_LEN]; +}; + +struct scalar_param_msg { + uint32_t hw_type; + uint32_t mon_idx; + uint32_t val; +}; + +struct map_table { + uint32_t v1; + uint32_t v2; +}; + +struct map_param_msg { + uint32_t hw_type; + uint32_t mon_idx; + uint32_t nr_rows; + struct map_table tbl[MAX_MAP_ENTRIES]; +}; + +struct ev_map_msg { + uint32_t num_evs; + uint32_t hw_type; + uint8_t cid[MAX_EV_CNTRS]; +}; + +static int scmi_set_ev_map(const struct scmi_protocol_handle *ph, u32 hw_type, + void *buf, u32 msg_id, u32 num_evs) +{ + int ret, i = 0; + struct scmi_xfer *t; + struct ev_map_msg *msg; + uint8_t *src = buf; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->num_evs = cpu_to_le32(num_evs); + msg->hw_type = cpu_to_le32(hw_type); + + for (i = 0; i < num_evs; i++) + msg->cid[i] = src[i]; + + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_set_grp_map(const struct scmi_protocol_handle *ph, u32 hw_type, + void *buf, u32 num_evs) +{ + return scmi_set_ev_map(ph, hw_type, buf, MEMLAT_SET_GRP_EV_MAP, num_evs); +} + +static int scmi_set_common_map(const struct scmi_protocol_handle *ph, void *buf, u32 num_evs) +{ + return scmi_set_ev_map(ph, INVALID_IDX, buf, MEMLAT_SET_COMMON_EV_MAP, num_evs); +} + +static int scmi_set_memgrp_mon(const struct scmi_protocol_handle *ph, + u32 cpus_mpidr, u32 hw_type, u32 mon_type, + u32 mon_idx, const char *mon_name, u32 msg_id) +{ + int ret = 0; + struct scmi_xfer *t; + struct node_msg *msg; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->cpumask = cpu_to_le32(cpus_mpidr); + msg->hw_type = cpu_to_le32(hw_type); + msg->mon_type = cpu_to_le32(mon_type); + msg->mon_idx = cpu_to_le32(mon_idx); + if (mon_name) + snprintf(msg->mon_name, MAX_NAME_LEN, mon_name); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_set_mon(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, + u32 hw_type, u32 mon_type, u32 mon_idx, const char *mon_name) +{ + return scmi_set_memgrp_mon(ph, cpus_mpidr, hw_type, mon_type, + mon_idx, mon_name, MEMLAT_SET_MONITOR); +} + +static int scmi_set_mem_grp(const struct scmi_protocol_handle *ph, + u32 cpus_mpidr, u32 hw_type) +{ + return scmi_set_memgrp_mon(ph, cpus_mpidr, hw_type, 0, + 0, NULL, MEMLAT_SET_MEM_GROUP); +} + +static int scmi_freq_map(const struct scmi_protocol_handle *ph, u32 hw_type, + u32 mon_idx, u32 nr_rows, void *buf) +{ + int ret, i = 0; + struct scmi_xfer *t; + struct map_param_msg *msg; + struct map_table *tbl, *src = buf; + + if (nr_rows > MAX_MAP_ENTRIES) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, MEMLAT_MON_FREQ_MAP, sizeof(*msg), + sizeof(*msg), &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->hw_type = cpu_to_le32(hw_type); + msg->mon_idx = cpu_to_le32(mon_idx); + msg->nr_rows = cpu_to_le32(nr_rows); + tbl = msg->tbl; + + for (i = 0; i < nr_rows; i++) { + tbl[i].v1 = cpu_to_le32(src[i].v1); + tbl[i].v2 = cpu_to_le32(src[i].v2); + } + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_set_tunable(const struct scmi_protocol_handle *ph, + u32 hw_type, u32 msg_id, u32 mon_idx, u32 val) +{ + int ret = 0; + struct scmi_xfer *t; + struct scalar_param_msg *msg; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), + sizeof(*msg), &t); + if (ret) + return ret; + msg = t->tx.buf; + msg->hw_type = cpu_to_le32(hw_type); + msg->mon_idx = cpu_to_le32(mon_idx); + msg->val = cpu_to_le32(val); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +#define scmi_send_cmd(name, _msg_id) \ +static int scmi_##name(const struct scmi_protocol_handle *ph, \ + u32 hw_type, u32 mon_idx, u32 val) \ +{ \ + return scmi_set_tunable(ph, hw_type, _msg_id, mon_idx, val); \ +} \ + +scmi_send_cmd(ipm_ceil, MEMLAT_IPM_CEIL); +scmi_send_cmd(fe_stall_floor, MEMLAT_FE_STALL_FLOOR); +scmi_send_cmd(be_stall_floor, MEMLAT_BE_STALL_FLOOR); +scmi_send_cmd(wb_pct_thres, MEMLAT_WB_PCT); +scmi_send_cmd(wb_filter_ipm, MEMLAT_IPM_FILTER); +scmi_send_cmd(freq_scale_pct, MEMLAT_FREQ_SCALE_PCT); +scmi_send_cmd(freq_scale_limit_mhz, MEMLAT_FREQ_SCALE_LIMIT_MHZ); +scmi_send_cmd(min_freq, MEMLAT_SET_MIN_FREQ); +scmi_send_cmd(max_freq, MEMLAT_SET_MAX_FREQ); +scmi_send_cmd(adaptive_low_freq, MEMLAT_ADAPTIVE_LOW_FREQ); +scmi_send_cmd(adaptive_high_freq, MEMLAT_ADAPTIVE_HIGH_FREQ); + +static int scmi_send_start_stop(const struct scmi_protocol_handle *ph, u32 msg_id) +{ + int ret = 0; + struct scmi_xfer *t; + + ret = ph->xops->xfer_get_init(ph, msg_id, 0, 0, &t); + if (ret) + return ret; + + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_stop_timer(const struct scmi_protocol_handle *ph) +{ + return scmi_send_start_stop(ph, MEMLAT_STOP_TIMER); +} + +static int scmi_start_timer(const struct scmi_protocol_handle *ph) +{ + return scmi_send_start_stop(ph, MEMLAT_START_TIMER); +} + +static int scmi_flush_cpucp_log(const struct scmi_protocol_handle *ph) +{ + return scmi_send_start_stop(ph, MEMLAT_FLUSH_LOGBUF); +} + +static int scmi_set_global_var(const struct scmi_protocol_handle *ph, u32 val, u32 msg_id) +{ + int ret = 0; + struct scmi_xfer *t; + u32 *ptr; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), sizeof(u32), &t); + if (ret) + return ret; + ptr = (u32 *)t->tx.buf; + *ptr = cpu_to_le32(val); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_set_log_level(const struct scmi_protocol_handle *ph, u32 val) +{ + return scmi_set_global_var(ph, val, MEMLAT_SET_LOG_LEVEL); +} + +static int scmi_set_sample_ms(const struct scmi_protocol_handle *ph, u32 val) +{ + return scmi_set_global_var(ph, val, MEMLAT_SAMPLE_MS); +} + +static int scmi_get_timestamp(const struct scmi_protocol_handle *ph, void *buf) +{ + int ret = 0; + struct scmi_xfer *t; + + ret = ph->xops->xfer_get_init(ph, MEMLAT_GET_TIMESTAMP, sizeof(u32), + SCMI_MAX_RX_SIZE, &t); + if (ret) + return ret; + + ret = ph->xops->do_xfer(ph, t); + if (t->rx.len != sizeof(u64)) + return -EMSGSIZE; + + memcpy(buf, t->rx.buf, t->rx.len); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_get_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type, + uint32_t mon_idx, void *buf, uint32_t msg_id) +{ + int ret = 0; + struct scmi_xfer *t; + struct scalar_param_msg *msg; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), + SCMI_MAX_RX_SIZE, &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->hw_type = cpu_to_le32(hw_type); + msg->mon_idx = cpu_to_le32(mon_idx); + ret = ph->xops->do_xfer(ph, t); + if (t->rx.len != sizeof(u32)) + return -EMSGSIZE; + + memcpy(buf, t->rx.buf, t->rx.len); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_get_cur_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type, + uint32_t mon_idx, void *buf) +{ + return scmi_get_freq(ph, hw_type, mon_idx, buf, MEMLAT_GET_CUR_FREQ); +} + +static int scmi_get_adaptive_cur_freq(const struct scmi_protocol_handle *ph, uint32_t hw_type, + uint32_t mon_idx, void *buf) +{ + return scmi_get_freq(ph, hw_type, mon_idx, buf, MEMLAT_GET_ADAPTIVE_CUR_FREQ); +} + +static struct scmi_memlat_vendor_ops memlat_proto_ops = { + .set_mem_grp = scmi_set_mem_grp, + .freq_map = scmi_freq_map, + .set_mon = scmi_set_mon, + .set_common_ev_map = scmi_set_common_map, + .set_grp_ev_map = scmi_set_grp_map, + .adaptive_low_freq = scmi_adaptive_low_freq, + .adaptive_high_freq = scmi_adaptive_high_freq, + .get_adaptive_cur_freq = scmi_get_adaptive_cur_freq, + .ipm_ceil = scmi_ipm_ceil, + .fe_stall_floor = scmi_fe_stall_floor, + .be_stall_floor = scmi_be_stall_floor, + .sample_ms = scmi_set_sample_ms, + .wb_filter_ipm = scmi_wb_filter_ipm, + .wb_pct_thres = scmi_wb_pct_thres, + .freq_scale_pct = scmi_freq_scale_pct, + .freq_scale_limit_mhz = scmi_freq_scale_limit_mhz, + .min_freq = scmi_min_freq, + .max_freq = scmi_max_freq, + .get_cur_freq = scmi_get_cur_freq, + .start_timer = scmi_start_timer, + .stop_timer = scmi_stop_timer, + .set_log_level = scmi_set_log_level, + .flush_cpucp_log = scmi_flush_cpucp_log, + .get_timestamp = scmi_get_timestamp, +}; + +static int scmi_memlat_vendor_protocol_init(const struct scmi_protocol_handle *ph) +{ + u32 version; + + ph->xops->version_get(ph, &version); + + dev_dbg(ph->dev, "memlat version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + return 0; +} + +static const struct scmi_protocol scmi_memlat_vendor = { + .id = SCMI_PROTOCOL_MEMLAT, + .owner = THIS_MODULE, + .instance_init = &scmi_memlat_vendor_protocol_init, + .ops = &memlat_proto_ops, +}; +module_scmi_protocol(scmi_memlat_vendor); + +MODULE_DESCRIPTION("SCMI memlat vendor Protocol"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/arm_scmi/pmu_vendor.c b/drivers/firmware/arm_scmi/pmu_vendor.c new file mode 100644 index 000000000000..0becebf89d1d --- /dev/null +++ b/drivers/firmware/arm_scmi/pmu_vendor.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "common.h" + +enum scmi_c1dcvs_protocol_cmd { + SET_PMU_MAP = 11, + SET_ENABLE_TRACE, + SET_ENABLE_CACHING, +}; + +struct pmu_map_msg { + uint8_t hw_cntrs[MAX_NUM_CPUS][MAX_CPUCP_EVT]; +}; + +static int scmi_send_pmu_map(const struct scmi_protocol_handle *ph, + void *buf, u32 msg_id) +{ + int ret, i, j; + struct scmi_xfer *t; + struct pmu_map_msg *msg; + uint8_t *src = buf; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + + for (i = 0; i < MAX_NUM_CPUS; i++) + for (j = 0; j < MAX_CPUCP_EVT; j++) + msg->hw_cntrs[i][j] = *((src + i * MAX_CPUCP_EVT) + j); + + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_send_tunable_pmu(const struct scmi_protocol_handle *ph, + void *buf, u32 msg_id) +{ + int ret; + struct scmi_xfer *t; + unsigned int *msg; + unsigned int *src = buf; + + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(*msg), sizeof(*msg), + &t); + if (ret) + return ret; + + msg = t->tx.buf; + *msg = cpu_to_le32(*src); + ret = ph->xops->do_xfer(ph, t); + ph->xops->xfer_put(ph, t); + return ret; +} + +static int scmi_pmu_map(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_pmu_map(ph, buf, SET_PMU_MAP); +} + +static int scmi_set_enable_trace(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_tunable_pmu(ph, buf, SET_ENABLE_TRACE); +} + +static int scmi_set_caching_enable(const struct scmi_protocol_handle *ph, void *buf) +{ + return scmi_send_tunable_pmu(ph, buf, SET_ENABLE_CACHING); +} + +static struct scmi_pmu_vendor_ops pmu_config_ops = { + .set_pmu_map = scmi_pmu_map, + .set_enable_trace = scmi_set_enable_trace, + .set_cache_enable = scmi_set_caching_enable, +}; + +static int scmi_pmu_protocol_init(const struct scmi_protocol_handle *ph) +{ + u32 version; + + ph->xops->version_get(ph, &version); + + dev_dbg(ph->dev, "version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + return 0; +} + +static const struct scmi_protocol scmi_pmu = { + .id = SCMI_PMU_PROTOCOL, + .owner = THIS_MODULE, + .instance_init = &scmi_pmu_protocol_init, + .ops = &pmu_config_ops, +}; +module_scmi_protocol(scmi_pmu); + +MODULE_DESCRIPTION("SCMI PMU vendor Protocol"); +MODULE_LICENSE("GPL");