Browse Source

cnss2: Update AOP Mbox interface for PDC config

AOP Mbox interface message is updated to include the PDC name as WLAN
devices like KIWI needs 2 PDCs.

Also following updates are done:
1. Always open Mbox channel for OL CPR update.
2. Add device tree config for PDC - VReg mapping and
   WLAN device PDC Init table.
3. Reconfig PDC based on WLAN device connected to the platform.
4. Add debug interface for PDC update.

Change-Id: Ia3150166a0ef5d44cb74a8c7e3b78870284cd18f
Manikandan Mohan 3 years ago
parent
commit
5f2db0d3b8
4 changed files with 211 additions and 47 deletions
  1. 15 1
      cnss2/debug.c
  2. 1 0
      cnss2/main.c
  3. 5 0
      cnss2/main.h
  4. 190 46
      cnss2/power.c

+ 15 - 1
cnss2/debug.c

@@ -190,6 +190,8 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
 	char buf[64];
 	char *cmd;
 	unsigned int len = 0;
+	char *sptr, *token;
+	const char *delim = " ";
 	int ret = 0;
 
 	if (!plat_priv)
@@ -200,7 +202,12 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
 		return -EFAULT;
 
 	buf[len] = '\0';
-	cmd = buf;
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+	cmd = token;
 	cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
 
 	if (sysfs_streq(cmd, "on")) {
@@ -223,6 +230,10 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
 		ret = cnss_set_host_sol_value(plat_priv, 1);
 	} else if (sysfs_streq(cmd, "deassert_host_sol")) {
 		ret = cnss_set_host_sol_value(plat_priv, 0);
+	} else if (sysfs_streq(cmd, "pdc_update")) {
+		if (!sptr)
+			return -EINVAL;
+		ret = cnss_aop_send_msg(plat_priv, sptr);
 	} else {
 		pci_priv = plat_priv->bus_priv;
 		if (!pci_priv)
@@ -268,6 +279,9 @@ static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
 	seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
 	seq_puts(s, "assert: trigger firmware assert\n");
 	seq_puts(s, "set_cbc_done: Set cold boot calibration done status\n");
+	seq_puts(s, "\npdc_update usage:");
+	seq_puts(s, "1. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: <vreg>.<mode>, <seq>: <val>} > <debugfs_path>/cnss/dev_boot\n");
+	seq_puts(s, "2. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: pdc, enable: <val>} > <debugfs_path>/cnss/dev_boot\n");
 
 	return 0;
 }

+ 1 - 0
cnss2/main.c

@@ -3840,6 +3840,7 @@ static int cnss_probe(struct platform_device *plat_dev)
 
 	cnss_get_pm_domain_info(plat_priv);
 	cnss_get_wlaon_pwr_ctrl_info(plat_priv);
+	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);

+ 5 - 0
cnss2/main.h

@@ -535,6 +535,8 @@ struct cnss_plat_data {
 	struct mbox_client mbox_client_data;
 	struct mbox_chan *mbox_chan;
 	const char *vreg_ol_cpr, *vreg_ipa;
+	const char **pdc_init_table, **vreg_pdc_map;
+	int pdc_init_table_len, vreg_pdc_map_len;
 	bool adsp_pc_enabled;
 	u64 feature_list;
 	u32 is_converged_dt;
@@ -612,6 +614,9 @@ 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_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);
 int cnss_request_firmware_direct(struct cnss_plat_data *plat_priv,
 				 const struct firmware **fw_entry,
 				 const char *filename);

+ 190 - 46
cnss2/power.c

