ソースを参照

Merge 02e22639bc64fc20863a4bb86813cd8983410962 on remote branch

Change-Id: Ia5482794c3693c6e6d13c7a4479712f6c79df9db
Linux Build Service Account 1 年間 前
コミット
ba9ccd5db9

+ 47 - 0
cnss2/bus.c

@@ -154,6 +154,22 @@ int cnss_bus_load_tme_patch(struct cnss_plat_data *plat_priv)
 	}
 }
 
+int cnss_bus_load_tme_opt_file(struct cnss_plat_data *plat_priv,
+				enum wlfw_tme_lite_file_type_v01 file)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_load_tme_opt_file(plat_priv->bus_priv, file);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
 int cnss_bus_load_m3(struct cnss_plat_data *plat_priv)
 {
 	if (!plat_priv)
@@ -459,6 +475,37 @@ int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
 	}
 }
 
+int cnss_bus_runtime_pm_get_sync(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_pm_runtime_get_sync(plat_priv->bus_priv, RTPM_ID_CNSS);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+void cnss_bus_runtime_pm_put(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		cnss_pci_pm_runtime_mark_last_busy(plat_priv->bus_priv);
+		cnss_pci_pm_runtime_put_autosuspend(plat_priv->bus_priv, RTPM_ID_CNSS);
+		break;
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+	}
+}
+
 int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
 {
 	if (!plat_priv)

+ 4 - 0
cnss2/bus.h

@@ -22,6 +22,10 @@ void cnss_bus_deinit(struct cnss_plat_data *plat_priv);
 void cnss_bus_add_fw_prefix_name(struct cnss_plat_data *plat_priv,
 				 char *prefix_name, char *name);
 int cnss_bus_load_tme_patch(struct cnss_plat_data *plat_priv);
+int cnss_bus_load_tme_opt_file(struct cnss_plat_data *plat_priv,
+				enum wlfw_tme_lite_file_type_v01 file);
+int cnss_bus_runtime_pm_get_sync(struct cnss_plat_data *plat_priv);
+void cnss_bus_runtime_pm_put(struct cnss_plat_data *plat_priv);
 int cnss_bus_load_m3(struct cnss_plat_data *plat_priv);
 int cnss_bus_load_aux(struct cnss_plat_data *plat_priv);
 int cnss_bus_handle_dev_sol_irq(struct cnss_plat_data *plat_priv);

+ 61 - 0
cnss2/main.c

@@ -592,6 +592,10 @@ bool cnss_get_fw_cap(struct device *dev, enum cnss_fw_caps fw_cap)
 		if (is_supported && cnss_get_audio_iommu_domain(plat_priv))
 			is_supported = false;
 		break;
+	case CNSS_FW_CAP_CALDB_SEG_DDR_SUPPORT:
+		is_supported = !!(plat_priv->fw_caps &
+				  QMI_WLFW_CALDB_SEG_DDR_SUPPORT_V01);
+		break;
 	default:
 		cnss_pr_err("Invalid FW Capability: 0x%x\n", fw_cap);
 	}
@@ -4120,6 +4124,23 @@ static ssize_t recovery_show(struct device *dev,
 	return curr_len;
 }
 
+static ssize_t tme_opt_file_download_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	u32 buf_size = PAGE_SIZE;
+	u32 curr_len = 0;
+	u32 buf_written = 0;
+
+	buf_written = scnprintf(buf, buf_size,
+				"Usage: echo [file_type] > /sys/kernel/cnss/tme_opt_file_download\n"
+				"file_type = sec -- For OEM_FUSE file\n"
+				"file_type = rpr -- For RPR file\n"
+				"file_type = dpr -- For DPR file\n");
+
+	curr_len += buf_written;
+	return curr_len;
+}
+
 static ssize_t time_sync_period_show(struct device *dev,
 				     struct device_attribute *attr,
 				     char *buf)
