diff --git a/android/ACK_SHA b/android/ACK_SHA
index 85bd64718859..2272aff17b9e 100644
--- a/android/ACK_SHA
+++ b/android/ACK_SHA
@@ -1,2 +1,2 @@
-c02e95e82b343fe03d03dfd6fb74ecc2077e1ee3
-android12-5.10-2024-05_r1
+7e657aa362f21c8fb472e03a22795b18f831a178
+android12-5.10-2024-08_r1
diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml
index 3f244f8788a6..86f118c8f763 100755
--- a/android/abi_gki_aarch64.xml
+++ b/android/abi_gki_aarch64.xml
@@ -78522,9 +78522,9 @@
-
+
-
+
diff --git a/arch/arm64/configs/vendor/anorak.config b/arch/arm64/configs/vendor/anorak.config
index 008d477727fa..b80d891fa271 100644
--- a/arch/arm64/configs/vendor/anorak.config
+++ b/arch/arm64/configs/vendor/anorak.config
@@ -214,6 +214,7 @@ CONFIG_PWM_QTI_LPG=m
CONFIG_QCOM_AOSS_QMP=m
CONFIG_QCOM_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_QCOM_BAM_DMA=m
+CONFIG_QCOM_BUS_PROF=m
CONFIG_QCOM_BWMON=m
CONFIG_QCOM_BWPROF=m
# CONFIG_QCOM_CLK_APCC_MSM8996 is not set
@@ -249,6 +250,7 @@ CONFIG_QCOM_KGSL_CONTEXT_DEBUG=y
CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT=y
CONFIG_QCOM_LAZY_MAPPING=m
CONFIG_QCOM_LLCC=m
+CONFIG_QCOM_LLCC_MISS=m
CONFIG_QCOM_LLCC_PERFMON=m
CONFIG_QCOM_LLCC_PMU=m
CONFIG_QCOM_LOGBUF_VENDOR_HOOKS=m
diff --git a/arch/arm64/configs/vendor/neo_le.config b/arch/arm64/configs/vendor/neo_le.config
index b41fd7d82eaa..071b6b06a521 100644
--- a/arch/arm64/configs/vendor/neo_le.config
+++ b/arch/arm64/configs/vendor/neo_le.config
@@ -369,6 +369,7 @@ CONFIG_REGMAP_QTI_DEBUGFS=m
CONFIG_REGMAP_SPMI=m
CONFIG_REGULATOR_DEBUG_CONTROL=y
CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QCOM_PM8008=m
CONFIG_REGULATOR_QCOM_RPMH=m
CONFIG_REGULATOR_QTI_FIXED_VOLTAGE=y
CONFIG_REGULATOR_RPMH=m
diff --git a/drivers/clk/qcom/gcc-anorak.c b/drivers/clk/qcom/gcc-anorak.c
index 29ad24fc2e8c..72e801e8460b 100644
--- a/drivers/clk/qcom/gcc-anorak.c
+++ b/drivers/clk/qcom/gcc-anorak.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2022, 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include
@@ -3773,6 +3773,7 @@ static struct clk_branch gcc_usb2_0_clkref_en = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb2_0_clkref_en",
+ .flags = CLK_DONT_HOLD_STATE,
.ops = &clk_branch2_ops,
},
},
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index d632150a8012..f7ab766f6b5b 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -528,18 +528,15 @@ int __qcom_scm_set_dload_mode(struct device *dev, enum qcom_download_mode mode)
void qcom_scm_set_download_mode(enum qcom_download_mode mode,
phys_addr_t tcsr_boot_misc)
{
- bool avail;
int ret = 0;
struct device *dev = __scm ? __scm->dev : NULL;
- avail = __qcom_scm_is_call_available(dev,
- QCOM_SCM_SVC_BOOT,
- QCOM_SCM_BOOT_SET_DLOAD_MODE);
- if (avail) {
+ if (tcsr_boot_misc || (__scm && __scm->dload_mode_addr)) {
+ ret = qcom_scm_io_writel(tcsr_boot_misc ? : __scm->dload_mode_addr, mode);
+ } else if (__qcom_scm_is_call_available(dev,
+ QCOM_SCM_SVC_BOOT,
+ QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
ret = __qcom_scm_set_dload_mode(dev, mode);
- } else if (tcsr_boot_misc || (__scm && __scm->dload_mode_addr)) {
- ret = qcom_scm_io_writel(
- tcsr_boot_misc ? : __scm->dload_mode_addr, mode);
} else {
dev_err(dev,
"No available mechanism for setting download mode\n");
@@ -806,6 +803,34 @@ int qcom_scm_get_sec_dump_state(u32 *dump_state)
}
EXPORT_SYMBOL(qcom_scm_get_sec_dump_state);
+int __qcom_scm_get_llcc_missrate(struct device *dev, phys_addr_t in_buf,
+ size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MISSRATE,
+ .cmd = QCOM_SCM_GET_LLCC_MISSRATE_STATS_ID,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL),
+ };
+
+ desc.args[0] = in_buf;
+ desc.args[1] = in_buf_size;
+ desc.args[2] = out_buf;
+ desc.args[3] = out_buf_size;
+ ret = qcom_scm_call(dev, &desc, NULL);
+
+ return ret;
+}
+
+int qcom_scm_get_llcc_missrate(phys_addr_t in_buf,
+ size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size)
+{
+ return __qcom_scm_get_llcc_missrate(__scm ? __scm->dev : NULL, in_buf,
+ in_buf_size, out_buf, out_buf_size);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_get_llcc_missrate);
+
int qcom_scm_assign_dump_table_region(bool is_assign, phys_addr_t addr, size_t size)
{
struct qcom_scm_desc desc = {
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index be0a33414813..08e60c3f1854 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -231,6 +231,9 @@ int qcom_scm_handle_wait(struct device *dev, int scm_ret,
#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01
#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
+#define QCOM_SCM_GET_LLCC_MISSRATE_STATS_ID 0x14
+#define QCOM_SCM_SVC_MISSRATE 0x06
+
extern void __qcom_scm_init(void);
/* common error codes */
diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c
index 8a5e02e09e56..6fb34fd766ea 100644
--- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c
+++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c
@@ -146,11 +146,6 @@ static void log_profiling_info(struct adreno_device *adreno_dev, u32 *rcvd)
if (context == NULL)
return;
- /* protected GPU work must not be reported */
- if (!(context->flags & KGSL_CONTEXT_SECURE))
- kgsl_work_period_update(device, context->proc_priv->period,
- cmd->active);
-
info.timestamp = cmd->ts;
info.rb_id = adreno_get_level(context);
info.gmu_dispatch_queue = context->gmu_dispatch_queue;
@@ -163,6 +158,10 @@ static void log_profiling_info(struct adreno_device *adreno_dev, u32 *rcvd)
info.active = cmd->active;
info.retired_on_gmu = cmd->retired_on_gmu;
+ /* protected GPU work must not be reported */
+ if (!(context->flags & KGSL_CONTEXT_SECURE))
+ kgsl_work_period_update(device, context->proc_priv->period, info.active);
+
trace_adreno_cmdbatch_retired(context, &info, 0, 0, 0);
log_kgsl_cmdbatch_retired_event(context->id, cmd->ts, context->priority,
diff --git a/drivers/i2c/busses/i2c-msm-geni.c b/drivers/i2c/busses/i2c-msm-geni.c
index c0a746f07b16..ba803e94c2d7 100644
--- a/drivers/i2c/busses/i2c-msm-geni.c
+++ b/drivers/i2c/busses/i2c-msm-geni.c
@@ -799,8 +799,16 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str,
void *ptr)
{
- struct geni_i2c_dev *gi2c = ptr;
- u32 m_stat = cb_str->status;
+ struct geni_i2c_dev *gi2c;
+ u32 m_stat;
+
+ if (!ptr || !cb_str) {
+ pr_err("%s: Invalid ev_cb buffer\n", __func__);
+ return;
+ }
+
+ gi2c = (struct geni_i2c_dev *)ptr;
+ m_stat = cb_str->status;
switch (cb_str->cb_event) {
case MSM_GPI_QUP_ERROR:
diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c
index 1edfb2fffa83..dda4b8f9c331 100644
--- a/drivers/interconnect/qcom/icc-rpmh.c
+++ b/drivers/interconnect/qcom/icc-rpmh.c
@@ -324,8 +324,8 @@ static struct regmap *qcom_icc_rpmh_map(struct platform_device *pdev,
static bool is_voter_disabled(char *voter)
{
- if ((strnstr(voter, "disp", strlen(voter)) &&
- (socinfo_get_part_info(PART_DISPLAY) || socinfo_get_part_info(PART_DISPLAY1))) ||
+ if ((!strcmp(voter, "disp") && socinfo_get_part_info(PART_DISPLAY)) ||
+ (!strcmp(voter, "disp2") && socinfo_get_part_info(PART_DISPLAY1)) ||
(strnstr(voter, "cam", strlen(voter)) && socinfo_get_part_info(PART_CAMERA)))
return true;
@@ -359,7 +359,12 @@ static int qcom_icc_init_disabled_parts(struct qcom_icc_provider *qp)
if (!qn)
continue;
- if (strnstr(qn->name, voter_name, strlen(qn->name)))
+ /*
+ * Find the ICC node to be disabled by comparing voter_name in
+ * node name string, adjust the start position accordingly
+ */
+ if (!strcmp(qn->name + (strlen(qn->name) - strlen(voter_name)),
+ voter_name))
qn->disabled = true;
}
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c543550f2b82..76a2948a584d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -8509,7 +8509,9 @@ static int qseecom_release(struct inode *inode, struct file *file)
static const struct file_operations qseecom_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = qseecom_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = compat_qseecom_ioctl,
+#endif
.open = qseecom_open,
.release = qseecom_release
};
diff --git a/drivers/power/reset/qcom-dload-mode.c b/drivers/power/reset/qcom-dload-mode.c
index 46b86d92bc20..8af5318d526f 100644
--- a/drivers/power/reset/qcom-dload-mode.c
+++ b/drivers/power/reset/qcom-dload-mode.c
@@ -98,7 +98,9 @@ static int param_set_download_mode(const char *val,
if (ret)
return ret;
- msm_enable_dump_mode(true);
+ msm_enable_dump_mode(enable_dump);
+ if (!enable_dump)
+ qcom_scm_disable_sdi();
return 0;
}
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 1ab2a70cc17d..809b1fb209a6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -1171,6 +1171,7 @@ config QCOM_HUNG_TASK_ENH
config QCOM_SMCINVOKE
tristate "Secure QSEE Support"
+ depends on QCOM_SCM && QCOM_MEM_BUF
help
Enable SMCInvoke driver which supports capability based secure
communication between QTI Secure Execution Environment (QSEE)
diff --git a/drivers/soc/qcom/dcvs/Kconfig b/drivers/soc/qcom/dcvs/Kconfig
index 3e541bc5e8e4..3d0dc6343685 100644
--- a/drivers/soc/qcom/dcvs/Kconfig
+++ b/drivers/soc/qcom/dcvs/Kconfig
@@ -76,6 +76,29 @@ config QTI_HW_MEMLAT_SCMI_CLIENT
driver, and interface driver will use this handle to communicate with
memlat HW.
+config QCOM_LLCC_MISS
+ tristate "Qualcomm Technologies Inc. LLCC_MISS_STATS Driver"
+ depends on ARCH_QCOM && QCOM_BUS_PROF
+ default n
+ help
+ This enables the QCOM LLCC miss stats driver which exposes LLCC miss
+ stats to user space clients at modest time intervals for the intention
+ of profiling.
+
+ The purpose of the driver is to enable the monitoring of LLCC misses
+ at regular intervals and providing the miss rate data to the user
+ space clients upon read.
+
+config QCOM_BUS_PROF
+ tristate "Qualcomm Technologies Inc. BUS_PROF Driver"
+ depends on ARCH_QCOM
+ default n
+ help
+ This enables the QCOM bus profiling common framework and ftraces,
+ which provide support for a variety of features. These features
+ include memory latency, LLCC miss, and LLCC occupancy, all of
+ which are supported on certain Qualcomm Technologies, Inc.
+ (QTI) chipsets.
config QTI_PMU_SCMI_CLIENT
tristate "Qualcomm Technologies Inc. SCMI client driver for PMU"
diff --git a/drivers/soc/qcom/dcvs/Makefile b/drivers/soc/qcom/dcvs/Makefile
index af0ca145d33e..8b1627f27647 100644
--- a/drivers/soc/qcom/dcvs/Makefile
+++ b/drivers/soc/qcom/dcvs/Makefile
@@ -7,6 +7,8 @@ qcom-dcvs-y := dcvs.o dcvs_icc.o dcvs_epss.o trace-dcvs.o
obj-$(CONFIG_QCOM_MEMLAT) += memlat.o
obj-$(CONFIG_QCOM_BWMON) += bwmon.o
obj-$(CONFIG_QCOM_BWPROF) += bwprof.o
+obj-$(CONFIG_QCOM_BUS_PROF) += trace-bus-prof.o
+obj-$(CONFIG_QCOM_LLCC_MISS) += llcc_miss.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
diff --git a/drivers/soc/qcom/dcvs/bus_prof.h b/drivers/soc/qcom/dcvs/bus_prof.h
new file mode 100644
index 000000000000..9c9985d2acd0
--- /dev/null
+++ b/drivers/soc/qcom/dcvs/bus_prof.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include
+
+#ifndef _QCOM_BUS_PROF_H
+#define _QCOM_BUS_PROF_H
+#define MAX_CONCURRENT_MASTERS 2
+struct llcc_miss_buf {
+ u8 master_id;
+ uint16_t miss_info;
+ u32 rd_miss;
+ u32 wr_miss;
+ u32 all_access;
+} __packed;
+
+#endif /* _QCOM_BUS_PROF_H */
diff --git a/drivers/soc/qcom/dcvs/llcc_miss.c b/drivers/soc/qcom/dcvs/llcc_miss.c
new file mode 100644
index 000000000000..dbfdea250ce9
--- /dev/null
+++ b/drivers/soc/qcom/dcvs/llcc_miss.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "bus_prof.h"
+#include "trace-bus-prof.h"
+
+#define SAMPLE_MS 10
+#define DDR_OUT_BUF_MAGIC (0xDD4)
+
+enum cmd {
+ LLCC_MISS_START_PROFILING = 1,
+ LLCC_MISS_GET_DATA = 2,
+ LLCC_MISS_STOP_PROFILING = 3,
+};
+
+enum error {
+ E_SUCCESS = 0, /* Operation successful */
+ E_FAILURE = 1, /* Operation failed due to unknown err*/
+ E_NULL_PARAM = 2,/* Null Parameter */
+ E_INVALID_ARG = 3,/* Arg is not recognized */
+ E_BAD_ADDRESS = 4,/* Ptr arg is bad address */
+ E_INVALID_ARG_LEN = 5,/* Arg length is wrong */
+ E_NOT_SUPPORTED = 6,/* Operation not supported */
+ E_UNINITIALIZED = 7,/* Operation not permitted on platform */
+ E_PARTIAL_DUMP = 8,/* Operation not permitted right now */
+ E_RESERVED = 0x7FFFFFFF
+};
+
+enum llcc_miss_masters {
+ CPU = 0,
+ GPU,
+ NSP,
+ MAX_MASTER,
+};
+
+static char *master_names[MAX_MASTER] = {"CPU", "GPU", "NSP"};
+
+struct llcc_miss_start_req {
+ u32 cmd_id;
+ u32 active_masters;
+} __packed;
+
+struct llcc_miss_resp {
+ u32 cmd_id;
+ enum error status;
+} __packed;
+
+struct llcc_miss_get_req {
+ u32 cmd_id;
+ u8 *buf_ptr;
+ u32 buf_size;
+ u32 type; /* Stop : 0, Reset : 1 */
+} __packed;
+
+struct llcc_miss_stop_req {
+ u32 cmd_id;
+} __packed;
+
+/* cmd_id is expected to be defined first for each member of the union */
+union llcc_miss_req {
+ struct llcc_miss_start_req start_req;
+ struct llcc_miss_get_req get_req;
+ struct llcc_miss_stop_req stop_req;
+} __packed;
+
+struct llcc_cmd_buf {
+ union llcc_miss_req llcc_miss_req;
+ struct llcc_miss_resp llcc_miss_resp;
+ u32 req_size;
+} __packed;
+
+struct llcc_miss_data {
+ struct llcc_miss_buf master_buf[MAX_CONCURRENT_MASTERS];
+ enum error err;
+ u16 magic;
+ u64 qtime;
+} __packed;
+
+struct miss_sample {
+ u64 ts;
+ u16 measured_miss_rate;
+} __packed;
+
+struct llcc_miss_dev_data {
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct hrtimer hrtimer;
+ u16 max_samples;
+ u16 size_of_line;
+ u32 active_masters;
+ u32 available_masters;
+ struct llcc_miss_data *data;
+ struct mutex lock;
+};
+
+struct master_data {
+ u16 curr_idx;
+ u16 unread_samples;
+ struct miss_sample *miss_data;
+ char buf[PAGE_SIZE];
+};
+
+static struct master_data mdata[MAX_MASTER];
+static struct dentry *llcc_miss_dir;
+static struct llcc_miss_dev_data *llcc_miss;
+
+static ssize_t get_last_samples(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int index = 0, ret = 0, m_idx;
+ int i = 0, size = 0, enable;
+ char *master_name;
+
+ mutex_lock(&llcc_miss->lock);
+ if (!llcc_miss->active_masters) {
+ pr_err("No master is enabled for mem miss\n");
+ goto unlock;
+ }
+ master_name = file->private_data;
+ for (m_idx = 0; m_idx < MAX_MASTER ; m_idx++) {
+ if (!strcasecmp(master_names[m_idx], master_name))
+ break;
+ }
+
+ enable = (llcc_miss->active_masters & BIT(m_idx));
+ if (!enable) {
+ pr_err("%s memory miss is not enabled\n", master_names[m_idx]);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ index = (mdata[m_idx].curr_idx - mdata[m_idx].unread_samples +
+ llcc_miss->max_samples) % llcc_miss->max_samples;
+ for (i = 0; i < mdata[m_idx].unread_samples; i++) {
+ size += scnprintf(mdata[m_idx].buf + size, PAGE_SIZE - size,
+ "%llx\t%x\n", mdata[m_idx].miss_data[index].ts,
+ mdata[m_idx].miss_data[index].measured_miss_rate);
+ index = (index + 1) % llcc_miss->max_samples;
+ }
+
+ mdata[m_idx].unread_samples = 0;
+ ret = simple_read_from_buffer(user_buf, count, ppos, mdata[m_idx].buf, size);
+unlock:
+ mutex_unlock(&llcc_miss->lock);
+
+ return ret;
+}
+
+static int send_llcc_miss_profiling_command(const void *req)
+{
+ int ret = 0;
+ u32 qseos_cmd_id = 0;
+ struct llcc_miss_resp *rsp = NULL;
+ size_t req_size = 0, rsp_size = 0;
+ struct qtee_shm shm = {0};
+
+ if (!req)
+ return -EINVAL;
+ rsp = &((struct llcc_cmd_buf *)req)->llcc_miss_resp;
+ rsp_size = sizeof(struct llcc_miss_resp);
+ req_size = ((struct llcc_cmd_buf *)req)->req_size;
+ qseos_cmd_id = *(u32 *)req;
+ ret = qtee_shmbridge_allocate_shm(PAGE_ALIGN(req_size + rsp_size), &shm);
+ if (ret) {
+ pr_err("qtee_shmbridge_allocate_shm failed, ret :%d\n", ret);
+ return -ENOMEM;
+ }
+
+ memcpy(shm.vaddr, req, req_size);
+ qtee_shmbridge_flush_shm_buf(&shm);
+ switch (qseos_cmd_id) {
+ case LLCC_MISS_START_PROFILING:
+ case LLCC_MISS_GET_DATA:
+ case LLCC_MISS_STOP_PROFILING:
+ /* Send the command to TZ */
+ ret = qcom_scm_get_llcc_missrate(shm.paddr, req_size,
+ shm.paddr + req_size, rsp_size);
+ break;
+ default:
+ pr_err("cmd_id %d is not supported.\n",
+ qseos_cmd_id);
+ ret = -EINVAL;
+ }
+
+ qtee_shmbridge_inv_shm_buf(&shm);
+ memcpy(rsp, (char *)shm.vaddr + req_size, rsp_size);
+ qtee_shmbridge_free_shm(&shm);
+ /* Verify cmd id and Check that request succeeded. */
+ if (rsp->status != 0 ||
+ qseos_cmd_id != rsp->cmd_id) {
+ ret = -1;
+ pr_err("Status: %d,Cmd: %d\n",
+ rsp->status,
+ rsp->cmd_id);
+ }
+
+ return ret;
+}
+
+static int start_memory_miss_stats(void)
+{
+ int ret = 0;
+ struct llcc_cmd_buf *llcc_cmd_buf = NULL;
+
+ llcc_cmd_buf = kzalloc(sizeof(*llcc_cmd_buf), GFP_KERNEL);
+ if (!llcc_cmd_buf)
+ return -ENOMEM;
+ llcc_cmd_buf->llcc_miss_req.start_req.cmd_id = LLCC_MISS_START_PROFILING;
+ llcc_cmd_buf->llcc_miss_req.start_req.active_masters = llcc_miss->active_masters;
+ llcc_cmd_buf->req_size = sizeof(struct llcc_miss_start_req);
+ ret = send_llcc_miss_profiling_command(llcc_cmd_buf);
+ if (ret) {
+ pr_err("Error in %s, ret = %d\n", __func__, ret);
+ goto out;
+ }
+
+ if (!hrtimer_active(&llcc_miss->hrtimer))
+ hrtimer_start(&llcc_miss->hrtimer,
+ ms_to_ktime(SAMPLE_MS), HRTIMER_MODE_REL_PINNED);
+out:
+ kfree(llcc_cmd_buf);
+
+ return ret;
+}
+
+static int stop_memory_miss_stats(void)
+{
+ int ret;
+ struct llcc_cmd_buf *llcc_cmd_buf = NULL;
+
+ hrtimer_cancel(&llcc_miss->hrtimer);
+ cancel_work_sync(&llcc_miss->work);
+ llcc_cmd_buf = kzalloc(sizeof(*llcc_cmd_buf), GFP_KERNEL);
+ if (!llcc_cmd_buf)
+ return -ENOMEM;
+
+ llcc_cmd_buf->llcc_miss_req.stop_req.cmd_id = LLCC_MISS_STOP_PROFILING;
+ llcc_cmd_buf->req_size = sizeof(struct llcc_miss_stop_req);
+ ret = send_llcc_miss_profiling_command(llcc_cmd_buf);
+ if (ret)
+ pr_err("Error in %s, ret = %d\n", __func__, ret);
+
+ kfree(llcc_cmd_buf);
+
+ return 0;
+}
+
+static int set_mon_enabled(void *data, u64 val)
+{
+ char *master_name = data;
+ int i, ret = 0;
+ u32 count, enable = val ? 1 : 0;
+
+ mutex_lock(&llcc_miss->lock);
+ for (i = 0; i < MAX_MASTER; i++) {
+ if (!strcasecmp(master_names[i], master_name))
+ break;
+ }
+ if (enable == (llcc_miss->active_masters & BIT(i)))
+ goto unlock;
+ count = hweight32(llcc_miss->active_masters);
+ if (count >= MAX_CONCURRENT_MASTERS && enable) {
+ pr_err("Max masters already enabled\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+ mutex_unlock(&llcc_miss->lock);
+ if (count)
+ stop_memory_miss_stats();
+ mutex_lock(&llcc_miss->lock);
+ llcc_miss->active_masters = (llcc_miss->active_masters ^ BIT(i));
+ if (llcc_miss->active_masters)
+ start_memory_miss_stats();
+
+unlock:
+ mutex_unlock(&llcc_miss->lock);
+
+ return ret;
+}
+
+static int get_mon_enabled(void *data, u64 *val)
+{
+ char *master_name = data;
+ int i;
+
+ mutex_lock(&llcc_miss->lock);
+ for (i = 0; i < MAX_MASTER; i++) {
+ if (!strcasecmp(master_names[i], master_name))
+ break;
+ }
+
+ if (llcc_miss->active_masters & BIT(i))
+ *val = 1;
+ else
+ *val = 0;
+ mutex_unlock(&llcc_miss->lock);
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(set_mon_enabled_ops, get_mon_enabled, set_mon_enabled, "%llu\n");
+
+static const struct file_operations show_last_samples_ops = {
+ .read = get_last_samples,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+static void llcc_miss_update_work(struct work_struct *work)
+{
+ int ret = 0, i, m;
+ u16 magic;
+ struct llcc_cmd_buf *llcc_cmd_buf;
+ struct qtee_shm buf_shm = {0};
+ const int bufsize = sizeof(struct llcc_miss_data);
+
+ llcc_cmd_buf = kzalloc(sizeof(*llcc_cmd_buf), GFP_KERNEL);
+ if (!llcc_cmd_buf)
+ return;
+ ret = qtee_shmbridge_allocate_shm(PAGE_ALIGN(bufsize), &buf_shm);
+ if (ret) {
+ pr_err("shmbridge alloc buf failed\n");
+ return;
+ }
+
+ llcc_cmd_buf->llcc_miss_req.get_req.cmd_id = LLCC_MISS_GET_DATA;
+ llcc_cmd_buf->llcc_miss_req.get_req.buf_ptr = (u8 *)buf_shm.paddr;
+ llcc_cmd_buf->llcc_miss_req.get_req.buf_size = bufsize;
+ llcc_cmd_buf->llcc_miss_req.get_req.type = 1;
+ llcc_cmd_buf->req_size = sizeof(struct llcc_miss_get_req);
+ qtee_shmbridge_flush_shm_buf(&buf_shm);
+ ret = send_llcc_miss_profiling_command(llcc_cmd_buf);
+ if (ret) {
+ pr_err("send_llcc_miss_profiling_command failed\n");
+ goto err;
+ }
+
+ qtee_shmbridge_inv_shm_buf(&buf_shm);
+ memcpy(llcc_miss->data, (char *)buf_shm.vaddr, sizeof(*llcc_miss->data));
+ magic = llcc_miss->data->magic;
+ if (magic != DDR_OUT_BUF_MAGIC) {
+ pr_err("Expected magic value is %x but got %x\n", DDR_OUT_BUF_MAGIC, magic);
+ goto err;
+ }
+
+ mutex_lock(&llcc_miss->lock);
+ for (i = 0; i < MAX_CONCURRENT_MASTERS; i++) {
+ m = llcc_miss->data->master_buf[i].master_id;
+ if (m >= MAX_MASTER)
+ continue;
+ mdata[m].miss_data[mdata[m].curr_idx].ts = llcc_miss->data->qtime;
+ mdata[m].miss_data[mdata[m].curr_idx].measured_miss_rate =
+ llcc_miss->data->master_buf[i].miss_info;
+ mdata[m].unread_samples = min(++mdata[m].unread_samples, llcc_miss->max_samples);
+ mdata[m].curr_idx = (mdata[m].curr_idx + 1) % llcc_miss->max_samples;
+ }
+
+ trace_memory_miss_last_sample(llcc_miss->data->qtime,
+ &llcc_miss->data->master_buf[0],
+ &llcc_miss->data->master_buf[1]);
+
+ mutex_unlock(&llcc_miss->lock);
+err:
+ qtee_shmbridge_free_shm(&buf_shm);
+ kfree(llcc_cmd_buf);
+}
+
+static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
+{
+ ktime_t now = ktime_get();
+
+ queue_work(llcc_miss->wq, &llcc_miss->work);
+ hrtimer_forward(timer, now, ms_to_ktime(SAMPLE_MS));
+
+ return HRTIMER_RESTART;
+}
+
+static int llcc_miss_create_fs_entries(void)
+{
+ int i;
+ struct dentry *ret, *master_dir;
+
+ llcc_miss_dir = debugfs_create_dir("llcc_miss", 0);
+ if (IS_ERR(llcc_miss_dir)) {
+ pr_err("Debugfs directory creation failed for llcc_miss\n");
+ return PTR_ERR(llcc_miss_dir);
+ }
+
+ for (i = 0; i < MAX_MASTER; i++) {
+ master_dir = debugfs_create_dir(master_names[i], llcc_miss_dir);
+ if (IS_ERR(master_dir)) {
+ pr_err("Debugfs directory creation failed for %s\n", master_names[i]);
+ goto error_cleanup;
+ }
+
+ ret = debugfs_create_file("show_last_samples", 0400, master_dir,
+ master_names[i], &show_last_samples_ops);
+ if (IS_ERR(ret)) {
+ pr_err("Debugfs file creation failed for show_last_samples\n");
+ goto error_cleanup;
+ }
+
+ ret = debugfs_create_file("enable", 0644, master_dir,
+ master_names[i], &set_mon_enabled_ops);
+ if (IS_ERR(ret)) {
+ pr_err("Debugfs file creation failed for enable\n");
+ goto error_cleanup;
+ }
+ }
+
+ return 0;
+
+error_cleanup:
+ for (; i >= 0; i--)
+ debugfs_remove_recursive(debugfs_lookup(master_names[i], llcc_miss_dir));
+ debugfs_remove_recursive(llcc_miss_dir);
+
+ return -ENOENT;
+}
+
+static int __init qcom_llcc_miss_init(void)
+{
+ int ret, i, j;
+
+ llcc_miss = kzalloc(sizeof(*llcc_miss), GFP_KERNEL);
+ if (!llcc_miss)
+ return -ENOMEM;
+ llcc_miss->data = kzalloc(sizeof(*llcc_miss->data), GFP_KERNEL);
+ if (!llcc_miss->data) {
+ kfree(llcc_miss);
+ return -ENOMEM;
+ }
+ for (i = 0; i < MAX_MASTER; i++)
+ llcc_miss->available_masters |= BIT(i);
+ ret = llcc_miss_create_fs_entries();
+ if (ret < 0)
+ goto err;
+
+ /*
+ * to get no of hex char in a line multiplying size of struct miss_sample by 2
+ * and adding 1 for tab and 1 for newline.
+ * output format is qtime followed by miss data in hexa,example -> 32c7bd2 a
+ */
+ llcc_miss->size_of_line = sizeof(struct miss_sample) * 2 + 2;
+ llcc_miss->max_samples = PAGE_SIZE / llcc_miss->size_of_line;
+ for (i = 0; i < MAX_MASTER; i++) {
+ mdata[i].miss_data = kcalloc(llcc_miss->max_samples,
+ sizeof(struct miss_sample), GFP_KERNEL);
+ if (!mdata[i].miss_data) {
+ ret = -ENOMEM;
+ goto debugfs_file_err;
+ }
+ }
+
+ mutex_init(&llcc_miss->lock);
+ hrtimer_init(&llcc_miss->hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ llcc_miss->hrtimer.function = hrtimer_handler;
+ llcc_miss->wq = create_freezable_workqueue("llcc_miss_wq");
+ if (!llcc_miss->wq) {
+ pr_err("Couldn't create llcc_miss workqueue.\n");
+ ret = -ENOMEM;
+ goto debugfs_file_err;
+ }
+
+ INIT_WORK(&llcc_miss->work, &llcc_miss_update_work);
+
+ return ret;
+
+debugfs_file_err:
+ for (j = 0; j < i; j++)
+ kfree(mdata[j].miss_data);
+ debugfs_remove_recursive(llcc_miss_dir);
+err:
+ kfree(llcc_miss->data);
+ kfree(llcc_miss);
+
+ return ret;
+}
+
+module_init(qcom_llcc_miss_init);
+
+MODULE_DESCRIPTION("QCOM LLCC_MISS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/dcvs/trace-bus-prof.c b/drivers/soc/qcom/dcvs/trace-bus-prof.c
new file mode 100644
index 000000000000..2f7988eaaae9
--- /dev/null
+++ b/drivers/soc/qcom/dcvs/trace-bus-prof.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace-bus-prof.h"
+
+
+EXPORT_TRACEPOINT_SYMBOL(memory_miss_last_sample);
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/dcvs/trace-bus-prof.h b/drivers/soc/qcom/dcvs/trace-bus-prof.h
new file mode 100644
index 000000000000..9bd5b02c9522
--- /dev/null
+++ b/drivers/soc/qcom/dcvs/trace-bus-prof.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM bus_prof
+
+#if !defined(_TRACE_BUS_PROF_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_BUS_PROF_H
+#include "bus_prof.h"
+#include
+
+TRACE_EVENT(memory_miss_last_sample,
+
+ TP_PROTO(u64 qtime, struct llcc_miss_buf *master_buf0, struct llcc_miss_buf *master_buf1),
+
+ TP_ARGS(qtime, master_buf0, master_buf1),
+
+ TP_STRUCT__entry(
+ __field(u64, qtime)
+ __field(u8, master1)
+ __field(u16, miss1)
+ __field(u8, master2)
+ __field(u16, miss2)
+ ),
+
+ TP_fast_assign(
+ __entry->qtime = qtime;
+ __entry->master1 = master_buf0->master_id;
+ __entry->miss1 = master_buf0->miss_info;
+ __entry->master2 = master_buf1->master_id;
+ __entry->miss2 = master_buf1->miss_info;
+ ),
+
+ TP_printk("qtime=%llu master1=%u miss1=%u master2=%u miss2=%u",
+ __entry->qtime,
+ __entry->master1,
+ __entry->miss1,
+ __entry->master2,
+ __entry->miss2)
+);
+#endif /* _TRACE_BUS_PROF_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/soc/qcom/dcvs
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-bus-prof
+
+#include
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
index e6e65c985daf..8fe14a60da1d 100644
--- a/drivers/soc/qcom/smcinvoke.c
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -2851,6 +2851,9 @@ static int smcinvoke_probe(struct platform_device *pdev)
unsigned int count = 1;
int rc = 0;
+ if (!qcom_scm_is_available())
+ return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "qcom_scm is not up!\n");
+
rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (rc) {
pr_err("dma_set_mask_and_coherent failed %d\n", rc);
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 5769e9478c94..f31449a2901b 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -119,6 +119,8 @@ extern int qcom_scm_pas_shutdown_retry(u32 peripheral);
extern bool qcom_scm_pas_supported(u32 peripheral);
extern int qcom_scm_get_sec_dump_state(u32 *dump_state);
+extern int qcom_scm_get_llcc_missrate(phys_addr_t in_buf, size_t in_buf_size,
+ phys_addr_t out_buf, size_t out_buf_size);
extern int qcom_scm_assign_dump_table_region(bool is_assign, phys_addr_t addr, size_t size);
extern int qcom_scm_tz_blsp_modify_owner(int food, u64 subsystem, int *out);
diff --git a/modules.list.neo_la b/modules.list.neo_la
index 16a15f9e401f..196475bb6997 100644
--- a/modules.list.neo_la
+++ b/modules.list.neo_la
@@ -54,6 +54,8 @@ msm_geni_serial.ko
msm_rtb.ko
mem_buf.ko
mem_buf_dev.ko
+qseecom-mod.ko
+smcinvoke_mod.ko
pinctrl-neo.ko
pinctrl-msm.ko
phy-generic.ko
diff --git a/modules.list.neo_le b/modules.list.neo_le
index c16dbff95fd2..ac7c7f0163bb 100644
--- a/modules.list.neo_le
+++ b/modules.list.neo_le
@@ -59,6 +59,7 @@ nvmem_qcom-spmi-sdam.ko
pinctrl-spmi-gpio.ko
qcom-spmi-temp-alarm.ko
clk-spmi-pmic-div.ko
+qcom_pm8008-regulator.ko
sdhci-msm.ko
core_hang_detect.ko
kryo_arm64_edac.ko