[Feature] merge MTK MR3.0 from 20220916

Change-Id: I7e07c7c1a6069994f9938d3d8a01cac6fd3bc5ae
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
index 7dd96f1..af9ea72 100755
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/auto2735evb.dts
@@ -187,7 +187,11 @@
 	interrupt-parent = <&pio>;
 	interrupts = <65 IRQ_TYPE_LEVEL_HIGH>;
 
+#if defined(CONFIG_MTK_SGMII_NETSYS) /*merge MTK3.0 on 20220917*/
 	status = "okay";
+#else /*merge MTK3.0 on 20220917*/
+	status = "disabled" /*merge MTK3.0 on 20220917*/;
+#endif /*merge MTK3.0 on 20220917*/
 
 	port5: port@5 {
 		compatible = "mediatek,mt753x-port";
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/evb6890v1_64_cpe/cust.dtsi b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/evb6890v1_64_cpe/cust.dtsi
index 0aad9d5..fe4c2ca 100644
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/evb6890v1_64_cpe/cust.dtsi
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/evb6890v1_64_cpe/cust.dtsi
@@ -151,7 +151,7 @@
 	GPIO_SIM2_SRST = <&pio 89 0>;
 	GPIO_SIM2_SIO = <&pio 90 0>;
 	GPIO_FDD_BAND_SUPPORT_DETECT_1ST_PIN = <&pio 142 0>;
-	GPIO_FDD_BAND_SUPPORT_DETECT_2ND_PIN = <&pio 152 0>;
+	GPIO_FDD_BAND_SUPPORT_DETECT_2ND_PIN = <&pio 152 0> /*< chencheng 20220916: add DR/DI function>*/;
 };
 
 &gpio{
diff --git a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
index 66ee7a3..d60ce99 100644
--- a/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
+++ b/src/kernel/linux/v4.19/arch/arm64/boot/dts/mediatek/mt2735.dtsi
@@ -574,6 +574,14 @@
 		infracfg = <&infracfg_ao_clk>;
 		clocks = <&topckgen_clk CLK_TOP_MM_SEL>,
 			<&topckgen_clk CLK_TOP_MFG_SEL>,
+			<&topckgen_clk CLK_TOP_MEDSYS_SEL>,
+			<&topckgen_clk CLK_TOP_NETSYS_SEL>,
+			<&topckgen_clk CLK_TOP_NETSYS_500M_SEL>,
+			<&topckgen_clk CLK_TOP_NETSYS_MED_MCU_SEL>,
+			<&topckgen_clk CLK_TOP_NETSYS_WED_MCU_SEL>,
+			<&topckgen_clk CLK_TOP_NETSYS_2X_SEL>,
+			<&topckgen_clk CLK_TOP_SGMII_SEL>,
+			<&topckgen_clk CLK_TOP_SGMII_SBUS_SEL>,
 			<&topckgen_clk CLK_TOP_SNPS_ETH_312P5M_SEL>,
 			<&topckgen_clk CLK_TOP_SNPS_ETH_250M_SEL>,
 			<&topckgen_clk CLK_TOP_SNPS_ETH_62P4M_PTP_SEL>,
@@ -583,6 +591,14 @@
 			<&topckgen_clk CLK_TOP_HSM_ARC_SEL>;
 		clock-names = "mm",
 			"mfg",
+			"medsys_sel",
+			"netsys_sel",
+			"netsys_500m_sel",
+			"netsys_med_mcu_sel",
+			"netsys_wed_mcu_sel",
+			"netsys_2x_sel",
+			"sgmii_sel",
+			"sgmii_sbus_sel",
 			"snps_eth_312p5m_sel",
  			"snps_eth_250m_sel",
 			"snps_ptp_sel",
@@ -3201,6 +3217,11 @@
                 reg = <0 0x15195000 0 0x1000>;
         };
 
+	hnat: hnat@15100e00 {
+		compatible = "mediatek,hnat", "syscon";
+		reg = <0 0x15100e00 0 0x1000>;
+	};
+
 	eth: ethernet@15100000 {
 #if defined(CONFIG_MTK_SGMII_NETSYS)
 		compatible = "mediatek,mt6890-eth",
@@ -3241,8 +3262,8 @@
 			      "med_mcu_sel", "wed_mcu_sel",
 			      "net_2x_sel";
 #endif
-        /*modify by CLK SW Pei-hsuan Cheng
-		power-domains = <&scpsys MT6890_POWER_DOMAIN_NETSYS>;*/
+        /*modify by CLK SW Pei-hsuan Cheng*/
+		power-domains = <&scpsys MT6890_POWER_DOMAIN_NETSYS>;
 		mediatek,ethsys = <&ethsys>;
 		mediatek,wo = <&wo>;
 #if defined(CONFIG_MTK_SGMII_NETSYS)
@@ -4150,7 +4171,8 @@
                 <0 0x15fff000 0 0x100>,      /* mbox4 base */
                 <0 0x15fff100 0 0x4>,        /* mbox4 set */
                 <0 0x15fff10c 0 0x4>,        /* mbox4 clr */
-                <0 0x15fa5030 0 0x4>;        /* mbox4 init */
+                <0 0x15fa5030 0 0x4>,        /* mbox4 init */
+                <0 0x15B80000 0 0x100>;      /* MED_INFRA_CLK 0x15B80014 */
 
             reg-names = "scp_sram_base",
                 "scp_cfgreg",
diff --git a/src/kernel/linux/v4.19/drivers/base/regmap/regmap-debugfs.c b/src/kernel/linux/v4.19/drivers/base/regmap/regmap-debugfs.c
index 1adf923..eafc357 100644
--- a/src/kernel/linux/v4.19/drivers/base/regmap/regmap-debugfs.c
+++ b/src/kernel/linux/v4.19/drivers/base/regmap/regmap-debugfs.c
@@ -275,7 +275,7 @@
 }
 
 #undef REGMAP_ALLOW_WRITE_DEBUGFS
-#define REGMAP_ALLOW_WRITE_DEBUGFS
+#define REGMAP_ALLOW_WRITE_DEBUGFS//<chencheng 20220512: modify codec registers from userspace>
 
 #ifdef REGMAP_ALLOW_WRITE_DEBUGFS
 /*
diff --git a/src/kernel/linux/v4.19/drivers/mfd/mt6330-core.c b/src/kernel/linux/v4.19/drivers/mfd/mt6330-core.c
index 4dbb81f..bd4c6a5 100644
--- a/src/kernel/linux/v4.19/drivers/mfd/mt6330-core.c
+++ b/src/kernel/linux/v4.19/drivers/mfd/mt6330-core.c
@@ -143,42 +143,44 @@
 	.cid_shift = 0,
 };
 
-static int mt6330_spmi_reg_read(void *context,
-				unsigned int reg, unsigned int *val)
-{
-	struct mt6330_chip *data = context;
-	u8 regval = 0;
-	int ret;
-
-	ret = spmi_ext_register_readl(data->sdev, reg, &regval, 1);
-	if (ret < 0)
-		return ret;
-	*val = regval;
-
-	return 0;
-}
-
-static int mt6330_spmi_reg_write(void *context,
-				 unsigned int reg, unsigned int val)
+static int mt6330_spmi_read(void *context, const void *reg, size_t reg_size,
+			    void *val, size_t val_size)
 {
 	struct mt6330_chip *data = context;
 	int ret;
+	u16 addr = cpu_to_be16(*(u16 *)reg);
 
-	ret = spmi_ext_register_writel(data->sdev, reg, (u8 *)&val, 1);
-	if (ret)
-		return ret;
+	ret = spmi_ext_register_readl(data->sdev, addr, val, val_size);
 
-	return 0;
+	return ret;
 }
 
+static int mt6330_spmi_write(void *context, const void *data, size_t count)
+{
+	struct mt6330_chip *ddata = context;
+	u16 addr = cpu_to_be16(*(u16 *)data);
+	u8 *val = (u8 *)data + 2;
+	int val_size = count - 2;
+	int ret;
+
+	ret = spmi_ext_register_writel(ddata->sdev, addr, (u8 *)val, val_size);
+
+	return ret;
+}
+
+static struct regmap_bus mt6330_regmap_bus = {
+	.read = mt6330_spmi_read,
+	.write = mt6330_spmi_write,
+	.max_raw_read = 2,
+	.max_raw_write = 2,
+};
+
 static const struct regmap_config spmi_regmap_config = {
 	.reg_bits	= 16,
 	.val_bits	= 8,
 	.max_register	= 0x22ff,
 	.fast_io	= true,
-	.use_single_rw  = true,
-	.reg_read	= mt6330_spmi_reg_read,
-	.reg_write	= mt6330_spmi_reg_write,
+	.use_single_rw  = false,
 };
 static int mt6330_probe(struct spmi_device *sdev)
 {
@@ -204,7 +206,8 @@
 	 * mt6330 MFD is child device of soc pmic spmi.
 	 * Regmap is set from its parent.
 	 */
-	regmap = devm_regmap_init(&sdev->dev, NULL, pmic, &spmi_regmap_config);
+	regmap = devm_regmap_init(&sdev->dev, &mt6330_regmap_bus,
+				pmic, &spmi_regmap_config);
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 	pmic->regmap = regmap;
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/hif/ccci_hif_dpmaif.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/hif/ccci_hif_dpmaif.c
index 0938c75..034ee5f 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/hif/ccci_hif_dpmaif.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/eccci/hif/ccci_hif_dpmaif.c
@@ -2781,6 +2781,46 @@
 	mutex_unlock(&scp_A_notify_mutex);
 }
 
+void ccci_dpmaif_reset_pit_nat_indexes(void)
+{
+	//reset pit_nat indexes because medmcu is reset.
+	//Note: this timing is medmcu confirmed all pkts are handled and stop irqs.
+	//At resume state it should no timing issue since no pkt remained and no ipi triggered.
+	struct dpmaif_rx_queue *rxq;
+	int i;
+	for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
+		rxq = &dpmaif_ctrl->rxq[i];
+		CCCI_NORMAL_LOG(-1, TAG, "[dpmaif] pit_nat_idx[%d]: %d, %d, %d\n",
+				i, rxq->pit_rd_idx, rxq->pit_wr_idx, rxq->pit_rel_rd_idx);
+		//error when these indexes not all match
+		if (!(rxq->pit_rd_idx == rxq->pit_wr_idx && rxq->pit_rd_idx == rxq->pit_rel_rd_idx)) {
+			//KE! idx not process done!
+		}
+
+		//reset pit_nat related index to zero
+		rxq->pit_rd_idx = 0;
+		rxq->pit_wr_idx = 0;
+		rxq->pit_rel_rd_idx = 0;
+	}
+}
+EXPORT_SYMBOL_GPL(ccci_dpmaif_reset_pit_nat_indexes);
+
+void ccci_dpmaif_resend_ready(void)
+{
+	//check if dpmaif driver alive when medmcu resume
+	//Note: this timing is medmcu confirmed all pkts are handled and stop irqs.
+	//At resume state it should no timing issue since no pkt remained and no ipi triggered.
+	if (dpmaif_ctrl->dpmaif_state != HIFDPMAIF_STATE_PWRON) {
+		CCCI_NORMAL_LOG(-1, TAG, "[dpmaif] abnormal err, pwrdown when medmcu resume\n");
+		CCCI_HISTORY_LOG(-1, TAG, "[dpmaif] abnormal err, pwrdown when medmcu resume\n");
+		return;
+	}
+	CCCI_NORMAL_LOG(-1, TAG, "[dpmaif] resume send ready");
+	/*Blocking call notify for dpmaif start*/
+	ccci_dpmaif_notify(CCCI_DPMAIF_EVENT_READY);
+}
+EXPORT_SYMBOL_GPL(ccci_dpmaif_resend_ready);
+
 void ccci_dpmaif_register_notify(struct notifier_block *nb)
 {
 	CCCI_NORMAL_LOG(-1, TAG, "[Register]ccci_dpmaif_register_notify start");
@@ -2811,12 +2851,11 @@
 	unsigned long event, void *ptr)
 {
 	switch (event) {
-	case SCP_EVENT_STOP_ACK:
-		//to-do, change to medmcu stop ack event
-		CCCI_HISTORY_TAG_LOG(-1, TAG, "medmcu notified\n");
-		CCCI_NORMAL_LOG(-1, TAG, "medmcu notified\n");
-		atomic_set(&med_mcu_ack_flag, 1);
-	break;
+		case SCP_EVENT_STOP_ACK/*to-do, change to medmcu stop ack event*/:
+			CCCI_HISTORY_TAG_LOG(-1, TAG, "medmcu notified\n");
+			CCCI_NORMAL_LOG(-1, TAG, "medmcu notified\n"); 
+			atomic_set(&med_mcu_ack_flag, 1);
+			break;
 	}
 	return NOTIFY_DONE;
 }
