Loading drivers/net/usb/r8152.c +357 −71 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ #define OCP_PHY_PATCH_STAT 0xb800 #define OCP_PHY_PATCH_CMD 0xb820 #define OCP_PHY_LOCK 0xb82e #define OCP_ADC_IOFFSET 0xbcfc #define OCP_ADC_CFG 0xbc06 #define OCP_SYSCLK_CFG 0xc416 Loading @@ -197,6 +198,7 @@ #define SRAM_10M_AMP1 0x8080 #define SRAM_10M_AMP2 0x8082 #define SRAM_IMPEDANCE 0x8084 #define SRAM_PHY_LOCK 0xb82e /* PLA_RCR */ #define RCR_AAP 0x00000001 Loading Loading @@ -577,6 +579,9 @@ enum spd_duplex { /* OCP_PHY_PATCH_CMD */ #define PATCH_REQUEST BIT(4) /* OCP_PHY_LOCK */ #define PATCH_LOCK BIT(0) /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 Loading @@ -601,6 +606,9 @@ enum spd_duplex { /* SRAM_IMPEDANCE */ #define RX_DRIVING_MASK 0x6000 /* SRAM_PHY_LOCK */ #define PHY_PATCH_LOCK 0x0001 /* MAC PASSTHRU */ #define AD_MASK 0xfee0 #define BND_MASK 0x0004 Loading Loading @@ -867,11 +875,11 @@ struct fw_header { } __packed; /** * struct fw_type_1 - a firmware block used by RTL_FW_PLA and RTL_FW_USB. * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB. * The layout of the firmware block is: * <struct fw_type_1> + <info> + <firmware data>. * <struct fw_mac> + <info> + <firmware data>. * @fw_offset: offset of the firmware binary data. The start address of * the data would be the address of struct fw_type_1 + @fw_offset. * the data would be the address of struct fw_mac + @fw_offset. * @fw_reg: the register to load the firmware. Depends on chip. * @bp_ba_addr: the register to write break point base address. Depends on * chip. Loading @@ -888,7 +896,7 @@ struct fw_header { * @info: additional information for debugging, and is followed by the * binary data of firmware. */ struct fw_type_1 { struct fw_mac { struct fw_block blk_hdr; __le16 fw_offset; __le16 fw_reg; Loading @@ -905,10 +913,65 @@ struct fw_type_1 { char info[0]; } __packed; /** * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START. * This is used to set patch key when loading the firmware of PHY. * @key_reg: the register to write the patch key. * @key_data: patch key. */ struct fw_phy_patch_key { struct fw_block blk_hdr; __le16 key_reg; __le16 key_data; __le32 reserved; } __packed; /** * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC. * The layout of the firmware block is: * <struct fw_phy_nc> + <info> + <firmware data>. * @fw_offset: offset of the firmware binary data. The start address of * the data would be the address of struct fw_phy_nc + @fw_offset. * @fw_reg: the register to load the firmware. Depends on chip. * @ba_reg: the register to write the base address. Depends on chip. * @ba_data: base address. Depends on chip. * @patch_en_addr: the register of enabling patch mode. Depends on chip. * @patch_en_value: patch mode enabled mask. Depends on the firmware. * @mode_reg: the regitster of switching the mode. * @mod_pre: the mode needing to be set before loading the firmware. * @mod_post: the mode to be set when finishing to load the firmware. * @bp_start: the start register of break points. Depends on chip. * @bp_num: the break point number which needs to be set for this firmware. * Depends on the firmware. * @bp: break points. Depends on firmware. * @info: additional information for debugging, and is followed by the * binary data of firmware. */ struct fw_phy_nc { struct fw_block blk_hdr; __le16 fw_offset; __le16 fw_reg; __le16 ba_reg; __le16 ba_data; __le16 patch_en_addr; __le16 patch_en_value; __le16 mode_reg; __le16 mode_pre; __le16 mode_post; __le16 reserved; __le16 bp_start; __le16 bp_num; __le16 bp[4]; char info[0]; } __packed; enum rtl_fw_type { RTL_FW_END = 0, RTL_FW_PLA, RTL_FW_USB, RTL_FW_PHY_START, RTL_FW_PHY_STOP, RTL_FW_PHY_NC, }; enum rtl_version { Loading Loading @@ -3397,14 +3460,149 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) ocp_write_word(tp, type, PLA_BP_BA, 0); } static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) static int r8153_patch_request(struct r8152 *tp, bool request) { u16 data; int i; data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); if (request) data |= PATCH_REQUEST; else data &= ~PATCH_REQUEST; ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); for (i = 0; request && i < 5000; i++) { usleep_range(1000, 2000); if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) break; } if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { netif_err(tp, drv, tp->netdev, "patch request fail\n"); r8153_patch_request(tp, false); return -ETIME; } else { return 0; } } static int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key) { if (r8153_patch_request(tp, true)) { dev_err(&tp->intf->dev, "patch request fail\n"); return -ETIME; } sram_write(tp, key_addr, patch_key); sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK); return 0; } static int r8153_post_ram_code(struct r8152 *tp, u16 key_addr) { u16 data; sram_write(tp, 0x0000, 0x0000); data = ocp_reg_read(tp, OCP_PHY_LOCK); data &= ~PATCH_LOCK; ocp_reg_write(tp, OCP_PHY_LOCK, data); sram_write(tp, key_addr, 0x0000); r8153_patch_request(tp, false); ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base); return 0; } static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start; u32 length; u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start; bool rc = false; switch (tp->version) { case RTL_VER_04: case RTL_VER_05: case RTL_VER_06: fw_reg = 0xa014; ba_reg = 0xa012; patch_en_addr = 0xa01a; mode_reg = 0xb820; bp_start = 0xa000; break; default: goto out; } fw_offset = __le16_to_cpu(phy->fw_offset); if (fw_offset < sizeof(*phy)) { dev_err(&tp->intf->dev, "fw_offset too small\n"); goto out; } length = __le32_to_cpu(phy->blk_hdr.length); if (length < fw_offset) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } length -= __le16_to_cpu(phy->fw_offset); if (!length || (length & 1)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; } if (__le16_to_cpu(phy->fw_reg) != fw_reg) { dev_err(&tp->intf->dev, "invalid register to load firmware\n"); goto out; } if (__le16_to_cpu(phy->ba_reg) != ba_reg) { dev_err(&tp->intf->dev, "invalid base address register\n"); goto out; } if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) { dev_err(&tp->intf->dev, "invalid patch mode enabled register\n"); goto out; } if (__le16_to_cpu(phy->mode_reg) != mode_reg) { dev_err(&tp->intf->dev, "invalid register to switch the mode\n"); goto out; } if (__le16_to_cpu(phy->bp_start) != bp_start) { dev_err(&tp->intf->dev, "invalid start register of break point\n"); goto out; } if (__le16_to_cpu(phy->bp_num) > 4) { dev_err(&tp->intf->dev, "invalid break point number\n"); goto out; } rc = true; out: return rc; } static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; bool rc = false; u32 length, type; int i, max_bp; type = __le32_to_cpu(type1->blk_hdr.type); type = __le32_to_cpu(mac->blk_hdr.type); if (type == RTL_FW_PLA) { switch (tp->version) { case RTL_VER_01: Loading Loading @@ -3461,46 +3659,52 @@ static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) goto out; } length = __le32_to_cpu(type1->blk_hdr.length); if (length < __le16_to_cpu(type1->fw_offset)) { fw_offset = __le16_to_cpu(mac->fw_offset); if (fw_offset < sizeof(*mac)) { dev_err(&tp->intf->dev, "fw_offset too small\n"); goto out; } length = __le32_to_cpu(mac->blk_hdr.length); if (length < fw_offset) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } length -= __le16_to_cpu(type1->fw_offset); length -= fw_offset; if (length < 4 || (length & 3)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; } if (__le16_to_cpu(type1->fw_reg) != fw_reg) { if (__le16_to_cpu(mac->fw_reg) != fw_reg) { dev_err(&tp->intf->dev, "invalid register to load firmware\n"); goto out; } if (__le16_to_cpu(type1->bp_ba_addr) != bp_ba_addr) { if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) { dev_err(&tp->intf->dev, "invalid base address register\n"); goto out; } if (__le16_to_cpu(type1->bp_en_addr) != bp_en_addr) { if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) { dev_err(&tp->intf->dev, "invalid enabled mask register\n"); goto out; } if (__le16_to_cpu(type1->bp_start) != bp_start) { if (__le16_to_cpu(mac->bp_start) != bp_start) { dev_err(&tp->intf->dev, "invalid start register of break point\n"); goto out; } if (__le16_to_cpu(type1->bp_num) > max_bp) { if (__le16_to_cpu(mac->bp_num) > max_bp) { dev_err(&tp->intf->dev, "invalid break point number\n"); goto out; } for (i = __le16_to_cpu(type1->bp_num); i < max_bp; i++) { if (type1->bp[i]) { for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) { if (mac->bp[i]) { dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); goto out; } Loading Loading @@ -3566,7 +3770,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) { const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; struct fw_type_1 *pla = NULL, *usb = NULL; struct fw_mac *pla = NULL, *usb = NULL; struct fw_phy_patch_key *start = NULL; struct fw_phy_nc *phy_nc = NULL; struct fw_block *stop = NULL; long ret = -EFAULT; int i; Loading @@ -3593,7 +3800,7 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) case RTL_FW_END: if (__le32_to_cpu(block->length) != sizeof(*block)) goto fail; goto success; goto fw_end; case RTL_FW_PLA: if (pla) { dev_err(&tp->intf->dev, Loading @@ -3601,10 +3808,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } pla = (struct fw_type_1 *)block; if (!rtl8152_is_fw_type1_ok(tp, pla)) { pla = (struct fw_mac *)block; if (!rtl8152_is_fw_mac_ok(tp, pla)) { dev_err(&tp->intf->dev, "load PLA firmware failed\n"); "check PLA firmware failed\n"); goto fail; } break; Loading @@ -3615,12 +3822,63 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } usb = (struct fw_type_1 *)block; if (!rtl8152_is_fw_type1_ok(tp, usb)) { usb = (struct fw_mac *)block; if (!rtl8152_is_fw_mac_ok(tp, usb)) { dev_err(&tp->intf->dev, "check USB firmware failed\n"); goto fail; } break; case RTL_FW_PHY_START: if (start || phy_nc || stop) { dev_err(&tp->intf->dev, "check PHY_START fail\n"); goto fail; } if (__le32_to_cpu(block->length) != sizeof(*start)) { dev_err(&tp->intf->dev, "Invalid length for PHY_START\n"); goto fail; } start = (struct fw_phy_patch_key *)block; break; case RTL_FW_PHY_STOP: if (stop || !start) { dev_err(&tp->intf->dev, "load USB firmware failed\n"); "Check PHY_STOP fail\n"); goto fail; } if (__le32_to_cpu(block->length) != sizeof(*block)) { dev_err(&tp->intf->dev, "Invalid length for PHY_STOP\n"); goto fail; } stop = block; break; case RTL_FW_PHY_NC: if (!start || stop) { dev_err(&tp->intf->dev, "check PHY_NC fail\n"); goto fail; } if (phy_nc) { dev_err(&tp->intf->dev, "multiple PHY NC encountered\n"); goto fail; } phy_nc = (struct fw_phy_nc *)block; if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) { dev_err(&tp->intf->dev, "check PHY NC firmware failed\n"); goto fail; } break; default: dev_warn(&tp->intf->dev, "Unknown type %u is found\n", Loading @@ -3632,20 +3890,60 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) i += ALIGN(__le32_to_cpu(block->length), 8); } success: fw_end: if ((phy_nc || start) && !stop) { dev_err(&tp->intf->dev, "without PHY_STOP\n"); goto fail; } return 0; fail: return ret; } static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) { u16 mode_reg, bp_index; u32 length, i, num; __le16 *data; mode_reg = __le16_to_cpu(phy->mode_reg); sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre)); sram_write(tp, __le16_to_cpu(phy->ba_reg), __le16_to_cpu(phy->ba_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])); sram_write(tp, __le16_to_cpu(phy->patch_en_addr), __le16_to_cpu(phy->patch_en_value)); bp_index = __le16_to_cpu(phy->bp_start); num = __le16_to_cpu(phy->bp_num); for (i = 0; i < num; i++) { sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i])); bp_index += 2; } sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post)); dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info); } static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) { u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; u32 length; u8 *data; int i; switch (__le32_to_cpu(type1->blk_hdr.type)) { switch (__le32_to_cpu(mac->blk_hdr.type)) { case RTL_FW_PLA: type = MCU_TYPE_PLA; break; Loading @@ -3667,36 +3965,36 @@ static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); } length = __le32_to_cpu(type1->blk_hdr.length); length -= __le16_to_cpu(type1->fw_offset); length = __le32_to_cpu(mac->blk_hdr.length); length -= __le16_to_cpu(mac->fw_offset); data = (u8 *)type1; data += __le16_to_cpu(type1->fw_offset); data = (u8 *)mac; data += __le16_to_cpu(mac->fw_offset); generic_ocp_write(tp, __le16_to_cpu(type1->fw_reg), 0xff, length, data, generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data, type); ocp_write_word(tp, type, __le16_to_cpu(type1->bp_ba_addr), __le16_to_cpu(type1->bp_ba_value)); ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr), __le16_to_cpu(mac->bp_ba_value)); bp_index = __le16_to_cpu(type1->bp_start); bp_num = __le16_to_cpu(type1->bp_num); bp_index = __le16_to_cpu(mac->bp_start); bp_num = __le16_to_cpu(mac->bp_num); for (i = 0; i < bp_num; i++) { ocp_write_word(tp, type, bp_index, __le16_to_cpu(type1->bp[i])); ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i])); bp_index += 2; } bp_en_addr = __le16_to_cpu(type1->bp_en_addr); bp_en_addr = __le16_to_cpu(mac->bp_en_addr); if (bp_en_addr) ocp_write_word(tp, type, bp_en_addr, __le16_to_cpu(type1->bp_en_value)); __le16_to_cpu(mac->bp_en_value)); fw_ver_reg = __le16_to_cpu(type1->fw_ver_reg); fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg); if (fw_ver_reg) ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, type1->fw_ver_data); mac->fw_ver_data); dev_dbg(&tp->intf->dev, "successfully applied %s\n", type1->info); dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info); } static void rtl8152_apply_firmware(struct r8152 *tp) Loading @@ -3704,6 +4002,8 @@ static void rtl8152_apply_firmware(struct r8152 *tp) struct rtl_fw *rtl_fw = &tp->rtl_fw; const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; struct fw_phy_patch_key *key; u16 key_addr = 0; int i; if (IS_ERR_OR_NULL(rtl_fw->fw)) Loading @@ -3720,7 +4020,20 @@ static void rtl8152_apply_firmware(struct r8152 *tp) goto post_fw; case RTL_FW_PLA: case RTL_FW_USB: rtl8152_fw_type_1_apply(tp, (struct fw_type_1 *)block); rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); break; case RTL_FW_PHY_START: key = (struct fw_phy_patch_key *)block; key_addr = __le16_to_cpu(key->key_reg); r8153_pre_ram_code(tp, key_addr, __le16_to_cpu(key->key_data)); break; case RTL_FW_PHY_STOP: WARN_ON(!key_addr); r8153_post_ram_code(tp, key_addr); break; case RTL_FW_PHY_NC: rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block); break; default: break; Loading Loading @@ -4050,33 +4363,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } static int r8153_patch_request(struct r8152 *tp, bool request) { u16 data; int i; data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); if (request) data |= PATCH_REQUEST; else data &= ~PATCH_REQUEST; ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); for (i = 0; request && i < 5000; i++) { usleep_range(1000, 2000); if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) break; } if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { netif_err(tp, drv, tp->netdev, "patch request fail\n"); r8153_patch_request(tp, false); return -ETIME; } else { return 0; } } static int r8153_pre_firmware_1(struct r8152 *tp) { int i; Loading Loading
drivers/net/usb/r8152.c +357 −71 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ #define OCP_PHY_PATCH_STAT 0xb800 #define OCP_PHY_PATCH_CMD 0xb820 #define OCP_PHY_LOCK 0xb82e #define OCP_ADC_IOFFSET 0xbcfc #define OCP_ADC_CFG 0xbc06 #define OCP_SYSCLK_CFG 0xc416 Loading @@ -197,6 +198,7 @@ #define SRAM_10M_AMP1 0x8080 #define SRAM_10M_AMP2 0x8082 #define SRAM_IMPEDANCE 0x8084 #define SRAM_PHY_LOCK 0xb82e /* PLA_RCR */ #define RCR_AAP 0x00000001 Loading Loading @@ -577,6 +579,9 @@ enum spd_duplex { /* OCP_PHY_PATCH_CMD */ #define PATCH_REQUEST BIT(4) /* OCP_PHY_LOCK */ #define PATCH_LOCK BIT(0) /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 Loading @@ -601,6 +606,9 @@ enum spd_duplex { /* SRAM_IMPEDANCE */ #define RX_DRIVING_MASK 0x6000 /* SRAM_PHY_LOCK */ #define PHY_PATCH_LOCK 0x0001 /* MAC PASSTHRU */ #define AD_MASK 0xfee0 #define BND_MASK 0x0004 Loading Loading @@ -867,11 +875,11 @@ struct fw_header { } __packed; /** * struct fw_type_1 - a firmware block used by RTL_FW_PLA and RTL_FW_USB. * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB. * The layout of the firmware block is: * <struct fw_type_1> + <info> + <firmware data>. * <struct fw_mac> + <info> + <firmware data>. * @fw_offset: offset of the firmware binary data. The start address of * the data would be the address of struct fw_type_1 + @fw_offset. * the data would be the address of struct fw_mac + @fw_offset. * @fw_reg: the register to load the firmware. Depends on chip. * @bp_ba_addr: the register to write break point base address. Depends on * chip. Loading @@ -888,7 +896,7 @@ struct fw_header { * @info: additional information for debugging, and is followed by the * binary data of firmware. */ struct fw_type_1 { struct fw_mac { struct fw_block blk_hdr; __le16 fw_offset; __le16 fw_reg; Loading @@ -905,10 +913,65 @@ struct fw_type_1 { char info[0]; } __packed; /** * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START. * This is used to set patch key when loading the firmware of PHY. * @key_reg: the register to write the patch key. * @key_data: patch key. */ struct fw_phy_patch_key { struct fw_block blk_hdr; __le16 key_reg; __le16 key_data; __le32 reserved; } __packed; /** * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC. * The layout of the firmware block is: * <struct fw_phy_nc> + <info> + <firmware data>. * @fw_offset: offset of the firmware binary data. The start address of * the data would be the address of struct fw_phy_nc + @fw_offset. * @fw_reg: the register to load the firmware. Depends on chip. * @ba_reg: the register to write the base address. Depends on chip. * @ba_data: base address. Depends on chip. * @patch_en_addr: the register of enabling patch mode. Depends on chip. * @patch_en_value: patch mode enabled mask. Depends on the firmware. * @mode_reg: the regitster of switching the mode. * @mod_pre: the mode needing to be set before loading the firmware. * @mod_post: the mode to be set when finishing to load the firmware. * @bp_start: the start register of break points. Depends on chip. * @bp_num: the break point number which needs to be set for this firmware. * Depends on the firmware. * @bp: break points. Depends on firmware. * @info: additional information for debugging, and is followed by the * binary data of firmware. */ struct fw_phy_nc { struct fw_block blk_hdr; __le16 fw_offset; __le16 fw_reg; __le16 ba_reg; __le16 ba_data; __le16 patch_en_addr; __le16 patch_en_value; __le16 mode_reg; __le16 mode_pre; __le16 mode_post; __le16 reserved; __le16 bp_start; __le16 bp_num; __le16 bp[4]; char info[0]; } __packed; enum rtl_fw_type { RTL_FW_END = 0, RTL_FW_PLA, RTL_FW_USB, RTL_FW_PHY_START, RTL_FW_PHY_STOP, RTL_FW_PHY_NC, }; enum rtl_version { Loading Loading @@ -3397,14 +3460,149 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) ocp_write_word(tp, type, PLA_BP_BA, 0); } static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) static int r8153_patch_request(struct r8152 *tp, bool request) { u16 data; int i; data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); if (request) data |= PATCH_REQUEST; else data &= ~PATCH_REQUEST; ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); for (i = 0; request && i < 5000; i++) { usleep_range(1000, 2000); if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) break; } if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { netif_err(tp, drv, tp->netdev, "patch request fail\n"); r8153_patch_request(tp, false); return -ETIME; } else { return 0; } } static int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key) { if (r8153_patch_request(tp, true)) { dev_err(&tp->intf->dev, "patch request fail\n"); return -ETIME; } sram_write(tp, key_addr, patch_key); sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK); return 0; } static int r8153_post_ram_code(struct r8152 *tp, u16 key_addr) { u16 data; sram_write(tp, 0x0000, 0x0000); data = ocp_reg_read(tp, OCP_PHY_LOCK); data &= ~PATCH_LOCK; ocp_reg_write(tp, OCP_PHY_LOCK, data); sram_write(tp, key_addr, 0x0000); r8153_patch_request(tp, false); ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base); return 0; } static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start; u32 length; u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start; bool rc = false; switch (tp->version) { case RTL_VER_04: case RTL_VER_05: case RTL_VER_06: fw_reg = 0xa014; ba_reg = 0xa012; patch_en_addr = 0xa01a; mode_reg = 0xb820; bp_start = 0xa000; break; default: goto out; } fw_offset = __le16_to_cpu(phy->fw_offset); if (fw_offset < sizeof(*phy)) { dev_err(&tp->intf->dev, "fw_offset too small\n"); goto out; } length = __le32_to_cpu(phy->blk_hdr.length); if (length < fw_offset) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } length -= __le16_to_cpu(phy->fw_offset); if (!length || (length & 1)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; } if (__le16_to_cpu(phy->fw_reg) != fw_reg) { dev_err(&tp->intf->dev, "invalid register to load firmware\n"); goto out; } if (__le16_to_cpu(phy->ba_reg) != ba_reg) { dev_err(&tp->intf->dev, "invalid base address register\n"); goto out; } if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) { dev_err(&tp->intf->dev, "invalid patch mode enabled register\n"); goto out; } if (__le16_to_cpu(phy->mode_reg) != mode_reg) { dev_err(&tp->intf->dev, "invalid register to switch the mode\n"); goto out; } if (__le16_to_cpu(phy->bp_start) != bp_start) { dev_err(&tp->intf->dev, "invalid start register of break point\n"); goto out; } if (__le16_to_cpu(phy->bp_num) > 4) { dev_err(&tp->intf->dev, "invalid break point number\n"); goto out; } rc = true; out: return rc; } static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; bool rc = false; u32 length, type; int i, max_bp; type = __le32_to_cpu(type1->blk_hdr.type); type = __le32_to_cpu(mac->blk_hdr.type); if (type == RTL_FW_PLA) { switch (tp->version) { case RTL_VER_01: Loading Loading @@ -3461,46 +3659,52 @@ static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) goto out; } length = __le32_to_cpu(type1->blk_hdr.length); if (length < __le16_to_cpu(type1->fw_offset)) { fw_offset = __le16_to_cpu(mac->fw_offset); if (fw_offset < sizeof(*mac)) { dev_err(&tp->intf->dev, "fw_offset too small\n"); goto out; } length = __le32_to_cpu(mac->blk_hdr.length); if (length < fw_offset) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } length -= __le16_to_cpu(type1->fw_offset); length -= fw_offset; if (length < 4 || (length & 3)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; } if (__le16_to_cpu(type1->fw_reg) != fw_reg) { if (__le16_to_cpu(mac->fw_reg) != fw_reg) { dev_err(&tp->intf->dev, "invalid register to load firmware\n"); goto out; } if (__le16_to_cpu(type1->bp_ba_addr) != bp_ba_addr) { if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) { dev_err(&tp->intf->dev, "invalid base address register\n"); goto out; } if (__le16_to_cpu(type1->bp_en_addr) != bp_en_addr) { if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) { dev_err(&tp->intf->dev, "invalid enabled mask register\n"); goto out; } if (__le16_to_cpu(type1->bp_start) != bp_start) { if (__le16_to_cpu(mac->bp_start) != bp_start) { dev_err(&tp->intf->dev, "invalid start register of break point\n"); goto out; } if (__le16_to_cpu(type1->bp_num) > max_bp) { if (__le16_to_cpu(mac->bp_num) > max_bp) { dev_err(&tp->intf->dev, "invalid break point number\n"); goto out; } for (i = __le16_to_cpu(type1->bp_num); i < max_bp; i++) { if (type1->bp[i]) { for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) { if (mac->bp[i]) { dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); goto out; } Loading Loading @@ -3566,7 +3770,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) { const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; struct fw_type_1 *pla = NULL, *usb = NULL; struct fw_mac *pla = NULL, *usb = NULL; struct fw_phy_patch_key *start = NULL; struct fw_phy_nc *phy_nc = NULL; struct fw_block *stop = NULL; long ret = -EFAULT; int i; Loading @@ -3593,7 +3800,7 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) case RTL_FW_END: if (__le32_to_cpu(block->length) != sizeof(*block)) goto fail; goto success; goto fw_end; case RTL_FW_PLA: if (pla) { dev_err(&tp->intf->dev, Loading @@ -3601,10 +3808,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } pla = (struct fw_type_1 *)block; if (!rtl8152_is_fw_type1_ok(tp, pla)) { pla = (struct fw_mac *)block; if (!rtl8152_is_fw_mac_ok(tp, pla)) { dev_err(&tp->intf->dev, "load PLA firmware failed\n"); "check PLA firmware failed\n"); goto fail; } break; Loading @@ -3615,12 +3822,63 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } usb = (struct fw_type_1 *)block; if (!rtl8152_is_fw_type1_ok(tp, usb)) { usb = (struct fw_mac *)block; if (!rtl8152_is_fw_mac_ok(tp, usb)) { dev_err(&tp->intf->dev, "check USB firmware failed\n"); goto fail; } break; case RTL_FW_PHY_START: if (start || phy_nc || stop) { dev_err(&tp->intf->dev, "check PHY_START fail\n"); goto fail; } if (__le32_to_cpu(block->length) != sizeof(*start)) { dev_err(&tp->intf->dev, "Invalid length for PHY_START\n"); goto fail; } start = (struct fw_phy_patch_key *)block; break; case RTL_FW_PHY_STOP: if (stop || !start) { dev_err(&tp->intf->dev, "load USB firmware failed\n"); "Check PHY_STOP fail\n"); goto fail; } if (__le32_to_cpu(block->length) != sizeof(*block)) { dev_err(&tp->intf->dev, "Invalid length for PHY_STOP\n"); goto fail; } stop = block; break; case RTL_FW_PHY_NC: if (!start || stop) { dev_err(&tp->intf->dev, "check PHY_NC fail\n"); goto fail; } if (phy_nc) { dev_err(&tp->intf->dev, "multiple PHY NC encountered\n"); goto fail; } phy_nc = (struct fw_phy_nc *)block; if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) { dev_err(&tp->intf->dev, "check PHY NC firmware failed\n"); goto fail; } break; default: dev_warn(&tp->intf->dev, "Unknown type %u is found\n", Loading @@ -3632,20 +3890,60 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) i += ALIGN(__le32_to_cpu(block->length), 8); } success: fw_end: if ((phy_nc || start) && !stop) { dev_err(&tp->intf->dev, "without PHY_STOP\n"); goto fail; } return 0; fail: return ret; } static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) { u16 mode_reg, bp_index; u32 length, i, num; __le16 *data; mode_reg = __le16_to_cpu(phy->mode_reg); sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre)); sram_write(tp, __le16_to_cpu(phy->ba_reg), __le16_to_cpu(phy->ba_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])); sram_write(tp, __le16_to_cpu(phy->patch_en_addr), __le16_to_cpu(phy->patch_en_value)); bp_index = __le16_to_cpu(phy->bp_start); num = __le16_to_cpu(phy->bp_num); for (i = 0; i < num; i++) { sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i])); bp_index += 2; } sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post)); dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info); } static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) { u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; u32 length; u8 *data; int i; switch (__le32_to_cpu(type1->blk_hdr.type)) { switch (__le32_to_cpu(mac->blk_hdr.type)) { case RTL_FW_PLA: type = MCU_TYPE_PLA; break; Loading @@ -3667,36 +3965,36 @@ static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); } length = __le32_to_cpu(type1->blk_hdr.length); length -= __le16_to_cpu(type1->fw_offset); length = __le32_to_cpu(mac->blk_hdr.length); length -= __le16_to_cpu(mac->fw_offset); data = (u8 *)type1; data += __le16_to_cpu(type1->fw_offset); data = (u8 *)mac; data += __le16_to_cpu(mac->fw_offset); generic_ocp_write(tp, __le16_to_cpu(type1->fw_reg), 0xff, length, data, generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data, type); ocp_write_word(tp, type, __le16_to_cpu(type1->bp_ba_addr), __le16_to_cpu(type1->bp_ba_value)); ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr), __le16_to_cpu(mac->bp_ba_value)); bp_index = __le16_to_cpu(type1->bp_start); bp_num = __le16_to_cpu(type1->bp_num); bp_index = __le16_to_cpu(mac->bp_start); bp_num = __le16_to_cpu(mac->bp_num); for (i = 0; i < bp_num; i++) { ocp_write_word(tp, type, bp_index, __le16_to_cpu(type1->bp[i])); ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i])); bp_index += 2; } bp_en_addr = __le16_to_cpu(type1->bp_en_addr); bp_en_addr = __le16_to_cpu(mac->bp_en_addr); if (bp_en_addr) ocp_write_word(tp, type, bp_en_addr, __le16_to_cpu(type1->bp_en_value)); __le16_to_cpu(mac->bp_en_value)); fw_ver_reg = __le16_to_cpu(type1->fw_ver_reg); fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg); if (fw_ver_reg) ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, type1->fw_ver_data); mac->fw_ver_data); dev_dbg(&tp->intf->dev, "successfully applied %s\n", type1->info); dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info); } static void rtl8152_apply_firmware(struct r8152 *tp) Loading @@ -3704,6 +4002,8 @@ static void rtl8152_apply_firmware(struct r8152 *tp) struct rtl_fw *rtl_fw = &tp->rtl_fw; const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; struct fw_phy_patch_key *key; u16 key_addr = 0; int i; if (IS_ERR_OR_NULL(rtl_fw->fw)) Loading @@ -3720,7 +4020,20 @@ static void rtl8152_apply_firmware(struct r8152 *tp) goto post_fw; case RTL_FW_PLA: case RTL_FW_USB: rtl8152_fw_type_1_apply(tp, (struct fw_type_1 *)block); rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); break; case RTL_FW_PHY_START: key = (struct fw_phy_patch_key *)block; key_addr = __le16_to_cpu(key->key_reg); r8153_pre_ram_code(tp, key_addr, __le16_to_cpu(key->key_data)); break; case RTL_FW_PHY_STOP: WARN_ON(!key_addr); r8153_post_ram_code(tp, key_addr); break; case RTL_FW_PHY_NC: rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block); break; default: break; Loading Loading @@ -4050,33 +4363,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } static int r8153_patch_request(struct r8152 *tp, bool request) { u16 data; int i; data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); if (request) data |= PATCH_REQUEST; else data &= ~PATCH_REQUEST; ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); for (i = 0; request && i < 5000; i++) { usleep_range(1000, 2000); if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) break; } if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { netif_err(tp, drv, tp->netdev, "patch request fail\n"); r8153_patch_request(tp, false); return -ETIME; } else { return 0; } } static int r8153_pre_firmware_1(struct r8152 *tp) { int i; Loading