Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3898cff0 authored by Tharun Kumar Merugu's avatar Tharun Kumar Merugu
Browse files

soc:qcom: CDSPRM module update for SM8150 cx ipeak limit management



Added cx ipeak and CDSP thermal limit management framework in
CDSRPM module for SM8150. NPU will notify CDSPRM module of clock
and activity changes.
CDSPRM module interacts with cx ipeak limit management driver on
CDSP and control compute subsystem (CDSP, NPU) clocks to limit
cx ipeak to the characterized levels. Also added CDSP subsystem
thermal mitigation support by registering cooling devices for CDSP
and HVX cores.

Change-Id: Ide61e2df09859fbf1669e4821cc1d2c7fbb684df
Acked-by: default avatarSreekanth Gande <sgande@qti.qualcomm.com>
Signed-off-by: default avatarTharun Kumar Merugu <mtharu@codeaurora.org>
parent 51683be8
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -2,20 +2,45 @@ Qualcomm Technologies, Inc. CDSP Request Manager driver

CDSP Request Manager driver implements an rpmsg interface with
CDSP subsystem to serve L3 frequency and CPU QoS requests from CDSP.
It also interacts with NPU, Camera modules for Cx iPeak mitigations and
thermal module via CDSP/HVX cooling devices for thermal mitigation of
CDSP core.

Required properties:
- compatible: Must be "qcom,msm-cdsprm-rpmsg"
- qcom,glink-channels: Glink channel for communication with CDSP
- qcom,intents: A list of <number of intents, size of each intent>

- qcom,msm-cdsp-rm: A sub-device node to define CDSPM RM configuration
		parameters
- qcom,msm-cdsp-rm: A sub-device node to define CDSPM RM, Cx iPeak mitigation
		driver and CDSP core thermal cooling device
	Required properties:
	- compatible: Must be "qcom,msm-cdsp-rm"
	- qcom,qos-latency-us: pm_qos latency vote to be applied on CDSP request in
				micro seconds
	- qcom,qos-maxhold-ms: Maximum hold time for pm_qos latency vote from CDSP
				in milli seconds
	- qcom,compute-priority-mode: when Cx iPeak mitigation is enabled,
				this field sets desired compute priority mode
				for AIX and HVX concurrency cases based on
				following values, where in HVX and NPU cores,
				if required, are throttled in concurrency based
				on the selected priority mode
				1 : HVX_MAX - Allows HVX to run at maximum possible
						frequency during concurrency with NPU
				2 : AIX_MAX - Allows NPU to run at maximum possible
						frequency during concurrency with HVX
				3 : HVX_OVER_AIX - Allows HVX to run at a higher
						frequency than NPU during concurrency
				4 : AIX_OVER_HVX - Allows NPU to run at a higher
						frequency than HVX during concurrency
	- #cooling-cells: Number of cooling cells for CDSP cooling device based on
			CDSP Q6 core clock throttling

- qcom,msm-hvx-rm: A sub-device node to define HVX based thermal cooling device
	Required properties:
	- compatible: Must be "qcom,msm-hvx-rm"
	- #cooling-cells: Number of cooling cells for CDSP cooling device based on
			HVX hardware throttling

- qcom,cdsp-l3: A sub-device node to define CDSP L3 target device for L3
		clock voting
@@ -39,5 +64,12 @@ Example:
			compatible = "qcom,msm-cdsp-rm";
			qcom,qos-latency-us = <100>;
			qcom,qos-maxhold-ms = <20>;
			qcom,compute-priority-mode = <2>;
			#cooling-cells = <2>;
		};

		 msm_hvx_rm: qcom,msm_hvx_rm {
			compatible = "qcom,msm-hvx-rm";
			#cooling-cells = <2>;
		};
	};
+626 −11
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@
 */

/* This module uses rpmsg to communicate with CDSP and receive requests
 * for CPU L3 frequency and QoS.
 * for CPU L3 frequency and QoS along with Cx Limit management and
 * thermal cooling handling.
 */

#define pr_fmt(fmt) "cdsprm: " fmt
@@ -34,17 +35,33 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rpmsg.h>
#include <linux/thermal.h>
#include <linux/debugfs.h>
#include <asm/arch_timer.h>
#include <linux/soc/qcom/cdsprm.h>
#include <linux/soc/qcom/cdsprm_cxlimit.h>