@@ -4369,6 +4390,44 @@ static ssize_t qdss_conf_download_store(struct device *dev,
 	return count;
 }
 
+static ssize_t tme_opt_file_download_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	char cmd[5];
+
+	if (sscanf(buf, "%s", cmd) != 1)
+		return -EINVAL;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return 0;
+	}
+
+	if (plat_priv->device_id == PEACH_DEVICE_ID &&
+	    cnss_bus_runtime_pm_get_sync(plat_priv) < 0)
+		goto runtime_pm_put;
+
+	if (strcmp(cmd, "sec") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_OEM_FUSE_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_OEM_FUSE_FILE_V01);
+	} else if (strcmp(cmd, "rpr") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_RPR_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_RPR_FILE_V01);
+	} else if (strcmp(cmd, "dpr") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_DPR_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_DPR_FILE_V01);
+	}
+
+	cnss_pr_dbg("Received tme_opt_file_download indication cmd: %s\n", cmd);
+
+runtime_pm_put:
+	if (plat_priv->device_id == PEACH_DEVICE_ID)
+		cnss_bus_runtime_pm_put(plat_priv);
+	return count;
+}
+
 static ssize_t hw_trace_override_store(struct device *dev,
 				       struct device_attribute *attr,
 				       const char *buf, size_t count)
@@ -4406,6 +4465,7 @@ static DEVICE_ATTR_WO(enable_hds);
 static DEVICE_ATTR_WO(qdss_trace_start);
 static DEVICE_ATTR_WO(qdss_trace_stop);
 static DEVICE_ATTR_WO(qdss_conf_download);
+static DEVICE_ATTR_RW(tme_opt_file_download);
 static DEVICE_ATTR_WO(hw_trace_override);
 static DEVICE_ATTR_WO(charger_mode);
 static DEVICE_ATTR_RW(time_sync_period);
@@ -4418,6 +4478,7 @@ static struct attribute *cnss_attrs[] = {
 	&dev_attr_qdss_trace_start.attr,
 	&dev_attr_qdss_trace_stop.attr,
 	&dev_attr_qdss_conf_download.attr,
+	&dev_attr_tme_opt_file_download.attr,
 	&dev_attr_hw_trace_override.attr,
 	&dev_attr_charger_mode.attr,
 	&dev_attr_time_sync_period.attr,

+ 7 - 0
cnss2/main.h

@@ -59,6 +59,7 @@
 #define CNSS_RAMDUMP_MAGIC		0x574C414E
 #define CNSS_RAMDUMP_VERSION		0
 #define MAX_FIRMWARE_NAME_LEN		40
+#define FW_V1_NUMBER                    1
 #define FW_V2_NUMBER                    2
 #ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
 #define POWER_ON_RETRY_MAX_TIMES	2
@@ -80,6 +81,10 @@
 #define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
 				CNSS_EVENT_UNINTERRUPTIBLE)
 #define CNSS_EVENT_SYNC_UNKILLABLE (CNSS_EVENT_SYNC | CNSS_EVENT_UNKILLABLE)
