[rdk-b][common][bsp][Refactor and sync kernel from Openwrt]

[Description]
Refactor and sync kernel from Openwrt to v5.4.219

[Release-log]
N/A

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
index 09e8267..680ea7e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
@@ -71,7 +71,7 @@
 
 --- a/mm/page_alloc.c
 +++ b/mm/page_alloc.c
-@@ -6886,7 +6886,7 @@ static void __ref alloc_node_mem_map(str
+@@ -6931,7 +6931,7 @@ static void __ref alloc_node_mem_map(str
  		mem_map = NODE_DATA(0)->node_mem_map;
  #if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
  		if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
index 1c6eb8c..4bb74ed 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
@@ -65,7 +65,7 @@
  /**
   *	ata_build_rw_tf - Build ATA taskfile for given read/write request
   *	@tf: Target ATA taskfile
-@@ -5155,6 +5168,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
+@@ -5159,6 +5172,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
  		if (tag < 0)
  			return NULL;
  	}
@@ -75,7 +75,7 @@
  
  	qc = __ata_qc_from_tag(ap, tag);
  	qc->tag = qc->hw_tag = tag;
-@@ -6091,6 +6107,9 @@ struct ata_port *ata_port_alloc(struct a
+@@ -6095,6 +6111,9 @@ struct ata_port *ata_port_alloc(struct a
  	ap->stats.unhandled_irq = 1;
  	ap->stats.idle_irq = 1;
  #endif
@@ -85,7 +85,7 @@
  	ata_sff_port_init(ap);
  
  	return ap;
-@@ -6126,6 +6145,12 @@ static void ata_host_release(struct kref
+@@ -6130,6 +6149,12 @@ static void ata_host_release(struct kref
  
  		kfree(ap->pmp_link);
  		kfree(ap->slave_link);
@@ -98,7 +98,7 @@
  		kfree(ap);
  		host->ports[i] = NULL;
  	}
-@@ -6589,7 +6614,23 @@ int ata_host_register(struct ata_host *h
+@@ -6593,7 +6618,23 @@ int ata_host_register(struct ata_host *h
  		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
  		host->ports[i]->local_port_no = i + 1;
  	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 16b872e..a4d3f2f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -358,19 +358,23 @@
 			 <&topckgen CK_TOP_NPU_TOPS_SEL>,
 			 <&topckgen CK_TOP_CK_NPU_SEL_CM_TOPS_SEL>;
 		clock-names = "bus", "sram", "xdma", "offload", "mgmt";
+		power-domains = <&topmisc MT7988_POWER_DOMAIN_TOPS0>,
+				<&topmisc MT7988_POWER_DOMAIN_TOPS1>;
+
 		interrupt-parent = <&gic>;
 		interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "tdma-tx-pause", "mbox";
-		topmisc = <&topmisc>;
+
 		fe_mem = <&eth>;
-		topckgen = <&topckgen>;
 	};
+
 	hpdma1: hpdma@09106000 {
 		compatible = "mediatek,hpdma-top";
 		reg = <0 0x09106000 0 0x1000>;
 		reg-names = "base";
 	};
+
 	hpdma2: hpdma@09606000 {
 		compatible = "mediatek,hpdma-sub";
 		reg = <0 0x09606000 0 0x1000>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index c6f76bf..5ad8645 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -656,6 +656,26 @@
 	pr_info("+-----------------------------------------------+\n");
 }
 
+void dump_each_port(struct seq_file *seq, struct mtk_eth *eth, u32 base)
+{
+	u32 pkt_cnt = 0;
+	int i = 0;
+
+	for (i = 0; i < 7; i++) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+			if ((base == 0x402C) && (i == 6))
+				base = 0x408C;
+			else if ((base == 0x408C) && (i == 6))
+				base = 0x402C;
+			else
+				;
+		}
+		pkt_cnt = mt7530_mdio_r32(eth, (base) + (i * 0x100));
+		seq_printf(seq, "%8u ", pkt_cnt);
+	}
+	seq_puts(seq, "\n");
+}
+
 int esw_cnt_read(struct seq_file *seq, void *v)
 {
 	unsigned int pkt_cnt = 0;
@@ -669,56 +689,47 @@
 
 	mt798x_iomap();
 
-#define DUMP_EACH_PORT(base)					\
-	do { \
-		for (i = 0; i < 7; i++) {				\
-			pkt_cnt = mt7530_mdio_r32(eth, (base) + (i * 0x100));\
-			seq_printf(seq, "%8u ", pkt_cnt);		\
-		}							\
-		seq_puts(seq, "\n"); \
-	} while (0)
-
 	seq_printf(seq, "===================== %8s %8s %8s %8s %8s %8s %8s\n",
 		   "Port0", "Port1", "Port2", "Port3", "Port4", "Port5",
 		   "Port6");
 	seq_puts(seq, "Tx Drop Packet      :");
-	DUMP_EACH_PORT(0x4000);
+	dump_each_port(seq, eth, 0x4000);
 	seq_puts(seq, "Tx CRC Error        :");
-	DUMP_EACH_PORT(0x4004);
+	dump_each_port(seq, eth, 0x4004);
 	seq_puts(seq, "Tx Unicast Packet   :");
-	DUMP_EACH_PORT(0x4008);
+	dump_each_port(seq, eth, 0x4008);
 	seq_puts(seq, "Tx Multicast Packet :");
-	DUMP_EACH_PORT(0x400C);
+	dump_each_port(seq, eth, 0x400C);
 	seq_puts(seq, "Tx Broadcast Packet :");
-	DUMP_EACH_PORT(0x4010);
+	dump_each_port(seq, eth, 0x4010);
 	seq_puts(seq, "Tx Collision Event  :");
-	DUMP_EACH_PORT(0x4014);
+	dump_each_port(seq, eth, 0x4014);
 	seq_puts(seq, "Tx Pause Packet     :");
-	DUMP_EACH_PORT(0x402C);
+	dump_each_port(seq, eth, 0x402C);
 	seq_puts(seq, "Rx Drop Packet      :");
-	DUMP_EACH_PORT(0x4060);
+	dump_each_port(seq, eth, 0x4060);
 	seq_puts(seq, "Rx Filtering Packet :");
-	DUMP_EACH_PORT(0x4064);
+	dump_each_port(seq, eth, 0x4064);
 	seq_puts(seq, "Rx Unicast Packet   :");
-	DUMP_EACH_PORT(0x4068);
+	dump_each_port(seq, eth, 0x4068);
 	seq_puts(seq, "Rx Multicast Packet :");
-	DUMP_EACH_PORT(0x406C);
+	dump_each_port(seq, eth, 0x406C);
 	seq_puts(seq, "Rx Broadcast Packet :");
-	DUMP_EACH_PORT(0x4070);
+	dump_each_port(seq, eth, 0x4070);
 	seq_puts(seq, "Rx Alignment Error  :");
-	DUMP_EACH_PORT(0x4074);
+	dump_each_port(seq, eth, 0x4074);
 	seq_puts(seq, "Rx CRC Error	    :");
-	DUMP_EACH_PORT(0x4078);
+	dump_each_port(seq, eth, 0x4078);
 	seq_puts(seq, "Rx Undersize Error  :");
-	DUMP_EACH_PORT(0x407C);
+	dump_each_port(seq, eth, 0x407C);
 	seq_puts(seq, "Rx Fragment Error   :");
-	DUMP_EACH_PORT(0x4080);
+	dump_each_port(seq, eth, 0x4080);
 	seq_puts(seq, "Rx Oversize Error   :");
-	DUMP_EACH_PORT(0x4084);
+	dump_each_port(seq, eth, 0x4084);
 	seq_puts(seq, "Rx Jabber Error     :");
-	DUMP_EACH_PORT(0x4088);
+	dump_each_port(seq, eth, 0x4088);
 	seq_puts(seq, "Rx Pause Packet     :");
-	DUMP_EACH_PORT(0x408C);
+	dump_each_port(seq, eth, 0x408C);
 	mt7530_mdio_w32(eth, 0x4fe0, 0xf0);
 	mt7530_mdio_w32(eth, 0x4fe0, 0x800000f0);
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
index 0eefd36..50729d6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
@@ -538,7 +538,7 @@
 	switch(phydev->drv->phy_id) {
 		case 0x03a29481:
 		{
-			int tmp[16] = { 1, 1, 1, 1 };
+			int tmp[16] = { -1, -1, -1, -1 };
 			memcpy(bias, (const void *)tmp, sizeof(bias));
 			break;
 		}
@@ -894,6 +894,13 @@
 	/* Disable TX power saving */
 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
 			MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+
+	/* Slave mode finetune, Kp=3/Kf=2 */
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__phy_write(phydev, 0x12, 0x0);
+	__phy_write(phydev, 0x11, 0x750);
+	__phy_write(phydev, 0x10, 0x9686);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
 }
 
 static int mt798x_phy_calibration(struct phy_device *phydev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
index 8e99118..aa31f22 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
@@ -15,10 +15,10 @@
  	struct cpufreq_frequency_table *freq_table;
  	int ret;
 +	int target_vproc;
-+	u32 reg_val;
++	u8 reg_val;
 +	struct nvmem_cell *cell;
 +	size_t len;
-+	u32 *buf;
++	u8 *buf;
  
  	info = mtk_cpu_dvfs_info_lookup(policy->cpu);
  	if (!info) {
@@ -28,7 +28,7 @@
  
 +	cell = nvmem_cell_get(info->cpu_dev, "calibration-data");
 +	if (!IS_ERR(cell)) {
-+		buf = (u32 *)nvmem_cell_read(cell, &len);
++		buf = (u8 *)nvmem_cell_read(cell, &len);
 +		nvmem_cell_put(cell);
 +		if (!IS_ERR(buf)) {
 +			reg_val = buf[0] & 0x1f;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch
new file mode 100755
index 0000000..e3efa34
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch
@@ -0,0 +1,133 @@
+Index: linux-5.4.215/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.215.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.215/drivers/net/dsa/mt7530.c
+@@ -847,6 +847,117 @@ mt7531_ind_phy_write(struct dsa_switch *
+ 	return ret;
+ }
+
++static int mt753x_mdio_read(struct mii_bus *bus, int addr, int regnum)
++{
++	struct mt7530_priv *priv = bus->priv;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 val;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(addr) |
++		  MT7531_MDIO_REG_ADDR(regnum);
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	ret = val & MT7531_MDIO_RW_DATA_MASK;
++out:
++	mutex_unlock(&priv->bus->mdio_lock);
++
++	return ret;
++}
++
++static int mt753x_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
++{
++	struct mt7530_priv *priv = bus->priv;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 reg;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(addr) |
++		  MT7531_MDIO_REG_ADDR(regnum) | val;
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&priv->bus->mdio_lock);
++
++	return ret;
++}
++
++static int mt753x_setup_mdio(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++	struct device_node *mdio_np;
++	int ret;
++
++	mdio_np = of_get_compatible_child(priv->dev->of_node, "mediatek,dsa-slave-mdio");
++	if (!mdio_np) {
++		dev_err(priv->dev, "no MDIO bus node\n");
++		return -ENODEV;
++	}
++
++	priv->ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
++	if (!priv->ds->slave_mii_bus) {
++		ret = -ENOMEM;
++		goto err_put_node;
++	}
++	priv->ds->slave_mii_bus->name = "mediatek,dsa-slave-mdio";
++	priv->ds->slave_mii_bus->priv = priv;
++	priv->ds->slave_mii_bus->parent = priv->dev;
++	priv->ds->slave_mii_bus->phy_mask = ~priv->ds->phys_mii_mask;
++	priv->ds->slave_mii_bus->read = mt753x_mdio_read;
++	priv->ds->slave_mii_bus->write = mt753x_mdio_write;
++	snprintf(priv->ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d",
++		 priv->ds->dst->index, priv->ds->index);
++	priv->ds->slave_mii_bus->dev.of_node = mdio_np;
++
++	ret = of_mdiobus_register(priv->ds->slave_mii_bus, mdio_np);
++	if (ret)
++		dev_err(priv->dev, "unable to register MDIO bus %s\n",
++			priv->ds->slave_mii_bus->id);
++
++err_put_node:
++	of_node_put(mdio_np);
++
++	return ret;
++}
++
+ static void
+ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ 		   uint8_t *data)
+@@ -2694,6 +2805,10 @@ mt7988_setup(struct dsa_switch *ds)
+ 	if (ret < 0)
+ 		return ret;
+
++	ret = mt753x_setup_mdio(ds);
++	if (ret < 0)
++		dev_err(priv->dev, "mt753x_setup_mdio failed\n");
++
+ 	return 0;
+ }
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
deleted file mode 100644
index 5a130b1..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-Index: linux-5.4.203/drivers/net/dsa/mt7530.c
-===================================================================
---- linux-5.4.203.orig/drivers/net/dsa/mt7530.c
-+++ linux-5.4.203/drivers/net/dsa/mt7530.c
-@@ -847,6 +847,132 @@ mt7531_ind_phy_write(struct dsa_switch *
- 	return ret;
- }
-
-+static int mt753x_mdio_read(struct mii_bus *bus, int addr, int regnum)
-+{
-+	struct mt7530_priv *priv = bus->priv;
-+	struct mt7530_dummy_poll p;
-+	int ret;
-+	u32 val;
-+
-+	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-+
-+	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-+				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
-+	if (ret < 0) {
-+		dev_err(priv->dev, "poll timeout\n");
-+		goto out;
-+	}
-+
-+	val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(addr) |
-+		  MT7531_MDIO_REG_ADDR(regnum);
-+
-+	mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
-+
-+	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-+				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
-+	if (ret < 0) {
-+		dev_err(priv->dev, "poll timeout\n");
-+		goto out;
-+	}
-+
-+	ret = val & MT7531_MDIO_RW_DATA_MASK;
-+out:
-+	mutex_unlock(&priv->bus->mdio_lock);
-+
-+	return ret;
-+}
-+
-+static int mt753x_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
-+{
-+	struct mt7530_priv *priv = bus->priv;
-+	struct mt7530_dummy_poll p;
-+	int ret;
-+	u32 reg;
-+
-+	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-+
-+	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-+				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
-+	if (ret < 0) {
-+		dev_err(priv->dev, "poll timeout\n");
-+		goto out;
-+	}
-+
-+	reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(addr) |
-+		  MT7531_MDIO_REG_ADDR(regnum) | val;
-+
-+	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
-+
-+	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-+				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
-+	if (ret < 0) {
-+		dev_err(priv->dev, "poll timeout\n");
-+		goto out;
-+	}
-+
-+out:
-+	mutex_unlock(&priv->bus->mdio_lock);
-+
-+	return ret;
-+}
-+
-+static int mt753x_mdio_init(struct mt7530_priv *priv)
-+{
-+	struct device_node *dn;
-+	struct device_node *mii_np;
-+	int ret;
-+
-+	dn = priv->dev->of_node;
-+
-+	mii_np = of_get_child_by_name(dn, "mdio-bus");
-+	if (!mii_np) {
-+		ret = -ENODEV;
-+		goto err_put_node;
-+	}
-+
-+	if (!of_device_is_available(mii_np)) {
-+		ret = -ENODEV;
-+		goto err_put_node;
-+	}
-+
-+	priv->gbus = devm_mdiobus_alloc(priv->dev);
-+	if (!priv->gbus) {
-+		ret = -ENOMEM;
-+		goto err_put_node;
-+	}
-+	priv->gbus->name = "mt753x_mdio";
-+	priv->gbus->read = mt753x_mdio_read;
-+	priv->gbus->write = mt753x_mdio_write;
-+	priv->gbus->priv = priv;
-+	priv->gbus->parent = priv->dev;
-+
-+	if(snprintf(priv->gbus->id, MII_BUS_ID_SIZE, "%s@%s", mii_np->name, dn->name) < 0) {
-+		ret = -ENOMEM;
-+		goto err_put_node;
-+	}
-+
-+	ret = of_mdiobus_register(priv->gbus, mii_np);
-+	if (ret)
-+		priv->gbus = NULL;
-+
-+err_put_node:
-+	of_node_put(mii_np);
-+
-+	return ret;
-+}
-+
-+static void mt753x_mdio_exit(struct mt7530_priv *priv)
-+{
-+	if (!priv->gbus)
-+		return;
-+
-+	mdiobus_unregister(priv->gbus);
-+}
-+
- static void
- mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
- 		   uint8_t *data)
-@@ -2892,6 +3018,7 @@ mt7530_probe(struct mdio_device *mdiodev
- 		return ret;
- 	}
- 	mt7530_nl_init(&priv);
-+	mt753x_mdio_init(priv);
-
- 	return 0;
- }
-@@ -2919,6 +3046,7 @@ mt7530_remove(struct mdio_device *mdiode
- 		iounmap(priv->base);
-
- 	mt7530_nl_exit();
-+	mt753x_mdio_exit(priv);
- }
-
- static struct mdio_driver mt7530_mdio_driver = {
-Index: linux-5.4.203/drivers/net/dsa/mt7530.h
-===================================================================
---- linux-5.4.203.orig/drivers/net/dsa/mt7530.h
-+++ linux-5.4.203/drivers/net/dsa/mt7530.h
-@@ -730,6 +730,7 @@ struct mt7530_priv {
- 	struct device		*dev;
- 	struct dsa_switch	*ds;
- 	struct mii_bus		*bus;
-+	struct mii_bus		*gbus;
- 	struct reset_control	*rstc;
- 	struct regulator	*core_pwr;
- 	struct regulator	*io_pwr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch
new file mode 100755
index 0000000..d0764d2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch
@@ -0,0 +1,366 @@
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 9e8a5c4..16f5187 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -919,6 +919,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ 		      struct sw_flow_key *key)
+ {
+ 	struct vport *vport = ovs_vport_rcu(dp, out_port);
++	struct multicast_data_base *mdb;
++	struct multicast_table *table;
++	struct multicast_table_entry *entry;
++	struct sk_buff *skb_cpy;
+ 
+ 	if (likely(vport)) {
+ 		u16 mru = OVS_CB(skb)->mru;
+@@ -933,7 +937,28 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ 
+ 		if (likely(!mru ||
+ 		           (skb->len <= mru + vport->dev->hard_header_len))) {
+-			ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
++			if (is_ipv4_multicast(skb) && !is_igmp(skb)) {
++				mdb = vport->mdb;
++				spin_lock(&mdb->tbl_lock);
++				list_for_each_entry(table, &mdb->list_head, mdb_node) {
++					if (table->group_addr.u.ip4 == key->ipv4.addr.dst) {
++						list_for_each_entry(entry, &table->entry_list, entry_node) {
++							skb_cpy = skb_copy(skb, GFP_ATOMIC);
++							if (!skb_cpy) {
++								kfree_skb(skb);
++								pr_err("%s(): error\n", __func__);
++								spin_unlock(&mdb->tbl_lock);
++								return;
++							}
++							memcpy(skb_cpy->data, entry->eth_addr, ETH_ALEN);
++							ovs_vport_send(vport, skb_cpy, ovs_key_mac_proto(key));
++						}
++					}
++				}
++				spin_unlock(&mdb->tbl_lock);
++				kfree_skb(skb);
++			} else
++				ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
+ 		} else if (mru <= vport->dev->mtu) {
+ 			struct net *net = read_pnet(&dp->net);
+ 
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 4f097bd..e6be550 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -11,6 +11,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/in.h>
+ #include <linux/ip.h>
++#include <linux/igmp.h>
+ #include <linux/jhash.h>
+ #include <linux/delay.h>
+ #include <linux/time.h>
+@@ -530,6 +531,166 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 	return err;
+ }
+ 
++static int ovs_ip4_multicast_add_group(__be32 _group_addr,
++										const u8 *entry_addr,
++										struct vport *input_vport)
++{
++	struct multicast_data_base *mdb;
++	struct multicast_table *table;
++	struct multicast_table_entry *entry;
++
++	if (ipv4_is_local_multicast(_group_addr))
++		return 0;
++
++	mdb = input_vport->mdb;
++	spin_lock(&mdb->tbl_lock);
++	list_for_each_entry(table, &mdb->list_head, mdb_node) {
++		if (table->group_addr.u.ip4 == _group_addr) {
++			list_for_each_entry(entry, &table->entry_list, entry_node) {
++				if (!memcmp(entry->eth_addr, entry_addr, ETH_ALEN)) {
++					spin_unlock(&mdb->tbl_lock);
++					return 0;
++				}
++			}
++			entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
++			if (!entry) {
++				spin_unlock(&mdb->tbl_lock);
++				return -ENOMEM;
++			}
++
++			memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
++			list_add(&entry->entry_node, &table->entry_list);
++			spin_unlock(&mdb->tbl_lock);
++			return 0;
++		}
++	}
++
++	table = kzalloc(sizeof(struct multicast_table), GFP_ATOMIC);
++	if (!table) {
++		spin_unlock(&mdb->tbl_lock);
++		return -ENOMEM;
++	}
++
++	INIT_LIST_HEAD(&table->entry_list);
++	entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
++	if (!entry) {
++		kfree(table);
++		spin_unlock(&mdb->tbl_lock);
++		return -ENOMEM;
++	}
++
++	memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
++	list_add(&entry->entry_node, &table->entry_list);
++
++	table->group_addr.u.ip4 = _group_addr;
++	list_add(&table->mdb_node, &mdb->list_head);
++
++	spin_unlock(&mdb->tbl_lock);
++	return 0;
++}
++
++static int ovs_ip4_multicast_leave_group(__be32 _group_addr,
++										const u8 *entry_addr,
++										struct vport *input_vport)
++{
++	struct multicast_data_base *mdb;
++	struct multicast_table *table, *table_tmp;
++	struct multicast_table_entry *entry, *entry_tmp;
++
++	if (ipv4_is_local_multicast(_group_addr))
++		return 0;
++
++	mdb = input_vport->mdb;
++	spin_lock(&mdb->tbl_lock);
++	list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
++		if (table->group_addr.u.ip4 == _group_addr) {
++			list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
++				if (!memcmp(entry->eth_addr, entry_addr, ETH_ALEN)) {
++					list_del(&entry->entry_node);
++					kfree(entry);
++
++					if (list_empty(&table->entry_list)) {
++						list_del(&table->mdb_node);
++						kfree(table);
++					}
++					spin_unlock(&mdb->tbl_lock);
++					return 0;
++				}
++			}
++		}
++	}
++	spin_unlock(&mdb->tbl_lock);
++	return 0;
++}
++
++static int ovs_multicast_ipv4_rcv(struct sk_buff *skb, struct vport *input_vport)
++{
++	struct ethhdr *eth_hdr;
++	const u8 *dl_src;
++	__be32 group_addr;
++	struct iphdr *ip_header;
++	struct igmphdr *igmp_hdr;
++	int i;
++	struct igmpv3_report *igmpv3_hdr;
++	u16 group_num;
++	struct igmpv3_grec *grec;
++	u8 group_type;
++	u8 aux_data_len;
++	u16 num_of_source;
++	int err;
++
++	err = ip_mc_check_igmp(skb);
++	if (err < 0)
++		return 0;
++
++	eth_hdr = skb_eth_hdr(skb);
++	dl_src = eth_hdr->h_source;
++	ip_header = (struct iphdr *)(skb->data + 14);
++	igmp_hdr = (struct igmphdr *)((u8 *)ip_header + ip_header->ihl * 4);
++
++	switch (igmp_hdr->type) {
++	case IGMP_HOST_MEMBERSHIP_REPORT:
++	case IGMPV2_HOST_MEMBERSHIP_REPORT:
++		group_addr = igmp_hdr->group;
++		ovs_ip4_multicast_add_group(group_addr, dl_src, input_vport);
++		break;
++	case IGMP_HOST_LEAVE_MESSAGE:
++		group_addr = igmp_hdr->group;
++		ovs_ip4_multicast_leave_group(group_addr, dl_src, input_vport);
++		break;
++	case IGMPV3_HOST_MEMBERSHIP_REPORT:
++		igmpv3_hdr = (struct igmpv3_report *)igmp_hdr;
++		group_num = ntohs(igmpv3_hdr->ngrec);
++		grec = igmpv3_hdr->grec;
++		//group_num = ntohs(*(u16 *)(igmp_hdr + 6));
++		//group = igmp_hdr + 8;
++		for (i = 0; i < group_num; i++) {
++			group_type = grec->grec_type;
++			aux_data_len = grec->grec_auxwords;
++			num_of_source = ntohs(grec->grec_nsrcs);
++			group_addr = grec->grec_mca;
++
++			if (group_type == IGMPV3_MODE_IS_EXCLUDE ||
++				group_type == IGMPV3_CHANGE_TO_EXCLUDE ||
++				group_type == IGMPV3_ALLOW_NEW_SOURCES)
++				ovs_ip4_multicast_add_group(group_addr, dl_src, input_vport);
++
++			if (group_type == IGMPV3_MODE_IS_INCLUDE ||
++				group_type == IGMPV3_CHANGE_TO_INCLUDE ||
++				group_type == IGMPV3_BLOCK_OLD_SOURCES)
++				if (num_of_source == 0)
++					ovs_ip4_multicast_leave_group(group_addr, dl_src, input_vport);
++
++			grec += (8 + (num_of_source * 4) + aux_data_len);
++		}
++		break;
++	default:
++		pr_warning("%s(): error pkt\n", __func__);
++		break;
++	}
++	return 0;
++}
++
+ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ {
+ 	struct ovs_header *ovs_header = info->userhdr;
+@@ -604,6 +765,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ 	OVS_CB(packet)->input_vport = input_vport;
+ 	sf_acts = rcu_dereference(flow->sf_acts);
+ 
++	if (is_igmp(packet))
++		ovs_multicast_ipv4_rcv(packet, input_vport);
++
+ 	local_bh_disable();
+ 	err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
+ 	local_bh_enable();
+@@ -2183,6 +2347,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
+ 	struct datapath *dp;
+ 	struct vport *vport;
+ 	unsigned int new_headroom;
++	struct multicast_data_base *mdb;
++	struct multicast_table *table, *table_tmp;
++	struct multicast_table_entry *entry, *entry_tmp;
+ 	int err;
+ 
+ 	reply = ovs_vport_cmd_alloc_info();
+@@ -2210,6 +2377,22 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
+ 	if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
+ 		update_headroom = true;
+ 
++	mdb = vport->mdb;
++	spin_lock(&mdb->tbl_lock);
++	list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
++		list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
++			list_del(&entry->entry_node);
++			kfree(entry);
++
++			if (list_empty(&table->entry_list)) {
++				list_del(&table->mdb_node);
++				kfree(table);
++			}
++		}
++	}
++	spin_unlock(&mdb->tbl_lock);
++	kfree(mdb);
++
+ 	netdev_reset_rx_headroom(vport->dev);
+ 	ovs_dp_detach_port(vport);
+ 
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 81e85dd..520532e 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -215,6 +215,31 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
+ 	return dp;
+ }
+ 
++#define IGMP_PROTOCOL_OFFSET		23
++/* support ipv4 for now */
++static inline bool is_ipv4_multicast(struct sk_buff *skb)
++{
++	struct ethhdr *eth_hdr = skb_eth_hdr(skb);
++
++	return eth_hdr->h_dest[0] == 0x01 && skb->protocol == htons(ETH_P_IP);
++}
++
++static inline bool is_igmp(struct sk_buff *skb)
++{
++	struct ethhdr *eth_hdr;
++
++	if (!skb)
++		return 0;
++
++	eth_hdr = skb_eth_hdr(skb);
++
++	if (eth_hdr->h_dest[0] == 0x01 &&
++		skb->protocol == htons(ETH_P_IP))
++		return (*(skb->data + IGMP_PROTOCOL_OFFSET) == IPPROTO_IGMP);
++	else
++		return 0;
++}
++
+ extern struct notifier_block ovs_dp_device_notifier;
+ extern struct genl_family dp_vport_genl_family;
+ 
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index 19af0ef..77bc923 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -141,6 +141,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
+ 		return ERR_PTR(-EINVAL);
+ 	}
+ 
++	vport->mdb = kzalloc(sizeof(struct multicast_data_base), GFP_KERNEL);
++	if (!vport->mdb) {
++		kfree(vport);
++		return ERR_PTR(-ENOMEM);
++	}
++	INIT_LIST_HEAD(&vport->mdb->list_head);
++	spin_lock_init(&vport->mdb->tbl_lock);
++
+ 	return vport;
+ }
+ EXPORT_SYMBOL_GPL(ovs_vport_alloc);
+diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
+index 1eb7495..eb69d6c 100644
+--- a/net/openvswitch/vport.h
++++ b/net/openvswitch/vport.h
+@@ -55,6 +55,30 @@ struct vport_portids {
+ 	u32 ids[];
+ };
+ 
++struct ip_addr {
++	union {
++		__be32 ip4;
++		struct in6_addr ip6;
++	} u;
++};
++
++struct multicast_table_entry {
++	struct list_head entry_node;
++	u8 eth_addr[ETH_ALEN];
++};
++
++struct multicast_table {
++	struct list_head mdb_node;
++	struct list_head entry_list;
++	struct ip_addr group_addr;
++};
++
++struct multicast_data_base {
++	struct list_head list_head;
++	spinlock_t tbl_lock;
++};
++
++
+ /**
+  * struct vport - one port within a datapath
+  * @dev: Pointer to net_device.
+@@ -79,6 +103,8 @@ struct vport {
+ 
+ 	struct list_head detach_list;
+ 	struct rcu_head rcu;
++
++	struct multicast_data_base *mdb;
+ };
+ 
+ /**
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 4c9012a..d63d381 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -108,7 +108,7 @@
     file://747-net-phy-aquantia-add-AQR113C.patch \
     file://748-add-netlink-support-for-dsa.patch \
     file://749-net-dsa-support-mt7988.patch \
-    file://750-add-mdio-bus-for-phy-node.patch \
+    file://750-add-mdio-bus-for-gphy-calibration.patch \
     file://8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch \
     file://8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
     file://8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
@@ -120,6 +120,7 @@
     file://8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch \
     file://8010-ovs-support-flow-offload.patch \
     file://8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch \
+    file://8011-ovs-add-multicast-to-unicast-support.patch \
     file://9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch \
     file://9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
     file://9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch \
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index 06ca553..aecbc7d 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -7,8 +7,8 @@
 
 KBRANCH ?= "linux-5.4.y"
 
-LINUX_VERSION ?= "5.4.215"
-SRCREV_machine ?= "6215647d9699cb8f1bf7333ec849242c4a9cf9a6"
+LINUX_VERSION ?= "5.4.219"
+SRCREV_machine ?= "fd92cfed8bc6668d314acd1e6da708a80826f768"
 KMETA = "kernel-meta"
 SRCREV_meta ?= "feeb59687bc0f054af837a5061f8d413ec7c93e9"