#define SYSMON_CDSP_FEATURE_L3_RX		1
#define SYSMON_CDSP_FEATURE_RM_RX		2
#define SYSMON_CDSP_FEATURE_COMPUTE_PRIO_TX	3
#define SYSMON_CDSP_FEATURE_NPU_LIMIT_TX	4
#define SYSMON_CDSP_FEATURE_NPU_LIMIT_RX	5
#define SYSMON_CDSP_FEATURE_NPU_ACTIVITY_TX	6
#define SYSMON_CDSP_FEATURE_NPU_ACTIVITY_RX	7
#define SYSMON_CDSP_FEATURE_NPU_CORNER_TX	8
#define SYSMON_CDSP_FEATURE_NPU_CORNER_RX	9
#define SYSMON_CDSP_FEATURE_THERMAL_LIMIT_TX	10
#define SYSMON_CDSP_FEATURE_CAMERA_ACTIVITY_TX	11
#define SYSMON_CDSP_FEATURE_VERSION_RX		12

#define SYSMON_CDSP_FEATURE_L3		1
#define SYSMON_CDSP_FEATURE_RM		2
#define SYSMON_CDSP_QOS_FLAG_IGNORE	0
#define SYSMON_CDSP_QOS_FLAG_ENABLE	1
#define SYSMON_CDSP_QOS_FLAG_DISABLE	2
#define QOS_LATENCY_DISABLE_VALUE	-1
#define SYS_CLK_TICKS_PER_MS		19200
#define CDSPRM_MSG_QUEUE_DEPTH		10
#define CDSP_THERMAL_MAX_STATE		10
#define HVX_THERMAL_MAX_STATE		10

struct sysmon_l3_msg {
	unsigned int l3_clock_khz;
@@ -56,12 +73,62 @@ struct sysmon_rm_msg {
	unsigned int timetick_high;
};

struct sysmon_npu_limit_msg {
	unsigned int corner;
};

struct sysmon_npu_limit_ack {
	unsigned int corner;
};

struct sysmon_compute_prio_msg {
	unsigned int priority_idx;
};

struct sysmon_npu_activity_msg {
	unsigned int b_enabled;
};

struct sysmon_npu_corner_msg {
	unsigned int corner;
};

struct sysmon_thermal_msg {
	unsigned short hvx_level;
	unsigned short cdsp_level;
};

struct sysmon_camera_msg {
	unsigned int b_enabled;
};

struct sysmon_version_msg {
	unsigned int id;
};

struct sysmon_msg {
	unsigned int feature_id;
	union {
		struct sysmon_l3_msg l3_struct;
		struct sysmon_rm_msg rm_struct;
	} feature_struct;
		struct sysmon_npu_limit_msg npu_limit;
		struct sysmon_npu_activity_msg npu_activity;
		struct sysmon_npu_corner_msg npu_corner;
		struct sysmon_version_msg version;
	} fs;
	unsigned int size;
};

struct sysmon_msg_tx {
	unsigned int feature_id;
	union {
		struct sysmon_npu_limit_ack npu_limit_ack;
		struct sysmon_compute_prio_msg compute_prio;
		struct sysmon_npu_activity_msg npu_activity;
		struct sysmon_thermal_msg thermal;
		struct sysmon_npu_corner_msg npu_corner;
		struct sysmon_camera_msg camera;
	} fs;
	unsigned int size;
};

@@ -80,6 +147,7 @@ struct cdsprm_request {
};