+#define QMI_WLFW_MAX_TME_OPT_FILE_NUM 3
+#define TME_OEM_FUSE_FILE_NAME		"peach_sec.dat"
+#define TME_RPR_FILE_NAME		"peach_rpr.bin"
+#define TME_DPR_FILE_NAME		"peach_dpr.bin"
 
 enum cnss_dt_type {
 	CNSS_DTT_LEGACY = 0,
@@ -277,6 +282,7 @@ enum cnss_fw_dump_type {
 	CNSS_FW_IMAGE,
 	CNSS_FW_RDDM,
 	CNSS_FW_REMOTE_HEAP,
+	CNSS_FW_CAL,
 	CNSS_FW_DUMP_TYPE_MAX,
 };
 
@@ -550,6 +556,7 @@ struct cnss_plat_data {
 	struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 	struct cnss_fw_mem m3_mem;
 	struct cnss_fw_mem tme_lite_mem;
+	struct cnss_fw_mem tme_opt_file_mem[QMI_WLFW_MAX_TME_OPT_FILE_NUM];
 	struct cnss_fw_mem *cal_mem;
 	struct cnss_fw_mem aux_mem;
 	u64 cal_time;

+ 250 - 5
cnss2/pci.c

@@ -48,7 +48,8 @@
 #define DEFAULT_PHY_M3_FILE_NAME	"m3.bin"
 #define DEFAULT_AUX_FILE_NAME		"aux_ucode.elf"
 #define DEFAULT_PHY_UCODE_FILE_NAME	"phy_ucode.elf"
-#define TME_PATCH_FILE_NAME		"tmel_patch.elf"
+#define TME_PATCH_FILE_NAME_1_0		"tmel_peach_10.elf"
+#define TME_PATCH_FILE_NAME_2_0		"tmel_peach_20.elf"
 #define PHY_UCODE_V2_FILE_NAME		"phy_ucode20.elf"
 #define DEFAULT_FW_FILE_NAME		"amss.bin"
 #define FW_V2_FILE_NAME			"amss20.bin"
@@ -254,6 +255,124 @@ static const struct mhi_channel_config cnss_mhi_channels[] = {
 #endif
 };
 
+static const struct mhi_channel_config cnss_mhi_channels_no_diag[] = {
+	{
+		.num = 0,
+		.name = "LOOPBACK",
+		.num_elements = 32,
+		.event_ring = 1,
+		.dir = DMA_TO_DEVICE,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = false,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 1,
+		.name = "LOOPBACK",
+		.num_elements = 32,
+		.event_ring = 1,
+		.dir = DMA_FROM_DEVICE,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = false,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 20,
+		.name = "IPCR",
+		.num_elements = 64,
+		.event_ring = 1,
+		.dir = DMA_TO_DEVICE,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = false,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 21,
+		.name = "IPCR",
+		.num_elements = 64,
+		.event_ring = 1,
+		.dir = DMA_FROM_DEVICE,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = false,
+		.doorbell_mode_switch = false,
+		.auto_queue = true,
+	},
+/* All MHI satellite config to be at the end of data struct */
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	{
+		.num = 50,
+		.name = "ADSP_0",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 51,
+		.name = "ADSP_1",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 70,
+		.name = "ADSP_2",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 71,
+		.name = "ADSP_3",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+#endif
+};
+
 static const struct mhi_channel_config cnss_mhi_channels_genoa[] = {
 	{
 		.num = 0,
@@ -403,6 +522,22 @@ static const struct mhi_event_config cnss_mhi_events[] = {
 #define CNSS_MHI_SATELLITE_EVT_COUNT 0
 #endif
 
+static const struct mhi_controller_config cnss_mhi_config_no_diag = {
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	.max_channels = 72,
+#else
+	.max_channels = 32,
+#endif
+	.timeout_ms = 10000,
+	.use_bounce_buf = false,
+	.buf_len = 0x8000,
+	.num_channels = ARRAY_SIZE(cnss_mhi_channels_no_diag),
+	.ch_cfg = cnss_mhi_channels_no_diag,
+	.num_events = ARRAY_SIZE(cnss_mhi_events),
+	.event_cfg = cnss_mhi_events,
+	.m2_no_db = true,
+};
+
 static const struct mhi_controller_config cnss_mhi_config_default = {
 #if IS_ENABLED(CONFIG_MHI_SATELLITE)
 	.max_channels = 72,
@@ -4855,7 +4990,10 @@ int cnss_pci_load_tme_patch(struct cnss_pci_data *pci_priv)
 
 	switch (pci_priv->device_id) {
 	case PEACH_DEVICE_ID:
-		tme_patch_filename = TME_PATCH_FILE_NAME;
+		if (plat_priv->device_version.major_version == FW_V1_NUMBER)
+			tme_patch_filename = TME_PATCH_FILE_NAME_1_0;
+		else if (plat_priv->device_version.major_version == FW_V2_NUMBER)
+			tme_patch_filename = TME_PATCH_FILE_NAME_2_0;
 		break;
 	case QCA6174_DEVICE_ID:
 	case QCA6290_DEVICE_ID:
@@ -4870,8 +5008,7 @@ int cnss_pci_load_tme_patch(struct cnss_pci_data *pci_priv)
 	}
 
 	if (!tme_lite_mem->va && !tme_lite_mem->size) {
-		cnss_pci_add_fw_prefix_name(pci_priv, filename,
-					    tme_patch_filename);
+		scnprintf(filename, MAX_FIRMWARE_NAME_LEN, "%s", tme_patch_filename);
 
 		ret = firmware_request_nowarn(&fw_entry, filename,
 					      &pci_priv->pci_dev->dev);
@@ -4916,6 +5053,91 @@ static void cnss_pci_free_tme_lite_mem(struct cnss_pci_data *pci_priv)
 	tme_lite_mem->size = 0;
 }
 
+int cnss_pci_load_tme_opt_file(struct cnss_pci_data *pci_priv,
+				enum wlfw_tme_lite_file_type_v01 file)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_lite_mem = NULL;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	char *tme_opt_filename = NULL;
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	switch (pci_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		if (file == WLFW_TME_LITE_OEM_FUSE_FILE_V01) {
+			tme_opt_filename = TME_OEM_FUSE_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[0];
+		} else if (file == WLFW_TME_LITE_RPR_FILE_V01) {
+			tme_opt_filename = TME_RPR_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[1];
+		} else if (file == WLFW_TME_LITE_DPR_FILE_V01) {
+			tme_opt_filename = TME_DPR_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[2];
+		}
+		break;
+	case QCA6174_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	default:
+		cnss_pr_dbg("TME-L opt file: %s not supported for device ID: (0x%x)\n",
+			    tme_opt_filename, pci_priv->device_id);
+		return 0;
+	}
+
+	if (!tme_lite_mem->va && !tme_lite_mem->size) {
+		cnss_pci_add_fw_prefix_name(pci_priv, filename,
+					    tme_opt_filename);
+
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load TME-L opt file: %s, ret: %d\n",
+				    filename, ret);
+			return ret;
+		}
+
+		tme_lite_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &tme_lite_mem->pa,
+						GFP_KERNEL);
+		if (!tme_lite_mem->va) {
+			cnss_pr_err("Failed to allocate memory for TME-L opt file %s,size: 0x%zx\n",
+				    filename, fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(tme_lite_mem->va, fw_entry->data, fw_entry->size);
+		tme_lite_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_tme_opt_file_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_opt_file_mem = plat_priv->tme_opt_file_mem;
+	int i = 0;
+
+	for (i = 0; i < QMI_WLFW_MAX_TME_OPT_FILE_NUM; i++) {
+		if (tme_opt_file_mem[i].va && tme_opt_file_mem[i].size) {
+			cnss_pr_dbg("Free memory for TME opt file,va:0x%pK, pa:%pa, size:0x%zx\n",
+				tme_opt_file_mem[i].va, &tme_opt_file_mem[i].pa,
+				tme_opt_file_mem[i].size);
+			dma_free_coherent(&pci_priv->pci_dev->dev, tme_opt_file_mem[i].size,
+				tme_opt_file_mem[i].va, tme_opt_file_mem[i].pa);
+		}
+		tme_opt_file_mem[i].va = NULL;
+		tme_opt_file_mem[i].pa = 0;
+		tme_opt_file_mem[i].size = 0;
+	}
+}
+
 int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
 {
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -5937,7 +6159,7 @@ static void cnss_pci_add_dump_seg(struct cnss_pci_data *pci_priv,
 	cnss_pr_dbg("Seg: %x, va: %pK, dma: %pa, size: 0x%zx\n",
 		    seg_no, va, &dma, size);
 
-	if (cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS))
+	if (type == CNSS_FW_CAL || cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS))
 		return;
 
 	cnss_minidump_add_region(plat_priv, type, seg_no, va, pa, size);
@@ -6212,6 +6434,16 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
 			} else {
 				cnss_pr_dbg("Skip remote heap dumps as it is non-contiguous\n");
 			}
+		} else if (fw_mem[i].type == CNSS_MEM_CAL_V01) {
+				cnss_pr_dbg("Collect CAL memory dump segment\n");
+				cnss_pci_add_dump_seg(pci_priv, dump_seg,
+						      CNSS_FW_CAL, j,
+						      fw_mem[i].va,
+						      fw_mem[i].pa,
+						      fw_mem[i].size);
+				dump_seg++;
+				dump_data->nentries++;
+				j++;
 		}
 	}
 
@@ -6264,6 +6496,13 @@ void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
 						 fw_mem[i].size);
 			dump_seg++;
 			j++;
+		} else if (fw_mem[i].type == CNSS_MEM_CAL_V01) {
+			cnss_pci_remove_dump_seg(pci_priv, dump_seg,
+						 CNSS_FW_CAL, j,
+						 fw_mem[i].va, fw_mem[i].pa,
+						 fw_mem[i].size);
+			dump_seg++;
+			j++;
 		}
 	}
 
