+}
+
+static int scmi_common_pmu_map(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 nr_entries, void *buf)
+{
+ return scmi_send_pmu_map_command(ph, cpus_mpidr, mon_type, nr_entries,
+ buf, MEMLAT_COMMON_PMU_MAP);
+}
+
+static int scmi_mon_pmu_map(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 nr_entries, void *buf)
+{
+ return scmi_send_pmu_map_command(ph, cpus_mpidr, mon_type, nr_entries,
+ buf, MEMLAT_MON_PMU_MAP);
+}
+
+static int scmi_freq_map(const struct scmi_protocol_handle *ph, 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 = ph->xops->xfer_get_init(ph, MEMLAT_MON_FREQ_MAP, 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 = 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 cpus_mpidr,
+ u32 msg_id, u32 mon_type, 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->cpumask = cpu_to_le32(cpus_mpidr);
+ msg->mon_type = cpu_to_le32(mon_type);
+ msg->val = cpu_to_le32(val);
+ ret = ph->xops->do_xfer(ph, t);
+ ph->xops->xfer_put(ph, t);
+
+ return ret;
+}
+
+static int scmi_ipm_ratio(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val)
+{
+ return scmi_set_tunable(ph, cpus_mpidr, MEMLAT_IPM_RATIO, mon_type, val);
+}
+
+static int scmi_stall_ratio(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val)
+{
+ return scmi_set_tunable(ph, cpus_mpidr, MEMLAT_STALL_RATIO, mon_type, val);
+}
+
+static int scmi_sample_ms(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val)
+{
+ return scmi_set_tunable(ph, cpus_mpidr, MEMLAT_SAMPLE_MS, mon_type, val);
+}
+
+static int scmi_send_start_stop(const struct scmi_protocol_handle *ph,
+ u32 cpus_mpidr, u32 mon_type, u32 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), 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 = ph->xops->do_xfer(ph, t);
+ ph->xops->xfer_put(ph, t);
+
+ return ret;
+}
+
+static int scmi_stop_mon(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type)
+{
+ return scmi_send_start_stop(ph, cpus_mpidr, mon_type, MEMLAT_STOP_MONITOR);
+}
+
+static int scmi_start_mon(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type)
+{
+ return scmi_send_start_stop(ph, cpus_mpidr, mon_type, MEMLAT_START_MONITOR);
+}
+
+static struct scmi_vendor_memlat_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,
+ .ipm_ratio = scmi_ipm_ratio,
+ .stall_ratio = scmi_stall_ratio,
+ .sample_ms = scmi_sample_ms,
+ .start_monitor = scmi_start_mon,
+ .stop_monitor = scmi_stop_mon,
+};
+
+static int scmi_vendor_memlat_protocol_init(const struct scmi_protocol_handle *ph)
+{
+ int ret;
+ u32 version;
+
+ ret = ph->xops->version_get(ph, &version);
+ if (ret)
+ return ret;
+
+ 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_vendor_memlat = {
+ .id = SCMI_VENDOR_PROTOCOL_MEMLAT,
+ .owner = THIS_MODULE,
+ .instance_init = &scmi_vendor_memlat_protocol_init,
+ .ops = &memlat_ops,
+};
+module_scmi_protocol(scmi_vendor_memlat);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCMI Memlat Protocol");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 4f765bc788ff..57abb5be45c9 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -677,6 +677,40 @@ struct scmi_powercap_proto_ops {
};
/**
+ * struct scmi_vendor_memlat_ops - represents the various operations provided
+ * by SCMI QTI HW Memlat Vendor Protocol
+ *
+ * @cpu_grp: set the cpugrp
+ * @set_mon: set the supported monitors
+ * @common_pmu_map: sets the common PMU map supported by governor
+ * @mon_pmu_map: sets the additional PMU map supported by governor
+ * @ipm_ratio: sets the ratio_ceil needed for hw memlat governor
+ * @stall_ratio: sets the stall_floor needed for hw memlat governor
+ * @sample_ms: sets the poll iterval of the governor
+ * @freq_map: sets the freq_map of the governor
+ * @start_mon: starts the monitor in firmware
+ * @stop_mon: stops the monitor in firmware
+ */
+struct scmi_vendor_memlat_ops {
+ int (*set_cpu_grp)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type);
+ int (*set_mon)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type);
+ int (*common_pmu_map)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type,
+ u32 nr_rows, void *buf);
+ int (*mon_pmu_map)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type,
+ u32 nr_rows, void *buf);
+ int (*ipm_ratio)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val);
+ int (*stall_ratio)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val);
+ int (*sample_ms)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr,
+ u32 mon_type, u32 val);
+ int (*freq_map)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type,
+ u32 nr_rows, void *buf);
+ int (*start_monitor)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type);
+ int (*stop_monitor)(const struct scmi_protocol_handle *ph, u32 cpus_mpidr, u32 mon_type);
+};
+
+/**
* struct scmi_notify_ops - represents notifications' operations provided by
* SCMI core
* @devm_event_notifier_register: Managed registration of a notifier_block for
@@ -785,6 +819,8 @@ enum scmi_std_protocol {
SCMI_PROTOCOL_POWERCAP = 0x18,
};
+#define SCMI_VENDOR_PROTOCOL_MEMLAT 0x80
+
enum scmi_system_events {
SCMI_SYSTEM_SHUTDOWN,
SCMI_SYSTEM_COLDRESET,
--
2.7.4