--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -25,7 +25,7 @@
 #include "ahb.h"
 
 static const struct of_device_id ath10k_ahb_of_match[] = {
-	{ .compatible = "qcom,ipq4019-wifi",
+	{ .compatible = "qca,wifi-ipq40xx",
 	  .data = (void *)ATH10K_HW_QCA4019
 	},
 	{ }
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -19,6 +19,8 @@
 #include <linux/firmware.h>
 #include <linux/of.h>
 #include <asm/byteorder.h>
+#include <linux/mtd/mtd.h>
+#include <linux/vmalloc.h>
 
 #include "core.h"
 #include "mac.h"
@@ -69,6 +71,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 2116,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA988X_HW_2_0_FW_DIR,
 			.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
@@ -89,6 +92,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 2116,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA9887_HW_1_0_FW_DIR,
 			.board = QCA9887_HW_1_0_BOARD_DATA_FILE,
@@ -108,6 +112,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA6174_HW_2_1_FW_DIR,
 			.board = QCA6174_HW_2_1_BOARD_DATA_FILE,
@@ -127,6 +132,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA6174_HW_2_1_FW_DIR,
 			.board = QCA6174_HW_2_1_BOARD_DATA_FILE,
@@ -146,6 +152,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA6174_HW_3_0_FW_DIR,
 			.board = QCA6174_HW_3_0_BOARD_DATA_FILE,
@@ -165,6 +172,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			/* uses same binaries as hw3.0 */
 			.dir = QCA6174_HW_3_0_FW_DIR,
@@ -190,6 +198,7 @@ static const struct ath10k_hw_params ath
 		.rx_chain_mask = 0xf,
 		.max_spatial_stream = 4,
 		.cal_data_len = 12064,
+		.board_id_cap = 1,
 		.fw = {
 			.dir = QCA99X0_HW_2_0_FW_DIR,
 			.board = QCA99X0_HW_2_0_BOARD_DATA_FILE,
@@ -216,6 +225,7 @@ static const struct ath10k_hw_params ath
 		.rx_chain_mask = 0xf,
 		.max_spatial_stream = 4,
 		.cal_data_len = 12064,
+		.board_id_cap = 1,
 		.fw = {
 			.dir = QCA9984_HW_1_0_FW_DIR,
 			.board = QCA9984_HW_1_0_BOARD_DATA_FILE,
@@ -241,6 +251,7 @@ static const struct ath10k_hw_params ath
 		.rx_chain_mask = 3,
 		.max_spatial_stream = 2,
 		.cal_data_len = 12064,
+		.board_id_cap = 1,
 		.fw = {
 			.dir = QCA9888_HW_2_0_FW_DIR,
 			.board = QCA9888_HW_2_0_BOARD_DATA_FILE,
@@ -261,6 +272,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA9377_HW_1_0_FW_DIR,
 			.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
@@ -280,6 +292,7 @@ static const struct ath10k_hw_params ath
 		.channel_counters_freq_hz = 88000,
 		.max_probe_resp_desc_thres = 0,
 		.cal_data_len = 8124,
+		.board_id_cap = 0,
 		.fw = {
 			.dir = QCA9377_HW_1_0_FW_DIR,
 			.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
@@ -305,6 +318,7 @@ static const struct ath10k_hw_params ath
 		.rx_chain_mask = 0x3,
 		.max_spatial_stream = 2,
 		.cal_data_len = 12064,
+		.board_id_cap = 1,
 		.fw = {
 			.dir = QCA4019_HW_1_0_FW_DIR,
 			.board = QCA4019_HW_1_0_BOARD_DATA_FILE,
@@ -553,6 +567,125 @@ exit:
 	return ret;
 }
 
+static int ath10k_verify_mtd_cal_data_chksum(u32 *data, u32 len)
+{
+	u16 *buf = (u16 *)data;
+	u16 sum;
+	int i;
+
+	sum = 0;
+
+	for (i = 0; i < (len / 2); i++)
+		sum ^= le16_to_cpu(*buf++);
+
+	if (sum != 0xffff)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ath10k_download_cal_data_mtd(struct ath10k *ar)
+{
+	struct device_node *node;
+	struct mtd_info *mtd;
+	size_t retlen;
+	u32 *buf, addr, len;
+	const char *mtd_name;
+	int ret, i;
+
+	node = ar->dev->of_node;
+	if (!node) {
+		/* Device Tree is optional, don't print any warnings if
+		 * there is no node for ath10k.
+		 */
+		return -ENOENT;
+	}
+
+	ret = of_property_read_u32(node, "qcom,cal-len", &len);
+	if (ret)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "qcom,cal-offset", &addr);
+	if (ret)
+		return -ENOENT;
+
+	mtd_name = of_get_property(node, "qcom,mtd-name", NULL);
+	if (!mtd_name)
+		return -ENOENT;
+
+	if (len != ar->hw_params.cal_data_len) {
+		ath10k_warn(ar, "invalid cal data length in DT: %d\n", len);
+		return -EMSGSIZE;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "mtd name: %s addr: 0x%x len: %d\n",
+		   mtd_name, addr, len);
+
+	buf = vmalloc(len);
+	if (!buf) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "failed to alloc memory for mtd caldata\n");
+		return -ENOMEM;
+	}
+
+	mtd = get_mtd_device_nm(mtd_name);
+	if (IS_ERR_OR_NULL(mtd)) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "mtd device %s not found to read caldata\n",
+			   mtd_name);
+		ret = PTR_ERR(mtd);
+		goto release_buf;
+	}
+
+	ret = mtd_read(mtd, addr, len, &retlen, (u_char *)buf);
+	if (ret) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "failed to read caldata from mtd device %s: %d\n",
+			   mtd_name, ret);
+		goto release_mtd;
+	}
+
+	if (retlen != len) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "got only %d bytes from mtd (requested: %d)\n",
+			   retlen, len);
+		goto release_mtd;
+	}
+
+	ret = ath10k_verify_mtd_cal_data_chksum(buf, len);
+	if (ret) {
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
+			   "checksum verification failed\n");
+		goto release_mtd;
+	}
+
+	for (i = 0; i < (len / 4); i++)
+		buf[i] = cpu_to_le32(buf[i]);
+
+	ret = ath10k_download_board_data(ar, (const void *)buf,
+					 (size_t)len);
+	if (ret) {
+		ath10k_err(ar, "failed to download mtd caldata: %d\n", ret);
+		goto release_mtd;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
+		   "cal data downloaded successfully\n");
+
+	put_mtd_device(mtd);
+	vfree(buf);
+
+	return 0;
+
+release_mtd:
+	put_mtd_device(mtd);
+
+release_buf:
+	vfree(buf);
+
+	return ret;
+}
+
 static int ath10k_download_cal_file(struct ath10k *ar,
 				    const struct firmware *file)
 {
@@ -663,7 +796,7 @@ static int ath10k_core_get_board_id_from
 {
 	u32 result, address;
 	u8 board_id, chip_id;
-	int ret;
+	int ret, board_id_param;
 
 	address = ar->hw_params.patch_load_addr;
 
@@ -687,8 +820,12 @@ static int ath10k_core_get_board_id_from
 		return ret;
 	}
 
-	ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID,
-				 &result);
+	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_FLASH_MTD)
+		board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;
+	else
+		board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;
+
+	ret = ath10k_bmi_execute(ar, address, board_id_param, &result);
 	if (ret) {
 		ath10k_err(ar, "could not execute otp for board id check: %d\n",
 			   ret);
@@ -747,6 +884,9 @@ static int ath10k_download_and_run_otp(s
 		return ret;
 	}
 
+	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_FLASH_MTD)
+		bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
+
 	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
 	if (ret) {
 		ath10k_err(ar, "could not execute otp (%d)\n", ret);
@@ -1338,6 +1478,12 @@ static int ath10k_core_pre_cal_download(
 {
 	int ret;
 
+	ret = ath10k_download_cal_data_mtd(ar);
+	if (ret == 0) {
+		ar->cal_mode = ATH10K_PRE_CAL_MODE_FLASH_MTD;
+		goto success;
+	}
+
 	ret = ath10k_download_cal_file(ar, ar->pre_cal_file);
 	if (ret == 0) {
 		ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;
@@ -1374,8 +1520,11 @@ static int ath10k_core_pre_cal_config(st
 		return ret;
 	}
 
+	if (!ar->hw_params.board_id_cap)
+		return 0;
+
 	ret = ath10k_core_get_board_id_from_otp(ar);
-	if (ret) {
+	if (ret && ret != -EOPNOTSUPP) {
 		ath10k_err(ar, "failed to get board id: %d\n", ret);
 		return ret;
 	}
@@ -2138,6 +2287,9 @@ static int ath10k_core_probe_fw(struct a
 			   "could not load pre cal data: %d\n", ret);
 	}
 
+	if (!ar->hw_params.board_id_cap)
+		goto skip_get_board_id;
+
 	ret = ath10k_core_get_board_id_from_otp(ar);
 	if (ret && ret != -EOPNOTSUPP) {
 		ath10k_err(ar, "failed to get board id from otp: %d\n",
@@ -2145,6 +2297,7 @@ static int ath10k_core_probe_fw(struct a
 		goto err_free_firmware_files;
 	}
 
+skip_get_board_id:
 	ret = ath10k_core_fetch_board_file(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to fetch board file: %d\n", ret);
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -83,6 +83,8 @@ enum bmi_cmd_id {
 #define BMI_NVRAM_SEG_NAME_SZ 16
 
 #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10
+#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000
+#define BMI_PARAM_FLASH_SECTION_ALL 0x10000
 
 #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK   0x7c00
 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB    10
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -623,6 +623,7 @@ enum ath10k_cal_mode {
 	ATH10K_PRE_CAL_MODE_FILE,
 	ATH10K_PRE_CAL_MODE_DT,
 	ATH10K_CAL_MODE_EEPROM,
+	ATH10K_PRE_CAL_MODE_FLASH_MTD,
 };
 
 enum ath10k_crypt_mode {
@@ -647,6 +648,8 @@ static inline const char *ath10k_cal_mod
 		return "pre-cal-dt";
 	case ATH10K_CAL_MODE_EEPROM:
 		return "eeprom";
+	case ATH10K_PRE_CAL_MODE_FLASH_MTD:
+		return "flash mtd part";
 	}
 
 	return "unknown";
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -422,6 +422,7 @@ struct ath10k_hw_params {
 	u32 rx_chain_mask;
 	u32 max_spatial_stream;
 	u32 cal_data_len;
+	bool board_id_cap;
 
 	struct ath10k_hw_params_fw {
 		const char *dir;