@@ -6854,6 +7093,11 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
 			cnss_mhi_config = &cnss_mhi_config_no_satellite;
 	}
 
+	/* DIAG no longer supported on PEACH and later chipset */
+	if (plat_priv->device_id >= PEACH_DEVICE_ID) {
+		cnss_mhi_config = &cnss_mhi_config_no_diag;
+	}
+
 	mhi_ctrl->tme_supported_image = cnss_is_tme_supported(pci_priv);
 
 	ret = mhi_register_controller(mhi_ctrl, cnss_mhi_config);
@@ -7445,6 +7689,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev)
 	cnss_pci_unregister_driver_hdlr(pci_priv);
 	cnss_pci_free_aux_mem(pci_priv);
 	cnss_pci_free_tme_lite_mem(pci_priv);
+	cnss_pci_free_tme_opt_file_mem(pci_priv);
 	cnss_pci_free_m3_mem(pci_priv);
 	cnss_pci_free_fw_mem(pci_priv);
 	cnss_pci_free_qdss_mem(pci_priv);

+ 2 - 0
cnss2/pci.h

@@ -260,6 +260,8 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv);
 void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_load_tme_patch(struct cnss_pci_data *pci_priv);
+int cnss_pci_load_tme_opt_file(struct cnss_pci_data *pci_priv,
+				enum wlfw_tme_lite_file_type_v01 file);
 int cnss_pci_load_m3(struct cnss_pci_data *pci_priv);
 void cnss_pci_free_blob_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_load_aux(struct cnss_pci_data *pci_priv);