@@ -2925,8 +2964,7 @@
 		drv_dpmaif_unmask_dl_interrupt(rxq->index);
 #else
 		if (atomic_read(&rxq->should_ipi_re_process) != 0 &&
-				dpmaif_ctrl->dpmaif_state
-				== HIFDPMAIF_STATE_PWRON) {
+				dpmaif_ctrl->dpmaif_state == HIFDPMAIF_STATE_PWRON) {
 			atomic_set(&rxq->should_ipi_re_process, 0);
 			smp_mb(); /* for cpu exec. */
 			tasklet_hi_schedule(&rxq->dpmaif_rxq0_task);
@@ -3752,13 +3790,10 @@
 	CCCI_REPEAT_LOG(-1, TAG, "%s: i:0x%x t:0x%x\r\n",
 			__func__, irq_cpus, push_cpus);
 
-	//if (dpmaif_ctrl->dpmaif_irq_id)
-	//err1 = irq_force_affinity(dpmaif_ctrl->dpmaif_irq_id,
-	//	&imask);
+	/*if (dpmaif_ctrl->dpmaif_irq_id)
+		err1 = irq_force_affinity(dpmaif_ctrl->dpmaif_irq_id, &imask);*/
 	if (dpmaif_ctrl->rxq[0].rx_thread)
-		err2 = sched_setaffinity(
-				dpmaif_ctrl->rxq[0].rx_thread->pid,
-				&tmask);
+		err2 = sched_setaffinity(dpmaif_ctrl->rxq[0].rx_thread->pid, &tmask);
 	CCCI_BOOTUP_LOG(-1, TAG, "affinity: %d, %d\r\n",
 			err1, err2);
 	CCCI_NORMAL_LOG(-1, TAG, "affinity: %d, %d\r\n",
@@ -4148,6 +4183,7 @@
 	}
 #endif
 
+	CCCI_ERROR_LOG(-1, TAG, "tx init size: %ld, %ld\n", txq->drb_size_cnt * sizeof(struct dpmaif_drb_pd), txq->drb_size_cnt * sizeof(struct dpmaif_drb_skb));
 	return ret;
 }
 
@@ -4287,11 +4323,8 @@
 		rx_q->skb_idx = -1;
 	}
 #if defined(_DPMAIF_MED_SUPPORT_) && defined(ENABLE_CPU_AFFINITY_WITH_MED)
-	//TASK_AFFINITY_WITH_MED needs to run on different
-	//cpus from isrs
-	mtk_ccci_affinity_rta(IRQ_AFFINITY_WITH_MED,
-			TASK_AFFINITY_WITH_MED,
-			CCCI_CPUNUM);
+	/*TASK_AFFINITY_WITH_MED needs to run on different cpus from isrs*/
+	mtk_ccci_affinity_rta(IRQ_AFFINITY_WITH_MED, TASK_AFFINITY_WITH_MED, CCCI_CPUNUM);
 #endif
 
 	/* tx tx */
@@ -4919,8 +4952,9 @@
 
 	/*b. try to receive ack. Before receiving ack, use a while loop to block here*/
 	while (1) {
-		if (atomic_read(&med_mcu_ack_flag) == 1)
+		if (atomic_read(&med_mcu_ack_flag) == 1) {
 			break;
+		}
 	}
 	atomic_set(&med_mcu_ack_flag, 0);
 	CCCI_NORMAL_LOG(-1, TAG, "dpmaif:medmcu acked\n");
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/include/medmcu_ipi_pin.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/include/medmcu_ipi_pin.h
index 742b133..3e334ca 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/include/medmcu_ipi_pin.h
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/include/medmcu_ipi_pin.h
@@ -1,3 +1,4 @@
+
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2019 MediaTek Inc.
@@ -45,28 +46,31 @@
 	IPI_IN_MED_CCCI           = 12,
 	IPI_OUT_MED_STOP          = 13,
 	IPI_IN_MED_STOP_ACK       = 14,
+	IPI_OUT_QUERY_MED_SUSPEND = 15,
+	IPI_IN_MED_SUSPEND_RESPONSE = 16,
+	IPI_OUT_MED_UNMASK_IRQ    = 17,
 
 /* core1 */
 	/* the following will use mbox3 */
-	IPI_OUT_AUDIO_ULTRA_SND_1 = 15,
-	IPI_OUT_DVFS_SET_FREQ_1   = 16,
-	IPI_OUT_C_SLEEP_1         = 17,
-	IPI_OUT_TEST_1            = 18,
-	IPI_OUT_LOGGER_ENABLE_1   = 19,
-	IPI_OUT_LOGGER_WAKEUP_1   = 20,
-	IPI_OUT_LOGGER_INIT_1     = 21,
-	IPI_OUT_SCPCTL_1          = 22,
-	IPI_OUT_SCP_LOG_FILTER_1  = 23,
-	IPI_IN_AUDIO_ULTRA_SND_1  = 24,
-	IPI_IN_SCP_ERROR_INFO_1   = 25,
-	IPI_IN_LOGGER_WAKEUP_1    = 26,
-	IPI_IN_LOGGER_INIT_1      = 27,
-	IPI_IN_SCP_READY_1        = 28,
-	IPI_IN_SCP_RAM_DUMP_1     = 29,
+	IPI_OUT_AUDIO_ULTRA_SND_1 = 18,
+	IPI_OUT_DVFS_SET_FREQ_1   = 19,
+	IPI_OUT_C_SLEEP_1         = 20,
+	IPI_OUT_TEST_1            = 21,
+	IPI_OUT_LOGGER_ENABLE_1   = 22,
+	IPI_OUT_LOGGER_WAKEUP_1   = 23,
+	IPI_OUT_LOGGER_INIT_1     = 24,
+	IPI_OUT_SCPCTL_1          = 25,
+	IPI_OUT_SCP_LOG_FILTER_1  = 26,
+	IPI_IN_AUDIO_ULTRA_SND_1  = 27,
+	IPI_IN_SCP_ERROR_INFO_1   = 28,
+	IPI_IN_LOGGER_WAKEUP_1    = 29,
+	IPI_IN_LOGGER_INIT_1      = 30,
+	IPI_IN_SCP_READY_1        = 31,
+	IPI_IN_SCP_RAM_DUMP_1     = 32,
 
 	/* the following will use mbox4 */
-	IPI_OUT_SCP_MPOOL_1       = 30,
-	IPI_IN_SCP_MPOOL_1        = 31,
+	IPI_OUT_SCP_MPOOL_1       = 33,
+	IPI_IN_SCP_MPOOL_1        = 34,
 	SCP_IPI_COUNT
 };
 
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_helper.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_helper.h
index dbb4a3f..16b0083 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_helper.h
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_helper.h
@@ -88,6 +88,7 @@
 	RESET_TYPE_CMD = 2,
 	RESET_TYPE_TIMEOUT = 3,
 	RESET_TYPE_MD_EXCEP = 4,
+	RESET_TYPE_RESUME = 5,
 };
 
 struct scp_regs {
@@ -100,6 +101,7 @@
 	void __iomem *cfg_core1;
 	void __iomem *cfg_sec;
 	void __iomem *bus_tracker;
+	void __iomem *infra_clk;
 	int irq;
 	unsigned int total_tcmsize;
 	unsigned int cfgregsize;
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_ipi_table.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_ipi_table.h
index 3ff8962..910b300 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_ipi_table.h
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_ipi_table.h
@@ -81,6 +81,9 @@
 	{.mbox=2, .recv_opt=0, .buf_full_opt=1,
 	          .msg_size= PIN_IN_SIZE_MED_STOP_ACK,
 	          .chan_id =      IPI_IN_MED_STOP_ACK},
+	{.mbox=2, .recv_opt=0, .buf_full_opt=1,
+	          .msg_size= PIN_IN_SIZE_MED_SUSPEND_RESPONSE,
+	          .chan_id =      IPI_IN_MED_SUSPEND_RESPONSE},
 
 	{.mbox=3, .recv_opt=0, .buf_full_opt=1,
 	          .msg_size= PIN_IN_SIZE_AUDIO_ULTRA_SND_1,
@@ -140,6 +143,10 @@
 	          .chan_id  =      IPI_OUT_MED_TABLE_ADDR},
 	{.mbox=2, .msg_size = PIN_OUT_SIZE_MED_STOP,
 	          .chan_id  =      IPI_OUT_MED_STOP},
+	{.mbox=2, .msg_size = PIN_OUT_SIZE_QUERY_MED_SUSPEND ,
+	          .chan_id  =      IPI_OUT_QUERY_MED_SUSPEND },
+	{.mbox=2, .msg_size = PIN_OUT_SIZE_MED_UNMASK_IRQ ,
+	          .chan_id  =      IPI_OUT_MED_UNMASK_IRQ },
 
 	{.mbox=3, .msg_size = PIN_OUT_SIZE_AUDIO_ULTRA_SND_1,
 	          .chan_id  =      IPI_OUT_AUDIO_ULTRA_SND_1},
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_mbox_layout.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_mbox_layout.h
index f7f5652..bebc972 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_mbox_layout.h
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_mbox_layout.h
@@ -56,8 +56,11 @@
 /* this is mbox pool for 2 cores */
 #define PIN_OUT_SIZE_MED_TABLE_ADDR    18 /* the following will use mbox 2 */
 #define PIN_IN_SIZE_MED_CCCI           2 /* the following will use mbox 2 */
-#define PIN_OUT_SIZE_MED_STOP          2 /* the following will use mbox 2 */
+#define PIN_OUT_SIZE_MED_STOP          1 /* the following will use mbox 2 */
 #define PIN_IN_SIZE_MED_STOP_ACK       2 /* the following will use mbox 2 */
+#define PIN_OUT_SIZE_QUERY_MED_SUSPEND 1 /* the following will use mbox 2 */
+#define PIN_IN_SIZE_MED_SUSPEND_RESPONSE  1 /* the following will use mbox 2 */
+#define PIN_OUT_SIZE_MED_UNMASK_IRQ    1 /* the following will use mbox 2 */
 #define PIN_OUT_SIZE_SCP_MPOOL         34 /* the following will use mbox 4 */
 #define PIN_IN_SIZE_SCP_MPOOL          30 /* the following will use mbox 4 */
 #define PIN_OUT_SIZE_CHRE_0            34
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_reg.h b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_reg.h
index 6b94931..3461af7 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_reg.h
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/medmcu_reg.h
@@ -135,6 +135,7 @@
 
 /* clk reg*/
 #define SCP_A_SLEEP_DEBUG_REG		(scpreg.clkctrl + 0x0028)
+#define R_SET_CLK_CG				(scpreg.clkctrl + 0x0030) //medmcu CLK_CG
 #define SCP_CLK_CTRL_L1_SRAM_PD		(scpreg.clkctrl + 0x002C)
 #define SCP_CLK_HIGH_CORE_CG		(scpreg.clkctrl + 0x005C)
 #define SCP_CPU0_SRAM_PD		(scpreg.clkctrl + 0x0080)
@@ -156,5 +157,6 @@
 	#define CONNSYS_AWAKE_UNLOCK	(3)
 #define INFRA_IRQ_CLEAR			(scpreg.scpsys + 0x0B18)
 #define SCP_SYS_INFRA_MON		(scpreg.scpsys + 0x0D50)
+#define MED_INFRA_CLK			(scpreg.infra_clk + 0x14)
 
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/v02/medmcu_helper.c b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/v02/medmcu_helper.c
index 4e6df9f..a9986e0 100644
--- a/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/v02/medmcu_helper.c
+++ b/src/kernel/linux/v4.19/drivers/misc/mediatek/medmcu/rv33/v02/medmcu_helper.c
@@ -87,6 +87,10 @@
 EXPORT_SYMBOL_GPL(medmcu_rx_desc_base_virt);
 EXPORT_SYMBOL_GPL(gMedmcuRxDescSize);
 
+phys_addr_t gMedmcuRxDescDupPhyBase;
+unsigned long long gMedmcuRxDescDupSize;
+void __iomem *medmcu_rx_desc_base_dup_virt;
+
 phys_addr_t gMedmcuHnatInfoPhyBase;
 unsigned long long gMedmcuHnatInfoSize;
 void __iomem *medmcu_hnat_info_base_virt;
@@ -158,8 +162,8 @@
 /* scp ipi message buffer */
 uint32_t msg_scp_ready0, msg_scp_ready1;
 char msg_scp_err_info0[40], msg_scp_err_info1[40];
-
-uint32_t msg_med_stop_ack;
+char msg_med_stop_ack[8];
+char msg_query_suspend_response[8];
 
 /* scp ready status for notify*/
 unsigned int scp_ready[SCP_CORE_TOTAL];
@@ -225,6 +229,16 @@
 #endif
 static struct scp_work_struct scp_A_notify_work;
 
+//represent the suspend response from medmcu, 0: no response, 1: idle, -1: can't suspend
+atomic_t medmcu_suspend_response;
+//represent the medmcu is ready for suspend query or not
+atomic_t medmcu_suspend_query_ready;
+//represent the medmcu needs dpmaif ready event after resume reset
+atomic_t medmcu_resume_need_dpmaif_ready;
+//re-init mdma device structure
+struct MDMA_END_DEVICE mdma_device;
+struct timespec start_query_med_time;
+
 static DEFINE_MUTEX(scp_A_notify_mutex);
 static DEFINE_MUTEX(scp_feature_mutex);
 //static DEFINE_MUTEX(scp_register_sensor_mutex);
@@ -253,6 +267,15 @@
 };
 #define IRQ_NUMBER  (sizeof(scp_ipi_irqs)/sizeof(struct scp_ipi_irq))
 
