diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index bd1ca33..c690c2b2 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -21,6 +21,14 @@
 #include "ksz_common.h"
 #include "ksz9477_reg.h"
 
+/* features flags */
+#define GBIT_SUPPORT			BIT(0)
+#define NEW_XMII			BIT(1)
+#define IS_9893				BIT(2)
+
+/* overrides flags */
+#define PTP_TAG				BIT(0)
+
 static const struct {
 	int index;
 	char string[ETH_GSTRING_LEN];
@@ -1356,9 +1364,77 @@ static void ksz9477_switch_exit(struct ksz_device *dev)
 	.exit = ksz9477_switch_exit,
 };
 
+/* For Ingress (Host -> KSZ), 2 bytes are added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0 : Prioritization (not used now)
+ * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5)
+ *
+ * For switch with 3 ports only one byte is needed.
+ * When PTP function is enabled additional 4 bytes are needed.
+ *
+ * For Egress (KSZ -> Host), 1 byte is added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0 : zero-based value represents port
+ *	  (eg, 0x00=port1, 0x02=port3, 0x06=port7)
+ *
+ * When PTP function is enabled BIT 7 indicates the received frame is a PTP
+ * message and so there are 4 additional bytes for the receive timestamp.
+ */
+
+static int ksz9477_get_len(struct ksz_device *dev)
+{
+	int len = 1;
+
+	if (!(dev->features & IS_9893))
+		len += 1;
+	if (dev->overrides & PTP_TAG)
+		len += 4;
+	return len;
+}
+
+static int ksz9477_get_tag(struct ksz_device *dev, u8 *tag, int *port)
+{
+	int len = 1;
+
+	if (tag[0] & BIT(7))
+		len += 4;
+	*port = tag[0] & 7;
+	return len;
+}
+
+static void ksz9477_set_tag(struct ksz_device *dev, void *ptr, u8 *addr, int p)
+{
+	if (dev->overrides & PTP_TAG) {
+		u32 *timestamp = (u32 *)ptr;
+
+		*timestamp = 0;
+		ptr = timestamp + 1;
+	}
+	if (dev->features & IS_9893) {
+		u8 *tag = (u8 *)ptr;
+
+		*tag = 1 << p;
+	} else {
+		u16 *tag = (u16 *)ptr;
+
+		*tag = 1 << p;
+		*tag = cpu_to_be16(*tag);
+	}
+}
+
+static const struct ksz_tag_ops ksz9477_tag_ops = {
+	.get_len = ksz9477_get_len,
+	.get_tag = ksz9477_get_tag,
+	.set_tag = ksz9477_set_tag,
+};
+
 int ksz9477_switch_register(struct ksz_device *dev)
 {
-	return ksz_switch_register(dev, &ksz9477_dev_ops);
+	return ksz_switch_register(dev, &ksz9477_dev_ops, &ksz9477_tag_ops);
 }
 EXPORT_SYMBOL(ksz9477_switch_register);
 
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 7b8f57b..a72659b 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -399,7 +399,8 @@ struct ksz_device *ksz_switch_alloc(struct device *base,
 EXPORT_SYMBOL(ksz_switch_alloc);
 
 int ksz_switch_register(struct ksz_device *dev,
-			const struct ksz_dev_ops *ops)
+			const struct ksz_dev_ops *ops,
+			const struct ksz_tag_ops *tag_ops)
 {
 	int ret;
 
@@ -412,6 +413,7 @@ int ksz_switch_register(struct ksz_device *dev,
 	mutex_init(&dev->vlan_mutex);
 
 	dev->dev_ops = ops;
+	dev->tag_ops = tag_ops;
 
 	if (dev->dev_ops->detect(dev))
 		return -EINVAL;
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index 5d93822..d020c1e 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -78,7 +78,8 @@ struct ksz_dev_ops {
 struct ksz_device *ksz_switch_alloc(struct device *base,
 				    const struct ksz_io_ops *ops, void *priv);
 int ksz_switch_register(struct ksz_device *dev,
-			const struct ksz_dev_ops *ops);
+			const struct ksz_dev_ops *ops,
+			const struct ksz_tag_ops *tag_ops);
 void ksz_switch_remove(struct ksz_device *dev);
 
 int ksz9477_switch_register(struct ksz_device *dev);
diff --git a/include/linux/dsa/ksz_dsa.h b/include/linux/dsa/ksz_dsa.h
index 3148cae..3fb2713 100644
--- a/include/linux/dsa/ksz_dsa.h
+++ b/include/linux/dsa/ksz_dsa.h
@@ -7,6 +7,14 @@
 
 #include <linux/phy.h>
 
+struct ksz_device;
+
+struct ksz_tag_ops {
+	int (*get_len)(struct ksz_device *dev);
+	int (*get_tag)(struct ksz_device *dev, u8 *tag, int *port);
+	void (*set_tag)(struct ksz_device *dev, void *ptr, u8 *addr, int p);
+};
+
 struct vlan_table {
 	u32 table[3];
 };
@@ -45,6 +53,7 @@ struct ksz_device {
 	struct mutex vlan_mutex;	/* vlan access */
 	const struct ksz_io_ops *ops;
 	const struct ksz_dev_ops *dev_ops;
+	const struct ksz_tag_ops *tag_ops;
 
 	struct device *dev;
 
