mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	Manually rebased: bcm53xx/patches-5.10/180-usb-xhci-add-support-for-performing-fake-doorbell.patch All patches automatically rebased. Signed-off-by: John Audia <therealgraysky@proton.me> [Move gro_skip in 680-NET-skip-GRO-for-foreign-MAC-addresses.patch to old position] Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
		
			
				
	
	
		
			692 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			692 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From ca09589a72a0aa17389754fb75a5cd1a5d46818f Mon Sep 17 00:00:00 2001
 | 
						|
From: Hayes Wang <hayeswang@realtek.com>
 | 
						|
Date: Fri, 16 Apr 2021 16:04:36 +0800
 | 
						|
Subject: [PATCH] r8152: support PHY firmware for RTL8156 series
 | 
						|
 | 
						|
commit 4a51b0e8a0143b0e83d51d9c58c6416c3818a9f2 upstream.
 | 
						|
 | 
						|
Support new firmware type and method for RTL8156 series.
 | 
						|
 | 
						|
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 drivers/net/usb/r8152.c | 563 +++++++++++++++++++++++++++++++++++++++-
 | 
						|
 1 file changed, 561 insertions(+), 2 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/usb/r8152.c
 | 
						|
+++ b/drivers/net/usb/r8152.c
 | 
						|
@@ -974,8 +974,60 @@ enum rtl8152_fw_flags {
 | 
						|
 	FW_FLAGS_START,
 | 
						|
 	FW_FLAGS_STOP,
 | 
						|
 	FW_FLAGS_NC,
 | 
						|
+	FW_FLAGS_NC1,
 | 
						|
+	FW_FLAGS_NC2,
 | 
						|
+	FW_FLAGS_UC2,
 | 
						|
+	FW_FLAGS_UC,
 | 
						|
+	FW_FLAGS_SPEED_UP,
 | 
						|
+	FW_FLAGS_VER,
 | 
						|
 };
 | 
						|
 
 | 
						|
+enum rtl8152_fw_fixup_cmd {
 | 
						|
+	FW_FIXUP_AND = 0,
 | 
						|
+	FW_FIXUP_OR,
 | 
						|
+	FW_FIXUP_NOT,
 | 
						|
+	FW_FIXUP_XOR,
 | 
						|
+};
 | 
						|
+
 | 
						|
+struct fw_phy_set {
 | 
						|
+	__le16 addr;
 | 
						|
+	__le16 data;
 | 
						|
+} __packed;
 | 
						|
+
 | 
						|
+struct fw_phy_speed_up {
 | 
						|
+	struct fw_block blk_hdr;
 | 
						|
+	__le16 fw_offset;
 | 
						|
+	__le16 version;
 | 
						|
+	__le16 fw_reg;
 | 
						|
+	__le16 reserved;
 | 
						|
+	char info[];
 | 
						|
+} __packed;
 | 
						|
+
 | 
						|
+struct fw_phy_ver {
 | 
						|
+	struct fw_block blk_hdr;
 | 
						|
+	struct fw_phy_set ver;
 | 
						|
+	__le32 reserved;
 | 
						|
+} __packed;
 | 
						|
+
 | 
						|
+struct fw_phy_fixup {
 | 
						|
+	struct fw_block blk_hdr;
 | 
						|
+	struct fw_phy_set setting;
 | 
						|
+	__le16 bit_cmd;
 | 
						|
+	__le16 reserved;
 | 
						|
+} __packed;
 | 
						|
+
 | 
						|
+struct fw_phy_union {
 | 
						|
+	struct fw_block blk_hdr;
 | 
						|
+	__le16 fw_offset;
 | 
						|
+	__le16 fw_reg;
 | 
						|
+	struct fw_phy_set pre_set[2];
 | 
						|
+	struct fw_phy_set bp[8];
 | 
						|
+	struct fw_phy_set bp_en;
 | 
						|
+	u8 pre_num;
 | 
						|
+	u8 bp_num;
 | 
						|
+	char info[];
 | 
						|
+} __packed;
 | 
						|