+//used in resume call back function to check if netsys powerdown before
+int is_fdma_poweroff_before(void)
+{
+	unsigned int reg_val = (unsigned int)reg_read(FDMA_HNAT_INFO_RX_BASE);
+	if (reg_val == 0) {
+		return 1;
+	}
+	return 0;
+}
 
 void fdma_init(struct net_device *dev)
 {
@@ -305,48 +328,52 @@
 #endif
 }
 
-int fe_pdma_rx_dma_init(struct net_device *dev)
+int fe_pdma_rx_dma_init(struct net_device *dev, struct MDMA_END_DEVICE *ei_local)
 {
 	int i;
 	unsigned int skb_size;
-	struct MDMA_END_DEVICE *ei_local = netdev_priv(dev);
+	//struct MDMA_END_DEVICE *ei_local = netdev_priv(dev);
 	dma_addr_t dma_addr;
 
-	skb_size = SKB_DATA_ALIGN(MAX_RX_LENGTH + NET_IP_ALIGN + NET_SKB_PAD) +
-		   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	if(dev != NULL) {
+		skb_size = SKB_DATA_ALIGN(MAX_RX_LENGTH + NET_IP_ALIGN + NET_SKB_PAD) +
+			   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
-	ei_local->phy_rx_ring[0] = scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].start_phys;
-	ei_local->rx_ring[0] = (void __iomem *)scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].start_virt;
+		ei_local->phy_rx_ring[0] = scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].start_phys;
+		ei_local->rx_ring[0] = (void __iomem *)scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].start_virt;
 
-	pr_info("phy_rx_ring[0] = 0x%08x, rx_ring[0] = 0x%p, skb_size = %u, rx ring size = %ld, gMedmcuRxDescSize = %llu\n",
-		 (unsigned int)ei_local->phy_rx_ring[0],
-		 (void *)ei_local->rx_ring[0], skb_size, NUM_RX_DESC * sizeof(struct MDMA_rxdesc), scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].size);
-	for (i = 0; i < MAX_RX_RING_NUM; i++)
-		ei_local->netrx_skb_data[i] =
-			kmalloc_array(NUM_RX_DESC, sizeof(void *), GFP_KERNEL);
-	ei_local->netrx0_skb_data = kmalloc_array(NUM_RX_DESC, sizeof(void *), GFP_KERNEL);
+		pr_info("phy_rx_ring[0] = 0x%08x, rx_ring[0] = 0x%p, skb_size = %u, rx ring size = %ld, gMedmcuRxDescSize = %llu\n",
+			 (unsigned int)ei_local->phy_rx_ring[0],
+			 (void *)ei_local->rx_ring[0], skb_size, NUM_RX_DESC * sizeof(struct MDMA_rxdesc), scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].size);
+		for (i = 0; i < MAX_RX_RING_NUM; i++)
+			ei_local->netrx_skb_data[i] =
+				kmalloc_array(NUM_RX_DESC, sizeof(void *), GFP_KERNEL);
+		ei_local->netrx0_skb_data = kmalloc_array(NUM_RX_DESC, sizeof(void *), GFP_KERNEL);
 
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		ei_local->netrx_skb_data[0][i] =
-			raeth_alloc_skb_data(skb_size, GFP_KERNEL);
-		if (!ei_local->netrx_skb_data[0][i]) {
-			pr_info("rx skbuff buffer allocation failed!");
-			goto no_rx_mem;
+		for (i = 0; i < NUM_RX_DESC; i++) {
+			ei_local->netrx_skb_data[0][i] =
+				raeth_alloc_skb_data(skb_size, GFP_KERNEL);
+			if (!ei_local->netrx_skb_data[0][i]) {
+				pr_info("rx skbuff buffer allocation failed!");
+				goto no_rx_mem;
+			}
+			memset(&ei_local->rx_ring[0][i], 0, sizeof(struct MDMA_rxdesc));
+			ei_local->rx_ring[0][i].rxd_info2.DDONE_bit = 0;
+			ei_local->rx_ring[0][i].rxd_info2.LS0 = 0;
+			ei_local->rx_ring[0][i].rxd_info2.PLEN0 = MAX_RX_LENGTH;
+			dma_addr = dma_map_single(dev->dev.parent,
+						  ei_local->netrx_skb_data[0][i] +
+						  NET_SKB_PAD,
+						  MAX_RX_LENGTH,
+						  DMA_FROM_DEVICE);
+			ei_local->rx_ring[0][i].rxd_info1.PDP0 = dma_addr;
+			if (unlikely(dma_mapping_error(dev->dev.parent, ei_local->rx_ring[0][i].rxd_info1.PDP0))) {
+				pr_info("[%s] rx_desc entry_%d dma_map_single() failed...\n", __func__, i);
+				goto no_rx_mem;
+			}
 		}
-		memset(&ei_local->rx_ring[0][i], 0, sizeof(struct MDMA_rxdesc));
-		ei_local->rx_ring[0][i].rxd_info2.DDONE_bit = 0;
-		ei_local->rx_ring[0][i].rxd_info2.LS0 = 0;
-		ei_local->rx_ring[0][i].rxd_info2.PLEN0 = MAX_RX_LENGTH;
-		dma_addr = dma_map_single(dev->dev.parent,
-					  ei_local->netrx_skb_data[0][i] +
-					  NET_SKB_PAD,
-					  MAX_RX_LENGTH,
-					  DMA_FROM_DEVICE);
-		ei_local->rx_ring[0][i].rxd_info1.PDP0 = dma_addr;
-		if (unlikely(dma_mapping_error(dev->dev.parent, ei_local->rx_ring[0][i].rxd_info1.PDP0))) {
-			pr_info("[%s] rx_desc entry_%d dma_map_single() failed...\n", __func__, i);
-			goto no_rx_mem;
-		}
+	} else {
+		pr_info("[MEDMCU] skip allocate mdma skb data");
 	}
 
 	/* Tell the adapter where the RX rings are located. */
@@ -366,10 +393,10 @@
 	return -ENOMEM;
 }
 
-int fe_pdma_tx_dma_init(struct net_device *dev)
+int fe_pdma_tx_dma_init(struct net_device *dev, struct MDMA_END_DEVICE *ei_local)
 {
 	int i;
-	struct MDMA_END_DEVICE *ei_local = netdev_priv(dev);
+	//struct MDMA_END_DEVICE *ei_local = netdev_priv(dev);
 	ei_local->phy_tx_ring0 = scp_reserve_mblock[SCP_A_TX_DESC_MEM_ID].start_phys;
 	ei_local->tx_ring0 = (void __iomem *)scp_reserve_mblock[SCP_A_TX_DESC_MEM_ID].start_virt;
 	pr_info("phy_tx_ring = 0x%08x, tx_ring = 0x%p\n",
@@ -398,7 +425,7 @@
 	reg_write(MDMA_GLO_CFG, 0x10404825);
 }
 
-int mdma_init(struct net_device *dev)
+int mdma_init(struct net_device *dev, struct MDMA_END_DEVICE *ei_local)
 {
 	int err;
 
@@ -408,13 +435,13 @@
 		return err;
 	}
 
-	err = fe_pdma_rx_dma_init(dev);
+	err = fe_pdma_rx_dma_init(dev, ei_local);
 	if (err) {
 		pr_info("fe_pdma_rx_dma_init err\n");
 		//return err;
 	}
 
-	err = fe_pdma_tx_dma_init(dev);
+	err = fe_pdma_tx_dma_init(dev, ei_local);
 	if (err) {
 		pr_info("fe_pdma_tx_dma_init err\n");
 		//return err;
@@ -572,6 +599,10 @@
 #if (TEST_WITHOUT_CCCI == 0)
 extern void ccci_dpmaif_register_notify(struct notifier_block *nb);
 
+//suspend/resume for index sync
+extern void ccci_dpmaif_reset_pit_nat_indexes(void);
+extern void ccci_dpmaif_resend_ready(void);
+
 static void handle_dpmaif_ready(void)
 {
 	int ret = 0;
@@ -638,7 +669,7 @@
 			(unsigned int)reg_read(TX_MAX_CNT0),
 			(unsigned int)reg_read(TX_CTX_IDX0),
 			(unsigned int)reg_read(MDMA_RST_CFG));
-
+	atomic_set(&medmcu_suspend_query_ready, 1);
 }
 
 static void handle_dpmaif_stop(void)
@@ -666,6 +697,57 @@
 	}
 }
 
+static void handle_query_medmcu_can_suspend(void)
+{
+	int ret = 0;
+	int cnt = 0;
+	uint32_t dummy;
+
+	pr_notice("[MEDMCU]Query medmcu suspend state!\n");
+	while (1) {
+		ret = mtk_ipi_send(&scp_ipidev, IPI_OUT_QUERY_MED_SUSPEND, 1 /*IPI_SEND_POLLING */ ,
+				&dummy, PIN_OUT_SIZE_QUERY_MED_SUSPEND, 0);
+		if (ret != IPI_PIN_BUSY)
+			break;
+		cnt++;
+		if (cnt > 10) {
+			pr_err("[MEDMCU] IPI_OUT_QUERY_MED_SUSPEND send 10 times fail!\n");
+			break;
+		}
+	}
+	if (ret != IPI_ACTION_DONE) {
+		pr_err("[MEDMCU] IPI_OUT_QUERY_MED_SUSPEND send fail!\n");
+	} else {
+		pr_notice("[MEDMCU] IPI_OUT_QUERY_MED_SUSPEND send ok!\n");
+	}
+}
+
+static void notify_medmcu_unmask_irq(void)
+{
+	int ret = 0;
+	int cnt = 0;
+	uint32_t dummy;
+
+	pr_notice("[MEDMCU]notify_medmcu_unmask_irq\n");
+	while (1) {
+		ret = mtk_ipi_send(&scp_ipidev, IPI_OUT_MED_UNMASK_IRQ, 1 /*IPI_SEND_POLLING */ ,
+				&dummy, PIN_OUT_SIZE_MED_UNMASK_IRQ, 0);
+		if (ret != IPI_PIN_BUSY)
+			break;
+		cnt++;
+		if (cnt > 10) {
+			pr_err("[MEDMCU] IPI_OUT_MED_UNMASK_IRQ send 10 times fail!\n");
+			break;
+		}
+	}
+	if (ret != IPI_ACTION_DONE) {
+		pr_err("[MEDMCU] IPI_OUT_MED_UNMASK_IRQ send fail!\n");
+	} else {
+		pr_notice("[MEDMCU] IPI_OUT_MED_UNMASK_IRQ send ok!\n");
+	}
+	atomic_set(&medmcu_suspend_query_ready, 1);
+}
+
 static int ccci_apsync_event(struct notifier_block *this,
 		unsigned long event, void *ptr)
 {
@@ -684,6 +766,8 @@
 				pended_dpmaif_ready = true;
 			} else {
 				handle_dpmaif_ready();
+				//handle_query_medmcu_can_suspend(); //testing
+				//notify_medmcu_unmask_irq(); //testing
 			}
 			break;
 		default:
@@ -790,6 +874,12 @@
 		blocking_notifier_call_chain(&scp_A_notifier_list
 			, SCP_EVENT_READY, NULL);
 		mutex_unlock(&scp_A_notify_mutex);
+		//for resume medmcu, need dpamif ready event.
+		if (atomic_read(&medmcu_resume_need_dpmaif_ready) == 1) {
+			//ask ccci to send dpmaif ready, since dpmaif hw/sw is still alive after resume
+			ccci_dpmaif_resend_ready();
+			atomic_set(&medmcu_resume_need_dpmaif_ready, 0);
+		}
 	}
 
 	/* register scp dvfs*/
@@ -995,6 +1085,60 @@
 	return 0;
 }
 