struct cdsprm {
	unsigned int			cdsp_version;
	unsigned int			event;
	struct completion		msg_avail;
	struct cdsprm_request		msg_queue[CDSPRM_MSG_QUEUE_DEPTH];
@@ -91,6 +159,7 @@ struct cdsprm {
	struct mutex			rm_lock;
	spinlock_t			l3_lock;
	spinlock_t			list_lock;
	struct mutex			rpmsg_lock;
	struct rpmsg_device		*rpmsgdev;
	enum delay_state		dt_state;
	enum delay_state		work_state;
@@ -98,12 +167,34 @@ struct cdsprm {
	struct pm_qos_request		pm_qos_req;
	unsigned int			qos_latency_us;
	unsigned int			qos_max_ms;
	unsigned int			compute_prio_idx;
	struct mutex			npu_activity_lock;
	unsigned int			b_npu_enabled;
	unsigned int			b_camera_enabled;
	unsigned int			b_npu_activity_waiting;
	unsigned int			b_npu_corner_waiting;
	struct completion		npu_activity_complete;
	struct completion		npu_corner_complete;
	unsigned int			npu_enable_cnt;
	enum cdsprm_npu_corner		npu_corner;
	enum cdsprm_npu_corner		allowed_npu_corner;
	enum cdsprm_npu_corner		npu_corner_limit;
	struct mutex			thermal_lock;
	unsigned int			thermal_cdsp_level;
	unsigned int			thermal_hvx_level;
	struct thermal_cooling_device	*cdsp_tcdev;
	struct thermal_cooling_device	*hvx_tcdev;
	bool				qos_request;
	bool				b_rpmsg_register;
	bool				b_qosinitdone;
	bool				b_applyingNpuLimit;
	int				latency_request;
	struct dentry			*debugfs_dir;
	struct dentry			*debugfs_file;
	int (*set_l3_freq)(unsigned int freq_khz);
	int (*set_l3_freq_cached)(unsigned int freq_khz);
	int (*set_corner_limit)(enum cdsprm_npu_corner);
	int (*set_corner_limit_cached)(enum cdsprm_npu_corner);
};

static struct cdsprm gcdsprm;
@@ -130,6 +221,224 @@ void cdsprm_register_cdspl3gov(struct cdsprm_l3 *arg)
}
EXPORT_SYMBOL(cdsprm_register_cdspl3gov);

int cdsprm_cxlimit_npu_limit_register(
	const struct cdsprm_npu_limit_cbs *npu_limit_cb)
{
	if (!npu_limit_cb)
		return -EINVAL;

	gcdsprm.set_corner_limit = npu_limit_cb->set_corner_limit;

	return 0;
}
EXPORT_SYMBOL(cdsprm_cxlimit_npu_limit_register);

int cdsprm_cxlimit_npu_limit_deregister(void)
{
	int result = 0;

	if (gcdsprm.set_corner_limit)
		gcdsprm.set_corner_limit = NULL;
	else
		result = -EINVAL;

	return result;
}
EXPORT_SYMBOL(cdsprm_cxlimit_npu_limit_deregister);

int cdsprm_compute_core_set_priority(unsigned int priority_idx)
{
	struct sysmon_msg_tx rpmsg_msg_tx;

	gcdsprm.compute_prio_idx = priority_idx;

	if (gcdsprm.rpmsgdev && gcdsprm.cdsp_version) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_COMPUTE_PRIO_TX;
		rpmsg_msg_tx.fs.compute_prio.priority_idx =
				priority_idx;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		rpmsg_send(gcdsprm.rpmsgdev->ept,
			&rpmsg_msg_tx,
			sizeof(rpmsg_msg_tx));
		pr_debug("Compute core priority set to %d\n",
			priority_idx);
	}

	return 0;
}
EXPORT_SYMBOL(cdsprm_compute_core_set_priority);

int cdsprm_cxlimit_npu_activity_notify(unsigned int b_enabled)
{
	int result = -EINVAL;
	struct sysmon_msg_tx rpmsg_msg_tx;

	mutex_lock(&gcdsprm.npu_activity_lock);
	if (b_enabled)
		gcdsprm.npu_enable_cnt++;
	else if (gcdsprm.npu_enable_cnt)
		gcdsprm.npu_enable_cnt--;

	if ((gcdsprm.npu_enable_cnt &&
		gcdsprm.b_npu_enabled) ||
		(!gcdsprm.npu_enable_cnt &&
			!gcdsprm.b_npu_enabled)) {
		mutex_unlock(&gcdsprm.npu_activity_lock);
		return 0;
	}

	gcdsprm.b_npu_enabled = b_enabled;

	if (gcdsprm.rpmsgdev && gcdsprm.cdsp_version) {
		if (gcdsprm.b_npu_enabled)
			gcdsprm.b_npu_activity_waiting++;
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_NPU_ACTIVITY_TX;
		rpmsg_msg_tx.fs.npu_activity.b_enabled =
			gcdsprm.b_npu_enabled;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		result = rpmsg_send(gcdsprm.rpmsgdev->ept,
				&rpmsg_msg_tx,
				sizeof(rpmsg_msg_tx));
		if (gcdsprm.b_npu_enabled && result)
			gcdsprm.b_npu_activity_waiting--;
	}

	if (gcdsprm.b_npu_enabled && !result) {
		mutex_unlock(&gcdsprm.npu_activity_lock);
		wait_for_completion(&gcdsprm.npu_activity_complete);
		mutex_lock(&gcdsprm.npu_activity_lock);
		gcdsprm.b_npu_activity_waiting--;
	}

	mutex_unlock(&gcdsprm.npu_activity_lock);
	return result;
}
EXPORT_SYMBOL(cdsprm_cxlimit_npu_activity_notify);