+ 105 - 0
cnss2/qmi.c

@@ -58,6 +58,10 @@
 #define QMI_WLFW_MAC_READY_TIMEOUT_MS	50
 #define QMI_WLFW_MAC_READY_MAX_RETRY	200
 
+// these error values are not defined in <linux/soc/qcom/qmi.h> and fw is sending as error response
+#define QMI_ERR_HARDWARE_RESTRICTED_V01		0x0053
+#define QMI_ERR_ENOMEM_V01		0x0002
+
 enum nm_modem_bit {
 	SLEEP_CLOCK_SELECT_INTERNAL_BIT = BIT(1),
 	HOST_CSTATE_BIT = BIT(2),
@@ -982,6 +986,107 @@ out:
 	return ret;
 }
 
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file)
+{
+	struct wlfw_tme_lite_info_req_msg_v01 *req;
+	struct wlfw_tme_lite_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *tme_opt_file_mem = NULL;
+	char *file_name = NULL;
+	int ret = 0;
+
+	if (plat_priv->device_id != PEACH_DEVICE_ID)
+		return 0;
+
+	cnss_pr_dbg("Sending TME opt file information message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	if (file == WLFW_TME_LITE_OEM_FUSE_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[0];
+		file_name = TME_OEM_FUSE_FILE_NAME;
+	} else if (file == WLFW_TME_LITE_RPR_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[1];
+		file_name = TME_RPR_FILE_NAME;
+	} else if (file == WLFW_TME_LITE_DPR_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[2];
+		file_name = TME_DPR_FILE_NAME;
+	}
+
+	if (!tme_opt_file_mem->pa || !tme_opt_file_mem->size) {
+		cnss_pr_err("Memory for TME opt file is not available\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("TME opt file %s memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    file_name, tme_opt_file_mem->va, &tme_opt_file_mem->pa, tme_opt_file_mem->size);
+
+	req->tme_file = file;
+	req->addr = tme_opt_file_mem->pa;
+	req->size = tme_opt_file_mem->size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_tme_lite_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_TME_LITE_INFO_REQ_V01,
+			       WLFW_TME_LITE_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_tme_lite_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		ret = -resp->resp.result;
+		if (resp->resp.error == QMI_ERR_HARDWARE_RESTRICTED_V01) {
+			cnss_pr_err("TME Power On failed\n");
+			goto out;
+		} else if (resp->resp.error == QMI_ERR_ENOMEM_V01) {
+			cnss_pr_err("malloc SRAM failed\n");
+			goto out;
+		}
+		cnss_pr_err("TME opt file information request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
 int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
 {
 	struct wlfw_m3_info_req_msg_v01 *req;

+ 8 - 0
cnss2/qmi.h

@@ -87,6 +87,8 @@ void cnss_dms_deinit(struct cnss_plat_data *plat_priv);
 int cnss_wlfw_qdss_dnld_send_sync(struct cnss_plat_data *plat_priv);
 int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_name,
 				  u32 total_size);
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file);
 int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv);
 int wlfw_qdss_trace_stop(struct cnss_plat_data *plat_priv, unsigned long long option);
 int cnss_wlfw_cal_report_req_send_sync(struct cnss_plat_data *plat_priv,
@@ -297,6 +299,12 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n
 	return 0;
 }
 
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file)
+{
+	return 0;
+}
+
 static inline void cnss_dms_deinit(struct cnss_plat_data *plat_priv) {}
 
 int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv)