+static int sync_medmcu_can_suspend(void) {
+	struct timespec cur_med_driver_time, diff_med_time;
+	if (scp_ready[SCP_A_ID] && atomic_read(&medmcu_suspend_query_ready) == 1) {
+		atomic_set(&medmcu_suspend_response, 0);
+		getnstimeofday(&start_query_med_time);
+		handle_query_medmcu_can_suspend();
+		//wait handshake with scp
+		while (1) {
+			getnstimeofday(&cur_med_driver_time);
+			diff_med_time = timespec_sub(cur_med_driver_time, start_query_med_time);
+			if (atomic_read(&medmcu_suspend_response) != 0) {
+				break;
+			}
+			if (diff_med_time.tv_sec > 5) {
+				pr_err("[MEDMCU] suspend query timeout\n");
+				return -1;
+			}
+		}
+		if (atomic_read(&medmcu_suspend_response) == 1) {
+			//scp idle
+			atomic_set(&medmcu_suspend_query_ready, 0);
+			return 0;
+		} else {
+			return -1;
+		}
+	} else {
+		pr_info("[MEDMCU] scp not ready in suspend, %d, %d\n",
+				scp_ready[SCP_A_ID], atomic_read(&medmcu_suspend_query_ready));
+		return -1;
+	}
+}
+
+/*
+ * handle notification from scp
+ * Check if scp idle or not
+ * @param id:   ipi id
+ * @param prdata: ipi handler parameter
+ * @param data: ipi data
+ * @param len:  length of ipi data
+ */
+static int med_query_suspend_response_ipi_handler(unsigned int id, void *prdata, void *data,
+				    unsigned int len)
+{
+	unsigned int response = *(unsigned int *)data;
+	pr_notice("[MEDMCU] query response %u\n", response);
+	if (response == 0) {
+		//scp idle
+		atomic_set(&medmcu_suspend_response, 1);
+	} else {
+		atomic_set(&medmcu_suspend_response, -1);
+	}
+	return 0;
+}
+
 /*
  * Handle notification from scp.
  * Report error from SCP to other kernel driver.
@@ -1316,23 +1460,67 @@
 }
 EXPORT_SYMBOL(scp_wdt_reset);
 
+static void reset_scp_without_restart_md(void) {
+	int is_netsys_poweroff_before = is_fdma_poweroff_before();
+	struct MDMA_END_DEVICE *ei_local = &mdma_device;
+	pr_info("[MEDMCU] reset_scp_without_restart_md\n");
+	//reset ccci pit_nat indexes
+	ccci_dpmaif_reset_pit_nat_indexes();
+
+	//reinit fdma, mdma
+	if (is_netsys_poweroff_before == 1) {
+		pr_info("[MEDMCU] reset_scp_without_restart_md: reset f_mdma\n");
+		//copy dup rx_desc value prevent re-allocate skb data
+		memcpy(medmcu_rx_desc_base_virt, medmcu_rx_desc_base_dup_virt,
+				gMedmcuRxDescSize);
+		fdma_init(NULL);
+		mdma_init(NULL, ei_local);
+	}
+
+	//reset medmcu clks CR
+	writel(0xffffffff, R_SET_CLK_CG);
+	writel(0x0, MED_INFRA_CLK);
+
+	//reset medmcu
+	scp_reset_counts = 9999;
+	scp_reset_by_md_excep = 1;
+	scp_send_reset_wq(RESET_TYPE_RESUME);
+}
+
 /*
  * trigger wdt manually (debug use)
  * Warning! watch dog may be refresh just after you set
  */
+static int medmcu_pm_resume_early(struct device *dev);
 static ssize_t scp_wdt_trigger(struct device *dev
 		, struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned int value = 0;
+	int retval = 0;
 
 	if (!buf || count == 0)
 		return count;
-	pr_debug("[MEDMCU] %s: %8s\n", __func__, buf);
+	pr_notice("[MEDMCU] %s: %8s\n", __func__, buf);
 	if (kstrtouint(buf, 10, &value) == 0) {
 		if (value == 666)
 			scp_wdt_reset(0);
 		else if (value == 667)
 			scp_wdt_reset(1);
+		else if (value == 669)
+			sync_medmcu_can_suspend();
+		else if (value == 670) {
+			reset_scp_without_restart_md();
+		}
+		else if (value == 671) {
+			retval = reset_scp(SCP_ALL_REBOOT);
+			if (retval < 0) {
+				retval = -EINVAL;
+				pr_err("[MEDMCU] %s: reboot fail\n", __func__);
+			}
+		}
+		else if (value == 672) {
+			medmcu_pm_resume_early(NULL);
+		}
 	}
 	return count;
 }
@@ -1704,6 +1892,11 @@
 	medmcu_rx_desc_base_virt = (void __iomem *)scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].start_virt;
 	gMedmcuRxDescSize= scp_reserve_mblock[SCP_A_RX_DESC_MEM_ID].size;
 
+	//Medmcu Resume: copy dup to rxdesc address
+	gMedmcuRxDescDupPhyBase = scp_reserve_mblock[SCP_A_RX_DESC_DUP_MEM_ID].start_phys;
+	medmcu_rx_desc_base_dup_virt = (void __iomem *)scp_reserve_mblock[SCP_A_RX_DESC_DUP_MEM_ID].start_virt;
+	gMedmcuRxDescDupSize= scp_reserve_mblock[SCP_A_RX_DESC_DUP_MEM_ID].size;
+
 	gMedmcuHnatInfoPhyBase = scp_reserve_mblock[SCP_A_HNAT_INFO_MEM_ID].start_phys;
 	medmcu_hnat_info_base_virt = (void __iomem *)scp_reserve_mblock[SCP_A_HNAT_INFO_MEM_ID].start_virt;
 	gMedmcuHnatInfoSize= scp_reserve_mblock[SCP_A_HNAT_INFO_MEM_ID].size;
@@ -2054,13 +2247,22 @@
 
 	/* scp reset by CMD, WDT or awake fail */
 	if ((scp_reset_type == RESET_TYPE_TIMEOUT) ||
-		(scp_reset_type == RESET_TYPE_AWAKE)) {
+		(scp_reset_type == RESET_TYPE_AWAKE) ||
+		(scp_reset_type == RESET_TYPE_RESUME)) {
 		/* stop scp */
 		writel(1, R_CORE0_SW_RSTN_SET);
 		writel(1, R_CORE1_SW_RSTN_SET);
 		dsb(SY); /* may take lot of time */
 		pr_notice("[MEDMCU] rstn core0 %x core1 %x\n",
 		readl(R_CORE0_SW_RSTN_SET), readl(R_CORE1_SW_RSTN_SET));
+		if (scp_reset_type == RESET_TYPE_RESUME) {
+#if SCP_RESERVED_MEM
+			writel((unsigned int)scp_mem_base_phys, DRAM_RESV_ADDR_REG);
+			writel((unsigned int)scp_mem_size, DRAM_RESV_SIZE_REG);
+			pr_notice("[MEDMCU]%s set mem: 0x%llx 0x%llx\n", __func__,
+				(uint64_t)scp_mem_base_phys, (uint64_t)scp_mem_size);
+#endif
+		}
 	} else {
 		/* reset type scp WDT or CMD or MD_EXCEP*/
 		/* make sure scp is in idle state */
@@ -2087,6 +2289,8 @@
 	pr_notice("[MEDMCU] rstn core0 %x\n", readl(R_CORE0_SW_RSTN_CLR));
 	dsb(SY); /* may take lot of time */
 
+	atomic_set(&medmcu_resume_need_dpmaif_ready, 0);
+
 	if (scp_reset_type == RESET_TYPE_MD_EXCEP) {
 		/*notify scp functions stop*/
 		pr_notice("[MEDMCU] %s(): scp_extern_notify SCP_EVENT_STOP_ACK\n", __func__);
@@ -2095,6 +2299,10 @@
 		/*notify scp functions stop*/
 		pr_notice("[MEDMCU] %s(): scp_extern_notify SCP_EVENT_STOP_BY_WDT\n", __func__);
 		scp_extern_notify(SCP_EVENT_STOP_BY_WDT);
+	} else if (scp_reset_type == RESET_TYPE_RESUME) {
+		//wait scp ready and ask for dpmaif_ready_event
+		pr_notice("[MEDMCU] %s(): scp_extern_notify RESET_TYPE_RESUME222\n", __func__);
+		atomic_set(&medmcu_resume_need_dpmaif_ready, 1);
 	}
 
 #if SCP_BOOT_TIME_OUT_MONITOR
@@ -2145,7 +2353,7 @@
 
 	clear_medhw_logged();
 
-	if (scp_reset_type == RESET_TYPE_MD_EXCEP) {
+	if (scp_reset_type == RESET_TYPE_MD_EXCEP || scp_reset_type == RESET_TYPE_RESUME) {
 		// no need to dump log
 		goto scp_reset;
 	}
@@ -2288,6 +2496,8 @@
 
 	struct net_device *netdev;
 
+	struct MDMA_END_DEVICE *ei_local = &mdma_device;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	scpreg.sram = devm_ioremap_resource(dev, res);
 	if (IS_ERR((void const *) scpreg.sram)) {
@@ -2354,6 +2564,14 @@
 	}
 	pr_debug("[MEDMCU] cfg_sec base = 0x%p\n", scpreg.cfg_sec);
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 28);
+	scpreg.infra_clk = devm_ioremap_resource(dev, res);
+	if (IS_ERR((void const *) scpreg.infra_clk)) {
+		pr_err("[MEDMCU] scpreg.infra_clk error\n");
+		return -1;
+	}
+	pr_debug("[MEDMCU] infra_clk base = 0x%p\n", scpreg.infra_clk);
+
 
 	of_property_read_u32(pdev->dev.of_node, "scp_sramSize"
 						, &scpreg.scp_tcmsize);
@@ -2423,15 +2641,45 @@
 	}
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
-	fdma_init(netdev);
-	mdma_init(netdev);
+	fdma_init(NULL);
+	mdma_init(netdev, ei_local);
+
+	/*pr_info("[MEDMCU] reinit dmad test\n");
+	fdma_init(NULL);
+	mdma_init(NULL, ei_local);*/
 
 	free_netdev(netdev);
+	pr_info("[MEDMCU] probe done\n");
 	return ret;
 }
 
+/*static int medmcu_pm_suspend_late(struct device *dev)
+{
+	return sync_medmcu_can_suspend();
+}*/
+
+static int medmcu_pm_resume_early(struct device *dev)
+{
+	int is_netsys_poweroff_before = is_fdma_poweroff_before();
+	pr_info("[MEDMCU] medmcu_pm_resume_early: %d, %d\n",
+			is_netsys_poweroff_before, atomic_read(&medmcu_suspend_response));
+	if (is_netsys_poweroff_before == 1 && atomic_read(&medmcu_suspend_response) == 1) {
+		reset_scp_without_restart_md();
+	} else if (is_netsys_poweroff_before == 0 && atomic_read(&medmcu_suspend_response) == 1) {
+		//unmask irqs
+		notify_medmcu_unmask_irq();
+	} else {
+		//unknown
+	}
+	atomic_set(&medmcu_suspend_response, 0);
+	return 0;
+}
+
 int medmcu_pm_suspend(struct device *device)
 {
+	if (sync_medmcu_can_suspend() == -1) {
+		return -1;
+	}
 	writel(V_DISABLE_WDT, R_CORE0_WDT_CFG);
 	//writel(V_DISABLE_WDT, R_CORE1_WDT_CFG);
 	pr_notice("medmcu suspend done\n");
@@ -2441,16 +2689,19 @@
 
 int medmcu_pm_resume(struct device *device)
 {
+	pr_notice("medmcu resume start\n");
 	writel(V_START_WDT, R_CORE0_WDT_CFG);
 	writel(V_KICK_WDT, R_CORE0_KICKREG);
 	//writel(V_START_WDT, R_CORE1_WDT_CFG);
 	//writel(V_KICK_WDT, R_CORE1_KICKREG);
-	pr_notice("medmcu resume done\n");
-
+	pr_notice("medmcu resume kick start\n");
+	medmcu_pm_resume_early(NULL);
 	return 0;
 }
 
 static const struct dev_pm_ops medmcu_pm_ops = {
+	/*.suspend_late = medmcu_pm_suspend_late,
+	.resume_early = medmcu_pm_resume_early,*/
 	.suspend = medmcu_pm_suspend,
 	.resume = medmcu_pm_resume,
 };
@@ -2606,6 +2857,9 @@
 	mtk_ipi_register(&scp_ipidev, IPI_IN_MED_STOP_ACK,
 			(void *)med_stop_ack_ipi_handler, NULL, &msg_med_stop_ack);
 
+	mtk_ipi_register(&scp_ipidev, IPI_IN_MED_SUSPEND_RESPONSE,
+			(void *)med_query_suspend_response_ipi_handler, NULL, &msg_query_suspend_response);
+
 #if (TEST_WITHOUT_CCCI == 0)
 	ccci_dpmaif_register_notify(&ccci_apsync_notifier);
 #endif
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index cd34f12..6dd83e1 100644
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3156,8 +3156,7 @@
 		MTK_CHK_DDONE_EN | MTK_RX_DMA_EN | MTK_RX_2B_OFFSET,
 		MTK_QDMA_GLO_CFG);
 #endif
