Loading arch/arm64/configs/vendor/holi_QGKI.config +6 −0 Original line number Diff line number Diff line Loading @@ -169,3 +169,9 @@ CONFIG_QCOM_QFPROM_SYSFS=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y CONFIG_STM_PROTO_BASIC=y CONFIG_INTERCONNECT_QCOM_CPUCP_L3=y CONFIG_QCOM_RIMPS=y CONFIG_QTI_SCMI_MEMLAT_PROTOCOL=y CONFIG_QTI_HW_MEMLAT=y CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT=y CONFIG_SRAM=y CONFIG_QTI_HW_MEMLAT_LOG=y drivers/firmware/Kconfig +12 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ config ARM_SCMI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCMI. 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_RIMPS 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 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) Loading drivers/firmware/arm_scmi/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -4,3 +4,4 @@ scmi-bus-y = bus.o 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 drivers/firmware/arm_scmi/memlat_vendor.c 0 → 100644 +335 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #include "common.h" #define MAX_MAP_ENTRIES 14 #define MAX_PMU_ENTRIES 24 #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 enum scmi_memlat_protocol_cmd { MEMLAT_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START, MEMLAT_SET_CPU_GROUP = SCMI_VENDOR_MSG_MODULE_START, MEMLAT_SET_MONITOR, MEMLAT_COMMON_PMU_MAP, MEMLAT_MON_PMU_MAP, MEMLAT_RATIO_CEIL, MEMLAT_STALL_FLOOR, MEMLAT_L3_L2WB_PCT, MEMLAT_L3_IPM_FILTER, MEMLAT_SAMPLE_MS, MEMLAT_MON_FREQ_MAP, MEMLAT_SET_MIN_FREQ, MEMLAT_SET_MAX_FREQ, MEMLAT_START_MONITOR, MEMLAT_STOP_MONITOR, MEMLAT_GET_DATA = 0xFF, MEMLAT_MAX_MSG }; struct node_msg { uint32_t cpumask; uint32_t mon_type; }; struct scalar_param_msg { uint32_t cpumask; uint32_t mon_type; uint32_t val; }; struct map_table { uint32_t v1; uint32_t v2; }; struct map_param_msg { uint32_t cpumask; uint32_t mon_type; uint32_t nr_rows; struct map_table tbl[MAX_MAP_ENTRIES]; }; struct pmu_map_msg { uint32_t cpumask; uint32_t mon_type; uint32_t nr_entries; uint32_t pmu[MAX_PMU_ENTRIES]; }; static int scmi_set_cpugrp_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 msg_id) { int ret = 0; struct scmi_xfer *t; struct node_msg *msg; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_set_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_set_cpugrp_mon(handle, cpus_mpidr, mon_type, MEMLAT_SET_MONITOR); } static int scmi_set_cpu_grp(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_set_cpugrp_mon(handle, cpus_mpidr, mon_type, MEMLAT_SET_CPU_GROUP); } static int scmi_send_pmu_map_command(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf, u32 msg_id) { int ret, i = 0; struct scmi_xfer *t; struct pmu_map_msg *msg; u32 *dst; struct map_table *src = buf; if (nr_entries > MAX_PMU_ENTRIES) return -EINVAL; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); msg->nr_entries = cpu_to_le32(nr_entries); dst = msg->pmu; for (i = 0; i < nr_entries; i++) dst[i] = cpu_to_le32(src[i].v2); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_common_pmu_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf) { return scmi_send_pmu_map_command(handle, cpus_mpidr, mon_type, nr_entries, buf, MEMLAT_COMMON_PMU_MAP); } static int scmi_mon_pmu_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf) { return scmi_send_pmu_map_command(handle, cpus_mpidr, mon_type, nr_entries, buf, MEMLAT_MON_PMU_MAP); } static int scmi_freq_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, 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 = scmi_xfer_get_init(handle, MEMLAT_MON_FREQ_MAP, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); 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 = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } #define scmi_send_cmd(name, _msg_id) \ static int scmi_##name(const struct scmi_handle *handle, \ u32 cpus_mpidr, u32 mon_type, u32 val) \ { \ int ret = 0; \ struct scmi_xfer *t; \ struct scalar_param_msg *msg; \ ret = scmi_xfer_get_init(handle, _msg_id, \ SCMI_PROTOCOL_MEMLAT, \ sizeof(*msg), sizeof(*msg), &t); \ if (ret) \ return ret; \ msg = t->tx.buf; \ msg->cpumask = cpu_to_le32(cpus_mpidr); \ msg->mon_type = cpu_to_le32(mon_type); \ msg->val = cpu_to_le32(val); \ ret = scmi_do_xfer(handle, t); \ scmi_xfer_put(handle, t); \ return ret; \ } \ scmi_send_cmd(ratio_ceil, MEMLAT_RATIO_CEIL); scmi_send_cmd(stall_floor, MEMLAT_STALL_FLOOR); scmi_send_cmd(l2wb_pct, MEMLAT_L3_L2WB_PCT); scmi_send_cmd(l2wb_filter, MEMLAT_L3_IPM_FILTER); scmi_send_cmd(sample_ms, MEMLAT_SAMPLE_MS); scmi_send_cmd(min_freq, MEMLAT_SET_MIN_FREQ); scmi_send_cmd(max_freq, MEMLAT_SET_MAX_FREQ); static int scmi_send_start_stop(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 msg_id) { int ret = 0; struct scmi_xfer *t; struct scalar_param_msg *msg; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_stop_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_send_start_stop(handle, cpus_mpidr, mon_type, MEMLAT_STOP_MONITOR); } static int scmi_start_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_send_start_stop(handle, cpus_mpidr, mon_type, MEMLAT_START_MONITOR); } static int scmi_get_data(const struct scmi_handle *handle, u8 *buf) { int ret = 0; struct scmi_xfer *t; u32 prev_cnt = 0; struct scalar_param_msg *msg; ret = scmi_xfer_get_init(handle, MEMLAT_GET_DATA, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), SCMI_MAX_RX_SIZE, &t); if (ret) return ret; do { ret = scmi_do_xfer(handle, t); if (ret == -ETIMEDOUT) ret = scmi_do_xfer(handle, t); if (ret < 0) break; memcpy((buf + prev_cnt), t->rx.buf, t->rx.len); prev_cnt += t->rx.len; } while (t->rx.len >= SCMI_MAX_GET_DATA_SIZE); scmi_xfer_put(handle, t); return ret; } static int scmi_set_log_level(const struct scmi_handle *handle, u32 val) { int ret = 0; struct scmi_xfer *t; u32 *ptr; ret = scmi_xfer_get_init(handle, MEMLAT_SET_LOG_LEVEL, SCMI_PROTOCOL_MEMLAT, sizeof(u32), sizeof(u32), &t); if (ret) return ret; ptr = (u32 *)t->tx.buf; *ptr = cpu_to_le32(val); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static struct scmi_memlat_vendor_ops memlat_ops = { .set_cpu_grp = scmi_set_cpu_grp, .freq_map = scmi_freq_map, .set_mon = scmi_set_mon, .common_pmu_map = scmi_common_pmu_map, .mon_pmu_map = scmi_mon_pmu_map, .ratio_ceil = scmi_ratio_ceil, .stall_floor = scmi_stall_floor, .sample_ms = scmi_sample_ms, .l2wb_filter = scmi_l2wb_filter, .l2wb_pct = scmi_l2wb_pct, .min_freq = scmi_min_freq, .max_freq = scmi_max_freq, .start_monitor = scmi_start_mon, .stop_monitor = scmi_stop_mon, .set_log_level = scmi_set_log_level, .get_data = scmi_get_data, }; static int scmi_memlat_vendor_protocol_init(struct scmi_handle *handle) { u32 version; scmi_version_get(handle, SCMI_PROTOCOL_MEMLAT, &version); dev_dbg(handle->dev, "memlat version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); handle->memlat_ops = &memlat_ops; return 0; } static int __init scmi_memlat_init(void) { return scmi_protocol_register(SCMI_PROTOCOL_MEMLAT, &scmi_memlat_vendor_protocol_init); } subsys_initcall(scmi_memlat_init); drivers/soc/qcom/Kconfig +46 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,16 @@ config QCOM_IPCC Say Y here to compile the driver as a part of kernel or M to compile as a module. config QCOM_RIMPS tristate "Qualcomm Technologies, Inc. Rimps driver" depends on MAILBOX help Qualcomm Technologies, Inc. RIMPS driver for MSM devices. This driver acts as a mailbox controller to do doorbell between Apss and Rimps subsystem. Say yes here to enable rx and tx channel between both the subsystems. If unsure, say n. config QCOM_LLCC tristate "Qualcomm Technologies, Inc. LLCC driver" depends on ARCH_QCOM || COMPILE_TEST Loading Loading @@ -710,6 +720,42 @@ config QTI_SYSTEM_PM config QTI_SYSTEM_PM_RPM bool config QTI_HW_MEMLAT tristate "Qualcomm Technologies Inc. RIMPS memlat interface driver" depends on PERF_EVENTS default n help Interface driver between RIMPS memlat and userspace. This driver is responsible for handling the communication with RIMPS memlat such as setting up PMU events, passing tunables, frequency table, PMU counters and saving the values of PMU counters during LPM and hotplug. config QTI_HW_MEMLAT_SCMI_CLIENT tristate "Qualcomm Technologies Inc. SCMI client driver for HW MEMLAT" depends on QTI_HW_MEMLAT default n help SCMI client driver registers itself with SCMI framework for memlat vendor protocol, and also registers with the memlat hw interface driver. This driver deliver the memlat vendor protocol handle to interface driver, and interface driver will use this handle to communicate with memlat HW. config QTI_HW_MEMLAT_LOG tristate "Qualcomm Technologies Inc. HW MEMLAT Logging" depends on IPC_LOGGING && QCOM_RIMPS default n help Memlat hw logging driver, this driver has the infra to collect logs generated in MEMLAT HW and log the buffers. This driver register with IPC_Logging framework, to have dedicated buffer for memlat hw device. if MSM_PM menuconfig MSM_IDLE_STATS bool "Collect idle statistics" Loading Loading
arch/arm64/configs/vendor/holi_QGKI.config +6 −0 Original line number Diff line number Diff line Loading @@ -169,3 +169,9 @@ CONFIG_QCOM_QFPROM_SYSFS=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y CONFIG_STM_PROTO_BASIC=y CONFIG_INTERCONNECT_QCOM_CPUCP_L3=y CONFIG_QCOM_RIMPS=y CONFIG_QTI_SCMI_MEMLAT_PROTOCOL=y CONFIG_QTI_HW_MEMLAT=y CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT=y CONFIG_SRAM=y CONFIG_QTI_HW_MEMLAT_LOG=y
drivers/firmware/Kconfig +12 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ config ARM_SCMI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCMI. 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_RIMPS 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 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) Loading
drivers/firmware/arm_scmi/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -4,3 +4,4 @@ scmi-bus-y = bus.o 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
drivers/firmware/arm_scmi/memlat_vendor.c 0 → 100644 +335 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #include "common.h" #define MAX_MAP_ENTRIES 14 #define MAX_PMU_ENTRIES 24 #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 enum scmi_memlat_protocol_cmd { MEMLAT_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START, MEMLAT_SET_CPU_GROUP = SCMI_VENDOR_MSG_MODULE_START, MEMLAT_SET_MONITOR, MEMLAT_COMMON_PMU_MAP, MEMLAT_MON_PMU_MAP, MEMLAT_RATIO_CEIL, MEMLAT_STALL_FLOOR, MEMLAT_L3_L2WB_PCT, MEMLAT_L3_IPM_FILTER, MEMLAT_SAMPLE_MS, MEMLAT_MON_FREQ_MAP, MEMLAT_SET_MIN_FREQ, MEMLAT_SET_MAX_FREQ, MEMLAT_START_MONITOR, MEMLAT_STOP_MONITOR, MEMLAT_GET_DATA = 0xFF, MEMLAT_MAX_MSG }; struct node_msg { uint32_t cpumask; uint32_t mon_type; }; struct scalar_param_msg { uint32_t cpumask; uint32_t mon_type; uint32_t val; }; struct map_table { uint32_t v1; uint32_t v2; }; struct map_param_msg { uint32_t cpumask; uint32_t mon_type; uint32_t nr_rows; struct map_table tbl[MAX_MAP_ENTRIES]; }; struct pmu_map_msg { uint32_t cpumask; uint32_t mon_type; uint32_t nr_entries; uint32_t pmu[MAX_PMU_ENTRIES]; }; static int scmi_set_cpugrp_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 msg_id) { int ret = 0; struct scmi_xfer *t; struct node_msg *msg; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_set_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_set_cpugrp_mon(handle, cpus_mpidr, mon_type, MEMLAT_SET_MONITOR); } static int scmi_set_cpu_grp(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_set_cpugrp_mon(handle, cpus_mpidr, mon_type, MEMLAT_SET_CPU_GROUP); } static int scmi_send_pmu_map_command(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf, u32 msg_id) { int ret, i = 0; struct scmi_xfer *t; struct pmu_map_msg *msg; u32 *dst; struct map_table *src = buf; if (nr_entries > MAX_PMU_ENTRIES) return -EINVAL; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); msg->nr_entries = cpu_to_le32(nr_entries); dst = msg->pmu; for (i = 0; i < nr_entries; i++) dst[i] = cpu_to_le32(src[i].v2); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_common_pmu_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf) { return scmi_send_pmu_map_command(handle, cpus_mpidr, mon_type, nr_entries, buf, MEMLAT_COMMON_PMU_MAP); } static int scmi_mon_pmu_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 nr_entries, void *buf) { return scmi_send_pmu_map_command(handle, cpus_mpidr, mon_type, nr_entries, buf, MEMLAT_MON_PMU_MAP); } static int scmi_freq_map(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, 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 = scmi_xfer_get_init(handle, MEMLAT_MON_FREQ_MAP, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); 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 = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } #define scmi_send_cmd(name, _msg_id) \ static int scmi_##name(const struct scmi_handle *handle, \ u32 cpus_mpidr, u32 mon_type, u32 val) \ { \ int ret = 0; \ struct scmi_xfer *t; \ struct scalar_param_msg *msg; \ ret = scmi_xfer_get_init(handle, _msg_id, \ SCMI_PROTOCOL_MEMLAT, \ sizeof(*msg), sizeof(*msg), &t); \ if (ret) \ return ret; \ msg = t->tx.buf; \ msg->cpumask = cpu_to_le32(cpus_mpidr); \ msg->mon_type = cpu_to_le32(mon_type); \ msg->val = cpu_to_le32(val); \ ret = scmi_do_xfer(handle, t); \ scmi_xfer_put(handle, t); \ return ret; \ } \ scmi_send_cmd(ratio_ceil, MEMLAT_RATIO_CEIL); scmi_send_cmd(stall_floor, MEMLAT_STALL_FLOOR); scmi_send_cmd(l2wb_pct, MEMLAT_L3_L2WB_PCT); scmi_send_cmd(l2wb_filter, MEMLAT_L3_IPM_FILTER); scmi_send_cmd(sample_ms, MEMLAT_SAMPLE_MS); scmi_send_cmd(min_freq, MEMLAT_SET_MIN_FREQ); scmi_send_cmd(max_freq, MEMLAT_SET_MAX_FREQ); static int scmi_send_start_stop(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type, u32 msg_id) { int ret = 0; struct scmi_xfer *t; struct scalar_param_msg *msg; ret = scmi_xfer_get_init(handle, msg_id, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), sizeof(*msg), &t); if (ret) return ret; msg = t->tx.buf; msg->cpumask = cpu_to_le32(cpus_mpidr); msg->mon_type = cpu_to_le32(mon_type); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static int scmi_stop_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_send_start_stop(handle, cpus_mpidr, mon_type, MEMLAT_STOP_MONITOR); } static int scmi_start_mon(const struct scmi_handle *handle, u32 cpus_mpidr, u32 mon_type) { return scmi_send_start_stop(handle, cpus_mpidr, mon_type, MEMLAT_START_MONITOR); } static int scmi_get_data(const struct scmi_handle *handle, u8 *buf) { int ret = 0; struct scmi_xfer *t; u32 prev_cnt = 0; struct scalar_param_msg *msg; ret = scmi_xfer_get_init(handle, MEMLAT_GET_DATA, SCMI_PROTOCOL_MEMLAT, sizeof(*msg), SCMI_MAX_RX_SIZE, &t); if (ret) return ret; do { ret = scmi_do_xfer(handle, t); if (ret == -ETIMEDOUT) ret = scmi_do_xfer(handle, t); if (ret < 0) break; memcpy((buf + prev_cnt), t->rx.buf, t->rx.len); prev_cnt += t->rx.len; } while (t->rx.len >= SCMI_MAX_GET_DATA_SIZE); scmi_xfer_put(handle, t); return ret; } static int scmi_set_log_level(const struct scmi_handle *handle, u32 val) { int ret = 0; struct scmi_xfer *t; u32 *ptr; ret = scmi_xfer_get_init(handle, MEMLAT_SET_LOG_LEVEL, SCMI_PROTOCOL_MEMLAT, sizeof(u32), sizeof(u32), &t); if (ret) return ret; ptr = (u32 *)t->tx.buf; *ptr = cpu_to_le32(val); ret = scmi_do_xfer(handle, t); scmi_xfer_put(handle, t); return ret; } static struct scmi_memlat_vendor_ops memlat_ops = { .set_cpu_grp = scmi_set_cpu_grp, .freq_map = scmi_freq_map, .set_mon = scmi_set_mon, .common_pmu_map = scmi_common_pmu_map, .mon_pmu_map = scmi_mon_pmu_map, .ratio_ceil = scmi_ratio_ceil, .stall_floor = scmi_stall_floor, .sample_ms = scmi_sample_ms, .l2wb_filter = scmi_l2wb_filter, .l2wb_pct = scmi_l2wb_pct, .min_freq = scmi_min_freq, .max_freq = scmi_max_freq, .start_monitor = scmi_start_mon, .stop_monitor = scmi_stop_mon, .set_log_level = scmi_set_log_level, .get_data = scmi_get_data, }; static int scmi_memlat_vendor_protocol_init(struct scmi_handle *handle) { u32 version; scmi_version_get(handle, SCMI_PROTOCOL_MEMLAT, &version); dev_dbg(handle->dev, "memlat version %d.%d\n", PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); handle->memlat_ops = &memlat_ops; return 0; } static int __init scmi_memlat_init(void) { return scmi_protocol_register(SCMI_PROTOCOL_MEMLAT, &scmi_memlat_vendor_protocol_init); } subsys_initcall(scmi_memlat_init);
drivers/soc/qcom/Kconfig +46 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,16 @@ config QCOM_IPCC Say Y here to compile the driver as a part of kernel or M to compile as a module. config QCOM_RIMPS tristate "Qualcomm Technologies, Inc. Rimps driver" depends on MAILBOX help Qualcomm Technologies, Inc. RIMPS driver for MSM devices. This driver acts as a mailbox controller to do doorbell between Apss and Rimps subsystem. Say yes here to enable rx and tx channel between both the subsystems. If unsure, say n. config QCOM_LLCC tristate "Qualcomm Technologies, Inc. LLCC driver" depends on ARCH_QCOM || COMPILE_TEST Loading Loading @@ -710,6 +720,42 @@ config QTI_SYSTEM_PM config QTI_SYSTEM_PM_RPM bool config QTI_HW_MEMLAT tristate "Qualcomm Technologies Inc. RIMPS memlat interface driver" depends on PERF_EVENTS default n help Interface driver between RIMPS memlat and userspace. This driver is responsible for handling the communication with RIMPS memlat such as setting up PMU events, passing tunables, frequency table, PMU counters and saving the values of PMU counters during LPM and hotplug. config QTI_HW_MEMLAT_SCMI_CLIENT tristate "Qualcomm Technologies Inc. SCMI client driver for HW MEMLAT" depends on QTI_HW_MEMLAT default n help SCMI client driver registers itself with SCMI framework for memlat vendor protocol, and also registers with the memlat hw interface driver. This driver deliver the memlat vendor protocol handle to interface driver, and interface driver will use this handle to communicate with memlat HW. config QTI_HW_MEMLAT_LOG tristate "Qualcomm Technologies Inc. HW MEMLAT Logging" depends on IPC_LOGGING && QCOM_RIMPS default n help Memlat hw logging driver, this driver has the infra to collect logs generated in MEMLAT HW and log the buffers. This driver register with IPC_Logging framework, to have dedicated buffer for memlat hw device. if MSM_PM menuconfig MSM_IDLE_STATS bool "Collect idle statistics" Loading