+
 | 
						|
 /**
 | 
						|
  * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB.
 | 
						|
  *	The layout of the firmware block is:
 | 
						|
@@ -1080,6 +1132,15 @@ enum rtl_fw_type {
 | 
						|
 	RTL_FW_PHY_START,
 | 
						|
 	RTL_FW_PHY_STOP,
 | 
						|
 	RTL_FW_PHY_NC,
 | 
						|
+	RTL_FW_PHY_FIXUP,
 | 
						|
+	RTL_FW_PHY_UNION_NC,
 | 
						|
+	RTL_FW_PHY_UNION_NC1,
 | 
						|
+	RTL_FW_PHY_UNION_NC2,
 | 
						|
+	RTL_FW_PHY_UNION_UC2,
 | 
						|
+	RTL_FW_PHY_UNION_UC,
 | 
						|
+	RTL_FW_PHY_UNION_MISC,
 | 
						|
+	RTL_FW_PHY_SPEED_UP,
 | 
						|
+	RTL_FW_PHY_VER,
 | 
						|
 };
 | 
						|
 
 | 
						|
 enum rtl_version {
 | 
						|
@@ -4001,6 +4062,162 @@ static int rtl_post_ram_code(struct r815
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static bool rtl8152_is_fw_phy_speed_up_ok(struct r8152 *tp, struct fw_phy_speed_up *phy)
 | 
						|
+{
 | 
						|
+	u16 fw_offset;
 | 
						|
+	u32 length;
 | 
						|
+	bool rc = false;
 | 
						|
+
 | 
						|
+	switch (tp->version) {
 | 
						|
+	case RTL_VER_01:
 | 
						|
+	case RTL_VER_02:
 | 
						|
+	case RTL_VER_03:
 | 
						|
+	case RTL_VER_04:
 | 
						|
+	case RTL_VER_05:
 | 
						|
+	case RTL_VER_06:
 | 
						|
+	case RTL_VER_07:
 | 
						|
+	case RTL_VER_08:
 | 
						|
+	case RTL_VER_09:
 | 
						|
+	case RTL_VER_10:
 | 
						|
+	case RTL_VER_11:
 | 
						|
+	case RTL_VER_12:
 | 
						|
+	case RTL_VER_14:
 | 
						|
+		goto out;
 | 
						|
+	case RTL_VER_13:
 | 
						|
+	case RTL_VER_15:
 | 
						|
+	default:
 | 
						|
+		break;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	fw_offset = __le16_to_cpu(phy->fw_offset);
 | 
						|
+	length = __le32_to_cpu(phy->blk_hdr.length);
 | 
						|
+	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid fw_offset\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	length -= fw_offset;
 | 
						|
+	if (length & 3) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid block length\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (__le16_to_cpu(phy->fw_reg) != 0x9A00) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid register to load firmware\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	rc = true;
 | 
						|
+out:
 | 
						|
+	return rc;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool rtl8152_is_fw_phy_ver_ok(struct r8152 *tp, struct fw_phy_ver *ver)
 | 
						|
+{
 | 
						|
+	bool rc = false;
 | 
						|
+
 | 
						|
+	switch (tp->version) {
 | 
						|
+	case RTL_VER_10:
 | 
						|
+	case RTL_VER_11:
 | 
						|
+	case RTL_VER_12:
 | 
						|
+	case RTL_VER_13:
 | 
						|
+	case RTL_VER_15:
 | 
						|
+		break;
 | 
						|
+	default:
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (__le32_to_cpu(ver->blk_hdr.length) != sizeof(*ver)) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid block length\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (__le16_to_cpu(ver->ver.addr) != SRAM_GPHY_FW_VER) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid phy ver addr\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	rc = true;
 | 
						|
+out:
 | 
						|
+	return rc;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool rtl8152_is_fw_phy_fixup_ok(struct r8152 *tp, struct fw_phy_fixup *fix)
 | 
						|
+{
 | 
						|
+	bool rc = false;
 | 
						|
+
 | 
						|
+	switch (tp->version) {
 | 
						|
+	case RTL_VER_10:
 | 
						|
+	case RTL_VER_11:
 | 
						|
+	case RTL_VER_12:
 | 
						|
+	case RTL_VER_13:
 | 
						|
+	case RTL_VER_15:
 | 
						|
+		break;
 | 
						|
+	default:
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (__le32_to_cpu(fix->blk_hdr.length) != sizeof(*fix)) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid block length\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (__le16_to_cpu(fix->setting.addr) != OCP_PHY_PATCH_CMD ||
 | 
						|
+	    __le16_to_cpu(fix->setting.data) != BIT(7)) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid phy fixup\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	rc = true;
 | 
						|
+out:
 | 
						|
+	return rc;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool rtl8152_is_fw_phy_union_ok(struct r8152 *tp, struct fw_phy_union *phy)
 | 
						|
+{
 | 
						|
+	u16 fw_offset;
 | 
						|
+	u32 length;
 | 
						|
+	bool rc = false;
 | 
						|
+
 | 
						|
+	switch (tp->version) {
 | 
						|
+	case RTL_VER_10:
 | 
						|
+	case RTL_VER_11:
 | 
						|
+	case RTL_VER_12:
 | 
						|
+	case RTL_VER_13:
 | 
						|
+	case RTL_VER_15:
 | 
						|
+		break;
 | 
						|
+	default:
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	fw_offset = __le16_to_cpu(phy->fw_offset);
 | 
						|
+	length = __le32_to_cpu(phy->blk_hdr.length);
 | 
						|
+	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid fw_offset\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	length -= fw_offset;
 | 
						|
+	if (length & 1) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid block length\n");
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (phy->pre_num > 2) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid pre_num %d\n", phy->pre_num);
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (phy->bp_num > 8) {
 | 
						|
+		dev_err(&tp->intf->dev, "invalid bp_num %d\n", phy->bp_num);
 | 
						|
+		goto out;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	rc = true;
 | 
						|
+out:
 | 
						|
+	return rc;
 | 
						|
+}
 | 
						|
+
 | 
						|
 static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy)
 | 
						|
 {
 | 
						|
 	u32 length;
 | 
						|
@@ -4321,6 +4538,10 @@ static long rtl8152_check_firmware(struc
 | 
						|
 		case RTL_FW_PHY_START:
 | 
						|
 			if (test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
 			    test_bit(FW_FLAGS_NC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
 			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
 				dev_err(&tp->intf->dev,
 | 
						|
 					"check PHY_START fail\n");
 | 
						|
@@ -4369,7 +4590,153 @@ static long rtl8152_check_firmware(struc
 | 
						|
 				goto fail;
 | 
						|
 			}
 | 
						|
 			__set_bit(FW_FLAGS_NC, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_NC:
 | 
						|
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "PHY_UNION_NC out of order\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_NC, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY_UNION_NC encountered\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
 
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_NC, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_NC1:
 | 
						|
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "PHY_UNION_NC1 out of order\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_NC1, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY NC1 encountered\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC1 failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_NC1, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_NC2:
 | 
						|
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "PHY_UNION_NC2 out of order\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_NC2, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY NC2 encountered\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC2 failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_NC2, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_UC2:
 | 
						|
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "PHY_UNION_UC2 out of order\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_UC2, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY UC2 encountered\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY_UNION_UC2 failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_UC2, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_UC:
 | 
						|
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "PHY_UNION_UC out of order\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_UC, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY UC encountered\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY_UNION_UC failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_UC, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_MISC:
 | 
						|
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check RTL_FW_PHY_UNION_MISC failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_FIXUP:
 | 
						|
+			if (!rtl8152_is_fw_phy_fixup_ok(tp, (struct fw_phy_fixup *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY fixup failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_SPEED_UP:
 | 
						|
+			if (test_bit(FW_FLAGS_SPEED_UP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY firmware encountered");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_speed_up_ok(tp, (struct fw_phy_speed_up *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY speed up failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_SPEED_UP, &fw_flags);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_VER:
 | 
						|
+			if (test_bit(FW_FLAGS_START, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
 | 
						|
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "Invalid order to set PHY version\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (test_bit(FW_FLAGS_VER, &fw_flags)) {
 | 
						|
+				dev_err(&tp->intf->dev, "multiple PHY version encountered");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+
 | 
						|
+			if (!rtl8152_is_fw_phy_ver_ok(tp, (struct fw_phy_ver *)block)) {
 | 
						|
+				dev_err(&tp->intf->dev, "check PHY version failed\n");
 | 
						|
+				goto fail;
 | 
						|
+			}
 | 
						|
+			__set_bit(FW_FLAGS_VER, &fw_flags);
 | 
						|
 			break;
 | 
						|
 		default:
 | 
						|
 			dev_warn(&tp->intf->dev, "Unknown type %u is found\n",
 | 
						|
@@ -4392,6 +4759,143 @@ fail:
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy, bool wait)
 | 
						|
+{
 | 
						|
+	u32 len;
 | 
						|
+	u8 *data;
 | 
						|
+
 | 
						|
+	if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
 | 
						|
+		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
 | 
						|
+		return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	len = __le32_to_cpu(phy->blk_hdr.length);
 | 
						|
+	len -= __le16_to_cpu(phy->fw_offset);
 | 
						|
+	data = (u8 *)phy + __le16_to_cpu(phy->fw_offset);
 | 
						|
+
 | 
						|
+	if (rtl_phy_patch_request(tp, true, wait))
 | 
						|
+		return;
 | 
						|
+
 | 
						|
+	while (len) {
 | 
						|
+		u32 ocp_data, size;
 | 
						|
+		int i;
 | 
						|
+
 | 
						|
+		if (len < 2048)
 | 
						|
+			size = len;
 | 
						|
+		else
 | 
						|
+			size = 2048;
 | 
						|
+
 | 
						|
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL);
 | 
						|
+		ocp_data |= GPHY_PATCH_DONE | BACKUP_RESTRORE;
 | 
						|
+		ocp_write_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL, ocp_data);
 | 
						|
+
 | 
						|
+		generic_ocp_write(tp, __le16_to_cpu(phy->fw_reg), 0xff, size, data, MCU_TYPE_USB);
 | 
						|
+
 | 
						|
+		data += size;
 | 
						|
+		len -= size;
 | 
						|
+
 | 
						|
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL);
 | 
						|
+		ocp_data |= POL_GPHY_PATCH;
 | 
						|
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL, ocp_data);
 | 
						|
+
 | 
						|
+		for (i = 0; i < 1000; i++) {
 | 
						|
+			if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & POL_GPHY_PATCH))
 | 
						|
+				break;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		if (i == 1000) {
 | 
						|
+			dev_err(&tp->intf->dev, "ram code speedup mode timeout\n");
 | 
						|
+			return;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
 | 
						|
+	rtl_phy_patch_request(tp, false, wait);
 | 
						|
+
 | 
						|
+	if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
 | 
						|
+		dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
 | 
						|
+	else
 | 
						|
+		dev_err(&tp->intf->dev, "ram code speedup mode fail\n");
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int rtl8152_fw_phy_ver(struct r8152 *tp, struct fw_phy_ver *phy_ver)
 | 
						|
+{
 | 
						|
+	u16 ver_addr, ver;
 | 
						|
+
 | 
						|
+	ver_addr = __le16_to_cpu(phy_ver->ver.addr);
 | 
						|
+	ver = __le16_to_cpu(phy_ver->ver.data);
 | 
						|
+
 | 
						|
+	if (sram_read(tp, ver_addr) >= ver) {
 | 
						|
+		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
 | 
						|
+		return 0;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	sram_write(tp, ver_addr, ver);
 | 
						|
+
 | 
						|
+	dev_dbg(&tp->intf->dev, "PHY firmware version %x\n", ver);
 | 
						|
+
 | 
						|
+	return ver;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void rtl8152_fw_phy_fixup(struct r8152 *tp, struct fw_phy_fixup *fix)
 | 
						|
+{
 | 
						|
+	u16 addr, data;
 | 
						|
+
 | 
						|
+	addr = __le16_to_cpu(fix->setting.addr);
 | 
						|
+	data = ocp_reg_read(tp, addr);
 | 
						|
+
 | 
						|
+	switch (__le16_to_cpu(fix->bit_cmd)) {
 | 
						|
+	case FW_FIXUP_AND:
 | 
						|
+		data &= __le16_to_cpu(fix->setting.data);
 | 
						|
+		break;
 | 
						|
+	case FW_FIXUP_OR:
 | 
						|
+		data |= __le16_to_cpu(fix->setting.data);
 | 
						|
+		break;
 | 
						|
+	case FW_FIXUP_NOT:
 | 
						|
+		data &= ~__le16_to_cpu(fix->setting.data);
 | 
						|
+		break;
 | 
						|
+	case FW_FIXUP_XOR:
 | 
						|
+		data ^= __le16_to_cpu(fix->setting.data);
 | 
						|
+		break;
 | 
						|
+	default:
 | 
						|
+		return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	ocp_reg_write(tp, addr, data);
 | 
						|
+
 | 
						|
+	dev_dbg(&tp->intf->dev, "applied ocp %x %x\n", addr, data);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void rtl8152_fw_phy_union_apply(struct r8152 *tp, struct fw_phy_union *phy)
 | 
						|
+{
 | 
						|
+	__le16 *data;
 | 
						|
+	u32 length;
 | 
						|
+	int i, num;
 | 
						|
+
 | 
						|
+	num = phy->pre_num;
 | 
						|
+	for (i = 0; i < num; i++)
 | 
						|
+		sram_write(tp, __le16_to_cpu(phy->pre_set[i].addr),
 | 
						|
+			   __le16_to_cpu(phy->pre_set[i].data));
 | 
						|
+
 | 
						|
+	length = __le32_to_cpu(phy->blk_hdr.length);
 | 
						|
+	length -= __le16_to_cpu(phy->fw_offset);
 | 
						|
+	num = length / 2;
 | 
						|
+	data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset));
 | 
						|
+
 | 
						|
+	ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg));
 | 
						|
+	for (i = 0; i < num; i++)
 | 
						|
+		ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i]));
 | 
						|
+
 | 
						|
+	num = phy->bp_num;
 | 
						|
+	for (i = 0; i < num; i++)
 | 
						|
+		sram_write(tp, __le16_to_cpu(phy->bp[i].addr), __le16_to_cpu(phy->bp[i].data));
 | 
						|
+
 | 
						|
+	if (phy->bp_num && phy->bp_en.addr)
 | 
						|
+		sram_write(tp, __le16_to_cpu(phy->bp_en.addr), __le16_to_cpu(phy->bp_en.data));
 | 
						|
+
 | 
						|
+	dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
 | 
						|
+}
 | 
						|
+
 | 
						|
 static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy)
 | 
						|
 {
 | 
						|
 	u16 mode_reg, bp_index;
 | 
						|
@@ -4445,6 +4949,12 @@ static void rtl8152_fw_mac_apply(struct
 | 
						|
 		return;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg);
 | 
						|
+	if (fw_ver_reg && ocp_read_byte(tp, MCU_TYPE_USB, fw_ver_reg) >= mac->fw_ver_data) {
 | 
						|
+		dev_dbg(&tp->intf->dev, "%s firmware has been the newest\n", type ? "PLA" : "USB");
 | 
						|
+		return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	rtl_clear_bp(tp, type);
 | 
						|
 
 | 
						|
 	/* Enable backup/restore of MACDBG. This is required after clearing PLA
 | 
						|
@@ -4480,7 +4990,6 @@ static void rtl8152_fw_mac_apply(struct
 | 
						|
 		ocp_write_word(tp, type, bp_en_addr,
 | 
						|
 			       __le16_to_cpu(mac->bp_en_value));
 | 
						|
 
 | 
						|
-	fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg);
 | 
						|
 	if (fw_ver_reg)
 | 
						|
 		ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg,
 | 
						|
 			       mac->fw_ver_data);
 | 
						|
@@ -4495,7 +5004,7 @@ static void rtl8152_apply_firmware(struc
 | 
						|
 	struct fw_header *fw_hdr;
 | 
						|
 	struct fw_phy_patch_key *key;
 | 
						|
 	u16 key_addr = 0;
 | 
						|
-	int i;
 | 
						|
+	int i, patch_phy = 1;
 | 
						|
 
 | 
						|
 	if (IS_ERR_OR_NULL(rtl_fw->fw))
 | 
						|
 		return;
 | 
						|
@@ -4517,17 +5026,40 @@ static void rtl8152_apply_firmware(struc
 | 
						|
 			rtl8152_fw_mac_apply(tp, (struct fw_mac *)block);
 | 
						|
 			break;
 | 
						|
 		case RTL_FW_PHY_START:
 | 
						|
+			if (!patch_phy)
 | 
						|
+				break;
 | 
						|
 			key = (struct fw_phy_patch_key *)block;
 | 
						|
 			key_addr = __le16_to_cpu(key->key_reg);
 | 
						|
 			rtl_pre_ram_code(tp, key_addr, __le16_to_cpu(key->key_data), !power_cut);
 | 
						|
 			break;
 | 
						|
 		case RTL_FW_PHY_STOP:
 | 
						|
+			if (!patch_phy)
 | 
						|
+				break;
 | 
						|
 			WARN_ON(!key_addr);
 | 
						|
 			rtl_post_ram_code(tp, key_addr, !power_cut);
 | 
						|
 			break;
 | 
						|
 		case RTL_FW_PHY_NC:
 | 
						|
 			rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block);
 | 
						|
 			break;
 | 
						|
+		case RTL_FW_PHY_VER:
 | 
						|
+			patch_phy = rtl8152_fw_phy_ver(tp, (struct fw_phy_ver *)block);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_UNION_NC:
 | 
						|
+		case RTL_FW_PHY_UNION_NC1:
 | 
						|
+		case RTL_FW_PHY_UNION_NC2:
 | 
						|
+		case RTL_FW_PHY_UNION_UC2:
 | 
						|
+		case RTL_FW_PHY_UNION_UC:
 | 
						|
+		case RTL_FW_PHY_UNION_MISC:
 | 
						|
+			if (patch_phy)
 | 
						|
+				rtl8152_fw_phy_union_apply(tp, (struct fw_phy_union *)block);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_FIXUP:
 | 
						|
+			if (patch_phy)
 | 
						|
+				rtl8152_fw_phy_fixup(tp, (struct fw_phy_fixup *)block);
 | 
						|
+			break;
 | 
						|
+		case RTL_FW_PHY_SPEED_UP:
 | 
						|
+			rtl_ram_code_speed_up(tp, (struct fw_phy_speed_up *)block, !power_cut);
 | 
						|
+			break;
 | 
						|
 		default:
 | 
						|
 			break;
 | 
						|
 		}
 | 
						|
@@ -5035,6 +5567,21 @@ static int r8153c_post_firmware_1(struct
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static int r8156a_post_firmware_1(struct r8152 *tp)
 | 
						|
+{
 | 
						|
+	u32 ocp_data;
 | 
						|
+
 | 
						|
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
 | 
						|
+	ocp_data |= FW_IP_RESET_EN;
 | 
						|
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
 | 
						|
+
 | 
						|
+	/* Modify U3PHY parameter for compatibility issue */
 | 
						|
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4026840e);
 | 
						|
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4001acc9);
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
 static void r8153_aldps_en(struct r8152 *tp, bool enable)
 | 
						|
 {
 | 
						|
 	u16 data;
 | 
						|
@@ -8653,12 +9200,16 @@ static int rtl_ops_init(struct r8152 *tp
 | 
						|
 #define FIRMWARE_8153A_4	"rtl_nic/rtl8153a-4.fw"
 | 
						|
 #define FIRMWARE_8153B_2	"rtl_nic/rtl8153b-2.fw"
 | 
						|
 #define FIRMWARE_8153C_1	"rtl_nic/rtl8153c-1.fw"
 | 
						|
+#define FIRMWARE_8156A_2	"rtl_nic/rtl8156a-2.fw"
 | 
						|
+#define FIRMWARE_8156B_2	"rtl_nic/rtl8156b-2.fw"
 | 
						|
 
 | 
						|
 MODULE_FIRMWARE(FIRMWARE_8153A_2);
 | 
						|
 MODULE_FIRMWARE(FIRMWARE_8153A_3);
 | 
						|
 MODULE_FIRMWARE(FIRMWARE_8153A_4);
 | 
						|
 MODULE_FIRMWARE(FIRMWARE_8153B_2);
 | 
						|
 MODULE_FIRMWARE(FIRMWARE_8153C_1);
 | 
						|
+MODULE_FIRMWARE(FIRMWARE_8156A_2);
 | 
						|
+MODULE_FIRMWARE(FIRMWARE_8156B_2);
 | 
						|
 
 | 
						|
 static int rtl_fw_init(struct r8152 *tp)
 | 
						|
 {
 | 
						|
@@ -8684,6 +9235,14 @@ static int rtl_fw_init(struct r8152 *tp)
 | 
						|
 		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
 | 
						|
 		rtl_fw->post_fw		= r8153b_post_firmware_1;
 | 
						|
 		break;
 | 
						|
+	case RTL_VER_11:
 | 
						|
+		rtl_fw->fw_name		= FIRMWARE_8156A_2;
 | 
						|
+		rtl_fw->post_fw		= r8156a_post_firmware_1;
 | 
						|
+		break;
 | 
						|
+	case RTL_VER_13:
 | 
						|
+	case RTL_VER_15:
 | 
						|
+		rtl_fw->fw_name		= FIRMWARE_8156B_2;
 | 
						|
+		break;
 | 
						|
 	case RTL_VER_14:
 | 
						|
 		rtl_fw->fw_name		= FIRMWARE_8153C_1;
 | 
						|
 		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
 |