-	//0x9560F537
-	mtk_w32(eth, 0x95404535, MTK_QDMA_GLO_CFG);
+	mtk_w32(eth, 0x95804535, MTK_QDMA_GLO_CFG);
 	mtk_w32(eth,
 		MTK_RX_DMA_EN | rx_2b_offet |
 		MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
@@ -3390,30 +3389,144 @@
 	return ret;
 }
 
+static int mtk_hw_init_resume(struct mtk_eth *eth)
+{
+	int i;
+	u32 reg_val = 0;
+
+
+	//ethsys_reset(eth, RSTCTRL_FE);
+	ethsys_reset(eth, RSTCTRL_PPE);
+
+	regmap_write(eth->ethsys, 0x14, 0x00110314);
+
+	/* Set linkdown as the default for each GMAC. Its own MCR would be set
+	 * up with the more appropriate value when mtk_phy_link_adjust call is
+	 * being invoked.
+	 */
+	for (i = 0; i < MTK_MAC_COUNT; i++)
+		mtk_w32(eth, 0, MTK_MAC_MCR(i));
+
+	/* Indicates CDM to parse the MTK special tag from CPU
+	 * which also is working out for untag packets.
+	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+	*/
+	/* Disable RX VLan Offloading */
+	mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+
+	mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA_DELAY_INT);
+	if (eth->hwrss) {
+		mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA1_DELAY_INT);
+		mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA2_DELAY_INT);
+		mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA3_DELAY_INT);
+	}
+	mtk_w32(eth, 0x8f0f8f0f, MTK_QDMA_DELAY_INT);
+
+	mtk_tx_irq_disable(eth, ~0);
+
+	if (eth->hwrss) {
+		mtk_rx_irq_disable0(eth, MTK_RX_DONE_DLY);
+		mtk_rx_irq_disable1(eth, MTK_RX_DONE_DLY1);
+		mtk_rx_irq_disable2(eth, MTK_RX_DONE_DLY2);
+		mtk_rx_irq_disable3(eth, MTK_RX_DONE_DLY3);
+	} else {
+		mtk_rx_irq_disable(eth, ~0);
+	}
+	if(eth->hwedmarx) {
+		mtk_rx_irq_disable_edma_all(eth);
+	}
+
+	/* FE int grouping */
+	/* Enable multipe rx ring delay interrupt */
+	if (eth->hwrss) {
+		reg_val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0);
+		reg_val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, reg_val, MTK_PDMA_LRO_CTRL_DW0);
+		mtk_w32(eth, 0x2020000, MTK_PDMA_INT_GRP1);
+		mtk_w32(eth, 0x4040000, MTK_PDMA_INT_GRP2);
+		mtk_w32(eth, 0x8080000, MTK_PDMA_INT_GRP3);
+		mtk_w32(eth, 0x01000000, MTK_FE_INT_GRP);
+	} else {
+		//RX use MTK_PDMA_INT_GRP0
+		mtk_w32(eth, 0x0, MTK_PDMA_INT_GRP1);
+		mtk_w32(eth, 0x0, MTK_PDMA_INT_GRP2);
+		mtk_w32(eth, 0x0, MTK_PDMA_INT_GRP3);
+
+		//mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2);
+		mtk_w32(eth, 0x01000000, MTK_FE_INT_GRP); //set FE_INT no RX ADMA INT
+	}
+
+	mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1);
+	//mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); ///maybe no need to set
+
+	if(eth->hwedmarx) {
+		mtk_w32(eth, 0x8f0f8f0f, MTK_EDMA0_DELAY_INT);
+		mtk_w32(eth, 0x8f0f8f0f, MTK_EDMA1_DELAY_INT);
+
+	}
+
+	//#Global FC threshold
+	mtk_w32(eth, 0x01fa01f4, 0x104);
+
+	//#Per CDM Input threshold update
+	mtk_w32(eth, 0x001a000e, 0x140);
+	mtk_w32(eth, 0x01ff001a, 0x144);
+	mtk_w32(eth, 0x000e01ff, 0x148);
+	mtk_w32(eth, 0x000e000e, 0x14c);
+	mtk_w32(eth, 0x000e000e, 0x150);
+	mtk_w32(eth, 0x000e000e, 0x154);
+	mtk_w32(eth, 0x000e000e, 0x158);
+	mtk_w32(eth, 0x000e000e, 0x15c);
+
+	//#Per port Output threshold update 
+	mtk_w32(eth, 0x000f000a, 0x160);
+	mtk_w32(eth, 0x001a000f, 0x164);
+	mtk_w32(eth, 0x000f001a, 0x168);
+	mtk_w32(eth, 0x01ff000f, 0x16c);
+	mtk_w32(eth, 0x000f000f, 0x170);
+	mtk_w32(eth, 0x0006000f, 0x174);
+	mtk_w32(eth, 0x00060006, 0x178);
+	mtk_w32(eth, 0x00060006, 0x17c);
+
+	mtk_w32(eth, 0x00000004, 0x1530);
+	mtk_w32(eth, 0x00000004, 0x164c);
+	mtk_w32(eth, 0x00000004, 0x1650);
+	mtk_w32(eth, 0x00000004, 0x1654);
+	mtk_w32(eth, 0x00000004, 0x1658);
+	mtk_w32(eth, 0x00000004, 0x165c);
+
+	_mtk_mdio_write_C45(eth, 8, 0x10, 0x9d81, 7);
+	_mtk_mdio_write_C45(eth, 8, 0, 0x3200, 7);
+
+	return 0;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth)
 {
 	int i, val = 0, ret;
 	u32 reg_val = 0;
 	u32 tmp;
 
-	if (test_and_set_bit(MTK_HW_INIT, &eth->state)) {
-		//////pr_notice("#######return\n");
-		return 0;
-	}
+	//if (test_and_set_bit(MTK_HW_INIT, &eth->state)) {
+		//////pr_notice("#######HW init return\n");
+		//return 0;
+	//}
 
 	if (!(MTK_HAS_CAPS(eth->soc->caps, MTK_FPGA_CLK))) {
+		pr_notice("Harry TEST !!!!!\n");
 		pm_runtime_enable(eth->dev);
 		pm_runtime_get_sync(eth->dev);
-		if (eth->soc->sgmii_pm) {
-			pm_runtime_enable(eth->sgmii_phy_dev0);
-			pm_runtime_get_sync(eth->sgmii_phy_dev0);
-			pm_runtime_enable(eth->sgmii_phy_dev1);
-			pm_runtime_get_sync(eth->sgmii_phy_dev1);
-			pm_runtime_enable(eth->sgmii_dev0);
-			pm_runtime_get_sync(eth->sgmii_dev0);
-			pm_runtime_enable(eth->sgmii_dev1);
-			pm_runtime_get_sync(eth->sgmii_dev1);
-		}
+		//if (eth->soc->sgmii_pm) {
+		//	pm_runtime_enable(eth->sgmii_phy_dev0);
+		//	pm_runtime_get_sync(eth->sgmii_phy_dev0);
+		//	pm_runtime_enable(eth->sgmii_phy_dev1);
+		//	pm_runtime_get_sync(eth->sgmii_phy_dev1);
+		//	pm_runtime_enable(eth->sgmii_dev0);
+		//	pm_runtime_get_sync(eth->sgmii_dev0);
+		//	pm_runtime_enable(eth->sgmii_dev1);
+		//	pm_runtime_get_sync(eth->sgmii_dev1);
+		//}
 		ret = mtk_clk_enable(eth);
 		if (ret)
 			goto err_disable_pm;
@@ -3587,13 +3700,13 @@
 	pm_runtime_disable(eth->dev);
 	if (eth->soc->sgmii_pm) {
 		pm_runtime_put_sync(eth->sgmii_dev0);
-		pm_runtime_disable(eth->sgmii_dev0);
+		//pm_runtime_disable(eth->sgmii_dev0);
 		pm_runtime_put_sync(eth->sgmii_dev1);
-		pm_runtime_disable(eth->sgmii_dev1);
+		//pm_runtime_disable(eth->sgmii_dev1);
 		pm_runtime_put_sync(eth->sgmii_phy_dev0);
-		pm_runtime_disable(eth->sgmii_phy_dev0);
+		//pm_runtime_disable(eth->sgmii_phy_dev0);
 		pm_runtime_put_sync(eth->sgmii_phy_dev1);
-		pm_runtime_disable(eth->sgmii_phy_dev1);
+		//pm_runtime_disable(eth->sgmii_phy_dev1);
 	}
 	return ret;
 }
@@ -3606,16 +3719,16 @@
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_FPGA_CLK)) {
 		mtk_clk_disable(eth);
 		pm_runtime_put_sync(eth->dev);
-		pm_runtime_disable(eth->dev);
+		//pm_runtime_disable(eth->dev);
 		if (eth->soc->sgmii_pm) {
 			pm_runtime_put_sync(eth->sgmii_dev0);
-			pm_runtime_disable(eth->sgmii_dev0);
+			//pm_runtime_disable(eth->sgmii_dev0);
 			pm_runtime_put_sync(eth->sgmii_dev1);
-			pm_runtime_disable(eth->sgmii_dev1);
+			//pm_runtime_disable(eth->sgmii_dev1);
 			pm_runtime_put_sync(eth->sgmii_phy_dev0);
-			pm_runtime_disable(eth->sgmii_phy_dev0);
+			//pm_runtime_disable(eth->sgmii_phy_dev0);
 			pm_runtime_put_sync(eth->sgmii_phy_dev1);
-			pm_runtime_disable(eth->sgmii_phy_dev1);
+			//pm_runtime_disable(eth->sgmii_phy_dev1);
 		}
 	}
 
@@ -4420,6 +4533,7 @@
 	int i, ret;
 	static int enable_hw_idle = 0;
 
+	pr_notice("ethernet suspend time start = %lx\n", jiffies);
 	if (pdev == NULL) {
 		////pr_notice("%s pdev == NULL\n", __func__);
 		return -1;
@@ -4442,6 +4556,7 @@
 			phy_stop(eth->netdev[i]->phydev);
 		}
 	}
+	pr_notice("ethernet suspend time  kerenel stop = %lx\n", jiffies);
 
 #if 0
 	regmap_update_bits(eth->ethsys, MTK_PPE_TB_CFG,
@@ -4451,14 +4566,17 @@
 			   SCAN_MODE_MASK,
 			   0x0 <<  16);
 #endif
-	mtk_w32(eth, 0x7fb5, MTK_PPE_TB_CFG);
-	mtk_w32(eth, 0x7fb5, MTK_PPE1_TB_CFG);
+	//mtk_w32(eth, 0x7fb5, MTK_PPE_TB_CFG);
+	//mtk_w32(eth, 0x7fb5, MTK_PPE1_TB_CFG);
 
 	if (eth->soc->sgmii_pm)
 		regulator_set_voltage(eth->dvfsrc_vcore_power,
 				      SGMII_VCORE_NON_OPS, INT_MAX);
+	pr_notice("ethernet suspend time  vcore 0.55V = %lx\n", jiffies);
 
 	mtk_gdma_config(eth, MTK_GDMA_DROP_ALL);
+	pr_notice("ethernet suspend time  set GDM ingress pkt drop = %lx\n", jiffies);
+
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
 	if (eth->hwrss) {
 		mtk_rx_irq_disable0(eth, MTK_RX_DONE_DLY);
@@ -4481,6 +4599,7 @@
 	//napi_disable(&eth->tx_napi);
 	//napi_disable(&eth->rx_napi);
 	/*disable ADMA*/
+	pr_notice("ethernet suspend time disable irq = %lx\n", jiffies);
 	mtk_w32(eth, 0x00200080, MTK_PDMA_LRO_CTRL_DW0);
 	mtk_w32(eth, 0x80001c00, MTK_PDMA_GLO_CFG);
 	mtk_w32(eth, 0x810001b0, 0);
@@ -4509,7 +4628,15 @@
 		msleep(3);
 	} else
 		pr_notice("ADMA related bus not idle!!!!\n");
+	pr_notice("ethernet suspend time reset ADMA = %lx\n", jiffies);
+
+	mtk_dma_free(eth);	
+	pr_notice("ethernet suspend time dma freee = %lx\n", jiffies);
+
 	mtk_clk_disable(eth);
+	pr_notice("ethernet suspend time clk disable = %lx\n", jiffies);
+	pr_notice("ethernet suspend time end = %lx\n", jiffies);
+	pr_notice("power down\n");
 	pr_notice("netsys suspend_noirq done\n");
 
 	return 0;
@@ -4523,12 +4650,16 @@
 	int i, err;
 	const char *str;
 
-//	if (pdev == NULL) {
+	pr_notice("ethernet resume time start = %lx\n", jiffies);
+	if (pdev == NULL) {
 		////pr_notice("%s pdev == NULL\n", __func__);
-//		return -1;
-//	}
+		return -1;
+	}
 