enum cdsprm_npu_corner cdsprm_cxlimit_npu_corner_notify(
				enum cdsprm_npu_corner corner)
{
	int result = -EINVAL;
	enum cdsprm_npu_corner past_npu_corner;
	enum cdsprm_npu_corner return_npu_corner = corner;
	struct sysmon_msg_tx rpmsg_msg_tx;

	if (gcdsprm.b_applyingNpuLimit)
		return corner;

	mutex_lock(&gcdsprm.npu_activity_lock);
	past_npu_corner = gcdsprm.npu_corner;
	gcdsprm.npu_corner = corner;

	if (gcdsprm.rpmsgdev && gcdsprm.cdsp_version) {
		if ((gcdsprm.npu_corner > past_npu_corner) ||
			!gcdsprm.npu_corner)
			gcdsprm.b_npu_corner_waiting++;
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_NPU_CORNER_TX;
		rpmsg_msg_tx.fs.npu_corner.corner =
			(unsigned int)gcdsprm.npu_corner;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		result = rpmsg_send(gcdsprm.rpmsgdev->ept,
				&rpmsg_msg_tx,
				sizeof(rpmsg_msg_tx));
		if (((gcdsprm.npu_corner > past_npu_corner) ||
			!gcdsprm.npu_corner) && result)
			gcdsprm.b_npu_corner_waiting--;
	}

	if (((gcdsprm.npu_corner > past_npu_corner) ||
		!gcdsprm.npu_corner) && !result) {
		mutex_unlock(&gcdsprm.npu_activity_lock);
		wait_for_completion(&gcdsprm.npu_corner_complete);
		mutex_lock(&gcdsprm.npu_activity_lock);
		if (gcdsprm.allowed_npu_corner) {
			return_npu_corner = gcdsprm.allowed_npu_corner;
			gcdsprm.npu_corner = gcdsprm.allowed_npu_corner;
		}
		gcdsprm.b_npu_corner_waiting--;
	}

	mutex_unlock(&gcdsprm.npu_activity_lock);
	return return_npu_corner;
}
EXPORT_SYMBOL(cdsprm_cxlimit_npu_corner_notify);

int cdsprm_cxlimit_camera_activity_notify(unsigned int b_enabled)
{
	struct sysmon_msg_tx rpmsg_msg_tx;

	gcdsprm.b_camera_enabled = b_enabled;

	if (gcdsprm.rpmsgdev) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_CAMERA_ACTIVITY_TX;
		rpmsg_msg_tx.fs.camera.b_enabled =
				b_enabled;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		rpmsg_send(gcdsprm.rpmsgdev->ept,
			&rpmsg_msg_tx,
			sizeof(rpmsg_msg_tx));
	}

	return 0;
}
EXPORT_SYMBOL(cdsprm_cxlimit_camera_activity_notify);

static int cdsprm_thermal_cdsp_clk_limit(unsigned int level)
{
	int result = -EINVAL;
	struct sysmon_msg_tx rpmsg_msg_tx;

	mutex_lock(&gcdsprm.thermal_lock);
	gcdsprm.thermal_cdsp_level = level;

	if (gcdsprm.rpmsgdev && gcdsprm.cdsp_version) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_THERMAL_LIMIT_TX;
		rpmsg_msg_tx.fs.thermal.hvx_level =
			gcdsprm.thermal_hvx_level;
		rpmsg_msg_tx.fs.thermal.cdsp_level =
			gcdsprm.thermal_cdsp_level;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		result = rpmsg_send(gcdsprm.rpmsgdev->ept,
					&rpmsg_msg_tx,
					sizeof(rpmsg_msg_tx));
	}

	mutex_unlock(&gcdsprm.thermal_lock);

	return result;
}

static int cdsprm_thermal_hvx_instruction_limit(unsigned int level)
{
	int result = -EINVAL;
	struct sysmon_msg_tx rpmsg_msg_tx;

	mutex_lock(&gcdsprm.thermal_lock);
	gcdsprm.thermal_hvx_level = level;

	if (gcdsprm.rpmsgdev && gcdsprm.cdsp_version) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_THERMAL_LIMIT_TX;
		rpmsg_msg_tx.fs.thermal.hvx_level =
			gcdsprm.thermal_hvx_level;
		rpmsg_msg_tx.fs.thermal.cdsp_level =
			gcdsprm.thermal_cdsp_level;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		result = rpmsg_send(gcdsprm.rpmsgdev->ept,
				&rpmsg_msg_tx,
				sizeof(rpmsg_msg_tx));
	}

	mutex_unlock(&gcdsprm.thermal_lock);

	return result;
}