@@ -82,30 +82,40 @@ static struct cnss_clk_cfg cnss_clk_list[] = {
 #define CNSS_MBOX_TIMEOUT_MS 1000
 
 /**
- * enum cnss_vreg_param: Voltage regulator TCS param
- * @CNSS_VREG_VOLTAGE: Provides voltage level to be configured in TCS
+ * enum cnss_aop_vreg_param: Voltage regulator TCS param
+ * @CNSS_VREG_VOLTAGE: Provides voltage level in mV to be configured in TCS
  * @CNSS_VREG_MODE: Regulator mode
- * @CNSS_VREG_TCS_ENABLE: Set Voltage regulator enable config in TCS
+ * @CNSS_VREG_TCS_ENABLE: Set bool Voltage regulator enable config in TCS.
  */
-enum cnss_vreg_param {
+enum cnss_aop_vreg_param {
 	CNSS_VREG_VOLTAGE,
 	CNSS_VREG_MODE,
 	CNSS_VREG_ENABLE,
+	CNSS_VREG_PARAM_MAX
+};
+
+/** enum cnss_aop_vreg_param_mode: Voltage modes supported by AOP*/
+enum cnss_aop_vreg_param_mode {
+	CNSS_VREG_RET_MODE = 3,
+	CNSS_VREG_LPM_MODE = 4,
+	CNSS_VREG_AUTO_MODE = 6,
+	CNSS_VREG_NPM_MODE = 7,
+	CNSS_VREG_MODE_MAX
 };
 
 /**
- * enum cnss_tcs_seq: TCS sequence ID for trigger
- * CNSS_TCS_UP_SEQ: TCS Sequence based on up trigger / Wake TCS
- * CNSS_TCS_DOWN_SEQ: TCS Sequence based on down trigger / Sleep TCS
- * CNSS_TCS_ALL_SEQ: Update for both up and down triggers
+ * enum cnss_aop_tcs_seq: TCS sequence ID for trigger
+ * @CNSS_TCS_UP_SEQ: TCS Sequence based on up trigger / Wake TCS
+ * @CNSS_TCS_DOWN_SEQ: TCS Sequence based on down trigger / Sleep TCS
+ * @CNSS_TCS_ENABLE_SEQ: Enable this TCS seq entry
  */
-enum cnss_tcs_seq {
+enum cnss_aop_tcs_seq_param {
 	CNSS_TCS_UP_SEQ,
 	CNSS_TCS_DOWN_SEQ,
-	CNSS_TCS_ALL_SEQ,
+	CNSS_TCS_ENABLE_SEQ,
+	CNSS_TCS_SEQ_MAX
 };
 
-
 static int cnss_get_vreg_single(struct cnss_plat_data *plat_priv,
 				struct cnss_vreg_info *vreg)
 {
@@ -1133,34 +1143,20 @@ out:
 	return ret;
 }
 
+#if IS_ENABLED(CONFIG_MSM_QMP)
 int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
 {
 	struct mbox_client *mbox = &plat_priv->mbox_client_data;
 	struct mbox_chan *chan;
-	int ret = 0;
+	int ret;
+
+	plat_priv->mbox_chan = NULL;
 
 	mbox->dev = &plat_priv->plat_dev->dev;
 	mbox->tx_block = true;
 	mbox->tx_tout = CNSS_MBOX_TIMEOUT_MS;
 	mbox->knows_txdone = false;
 
-	plat_priv->mbox_chan = NULL;
-
-	ret = of_property_read_string(plat_priv->plat_dev->dev.of_node,
-				      "qcom,vreg_ol_cpr",
-				      &plat_priv->vreg_ol_cpr);
-	if (ret)
-		cnss_pr_dbg("Vreg for OL CPR not configured\n");
-
-	ret = of_property_read_string(plat_priv->plat_dev->dev.of_node,
-				      "qcom,vreg_ipa",
-				      &plat_priv->vreg_ipa);
-	if (ret)
-		cnss_pr_dbg("Volt regulator for Int Power Amp not configured\n");
-
-	if (!plat_priv->vreg_ol_cpr && !plat_priv->vreg_ipa)
-		return 0;
-
 	chan = mbox_request_channel(mbox, 0);
 	if (IS_ERR(chan)) {
 		cnss_pr_err("Failed to get mbox channel\n");
@@ -1169,29 +1165,32 @@ int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
 
 	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;
 }
 
-#if IS_ENABLED(CONFIG_MSM_QMP)
-static int cnss_aop_set_vreg_param(struct cnss_plat_data *plat_priv,
-				   const char *vreg_name,
-				   enum cnss_vreg_param param,
-				   enum cnss_tcs_seq seq, int val)
+/**
+ * cnss_aop_send_msg: Sends json message to AOP using QMP
+ * @plat_priv: Pointer to cnss platform data
+ * @msg: String in json format
+ *
+ * AOP accepts JSON message to configure WLAN resources. Format as follows:
+ * To send VReg config: {class: wlan_pdc, ss: <pdc_name>,
+ *                       res: <VReg_name>.<param>, <seq_param>: <value>}
+ * To send PDC Config: {class: wlan_pdc, ss: <pdc_name>, res: pdc,
+ *                      enable: <Value>}
+ * QMP returns timeout error if format not correct or AOP operation fails.
+ *
+ * Return: 0 for success
+ */
+int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
 {
 	struct qmp_pkt pkt;
-	char mbox_msg[CNSS_MBOX_MSG_MAX_LEN];
-	static const char * const vreg_param_str[] = {"v", "m", "e"};
-	static const char *const tcs_seq_str[] = {"upval", "dwnval", "enable"};
 	int ret = 0;
 
-	if (param > CNSS_VREG_ENABLE || seq > CNSS_TCS_ALL_SEQ || !vreg_name)
-		return -EINVAL;
-
-	snprintf(mbox_msg, CNSS_MBOX_MSG_MAX_LEN,
-		 "{class: wlan_pdc, res: %s.%s, %s: %d}", vreg_name,
-		 vreg_param_str[param], tcs_seq_str[seq], val);
-
 	cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
 	pkt.size = CNSS_MBOX_MSG_MAX_LEN;
 	pkt.data = mbox_msg;
@@ -1204,16 +1203,161 @@ static int cnss_aop_set_vreg_param(struct cnss_plat_data *plat_priv,
 
 	return ret;
 }
+
+/* cnss_pdc_reconfig: Send PDC init table as configured in DT for wlan device */
+int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv)
+{
+	u32 i;
+	int ret;
+
+	if (plat_priv->pdc_init_table_len <= 0 || !plat_priv->pdc_init_table)
+		return 0;
+
+	cnss_pr_dbg("Setting PDC defaults for device ID: %d\n",
+		    plat_priv->device_id);
+	for (i = 0; i < plat_priv->pdc_init_table_len; i++) {
+		ret = cnss_aop_send_msg(plat_priv,
+					(char *)plat_priv->pdc_init_table[i]);
+		if (ret < 0)
+			break;
+	}
+	return ret;
+}
+
+/* cnss_aop_pdc_name_str: Get PDC name corresponding to VReg from DT Mapiping */
+static const char *cnss_aop_pdc_name_str(struct cnss_plat_data *plat_priv,
+					 const char *vreg_name)
+{
+	u32 i;
+	static const char * const aop_pdc_ss_str[] = {"rf", "bb"};
+	const char *pdc = aop_pdc_ss_str[0], *vreg_map_name;
+
+	if (plat_priv->vreg_pdc_map_len <= 0 || !plat_priv->vreg_pdc_map)
+		goto end;
+
+	for (i = 0; i < plat_priv->vreg_pdc_map_len; i++) {
+		vreg_map_name = plat_priv->vreg_pdc_map[i];
+		if (strnstr(vreg_map_name, vreg_name, strlen(vreg_map_name))) {
+			pdc = plat_priv->vreg_pdc_map[i + 1];
+			break;
+		}
+	}
+end:
+	cnss_pr_dbg("%s mapped to %s\n", vreg_name, pdc);
+	return pdc;
+}
+
+static int cnss_aop_set_vreg_param(struct cnss_plat_data *plat_priv,
+				   const char *vreg_name,
+				   enum cnss_aop_vreg_param param,
+				   enum cnss_aop_tcs_seq_param seq_param,
+				   int val)
+{
+	char msg[CNSS_MBOX_MSG_MAX_LEN];
+	static const char * const aop_vreg_param_str[] = {
+		[CNSS_VREG_VOLTAGE] = "v", [CNSS_VREG_MODE] = "m",
+		[CNSS_VREG_ENABLE] = "e",};
+	static const char * const aop_tcs_seq_str[] = {
+		[CNSS_TCS_UP_SEQ] = "upval", [CNSS_TCS_DOWN_SEQ] = "dwnval",
+		[CNSS_TCS_ENABLE_SEQ] = "enable",};
+
+	if (param >= CNSS_VREG_PARAM_MAX || seq_param >= CNSS_TCS_SEQ_MAX ||
+	    !vreg_name)
+		return -EINVAL;
+
+	snprintf(msg, CNSS_MBOX_MSG_MAX_LEN,
+		 "{class: wlan_pdc, ss: %s, res: %s.%s, %s: %d}",
+		 cnss_aop_pdc_name_str(plat_priv, vreg_name),
+		 vreg_name, aop_vreg_param_str[param],
+		 aop_tcs_seq_str[seq_param], val);
+
+	return cnss_aop_send_msg(plat_priv, msg);
+}
 #else
+int cnss_aop_mbox_init(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg)
+{
+	return 0;
+}
+
+int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
 static int cnss_aop_set_vreg_param(struct cnss_plat_data *plat_priv,
 				   const char *vreg_name,
-				   enum cnss_vreg_param param,
-				   enum cnss_tcs_seq seq, int val)
+				   enum cnss_aop_vreg_param param,
+				   enum cnss_aop_tcs_seq_pram seq_param,
+				   int val)
 {
 	return 0;
 }
 #endif
 
+void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	int ret;
+
+	/* common DT Entries */
+	plat_priv->pdc_init_table_len =
+				of_property_count_strings(dev->of_node,
+							  "qcom,pdc_init_table");
+	if (plat_priv->pdc_init_table_len > 0) {
+		plat_priv->pdc_init_table =
+			kcalloc(plat_priv->pdc_init_table_len,
+				sizeof(char *), GFP_KERNEL);
+		ret =
+		of_property_read_string_array(dev->of_node,
+					      "qcom,pdc_init_table",
+					      plat_priv->pdc_init_table,
+					      plat_priv->pdc_init_table_len);
+		if (ret < 0)
+			cnss_pr_err("Failed to get PDC Init Table\n");
+	} else {
+		cnss_pr_dbg("PDC Init Table not configured\n");
+	}
+
+	plat_priv->vreg_pdc_map_len =
+			of_property_count_strings(dev->of_node,
+						  "qcom,vreg_pdc_map");
+	if (plat_priv->vreg_pdc_map_len > 0) {
+		plat_priv->vreg_pdc_map =
+			kcalloc(plat_priv->vreg_pdc_map_len,
+				sizeof(char *), GFP_KERNEL);
+		ret =
+		of_property_read_string_array(dev->of_node,
+					      "qcom,vreg_pdc_map",
+					      plat_priv->vreg_pdc_map,
+					      plat_priv->vreg_pdc_map_len);
+		if (ret < 0)
+			cnss_pr_err("Failed to get VReg PDC Mapping\n");
+	} else {
+		cnss_pr_dbg("VReg PDC Mapping not configured\n");
+	}
+
+	/* Device DT Specific */
+	if (plat_priv->device_id == QCA6390_DEVICE_ID ||
+	    plat_priv->device_id == QCA6490_DEVICE_ID) {
+		ret = of_property_read_string(dev->of_node,
+					      "qcom,vreg_ol_cpr",
+					      &plat_priv->vreg_ol_cpr);
+		if (ret)
+			cnss_pr_dbg("VReg for QCA6490 OL CPR not configured\n");
+
+		ret = of_property_read_string(dev->of_node,
+					      "qcom,vreg_ipa",
+					      &plat_priv->vreg_ipa);
+		if (ret)
+			cnss_pr_dbg("VReg for QCA6490 Int Power Amp not configured\n");
+	}
+}
+
 int cnss_update_cpr_info(struct cnss_plat_data *plat_priv)
 {
 	struct cnss_cpr_info *cpr_info = &plat_priv->cpr_info;