+	pr_notice("ethernet resume time start = %lx\n", jiffies);
 	eth = platform_get_drvdata(pdev);
+	pr_notice("ethernet resume platform_get_drvdata = %lx\n", jiffies);
+
 #if 0
 	regmap_update_bits(eth->ethsys, MTK_PPE_TB_CFG,
 			   SCAN_MODE_MASK,
@@ -4538,8 +4669,13 @@
 			   SCAN_MODE);
 #endif
 	mtk_clk_enable(eth);
-	mtk_w32(eth, 0x27fb5, MTK_PPE_TB_CFG);
-	mtk_w32(eth, 0x27fb5, MTK_PPE1_TB_CFG);
+	pr_notice("ethernet resume mtk_clk_enable = %lx\n", jiffies);
+
+	mtk_hw_init_resume(eth);
+	pr_notice("ethernet resume mtk_hw_init_resume = %lx\n", jiffies);
+
+	//mtk_w32(eth, 0x27fb5, MTK_PPE_TB_CFG);
+	//mtk_w32(eth, 0x27fb5, MTK_PPE1_TB_CFG);
 
 	if (eth->soc->sgmii_pm) {
 		np = of_parse_phandle(pdev->dev.of_node,
@@ -4549,6 +4685,7 @@
 		if (err)
 			return err;
 
+		pr_notice("ethernet resume get device node = %lx\n", jiffies);
 		if (refcount_read(&eth->dma_refcnt)) {
 			if (!strcmp(str, "auto"))
 				regulator_set_voltage(eth->dvfsrc_vcore_power,
@@ -4557,6 +4694,7 @@
 				regulator_set_voltage(eth->dvfsrc_vcore_power,
 						      SGMII_VCORE_OPS, INT_MAX);
 		}
+		pr_notice("ethernet resume set vcore 0.65v = %lx\n", jiffies);
 	}
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
@@ -4570,6 +4708,14 @@
 			else
 				mtk_sgmii_setup_mode_force(eth->sgmii, i, eth);
 		}
+		pr_notice("ethernet resume set sgmii force mode = %lx\n", jiffies);
+	}
+
+	err = mtk_start_dma(eth);
+	pr_notice("ethernet resume start dma = %lx\n", jiffies);
+	if (err) {
+		pr_notice("resume : mtk_start_dma fail\n");
+		return err;
 	}
 
 	//napi_enable(&eth->tx_napi);
@@ -4584,6 +4730,7 @@
 	} else {
 		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT);
 	}
+	pr_notice("ethernet resume irq enable = %lx\n", jiffies);
 
 	if (eth->hwedmarx) {
 		mtk_rx_irq_enable_edma_all(eth);
@@ -4594,6 +4741,8 @@
 		enable_irq(eth->irq[8]);
 
 	mtk_gdma_config(eth, MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN);
+	pr_notice("ethernet resume set GDM normal = %lx\n", jiffies);
+
 	mtk_w32(eth, 0x810000b0, 0);
 	//TBD check harry
 	if (eth->hwrss)
@@ -4601,6 +4750,7 @@
 	else
 		mtk_w32(eth, 0x00200081, MTK_PDMA_LRO_CTRL_DW0);
 	mtk_w32(eth, 0x80001c04, MTK_PDMA_GLO_CFG);
+	pr_notice("ethernet resume ADMA setting  = %lx\n", jiffies);
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_DISABLE_PHY)) {
 		for (i = 0; i < MTK_MAC_COUNT; i++) {
@@ -4617,7 +4767,9 @@
 
 		netif_start_queue(eth->netdev[i]);
 	}
-	//pr_notice("netsys resume_noirq done\n");
+	pr_notice("ethernet resume netif_start_queue  = %lx\n", jiffies);
+	pr_notice("ethernet resume time end = %lx\n", jiffies);
+	pr_notice("netsys resume_noirq done\n");
 
 	return 0;
 }
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 4e89135..5af8aca 100644
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -493,6 +493,7 @@
 /* ethernet reset control register */
 #define ETHSYS_RSTCTRL		0x34
 #define RSTCTRL_FE		BIT(6)
+#define RSTCTRL_GMAC		BIT(23)
 #define RSTCTRL_PPE		BIT(31)
 
 /*PPE GLO_CFG*/
diff --git a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 9e86a19..34d0723 100644
--- a/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/src/kernel/linux/v4.19/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -313,7 +313,7 @@
 			msleep(DIV_ROUND_UP(data->delays[2], 1000));
 	}
 #endif
-    msleep(100);
+    msleep(100);//<chencheng 20220531:modify ethernet reset delay 100ms before access registers  >
 	if (data->phy_reset) {
 		netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n");
 		data->phy_reset(priv->plat->bsp_priv);
diff --git a/src/kernel/linux/v4.19/drivers/rtc/interface.c b/src/kernel/linux/v4.19/drivers/rtc/interface.c
index 089ff8c..be88a0d 100644
--- a/src/kernel/linux/v4.19/drivers/rtc/interface.c
+++ b/src/kernel/linux/v4.19/drivers/rtc/interface.c
@@ -822,7 +822,7 @@
 	struct rtc_time tm;
 	ktime_t now;
 
-	if(timer->enabled == 0)
+	if (timer->enabled == 0)
 		timer->enabled = 1;
 	__rtc_read_time(rtc, &tm);
 	now = rtc_tm_to_ktime(tm);
diff --git a/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c b/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
index 1b373a8..d5286da 100644
--- a/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
+++ b/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
@@ -123,7 +123,8 @@
 
 #define SPARE_REG_WIDTH		1
 
-#define RTC_POFF_ALM_SET	_IOW('p', 0x15, struct rtc_time) /* Set alarm time  */
+/* Set alarm time  */
+#define RTC_POFF_ALM_SET	_IOW('p', 0x15, struct rtc_time)
 
 enum mtk_rtc_spare_enum {
 	SPARE_AL_HOU,
@@ -297,7 +298,7 @@
 	}
 	// else, not access RTC register
 
-    ret = regmap_bulk_write(rtc->regmap, reg, val, val_count);
+	ret = regmap_bulk_write(rtc->regmap, reg, val, val_count);
 
 	if (reg == rtc->addr_base + rtc->dev_comp->wrtgr_addr) {
 		// need 1 ms delay to make sure write completely
diff --git a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
index 20ebc23..d9736f0 100755
--- a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
+++ b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk-scpsys.c
@@ -186,6 +186,14 @@
 	CLK_HIFSEL,
 	CLK_JPGDEC,
 	CLK_AUDIO,
+	CLK_NETSYS1,
+	CLK_NETSYS2,
+	CLK_NETSYS3,
+	CLK_NETSYS4,
+	CLK_NETSYS5,
+	CLK_NETSYS6,
+	CLK_NETSYS7,
+	CLK_NETSYS8,
 	CLK_ETH1,
 	CLK_ETH2,
 	CLK_ETH3,
@@ -206,6 +214,14 @@
 	"hif_sel",
 	"jpgdec",
 	"audio",
+	"medsys_sel",
+	"netsys_sel",
+	"netsys_500m_sel",
+	"netsys_med_mcu_sel",
+	"netsys_wed_mcu_sel",
+	"netsys_2x_sel",
+	"sgmii_sel",
+	"sgmii_sbus_sel",
 	"snps_eth_312p5m_sel",
 	"snps_eth_250m_sel",
 	"snps_ptp_sel",
@@ -244,6 +260,7 @@
 	bool sram_iso_ctrl;
 	u32 sram_pdn_bits;
 	u32 sram_pdn_ack_bits;
+	u32 sram_pdn_bits1;
 	u32 sram_pdn_bits2;
 	u32 sram_pdn_ack_bits2;
 	u32 bus_prot_mask;
@@ -459,29 +476,26 @@
 	u32 val;
 	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
 	int tmp;
+	u32 val1;
 	u32 val2;
 	u32 pdn_ack2 = scpd->data->sram_pdn_ack_bits2;
 	int tmp2;
-/*mt6880 pdn_ack1*/
-	val = readl(net_sram_addr) & ~scpd->data->sram_pdn_bits;
+	int ret;
+
+pr_notice("netsys SRAM control step 1");
+	val = readl(net_sram_addr) | scpd->data->sram_pdn_bits;
 	writel(val, net_sram_addr);
 
-	/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
-	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
-		/*
-		 * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
-		 * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
-		 * is applied here.
-		 */
-		usleep_range(12000, 12100);
-	} else {
-		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
-		int ret = readl_poll_timeout(net_sram_addr, tmp,
-				(tmp & pdn_ack) == 0,
-				MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
-		if (ret < 0)
-			return ret;
-	}
+	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
+	ret = readl_poll_timeout(net_sram_addr, tmp,
+			(tmp & pdn_ack) == pdn_ack,
+			MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+	if (ret < 0)
+		return ret;
+
+pr_notice("netsys SRAM control step 2");
+	val1 = readl(net_sram_addr) | scpd->data->sram_pdn_bits1;
+	writel(val1, net_sram_addr);
 
 /*mt6880 pdn_ack2*/
 
@@ -505,6 +519,7 @@
 			return ret;
 	}
 
+pr_notice("netsys SRAM control step 3");
 	return 0;
 }
 
@@ -513,26 +528,52 @@
 	u32 val;
 	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
 	int tmp;
+	u32 val1;
 	u32 val2;
 	u32 pdn_ack2 = scpd->data->sram_pdn_ack_bits2;
 	int tmp2;
+	int ret;
 
-	val = readl(net_sram_addr) | scpd->data->sram_pdn_bits;
-	writel(val, net_sram_addr);
-
-	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
-	return readl_poll_timeout(net_sram_addr, tmp,
-			(tmp & pdn_ack) == pdn_ack,
-			MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
-		
+pr_notice("netsys SRAM control step 1");
 /*mt6880 pdn_ack2*/	
 	val2 = readl(net_sram_addr) | scpd->data->sram_pdn_bits2;
 	writel(val2, net_sram_addr);
 
 	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
-	return readl_poll_timeout(net_sram_addr, tmp2,
+	ret = readl_poll_timeout(net_sram_addr, tmp2,
 			(tmp2 & pdn_ack2) == pdn_ack2,
 			MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+	if (ret < 0)
+		return ret;
+
+pr_notice("netsys SRAM control step 2");
+	val1 = readl(net_sram_addr) & ~scpd->data->sram_pdn_bits1;
+	writel(val1, net_sram_addr);  
+
+/*mt6880 pdn_ack1*/
+	val = readl(net_sram_addr) & ~scpd->data->sram_pdn_bits;
+	writel(val, net_sram_addr);
+
+	/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
+		/*
+		 * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
+		 * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
+		 * is applied here.
+		 */
+		usleep_range(12000, 12100);
+	} else {
+		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
+		int ret = readl_poll_timeout(net_sram_addr, tmp,
+				(tmp & pdn_ack) == 0,
+				MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+		if (ret < 0)
+			return ret;
+	}
+
+pr_notice("netsys SRAM control step 3");
+
+	return 0;
 }
 
 static int scpsys_bus_protect_enable(struct scp_domain *scpd)
@@ -1320,7 +1361,13 @@
 		 */
 		if(strcmp(genpd->name,"conn")){
 			if(strcmp(genpd->name,"ssusb_phy")==0)
-				dev_err(&pdev->dev, "Skip ssusb_phy pwr_on \n");
+				dev_err(&pdev->dev, "Skip ssusb_phy & netsys pwr_on \n");
+			else if (strcmp(genpd->name,"netsys")==0){
+				ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
+				if (ret)
+					pr_notice("netsys clock on fail");
+				dev_err(&pdev->dev, "Skip netsys pwr_on \n");
+			}
 			else
 				genpd->power_on(genpd);
 		}
@@ -1987,6 +2034,29 @@
 				MT6890_TOP_AXI_PROT_EN_INFRA_VDNR_1_ETH,MT6890_TOP_AXI_PROT_EN_INFRA_VDNR_1_ETH,0),
 		},
 	},