/**
 * cdsprm_unregister_cdspl3gov() - Unregister the method to set L3 clock
 *                                 frequency
@@ -166,9 +475,9 @@ static void process_rm_request(struct sysmon_msg *msg)
	if (!msg)
		return;

	if (msg->feature_id == SYSMON_CDSP_FEATURE_RM) {
	if (msg->feature_id == SYSMON_CDSP_FEATURE_RM_RX) {
		mutex_lock(&gcdsprm.rm_lock);
		rm_msg = &msg->feature_struct.rm_struct;
		rm_msg = &msg->fs.rm_struct;
		if (rm_msg->b_qos_flag ==
			SYSMON_CDSP_QOS_FLAG_ENABLE) {
			if (gcdsprm.latency_request !=
@@ -250,12 +559,68 @@ static void process_delayed_rm_request(struct work_struct *work)
	mutex_unlock(&gcdsprm.rm_lock);
}

static void cdsprm_rpmsg_send_details(void)
{
	struct sysmon_msg_tx rpmsg_msg_tx;

	if (!gcdsprm.cdsp_version)
		return;

	reinit_completion(&gcdsprm.npu_activity_complete);
	reinit_completion(&gcdsprm.npu_corner_complete);

	if (gcdsprm.npu_corner) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_NPU_CORNER_TX;
		rpmsg_msg_tx.fs.npu_corner.corner =
			(unsigned int)gcdsprm.npu_corner;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		rpmsg_send(gcdsprm.rpmsgdev->ept,
				&rpmsg_msg_tx,
				sizeof(rpmsg_msg_tx));
	}

	if (gcdsprm.b_npu_enabled) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_NPU_ACTIVITY_TX;
		rpmsg_msg_tx.fs.npu_activity.b_enabled =
			gcdsprm.b_npu_enabled;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		rpmsg_send(gcdsprm.rpmsgdev->ept,
			&rpmsg_msg_tx,
			sizeof(rpmsg_msg_tx));
	}

	cdsprm_compute_core_set_priority(gcdsprm.compute_prio_idx);

	if (gcdsprm.b_camera_enabled) {
		rpmsg_msg_tx.feature_id =
			SYSMON_CDSP_FEATURE_CAMERA_ACTIVITY_TX;
		rpmsg_msg_tx.fs.camera.b_enabled =
				gcdsprm.b_camera_enabled;
		rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
		rpmsg_send(gcdsprm.rpmsgdev->ept,
			&rpmsg_msg_tx,
			sizeof(rpmsg_msg_tx));
	}

	if (gcdsprm.thermal_cdsp_level) {
		cdsprm_thermal_cdsp_clk_limit(
			gcdsprm.thermal_cdsp_level);
	} else if (gcdsprm.thermal_hvx_level) {
		cdsprm_thermal_hvx_instruction_limit(
			gcdsprm.thermal_hvx_level);
	}
}

static void process_cdsp_request(struct work_struct *work)
{
	struct cdsprm_request *req = NULL;
	struct sysmon_msg *msg = NULL;
	unsigned int l3_clock_khz;
	unsigned long flags;
	int result = 0;
	struct sysmon_msg_tx rpmsg_msg_tx;

	while (gcdsprm.work_state ==
			CDSP_DELAY_THREAD_STARTED) {
@@ -271,12 +636,13 @@ static void process_cdsp_request(struct work_struct *work)
					flags);
				continue;
			}
			if ((msg->feature_id == SYSMON_CDSP_FEATURE_RM) &&
			if ((msg->feature_id == SYSMON_CDSP_FEATURE_RM_RX) &&
				gcdsprm.b_qosinitdone) {
				process_rm_request(msg);
			} else if (msg->feature_id == SYSMON_CDSP_FEATURE_L3) {
			} else if (msg->feature_id ==
				SYSMON_CDSP_FEATURE_L3_RX) {
				l3_clock_khz =
				msg->feature_struct.l3_struct.l3_clock_khz;
				msg->fs.l3_struct.l3_clock_khz;
				spin_lock_irqsave(&gcdsprm.l3_lock, flags);
				gcdsprm.set_l3_freq_cached =
							gcdsprm.set_l3_freq;
@@ -287,6 +653,51 @@ static void process_cdsp_request(struct work_struct *work)
					pr_debug("Set L3 clock %d done\n",
					l3_clock_khz);
				}
			} else if (msg->feature_id ==
					SYSMON_CDSP_FEATURE_NPU_LIMIT_RX) {
				mutex_lock(&gcdsprm.npu_activity_lock);
				gcdsprm.set_corner_limit_cached =
					gcdsprm.set_corner_limit;
				if (gcdsprm.set_corner_limit_cached) {
					gcdsprm.npu_corner_limit =
						msg->fs.npu_limit.corner;
					gcdsprm.b_applyingNpuLimit = true;
					result =
					gcdsprm.set_corner_limit_cached(
						gcdsprm.npu_corner_limit);
					gcdsprm.b_applyingNpuLimit = false;
					pr_debug("Set NPU limit to %d\n",
						msg->fs.npu_limit.corner);
				} else {
					result = -ENOMSG;
					pr_debug("NPU limit not registered\n");
				}
				mutex_unlock(&gcdsprm.npu_activity_lock);
				/*
				 * Send Limit ack back to DSP
				 */
				rpmsg_msg_tx.feature_id =
					SYSMON_CDSP_FEATURE_NPU_LIMIT_TX;
				if (result == 0) {
					rpmsg_msg_tx.fs.npu_limit_ack.corner =
						msg->fs.npu_limit.corner;
				} else {
					rpmsg_msg_tx.fs.npu_limit_ack.corner =
							CDSPRM_NPU_CLK_OFF;
				}
				rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
				result = rpmsg_send(gcdsprm.rpmsgdev->ept,
					&rpmsg_msg_tx,
					sizeof(rpmsg_msg_tx));
				if (result)
					pr_err("rpmsg send failed %d\n",
					result);
				else
					pr_debug("NPU limit ack sent\n");
			} else if (msg->feature_id ==
					SYSMON_CDSP_FEATURE_VERSION_RX) {
				cdsprm_rpmsg_send_details();
				pr_debug("Sent preserved data to DSP\n");
			}
			spin_lock_irqsave(&gcdsprm.list_lock, flags);
			list_del(&req->node);