+ 2 - 0
cnss_genl/pitti_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_genl/pitti_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_genl/volcano_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_genl/volcano_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_prealloc/pitti_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_prealloc/pitti_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_prealloc/volcano_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
cnss_prealloc/volcano_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
cnss_utils/pitti_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
cnss_utils/pitti_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
cnss_utils/volcano_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
cnss_utils/volcano_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 1 - 0
cnss_utils/wlan_firmware_service_v01.h

@@ -402,6 +402,7 @@ enum wlfw_lpass_ssr_reason_v01 {
 #define QMI_WLFW_HOST_PCIE_GEN_SWITCH_V01 ((u64)0x01ULL)
 #define QMI_WLFW_DIRECT_LINK_SUPPORT_V01 ((u64)0x02ULL)
 #define QMI_WLFW_AUX_UC_SUPPORT_V01 ((u64)0x04ULL)
+#define QMI_WLFW_CALDB_SEG_DDR_SUPPORT_V01 ((u64)0x08ull)
 
 struct wlfw_ce_tgt_pipe_cfg_s_v01 {
 	u32 pipe_num;

+ 1 - 0
icnss2/main.c

@@ -4815,6 +4815,7 @@ static int icnss_probe(struct platform_device *pdev)
 		icnss_pr_err("fw service registration failed: %d\n", ret);
 		goto out_destroy_wq;
 	}
+	icnss_power_misc_params_init(priv);
 
 	icnss_enable_recovery(priv);
 

+ 4 - 0
icnss2/main.h

@@ -492,6 +492,8 @@ struct icnss_priv {
 	struct qmp *qmp;
 #endif
 	bool use_direct_qmp;
+	const char **pdc_init_table;
+	int pdc_init_table_len;
 	u32 wlan_en_delay_ms;
 	u32 wlan_en_delay_ms_user;
 	struct class *icnss_ramdump_class;
@@ -552,6 +554,8 @@ void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
 			      char *name);
 int icnss_aop_interface_init(struct icnss_priv *priv);
 void icnss_aop_interface_deinit(struct icnss_priv *priv);
+int icnss_aop_pdc_reconfig(struct icnss_priv *priv);
+void icnss_power_misc_params_init(struct icnss_priv *priv);
 void icnss_recovery_timeout_hdlr(struct timer_list *t);
 void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
 #endif

+ 6 - 0
icnss2/pitti_consolidate_defconfig

@@ -0,0 +1,6 @@
+CONFIG_ICNSS2=m
+CONFIG_ICNSS2_DEBUG=y
+CONFIG_ICNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 5 - 0
icnss2/pitti_gki_defconfig

@@ -0,0 +1,5 @@
+CONFIG_ICNSS2=m
+CONFIG_ICNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 93 - 7
icnss2/power.c

@@ -751,13 +751,14 @@ int icnss_aop_interface_init(struct icnss_priv *priv)
 {
 	struct mbox_client *mbox = &priv->mbox_client_data;
 	struct mbox_chan *chan;
-	int ret = 0;
+	int ret = 0, ol_cpr = 0;
 
-	ret = of_property_read_string(priv->pdev->dev.of_node,
-				      "qcom,vreg_ol_cpr",
-				      &priv->cpr_info.vreg_ol_cpr);
-	if (ret) {
-		icnss_pr_dbg("Vreg for OL CPR not configured\n");
+	ol_cpr = of_property_read_string(priv->pdev->dev.of_node,
+					 "qcom,vreg_ol_cpr",
+					 &priv->cpr_info.vreg_ol_cpr);
+
+	if (ol_cpr && !priv->pdc_init_table) {
+		icnss_pr_dbg("Vreg for OL CPR and pdc_init table not configured\n");
 		return -EINVAL;
 	}
 
@@ -789,11 +790,15 @@ int icnss_aop_interface_init(struct icnss_priv *priv)
 		priv->mbox_chan = chan;
 		icnss_pr_dbg("Mbox channel initialized\n");
 	}
+	ret = icnss_aop_pdc_reconfig(priv);
+	if (ret)
+		icnss_pr_err("Failed to reconfig WLAN PDC, err = %d\n", ret);
+
 	return ret;
 }
 
 /**
- * cnss_aop_interface_deinit: Cleanup AOP interface
+ * icnss_aop_interface_deinit: Cleanup AOP interface
  * @priv: Pointer to icnss platform data
  *
  * Cleanup mbox channel or QMP whichever was configured during initialization.
@@ -850,6 +855,53 @@ static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
 
 	return ret;
 }
+
+/* icnss_aop_pdc_reconfig: Send AOP msg to configure PDC table for WLAN device
+ * @priv: Pointer to icnss platform data
+ *
+ * Send AOP QMP or Mbox msg to configure PDC table for WLAN device
+ *
+ * Return: 0 for success, otherwise error code
+ */
+int icnss_aop_pdc_reconfig(struct icnss_priv *priv)
+{
+	u32 i;
+	int ret;
+	char *mbox_msg;
+	struct qmp_pkt pkt;
+
+	if (priv->pdc_init_table_len <= 0 || !priv->pdc_init_table)
+		return 0;
+
+	icnss_pr_dbg("Setting PDC defaults for device ID: (0x%x)\n",
+		     priv->device_id);
+	for (i = 0; i < priv->pdc_init_table_len; i++) {
+		mbox_msg = (char *)priv->pdc_init_table[i];
+		if (priv->use_direct_qmp) {
+			icnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg);
+			ret = qmp_send(priv->qmp, mbox_msg,
+				       ICNSS_MBOX_MSG_MAX_LEN);
+			if (ret < 0)
+				icnss_pr_err("Failed to send AOP QMP msg: %s\n",
+					     mbox_msg);
+			else
+				ret = 0;
+		} else {
+			icnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
+			pkt.size = ICNSS_MBOX_MSG_MAX_LEN;
+			pkt.data = mbox_msg;
+
+			ret = mbox_send_message(priv->mbox_chan, &pkt);
+			if (ret < 0)
+				icnss_pr_err("Failed to send AOP mbox msg: %s,ret: %d\n",
+					     mbox_msg, ret);
+			else
+				ret = 0;
+		}
+	}
+	return ret;
+}
+
 #else
 int icnss_aop_interface_init(struct icnss_priv *priv)
 {
@@ -867,8 +919,42 @@ static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
 {
 	return 0;
 }
+
+int icnss_aop_pdc_reconfig(struct icnss_priv *priv)
+{
+	return 0;
+}
+
 #endif
 
+void icnss_power_misc_params_init(struct icnss_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+	int ret;
+
+	/* common DT Entries */
+	priv->pdc_init_table_len =
+				of_property_count_strings(dev->of_node,
+							  "qcom,pdc_init_table");
+	if (priv->pdc_init_table_len > 0) {
+		priv->pdc_init_table =
+			kcalloc(priv->pdc_init_table_len,
+				sizeof(char *), GFP_KERNEL);
+		if (priv->pdc_init_table) {
+			ret = of_property_read_string_array(dev->of_node,
+						"qcom,pdc_init_table",
+						priv->pdc_init_table,
+						priv->pdc_init_table_len);
+			if (ret < 0)
+				icnss_pr_err("Failed to get PDC Init Table\n");
+		} else {
+			icnss_pr_err("Failed to alloc PDC Init Table mem\n");
+		}
+	} else {
+		icnss_pr_dbg("PDC Init Table not configured\n");
+	}
+}
+
 int icnss_update_cpr_info(struct icnss_priv *priv)
 {
 	struct icnss_cpr_info *cpr_info = &priv->cpr_info;

+ 6 - 0
icnss2/volcano_consolidate_defconfig

@@ -0,0 +1,6 @@
+CONFIG_ICNSS2=m
+CONFIG_ICNSS2_DEBUG=y
+CONFIG_ICNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 5 - 0
icnss2/volcano_gki_defconfig

@@ -0,0 +1,5 @@
+CONFIG_ICNSS2=m
+CONFIG_ICNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 1 - 0
inc/cnss2.h

@@ -346,6 +346,7 @@ enum cnss_recovery_reason {
 enum cnss_fw_caps {
 	CNSS_FW_CAP_DIRECT_LINK_SUPPORT,
 	CNSS_FW_CAP_AUX_UC_SUPPORT,
+	CNSS_FW_CAP_CALDB_SEG_DDR_SUPPORT,
 };
 
 enum cnss_remote_mem_type {

+ 1 - 1
wlan_platform_modules.bzl

@@ -10,7 +10,7 @@ _default_module_enablement_list = [
 ]
 
 _cnss2_enabled_target = ["niobe", "pineapple", "sun"]
-_icnss2_enabled_target = ["blair", "pineapple", "monaco"]
+_icnss2_enabled_target = ["blair", "pineapple", "monaco", "pitti", "volcano"]
 
 def _get_module_list(target, variant):
     tv = "{}_{}".format(target, variant)