+	[MT6890_POWER_DOMAIN_NETSYS] = {
+		.name = "netsys",
+		.sta_mask = BIT(19),
+		.ctl_offs = 0x34C,
+		.caps = MTK_SCPD_NETSYS_OPS,
+		.sram_pdn_bits = GENMASK(4, 4),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+		.sram_pdn_bits1 = GENMASK(1, 1),
+		.sram_pdn_bits2 = GENMASK(17, 17),
+		.sram_pdn_ack_bits2 = GENMASK(25, 25),
+		.clk_id = {CLK_NETSYS1, CLK_NETSYS2, CLK_NETSYS3, CLK_NETSYS4,
+		    CLK_NETSYS5, CLK_NETSYS6, CLK_NETSYS7, CLK_NETSYS8},
+		/*.bp_table = {
+			BUS_PROT(IFR_TYPE, 0x0714, 0x0718, 0x0710, 0x0724,
+				MT6890_TOP_AXI_PROT_EN_2_NETSYS,MT6890_TOP_AXI_PROT_EN_2_NETSYS,0),
+			BUS_PROT(IFR_TYPE, 0x02A0, 0x02A4, 0x0220, 0x0228,
+				MT6890_TOP_AXI_PROT_EN_NETSYS,MT6890_TOP_AXI_PROT_EN_NETSYS,0),
+			BUS_PROT(IFR_TYPE, 0x02A0, 0x02A4, 0x0220, 0x0228,
+				MT6890_TOP_AXI_PROT_EN_NETSYS_2ND,MT6890_TOP_AXI_PROT_EN_NETSYS_2ND,0),
+			BUS_PROT(IFR_TYPE, 0x0714, 0x0718, 0x0710, 0x0724,
+				MT6890_TOP_AXI_PROT_EN_2_NETSYS_2ND,MT6890_TOP_AXI_PROT_EN_2_NETSYS_2ND,0),
+		},*/
+	},
 	[MT6890_POWER_DOMAIN_AUDIO] = {
 		.name = "audio",
 		.sta_mask = BIT(21),
diff --git a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk_tinysys_ipi.c b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk_tinysys_ipi.c
index d4cd9c7..e7262ab 100644
--- a/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk_tinysys_ipi.c
+++ b/src/kernel/linux/v4.19/drivers/soc/mediatek/mtk_tinysys_ipi.c
@@ -394,6 +394,9 @@
 		pin->mbox_pin_cb(ipi_id, pin->prdata, pin->pin_buf,
 			pin->msg_size);
 
+	if (ipidev->post_cb)
+		ipidev->post_cb(ipidev->prdata);
+
 	return IPI_ACTION_DONE;
 }
 EXPORT_SYMBOL(mtk_ipi_recv);
diff --git a/src/kernel/linux/v4.19/drivers/spi/spi-slave-mt27xx.c b/src/kernel/linux/v4.19/drivers/spi/spi-slave-mt27xx.c
index c98b720..860d257 100644
--- a/src/kernel/linux/v4.19/drivers/spi/spi-slave-mt27xx.c
+++ b/src/kernel/linux/v4.19/drivers/spi/spi-slave-mt27xx.c
@@ -300,9 +300,9 @@
 
 static int mtk_spi_slave_setup(struct spi_device *spi)
 {
-
+	struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master);
 	u32 reg_val;
-	struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master);//zhengzhou 2021.03.03 modify 
+
 	reg_val = DMA_DONE_EN | DATA_DONE_EN |
 		  RSTA_DONE_EN | CMD_INVALID_EN;
 	writel(reg_val, mdata->base + SPIS_IRQ_EN_REG);
diff --git a/src/kernel/linux/v4.19/drivers/thermal/mediatek/board_temp.c b/src/kernel/linux/v4.19/drivers/thermal/mediatek/board_temp.c
index 53bce7d..164afaf 100755
--- a/src/kernel/linux/v4.19/drivers/thermal/mediatek/board_temp.c
+++ b/src/kernel/linux/v4.19/drivers/thermal/mediatek/board_temp.c
@@ -205,6 +205,12 @@
 	int temp, temp_hi, temp_lo, r_hi, r_lo;
 	int i;
 
+	/* Exclude the invalid val when NTC AUX_in is disconnect */
+	if (val > 10000000 || val < 1000) {
+		temp = 20000;
+		return temp;
+	}
+
 	for (i = 0; i < ntc_info->lookup_table_num; i++) {
 		if (val >= ntc_info->lookup_table[2 * i + 1])
 			break;
diff --git a/src/kernel/linux/v4.19/drivers/thermal/mediatek/mtk_thermal_ipi.c b/src/kernel/linux/v4.19/drivers/thermal/mediatek/mtk_thermal_ipi.c
index ea46a10..f7c076f 100644
--- a/src/kernel/linux/v4.19/drivers/thermal/mediatek/mtk_thermal_ipi.c
+++ b/src/kernel/linux/v4.19/drivers/thermal/mediatek/mtk_thermal_ipi.c
@@ -51,7 +51,7 @@
 	}
 
 	while (!kthread_should_stop()) {
-		mtk_ipi_recv_reply(&sspm_ipidev, IPIR_C_THERMAL, (void *)&g_ipi_reply, 1);
+		mtk_ipi_recv(&sspm_ipidev, IPIR_C_THERMAL);
 	}
 
 	return 0;
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
index 0b06a61..419648a 100644
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3.h
@@ -424,8 +424,8 @@
 #endif
 	struct delayed_work forward_to_driver_work;
 	struct mtu3_md_sync_data *md_sync_data;
-	int detect_gpio;
-	int detect_irq;
+	int detect_gpio;//<maybe lynq modify? 20220916>
+	int detect_irq;//<maybe lynq modify? 20220916>
 };
 
 static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g)
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
index c45daca..d581ff7 100644
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_core.c
@@ -330,7 +330,7 @@
 {
 
 	void __iomem *mbase = mtu->mac_base;
-	dev_info(mtu->dev, "%s\n", __func__);
+	dev_info(mtu->dev, "%s\n", __func__);//<maybe lynq modify? 20220916>
 
 	/* be sure interrupts are disabled before registration of ISR */
 	mtu3_intr_disable(mtu);
@@ -363,13 +363,13 @@
 	mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
 
 	ssusb_set_force_vbus(mtu->ssusb, true);
-	mtu3_writel(mbase, U3D_POWER_MANAGEMENT, (mtu3_readl(mbase, U3D_POWER_MANAGEMENT)| LPM_MODE(1)));
-	dev_info(mtu->dev, "%s, U3D_POWER_MANAGEMENT:0x%x\n", __func__, mtu3_readl(mbase, U3D_POWER_MANAGEMENT));
+	mtu3_writel(mbase, U3D_POWER_MANAGEMENT, (mtu3_readl(mbase, U3D_POWER_MANAGEMENT)| LPM_MODE(1)));//<maybe lynq modify? 20220916>
+	dev_info(mtu->dev, "%s, U3D_POWER_MANAGEMENT:0x%x\n", __func__, mtu3_readl(mbase, U3D_POWER_MANAGEMENT));//<maybe lynq modify? 20220916>
 	/* use new QMU format when HW version >= 0x1003 */
 	if (mtu->gen2cp)
 		mtu3_writel(mbase, U3D_QFCR, ~0x0);
 }
-
+//<maybe lynq add? 20220916>
 static irqreturn_t mtu3_vbus_detect_eint_isr(int irq, void *data)
 {
 	struct ssusb_mtk *ssusb = data;//tianyan@2021.11.29 modify for usb otg
@@ -453,7 +453,7 @@
 	}
 	return 0;
 }
-
+//<maybe lynq add? 20220916>
 void mtu3_start(struct mtu3 *mtu)
 {
 	void __iomem *mbase = mtu->mac_base;
diff --git a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_host.c b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_host.c
index 3766856..6550dda 100755
--- a/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_host.c
+++ b/src/kernel/linux/v4.19/drivers/usb/mtu3/mtu3_host.c
@@ -205,7 +205,7 @@
 		ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
 
 	/* if port0 supports dual-role, works as host mode by default */
-	//ssusb_set_force_vbus(ssusb, false);
+	//ssusb_set_force_vbus(ssusb, false);   <maybe lynq modify? 20220916>
 	ssusb_set_vbus(&ssusb->otg_switch, 1);
 }
 
diff --git a/src/kernel/linux/v4.19/include/dt-bindings/power/mt6890-power.h b/src/kernel/linux/v4.19/include/dt-bindings/power/mt6890-power.h
index 9c6e93f..6fdf4c7 100755
--- a/src/kernel/linux/v4.19/include/dt-bindings/power/mt6890-power.h
+++ b/src/kernel/linux/v4.19/include/dt-bindings/power/mt6890-power.h
@@ -8,18 +8,19 @@
 
 #define MT6890_POWER_DOMAIN_PEXTP_D_2LX1		0
 #define MT6890_POWER_DOMAIN_ETH				1
-#define MT6890_POWER_DOMAIN_AUDIO			2
-#define MT6890_POWER_DOMAIN_MD1				3
-#define MT6890_POWER_DOMAIN_EIP97			4
-#define MT6890_POWER_DOMAIN_CONN			5
-#define MT6890_POWER_DOMAIN_MSDC			6
-#define MT6890_POWER_DOMAIN_HSMTOP			7
-#define MT6890_POWER_DOMAIN_SSUSB			8
-#define MT6890_POWER_DOMAIN_SSUSB_PHY			9
-#define MT6890_POWER_DOMAIN_SGMII_0_PHY			10
-#define MT6890_POWER_DOMAIN_SGMII_0_TOP			11
-#define MT6890_POWER_DOMAIN_SGMII_1_PHY			12
-#define MT6890_POWER_DOMAIN_SGMII_1_TOP			13
-#define MT6890_POWER_DOMAIN_PEXTP_D_2LX1_PHY		14
+#define MT6890_POWER_DOMAIN_NETSYS			2
+#define MT6890_POWER_DOMAIN_AUDIO			3
+#define MT6890_POWER_DOMAIN_MD1				4
+#define MT6890_POWER_DOMAIN_EIP97			5
+#define MT6890_POWER_DOMAIN_CONN			6
+#define MT6890_POWER_DOMAIN_MSDC			7
+#define MT6890_POWER_DOMAIN_HSMTOP			8
+#define MT6890_POWER_DOMAIN_SSUSB			9
+#define MT6890_POWER_DOMAIN_SSUSB_PHY			10
+#define MT6890_POWER_DOMAIN_SGMII_0_PHY			11
+#define MT6890_POWER_DOMAIN_SGMII_0_TOP			12
+#define MT6890_POWER_DOMAIN_SGMII_1_PHY			13
+#define MT6890_POWER_DOMAIN_SGMII_1_TOP			14
+#define MT6890_POWER_DOMAIN_PEXTP_D_2LX1_PHY		15
 
 #endif /* _DT_BINDINGS_POWER_MT6890_POWER_H */
diff --git a/src/kernel/linux/v4.19/sound/soc/mediatek/mt6880/mt6880-mt6359.c b/src/kernel/linux/v4.19/sound/soc/mediatek/mt6880/mt6880-mt6359.c
index 34bd9d8..295b8ac 100644
--- a/src/kernel/linux/v4.19/sound/soc/mediatek/mt6880/mt6880-mt6359.c
+++ b/src/kernel/linux/v4.19/sound/soc/mediatek/mt6880/mt6880-mt6359.c
@@ -141,7 +141,7 @@
 	if (ret != 0 && ret != -ENOTSUPP)
 		return ret;
 
-    ret = snd_soc_dai_set_fmt(rtd->codec_dai, codec_dai_fmt);
+	ret = snd_soc_dai_set_fmt(rtd->codec_dai, codec_dai_fmt);
     if (ret != 0 && ret != -ENOTSUPP)
         return ret;
 	/*	zhengzhou 0316 +++*/
diff --git a/src/kernel/modules/connectivity/2.0/conninfra_driver/Makefile b/src/kernel/modules/connectivity/2.0/conninfra_driver/Makefile
index ef0e150..67ec6d9 100755
--- a/src/kernel/modules/connectivity/2.0/conninfra_driver/Makefile
+++ b/src/kernel/modules/connectivity/2.0/conninfra_driver/Makefile
@@ -74,6 +74,10 @@
 ccflags-y += -D CONFIG_CONNINFRA_THERMAL_SUPPORT=1
 endif
 
