kernel: move rtl8152 patches to generic
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 794-v5.13-r8152-support-PHY-firmware-for-RTL8156-series.patch
diff --git a/target/linux/generic/backport-5.10/794-v5.13-r8152-support-PHY-firmware-for-RTL8156-series.patch b/target/linux/generic/backport-5.10/794-v5.13-r8152-support-PHY-firmware-for-RTL8156-series.patch
new file mode 100644 (file)
index 0000000..943c821
--- /dev/null
@@ -0,0 +1,691 @@
+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
+@@ -975,8 +975,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:
+@@ -1081,6 +1133,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 {
+@@ -4000,6 +4061,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;
+@@ -4320,6 +4537,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");
+@@ -4368,7 +4589,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",
+@@ -4391,6 +4758,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;
+@@ -4444,6 +4948,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
+@@ -4479,7 +4989,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);
+@@ -4494,7 +5003,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;
+@@ -4516,17 +5025,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;
+               }
+@@ -5034,6 +5566,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;
+@@ -8674,12 +9221,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)
+ {
+@@ -8705,6 +9256,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;