mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 15:02:32 +00:00
210c534ce2
This commit moves the patches for the r8152.c driver to the generic directory. Previously they were only available on the bcm27xx target. With these patches the Realtek RTL8153C, RTL8153D, RTL8156A and RTL8156B chips are supported on all targets by the kmod-usb-net-rtl8152 module. The RTL8156A and RTL8156B are the 2.5Gb/s Ethernet adapters. The patches have been tested on TP-Link UE300 (RTL8153A) and UNITEK 1313B (RTL8156B). Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
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
|
|
@@ -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;
|