@@ -304,12 +715,25 @@ static int cdsprm_rpmsg_probe(struct rpmsg_device *dev)
	of_platform_populate(dev->dev.of_node, NULL, NULL, &dev->dev);
	gcdsprm.rpmsgdev = dev;
	dev_dbg(&dev->dev, "rpmsg probe called for cdsp\n");

	return 0;
}

static void cdsprm_rpmsg_remove(struct rpmsg_device *dev)
{
	gcdsprm.rpmsgdev = NULL;

	mutex_lock(&gcdsprm.npu_activity_lock);
	complete_all(&gcdsprm.npu_activity_complete);
	complete_all(&gcdsprm.npu_corner_complete);
	mutex_unlock(&gcdsprm.npu_activity_lock);

	gcdsprm.cdsp_version = 0;
	gcdsprm.set_corner_limit_cached = gcdsprm.set_corner_limit;

	if ((gcdsprm.npu_corner_limit < CDSPRM_NPU_TURBO_L1) &&
		gcdsprm.set_corner_limit_cached)
		gcdsprm.set_corner_limit_cached(CDSPRM_NPU_TURBO_L1);
}

static int cdsprm_rpmsg_callback(struct rpmsg_device *dev, void *data,
@@ -327,17 +751,40 @@ static int cdsprm_rpmsg_callback(struct rpmsg_device *dev, void *data,
		return -EINVAL;
	}

	if ((msg->feature_id == SYSMON_CDSP_FEATURE_RM) &&
	if ((msg->feature_id == SYSMON_CDSP_FEATURE_RM_RX) &&
			gcdsprm.b_qosinitdone) {
		dev_dbg(&dev->dev, "Processing RM request\n");
		b_valid = true;
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_L3) {
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_L3_RX) {
		dev_dbg(&dev->dev, "Processing L3 request\n");
		spin_lock_irqsave(&gcdsprm.l3_lock, flags);
		gcdsprm.set_l3_freq_cached = gcdsprm.set_l3_freq;
		spin_unlock_irqrestore(&gcdsprm.l3_lock, flags);
		if (gcdsprm.set_l3_freq_cached)
			b_valid = true;
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_NPU_CORNER_RX) {
		gcdsprm.allowed_npu_corner = msg->fs.npu_corner.corner;
		dev_dbg(&dev->dev,
			"Processing NPU corner request ack for %d\n",
			gcdsprm.allowed_npu_corner);
		if (gcdsprm.b_npu_corner_waiting)
			complete(&gcdsprm.npu_corner_complete);
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_NPU_LIMIT_RX) {
		dev_dbg(&dev->dev, "Processing NPU limit request for %d\n",
			msg->fs.npu_limit.corner);
		b_valid = true;
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_NPU_ACTIVITY_RX) {
		dev_dbg(&dev->dev, "Processing NPU activity request ack\n");
		if (gcdsprm.b_npu_activity_waiting)
			complete(&gcdsprm.npu_activity_complete);
	} else if (msg->feature_id == SYSMON_CDSP_FEATURE_VERSION_RX) {
		gcdsprm.cdsp_version = msg->fs.version.id;
		b_valid = true;
		dev_dbg(&dev->dev, "Received CDSP version 0x%x\n",
			gcdsprm.cdsp_version);
	} else {
		dev_err(&dev->dev, "Received incorrect msg feature %d\n",
		msg->feature_id);
	}

	if (b_valid) {
@@ -373,9 +820,70 @@ static int cdsprm_rpmsg_callback(struct rpmsg_device *dev, void *data,
	return 0;
}

static int cdsp_get_max_state(struct thermal_cooling_device *cdev,
				unsigned long *state)
{
	*state = CDSP_THERMAL_MAX_STATE;

	return 0;
}

static int cdsp_get_cur_state(struct thermal_cooling_device *cdev,
				unsigned long *state)
{
	*state = gcdsprm.thermal_cdsp_level;

	return 0;
}

static int cdsp_set_cur_state(struct thermal_cooling_device *cdev,
				unsigned long state)
{
	cdsprm_thermal_cdsp_clk_limit(state);

	return 0;
}

static const struct thermal_cooling_device_ops cdsp_cooling_ops = {
	.get_max_state = cdsp_get_max_state,
	.get_cur_state = cdsp_get_cur_state,
	.set_cur_state = cdsp_set_cur_state,
};

static int hvx_get_max_state(struct thermal_cooling_device *cdev,
				unsigned long *state)
{
	*state = HVX_THERMAL_MAX_STATE;

	return 0;
}

static int hvx_get_cur_state(struct thermal_cooling_device *cdev,
				unsigned long *state)
{
	*state = gcdsprm.thermal_hvx_level;

	return 0;
}

static int hvx_set_cur_state(struct thermal_cooling_device *cdev,
				unsigned long state)
{
	cdsprm_thermal_hvx_instruction_limit(state);

	return 0;
}

static const struct thermal_cooling_device_ops hvx_cooling_ops = {
	.get_max_state = hvx_get_max_state,
	.get_cur_state = hvx_get_cur_state,
	.set_cur_state = hvx_set_cur_state,
};

static int cdsp_rm_driver_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct thermal_cooling_device *tcdev = 0;

	if (of_property_read_u32(dev->of_node,
			"qcom,qos-latency-us", &gcdsprm.qos_latency_us)) {
@@ -387,12 +895,70 @@ static int cdsp_rm_driver_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	gcdsprm.compute_prio_idx = CDSPRM_COMPUTE_AIX_OVER_HVX;
	of_property_read_u32(dev->of_node,
				"qcom,compute-priority-mode",
				&gcdsprm.compute_prio_idx);

	if (IS_ENABLED(CONFIG_THERMAL)) {
		tcdev = thermal_of_cooling_device_register(dev->of_node,
							"cdsp", NULL,
							&cdsp_cooling_ops);
		if (IS_ERR(tcdev)) {
			dev_err(dev,
				"CDSP thermal driver reg failed\n");
		}
		gcdsprm.cdsp_tcdev = tcdev;
		thermal_cdev_update(tcdev);
	}

	dev_info(dev, "CDSP request manager driver probe called\n");
	gcdsprm.b_qosinitdone = true;

	return 0;
}

static int hvx_rm_driver_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct thermal_cooling_device *tcdev = 0;

	if (IS_ENABLED(CONFIG_THERMAL)) {
		tcdev = thermal_of_cooling_device_register(dev->of_node,
							"hvx", NULL,
							&hvx_cooling_ops);
		if (IS_ERR(tcdev)) {
			dev_err(dev,
				"HVX thermal driver reg failed\n");
		}
		gcdsprm.hvx_tcdev = tcdev;
		thermal_cdev_update(tcdev);
	}

	dev_dbg(dev, "HVX request manager driver probe called\n");

	return 0;
}

static int cdsprm_compute_prio_read(void *data, u64 *val)
{
	*val = gcdsprm.compute_prio_idx;

	return 0;
}

static int cdsprm_compute_prio_write(void *data, u64 val)
{
	cdsprm_compute_core_set_priority((unsigned int)val);

	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(cdsprm_debugfs_fops,
			cdsprm_compute_prio_read,
			cdsprm_compute_prio_write,
			"%llu\n");

static const struct rpmsg_device_id cdsprm_rpmsg_match[] = {
	{ "cdsprmglink-apps-dsp" },
	{ },
@@ -428,15 +994,34 @@ static struct platform_driver cdsp_rm = {
	},
};

static const struct of_device_id hvx_rm_match_table[] = {
	{ .compatible = "qcom,msm-hvx-rm" },
	{ },
};

static struct platform_driver hvx_rm = {
	.probe = hvx_rm_driver_probe,
	.driver = {
		.name = "msm_hvx_rm",
		.of_match_table = hvx_rm_match_table,
	},
};

static int __init cdsprm_init(void)
{
	int err;

	mutex_init(&gcdsprm.rm_lock);
	mutex_init(&gcdsprm.rpmsg_lock);
	mutex_init(&gcdsprm.npu_activity_lock);
	mutex_init(&gcdsprm.thermal_lock);
	spin_lock_init(&gcdsprm.l3_lock);
	spin_lock_init(&gcdsprm.list_lock);
	init_completion(&gcdsprm.msg_avail);
	init_completion(&gcdsprm.npu_activity_complete);
	init_completion(&gcdsprm.npu_corner_complete);
	gcdsprm.work_queue = create_singlethread_workqueue("cdsprm-wq");

	if (!gcdsprm.work_queue) {
		pr_err("Failed to create rm work queue\n");
		return -ENOMEM;
@@ -444,6 +1029,7 @@ static int __init cdsprm_init(void)

	gcdsprm.delay_work_queue =
			create_singlethread_workqueue("cdsprm-wq-delay");

	if (!gcdsprm.delay_work_queue) {
		err = -ENOMEM;
		pr_err("Failed to create rm delay work queue\n");
@@ -453,13 +1039,23 @@ static int __init cdsprm_init(void)
	INIT_WORK(&gcdsprm.cdsprm_delay_work, process_delayed_rm_request);
	INIT_WORK(&gcdsprm.cdsprm_work, process_cdsp_request);
	err = platform_driver_register(&cdsp_rm);

	if (err) {
		pr_err("Failed to register cdsprm platform driver: %d\n",
				err);
		goto bail;
	}

	err = platform_driver_register(&hvx_rm);

	if (err) {
		pr_err("Failed to register hvxrm platform driver: %d\n",
				err);
		goto bail;
	}

	err = register_rpmsg_driver(&cdsprm_rpmsg_client);

	if (err) {
		pr_err("Failed registering rpmsg driver with return %d\n",
				err);
@@ -467,12 +1063,30 @@ static int __init cdsprm_init(void)
	}

	gcdsprm.b_rpmsg_register = true;
	gcdsprm.debugfs_dir = debugfs_create_dir("compute", NULL);

	if (!gcdsprm.debugfs_dir) {
		pr_err("Failed to create debugfs directory for cdsprm\n");
		goto bail;
	} else {
		gcdsprm.debugfs_file = debugfs_create_file("priority",
						0644, gcdsprm.debugfs_dir,
						NULL, &cdsprm_debugfs_fops);
		if (!gcdsprm.debugfs_file) {
			debugfs_remove_recursive(gcdsprm.debugfs_dir);
			pr_err("Failed to create debugfs file\n");
			goto bail;
		}
	}

	pr_debug("Init successful\n");

	return 0;
bail:
	destroy_workqueue(gcdsprm.delay_work_queue);
err_wq:
	destroy_workqueue(gcdsprm.work_queue);

	return err;
}

@@ -482,6 +1096,7 @@ static void __exit cdsprm_exit(void)
		unregister_rpmsg_driver(&cdsprm_rpmsg_client);

	platform_driver_unregister(&cdsp_rm);
	platform_driver_unregister(&hvx_rm);
	gcdsprm.work_state = CDSP_DELAY_THREAD_NOT_STARTED;
	complete(&gcdsprm.msg_avail);
	destroy_workqueue(gcdsprm.work_queue);