Browse Source

cnss2: Add support for direct QMP to communicate with AOP

Add support for direct QMP to communicate with AOP. There
are two ways to communicate with AOP: mailbox, and direct
QMP. Based on property set in the device tree use either
direct QMP or mailbox to send messages to AOP.

Change-Id: I9fc24f8a483abb3084cda4d85acf2d53e43d9ad8
CRs-Fixed: 3488507
Rajesh Chauhan 1 year ago
parent
commit
90e0212ecc
3 changed files with 95 additions and 33 deletions
  1. 3 6
      cnss2/main.c
  2. 10 1
      cnss2/main.h
  3. 82 26
      cnss2/power.c

+ 3 - 6
cnss2/main.c

@@ -4946,7 +4946,7 @@ static int cnss_probe(struct platform_device *plat_dev)
 	cnss_power_misc_params_init(plat_priv);
 	cnss_get_tcs_info(plat_priv);
 	cnss_get_cpr_info(plat_priv);
-	cnss_aop_mbox_init(plat_priv);
+	cnss_aop_interface_init(plat_priv);
 	cnss_init_control_params(plat_priv);
 
 	ret = cnss_get_resources(plat_priv);
@@ -5022,6 +5022,7 @@ unreg_esoc:
 free_res:
 	cnss_put_resources(plat_priv);
 reset_ctx:
+	cnss_aop_interface_deinit(plat_priv);
 	platform_set_drvdata(plat_dev, NULL);
 	cnss_deinitialize_mem_pool();
 reset_plat_dev:
@@ -5049,12 +5050,8 @@ static int cnss_remove(struct platform_device *plat_dev)
 	cnss_unregister_bus_scale(plat_priv);
 	cnss_unregister_esoc(plat_priv);
 	cnss_put_resources(plat_priv);
-
-	if (!IS_ERR_OR_NULL(plat_priv->mbox_chan))
-		mbox_free_channel(plat_priv->mbox_chan);
-
+	cnss_aop_interface_deinit(plat_priv);
 	cnss_deinitialize_mem_pool();
-
 	platform_set_drvdata(plat_dev, NULL);
 	cnss_clear_plat_priv(plat_priv);
 

+ 10 - 1
cnss2/main.h

@@ -23,6 +23,10 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/time64.h>
+#if IS_ENABLED(CONFIG_MSM_QMP)
+#include <linux/mailbox/qmp.h>
+#include <linux/soc/qcom/qcom_aoss.h>
+#endif
 #ifdef CONFIG_CNSS_OUT_OF_TREE
 #include "cnss2.h"
 #else
@@ -588,6 +592,10 @@ struct cnss_plat_data {
 	u8 charger_mode;
 	struct mbox_client mbox_client_data;
 	struct mbox_chan *mbox_chan;
+#if IS_ENABLED(CONFIG_MSM_QMP)
+	struct qmp *qmp;
+#endif
+	bool use_direct_qmp;
 	const char *vreg_ol_cpr, *vreg_ipa;
 	const char **pdc_init_table, **vreg_pdc_map, **pmu_vreg_map;
 	int pdc_init_table_len, vreg_pdc_map_len, pmu_vreg_map_len;
@@ -699,7 +707,8 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv);
 int cnss_get_tcs_info(struct cnss_plat_data *plat_priv);
 unsigned int cnss_get_timeout(struct cnss_plat_data *plat_priv,
 			      enum cnss_timeout_type);
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv);
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv);
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv);
 int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv);
 int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg);
 void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv);

+ 82 - 26
cnss2/power.c

