diff options
Diffstat (limited to 'drivers/net/usb/r8152.c')
| -rw-r--r-- | drivers/net/usb/r8152.c | 1007 | 
1 files changed, 879 insertions, 128 deletions
| diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ddc62cb69be8..6cfffeff6108 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -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		"9" @@ -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 @@ -477,7 +569,6 @@ enum rtl_register_content {  #define RTL8152_MAX_TX		4  #define RTL8152_MAX_RX		10  #define INTBUFSIZE		2 -#define CRC_SIZE		4  #define TX_ALIGN		4  #define RX_ALIGN		8 @@ -496,12 +587,13 @@ enum rtl_register_content {  #define BYTE_EN_END_MASK	0xf0  #define RTL8153_MAX_PACKET	9216 /* 9K */ -#define RTL8153_MAX_MTU		(RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) -#define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + VLAN_HLEN) +#define RTL8153_MAX_MTU		(RTL8153_MAX_PACKET - VLAN_ETH_HLEN - \ +				 ETH_FCS_LEN) +#define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)  #define RTL8153_RMS		RTL8153_MAX_PACKET  #define RTL8152_TX_TIMEOUT	(5 * HZ)  #define RTL8152_NAPI_WEIGHT	64 -#define rx_reserved_size(x)	((x) + VLAN_ETH_HLEN + CRC_SIZE + \ +#define rx_reserved_size(x)	((x) + VLAN_ETH_HLEN + ETH_FCS_LEN + \  				 sizeof(struct rx_desc) + RX_ALIGN)  /* rtl8152 flags */ @@ -513,6 +605,7 @@ enum rtl8152_flags {  	SELECTIVE_SUSPEND,  	PHY_RESET,  	SCHEDULE_NAPI, +	GREEN_ETHERNET,  };  /* Define these values to match your device */ @@ -658,6 +751,9 @@ enum rtl_version {  	RTL_VER_04,  	RTL_VER_05,  	RTL_VER_06, +	RTL_VER_07, +	RTL_VER_08, +	RTL_VER_09,  	RTL_VER_MAX  }; @@ -674,7 +770,7 @@ static const int multicast_filter_limit = 32;  static unsigned int agg_buf_sz = 16384;  #define RTL_LIMITED_TSO_SIZE	(agg_buf_sz - sizeof(struct tx_desc) - \ -				 VLAN_ETH_HLEN - VLAN_HLEN) +				 VLAN_ETH_HLEN - ETH_FCS_LEN)  static  int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) @@ -841,12 +937,6 @@ int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)  }  static inline -int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) -{ -	return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB); -} - -static inline  int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)  {  	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB); @@ -872,11 +962,13 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)  {  	u32 data;  	__le32 tmp; +	u16 byen = BYTE_EN_WORD;  	u8 shift = index & 2;  	index &= ~3; +	byen <<= shift; -	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); +	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen);  	data = __le32_to_cpu(tmp);  	data >>= (shift * 8); @@ -988,6 +1080,12 @@ static void sram_write(struct r8152 *tp, u16 addr, u16 data)  	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); @@ -1818,6 +1916,10 @@ static int rx_bottom(struct r8152 *tp, int budget)  			unsigned int pkt_len;  			struct sk_buff *skb; +			/* limite the skb numbers for rx_queue */ +			if (unlikely(skb_queue_len(&tp->rx_queue) >= 1000)) +				break; +  			pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;  			if (pkt_len < ETH_ZLEN)  				break; @@ -1826,7 +1928,7 @@ static int rx_bottom(struct r8152 *tp, int budget)  			if (urb->actual_length < len_used)  				break; -			pkt_len -= CRC_SIZE; +			pkt_len -= ETH_FCS_LEN;  			rx_data += sizeof(struct rx_desc);  			skb = napi_alloc_skb(napi, pkt_len); @@ -1850,7 +1952,7 @@ static int rx_bottom(struct r8152 *tp, int budget)  			}  find_next_rx: -			rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); +			rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN);  			rx_desc = (struct rx_desc *)rx_data;  			len_used = (int)(rx_data - (u8 *)agg->head);  			len_used += sizeof(struct rx_desc); @@ -1939,7 +2041,8 @@ static int r8152_poll(struct napi_struct *napi, int budget)  	bottom_half(tp);  	if (work_done < budget) { -		napi_complete(napi); +		if (!napi_complete_done(napi, work_done)) +			goto out;  		if (!list_empty(&tp->rx_done))  			napi_schedule(napi);  		else if (!skb_queue_empty(&tp->tx_queue) && @@ -1947,6 +2050,7 @@ static int r8152_poll(struct napi_struct *napi, int budget)  			napi_schedule(napi);  	} +out:  	return work_done;  } @@ -2138,7 +2242,7 @@ static void set_tx_qlen(struct r8152 *tp)  {  	struct net_device *netdev = tp->netdev; -	tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN + +	tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN +  				    sizeof(struct tx_desc));  } @@ -2249,18 +2353,64 @@ static int rtl8152_enable(struct r8152 *tp)  	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)  { -	u32 ocp_data = (agg_buf_sz - rx_reserved_size(tp->netdev->mtu)) / 4; +	u32 ocp_data = agg_buf_sz - rx_reserved_size(tp->netdev->mtu); -	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) @@ -2268,7 +2418,6 @@ static int rtl8153_enable(struct r8152 *tp)  	if (test_bit(RTL8152_UNPLUG, &tp->flags))  		return -ENODEV; -	usb_disable_lpm(tp->udev);  	set_tx_qlen(tp);  	rtl_set_eee_plus(tp);  	r8153_set_rx_early_timeout(tp); @@ -2434,6 +2583,29 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)  		device_set_wakeup_enable(&tp->udev->dev, false);  } +static void r8153_mac_clk_spd(struct r8152 *tp, bool enable) +{ +	/* MAC clock speed down */ +	if (enable) { +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, +			       ALDPS_SPDWN_RATIO); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, +			       EEE_SPDWN_RATIO); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, +			       PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN | +			       U1U2_SPDWN_EN | L1_SPDWN_EN); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, +			       PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN | +			       TP100_SPDWN_EN | TP500_SPDWN_EN | EEE_SPDWN_EN | +			       TP1000_SPDWN_EN); +	} else { +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0); +		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0); +	} +} +  static void r8153_u1u2en(struct r8152 *tp, bool enable)  {  	u8 u1u2[8]; @@ -2446,18 +2618,133 @@ static void r8153_u1u2en(struct r8152 *tp, bool enable)  	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;  	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); -	if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04) +	if (enable)  		ocp_data |= U2P3_ENABLE;  	else  		ocp_data &= ~U2P3_ENABLE;  	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; @@ -2474,6 +2761,38 @@ static void r8153_power_cut_en(struct r8152 *tp, bool enable)  	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; @@ -2512,24 +2831,76 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)  static void rtl8153_runtime_enable(struct r8152 *tp, bool enable)  { -	rtl_runtime_suspend_enable(tp, enable); -  	if (enable) {  		r8153_u1u2en(tp, false);  		r8153_u2p3en(tp, false); +		r8153_mac_clk_spd(tp, true); +		rtl_runtime_suspend_enable(tp, true);  	} else { -		r8153_u2p3en(tp, true); +		rtl_runtime_suspend_enable(tp, false); +		r8153_mac_clk_spd(tp, false); + +		switch (tp->version) { +		case RTL_VER_03: +		case RTL_VER_04: +			break; +		case RTL_VER_05: +		case RTL_VER_06: +		default: +			r8153_u2p3en(tp, true); +			break; +		} +  		r8153_u1u2en(tp, true);  	}  } +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); @@ -2775,6 +3146,33 @@ 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 void r8153_aldps_en(struct r8152 *tp, bool enable)  {  	u16 data; @@ -2784,12 +3182,28 @@ static void r8153_aldps_en(struct r8152 *tp, bool enable)  		data |= EN_ALDPS;  		ocp_reg_write(tp, OCP_POWER_CFG, data);  	} else { +		int i; +  		data &= ~EN_ALDPS;  		ocp_reg_write(tp, OCP_POWER_CFG, data); -		msleep(20); +		for (i = 0; i < 20; i++) { +			usleep_range(1000, 2000); +			if (ocp_read_word(tp, MCU_TYPE_PLA, 0xe000) & 0x0100) +				break; +		}  	}  } +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; @@ -2810,6 +3224,22 @@ static void r8153_eee_en(struct r8152 *tp, bool enable)  	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; @@ -2857,6 +3287,111 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)  	r8153_aldps_en(tp, true);  	r8152b_enable_fc(tp); +	switch (tp->version) { +	case RTL_VER_03: +	case RTL_VER_04: +		break; +	case RTL_VER_05: +	case RTL_VER_06: +	default: +		r8153_u2p3en(tp, true); +		break; +	} + +	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);  } @@ -2865,6 +3400,7 @@ static void r8153_first_init(struct r8152 *tp)  	u32 ocp_data;  	int i; +	r8153_mac_clk_spd(tp, false);  	rxdy_gated_en(tp, true);  	r8153_teredo_off(tp); @@ -2903,7 +3439,7 @@ static void r8153_first_init(struct r8152 *tp)  	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); -	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; +	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);  	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); @@ -2919,11 +3455,6 @@ static void r8153_first_init(struct r8152 *tp)  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);  	/* TX share fifo free credit full threshold */  	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); - -	/* 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);  }  static void r8153_enter_oob(struct r8152 *tp) @@ -2931,6 +3462,8 @@ static void r8153_enter_oob(struct r8152 *tp)  	u32 ocp_data;  	int i; +	r8153_mac_clk_spd(tp, true); +  	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);  	ocp_data &= ~NOW_IS_OOB;  	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); @@ -2956,12 +3489,31 @@ static void r8153_enter_oob(struct r8152 *tp)  		usleep_range(1000, 2000);  	} -	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; +	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); -	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); @@ -2986,12 +3538,20 @@ static void rtl8153_disable(struct r8152 *tp)  	rtl_disable(tp);  	rtl_reset_bmu(tp);  	r8153_aldps_en(tp, true); -	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); @@ -3008,32 +3568,43 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)  		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) { @@ -3045,6 +3616,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)  				anar |= ADVERTISE_100HALF;  				gbcr |= ADVERTISE_1000HALF;  			} +			speed_duplex = NWAY_1000M_FULL;  		} else {  			ret = -EINVAL;  			goto out; @@ -3062,6 +3634,17 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)  	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; @@ -3105,12 +3688,23 @@ static void rtl8153_up(struct r8152 *tp)  		return;  	r8153_u1u2en(tp, false); +	r8153_u2p3en(tp, false);  	r8153_aldps_en(tp, false);  	r8153_first_init(tp);  	r8153_aldps_en(tp, true); -	r8153_u2p3en(tp, true); + +	switch (tp->version) { +	case RTL_VER_03: +	case RTL_VER_04: +		break; +	case RTL_VER_05: +	case RTL_VER_06: +	default: +		r8153_u2p3en(tp, true); +		break; +	} +  	r8153_u1u2en(tp, true); -	usb_enable_lpm(tp->udev);  }  static void rtl8153_down(struct r8152 *tp) @@ -3128,6 +3722,38 @@ static void rtl8153_down(struct r8152 *tp)  	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; @@ -3426,12 +4052,7 @@ static void r8153_init(struct r8152 *tp)  		msleep(20);  	} -	for (i = 0; i < 500; i++) { -		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; -		if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN) -			break; -		msleep(20); -	} +	data = r8153_phy_status(tp, 0);  	if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 ||  	    tp->version == RTL_VER_05) @@ -3443,14 +4064,8 @@ static void r8153_init(struct r8152 *tp)  		r8152_mdio_write(tp, MII_BMCR, data);  	} -	for (i = 0; i < 500; i++) { -		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; -		if (ocp_data == PHY_STAT_LAN_ON) -			break; -		msleep(20); -	} +	data = r8153_phy_status(tp, PHY_STAT_LAN_ON); -	usb_disable_lpm(tp->udev);  	r8153_u2p3en(tp, false);  	if (tp->version == RTL_VER_04) { @@ -3510,15 +4125,88 @@ static void r8153_init(struct r8152 *tp)  	r8153_power_cut_en(tp, false);  	r8153_u1u2en(tp, true); +	r8153_mac_clk_spd(tp, false); +	usb_enable_lpm(tp->udev); + +	/* 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); + +	switch (tp->udev->speed) { +	case USB_SPEED_SUPER: +	case USB_SPEED_SUPER_PLUS: +		tp->coalesce = COALESCE_SUPER; +		break; +	case USB_SPEED_HIGH: +		tp->coalesce = COALESCE_HIGH; +		break; +	default: +		tp->coalesce = COALESCE_SLOW; +		break; +	} +} + +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_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); -	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0); -	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0); -	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0); +	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); -	r8153_u2p3en(tp, true); + +	tp->coalesce = 15000;	/* 15 us */  }  static int rtl8152_pre_reset(struct usb_interface *intf) @@ -3601,6 +4289,61 @@ static bool delay_autosuspend(struct r8152 *tp)  		return false;  } +static int rtl8152_runtime_resume(struct r8152 *tp) +{ +	struct net_device *netdev = tp->netdev; + +	if (netif_running(netdev) && netdev->flags & IFF_UP) { +		struct napi_struct *napi = &tp->napi; + +		tp->rtl_ops.autosuspend_en(tp, false); +		napi_disable(napi); +		set_bit(WORK_ENABLE, &tp->flags); + +		if (netif_carrier_ok(netdev)) { +			if (rtl8152_get_speed(tp) & LINK_STATUS) { +				rtl_start_rx(tp); +			} else { +				netif_carrier_off(netdev); +				tp->rtl_ops.disable(tp); +				netif_info(tp, link, netdev, "linking down\n"); +			} +		} + +		napi_enable(napi); +		clear_bit(SELECTIVE_SUSPEND, &tp->flags); +		smp_mb__after_atomic(); + +		if (!list_empty(&tp->rx_done)) +			napi_schedule(&tp->napi); + +		usb_submit_urb(tp->intr_urb, GFP_NOIO); +	} else { +		if (netdev->flags & IFF_UP) +			tp->rtl_ops.autosuspend_en(tp, false); + +		clear_bit(SELECTIVE_SUSPEND, &tp->flags); +	} + +	return 0; +} + +static int rtl8152_system_resume(struct r8152 *tp) +{ +	struct net_device *netdev = tp->netdev; + +	netif_device_attach(netdev); + +	if (netif_running(netdev) && netdev->flags & IFF_UP) { +		tp->rtl_ops.up(tp); +		netif_carrier_off(netdev); +		set_bit(WORK_ENABLE, &tp->flags); +		usb_submit_urb(tp->intr_urb, GFP_NOIO); +	} + +	return 0; +} +  static int rtl8152_runtime_suspend(struct r8152 *tp)  {  	struct net_device *netdev = tp->netdev; @@ -3612,13 +4355,6 @@ static int rtl8152_runtime_suspend(struct r8152 *tp)  	if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {  		u32 rcr = 0; -		if (delay_autosuspend(tp)) { -			clear_bit(SELECTIVE_SUSPEND, &tp->flags); -			smp_mb__after_atomic(); -			ret = -EBUSY; -			goto out1; -		} -  		if (netif_carrier_ok(netdev)) {  			u32 ocp_data; @@ -3652,6 +4388,11 @@ static int rtl8152_runtime_suspend(struct r8152 *tp)  			ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);  			napi_enable(napi);  		} + +		if (delay_autosuspend(tp)) { +			rtl8152_runtime_resume(tp); +			ret = -EBUSY; +		}  	}  out1: @@ -3699,53 +4440,18 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)  static int rtl8152_resume(struct usb_interface *intf)  {  	struct r8152 *tp = usb_get_intfdata(intf); -	struct net_device *netdev = tp->netdev; +	int ret;  	mutex_lock(&tp->control); -	if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { -		tp->rtl_ops.init(tp); -		queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); -		netif_device_attach(netdev); -	} - -	if (netif_running(netdev) && netdev->flags & IFF_UP) { -		if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { -			struct napi_struct *napi = &tp->napi; - -			tp->rtl_ops.autosuspend_en(tp, false); -			napi_disable(napi); -			set_bit(WORK_ENABLE, &tp->flags); -			if (netif_carrier_ok(netdev)) { -				if (rtl8152_get_speed(tp) & LINK_STATUS) { -					rtl_start_rx(tp); -				} else { -					netif_carrier_off(netdev); -					tp->rtl_ops.disable(tp); -					netif_info(tp, link, netdev, -						   "linking down\n"); -				} -			} -			napi_enable(napi); -			clear_bit(SELECTIVE_SUSPEND, &tp->flags); -			smp_mb__after_atomic(); -			if (!list_empty(&tp->rx_done)) -				napi_schedule(&tp->napi); -		} else { -			tp->rtl_ops.up(tp); -			netif_carrier_off(netdev); -			set_bit(WORK_ENABLE, &tp->flags); -		} -		usb_submit_urb(tp->intr_urb, GFP_KERNEL); -	} else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { -		if (netdev->flags & IFF_UP) -			tp->rtl_ops.autosuspend_en(tp, false); -		clear_bit(SELECTIVE_SUSPEND, &tp->flags); -	} +	if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) +		ret = rtl8152_runtime_resume(tp); +	else +		ret = rtl8152_system_resume(tp);  	mutex_unlock(&tp->control); -	return 0; +	return ret;  }  static int rtl8152_reset_resume(struct usb_interface *intf) @@ -3753,6 +4459,10 @@ static int rtl8152_reset_resume(struct usb_interface *intf)  	struct r8152 *tp = usb_get_intfdata(intf);  	clear_bit(SELECTIVE_SUSPEND, &tp->flags); +	mutex_lock(&tp->control); +	tp->rtl_ops.init(tp); +	queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); +	mutex_unlock(&tp->control);  	return rtl8152_resume(intf);  } @@ -3841,7 +4551,7 @@ int rtl8152_get_link_ksettings(struct net_device *netdev,  	mutex_lock(&tp->control); -	ret = mii_ethtool_get_link_ksettings(&tp->mii, cmd); +	mii_ethtool_get_link_ksettings(&tp->mii, cmd);  	mutex_unlock(&tp->control); @@ -4022,6 +4732,20 @@ static int r8153_set_eee(struct r8152 *tp, struct ethtool_eee *eee)  	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)  { @@ -4097,6 +4821,7 @@ static int rtl8152_get_coalesce(struct net_device *netdev,  	switch (tp->version) {  	case RTL_VER_01:  	case RTL_VER_02: +	case RTL_VER_07:  		return -EOPNOTSUPP;  	default:  		break; @@ -4116,6 +4841,7 @@ static int rtl8152_set_coalesce(struct net_device *netdev,  	switch (tp->version) {  	case RTL_VER_01:  	case RTL_VER_02: +	case RTL_VER_07:  		return -EOPNOTSUPP;  	default:  		break; @@ -4215,6 +4941,7 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)  	switch (tp->version) {  	case RTL_VER_01:  	case RTL_VER_02: +	case RTL_VER_07:  		dev->mtu = new_mtu;  		return 0;  	default: @@ -4230,7 +4957,7 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)  	dev->mtu = new_mtu;  	if (netif_running(dev)) { -		u32 rms = new_mtu + VLAN_ETH_HLEN + CRC_SIZE; +		u32 rms = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;  		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rms); @@ -4276,6 +5003,14 @@ static void rtl8153_unload(struct r8152 *tp)  	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; @@ -4284,6 +5019,7 @@ static int rtl_ops_init(struct r8152 *tp)  	switch (tp->version) {  	case RTL_VER_01:  	case RTL_VER_02: +	case RTL_VER_07:  		ops->init		= r8152b_init;  		ops->enable		= rtl8152_enable;  		ops->disable		= rtl8152_disable; @@ -4314,6 +5050,21 @@ static int rtl_ops_init(struct r8152 *tp)  		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"); @@ -4362,12 +5113,23 @@ static u8 rtl_get_version(struct usb_interface *intf)  	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;  } @@ -4407,6 +5169,7 @@ static int rtl8152_probe(struct usb_interface *intf,  	switch (version) {  	case RTL_VER_01:  	case RTL_VER_02: +	case RTL_VER_07:  		tp->mii.supports_gmii = 0;  		break;  	default: @@ -4464,19 +5227,6 @@ static int rtl8152_probe(struct usb_interface *intf,  	tp->mii.reg_num_mask = 0x1f;  	tp->mii.phy_id = R8152_PHY_ID; -	switch (udev->speed) { -	case USB_SPEED_SUPER: -	case USB_SPEED_SUPER_PLUS: -		tp->coalesce = COALESCE_SUPER; -		break; -	case USB_SPEED_HIGH: -		tp->coalesce = COALESCE_HIGH; -		break; -	default: -		tp->coalesce = COALESCE_SLOW; -		break; -	} -  	tp->autoneg = AUTONEG_ENABLE;  	tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100;  	tp->duplex = DUPLEX_FULL; @@ -4554,6 +5304,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)  /* table of devices that work with this driver */  static struct usb_device_id rtl8152_table[] = { +	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050)},  	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},  	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},  	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, | 
