diff --git a/content/post/rtl8153b-for-4.9.md b/content/post/rtl8153b-for-4.9.md new file mode 100644 index 0000000..07e6ca3 --- /dev/null +++ b/content/post/rtl8153b-for-4.9.md @@ -0,0 +1,27 @@ +--- +title: RTL8153B support for 4.9 kernel +date: !!timestamp '2019-03-17 00:00:00' +tags: + - kernel +--- + +If you buy a *recent* USB to Ethernet adapter, embedding a Realtek chip, you +possibly face, like me, the following error, when connecting it: + +``` +r8152 4-1.1:1.0 (unnamed net_device) (uninitialized): Unknown version 0x6010 +r8152 4-1.1:1.0 (unnamed net_device) (uninitialized): Unknown Device +``` + +<!--more--> + +This error is raised because your Linux r8152 driver is too old and doesn't +support your chip's variant. + +In my case, I got the variant `0x6010` which has only been implemented in Linux +4.13, in the [commit +65b82d69...d3e7fb976](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/net/usb/r8152.c?h=v4.13&id=65b82d696b9e84fda6dd7df61801b57d3e7fb976). + +As I run at the time a 4.9 kernel and can't upgrade to a newer release, I +backport the commit to the 4.9 branch. You can find [the patch I made +here](r8152-for-4.9.patch). It only adds support for RTL8153B. diff --git a/static/post/rtl8153b-for-4.9/r8152-for-4.9.patch b/static/post/rtl8153b-for-4.9/r8152-for-4.9.patch new file mode 100644 index 0000000..8122cd9 --- /dev/null +++ b/static/post/rtl8153b-for-4.9/r8152-for-4.9.patch @@ -0,0 +1,1179 @@ +From: Pierre-Olivier Mercier <nemunaire@nemunai.re> +Date: Sat, 17 Mar 2019 00:23:00 +0100 +Subject: backport r8152: support RTL8153B + +This backports the upstream commit 65b82d696b9e84fda6dd7df61801b57d3e7fb976 +to the 4.9 branch. + +--- a/drivers/net/usb/r8152.c 2019-03-16 23:13:55.792422464 +0100 ++++ b/drivers/net/usb/r8152.c 2019-03-16 23:52:01.542199652 +0100 +@@ -29,7 +29,7 @@ + #include <linux/acpi.h> + + /* Information for net-next */ +-#define NETNEXT_VERSION "08" ++#define NETNEXT_VERSION "09" + + /* Information for net */ + #define NET_VERSION "7" +@@ -51,11 +51,14 @@ + #define PLA_FMC 0xc0b4 + #define PLA_CFG_WOL 0xc0b6 + #define PLA_TEREDO_CFG 0xc0bc ++#define PLA_TEREDO_WAKE_BASE 0xc0c4 + #define PLA_MAR 0xcd00 + #define PLA_BACKUP 0xd000 + #define PAL_BDC_CR 0xd1a0 + #define PLA_TEREDO_TIMER 0xd2cc + #define PLA_REALWOW_TIMER 0xd2e8 ++#define PLA_EFUSE_DATA 0xdd00 ++#define PLA_EFUSE_CMD 0xdd02 + #define PLA_LEDSEL 0xdd90 + #define PLA_LED_FEATURE 0xdd92 + #define PLA_PHYAR 0xde00 +@@ -105,7 +108,9 @@ + #define USB_CSR_DUMMY2 0xb466 + #define USB_DEV_STAT 0xb808 + #define USB_CONNECT_TIMER 0xcbf8 ++#define USB_MSC_TIMER 0xcbfc + #define USB_BURST_SIZE 0xcfc0 ++#define USB_LPM_CONFIG 0xcfd8 + #define USB_USB_CTRL 0xd406 + #define USB_PHY_CTRL 0xd408 + #define USB_TX_AGG 0xd40a +@@ -113,15 +118,20 @@ + #define USB_USB_TIMER 0xd428 + #define USB_RX_EARLY_TIMEOUT 0xd42c + #define USB_RX_EARLY_SIZE 0xd42e +-#define USB_PM_CTRL_STATUS 0xd432 ++#define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */ ++#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */ + #define USB_TX_DMA 0xd434 ++#define USB_UPT_RXDMA_OWN 0xd437 + #define USB_TOLERANCE 0xd490 + #define USB_LPM_CTRL 0xd41a + #define USB_BMU_RESET 0xd4b0 ++#define USB_U1U2_TIMER 0xd4da + #define USB_UPS_CTRL 0xd800 +-#define USB_MISC_0 0xd81a + #define USB_POWER_CUT 0xd80a ++#define USB_MISC_0 0xd81a + #define USB_AFE_CTRL2 0xd824 ++#define USB_UPS_CFG 0xd842 ++#define USB_UPS_FLAGS 0xd848 + #define USB_WDT11_CTRL 0xe43c + #define USB_BP_BA 0xfc26 + #define USB_BP_0 0xfc28 +@@ -133,6 +143,15 @@ + #define USB_BP_6 0xfc34 + #define USB_BP_7 0xfc36 + #define USB_BP_EN 0xfc38 ++#define USB_BP_8 0xfc38 ++#define USB_BP_9 0xfc3a ++#define USB_BP_10 0xfc3c ++#define USB_BP_11 0xfc3e ++#define USB_BP_12 0xfc40 ++#define USB_BP_13 0xfc42 ++#define USB_BP_14 0xfc44 ++#define USB_BP_15 0xfc46 ++#define USB_BP2_EN 0xfc48 + + /* OCP Registers */ + #define OCP_ALDPS_CONFIG 0x2010 +@@ -143,6 +162,7 @@ + #define OCP_EEE_AR 0xa41a + #define OCP_EEE_DATA 0xa41c + #define OCP_PHY_STATUS 0xa420 ++#define OCP_NCTL_CFG 0xa42c + #define OCP_POWER_CFG 0xa430 + #define OCP_EEE_CFG 0xa432 + #define OCP_SRAM_ADDR 0xa436 +@@ -152,9 +172,14 @@ + #define OCP_EEE_ADV 0xa5d0 + #define OCP_EEE_LPABLE 0xa5d2 + #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ ++#define OCP_PHY_PATCH_STAT 0xb800 ++#define OCP_PHY_PATCH_CMD 0xb820 ++#define OCP_ADC_IOFFSET 0xbcfc + #define OCP_ADC_CFG 0xbc06 ++#define OCP_SYSCLK_CFG 0xc416 + + /* SRAM Register */ ++#define SRAM_GREEN_CFG 0x8011 + #define SRAM_LPF_CFG 0x8012 + #define SRAM_10M_AMP1 0x8080 + #define SRAM_10M_AMP2 0x8082 +@@ -252,6 +277,10 @@ + /* PAL_BDC_CR */ + #define ALDPS_PROXY_MODE 0x0001 + ++/* PLA_EFUSE_CMD */ ++#define EFUSE_READ_CMD BIT(15) ++#define EFUSE_DATA_BIT16 BIT(7) ++ + /* PLA_CONFIG34 */ + #define LINK_ON_WAKE_EN 0x0010 + #define LINK_OFF_WAKE_EN 0x0008 +@@ -277,6 +306,7 @@ + + /* PLA_MAC_PWR_CTRL2 */ + #define EEE_SPDWN_RATIO 0x8007 ++#define MAC_CLK_SPDWN_EN BIT(15) + + /* PLA_MAC_PWR_CTRL3 */ + #define PKT_AVAIL_SPDWN_EN 0x0100 +@@ -328,6 +358,9 @@ + #define STAT_SPEED_HIGH 0x0000 + #define STAT_SPEED_FULL 0x0002 + ++/* USB_LPM_CONFIG */ ++#define LPM_U1U2_EN BIT(0) ++ + /* USB_TX_AGG */ + #define TX_AGG_MAX_THRESHOLD 0x03 + +@@ -335,6 +368,7 @@ + #define RX_THR_SUPPER 0x0c350180 + #define RX_THR_HIGH 0x7a120180 + #define RX_THR_SLOW 0xffff0180 ++#define RX_THR_B 0x00010001 + + /* USB_TX_DMA */ + #define TEST_MODE_DISABLE 0x00000001 +@@ -344,6 +378,10 @@ + #define BMU_RESET_EP_IN 0x01 + #define BMU_RESET_EP_OUT 0x02 + ++/* USB_UPT_RXDMA_OWN */ ++#define OWN_UPDATE BIT(0) ++#define OWN_CLEAR BIT(1) ++ + /* USB_UPS_CTRL */ + #define POWER_CUT 0x0100 + +@@ -360,6 +398,8 @@ + /* USB_POWER_CUT */ + #define PWR_EN 0x0001 + #define PHASE2_EN 0x0008 ++#define UPS_EN BIT(4) ++#define USP_PREWAKE BIT(5) + + /* USB_MISC_0 */ + #define PCUT_STATUS 0x0001 +@@ -386,6 +426,37 @@ + #define SEN_VAL_NORMAL 0xa000 + #define SEL_RXIDLE 0x0100 + ++/* USB_UPS_CFG */ ++#define SAW_CNT_1MS_MASK 0x0fff ++ ++/* USB_UPS_FLAGS */ ++#define UPS_FLAGS_R_TUNE BIT(0) ++#define UPS_FLAGS_EN_10M_CKDIV BIT(1) ++#define UPS_FLAGS_250M_CKDIV BIT(2) ++#define UPS_FLAGS_EN_ALDPS BIT(3) ++#define UPS_FLAGS_CTAP_SHORT_DIS BIT(4) ++#define UPS_FLAGS_SPEED_MASK (0xf << 16) ++#define ups_flags_speed(x) ((x) << 16) ++#define UPS_FLAGS_EN_EEE BIT(20) ++#define UPS_FLAGS_EN_500M_EEE BIT(21) ++#define UPS_FLAGS_EN_EEE_CKDIV BIT(22) ++#define UPS_FLAGS_EEE_PLLOFF_GIGA BIT(24) ++#define UPS_FLAGS_EEE_CMOD_LV_EN BIT(25) ++#define UPS_FLAGS_EN_GREEN BIT(26) ++#define UPS_FLAGS_EN_FLOW_CTR BIT(27) ++ ++enum spd_duplex { ++ NWAY_10M_HALF = 1, ++ NWAY_10M_FULL, ++ NWAY_100M_HALF, ++ NWAY_100M_FULL, ++ NWAY_1000M_FULL, ++ FORCE_10M_HALF, ++ FORCE_10M_FULL, ++ FORCE_100M_HALF, ++ FORCE_100M_FULL, ++}; ++ + /* OCP_ALDPS_CONFIG */ + #define ENPWRSAVE 0x8000 + #define ENPDNPS 0x0200 +@@ -394,9 +465,13 @@ + + /* OCP_PHY_STATUS */ + #define PHY_STAT_MASK 0x0007 ++#define PHY_STAT_EXT_INIT 2 + #define PHY_STAT_LAN_ON 3 + #define PHY_STAT_PWRDN 5 + ++/* OCP_NCTL_CFG */ ++#define PGA_RETURN_EN BIT(1) ++ + /* OCP_POWER_CFG */ + #define EEE_CLKDIV_EN 0x8000 + #define EN_ALDPS 0x0004 +@@ -438,17 +513,34 @@ + #define EEE10_EN 0x0010 + + /* OCP_DOWN_SPEED */ ++#define EN_EEE_CMODE BIT(14) ++#define EN_EEE_1000 BIT(13) ++#define EN_EEE_100 BIT(12) ++#define EN_10M_CLKDIV BIT(11) + #define EN_10M_BGOFF 0x0080 + + /* OCP_PHY_STATE */ + #define TXDIS_STATE 0x01 + #define ABD_STATE 0x02 + ++/* OCP_PHY_PATCH_STAT */ ++#define PATCH_READY BIT(6) ++ ++/* OCP_PHY_PATCH_CMD */ ++#define PATCH_REQUEST BIT(4) ++ + /* OCP_ADC_CFG */ + #define CKADSEL_L 0x0100 + #define ADC_EN 0x0080 + #define EN_EMI_L 0x0040 + ++/* OCP_SYSCLK_CFG */ ++#define clk_div_expo(x) (min(x, 5) << 8) ++ ++/* SRAM_GREEN_CFG */ ++#define GREEN_ETH_EN BIT(15) ++#define R_TUNE_EN BIT(11) ++ + /* SRAM_LPF_CFG */ + #define LPF_AUTO_TUNE 0x8000 + +@@ -511,6 +603,7 @@ + SELECTIVE_SUSPEND, + PHY_RESET, + SCHEDULE_NAPI, ++ GREEN_ETHERNET, + }; + + /* Define these values to match your device */ +@@ -655,6 +748,9 @@ + RTL_VER_04, + RTL_VER_05, + RTL_VER_06, ++ RTL_VER_07, ++ RTL_VER_08, ++ RTL_VER_09, + RTL_VER_MAX + }; + +@@ -985,6 +1081,12 @@ + ocp_reg_write(tp, OCP_SRAM_DATA, data); + } + ++static u16 sram_read(struct r8152 *tp, u16 addr) ++{ ++ ocp_reg_write(tp, OCP_SRAM_ADDR, addr); ++ return ocp_reg_read(tp, OCP_SRAM_DATA); ++} ++ + static int read_mii_word(struct net_device *netdev, int phy_id, int reg) + { + struct r8152 *tp = netdev_priv(netdev); +@@ -2240,11 +2342,40 @@ + return rtl_enable(tp); + } + ++static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp) ++{ ++ ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN, ++ OWN_UPDATE | OWN_CLEAR); ++} ++ + static void r8153_set_rx_early_timeout(struct r8152 *tp) + { + u32 ocp_data = tp->coalesce / 8; + +- ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ocp_data); ++ switch (tp->version) { ++ case RTL_VER_03: ++ case RTL_VER_04: ++ case RTL_VER_05: ++ case RTL_VER_06: ++ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ++ ocp_data); ++ break; ++ ++ case RTL_VER_08: ++ case RTL_VER_09: ++ /* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout ++ * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 128ns. ++ */ ++ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ++ 128 / 8); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR, ++ ocp_data); ++ r8153b_rx_agg_chg_indicate(tp); ++ break; ++ ++ default: ++ break; ++ } + } + + static void r8153_set_rx_early_size(struct r8152 *tp) +@@ -2252,7 +2383,24 @@ + u32 mtu = tp->netdev->mtu; + u32 ocp_data = (agg_buf_sz - mtu - VLAN_ETH_HLEN - VLAN_HLEN) / 8; + +- ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data); ++ switch (tp->version) { ++ case RTL_VER_03: ++ case RTL_VER_04: ++ case RTL_VER_05: ++ case RTL_VER_06: ++ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ++ ocp_data / 4); ++ break; ++ case RTL_VER_08: ++ case RTL_VER_09: ++ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ++ ocp_data / 8); ++ r8153b_rx_agg_chg_indicate(tp); ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ break; ++ } + } + + static int rtl8153_enable(struct r8152 *tp) +@@ -2438,6 +2586,19 @@ + usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); + } + ++static void r8153b_u1u2en(struct r8152 *tp, bool enable) ++{ ++ u32 ocp_data; ++ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG); ++ if (enable) ++ ocp_data |= LPM_U1U2_EN; ++ else ++ ocp_data &= ~LPM_U1U2_EN; ++ ++ ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data); ++} ++ + static void r8153_u2p3en(struct r8152 *tp, bool enable) + { + u32 ocp_data; +@@ -2450,6 +2611,108 @@ + ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); + } + ++static void r8153b_ups_flags_w1w0(struct r8152 *tp, u32 set, u32 clear) ++{ ++ u32 ocp_data; ++ ++ ocp_data = ocp_read_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS); ++ ocp_data &= ~clear; ++ ocp_data |= set; ++ ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ocp_data); ++} ++ ++static void r8153b_green_en(struct r8152 *tp, bool enable) ++{ ++ u16 data; ++ ++ if (enable) { ++ sram_write(tp, 0x8045, 0); /* 10M abiq&ldvbias */ ++ sram_write(tp, 0x804d, 0x1222); /* 100M short abiq&ldvbias */ ++ sram_write(tp, 0x805d, 0x0022); /* 1000M short abiq&ldvbias */ ++ } else { ++ sram_write(tp, 0x8045, 0x2444); /* 10M abiq&ldvbias */ ++ sram_write(tp, 0x804d, 0x2444); /* 100M short abiq&ldvbias */ ++ sram_write(tp, 0x805d, 0x2444); /* 1000M short abiq&ldvbias */ ++ } ++ ++ data = sram_read(tp, SRAM_GREEN_CFG); ++ data |= GREEN_ETH_EN; ++ sram_write(tp, SRAM_GREEN_CFG, data); ++ ++ r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_GREEN, 0); ++} ++ ++static u16 r8153_phy_status(struct r8152 *tp, u16 desired) ++{ ++ u16 data; ++ int i; ++ ++ for (i = 0; i < 500; i++) { ++ data = ocp_reg_read(tp, OCP_PHY_STATUS); ++ data &= PHY_STAT_MASK; ++ if (desired) { ++ if (data == desired) ++ break; ++ } else if (data == PHY_STAT_LAN_ON || data == PHY_STAT_PWRDN || ++ data == PHY_STAT_EXT_INIT) { ++ break; ++ } ++ ++ msleep(20); ++ } ++ ++ return data; ++} ++ ++static void r8153b_ups_en(struct r8152 *tp, bool enable) ++{ ++ u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT); ++ ++ if (enable) { ++ ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN; ++ ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); ++ ++ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); ++ ocp_data |= BIT(0); ++ ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); ++ } else { ++ u16 data; ++ ++ ocp_data &= ~(UPS_EN | USP_PREWAKE); ++ ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); ++ ++ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); ++ ocp_data &= ~BIT(0); ++ ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); ++ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); ++ ocp_data &= ~PCUT_STATUS; ++ ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); ++ ++ data = r8153_phy_status(tp, 0); ++ ++ switch (data) { ++ case PHY_STAT_PWRDN: ++ case PHY_STAT_EXT_INIT: ++ r8153b_green_en(tp, ++ test_bit(GREEN_ETHERNET, &tp->flags)); ++ ++ data = r8152_mdio_read(tp, MII_BMCR); ++ data &= ~BMCR_PDOWN; ++ data |= BMCR_RESET; ++ r8152_mdio_write(tp, MII_BMCR, data); ++ ++ data = r8153_phy_status(tp, PHY_STAT_LAN_ON); ++ ++ default: ++ if (data != PHY_STAT_LAN_ON) ++ netif_warn(tp, link, tp->netdev, ++ "PHY not ready"); ++ break; ++ } ++ } ++} ++ + static void r8153_power_cut_en(struct r8152 *tp, bool enable) + { + u32 ocp_data; +@@ -2466,6 +2729,38 @@ + ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); + } + ++static void r8153b_power_cut_en(struct r8152 *tp, bool enable) ++{ ++ u32 ocp_data; ++ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); ++ if (enable) ++ ocp_data |= PWR_EN | PHASE2_EN; ++ else ++ ocp_data &= ~PWR_EN; ++ ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); ++ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); ++ ocp_data &= ~PCUT_STATUS; ++ ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); ++} ++ ++static void r8153b_queue_wake(struct r8152 *tp, bool enable) ++{ ++ u32 ocp_data; ++ ++ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38a); ++ if (enable) ++ ocp_data |= BIT(0); ++ else ++ ocp_data &= ~BIT(0); ++ ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38a, ocp_data); ++ ++ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38c); ++ ocp_data &= ~BIT(0); ++ ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38c, ocp_data); ++} ++ + static bool rtl_can_wakeup(struct r8152 *tp) + { + struct usb_device *udev = tp->udev; +@@ -2515,13 +2810,52 @@ + } + } + ++static void rtl8153b_runtime_enable(struct r8152 *tp, bool enable) ++{ ++ if (enable) { ++ r8153b_queue_wake(tp, true); ++ r8153b_u1u2en(tp, false); ++ r8153_u2p3en(tp, false); ++ rtl_runtime_suspend_enable(tp, true); ++ r8153b_ups_en(tp, true); ++ } else { ++ r8153b_ups_en(tp, false); ++ r8153b_queue_wake(tp, false); ++ rtl_runtime_suspend_enable(tp, false); ++ r8153_u2p3en(tp, true); ++ r8153b_u1u2en(tp, true); ++ } ++} ++ + static void r8153_teredo_off(struct r8152 *tp) + { + u32 ocp_data; + +- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); +- ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); +- ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); ++ 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: ++ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ++ ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | ++ OOB_TEREDO_EN); ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); ++ break; ++ ++ case RTL_VER_08: ++ case RTL_VER_09: ++ /* The bit 0 ~ 7 are relative with teredo settings. They are ++ * W1C (write 1 to clear), so set all 1 to disable it. ++ */ ++ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff); ++ break; ++ ++ default: ++ break; ++ } + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); +@@ -2767,6 +3101,33 @@ + 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 void r8153_aldps_en(struct r8152 *tp, bool enable) + { + u16 data; +@@ -2782,6 +3143,16 @@ + } + } + ++static void r8153b_aldps_en(struct r8152 *tp, bool enable) ++{ ++ r8153_aldps_en(tp, enable); ++ ++ if (enable) ++ r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_ALDPS, 0); ++ else ++ r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_ALDPS); ++} ++ + static void r8153_eee_en(struct r8152 *tp, bool enable) + { + u32 ocp_data; +@@ -2802,6 +3173,22 @@ + ocp_reg_write(tp, OCP_EEE_CFG, config); + } + ++static void r8153b_eee_en(struct r8152 *tp, bool enable) ++{ ++ r8153_eee_en(tp, enable); ++ ++ if (enable) ++ r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_EEE, 0); ++ else ++ r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_EEE); ++} ++ ++static void r8153b_enable_fc(struct r8152 *tp) ++{ ++ r8152b_enable_fc(tp); ++ r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_FLOW_CTR, 0); ++} ++ + static void r8153_hw_phy_cfg(struct r8152 *tp) + { + u32 ocp_data; +@@ -2852,6 +3239,100 @@ + set_bit(PHY_RESET, &tp->flags); + } + ++static u32 r8152_efuse_read(struct r8152 *tp, u8 addr) ++{ ++ u32 ocp_data; ++ ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr); ++ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD); ++ ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9; /* data of bit16 */ ++ ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA); ++ ++ return ocp_data; ++} ++ ++static void r8153b_hw_phy_cfg(struct r8152 *tp) ++{ ++ u32 ocp_data, ups_flags = 0; ++ u16 data; ++ ++ /* disable ALDPS before updating the PHY parameters */ ++ r8153b_aldps_en(tp, false); ++ ++ /* disable EEE before updating the PHY parameters */ ++ r8153b_eee_en(tp, false); ++ ocp_reg_write(tp, OCP_EEE_ADV, 0); ++ ++ r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags)); ++ ++ data = sram_read(tp, SRAM_GREEN_CFG); ++ data |= R_TUNE_EN; ++ sram_write(tp, SRAM_GREEN_CFG, data); ++ data = ocp_reg_read(tp, OCP_NCTL_CFG); ++ data |= PGA_RETURN_EN; ++ ocp_reg_write(tp, OCP_NCTL_CFG, data); ++ ++ /* ADC Bias Calibration: ++ * read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake ++ * bit (bit3) to rebuild the real 16-bit data. Write the data to the ++ * ADC ioffset. ++ */ ++ ocp_data = r8152_efuse_read(tp, 0x7d); ++ data = (u16)(((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7)); ++ if (data != 0xffff) ++ ocp_reg_write(tp, OCP_ADC_IOFFSET, data); ++ ++ /* ups mode tx-link-pulse timing adjustment: ++ * rg_saw_cnt = OCP reg 0xC426 Bit[13:0] ++ * swr_cnt_1ms_ini = 16000000 / rg_saw_cnt ++ */ ++ ocp_data = ocp_reg_read(tp, 0xc426); ++ ocp_data &= 0x3fff; ++ if (ocp_data) { ++ u32 swr_cnt_1ms_ini; ++ ++ swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK; ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG); ++ ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini; ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data); ++ } ++ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); ++ ocp_data |= PFM_PWM_SWITCH; ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); ++ ++ /* Advnace EEE */ ++ if (!r8153_patch_request(tp, true)) { ++ data = ocp_reg_read(tp, OCP_POWER_CFG); ++ data |= EEE_CLKDIV_EN; ++ ocp_reg_write(tp, OCP_POWER_CFG, data); ++ ++ data = ocp_reg_read(tp, OCP_DOWN_SPEED); ++ data |= EN_EEE_CMODE | EN_EEE_1000 | EN_10M_CLKDIV; ++ ocp_reg_write(tp, OCP_DOWN_SPEED, data); ++ ++ ocp_reg_write(tp, OCP_SYSCLK_CFG, 0); ++ ocp_reg_write(tp, OCP_SYSCLK_CFG, clk_div_expo(5)); ++ ++ ups_flags |= UPS_FLAGS_EN_10M_CKDIV | UPS_FLAGS_250M_CKDIV | ++ UPS_FLAGS_EN_EEE_CKDIV | UPS_FLAGS_EEE_CMOD_LV_EN | ++ UPS_FLAGS_EEE_PLLOFF_GIGA; ++ ++ r8153_patch_request(tp, false); ++ } ++ ++ r8153b_ups_flags_w1w0(tp, ups_flags, 0); ++ ++ r8153b_eee_en(tp, true); ++ ocp_reg_write(tp, OCP_EEE_ADV, MDIO_EEE_1000T | MDIO_EEE_100TX); ++ ++ r8153b_aldps_en(tp, true); ++ r8153b_enable_fc(tp); ++ r8153_u2p3en(tp, true); ++ ++ set_bit(PHY_RESET, &tp->flags); ++} ++ + static void r8153_first_init(struct r8152 *tp) + { + u32 ocp_data; +@@ -2949,9 +3430,28 @@ + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); + +- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); +- ocp_data &= ~TEREDO_WAKE_MASK; +- ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); ++ switch (tp->version) { ++ case RTL_VER_03: ++ case RTL_VER_04: ++ case RTL_VER_05: ++ case RTL_VER_06: ++ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ++ ocp_data &= ~TEREDO_WAKE_MASK; ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); ++ break; ++ ++ case RTL_VER_08: ++ case RTL_VER_09: ++ /* Clear teredo wake event. bit[15:8] is the teredo wakeup ++ * type. Set it to zero. bits[7:0] are the W1C bits about ++ * the events. Set them to all 1 to clear them. ++ */ ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff); ++ break; ++ ++ default: ++ break; ++ } + + rtl_rx_vlan_en(tp, true); + +@@ -2979,9 +3479,18 @@ + usb_enable_lpm(tp->udev); + } + ++static void rtl8153b_disable(struct r8152 *tp) ++{ ++ r8153b_aldps_en(tp, false); ++ rtl_disable(tp); ++ rtl_reset_bmu(tp); ++ r8153b_aldps_en(tp, true); ++} ++ + static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) + { + u16 bmcr, anar, gbcr; ++ enum spd_duplex speed_duplex; + int ret = 0; + + anar = r8152_mdio_read(tp, MII_ADVERTISE); +@@ -2998,32 +3507,43 @@ + if (speed == SPEED_10) { + bmcr = 0; + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; ++ speed_duplex = FORCE_10M_HALF; + } else if (speed == SPEED_100) { + bmcr = BMCR_SPEED100; + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; ++ speed_duplex = FORCE_100M_HALF; + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { + bmcr = BMCR_SPEED1000; + gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; ++ speed_duplex = NWAY_1000M_FULL; + } else { + ret = -EINVAL; + goto out; + } + +- if (duplex == DUPLEX_FULL) ++ if (duplex == DUPLEX_FULL) { + bmcr |= BMCR_FULLDPLX; ++ if (speed != SPEED_1000) ++ speed_duplex++; ++ } + } else { + if (speed == SPEED_10) { +- if (duplex == DUPLEX_FULL) ++ if (duplex == DUPLEX_FULL) { + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; +- else ++ speed_duplex = NWAY_10M_FULL; ++ } else { + anar |= ADVERTISE_10HALF; ++ speed_duplex = NWAY_10M_HALF; ++ } + } else if (speed == SPEED_100) { + if (duplex == DUPLEX_FULL) { + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; ++ speed_duplex = NWAY_100M_FULL; + } else { + anar |= ADVERTISE_10HALF; + anar |= ADVERTISE_100HALF; ++ speed_duplex = NWAY_100M_HALF; + } + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { + if (duplex == DUPLEX_FULL) { +@@ -3035,6 +3555,7 @@ + anar |= ADVERTISE_100HALF; + gbcr |= ADVERTISE_1000HALF; + } ++ speed_duplex = NWAY_1000M_FULL; + } else { + ret = -EINVAL; + goto out; +@@ -3052,6 +3573,17 @@ + r8152_mdio_write(tp, MII_ADVERTISE, anar); + r8152_mdio_write(tp, MII_BMCR, bmcr); + ++ switch (tp->version) { ++ case RTL_VER_08: ++ case RTL_VER_09: ++ r8153b_ups_flags_w1w0(tp, ups_flags_speed(speed_duplex), ++ UPS_FLAGS_SPEED_MASK); ++ break; ++ ++ default: ++ break; ++ } ++ + if (bmcr & BMCR_RESET) { + int i; + +@@ -3118,6 +3650,38 @@ + r8153_aldps_en(tp, true); + } + ++static void rtl8153b_up(struct r8152 *tp) ++{ ++ if (test_bit(RTL8152_UNPLUG, &tp->flags)) ++ return; ++ ++ r8153b_u1u2en(tp, false); ++ r8153_u2p3en(tp, false); ++ r8153b_aldps_en(tp, false); ++ ++ r8153_first_init(tp); ++ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B); ++ ++ r8153b_aldps_en(tp, true); ++ r8153_u2p3en(tp, true); ++ r8153b_u1u2en(tp, true); ++} ++ ++static void rtl8153b_down(struct r8152 *tp) ++{ ++ if (test_bit(RTL8152_UNPLUG, &tp->flags)) { ++ rtl_drop_queued_tx(tp); ++ return; ++ } ++ ++ r8153b_u1u2en(tp, false); ++ r8153_u2p3en(tp, false); ++ r8153b_power_cut_en(tp, false); ++ r8153b_aldps_en(tp, false); ++ r8153_enter_oob(tp); ++ r8153b_aldps_en(tp, true); ++} ++ + static bool rtl8152_in_nway(struct r8152 *tp) + { + u16 nway_state; +@@ -3503,6 +4067,66 @@ + r8153_u2p3en(tp, true); + } + ++static void r8153b_init(struct r8152 *tp) ++{ ++ u32 ocp_data; ++ u16 data; ++ int i; ++ ++ if (test_bit(RTL8152_UNPLUG, &tp->flags)) ++ return; ++ ++ r8153b_u1u2en(tp, false); ++ ++ for (i = 0; i < 500; i++) { ++ if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & ++ AUTOLOAD_DONE) ++ break; ++ msleep(20); ++ } ++ ++ data = r8153_phy_status(tp, 0); ++ ++ data = r8152_mdio_read(tp, MII_BMCR); ++ if (data & BMCR_PDOWN) { ++ data &= ~BMCR_PDOWN; ++ r8152_mdio_write(tp, MII_BMCR, data); ++ } ++ ++ data = r8153_phy_status(tp, PHY_STAT_LAN_ON); ++ ++ r8153_u2p3en(tp, false); ++ ++ /* MSC timer = 0xfff * 8ms = 32760 ms */ ++ ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff); ++ ++ /* U1/U2/L1 idle timer. 500 us */ ++ ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500); ++ ++ r8153b_power_cut_en(tp, false); ++ r8153b_ups_en(tp, false); ++ r8153b_queue_wake(tp, false); ++ rtl_runtime_suspend_enable(tp, false); ++ r8153b_u1u2en(tp, true); ++ usb_enable_lpm(tp->udev); ++ ++ /* MAC clock speed down */ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2); ++ ocp_data |= MAC_CLK_SPDWN_EN; ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data); ++ ++ set_bit(GREEN_ETHERNET, &tp->flags); ++ ++ /* rx aggregation */ ++ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ++ ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); ++ ++ rtl_tally_reset(tp); ++ ++ tp->coalesce = 15000; /* 15 us */ ++} ++ + static int rtl8152_pre_reset(struct usb_interface *intf) + { + struct r8152 *tp = usb_get_intfdata(intf); +@@ -3973,6 +4597,20 @@ + return 0; + } + ++static int r8153b_set_eee(struct r8152 *tp, struct ethtool_eee *eee) ++{ ++ u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); ++ ++ r8153b_eee_en(tp, eee->eee_enabled); ++ ++ if (!eee->eee_enabled) ++ val = 0; ++ ++ ocp_reg_write(tp, OCP_EEE_ADV, val); ++ ++ return 0; ++} ++ + static int + rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) + { +@@ -4206,44 +4844,6 @@ + .ndo_features_check = rtl8152_features_check, + }; + +-static void r8152b_get_version(struct r8152 *tp) +-{ +- u32 ocp_data; +- u16 version; +- +- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1); +- version = (u16)(ocp_data & VERSION_MASK); +- +- switch (version) { +- case 0x4c00: +- tp->version = RTL_VER_01; +- break; +- case 0x4c10: +- tp->version = RTL_VER_02; +- break; +- case 0x5c00: +- tp->version = RTL_VER_03; +- tp->mii.supports_gmii = 1; +- break; +- case 0x5c10: +- tp->version = RTL_VER_04; +- tp->mii.supports_gmii = 1; +- break; +- case 0x5c20: +- tp->version = RTL_VER_05; +- tp->mii.supports_gmii = 1; +- break; +- case 0x5c30: +- tp->version = RTL_VER_06; +- tp->mii.supports_gmii = 1; +- break; +- default: +- netif_info(tp, probe, tp->netdev, +- "Unknown version 0x%04x\n", version); +- break; +- } +-} +- + static void rtl8152_unload(struct r8152 *tp) + { + if (test_bit(RTL8152_UNPLUG, &tp->flags)) +@@ -4261,6 +4861,14 @@ + r8153_power_cut_en(tp, false); + } + ++static void rtl8153b_unload(struct r8152 *tp) ++{ ++ if (test_bit(RTL8152_UNPLUG, &tp->flags)) ++ return; ++ ++ r8153b_power_cut_en(tp, false); ++} ++ + static int rtl_ops_init(struct r8152 *tp) + { + struct rtl_ops *ops = &tp->rtl_ops; +@@ -4299,6 +4907,21 @@ + ops->autosuspend_en = rtl8153_runtime_enable; + break; + ++ case RTL_VER_08: ++ case RTL_VER_09: ++ ops->init = r8153b_init; ++ ops->enable = rtl8153_enable; ++ ops->disable = rtl8153b_disable; ++ ops->up = rtl8153b_up; ++ ops->down = rtl8153b_down; ++ ops->unload = rtl8153b_unload; ++ ops->eee_get = r8153_get_eee; ++ ops->eee_set = r8153b_set_eee; ++ ops->in_nway = rtl8153_in_nway; ++ ops->hw_phy_cfg = r8153b_hw_phy_cfg; ++ ops->autosuspend_en = rtl8153b_runtime_enable; ++ break; ++ + default: + ret = -ENODEV; + netif_err(tp, probe, tp->netdev, "Unknown Device\n"); +@@ -4308,14 +4931,77 @@ + return ret; + } + ++static u8 rtl_get_version(struct usb_interface *intf) ++{ ++ struct usb_device *udev = interface_to_usbdev(intf); ++ u32 ocp_data = 0; ++ __le32 *tmp; ++ u8 version; ++ int ret; ++ ++ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); ++ if (!tmp) ++ return 0; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, ++ PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); ++ if (ret > 0) ++ ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK; ++ ++ kfree(tmp); ++ ++ switch (ocp_data) { ++ case 0x4c00: ++ version = RTL_VER_01; ++ break; ++ case 0x4c10: ++ version = RTL_VER_02; ++ break; ++ case 0x5c00: ++ version = RTL_VER_03; ++ break; ++ case 0x5c10: ++ version = RTL_VER_04; ++ break; ++ case 0x5c20: ++ version = RTL_VER_05; ++ break; ++ case 0x5c30: ++ version = RTL_VER_06; ++ break; ++ case 0x4800: ++ version = RTL_VER_07; ++ break; ++ case 0x6000: ++ version = RTL_VER_08; ++ break; ++ case 0x6010: ++ version = RTL_VER_09; ++ break; ++ default: ++ version = RTL_VER_UNKNOWN; ++ dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data); ++ break; ++ } ++ ++ dev_dbg(&intf->dev, "Detected version 0x%04x\n", version); ++ ++ return version; ++} ++ + static int rtl8152_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { + struct usb_device *udev = interface_to_usbdev(intf); ++ u8 version = rtl_get_version(intf); + struct r8152 *tp; + struct net_device *netdev; + int ret; + ++ if (version == RTL_VER_UNKNOWN) ++ return -ENODEV; ++ + if (udev->actconfig->desc.bConfigurationValue != 1) { + usb_driver_set_configuration(udev, 1); + return -ENODEV; +@@ -4335,8 +5021,19 @@ + tp->udev = udev; + tp->netdev = netdev; + tp->intf = intf; ++ tp->version = version; ++ ++ switch (version) { ++ case RTL_VER_01: ++ case RTL_VER_02: ++ case RTL_VER_07: ++ tp->mii.supports_gmii = 0; ++ break; ++ default: ++ tp->mii.supports_gmii = 1; ++ break; ++ } + +- r8152b_get_version(tp); + ret = rtl_ops_init(tp); + if (ret) + goto out;