@@ -6,9 +6,6 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
-#if IS_ENABLED(CONFIG_MSM_QMP)
-#include <linux/mailbox/qmp.h>
-#endif
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
@@ -1323,36 +1320,78 @@ out:
 }
 
 #if IS_ENABLED(CONFIG_MSM_QMP)
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
+/**
+ * cnss_aop_interface_init: Initialize AOP interface: either mbox channel or direct QMP
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Device tree file should have either mbox or qmp configured, but not both.
+ * Based on device tree configuration setup mbox channel or QMP
+ *
+ * Return: 0 for success, otherwise error code
+ */
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv)
 {
 	struct mbox_client *mbox = &plat_priv->mbox_client_data;
 	struct mbox_chan *chan;
 	int ret;
 
 	plat_priv->mbox_chan = NULL;
+	plat_priv->qmp = NULL;
+	plat_priv->use_direct_qmp = false;
 
 	mbox->dev = &plat_priv->plat_dev->dev;
 	mbox->tx_block = true;
 	mbox->tx_tout = CNSS_MBOX_TIMEOUT_MS;
 	mbox->knows_txdone = false;
 
+	/* First try to get mbox channel, if it fails then try qmp_get
+	 * In device tree file there should be either mboxes or qmp,
+	 * cannot have both properties at the same time.
+	 */
 	chan = mbox_request_channel(mbox, 0);
 	if (IS_ERR(chan)) {
-		cnss_pr_err("Failed to get mbox channel\n");
-		return PTR_ERR(chan);
+		cnss_pr_dbg("Failed to get mbox channel, try qmp get\n");
+		plat_priv->qmp = qmp_get(&plat_priv->plat_dev->dev);
+		if (IS_ERR(plat_priv->qmp)) {
+			cnss_pr_err("Failed to get qmp\n");
+			return PTR_ERR(plat_priv->qmp);
+		} else {
+			plat_priv->use_direct_qmp = true;
+			cnss_pr_dbg("QMP initialized\n");
+		}
+	} else {
+		plat_priv->mbox_chan = chan;
+		cnss_pr_dbg("Mbox channel initialized\n");
 	}
 
-	plat_priv->mbox_chan = chan;
-	cnss_pr_dbg("Mbox channel initialized\n");
 	ret = cnss_aop_pdc_reconfig(plat_priv);
 	if (ret)
 		cnss_pr_err("Failed to reconfig WLAN PDC, err = %d\n", ret);
 
-	return 0;
+	return ret;
 }
 
 /**
- * cnss_aop_send_msg: Sends json message to AOP using QMP
+ * cnss_aop_interface_deinit: Cleanup AOP interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Cleanup mbox channel or QMP whichever was configured during initialization.
+ *
+ * Return: None
+ */
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (!IS_ERR_OR_NULL(plat_priv->mbox_chan))
+		mbox_free_channel(plat_priv->mbox_chan);
+
+	if (!IS_ERR_OR_NULL(plat_priv->qmp)) {
+		qmp_put(plat_priv->qmp);
+		plat_priv->use_direct_qmp = false;
+	}
+}
+
+/**
+ * cnss_aop_send_msg: Sends json message to AOP using either mbox channel or direct QMP
  * @plat_priv: Pointer to cnss platform data
  * @msg: String in json format
  *
@@ -1370,15 +1409,24 @@ int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
 	struct qmp_pkt pkt;
 	int ret = 0;
 
-	cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
-	pkt.size = CNSS_MBOX_MSG_MAX_LEN;
-	pkt.data = mbox_msg;
 
-	ret = mbox_send_message(plat_priv->mbox_chan, &pkt);
-	if (ret < 0)
-		cnss_pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg);
-	else
-		ret = 0;
+	if (plat_priv->use_direct_qmp) {
+		cnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg);
+		ret = qmp_send(plat_priv->qmp, mbox_msg, CNSS_MBOX_MSG_MAX_LEN);
+		if (ret < 0)
+			cnss_pr_err("Failed to send AOP QMP msg: %s\n", mbox_msg);
+		else
+			ret = 0;
+	} else {
+		cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
+		pkt.size = CNSS_MBOX_MSG_MAX_LEN;
+		pkt.data = mbox_msg;
+		ret = mbox_send_message(plat_priv->mbox_chan, &pkt);
+		if (ret < 0)
+			cnss_pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg);
+		else
+			ret = 0;
+	}
 
 	return ret;
 }
@@ -1470,11 +1518,13 @@ int cnss_aop_ol_cpr_cfg_setup(struct cnss_plat_data *plat_priv,
 	if (config_done)
 		return 0;
 
-	if (plat_priv->pmu_vreg_map_len <= 0 || !plat_priv->mbox_chan ||
-	    !plat_priv->pmu_vreg_map) {
-		cnss_pr_dbg("Mbox channel / PMU VReg Map not configured\n");
+	if (plat_priv->pmu_vreg_map_len <= 0 ||
+	    !plat_priv->pmu_vreg_map ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / PMU VReg Map not configured\n");
 		goto end;
 	}
+
 	if (!fw_pmu_cfg)
 		return -EINVAL;
 
@@ -1574,11 +1624,15 @@ end:
 }
 
 #else
-int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv)
 {
 	return 0;
 }
 
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv)
+{
+}
+
 int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg)
 {
 	return 0;
@@ -1726,8 +1780,9 @@ int cnss_update_cpr_info(struct cnss_plat_data *plat_priv)
 	if (plat_priv->device_id != QCA6490_DEVICE_ID)
 		return -EINVAL;
 
-	if (!plat_priv->vreg_ol_cpr || !plat_priv->mbox_chan) {
-		cnss_pr_dbg("Mbox channel / OL CPR Vreg not configured\n");
+	if (!plat_priv->vreg_ol_cpr ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / OL CPR Vreg not configured\n");
 	} else {
 		return cnss_aop_set_vreg_param(plat_priv,
 					       plat_priv->vreg_ol_cpr,
@@ -1806,8 +1861,9 @@ int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv)
 		return 0;
 	}
 
-	if (!plat_priv->vreg_ipa || !plat_priv->mbox_chan) {
-		cnss_pr_dbg("Mbox channel / IPA Vreg not configured\n");
+	if (!plat_priv->vreg_ipa ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / IPA Vreg not configured\n");
 	} else {
 		ret = cnss_aop_set_vreg_param(plat_priv,
 					      plat_priv->vreg_ipa,