+ifeq ($(ENABLE_TCXO), yes)
+    ccflags-y += -D ENABLE_TCXO=1
+endif
+
 $(patsubst CONFIG_%, -DCFG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
 $(patsubst CONFIG_%, -DCFG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
 $(patsubst CONFIG_%, -DCFG_%=0, $(patsubst %=n,%,$(filter %=n,$(EXTRA_KCONFIG)))) \
diff --git a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/consys_hw.c b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/consys_hw.c
index 22ef3f9..1415faa 100755
--- a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/consys_hw.c
+++ b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/consys_hw.c
@@ -17,8 +17,10 @@
 */
 
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_reserved_mem.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "osal.h"
 
@@ -97,6 +99,8 @@
 
 struct consys_hw_env conn_hw_env;
 
+struct pinctrl *g_conninfra_pinctrl_ptr = NULL;
+
 const struct consys_hw_ops_struct *consys_hw_ops;
 struct platform_device *g_pdev;
 
@@ -452,6 +456,57 @@
 		return -1;
 }
 
+int consys_hw_tcxo_parser(struct platform_device *pdev)
+{
+	int ret = 0;
+	int pinmux = 0;
+	struct device_node *pinctrl_node;
+	struct device_node *pins_node;
+	unsigned int pin_num = 0xffffffff;
+	const char* tcxo_support;
+
+	/* Get tcxo status */
+	/* Set default value */
+	conn_hw_env.tcxo_support = false;
+	ret = of_property_read_string(pdev->dev.of_node, "tcxo_support", &tcxo_support);
+	if (!ret) {
+		if (strcmp(tcxo_support, "true") == 0) {
+			conn_hw_env.tcxo_support = true;
+			pr_info("[%s] Support TCXO", __func__);
+		}
+	} else {
+		pr_warn("Get tcxo property fail: %d", ret);
+	}
+
+	/* Set up gpio for TCXO */
+	g_conninfra_pinctrl_ptr = devm_pinctrl_get(&pdev->dev);
+
+	if (IS_ERR(g_conninfra_pinctrl_ptr)) {
+		pr_err("Fail to get conninfra pinctrl");
+	} else {
+		pinctrl_node = of_parse_phandle(pdev->dev.of_node, "pinctrl-1", 0);
+
+		if (pinctrl_node) {
+			pins_node = of_get_child_by_name(pinctrl_node, "pins_cmd_dat");
+
+			if (pins_node) {
+				ret = of_property_read_u32(pins_node, "pinmux", &pinmux);
+
+				if (ret == 0) {
+					pin_num = (pinmux >> 8) & 0xff;
+					pr_info("Conninfra gpio pin number[%d]\n", pin_num);
+				} else {
+					pr_err("Fail to get conninfra gpio pin number");
+				}
+			}
+		}
+	}
+
+	pr_info("[%s] tcxo=%d pintctrl=%p", __func__,
+		conn_hw_env.tcxo_support, g_conninfra_pinctrl_ptr);
+	return 0;
+}
+
 int mtk_conninfra_probe(struct platform_device *pdev)
 {
 	int ret = -1;
@@ -498,6 +553,12 @@
 		return -5;
 	}
 
+#ifdef ENABLE_TCXO
+	conn_hw_env.tcxo_support = true;
+#else
+	consys_hw_tcxo_parser(pdev);
+#endif
+
 #if CFG_CONNINFRA_FW_LOG_SUPPORT
 	/* Setup connsys log emi base */
 	emi_info = emi_mng_get_phy_addr();
diff --git a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/include/consys_hw.h b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/include/consys_hw.h
index 3ff7b22..77ca8ef 100755
--- a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/include/consys_hw.h
+++ b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/include/consys_hw.h
@@ -176,6 +176,7 @@
 struct consys_hw_env {
 	unsigned int adie_hw_version;
 	int is_rc_mode;
+	bool tcxo_support;
 };
 
 struct conninfra_plat_data {
diff --git a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/mt6880/mt6880.c b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/mt6880/mt6880.c
index c0a178e..88aa80b 100755
--- a/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/mt6880/mt6880.c
+++ b/src/kernel/modules/connectivity/2.0/conninfra_driver/platform/mt6880/mt6880.c
@@ -234,15 +234,16 @@
 int consys_co_clock_type(void)
 {
 	const struct conninfra_conf *conf;
+	bool conf_tcxo = false;
 
 	/* Default solution */
 	conf = conninfra_conf_get_cfg();
-	if (NULL == conf) {
-		pr_err("[%s] Get conf fail", __func__);
-		return -1;
+	if (conf != NULL && conf->tcxo_gpio != 0) {
+		conf_tcxo = true;
 	}
+
 	/* TODO: for co-clock mode, there are two case: 26M and 52M. Need something to distinguish it. */
-	if (conf->tcxo_gpio != 0)
+	if (conf_tcxo || conn_hw_env.tcxo_support)
 		return CONNSYS_CLOCK_SCHEMATIC_26M_EXTCXO;
 	else
 		return CONNSYS_CLOCK_SCHEMATIC_26M_COTMS;
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/frame_engine.h b/src/kernel/modules/netsys_driver/nat/hw_nat/frame_engine.h
index 7690316..d8d5ddb 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/frame_engine.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/frame_engine.h
@@ -381,7 +381,7 @@
 
 /* PPE FOE Bind Rate*/
 /* packet in a time stamp unit */
-#define DFL_FOE_BNDR		30
+#define DFL_FOE_BNDR		10
 /*config  RA_HW_NAT_PBND_RD_LMT*/
 /*        int "max retyr count"*/
 /*	default 10*/
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
index 614eeb0..09360ce 100644
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.c
@@ -430,12 +430,7 @@
 			return 0;
 		}
 	} else {
-		if (hnat_chip_name & (MT7622_HWNAT | LEOPARD_HWNAT)) {
-			ppe_foe_base =
-			    dma_alloc_coherent(dev, foe_tbl_size, &ppe_phy_foe_base, GFP_KERNEL);
-		} else {
-			ppe_foe_base = dma_alloc_coherent(NULL, foe_tbl_size, &ppe_phy_foe_base, GFP_KERNEL);
-		}
+		ppe_foe_base = dma_alloc_coherent(dev, foe_tbl_size, &ppe_phy_foe_base, GFP_KERNEL);
 
 		ppe_virt_foe_base_tmp = ppe_foe_base;
 		pr_notice("init PpeVirtFoeBase_tmp = %p\n", ppe_virt_foe_base_tmp);
@@ -497,12 +492,7 @@
 			return 0;
 		}
 	} else {
-		if (hnat_chip_name & (MT7622_HWNAT | LEOPARD_HWNAT)) {
-			ppe1_foe_base =
-			    dma_alloc_coherent(dev, foe_tbl_size, &ppe1_phy_foe_base, GFP_KERNEL);
-		} else {
-			ppe1_foe_base = dma_alloc_coherent(NULL, foe_tbl_size, &ppe1_phy_foe_base, GFP_KERNEL);
-		}
+		ppe1_foe_base = dma_alloc_coherent(dev, foe_tbl_size, &ppe1_phy_foe_base, GFP_KERNEL);
 
 		ppe1_virt_foe_base_tmp = ppe1_foe_base;
 		pr_notice("init Ppe1VirtFoeBase_tmp = %p\n", ppe1_virt_foe_base_tmp);
@@ -3714,14 +3704,20 @@
 }
 
 
-#if (0)
-static void foe_free_tbl(uint32_t num_of_entry)
+#if (1)
+static void foe_free_tbl(uint32_t num_of_entry, struct device *dev)
 {
-	u32 foe_tbl_size;
+	u32 foe_tbl_size, mib_tbl_size;
 
 	foe_tbl_size = num_of_entry * sizeof(struct foe_entry);
-	dma_free_coherent(NULL, foe_tbl_size, ppe_foe_base, ppe_phy_foe_base);
+	mib_tbl_size = num_of_entry * sizeof(struct mib_entry);
+	dma_free_coherent(dev, foe_tbl_size, ppe_foe_base, ppe_phy_foe_base);
+	dma_free_coherent(dev, foe_tbl_size, ppe1_foe_base, ppe1_phy_foe_base);
+	dma_free_coherent(dev, mib_tbl_size, ppe_mib_base, ppe_phy_mib_base);
+	dma_free_coherent(dev, mib_tbl_size, ppe1_mib_base, ppe1_phy_mib_base);
+
 	reg_write(PPE_FOE_BASE, 0);
+	reg_write(PPE1_FOE_BASE, 0);
 }
 #endif
 
@@ -3764,17 +3760,22 @@
 	return 0;
 }
 
-#if (0)
-static int32_t ppe_eng_stop(void)
+#if (1)
+int ppe_eng_stop(struct device *dev)
 {
+	/*disable TB CFG*/
+	reg_write(PPE_TB_CFG, 0x2f000);
+	reg_write(PPE1_TB_CFG, 0x2f000);
+
 	/* Set PPE FOE ENABLE */
 	ppe_setfoe_glocfg_ebl(0);
+	ppe1_setfoe_glocfg_ebl(0);
 
 	/* Set PPE Flow Set */
 	ppe_setfoe_ebl(0);
 
 	/* Free FOE table */
-	foe_free_tbl(FOE_4TB_SIZ);
+	foe_free_tbl(FOE_4TB_SIZ, dev);
 
 	return 0;
 }
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.h b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.h
index 0c4fd19..22d132d 100755
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.h
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/hnat_common.h
@@ -133,4 +133,5 @@
 void hwnat_config_setting(void);
 void fe_feature_setting(void);
 void FOE_INFO_DUMP(struct sk_buff *skb);
+int ppe_eng_stop(struct device *dev);
 #endif
diff --git a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
index 4f05d42..ab0f906 100644
--- a/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
+++ b/src/kernel/modules/netsys_driver/nat/hw_nat/ra_nat.c
@@ -85,6 +85,7 @@
 EXPORT_SYMBOL(fe_feature);
 void __iomem *fe_base;
 void __iomem *med_base;
+struct platform_device *pdev_hnat;
 extern u32 rndis_mod;
 extern u32 rndis_bind_count;
 
@@ -593,11 +594,78 @@
 	pr_notice("****************************************\n");
 
 }
+
+static int hnat_device_remove(struct platform_device *dev)
+{
+	pr_notice("!!!!hnat remove\n");
+	return 0;
+}
+
+static int hnat_device_probe(struct platform_device *pdev)
+{
+	pr_notice("!!!!hnat probe\n");
+	return 0;
+}
+
+int hnat_pm_suspend(struct device *device)
+{
+	ppe_eng_stop(&pdev_hnat->dev);
+	pr_notice("!!!!  hnat suspend done\n");
+
+	return 0;
+}
+
+int hnat_pm_resume(struct device *device)
+{
+	NAT_PRINT("MEDIATEK HW NAT Module Enabled\n");
+
+	/* Set PPE FOE Hash Mode */
+	if (!ppe_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev_hnat->dev)) {
+		pr_info("PPE0 memory allocation failed\n");
+		return -ENOMEM;	/* memory allocation failed */
+	}
+
+	if (!ppe1_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev_hnat->dev)) {
+		pr_info("PPE1 memory allocation failed\n");
+		return -ENOMEM;	/* memory allocation failed */
+	}
+
+	/* Register ioctl handler */
+	//ppe_reg_ioctl_handler(dev_hnat);
+
+	ppe_eng_init();
+
+	set_gdma_fwd(1);
+
+	pr_notice("!!!! hnat resume done\n");
+
+	return 0;
+}
+
+static const struct dev_pm_ops hnat_pm_ops = {
+	.suspend = hnat_pm_suspend,
+	.resume = hnat_pm_resume,
+};
+
+static const struct of_device_id hnat_of_ids[] = {
+	{ .compatible = "mediatek,hnat", },
+	{}
+};
+
+static struct platform_driver mtk_hnat_device = {
+	.probe  = hnat_device_probe,
+	.remove = hnat_device_remove,
+	.driver = {
+		.name = "hnat",
+		.pm = &hnat_pm_ops,
+		.owner = THIS_MODULE,
+		.of_match_table = hnat_of_ids,
+	},
+};
+
 dev_t dev_hnat;
 static int32_t ppe_init_mod(void)
 {
-	struct platform_device *pdev;
-
 	NAT_PRINT("MEDIATEK HW NAT Module Enabled\n");
 	hwnat_config_setting();
 	fe_feature_setting();
@@ -606,23 +674,25 @@
 	med_base = ioremap(MTK_MED_BASE, MTK_FE_RANGE);
 
 
-	pdev = platform_device_alloc("HW_NAT", PLATFORM_DEVID_AUTO);
-	if (!pdev)
+	pdev_hnat = platform_device_alloc("HW_NAT", PLATFORM_DEVID_AUTO);
+	if (!pdev_hnat)
 		return -ENOMEM;
 
-	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
-	hwnat_setup_dma_ops(&pdev->dev, FALSE);
+	pdev_hnat->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	pdev_hnat->dev.dma_mask = &pdev_hnat->dev.coherent_dma_mask;
+	hwnat_setup_dma_ops(&pdev_hnat->dev, FALSE);
 
 	/* Set PPE FOE Hash Mode */
-	if (!ppe_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev->dev)) {
+	if (!ppe_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev_hnat->dev)) {
 		pr_info("PPE0 memory allocation failed\n");
+		platform_device_put(pdev_hnat);
 		return -ENOMEM;	/* memory allocation failed */
 	}
 
 	/* Set PPE FOE Hash Mode */
-	if (!ppe1_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev->dev)) {
+	if (!ppe1_setfoe_hash_mode(DFL_FOE_HASH_MODE, &pdev_hnat->dev)) {
 		pr_info("PPE1 memory allocation failed\n");
+		platform_device_put(pdev_hnat);
 		return -ENOMEM;	/* memory allocation failed */
 	}
 
@@ -692,6 +762,9 @@
 	if (fe_feature & SW_DVFS)
 		sw_dvfs_init();
 
+	if (platform_driver_register(&mtk_hnat_device))
+		pr_notice("[HNAT] hnat probe fail\n");
+
 	ppe_init_mib_counter();
 	return 0;
 }